diff options
Diffstat (limited to 'bin')
-rw-r--r-- | bin/.gitignore | 4 | ||||
-rw-r--r-- | bin/Makefile | 15 | ||||
-rw-r--r-- | bin/README.7 | 18 | ||||
-rw-r--r-- | bin/bri.c | 85 | ||||
-rw-r--r-- | bin/fbatt.c | 123 | ||||
-rw-r--r-- | bin/fbclock.c | 132 | ||||
-rw-r--r-- | bin/html.mk | 1 | ||||
-rw-r--r-- | bin/man1/bri.1 | 44 | ||||
-rw-r--r-- | bin/man1/fbatt.1 | 34 | ||||
-rw-r--r-- | bin/man1/fbclock.1 | 36 | ||||
-rw-r--r-- | bin/man1/psfed.1 | 166 | ||||
-rw-r--r-- | bin/psfed.c | 577 |
12 files changed, 5 insertions, 1230 deletions
diff --git a/bin/.gitignore b/bin/.gitignore index 02f0536f..5f3bf0c7 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -3,15 +3,12 @@ beef bibsort bit -bri c config.mk dehtml downgrade dtch ever -fbatt -fbclock freecell git-comment glitch @@ -25,7 +22,6 @@ order pbd pngo psf2png -psfed ptee relay scheme diff --git a/bin/Makefile b/bin/Makefile index 8564f59b..9fe60278 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -37,18 +37,12 @@ BSD += ever GAMES += freecell -LINUX += bri -LINUX += fbatt -LINUX += fbclock -LINUX += psfed - TLS += downgrade TLS += relay MANS = ${BINS:%=man1/%.1} MANS.BSD = ${BSD:%=man1/%.1} MANS.GAMES = ${GAMES:%=man6/%.6} -MANS.LINUX = ${LINUX:%=man1/%.1} MANS.TLS = ${TLS:%=man1/%.1} LDLIBS.downgrade = -ltls @@ -78,12 +72,10 @@ bsd: ${BSD} games: ${GAMES} -linux: ${LINUX} - tls: ${TLS} IGNORE = *.o *.html -IGNORE += ${BINS} ${BSD} ${GAMES} ${LINUX} ${TLS} +IGNORE += ${BINS} ${BSD} ${GAMES} ${TLS} IGNORE += scheme.h tags htmltags .gitignore: Makefile @@ -112,10 +104,6 @@ install-games: install-meta ${GAMES} ${MANS.GAMES} install ${GAMES} ${PREFIX}/bin install -m 644 ${MANS.GAMES} ${MANDIR}/man6 -install-linux: install-meta ${LINUX} ${MANS.LINUX} - install ${LINUX} ${PREFIX}/bin - install -m 644 ${MANS.LINUX} ${MANDIR}/man1 - install-tls: install-meta ${TLS} ${MANS.TLS} install ${TLS} ${PREFIX}/bin install -m 644 ${MANS.TLS} ${MANDIR}/man1 @@ -124,7 +112,6 @@ uninstall: rm -f ${BINS:%=${PREFIX}/bin/%} ${MANS:%=${MANDIR}/%} rm -f ${BSD:%=${PREFIX}/bin/%} ${MANS.BSD:%=${MANDIR}/%} rm -f ${GAMES:%=${PREFIX}/bin/%} ${MANS.GAMES:%=${MANDIR}/%} - rm -f ${LINUX:%=${PREFIX}/bin/%} ${MANS.LINUX:%=${MANDIR}/%} rm -f ${TLS:%=${PREFIX}/bin/%} ${MANS.TLS:%=${MANDIR}/%} .SUFFIXES: .pl diff --git a/bin/README.7 b/bin/README.7 index f3407978..be4c6a31 100644 --- a/bin/README.7 +++ b/bin/README.7 @@ -1,4 +1,4 @@ -.Dd September 15, 2021 +.Dd September 22, 2021 .Dt BIN 7 .Os "Causal Agency" . @@ -8,11 +8,9 @@ . .Sh DESCRIPTION Various tools primarily targeting -Darwin, -.Fx -and -.Ox . -Some tools target Linux. +.Fx , +.Ox +and macOS. . .Pp .Bl -tag -width "git-comment(1)" -compact @@ -22,8 +20,6 @@ Befunge-93 interpreter reformat bibliography .It Xr bit 1 calculator -.It Xr bri 1 -backlight brightness control .It Xr c 1 run C statements .It Xr dehtml 1 @@ -34,10 +30,6 @@ IRC features for all detached sessions .It Xr ever 1 watch files -.It Xr fbatt 1 -framebuffer battery indicator -.It Xr fbclock 1 -framebuffer clock .It Xr freecell 6 patience game .It Xr git-comment 1 @@ -62,8 +54,6 @@ macOS pasteboard daemon PNG optimizer .It Xr psf2png 1 PSF2 to PNG renderer -.It Xr psfed 1 -PSF2 font editor .It Xr ptee 1 tee for PTYs .It Xr relay 1 diff --git a/bin/bri.c b/bin/bri.c deleted file mode 100644 index 81df2995..00000000 --- a/bin/bri.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (C) 2017 C. McEnroe <june@causal.agency> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <dirent.h> -#include <err.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sysexits.h> -#include <unistd.h> - -typedef unsigned uint; - -static const char *Class = "/sys/class/backlight"; - -int main(int argc, char *argv[]) { - int error; - - const char *input = (argc > 1) ? argv[1] : NULL; - - error = chdir(Class); - if (error) err(EX_OSFILE, "%s", Class); - - DIR *dir = opendir("."); - if (!dir) err(EX_OSFILE, "%s", Class); - - struct dirent *entry; - while (NULL != (errno = 0, entry = readdir(dir))) { - if (entry->d_name[0] == '.') continue; - - error = chdir(entry->d_name); - if (error) err(EX_OSFILE, "%s/%s", Class, entry->d_name); - break; - } - if (!entry) { - if (errno) err(EX_IOERR, "%s", Class); - errx(EX_CONFIG, "%s: empty", Class); - } - - FILE *actual = fopen("actual_brightness", "r"); - if (!actual) err(EX_OSFILE, "actual_brightness"); - - uint value; - int match = fscanf(actual, "%u", &value); - if (match == EOF) err(EX_IOERR, "actual_brightness"); - if (match < 1) errx(EX_DATAERR, "actual_brightness"); - - if (!input) { - printf("%u\n", value); - return EX_OK; - } - - if (input[0] == '+' || input[0] == '-') { - size_t count = strnlen(input, 16); - if (input[0] == '+') { - value += 16 * count; - } else { - value -= 16 * count; - } - } else { - value = strtoul(input, NULL, 0); - } - - FILE *brightness = fopen("brightness", "w"); - if (!brightness) err(EX_OSFILE, "brightness"); - - int size = fprintf(brightness, "%u", value); - if (size < 0) err(EX_IOERR, "brightness"); - - return EX_OK; -} diff --git a/bin/fbatt.c b/bin/fbatt.c deleted file mode 100644 index 9feffe47..00000000 --- a/bin/fbatt.c +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (C) 2018 C. McEnroe <june@causal.agency> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <dirent.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <linux/fb.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sysexits.h> -#include <unistd.h> - -#include "scheme.h" - -static const char *Class = "/sys/class/power_supply"; - -static const uint32_t Right = 5 * 8 + 1; // fbclock width. -static const uint32_t Width = 8; -static const uint32_t Height = 16; - -int main() { - int error; - - DIR *dir = opendir(Class); - if (!dir) err(EX_OSFILE, "%s", Class); - - FILE *chargeFull = NULL; - FILE *chargeNow = NULL; - - const struct dirent *entry; - while (NULL != (errno = 0, entry = readdir(dir))) { - if (entry->d_name[0] == '.') continue; - - error = chdir(Class); - if (error) err(EX_OSFILE, "%s", Class); - - error = chdir(entry->d_name); - if (error) err(EX_OSFILE, "%s/%s", Class, entry->d_name); - - chargeFull = fopen("charge_full", "r"); - chargeNow = fopen("charge_now", "r"); - if (chargeFull && chargeNow) break; - } - if (!chargeFull || !chargeNow) { - if (errno) err(EX_OSFILE, "%s", Class); - errx(EX_CONFIG, "%s: empty", Class); - } - closedir(dir); - - const char *path = getenv("FRAMEBUFFER"); - if (!path) path = "/dev/fb0"; - - int fb = open(path, O_RDWR); - if (fb < 0) err(EX_OSFILE, "%s", path); - - struct fb_var_screeninfo info; - error = ioctl(fb, FBIOGET_VSCREENINFO, &info); - if (error) err(EX_IOERR, "%s", path); - - size_t size = 4 * info.xres * info.yres; - uint32_t *buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0); - if (buf == MAP_FAILED) err(EX_IOERR, "%s", path); - - for (;;) { - int match; - - rewind(chargeFull); - fflush(chargeFull); - uint32_t full; - match = fscanf(chargeFull, "%u", &full); - if (match == EOF) err(EX_IOERR, "charge_full"); - if (match < 1) errx(EX_DATAERR, "charge_full"); - - rewind(chargeNow); - fflush(chargeNow); - uint32_t now; - match = fscanf(chargeNow, "%u", &now); - if (match == EOF) err(EX_IOERR, "charge_now"); - if (match < 1) errx(EX_DATAERR, "charge_now"); - - uint32_t percent = 100 * now / full; - uint32_t height = 16 * now / full; - - for (int i = 0; i < 60; ++i, sleep(1)) { - uint32_t left = info.xres - Right - Width; - - for (uint32_t y = 0; y <= Height; ++y) { - buf[y * info.xres + left - 1] = DarkWhite; - buf[y * info.xres + left + Width] = DarkWhite; - } - for (uint32_t x = left; x < left + Width; ++x) { - buf[Height * info.xres + x] = DarkWhite; - } - - for (uint32_t y = 0; y < Height; ++y) { - for (uint32_t x = left; x < left + Width; ++x) { - buf[y * info.xres + x] = - (Height - 1 - y > height) ? DarkBlack - : (percent <= 10) ? DarkRed - : (percent <= 30) ? DarkYellow - : LightBlack; - } - } - } - } -} diff --git a/bin/fbclock.c b/bin/fbclock.c deleted file mode 100644 index ddc32db6..00000000 --- a/bin/fbclock.c +++ /dev/null @@ -1,132 +0,0 @@ -/* Copyright (C) 2018 C. McEnroe <june@causal.agency> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <assert.h> -#include <err.h> -#include <fcntl.h> -#include <linux/fb.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sysexits.h> -#include <time.h> -#include <unistd.h> -#include <zlib.h> - -#include "scheme.h" - -static const uint32_t PSF2Magic = 0x864AB572; -struct PSF2Header { - uint32_t magic; - uint32_t version; - uint32_t headerSize; - uint32_t flags; - uint32_t glyphCount; - uint32_t glyphSize; - uint32_t glyphHeight; - uint32_t glyphWidth; -}; - -int main() { - size_t len; - - const char *fontPath = getenv("FONT"); - if (!fontPath) { - fontPath = "/usr/share/kbd/consolefonts/Lat2-Terminus16.psfu.gz"; - } - - gzFile font = gzopen(fontPath, "r"); - if (!font) err(EX_NOINPUT, "%s", fontPath); - - struct PSF2Header header; - len = gzfread(&header, sizeof(header), 1, font); - if (!len && gzeof(font)) errx(EX_DATAERR, "%s: missing header", fontPath); - if (!len) errx(EX_IOERR, "%s", gzerror(font, NULL)); - - if (header.magic != PSF2Magic) { - errx( - EX_DATAERR, "%s: invalid header magic %08X", - fontPath, header.magic - ); - } - if (header.headerSize != sizeof(struct PSF2Header)) { - errx( - EX_DATAERR, "%s: weird header size %d", - fontPath, header.headerSize - ); - } - - uint8_t glyphs[128][header.glyphSize]; - len = gzfread(glyphs, header.glyphSize, 128, font); - if (!len && gzeof(font)) errx(EX_DATAERR, "%s: missing glyphs", fontPath); - if (!len) errx(EX_IOERR, "%s", gzerror(font, NULL)); - - gzclose(font); - - const char *fbPath = getenv("FRAMEBUFFER"); - if (!fbPath) fbPath = "/dev/fb0"; - - int fb = open(fbPath, O_RDWR); - if (fb < 0) err(EX_OSFILE, "%s", fbPath); - - struct fb_var_screeninfo info; - int error = ioctl(fb, FBIOGET_VSCREENINFO, &info); - if (error) err(EX_IOERR, "%s", fbPath); - - size_t size = 4 * info.xres * info.yres; - uint32_t *buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0); - if (buf == MAP_FAILED) err(EX_IOERR, "%s", fbPath); - - for (;;) { - time_t t = time(NULL); - if (t < 0) err(EX_OSERR, "time"); - const struct tm *local = localtime(&t); - if (!local) err(EX_OSERR, "localtime"); - - char str[64]; - len = strftime(str, sizeof(str), "%H:%M", local); - assert(len); - - for (int i = 0; i < (60 - local->tm_sec); ++i, sleep(1)) { - uint32_t left = info.xres - header.glyphWidth * len; - uint32_t bottom = header.glyphHeight; - - for (uint32_t y = 0; y < bottom; ++y) { - buf[y * info.xres + left - 1] = DarkWhite; - } - for (uint32_t x = left - 1; x < info.xres; ++x) { - buf[bottom * info.xres + x] = DarkWhite; - } - - for (const char *s = str; *s; ++s) { - const uint8_t *glyph = glyphs[(unsigned)*s]; - uint32_t stride = header.glyphSize / header.glyphHeight; - for (uint32_t y = 0; y < header.glyphHeight; ++y) { - for (uint32_t x = 0; x < header.glyphWidth; ++x) { - uint8_t bits = glyph[y * stride + x / 8]; - uint8_t bit = bits >> (7 - x % 8) & 1; - buf[y * info.xres + left + x] = bit - ? DarkWhite - : DarkBlack; - } - } - left += header.glyphWidth; - } - } - } -} diff --git a/bin/html.mk b/bin/html.mk index 92baed46..c1f85595 100644 --- a/bin/html.mk +++ b/bin/html.mk @@ -4,7 +4,6 @@ HTMLS = index.html png.html HTMLS += ${BINS:=.html} HTMLS += ${BSD:=.html} HTMLS += ${GAMES:=.html} -HTMLS += ${LINUX:=.html} HTMLS += ${TLS:=.html} html: ${HTMLS} diff --git a/bin/man1/bri.1 b/bin/man1/bri.1 deleted file mode 100644 index 54a02322..00000000 --- a/bin/man1/bri.1 +++ /dev/null @@ -1,44 +0,0 @@ -.Dd September 7, 2018 -.Dt BRI 1 -.Os -. -.Sh NAME -.Nm bri -.Nd backlight brightness control -. -.Sh SYNOPSIS -.Nm -.Op Ar brightness -.Nm -.Cm + -.Nm -.Cm - -. -.Sh DESCRIPTION -.Nm -controls the backlight brightness on Linux. -. -.Pp -With no argument, -the current brightness is printed. -With a numerical -.Ar brightness -argument, -the brightness is set. -. -.Pp -The -.Cm + -and -.Cm - -arguments -may be repeated any number of times -and adjust the brightness -in increments of 16. -. -.Sh FILES -.Bl -tag -.It Pa /sys/class/backlight -Files under the first subdirectory found -are used to control the backlight brightness. -.El diff --git a/bin/man1/fbatt.1 b/bin/man1/fbatt.1 deleted file mode 100644 index 2d30cba7..00000000 --- a/bin/man1/fbatt.1 +++ /dev/null @@ -1,34 +0,0 @@ -.Dd September 7, 2018 -.Dt FBATT 1 -.Os -. -.Sh NAME -.Nm fbatt -.Nd framebuffer battery indicator -. -.Sh SYNOPSIS -.Nm -. -.Sh DESCRIPTION -.Nm -displays a battery charge indicator -in the top-right corner -of the Linux framebuffer. -. -.Sh ENVIRONMENT -.Bl -tag -.It Ev FRAMEBUFFER -The framebuffer device path. -.El -. -.Sh FILES -.Bl -tag -.It Pa /dev/fb0 -The default framebuffer device path. -.It Pa /sys/class/power_supply -The first subdirectory containing -.Pa charge_full -and -.Pa charge_now -is used to read the battery charge. -.El diff --git a/bin/man1/fbclock.1 b/bin/man1/fbclock.1 deleted file mode 100644 index 3195eb42..00000000 --- a/bin/man1/fbclock.1 +++ /dev/null @@ -1,36 +0,0 @@ -.Dd September 7, 2018 -.Dt FBCLOCK 1 -.Os -. -.Sh NAME -.Nm fbclock -.Nd framebuffer clock -. -.Sh SYNOPSIS -.Nm -. -.Sh DESCRIPTION -.Nm -displays a clock -in the top-right corner -of the Linux framebuffer. -. -.Sh ENVIRONMENT -.Bl -tag -.It Ev FONT -Path to gzipped PSF file. -. -.It Ev FRAMEBUFFER -The framebuffer device path. -.El -. -.Sh FILES -.Bl -tag -.It Pa /dev/fb0 -The default framebuffer device path. -.It Pa /usr/share/kbd/consolefonts/Lat2-Terminus16.psfu.gz -The default font path. -.El -. -.Sh SEE ALSO -.Xr setfont 8 diff --git a/bin/man1/psfed.1 b/bin/man1/psfed.1 deleted file mode 100644 index 3fbc4710..00000000 --- a/bin/man1/psfed.1 +++ /dev/null @@ -1,166 +0,0 @@ -.Dd January 14, 2019 -.Dt PSFED 1 -.Os -. -.Sh NAME -.Nm psfed -.Nd PSF2 font editor -. -.Sh SYNOPSIS -.Nm -.Op Fl H Ar height -.Op Fl g Ar glyphs -.Op Fl h Ar height -.Op Fl w Ar width -.Ar file -. -.Sh DESCRIPTION -.Nm -is a PSF2 font editor -for the Linux framebuffer. -. -.Pp -The arguments are as follows: -. -.Bl -tag -width Ds -.It Fl H Ar height -Modify the height of an existing font. -Only increasing the height is allowed. -. -.It Fl g Ar glyphs -Set the number of glyphs in a new font. -The default number of glyphs is 256. -. -.It Fl h Ar height -Set the height of a new font. -The default height is 16. -. -.It Fl w Ar width -Set the width of a new font. -The default width is 8. -.El -. -.Ss Normal Mode -In normal mode, -each glyph is displayed in a grid. -. -.Pp -.Bl -tag -width Ds -compact -.It Ic q -Quit. -.Nm -will ask for confirmation -if the font has been modified -since the last write. -. -.It Ic w -Write font to -.Ar file . -. -.It Ic - Ic + -Adjust display scale. -. -.It Ic h Ic l -Select previous/next glyph. -. -.It Ic k Ic j -Select glyph in previous/next row. -. -.It Ic f -Select glyph of next input character. -. -.It Ic ' -Return to previously selected glyph. -. -.It Ic y -Copy selected glyph. -. -.It Ic e -Edit selected glyph in -.Sx Edit Mode . -. -.It Ic i -Enter -.Sx Preview Mode . -.El -. -.Ss Edit Mode -In edit mode, -the selected glyph is displayed for editing -surrounded by a checked border. -The glyph is also displayed unscaled -in the bottom-right corner. -. -.Pp -.Bl -tag -width Ds -compact -.It Ic ESC -Return to -.Sx Normal Mode . -. -.It Ic - Ic + -Adjust display scale. -. -.It Ic g Ic G -Toggle guide on selected column/row. -. -.It Ic h Ic l -Select previous/next bit in row. -. -.It Ic k Ic j -Select previous/next bit in column. -. -.It Ic SPACE -Flip selected bit. -. -.It Ic r -Invert glyph. -. -.It Ic H Ic L -Move glyph left/right. -. -.It Ic K Ic J -Move glyph up/down. -. -.It Ic p -Paste the copied glyph. -. -.It Ic u -Revert glyph to initial state. -.El -. -.Ss Preview Mode -In preview mode, -arbitrary text may be entered -for preview. -Press -.Ic ESC -to return to -.Sx Normal Mode . -. -.Sh ENVIRONMENT -.Bl -tag -width FRAMEBUFFER -.It Ev FRAMEBUFFER -The framebuffer device path. -The default path is -.Pa /dev/fb0 . -.El -. -.Sh SEE ALSO -.Xr psfaddtable 1 , -.Xr psfgettable 1 , -.Xr psfstriptable 1 , -.Xr setfont 8 -. -.Sh CAVEATS -.Nm -does not support Unicode tables. -Use -.Xr psfaddtable 1 -to add Unicode tables -to fonts created by -.Nm . -. -.Sh BUGS -.Nm -makes no attempt to convert header fields -to and from little-endian format. diff --git a/bin/psfed.c b/bin/psfed.c deleted file mode 100644 index 4f46b500..00000000 --- a/bin/psfed.c +++ /dev/null @@ -1,577 +0,0 @@ -/* Copyright (C) 2018 C. McEnroe <june@causal.agency> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <linux/fb.h> -#include <locale.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sysexits.h> -#include <termios.h> -#include <unistd.h> -#include <wchar.h> - -static const wchar_t CP437[256] = - L"\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼" - L"►◄↕‼¶§▬↨↑↓→←∟↔▲▼" - L" !\"#$%&'()*+,-./" - L"0123456789:;<=>?" - L"@ABCDEFGHIJKLMNO" - L"PQRSTUVWXYZ[\\]^_" - L"`abcdefghijklmno" - L"pqrstuvwxyz{|}~⌂" - L"ÇüéâäàåçêëèïîìÄÅ" - L"ÉæÆôöòûùÿÖÜ¢£¥₧ƒ" - L"áíóúñѪº¿⌐¬½¼¡«»" - L"░▒▓│┤╡╢╖╕╣║╗╝╜╛┐" - L"└┴┬├─┼╞╟╚╔╩╦╠═╬╧" - L"╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀" - L"αßΓπΣσµτΦΘΩδ∞φε∩" - L"≡±≥≤⌠⌡÷≈°∙·√ⁿ²■\0"; - -static struct { - uint32_t width; - uint32_t height; - uint32_t *buffer; - uint32_t background; -} frame; - -static void frameClear(void) { - for (uint32_t i = 0; i < frame.width * frame.height; ++i) { - frame.buffer[i] = frame.background; - } -} - -static void frameOpen(void) { - const char *dev = getenv("FRAMEBUFFER"); - if (!dev) dev = "/dev/fb0"; - - int fd = open(dev, O_RDWR); - if (fd < 0) err(EX_OSFILE, "%s", dev); - - struct fb_var_screeninfo info; - int error = ioctl(fd, FBIOGET_VSCREENINFO, &info); - if (error) err(EX_IOERR, "%s", dev); - - frame.width = info.xres; - frame.height = 3 * info.yres / 4; - frame.buffer = mmap( - NULL, sizeof(*frame.buffer) * frame.width * frame.height, - PROT_READ | PROT_WRITE, MAP_SHARED, - fd, 0 - ); - if (frame.buffer == MAP_FAILED) err(EX_IOERR, "%s", dev); - close(fd); - - frame.background = frame.buffer[0]; - atexit(frameClear); -} - -static const uint32_t Magic = 0x864AB572; -static const uint32_t Version = 0; -static const uint32_t FlagUnicode = 1 << 0; -static uint32_t bytes(uint32_t bits) { - return (bits + 7) / 8; -} - -static char *path; -static struct { - uint32_t magic; - uint32_t version; - uint32_t size; - uint32_t flags; - struct { - uint32_t len; - uint32_t size; - uint32_t height; - uint32_t width; - } glyph; -} header; -static uint8_t *glyphs; - -static void fileRead(uint32_t newLen, uint32_t newWidth, uint32_t newHeight) { - FILE *file = fopen(path, "r"); - if (file) { - size_t len = fread(&header, sizeof(header), 1, file); - if (ferror(file)) err(EX_IOERR, "%s", path); - if (len < 1) errx(EX_DATAERR, "%s: truncated header", path); - - } else { - if (errno != ENOENT) err(EX_NOINPUT, "%s", path); - header.magic = Magic; - header.version = Version; - header.size = sizeof(header); - header.flags = 0; - header.glyph.len = newLen; - header.glyph.size = bytes(newWidth) * newHeight; - header.glyph.height = newHeight; - header.glyph.width = newWidth; - } - - if (header.magic != Magic) { - errx(EX_DATAERR, "%s: invalid magic %08X", path, header.magic); - } - if (header.version != Version) { - errx(EX_DATAERR, "%s: unsupported version %u", path, header.version); - } - if (header.flags & FlagUnicode) { - errx(EX_DATAERR, "%s: unsupported unicode table", path); - } - if (header.flags) { - errx(EX_DATAERR, "%s: unsupported flags %08X", path, header.flags); - } - - if (file && header.size > sizeof(header)) { - int error = fseek(file, header.size, SEEK_SET); - if (error) err(EX_IOERR, "%s", path); - - warnx("%s: truncating long header", path); - header.size = sizeof(header); - } - - glyphs = calloc(header.glyph.len, header.glyph.size); - if (!glyphs) err(EX_OSERR, "calloc"); - - if (file) { - size_t len = fread(glyphs, header.glyph.size, header.glyph.len, file); - if (ferror(file)) err(EX_IOERR, "%s", path); - if (len < header.glyph.len) { - errx(EX_DATAERR, "%s: truncated glyphs", path); - } - fclose(file); - } -} - -static void fileWrite(void) { - FILE *file = fopen(path, "w"); - if (!file) err(EX_CANTCREAT, "%s", path); - - fwrite(&header, sizeof(header), 1, file); - if (ferror(file)) err(EX_IOERR, "%s", path); - - fwrite(glyphs, header.glyph.size, header.glyph.len, file); - if (ferror(file)) err(EX_IOERR, "%s", path); - - int error = fclose(file); - if (error) err(EX_IOERR, "%s", path); -} - -static uint8_t *glyph(uint32_t index) { - return &glyphs[header.glyph.size * index]; -} -static uint8_t *bitByte(uint32_t index, uint32_t x, uint32_t y) { - return &glyph(index)[bytes(header.glyph.width) * y + x / 8]; -} -static uint8_t bitGet(uint32_t index, uint32_t x, uint32_t y) { - return *bitByte(index, x, y) >> (7 - x % 8) & 1; -} -static void bitFlip(uint32_t index, uint32_t x, uint32_t y) { - *bitByte(index, x, y) ^= 1 << (7 - x % 8); -} -static void bitSet(uint32_t index, uint32_t x, uint32_t y, uint8_t bit) { - *bitByte(index, x, y) &= ~(1 << (7 - x % 8)); - *bitByte(index, x, y) |= bit << (7 - x % 8); -} - -static void drawGlyph( - uint32_t destX, uint32_t destY, uint32_t scale, uint32_t index, - uint32_t selectX, uint32_t selectY, uint32_t guideX, uint32_t guideY -) { - destX <<= scale; - destY <<= scale; - - for (uint32_t y = 0; y < (header.glyph.height << scale); ++y) { - if (destY + y >= frame.height) break; - for (uint32_t x = 0; x < (header.glyph.width << scale); ++x) { - if (destX + x >= frame.width) break; - - uint32_t glyphX = x >> scale; - uint32_t glyphY = y >> scale; - uint32_t fill = -bitGet(index, glyphX, glyphY); - if (selectX & 1 << glyphX && selectY & 1 << glyphY) fill ^= 0x77; - if (guideX & 1 << glyphX || guideY & 1 << glyphY) fill ^= 0x3300; - - frame.buffer[frame.width * (destY + y) + destX + x] = fill; - } - } -} - -static void drawBorder(uint32_t destX, uint32_t destY, uint32_t scale) { - destX <<= scale; - destY <<= scale; - - for (uint32_t y = 0; y < destY; ++y) { - if (y >= frame.height) break; - uint32_t fill = -(y >> scale & 1) ^ 0x555555; - for (uint32_t x = 0; x < (uint32_t)(1 << scale); ++x) { - if (destX + x >= frame.width) break; - frame.buffer[frame.width * y + destX + x] = fill; - } - } - - for (uint32_t x = 0; x < destX; ++x) { - if (x >= frame.width) break; - uint32_t fill = -(x >> scale & 1) ^ 0x555555; - for (uint32_t y = 0; y < (uint32_t)(1 << scale); ++y) { - if (destY + y >= frame.height) break; - frame.buffer[frame.width * (destY + y) + x] = fill; - } - } -} - -enum { LF = '\n', Esc = '\33', Del = '\177' }; - -static enum { - Normal, - Edit, - Preview, - Discard, -} mode; - -static struct { - uint32_t scale; - uint32_t index; - bool modified; - bool to; - uint32_t from; -} normal; - -static struct { - uint32_t scale; - uint32_t index; - uint32_t x; - uint32_t y; - uint32_t guideX; - uint32_t guideY; - uint8_t *undo; - uint8_t *copy; -} edit = { - .scale = 4, -}; - -static const uint32_t NormalCols = 32; -static void drawNormal(void) { - for (uint32_t i = 0; i < header.glyph.len; ++i) { - drawGlyph( - header.glyph.width * (i % NormalCols), - header.glyph.height * (i / NormalCols), - normal.scale, i, - -(i == normal.index), -(i == normal.index), 0, 0 - ); - } -} - -static void normalDec(uint32_t n) { - if (normal.index >= n) normal.index -= n; -} -static void normalInc(uint32_t n) { - if (normal.index + n < header.glyph.len) normal.index += n; -} -static void normalPrint(const char *prefix) { - if (normal.index <= 256) { - printf( - "%s: %02X '%lc'\n", - prefix, normal.index, (wint_t)CP437[normal.index] - ); - } else { - printf("%s: %02X\n", prefix, normal.index); - } -} - -static void inputNormal(char ch) { - if (normal.to) { - if (ch < header.glyph.len) normal.index = ch; - normalPrint("index"); - normal.to = false; - return; - } - - switch (ch) { - break; case 'q': { - if (!normal.modified) exit(EX_OK); - mode = Discard; - } - break; case 'w': { - fileWrite(); - printf("write: %s\n", path); - normal.modified = false; - } - break; case '-': if (normal.scale) normal.scale--; frameClear(); - break; case '+': normal.scale++; - break; case 'h': normalDec(1); normalPrint("index"); - break; case 'l': normalInc(1); normalPrint("index"); - break; case 'k': normalDec(NormalCols); normalPrint("index"); - break; case 'j': normalInc(NormalCols); normalPrint("index"); - break; case 'f': normal.from = normal.index; normal.to = true; - break; case 047: normal.index = normal.from; normalPrint("index"); - break; case 'y': { - if (!edit.copy) edit.copy = malloc(header.glyph.size); - if (!edit.copy) err(EX_OSERR, "malloc"); - memcpy(edit.copy, glyph(normal.index), header.glyph.size); - normalPrint("copy"); - } - break; case 'e': { - normal.modified = true; - edit.index = normal.index; - if (!edit.undo) edit.undo = malloc(header.glyph.size); - if (!edit.undo) err(EX_OSERR, "malloc"); - memcpy(edit.undo, glyph(edit.index), header.glyph.size); - mode = Edit; - frameClear(); - } - break; case 'i': mode = Preview; frameClear(); - } -} - -static void drawEdit(void) { - drawGlyph( - 0, 0, edit.scale, edit.index, - 1 << edit.x, 1 << edit.y, edit.guideX, edit.guideY - ); - drawBorder(header.glyph.width, header.glyph.height, edit.scale); - drawGlyph( - header.glyph.width << edit.scale, - header.glyph.height << edit.scale, - 0, edit.index, - 0, 0, 0, 0 - ); -} - -static void inputEdit(char ch) { - switch (ch) { - break; case Esc: mode = Normal; frameClear(); - - break; case '-': if (edit.scale) edit.scale--; frameClear(); - break; case '+': edit.scale++; - break; case 'g': edit.guideY ^= 1 << edit.y; - break; case 'G': edit.guideX ^= 1 << edit.x; - - break; case 'h': if (edit.x) edit.x--; - break; case 'l': if (edit.x + 1 < header.glyph.width) edit.x++; - break; case 'k': if (edit.y) edit.y--; - break; case 'j': if (edit.y + 1 < header.glyph.height) edit.y++; - break; case ' ': bitFlip(edit.index, edit.x, edit.y); - - break; case 'r': { - for (uint32_t y = 0; y < header.glyph.height; ++y) { - for (uint32_t x = 0; x < header.glyph.width; ++x) { - bitFlip(edit.index, x, y); - } - } - } - - break; case 'H': { - for (uint32_t x = 0; x < header.glyph.width; ++x) { - for (uint32_t y = 0; y < header.glyph.height; ++y) { - if (x + 1 < header.glyph.width) { - bitSet(edit.index, x, y, bitGet(edit.index, x + 1, y)); - } else { - bitSet(edit.index, x, y, 0); - } - } - } - } - - break; case 'L': { - uint32_t width = header.glyph.width; - for (uint32_t x = width - 1; x < width; --x) { - for (uint32_t y = 0; y < header.glyph.height; ++y) { - if (x - 1 < width) { - bitSet(edit.index, x, y, bitGet(edit.index, x - 1, y)); - } else { - bitSet(edit.index, x, y, 0); - } - } - } - } - - break; case 'K': { - for (uint32_t y = 0; y < header.glyph.height; ++y) { - for (uint32_t x = 0; x < header.glyph.width; ++x) { - if (y + 1 < header.glyph.height) { - bitSet(edit.index, x, y, bitGet(edit.index, x, y + 1)); - } else { - bitSet(edit.index, x, y, 0); - } - } - } - } - - break; case 'J': { - uint32_t height = header.glyph.height; - for (uint32_t y = height - 1; y < height; --y) { - for (uint32_t x = 0; x < header.glyph.width; ++x) { - if (y - 1 < height) { - bitSet(edit.index, x, y, bitGet(edit.index, x, y - 1)); - } else { - bitSet(edit.index, x, y, 0); - } - } - } - } - - break; case 'p': { - if (!edit.copy) break; - memcpy(glyph(edit.index), edit.copy, header.glyph.size); - } - break; case 'u': { - if (!edit.undo) break; - memcpy(glyph(edit.index), edit.undo, header.glyph.size); - } - } -} - -enum { PreviewRows = 8, PreviewCols = 64 }; -static struct { - uint32_t glyphs[PreviewRows * PreviewCols]; - uint32_t index; -} preview; - -static void drawPreview(void) { - for (uint32_t i = 0; i < PreviewRows * PreviewCols; ++i) { - drawGlyph( - header.glyph.width * (i % PreviewCols), - header.glyph.height * (i / PreviewCols), - 0, preview.glyphs[i], - -(i == preview.index), -(i == preview.index), 0, 0 - ); - } -} - -static void inputPreview(char ch) { - switch (ch) { - break; case Esc: mode = Normal; frameClear(); - break; case Del: { - if (preview.index) preview.index--; - preview.glyphs[preview.index] = 0; - } - break; case LF: { - uint32_t tail = PreviewCols - (preview.index % PreviewCols); - memset( - &preview.glyphs[preview.index], - 0, sizeof(preview.glyphs[0]) * tail - ); - preview.index += tail; - } - break; default: preview.glyphs[preview.index++] = ch; - } - preview.index %= PreviewRows * PreviewCols; -} - -static void drawDiscard(void) { - printf("discard modifications? "); - fflush(stdout); -} - -static void inputDiscard(char ch) { - printf("%c\n", ch); - if (ch == 'Y' || ch == 'y') exit(EX_OK); - mode = Normal; -} - -static void draw(void) { - switch (mode) { - break; case Normal: drawNormal(); - break; case Edit: drawEdit(); - break; case Preview: drawPreview(); - break; case Discard: drawDiscard(); - } -} - -static void input(char ch) { - switch (mode) { - break; case Normal: inputNormal(ch); - break; case Edit: inputEdit(ch); - break; case Preview: inputPreview(ch); - break; case Discard: inputDiscard(ch); - } -} - -static struct termios saveTerm; -static void restoreTerm(void) { - tcsetattr(STDIN_FILENO, TCSADRAIN, &saveTerm); -} - -int main(int argc, char *argv[]) { - setlocale(LC_CTYPE, ""); - - uint32_t newLen = 256; - uint32_t newWidth = 8; - uint32_t newHeight = 16; - uint32_t setHeight = 0; - - int opt; - while (0 < (opt = getopt(argc, argv, "H:g:h:w:"))) { - switch (opt) { - break; case 'H': setHeight = strtoul(optarg, NULL, 0); - break; case 'g': newLen = strtoul(optarg, NULL, 0); - break; case 'h': newHeight = strtoul(optarg, NULL, 0); - break; case 'w': newWidth = strtoul(optarg, NULL, 0); - break; default: return EX_USAGE; - } - } - if (!newLen || !newWidth || !newHeight) return EX_USAGE; - if (optind == argc) return EX_USAGE; - - path = strdup(argv[optind]); - fileRead(newLen, newWidth, newHeight); - - if (setHeight) { - if (setHeight < header.glyph.height) { - errx(EX_CONFIG, "cannot decrease height"); - } - - uint32_t setSize = bytes(header.glyph.width) * setHeight; - uint8_t *setGlyphs = calloc(header.glyph.len, setSize); - for (uint32_t i = 0; i < header.glyph.len; ++i) { - memcpy(&setGlyphs[setSize * i], glyph(i), header.glyph.size); - } - free(glyphs); - glyphs = setGlyphs; - - header.glyph.height = setHeight; - header.glyph.size = setSize; - normal.modified = true; - } - - frameOpen(); - frameClear(); - - int error = tcgetattr(STDIN_FILENO, &saveTerm); - if (error) err(EX_IOERR, "tcgetattr"); - atexit(restoreTerm); - - struct termios term = saveTerm; - term.c_lflag &= ~(ICANON | ECHO); - error = tcsetattr(STDIN_FILENO, TCSADRAIN, &term); - if (error) err(EX_IOERR, "tcsetattr"); - - for (;;) { - draw(); - char ch; - ssize_t size = read(STDIN_FILENO, &ch, 1); - if (size < 0) err(EX_IOERR, "read"); - if (!size) return EX_SOFTWARE; - input(ch); - } -} |