/* psftools: Manipulate console fonts in the .PSF format Copyright (C) 2003, 2021 John Elliott This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cnvshell.h" #include "psflib.h" /* Compile a textual description (as generated by psf2txt) to a .PSF font. */ static char helpbuf[2048]; static int v1 = 0; static int v2 = 0; static PSF_FILE psf; /* Program name */ char *cnv_progname = "TXT2PSF"; /* ddash = 1 if option started with a double-dash; else 0 */ /* Return NULL if OK, else error string */ char *cnv_set_option(int ddash, char *variable, char *value) { if (!stricmp(variable, "psf1")) { v1 = 1; return NULL; } if (!stricmp(variable, "psf2")) { v2 = 1; return NULL; } if (strlen(variable) > 2000) variable[2000] = 0; sprintf(helpbuf, "Unknown option: %s\n", variable); return helpbuf; } /* Return help string */ char *cnv_help(void) { sprintf(helpbuf, "Syntax: %s textfile psffile { options }\n\n", cnv_progname); strcat (helpbuf, "Options:\n\n" "--psf1: Save in PSF1 format.\n" "--psf2: Save in PSF2 format.\n"); return helpbuf; } #define ATSTART 0 #define INHEADER 1 #define INCHAR 2 #define INBITMAP 3 char *cnv_execute(FILE *infile, FILE *outfile) { int rv, n, x = 0, y = 0; int state = 0; char linebuf[2000]; char unibuf[2000]; char *c; int version = -1, flags = -1, length = -1, width = -1, height = -1; int nchar = 0; int line = 0, wb = 0, havebitmap = 0; psf_byte *charbits = NULL; psf_file_new(&psf); while (fgets(linebuf, sizeof(linebuf), infile)) { ++line; /* If a long line, devour the rest of it */ if (!strchr(linebuf, '\n')) { do { n = fgetc(infile); } while (n != EOF && n != '\n'); } c = strchr(linebuf, '\n'); if (c) *c = 0; c = strstr(linebuf, "//"); if (c) *c = 0; if (linebuf[0] == 0) continue; if (linebuf[0] == '%') { if (!strncmp(linebuf + 1, "PSF2", 4) && state == ATSTART) { state = INHEADER; continue; } /* %STOP: Immediately stop parsing */ else if (!strncmp(linebuf + 1, "STOP", 4)) { break; } else if (state == INHEADER) { if (version == -1) return "Version not set"; if (flags == -1) return "Flags not set"; if (width == -1) return "Width not set"; if (height == -1) return "Height not set"; if (length == -1) return "Length not set"; if (version > 0) return "Versions greater than 0 are not supported"; rv = psf_file_create(&psf, width, height, length, (flags & 1)); if (!rv) { charbits = malloc(psf.psf_charlen); if (!charbits) rv = PSF_E_NOMEM; } if (rv) return psf_error_string(rv); state = INCHAR; unibuf[0] = 0; wb = ((width + 7) / 8); } else if (state == INCHAR || state == INBITMAP) { if (version == -1) return "Version not set"; if (nchar < psf.psf_length) memcpy (psf.psf_data + nchar * psf.psf_charlen, charbits, psf.psf_charlen); if (unibuf[0]) { rv = psf_unicode_from_string(&psf, nchar, unibuf); if (rv) { fprintf(stderr, "Line %d: Failed to decode %s\n", line, unibuf); return psf_error_string(rv); } } havebitmap = 0; state = INCHAR; nchar++; unibuf[0] = 0; } else { fprintf(stderr, "Line %d: Unexpected %% line\n", line); return "Invalid input format"; } } else { c = strstr(linebuf, ": "); if (c) { *c = 0; c++; while (*c == ' ') c++; if (state == INHEADER) { if (!strcmp(linebuf, "Version")) version = atol(c); else if (!strcmp(linebuf, "Flags")) flags = atol(c); else if (!strcmp(linebuf, "Width")) width = atol(c); else if (!strcmp(linebuf, "Height")) height = atol(c); else if (!strcmp(linebuf, "Length")) length = atol(c); else { fprintf(stderr, "Line %d: Unknown variable name '%s'\n", line, linebuf); return "Invalid input format"; } } else if (state == INCHAR) { if (!strcmp(linebuf, "Unicode")) strcpy(unibuf, c); else if (!strcmp(linebuf, "Bitmap")) { memmove(linebuf, c, 1 + strlen(c)); state = INBITMAP; havebitmap = 0; x = y = 0; } else { fprintf(stderr, "Line %d: Unknown variable name '%s'\n", line, linebuf); return "Invalid input format"; } } else /* Not INCHAR and not INHEADER */ { fprintf(stderr, "Line %d: Unknown variable name '%s'\n", line, linebuf); return "Invalid input format"; } if (state != INBITMAP) continue; } /* end if (c) */ if (state == INBITMAP) { psf_byte *dest, mask; c = linebuf; while (*c) { if (*c != '-' && *c != '#') { c++; continue; } dest = charbits + (y * wb) + (x/8); mask = 0x80 >> (x & 7); if (*c == '#') *dest |= mask; else *dest &= ~mask; x++; if (x >= psf.psf_width) { x = 0; y++; } if (y >= psf.psf_height) { state = INCHAR; havebitmap = 1; break; } ++c; } continue; } fprintf(stderr, "Line %d: Not a Variable: Value pair\n", line); return "Invalid input format"; } } if (state == INCHAR && havebitmap) { if (nchar < psf.psf_length) memcpy(psf.psf_data + nchar * psf.psf_charlen, charbits, psf.psf_charlen); if (unibuf[0]) { rv = psf_unicode_from_string(&psf, nchar, unibuf); if (rv) return psf_error_string(rv); } } if (v1) psf_force_v1(&psf); if (v2) psf_force_v2(&psf); rv = psf_file_write(&psf, outfile); psf_file_delete(&psf); if (rv) return psf_error_string(rv); return NULL; }