From b0b86a30e09c91118e8e87a4fcbfbd94f53150ca Mon Sep 17 00:00:00 2001 From: Jens Schweikhardt Date: Wed, 20 Aug 2025 19:41:47 +0200 Subject: Complete Specials. Implement srctohex in C. --- srctohex.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 srctohex.c (limited to 'srctohex.c') diff --git a/srctohex.c b/srctohex.c new file mode 100644 index 0000000..1f3e5d3 --- /dev/null +++ b/srctohex.c @@ -0,0 +1,191 @@ +/* + * NAME + * srctohex - convert font from src to hex format + * + * EXAMPLE USAGE + * srctohex -w 12 -h 22 < gallant.src > gallant.hex + */ +#include +#include +#include +#include +#include +#include +#include + +#define PixelWidth 12 +#define PixelHeight 22 +#define PixelSet L'Y' +#define PixelClear L' ' +#define LINE_MAX_WCHAR 1024 +#define FULL_BLOCK 0x2588 + +#define STARTCHAR 1 +#define BITMAP 2 +#define ENDCHAR 3 + +void parse_options(int aArgc, char **aArgv); +void usage(int aStatus); +void errx(const char *aFormat, ...); +int parse_startchar(const wchar_t *aLine); +void parse_bitmap(const wchar_t *aLine, int aWidth); +void parse_endchar(const wchar_t *aLine); + +int gWidth = PixelWidth; +int gHeight = PixelHeight; +int gLineNr = 0; +unsigned int gCodepoint = 0; + +int main(int aArgc, char **aArgv) { + if (!setlocale(LC_CTYPE, "")) { + fprintf(stderr, "Can't set the locale. Check LANG, LC_CTYPE, LC_ALL.\n"); + exit(EXIT_FAILURE); + } + int expect = STARTCHAR; + int bitmaps = 0; + int glyphs = 0; + int width = 1; + parse_options(aArgc, aArgv); + printf("# Width: %d\n# Height: %d\n", gWidth, gHeight); + wchar_t wbuf[LINE_MAX_WCHAR]; + while (fgetws(wbuf, LINE_MAX_WCHAR, stdin)) { + ++gLineNr; + switch (expect) { + case STARTCHAR: + width = parse_startchar(wbuf); + expect = BITMAP; + break; + case BITMAP: + parse_bitmap(wbuf, width); + ++bitmaps; + if (bitmaps == gHeight) { + putchar('\n'); + expect = ENDCHAR; + } + break; + case ENDCHAR: + parse_endchar(wbuf); + expect = STARTCHAR; + bitmaps = 0; + ++glyphs; + break; + default: + break; + } + } + if (expect != STARTCHAR) + errx("line %d, glyph U+%04x: incomplete glyph due to early end-of-file\n", gLineNr, gCodepoint); + fprintf(stderr, "found %d glyphs\n", glyphs); + return EXIT_SUCCESS; +} + +// Parse a STARTCHAR directive. +// +int parse_startchar(const wchar_t *aLine) { + if (swscanf(aLine, L"STARTCHAR U+%x", &gCodepoint) == 1) { + printf("%04x:", gCodepoint); + return wcwidth(gCodepoint); + } + errx("line %d: expected 'STARTCHAR U+xxxx', got %ls", gLineNr, aLine); + return 0; +} + +// Parse a |BITMAP| directive. +// +void parse_bitmap(const wchar_t *aLine, int aWidth) { + const wchar_t *delim1 = wcschr(aLine, L'|'); + if (delim1 == NULL) + errx("line %d: initial delimiter '|' not found in %ls; not enough pixel lines?\n", gLineNr, aLine); + + const wchar_t *delim2 = wcschr(delim1 + 1, L'|'); + if (delim2 == NULL) + errx("line %d: final delimiter '|' not found in %ls", gLineNr, aLine); + + const int bits = (delim2 - delim1) - 1; + if (aWidth == 2) { + if (bits != (2 * gWidth)) + errx("line %d, glyph U+%04x: expected %d pixels bewteen || delimiters for double width glyph, found %d\n", gLineNr, + gCodepoint, 2 * gWidth, bits); + } + else { + if (bits != gWidth) + errx("line %d, glyph U+%04x: expected %d pixels bewteen || delimiters for normal width glyph, found %d\n", gLineNr, + gCodepoint, gWidth, bits); + } + + int hex = 0; + aLine = delim1 + 1; + for (int i = 0; i < bits; ++i) { + const int rem = i % 4; + if (aLine[i] == FULL_BLOCK) + hex += (8 >> rem); + else { + if (aLine[i] != L' ') + errx("line %d, glyph U+%04x: pixels must be SPACE or FULL BLOCK U+2588 '%lc', found '%lc'\n", gLineNr, gCodepoint, + FULL_BLOCK, aLine[i]); + } + if (rem == 3) { + putchar("0123456789abcdef"[hex]); + hex = 0; + } + } + /* Pad to octet with zero bits, if any. */ + const int pad = 8 * ((bits + 7) / 8); + for (int i = bits; i < pad; ++i) { + if (i % 4 == 3) { + putchar("0123456789abcdef"[hex]); + hex = 0; + } + } +} + +// Parse an ENDCHAR directive. +// +void parse_endchar(const wchar_t *aLine) { + if (wcscmp(aLine, L"ENDCHAR\n") != 0) + errx("line %d, glyph U+%04x: expected 'ENDCHAR', got %ls", gLineNr, gCodepoint, aLine); +} + +// Parse the command line options. +// +void parse_options(int aArgc, char **aArgv) { + int ch; + while ((ch = getopt(aArgc, aArgv, "w:h:")) != -1) { + switch (ch) { + case 'h': + if (sscanf(optarg, "%d", &gHeight) != 1) + errx("can't convert '%s' to height integer\n", optarg); + break; + case 'w': + if (sscanf(optarg, "%d", &gWidth) != 1) + errx("can't convert '%s' to width integer\n", optarg); + break; + default: + usage(EXIT_FAILURE); + } + } +} + + + +// Output usage message and exit with status. +// +void usage(int aStatus) { + fprintf(stderr, "usage: srctohex [options]\n"); + fprintf(stderr, "Options [default]:\n"); + fprintf(stderr, " -h height height in pixels [%d]\n", PixelHeight); + fprintf(stderr, " -w width width in pixels [%d]\n", PixelWidth); + exit(aStatus); +} + +// Print formatted message on stderr and exit. +// +void errx(const char *aFormat, ...) { + va_list ap; + va_start(ap, aFormat); + vfprintf(stderr, aFormat, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +/* vim: set tabstop=4 shiftwidth=4 expandtab fileformat=unix: */ -- cgit v1.2.3