/* * psfxtable.c * * Manipulate headers and Unicode tables for psf fonts * * Copyright (C) 1999 Andries E. Brouwer * derived from sources that were * Copyright (C) 1994 H. Peter Anvin * * This program may be freely copied under the terms of the GNU * General Public License (GPL), version 2, or at your option * any later version. */ #include "config.h" #include #include #include #include #include #include "nls.h" #include "version.h" #include "psf.h" #include "xmalloc.h" #include "psffontop.h" /* * call: psfxtable -i infont -o outfont -it intable -ot outtable * psfaddtable infont intable [outfont] * psfgettable infont [outtable] * psfstriptable infont [outfont] * * When outfont is requested it will get psf1 header when * infont had psf1 header and intable does not have sequences * and psf2 header otherwise. */ /* * Parse humanly readable unicode table. * Format: lines * * or * * or * * where * :: | * :: | , * :: U+ * :: * :: - * Blank lines and lines starting with # are ignored. */ struct unicode_list *uclistheads; static void addpair(int fontpos, unsigned int uc) { struct unicode_list *ul; struct unicode_seq *us; ul = xmalloc(sizeof(struct unicode_list)); us = xmalloc(sizeof(struct unicode_seq)); us->uc = uc; us->prev = us; us->next = NULL; ul->seq = us; ul->prev = uclistheads[fontpos].prev; ul->prev->next = ul; ul->next = NULL; uclistheads[fontpos].prev = ul; } static void addseq(int fontpos, unsigned int uc) { struct unicode_list *ul; struct unicode_seq *us; ul = uclistheads[fontpos].prev; us = xmalloc(sizeof(struct unicode_seq)); us->uc = uc; us->prev = ul->seq->prev; us->prev->next = us; us->next = NULL; ul->seq->prev = us; } static int getunicode(char **p0) { char *p = *p0; while (*p == ' ' || *p == '\t') p++; if (*p != 'U' || p[1] != '+' || !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) || !isxdigit(p[5]) || isxdigit(p[6])) return -1; *p0 = p + 6; return strtol(p + 2, 0, 16); } static void parse_itab_line(char *buf, int fontlen) { char *p, *p1; int i; long fp0, fp1, un0, un1; if ((p = strchr(buf, '\n')) != NULL) *p = 0; else { char *u = _("%s: Warning: line too long\n"); fprintf(stderr, u, progname); exit(EX_DATAERR); } p = buf; while (*p == ' ' || *p == '\t') p++; if (!*p || *p == '#') return; fp0 = strtol(p, &p1, 0); if (p1 == p) { char *u = _("%s: Bad input line: %s\n"); fprintf(stderr, u, progname, buf); exit(EX_DATAERR); } p = p1; if (*p == '-') { p++; fp1 = strtol(p, &p1, 0); if (p1 == p) { char *u = _("%s: Bad input line: %s\n"); fprintf(stderr, u, progname, buf); exit(EX_DATAERR); } p = p1; } else fp1 = 0; if (fp0 < 0 || fp0 >= fontlen) { char *u = _("%s: Glyph number (0x%lx) past end of font\n"); fprintf(stderr, u, progname, fp0); exit(EX_DATAERR); } if (fp1 && (fp1 < fp0 || fp1 >= fontlen)) { char *u = _("%s: Bad end of range (0x%lx)\n"); fprintf(stderr, u, progname, fp1); exit(EX_DATAERR); } if (fp1) { /* we have a range; expect the word "idem" or a Unicode range of the same length */ while (*p == ' ' || *p == '\t') p++; if (!strncmp(p, "idem", 4)) { for (i = fp0; i <= fp1; i++) addpair(i, i); p += 4; } else { un0 = getunicode(&p); while (*p == ' ' || *p == '\t') p++; if (*p != '-') { char *u = _("%s: Corresponding to a range of " "font positions, there should be " "a Unicode range\n"); fprintf(stderr, u, progname); exit(EX_DATAERR); } p++; un1 = getunicode(&p); if (un0 < 0 || un1 < 0) { char *u = _("%s: Bad Unicode range " "corresponding to font position " "range 0x%x-0x%x\n"); fprintf(stderr, u, progname, fp0, fp1); exit(EX_DATAERR); } if (un1 - un0 != fp1 - fp0) { char *u = _("%s: Unicode range U+%x-U+%x not " "of the same length as font " "position range 0x%x-0x%x\n"); fprintf(stderr, u, progname, un0, un1, fp0, fp1); exit(EX_DATAERR); } for (i = fp0; i <= fp1; i++) addpair(i, un0 - fp0 + i); } /* not idem */ } else { /* no range */ while ((un0 = getunicode(&p)) >= 0) { addpair(fp0, un0); while (*p++ == ',' && (un1 = getunicode(&p)) >= 0) { addseq(fp0, un1); } p--; } while (*p == ' ' || *p == '\t') p++; if (*p && *p != '#') { char *u = _("%s: trailing junk (%s) ignored\n"); fprintf(stderr, u, progname, p); } } } static void read_itable(FILE *itab, int fontlen, struct unicode_list **uclistheadsp) { char buf[65536]; int i; if (uclistheadsp) { *uclistheadsp = xrealloc(*uclistheadsp, fontlen * sizeof(struct unicode_list)); for (i = 0; i < fontlen; i++) { struct unicode_list *up = &((*uclistheadsp)[i]); up->next = NULL; up->seq = NULL; up->prev = up; } while (fgets(buf, sizeof(buf), itab) != NULL) parse_itab_line(buf, fontlen); } } int debug = 0; int main(int argc, char **argv) { char *ifname, *ofname, *itname, *otname; FILE *ifil, *ofil, *itab, *otab; int psftype, fontlen, charsize, hastable, notable; int i; int width = 8, bytewidth, height; char *inbuf, *fontbuf; int inbuflth, fontbuflth; set_progname(argv[0]); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE_NAME, LOCALEDIR); textdomain(PACKAGE_NAME); if (argc == 2 && !strcmp(argv[1], "-V")) print_version_and_exit(); ifil = ofil = itab = otab = NULL; ifname = ofname = itname = otname = NULL; fontbuf = NULL; notable = 0; if (!strcmp(progname, "psfaddtable")) { /* Do not send binary data to stdout without explicit "-" */ if (argc != 4) { char *u = _("Usage:\n\t%s infont intable outfont\n"); fprintf(stderr, u, progname); exit(EX_USAGE); } ifname = argv[1]; itname = argv[2]; ofname = argv[3]; } else if (!strcmp(progname, "psfgettable")) { if (argc < 2 || argc > 3) { char *u = _("Usage:\n\t%s infont [outtable]\n"); fprintf(stderr, u, progname); exit(EX_USAGE); } ifname = argv[1]; otname = (argc == 3) ? argv[2] : "-"; } else if (!strcmp(progname, "psfstriptable")) { /* Do not send binary data to stdout without explicit "-" */ if (argc != 3) { char *u = _("Usage:\n\t%s infont outfont\n"); fprintf(stderr, u, progname); exit(EX_USAGE); } ifname = argv[1]; ofname = argv[2]; notable = 1; } else { for (i = 1; i < argc; i++) { if ((!strcmp(argv[i], "-i") || !strcmp(argv[i], "-if")) && i < argc - 1) ifname = argv[++i]; else if ((!strcmp(argv[i], "-o") || !strcmp(argv[i], "-of")) && i < argc - 1) ofname = argv[++i]; else if (!strcmp(argv[i], "-it") && i < argc - 1) itname = argv[++i]; else if (!strcmp(argv[i], "-ot") && i < argc - 1) otname = argv[++i]; else if (!strcmp(argv[i], "-nt")) notable = 1; else break; } if (i < argc || argc <= 1) { char *u = _("Usage:\n\t%s [-i infont] [-o outfont] " "[-it intable] [-ot outtable] [-nt]\n"); fprintf(stderr, u, progname); exit(EX_USAGE); } } if (!ifname) ifname = "-"; if (!strcmp(ifname, "-")) ifil = stdin; else { ifil = fopen(ifname, "r"); if (!ifil) { perror(ifname); exit(EX_NOINPUT); } } if (!itname) /* nothing */; else if (!strcmp(itname, "-")) itab = stdin; else { itab = fopen(itname, "r"); if (!itab) { perror(itname); exit(EX_NOINPUT); } } /* Refuse ifil == itab == stdin ? Perhaps not. */ if (!ofname) /* nothing */; else if (!strcmp(ofname, "-")) ofil = stdout; else { ofil = fopen(ofname, "w"); if (!ofil) { perror(ofname); exit(EX_CANTCREAT); } } if (!otname) /* nothing */; else if (!strcmp(otname, "-")) otab = stdout; else { otab = fopen(otname, "w"); if (!otab) { perror(otname); exit(EX_CANTCREAT); } } if (readpsffont(ifil, &inbuf, &inbuflth, &fontbuf, &fontbuflth, &width, &fontlen, 0, itab ? NULL : &uclistheads) == -1) { char *u = _("%s: Bad magic number on %s\n"); fprintf(stderr, u, progname, ifname); exit(EX_DATAERR); } fclose(ifil); charsize = fontbuflth / fontlen; bytewidth = (width + 7) / 8; if (!bytewidth) bytewidth = 1; height = charsize / bytewidth; hastable = (uclistheads != NULL); if (PSF1_MAGIC_OK((unsigned char *)inbuf)) { psftype = 1; } else if (PSF2_MAGIC_OK((unsigned char *)inbuf)) { psftype = 2; } else { char *u = _("%s: psf file with unknown magic\n"); fprintf(stderr, u, progname); exit(EX_DATAERR); } if (itab) { read_itable(itab, fontlen, &uclistheads); fclose(itab); } if (otab) { struct unicode_list *ul; struct unicode_seq *us; char *sep; if (!hastable) { char *u = _("%s: input font does not have an index\n"); fprintf(stderr, u, progname); exit(EX_DATAERR); } fprintf(otab, "#\n# Character table extracted from font %s\n#\n", ifname); for (i = 0; i < fontlen; i++) { fprintf(otab, "0x%03x\t", i); sep = ""; ul = uclistheads[i].next; while (ul) { us = ul->seq; while (us) { fprintf(otab, "%sU+%04x", sep, us->uc); us = us->next; sep = ", "; } ul = ul->next; sep = " "; } fprintf(otab, "\n"); } fclose(otab); } if (ofil) { writepsffont(ofil, fontbuf, width, height, fontlen, psftype, notable ? NULL : uclistheads); fclose(ofil); } return EX_OK; }