summaryrefslogtreecommitdiff
path: root/dviware/umddvi/misc/checkw.c
blob: d318b7e11b84ca279453b4ea4364275f04148b03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
#ifndef lint
static char rcsid[] = "$Header$";
#endif

/*
 * checkw -- check & fix the TFM widths in a PXL file
 *
 * Usage: checkw [-f] [-s] tfmfile pxlfile
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#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));
}