/* mkfont * * read files of the following format and outputs a bunch of DECLE * directives for the resulting font. Outputs a complete GRAM image * (512 decles == 64 characters * 8 decles/character). A grom image may * be generated by specifying a '-' as the first argument to the program. * * CHAR 'X' * ##...##. * ##...##. * .##.##.. * ..###... * ..###... * .##.##.. * ##...##. * ........ * * or * * CHAR # 88 * ##...##. * ##...##. * .##.##.. * ..###... * ..###... * .##.##.. * ##...##. * ........ * * Exactly 8 lines must follow a CHAR directive. Dots/spaces/0 * become zero-bits, everything else becomes 1-bits. Short lines are * padded with zero-bits. Characters beyond the 8th position are ignored. * Leading whitespace IS NOT. Nothing intelligent is done with tabs. * * An offset 32 is subtracted from the ASCII value for the character by * default. This can be changed with an "OFFSET" directive. All character * numbers are taken modulo 64. (Note: The offset is reset to 32 for each * file.) */ #include #include #include #include int offset = 32; int numchars = 64; #define NA (-10000) int font[256 * 8]; int name[256]; char buf1[1024]; char buf2[1024]; int handle_char(FILE *f, int chnum, int numeric) { int i, j, idx, eof = 0; unsigned row; char cbuf[9], *s; idx = (((unsigned)chnum - offset) % numchars) << 3; name[idx >> 3] = numeric ? ~chnum : chnum; for (i = 0; i < 8; i++, idx++) { if (fgets(buf1, 1024, f) == NULL) { eof = -1; buf1[0] = '\0'; } buf1[8] = 0; /* trim trailing newline */ s = buf1; while (*s) { if (*s == '\n' || *s == '\r') *s = 0; else s++; } sprintf(cbuf, "%-.8s", buf1); for (j = row = 0; j < 8; j++) { row <<= 1; if (cbuf[j] != '.' && cbuf[j] != ' ' && cbuf[j] != '0') row++; } font[idx] = row; } return eof; } void trim_whitespace(void) { char *s1; s1 = buf1; while (isspace(*s1)) s1++; strncpy(buf2, s1, sizeof(buf2)); s1 = buf2 + strlen(buf2) - 1; while (s1 > buf2 && isspace(*s1)) s1--; *++s1 = 0; } int main(int argc, char *argv[]) { FILE * f; char cval = 0; int val = 0; int eof = 0; int skip = 0; int decle = 0, chars = 0; int lineno; int i, j, k, idx; int suppress = 0; int rle_ok = 0; int gramfont = 1; int font16 = 1; char * fontname = "FONT"; if (argc == 1 || (argc==2 && argv[1][0] == '-')) { fprintf(stderr, "usage: mkfont [-] in1 [in2 [...]]" " > font.asm\n"); exit(1); } if (argv[1][0] == '-') { numchars = 256; argv++; } gramfont = numchars == 64; if (gramfont) { for (i = 0; i < 256; i++) name[i] = NA; for (i = 0; i < 256 * 8; i++) font[i] = NA; } else { for (i = 0; i < 256; i++) name[i] = ~i; for (i = 0; i < 256 * 8; i++) font[i] = 0; } while (*++argv) { f = fopen(argv[0], "r"); if (!f) { perror("fopen()"); fprintf(stderr, "Could not open %s for reading.\n", argv[0]); exit(1); } offset = 32; lineno = 0; eof = 0; fprintf(stderr, "Processing file: %s\n", argv[0]); while (!eof && fgets(buf1, 1024, f) != NULL) { lineno++; trim_whitespace(); if (buf2[0] == ';' || strlen(buf2) == 0) continue; if (sscanf(buf2, "CHAR '%c'", &cval) == 1) { eof = handle_char(f, cval, 0); lineno += 8; } else if (sscanf(buf2, "CHAR # %d", &val) == 1) { eof = handle_char(f, val, 1); lineno += 8; } else if (sscanf(buf2, "OFFSET %d", &val) == 1) { offset = val; } else if (!strncmp(buf2, "FONT ", 5)) { fontname = strdup(buf2 + 5); fprintf(stderr, "Font name: '%s'\n", fontname); } else { fprintf(stderr, "Warning: Ignoring line %d " "of file %s\n", lineno, argv[0]); } } fclose(f); } fprintf(stderr, "Generating font.\n"); if (gramfont) printf("%s: PROC\n", fontname); else printf(" ORG $3000\nGROM: PROC\n"); for (i = 0; i < numchars; i++) { if (gramfont && name[i] == NA) { skip++; continue; } if (gramfont && (skip || !i)) { int span; for (j = i + 1; j < numchars; j++) if (name[j] == NA) break; span = j - i; printf(";; Skipped %d indices.\n", skip); printf(";; Encoding span of %d %s\n", span, span != 1 ? "entries" : "entry"); /* We output skip * 8 since it makes the ASM easier */ /* Likewise for span length. This works because */ /* neither can get larger than 64. */ if (font16) { unsigned int x; x = (0xFF00 & (skip << 8)) | (0x00FF & span); x = (0xFFF8 & (x << 3)) | (0x0007 & (x >> 13)); printf(" DECLE $%.4X\n\n", x); decle++; } else { printf(" DECLE $%.3X, $%.3X\n\n", skip*8, span*8); decle += 2; } skip = 0; } if (name[i] < 0) printf(";; Character #%d, GR%cM character index %d\n", ~name[i], gramfont ?'A':'O', i); else printf(";; Character '%c', GR%cM character index %d\n", name[i], gramfont ? 'A':'O', i); chars++; if (font16) { for (j = 0, idx = i << 3; j < 8; j += 2, idx += 2) { printf(" DECLE $%.4X ;", ((0xFF & font[idx + 1]) << 8) | (0xFF & font[idx])); for (k = 7; k >= 0; k--) putchar((1 & (font[idx ] >> k))?'#':'.'); putchar('\n'); printf("; - - - ;"); for (k = 7; k >= 0; k--) putchar((1 & (font[idx + 1] >> k))?'#':'.'); putchar('\n'); decle++; } } else { for (j = 0, idx = i << 3; j < 8; j++, idx++) { printf(suppress > 0 ? "; - - - " : " DECLE "); if (rle_ok && suppress <= 0) { decle++; for(suppress = 0; suppress < 3; suppress++) if (font[idx] != font[1+idx+suppress]) break; printf(" $%.3X ; ", (suppress << 8) | font[idx]); } else { suppress--; printf(" $%.3X ; ", font[idx]); } for (k = 7; k >= 0; k--) putchar((1 & (font[idx] >> k))?'#':'.'); putchar('\n'); } } putchar('\n'); } printf("\n;; End of font.\n"); if (gramfont) { if (font16) { printf(" DECLE $0000\n\n"); decle++; } else { printf(" BYTE $00, $00\n\n"); decle += 2; } } printf(";; Total chars: %10d characters\n", chars); printf(";; Total length: %10d decles\n", decle); printf(";; Decles/char: %10.3f decles/character\n", (double)decle/chars); printf(" ENDP\n"); return 0; }