#ifndef lint static char rcsid[] = "$Header$"; #endif /* * checkw -- check & fix the TFM widths in a PXL file * * Usage: checkw [-f] [-s] tfmfile pxlfile */ #include #include #include #include "../h/types.h" #include "../h/fio.h" char *ProgName; struct tfmheader { int th_lf; /* length of the file (words) */ int th_lh; /* length of the header data (words) */ int th_bc; /* smallest char code in font */ int th_ec; /* largest char code in font (inclusive) */ int th_nw; /* number of words in width table */ int th_nh; /* number of words in height table */ int th_nd; /* number of words in depth table */ int th_ni; /* number of words in ital. corr. table */ int th_nl; /* number of words in lig/kern table */ int th_nk; /* number of words in kern table */ int th_ne; /* number of words in extensible char table */ int th_np; /* number of font param words */ }; /* * The rest of the TFM file is composed of the following information, * all of which are 32 bit quantities: * * header: array [0..lh-1] of stuff * char_info: array [bc..ec] of char_info_word * width: array [0..nw-1] of fix_word * height: array [0..nh-1] of fix_word * depth: array [0..nd-1] of fix_word * italic: array [0..ni-1] of fix_word * lig_kern: array [0..nl-1] of lig_kern_command * kern: array [0..nk-1] of fix_word * exten: array [0..ne-1] of extensible_recipie * param: array [1..np] of fix_word * * We are interested only in the width information. This can be * found by taking the first byte of each of the char_info_words * and using it as an index in the width table. That is, the * width of character $n$ is width[char_info[$n$-$bc$].width_index]. */ struct char_info_word { char width_index; char height_and_depth_index; char italic_index_and_tag; char remainder; }; /* * A PXL file ends with 2068 bytes of information which includes the * TFM widths and some other stuff (some of which we don't need, some * of which we do; it's easiest to just read it all). */ #define PXBUFSIZE 2068 #define PXL_ID 1001 #define PXIDOFF 2064 /* PXL_ID found here */ #define PXTFMOFF(n) (((n) << 4) + 12)/* TFM width of char $n$ here */ int FFlag; /* -f => fix */ int SFlag; /* -s => silent */ int QFlag; /* -q => quiet (like -s if match) */ char *tfname; /* name of the TFM file */ FILE *tf; /* the TFM file */ char *pxname; /* name of the PXL file */ int px; /* we don't use stdio on the pxl file */ char pxbuf[PXBUFSIZE]; /* the tail of the PXL file */ long pxtailoff; /* tells where pxbuf goes */ struct tfmheader th; /* the TFM file's header information */ i32 *width; /* the TFM width tables */ struct char_info_word *char_info;/* the TFM character info tables */ #define WIDTH(c) width[char_info[(c) - th.th_bc].width_index] extern char *optarg; extern int optind; extern int errno; char *malloc (); long lseek (); /* * Exit stati. */ #define EX_OK 0 /* all is well in fontland */ #define EX_NOMATCH 1 /* didn't match, didn't update PXL file */ #define EX_OTHER 2 /* other error (invalid command, etc.) */ main (argc, argv) register int argc; register char **argv; { register int c; ProgName = argv[0]; while ((c = getopt (argc, argv, "fqs")) != EOF) { switch (c) { case 'f': FFlag++; break; case 'q': QFlag++; break; case 's': SFlag++; break; case '?': usage: error (EX_OTHER, 0, "usage: %s [-f] [-s] tfmfile pxlfile", ProgName); /*NOTREACHED*/ } } if (argc - optind != 2) goto usage; tfname = argv[optind]; pxname = argv[optind + 1]; if ((tf = fopen (tfname, "r")) == NULL) error (EX_OTHER, errno, "can't open %s for reading", tfname); if ((px = open (pxname, FFlag ? 2 : 0)) < 0) error (EX_OTHER, errno, "can't open %s for %s", pxname, FFlag ? "update" : "reading"); ReadPXLTail (); ReadTFMHeader (); if (th.th_ec < th.th_bc) error (EX_OTHER, 0, "\ Are you sure %s is a TFM file? It contains no characters!", tfname); if (th.th_bc < 0 || th.th_ec > 127) error (EX_OTHER, 0, "\ I don't see how %s can correspond to your PXL file.\n\ (It has a first character entry of %d, and a last of %d.)", tfname, th.th_bc, th.th_ec); AllocateCharTable (th.th_ec - th.th_bc + 1); AllocateWidthTable (th.th_nw); SkipHeader (); ReadCharInfo (th.th_ec - th.th_bc + 1); ReadWidthTable (th.th_nw); if (WidthsMatch ()) { if (!SFlag && !QFlag) printf ("%s: width tables for %s match %s\n", ProgName, pxname, tfname); exit (EX_OK); } if (!FFlag) { if (!SFlag) printf ("%s: width tables for %s and %s do not match\n", ProgName, pxname, tfname); exit (EX_NOMATCH); } if (!SFlag) printf ("%s: width tables for %s and %s do not match; updating...\n", ProgName, pxname, tfname); FixPXLTail (); WritePXLTail (); if (!SFlag) printf ("%s: width tables in %s updated.\n", ProgName, pxname); exit (EX_OK); } /* * Called if the TFM file seems to be bogus. */ BadTFMFile () { error (EX_OTHER, 0, "unexpected EOF -- are you sure %s is a TFM file?", tfname); /* NOTREACHED */ } /* * Allocate n character info table entries. */ AllocateCharTable (n) register int n; { char_info = (struct char_info_word *) malloc ((unsigned) n * sizeof *char_info); if (char_info == 0) error (EX_OTHER, errno, "unable to allocate %d char table entries", n); } /* * Allocate n width table entries. */ AllocateWidthTable (n) register int n; { width = (i32 *) malloc ((unsigned) n * sizeof *width); if (width == 0) error (EX_OTHER, errno, "unable to allocate %d width table entries", n); } /* * Read the TFM header. */ ReadTFMHeader () { register int *ip, i; for (ip = &th.th_lf; ip <= &th.th_np;) { i = UnSign16 (GetWord (tf)); *ip++ = i; /* ``cheating'' */ } /* We could do something nice like make sure the actual file size and the reported size (tf.tf_lf * 4?) are the same... naaah. */ } /* * Skip over the miscellaneous header info in the TFM file. */ SkipHeader () { (void) fseek (tf, (long) th.th_lh * sizeof (i32), 1); } /* * Read the character info table from the TFM file. (We get all * of it, even though we're only going to use the width index.) */ ReadCharInfo (n) register int n; { register struct char_info_word *ci; for (ci = char_info; --n >= 0; ci++) { ci -> width_index = getc (tf); ci -> height_and_depth_index = getc (tf); ci -> italic_index_and_tag = getc (tf); ci -> remainder = getc (tf); } if (feof (tf)) BadTFMFile (); } /* * Read the width table from the TFM file. */ ReadWidthTable (n) register int n; { register i32 *ip; for (ip = width; --n >= 0; ip++) fGetLong (tf, *ip); if (feof (tf)) BadTFMFile (); } /* * Get a 32 bit quantity from the specified offset in the pxl buffer. */ i32 GetPXLong (off) { register char *p = pxbuf + off; register i32 rv; rv = UnSign8 (*p++) << 24; rv |= UnSign8 (*p++) << 16; rv |= UnSign8 (*p++) << 8; rv |= UnSign8 (*p); return rv; } /* * Put the specified value in the pxl buffer at the given offset. * N.B.: assuming 8 bit bytes (since val >> n might be signed). */ PutPXLong (off, val) int off; register i32 val; { register char *p = pxbuf + off; *p++ = val >> 24; *p++ = val >> 16; *p++ = val >> 8; *p = val; } /* * Read (and verify) the end part of the pxl file. */ ReadPXLTail () { struct stat st; if (fstat (px, &st)) error (EX_OTHER, errno, "fstat(%s)", px, pxname); if (st.st_size & 3 || st.st_size < PXBUFSIZE) error (EX_OTHER, 0, "%s doesn't seem to be a pxl file", pxname); pxtailoff = st.st_size - PXBUFSIZE; if (lseek (px, pxtailoff, 0) != pxtailoff) error (EX_OTHER, errno, "lseek(%s) didn't return %ld", pxname, pxtailoff); if (read (px, pxbuf, PXBUFSIZE) != PXBUFSIZE) error (EX_OTHER, errno, "read(%s)", pxname); if (GetPXLong (PXIDOFF) != PXL_ID) error (EX_OTHER, 0, "%s doesn't seem to be a PXL file.", pxname); } /* * Write the end part of the PXL file back to the original PXL file. */ WritePXLTail () { if (lseek (px, pxtailoff, 0) != pxtailoff) error (EX_OTHER, errno, "lseek(%s) didn't return %ld", pxname, pxtailoff); if (write (px, pxbuf, PXBUFSIZE) != PXBUFSIZE) error (EX_OTHER, errno, "write(%s) failed---pxl file may be damaged", pxname); } /* * Compare the width values in the PXL tail buffer with those in the * TFM width tables. Return 1 iff they all match. */ WidthsMatch () { register int i; for (i = th.th_bc; i <= th.th_ec; i++) if (GetPXLong (PXTFMOFF (i)) != WIDTH (i)) return 0; /* a mismatch */ /* perhaps we should make sure the rest are 0... oh well */ return 1; } /* * Fix the width values in the PXL file tail buffer. */ FixPXLTail () { register int i; for (i = th.th_bc; i <= th.th_ec; i++) PutPXLong (PXTFMOFF (i), WIDTH (i)); }