|
|
1.1 root 1: /* $Header: fc.c,v 1.4 87/07/24 14:50:35 toddb Exp $ */
2:
3: #include <stdio.h>
4: #include <sys/file.h>
5: #include <errno.h>
6: /* #include <malloc.h> */ extern char *malloc(), *realloc();
7:
8: #include "misc.h"
9: #include "X.h"
10: #include "Xproto.h"
11: #include "fontstruct.h"
12: #include "font.h"
13:
14: #include "fc.h" /* used by converters only */
15:
16: /*
17: * DESCRIPTION
18: * pure filter; filename argument only
19: *
20: * DISCLAIMER
21: * not much thought has been given to error recovery.
22: */
23: #define INDICES 256
24: #define MAXENCODING 0xFFFF
25:
26: extern char *gets(), *index();
27:
28: static char *myname; /* initialized from argv[0] */
29: static char *currentfont;
30:
31: int linenum = 0; /* for error messages */
32: int or_glyphPad = 0; /* override glyphPading?? */
33: int or_bitorder = 0; /* override bitorder?? */
34:
35:
36: int glyphPad = DEFAULTGLPAD;
37: int bitorder = DEFAULTBITORDER;
38:
39: /*
40: * read the next line and keep a count for error messages
41: */
42: char *
43: getline(s)
44: char *s;
45: {
46: s = gets(s);
47: linenum++;
48: while (s) {
49: int len = strlen(s);
50: if (len && s[len-1] == '\015')
51: s[--len] = '\0';
52: if ((len==0) || prefix(s, "COMMENT")) {
53: s = gets(s);
54: linenum++;
55: } else break;
56: }
57: return(s);
58: }
59:
60: /*
61: * malloc and copy a string value. Handle quoted strings.
62: */
63: char *
64: remember(s)
65: char *s;
66: {
67: char *p, *pp;
68:
69: /* strip leading white space */
70: while (*s && (*s == ' ' || *s == '\t'))
71: s++;
72: if (*s == 0)
73: return "";
74: if (*s != '"') {
75: pp = s;
76: /* no white space in value */
77: for (pp=s; *pp; pp++)
78: if (*pp == ' ' || *pp == '\t' || *pp == '\015' || *pp == '\n') {
79: *pp = 0;
80: break;
81: }
82: p = malloc(strlen(s)+1);
83: strcpy(p, s);
84: return p;
85: }
86: /* quoted string: strip outer quotes and undouble inner quotes */
87: s++;
88: pp = p = malloc(strlen(s)+1);
89: while (*s) {
90: if (*s == '"') {
91: if (*(s+1) != '"') {
92: *p++ = 0;
93: return pp;
94: } else {
95: s++;
96: }
97: }
98: *p++ = *s++;
99: }
100: *p++ = 0; /* just in case; space for it allocated above */
101: return pp;
102: }
103:
104: /*
105: * Invert bit order within each BYTE of an array.
106: * "In" and "out" may point to the same array.
107: */
108: void
109: bitorderinvert( in, out, nbytes)
110: register unsigned char *in;
111: register unsigned char *out;
112: register int nbytes;
113: {
114: static int BOTableInitialized = 0;
115: static unsigned char BOTable[256];
116:
117:
118: if ( !BOTableInitialized)
119: {
120: int btabi;
121: int biti;
122:
123: for ( btabi=0; btabi<256; btabi++)
124: for ( biti=0; biti<8; biti++)
125: if (btabi & 1<<biti)
126: BOTable[btabi] |= (unsigned)0x80 >> biti;
127: BOTableInitialized++;
128: }
129: while ( nbytes--)
130: *out++ = BOTable[ *in++];
131:
132: }
133:
134: /*
135: * return TRUE if str is a prefix of buf
136: */
137: prefix(buf, str)
138: char *buf, *str;
139: {
140: return strncmp(buf, str, strlen(str))? FALSE : TRUE;
141: }
142:
143: /*
144: * return TRUE if strings are equal
145: */
146: streq(a, b)
147: char *a, *b;
148: {
149: return strcmp(a, b)? FALSE : TRUE;
150: }
151:
152: /*
153: * make a byte from the first two hex characters in s
154: */
155: unsigned char
156: hexbyte(s)
157: char *s;
158: {
159: unsigned char b = 0;
160: register char c;
161: int i;
162:
163: for (i=2; i; i--) {
164: c = *s++;
165: if ((c >= '0') && (c <= '9'))
166: b = (b<<4) + (c - '0');
167: else if ((c >= 'A') && (c <= 'F'))
168: b = (b<<4) + 10 + (c - 'A');
169: else if ((c >= 'a') && (c <= 'f'))
170: b = (b<<4) + 10 + (c - 'a');
171: else
172: return 0; /* bad data */
173: }
174: return b;
175: }
176:
177: /*
178: * fatal error. never returns.
179: */
180: fatal(msg, p1, p2, p3, p4)
181: char *msg;
182: {
183: fprintf(stderr, "%s: %s:", myname, currentfont);
184: fprintf(stderr, msg, p1, p2, p3, p4);
185: if (linenum)
186: fprintf(stderr, " at line %d\n", linenum);
187: else
188: fprintf(stderr, "\n");
189: exit(1);
190: }
191:
192: /*
193: * these properties will be generated if not already present.
194: */
195: #define NULLPROP (FontPropPtr)0;
196:
197: FontPropPtr pointSizeProp = NULLPROP;
198: FontPropPtr familyProp = NULLPROP;
199: FontPropPtr resolutionProp = NULLPROP;
200: FontPropPtr xHeightProp = NULLPROP;
201: FontPropPtr weightProp = NULLPROP;
202: FontPropPtr quadWidthProp = NULLPROP;
203: #define GENPROPS 6
204:
205: BOOL haveFontAscent = FALSE;
206: BOOL haveFontDescent = FALSE;
207:
208: /*
209: * check for known property values
210: */
211:
212: int
213: specialproperty(pfp, pfi)
214: FontPropPtr pfp;
215: FontInfoPtr pfi;
216: {
217: if (streq(pfp->name, "FONT_ASCENT") && !pfp->indirect)
218: {
219: pfi->fontAscent = pfp->value;
220: haveFontAscent = TRUE;
221: return 0;
222: }
223: else if (streq(pfp->name, "FONT_DESCENT") && !pfp->indirect)
224: {
225: pfi->fontDescent = pfp->value;
226: haveFontDescent = TRUE;
227: return 0;
228: }
229: else if (streq(pfp->name, "DEFAULT_CHAR") && !pfp->indirect)
230: {
231: pfi->chDefault = pfp->value;
232: return 0;
233: }
234: else if (streq(pfp->name , "POINT_SIZE"))
235: pointSizeProp = pfp;
236: else if (streq(pfp->name , "FAMILY_NAME"))
237: familyProp = pfp;
238: else if (streq(pfp->name , "RESOLUTION"))
239: resolutionProp = pfp;
240: else if (streq(pfp->name , "X_HEIGHT"))
241: xHeightProp = pfp;
242: else if (streq(pfp->name , "WEIGHT"))
243: weightProp = pfp;
244: else if (streq(pfp->name , "QUAD_WIDTH"))
245: quadWidthProp = pfp;
246: return 1;
247: }
248:
249: computeweight(font)
250: TempFont *font;
251: {
252: int i;
253: int width = 0, area, bits = 0;
254: register b;
255: register unsigned char *p;
256:
257: for (i=0; i<n1dChars(font->pFI); i++)
258: width += font->pCI[i].metrics.characterWidth;
259: area = width*(font->pFI->fontAscent+font->pFI->fontDescent);
260: for (i=0,p=font->pGlyphs; i<font->pFI->maxbounds.byteOffset; i++,p++)
261: for (b=(*p); b; b >>= 1)
262: bits += b & 1;
263: return (int)((bits*1000.0)/area);
264: }
265:
266: main(argc, argv)
267: int argc;
268: char * argv[];
269: {
270: TempFont font;
271: FontInfoRec fi;
272: CharInfoPtr cinfos[INDICES]; /* rows waiting to be allocated */
273: int bytesGlAlloced = 1024; /* amount now allocated for glyphs
274: (bytes) */
275: unsigned char *pGl = (unsigned char *)malloc( bytesGlAlloced);
276: int bytesGlUsed = 0;
277: int nGl = 0;
278: int nchars;
279: float pointSize;
280: int xRes, yRes;
281: char linebuf[BUFSIZ];
282: char namebuf[100];
283: char family[100];
284: char *bdffile = NULL;
285: unsigned int attributes;
286: int digitWidths = 0, digitCount = 0, ex = 0;
287: int char_row, char_col;
288: int i;
289: CharInfoRec emptyCharInfo;
290:
291: myname = argv[0];
292: argc--, argv++;
293: while (argc--) {
294: if (argv[0][0] == '-') {
295: switch (argv[0][1]) {
296: case 'p': /* Pad Glyphs to Word boundaries */
297: switch (argv[0][2]) {
298: default:
299: goto usage;
300: case '1':
301: case '2':
302: case '4':
303: case '8':
304: glyphPad = argv[0][2] - '0';
305: break;
306: }
307: or_glyphPad = 1;
308: break;
309: case 'm':
310: or_bitorder = 1;
311: bitorder = MSBFirst;
312: break;
313:
314: case 'l':
315: or_bitorder = 1;
316: bitorder = LSBFirst;
317: break;
318:
319: default:
320: fprintf(stderr, "bad flag -%c\n", argv[0][1]);
321: break;
322: }
323: } else {
324: if (bdffile)
325: usage:
326: fatal("usage: %s [-p#] [bdf file]", myname);
327: bdffile = argv[0];
328: if (freopen( bdffile, "r", stdin) == NULL)
329: fatal("could not open file %s\n", bdffile);
330: }
331: argv++;
332: }
333: emptyCharInfo.metrics.leftSideBearing = 0;
334: emptyCharInfo.metrics.rightSideBearing = 0;
335: emptyCharInfo.metrics.ascent = 0;
336: emptyCharInfo.metrics.descent = 0;
337: emptyCharInfo.metrics.characterWidth = 0;
338: emptyCharInfo.byteOffset = 0;
339: emptyCharInfo.exists = FALSE;
340: emptyCharInfo.metrics.attributes = 0;
341:
342: for (i = 0; i < INDICES; i++)
343: cinfos[i] = (CharInfoPtr)NULL;
344:
345: font.pFI = &fi;
346: fi.firstRow = INDICES;
347: fi.lastRow = 0;
348: fi.chFirst = INDICES;
349: fi.chLast = 0;
350: fi.pixDepth = 1;
351: fi.glyphSets = 1;
352: fi.chDefault = 0; /* may be overridden by a property */
353:
354: getline(linebuf);
355:
356: if ((sscanf(linebuf, "STARTFONT %s", namebuf) != 1) ||
357: !streq(namebuf, "2.1"))
358: fatal("bad 'STARTFONT'");
359: getline(linebuf);
360:
361: if (sscanf(linebuf, "FONT %s", family) != 1)
362: fatal("bad 'FONT'");
363: getline(linebuf);
364:
365: if (!prefix(linebuf, "SIZE"))
366: fatal("missing 'SIZE'");
367: if ((sscanf(linebuf, "SIZE %f%d%d", &pointSize, &xRes, &yRes) != 3))
368: fatal("bad 'SIZE'");
369: if (xRes != yRes)
370: fatal("x and y resolution must be equal");
371: getline(linebuf);
372:
373: if (!prefix(linebuf, "FONTBOUNDINGBOX"))
374: fatal("missing 'FONTBOUNDINGBOX'");
375: getline(linebuf);
376:
377: if (prefix(linebuf, "STARTPROPERTIES")) {
378: int nprops;
379: FontPropPtr pfp;
380:
381: sscanf(linebuf, "%*s%d", &nprops);
382: fi.nProps = nprops;
383: pfp = (FontPropPtr)malloc((nprops+GENPROPS) * sizeof(FontPropRec));
384: font.pFP = pfp;
385: getline(linebuf);
386: while((nprops-- > 0) && !prefix(linebuf, "ENDPROPERTIES")) {
387: if (sscanf(linebuf, "%s%d", namebuf, &pfp->value) == 2) {
388: /* integer value */
389: pfp->indirect = FALSE;
390: } else {
391: /* value is (possibly quoted) string */
392: pfp->indirect = TRUE;
393: pfp->value = (INT32)remember(linebuf+strlen(namebuf)+1);
394: }
395: pfp->name = (CARD32)remember(namebuf);
396: if (specialproperty(pfp, &fi))
397: pfp++;
398: else
399: fi.nProps--;
400: getline(linebuf);
401: }
402: if (!prefix(linebuf, "ENDPROPERTIES"))
403: fatal("missing 'ENDPROPERTIES'");
404: if (!haveFontAscent || !haveFontDescent)
405: fatal("must have 'FONT_ASCENT' and 'FONT_DESCENT' properties");
406: if (nprops != -1)
407: fatal("%d too few properties", nprops+1);
408: if (!familyProp) {
409: fi.nProps++;
410: pfp->name = (CARD32)("FAMILY_NAME");
411: pfp->value = (INT32)family;
412: pfp->indirect = TRUE;
413: familyProp = pfp++;
414: }
415: if (!pointSizeProp) {
416: fi.nProps++;
417: pfp->name = (CARD32)("POINT_SIZE");
418: pfp->value = (INT32)(pointSize*10.0);
419: pfp->indirect = FALSE;
420: pointSizeProp = pfp++;
421: }
422: if (!weightProp) {
423: fi.nProps++;
424: pfp->name = (CARD32)("WEIGHT");
425: pfp->value = -1; /* computed later */
426: pfp->indirect = FALSE;
427: weightProp = pfp++;
428: }
429: if (!resolutionProp) {
430: fi.nProps++;
431: pfp->name = (CARD32)("RESOLUTION");
432: pfp->value = (INT32)((xRes*100.0)/72.27);
433: pfp->indirect = FALSE;
434: resolutionProp = pfp++;
435: }
436: if (!xHeightProp) {
437: fi.nProps++;
438: pfp->name = (CARD32)("X_HEIGHT");
439: pfp->value = -1; /* computed later */
440: pfp->indirect = FALSE;
441: xHeightProp = pfp++;
442: }
443: if (!quadWidthProp) {
444: fi.nProps++;
445: pfp->name = (CARD32)("QUAD_WIDTH");
446: pfp->value = -1; /* computed later */
447: pfp->indirect = FALSE;
448: quadWidthProp = pfp++;
449: }
450: } else { /* no properties */
451: fatal("missing 'PROPERTIES'");
452: }
453: getline(linebuf);
454:
455: if (!prefix(linebuf, "CHARS"))
456: fatal("missing 'CHARS'");
457: sscanf(linebuf, "%*s%d", &nchars);
458: getline(linebuf);
459:
460: while ((nchars-- > 0) && prefix(linebuf, "STARTCHAR")) {
461: int t;
462: int ix; /* counts bytes in a glyph */
463: int wx; /* x component of width */
464: int bw; /* bounding-box width */
465: int bh; /* bounding-box height */
466: int bl; /* bounding-box left */
467: int bb; /* bounding-box bottom */
468: int enc, enc2; /* encoding */
469: char *p; /* temp pointer into linebuf */
470: int bytesperrow, row;
471: char charName[100];
472:
473: if (sscanf(linebuf, "STARTCHAR %s", charName) != 1)
474: fatal("bad character name");
475:
476: getline( linebuf);
477: if ((t=sscanf(linebuf, "ENCODING %d %d", &enc, &enc2)) < 1)
478: fatal("bad 'ENCODING'");
479: if (t == 2 && enc == -1)
480: enc = enc2;
481: if (enc == -1) {
482: fprintf(stderr,
483: "character '%s'with encoding = -1 ignored at line %d\n",
484: charName, linenum);
485: do {
486: char *s = getline(linebuf);
487: if (!s)
488: fatal("Unexpected EOF");
489: } while (!prefix(linebuf, "ENDCHAR"));
490: getline(linebuf);
491: continue;
492: }
493: if (enc > MAXENCODING)
494: fatal("character '%s' has encoding(=%d) too large", charName, enc);
495: char_row = (enc >> 8) & 0xFF;
496: char_col = enc & 0xFF;
497: fi.firstRow = MIN(fi.firstRow, char_row);
498: fi.lastRow = MAX(fi.lastRow, char_row);
499: fi.chFirst = MIN(fi.chFirst, char_col);
500: fi.chLast = MAX(fi.chLast, char_col);
501: if (!cinfos[char_row])
502: {
503: cinfos[char_row] =
504: (CharInfoPtr)malloc(sizeof(CharInfoRec)*INDICES);
505: bzero(cinfos[char_row], sizeof(CharInfoRec)*INDICES);
506: }
507:
508: getline( linebuf);
509: if (!prefix(linebuf, "SWIDTH"))
510: fatal("bad 'SWIDTH'");
511:
512: getline( linebuf);
513: sscanf( linebuf, "DWIDTH %d %*d", &wx);
514:
515: getline( linebuf);
516: sscanf( linebuf, "BBX %d %d %d %d", &bw, &bh, &bl, &bb);
517:
518: getline( linebuf);
519: if (prefix(linebuf, "ATTRIBUTES"))
520: {
521: for (p = linebuf + strlen("ATTRIBUTES ");
522: (*p == ' ') || (*p == '\t');
523: p ++)
524: /* empty for loop */ ;
525: attributes = hexbyte(p)<< 8 + hexbyte(p+2);
526: getline( linebuf); /* set up for BITMAP which follows */
527: }
528: else
529: attributes = 0;
530: if (!prefix(linebuf, "BITMAP"))
531: fatal("missing 'BITMAP'");
532:
533: /* collect data for generated properties */
534: if ((strlen(charName) == 1)){
535: if ((charName[0] >='0') && (charName[0] <= '9')) {
536: digitWidths += wx;
537: digitCount++;
538: } else if (charName[0] == 'x') {
539: ex = (bh+bb)<=0? bh : bh+bb ;
540: }
541: }
542:
543: cinfos[char_row][char_col].metrics.leftSideBearing = bl;
544: cinfos[char_row][char_col].metrics.rightSideBearing = bl+bw;
545: cinfos[char_row][char_col].metrics.ascent = bh+bb;
546: cinfos[char_row][char_col].metrics.descent = -bb;
547: cinfos[char_row][char_col].metrics.characterWidth = wx;
548: cinfos[char_row][char_col].byteOffset = bytesGlUsed;
549: cinfos[char_row][char_col].exists = FALSE; /* overwritten later */
550: cinfos[char_row][char_col].metrics.attributes = attributes;
551:
552: bytesperrow = GLWIDTHBYTESPADDED(bw,glyphPad);
553: for (row=0; row < bh; row++) {
554: getline(linebuf);
555: p = linebuf;
556: for ( ix=0; ix < bytesperrow; ix++)
557: {
558: if ( bytesGlUsed >= bytesGlAlloced)
559: pGl = (unsigned char *)realloc( pGl, (bytesGlAlloced *= 2));
560: pGl[bytesGlUsed] = hexbyte(p);
561: p += 2;
562: bytesGlUsed++;
563: }
564: /*
565: * Now pad the glyph row our pad boundary.
566: */
567: bytesGlUsed = GLWIDTHBYTESPADDED(bytesGlUsed<<3,glyphPad);
568: }
569: getline( linebuf);
570: if (!prefix(linebuf, "ENDCHAR"))
571: fatal("missing 'ENDCHAR'");
572: nGl++;
573: getline( linebuf); /* get STARTCHAR or ENDFONT */
574: }
575:
576: if (!prefix(linebuf, "ENDFONT"))
577: fatal("missing 'ENDFONT'");
578: if (nchars != -1)
579: fatal("%d too few characters", nchars+1);
580: if (nGl == 0)
581: fatal("No characters with valid encodings");
582:
583: fi.maxbounds.byteOffset = bytesGlUsed;
584: font.pGlyphs = pGl;
585:
586: font.pCI = (CharInfoPtr)malloc(sizeof(CharInfoRec)*n2dChars(font.pFI));
587: i = 0;
588: for (char_row = fi.firstRow; char_row <= fi.lastRow; char_row++)
589: {
590: if (!cinfos[char_row])
591: for (char_col = fi.chFirst; char_col <= fi.chLast; char_col++)
592: {
593: font.pCI[i] = emptyCharInfo;
594: i++;
595: }
596: else
597: for (char_col = fi.chFirst; char_col <= fi.chLast; char_col++)
598: {
599: font.pCI[i] = cinfos[char_row][char_col];
600: i++;
601: }
602: }
603: computeNaccelerators(&font);
604:
605: /* generate properties */
606: if (xHeightProp && (xHeightProp->value == -1))
607: xHeightProp->value = ex? ex : fi.minbounds.metrics.ascent;
608: if (quadWidthProp && (quadWidthProp->value == -1))
609: quadWidthProp->value = digitCount?
610: (INT32)((float)digitWidths/(float)digitCount) :
611: (fi.minbounds.metrics.characterWidth+fi.maxbounds.metrics.characterWidth)/2;
612: if (weightProp && (weightProp->value == -1))
613: weightProp->value = computeweight(&font);
614:
615: if (bitorder == LSBFirst)
616: bitorderinvert( pGl, pGl, bytesGlUsed);
617: #ifdef UNSPECIFIED
618: if (!or_glyphPad || !or_bitorder) {
619: fprintf(stderr, "%s: ", currentfont);
620: if (!or_glyphPad && !or_bitorder)
621: fprintf(stderr, "bit order/pad unspecified:\n\t");
622: else if (!or_glyphPad)
623: fprintf(stderr, "pad unspecified:\n\t");
624: else
625: fprintf(stderr, "bit order unspecified:\n\t");
626: fprintf(stderr, "using ");
627:
628: if (!or_bitorder)
629: fprintf(stderr, "order=%s",
630: bitorder == LSBFirst ? "LSBFirst" : "MSBFirst");
631: if (!or_glyphPad && !or_bitorder)
632: fprintf(stderr, ", ");
633: if (!or_glyphPad)
634: fprintf(stderr, "pad=%d", glyphPad);
635: fprintf(stderr, "\n");
636: }
637: #endif
638:
639: WriteNFont( stdout, &font);
640: exit(0);
641: }
642:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.