| 1 | /* makevfont.c (Berkeley) 85/02/26 1.5 |
| 2 | * |
| 3 | * Font description file producer for versatec fonts: David Slattengren |
| 4 | * Taken from vfontinfo by Andy Hertzfeld 4/79 |
| 5 | * |
| 6 | * Use: makevfont [ -nNAME ] [ -s -a -o -l -c -p# -r# -f# -ddir ] |
| 7 | * [ "-xs1,s2[;s1,s2...]" ] [ "-ys1,s2[;s1,s2...]" ] font |
| 8 | * |
| 9 | * Makefont takes the font named "font" and produces a ditroff description |
| 10 | * file from it. The -n option takes the 1 or 2 letter troff name to put |
| 11 | * the description (default = XX). The -f option takes an integer per- |
| 12 | * centage factor to multiply widths by. The -s, -o and -a options select |
| 13 | * a different character mapping than for a "roman" font. s = special; |
| 14 | * o = otimespecal; a = ascii. The -l option indicates it has ligatures. |
| 15 | * The -c option tells makevfont that the font is constant width and |
| 16 | * will set parameters appropriately. |
| 17 | * |
| 18 | * Both -x and -y options allow character name mapping. A colon separated |
| 19 | * list of comma-separated character-name pairs follows the x or y. |
| 20 | * Notice that there are no spaces in the -x or -y command. A -x pair |
| 21 | * REPLACES the definition for s1 by s2. A -y pair creates a synonym for |
| 22 | * s1 and calls it s2. -x and -y MUST be sent after -s, -m, -i, or -a |
| 23 | * if one of them is used. Some synonyms are defaulted. To remove a |
| 24 | * synonym or character, leave out s2. |
| 25 | * |
| 26 | * The -p# option tells what point size the DESC file has as it's |
| 27 | * "unitwidth" argument (default: 36). The -r# option is the resolution |
| 28 | * of the device (default: 200, in units/inch). The -d option tells |
| 29 | * where to find fonts (default: /usr/lib/vfont). |
| 30 | */ |
| 31 | |
| 32 | /* |
| 33 | * Here's an ascii character set, just in case you need it: |
| 34 | |
| 35 | | 00 nul| 01 soh| 02 stx| 03 etx| 04 eot| 05 enq| 06 ack| 07 bel| |
| 36 | | 08 bs | 09 ht | 0a nl | 0b vt | 0c np | 0d cr | 0e so | 0f si | |
| 37 | | 10 dle| 11 dc1| 12 dc2| 13 dc3| 14 dc4| 15 nak| 16 syn| 17 etb| |
| 38 | | 18 can| 19 em | 1a sub| 1b esc| 1c fs | 1d gs | 1e rs | 1f us | |
| 39 | | 20 sp | 21 ! | 22 " | 23 # | 24 $ | 25 % | 26 & | 27 ' | |
| 40 | | 28 ( | 29 ) | 2a * | 2b + | 2c , | 2d - | 2e . | 2f / | |
| 41 | | 30 0 | 31 1 | 32 2 | 33 3 | 34 4 | 35 5 | 36 6 | 37 7 | |
| 42 | | 38 8 | 39 9 | 3a : | 3b ; | 3c < | 3d = | 3e > | 3f ? | |
| 43 | | 40 @ | 41 A | 42 B | 43 C | 44 D | 45 E | 46 F | 47 G | |
| 44 | | 48 H | 49 I | 4a J | 4b K | 4c L | 4d M | 4e N | 4f O | |
| 45 | | 50 P | 51 Q | 52 R | 53 S | 54 T | 55 U | 56 V | 57 W | |
| 46 | | 58 X | 59 Y | 5a Z | 5b [ | 5c \ | 5d ] | 5e ^ | 5f _ | |
| 47 | | 60 ` | 61 a | 62 b | 63 c | 64 d | 65 e | 66 f | 67 g | |
| 48 | | 68 h | 69 i | 6a j | 6b k | 6c l | 6d m | 6e n | 6f o | |
| 49 | | 70 p | 71 q | 72 r | 73 s | 74 t | 75 u | 76 v | 77 w | |
| 50 | | 78 x | 79 y | 7a z | 7b { | 7c | | 7d } | 7e ~ | 7f del| |
| 51 | |
| 52 | * |
| 53 | */ |
| 54 | |
| 55 | #include <stdio.h> |
| 56 | #include <ctype.h> |
| 57 | #include <vfont.h> |
| 58 | |
| 59 | char sccsid[] = "@(#)makevfont.c 1.5 (Berkeley) %G%"; |
| 60 | |
| 61 | #define MAGICN 0436 /* font file magic number */ |
| 62 | #define PCNTUP 62 /* percent of maximum height for an ascender */ |
| 63 | #define PCNTDOWN 73 /* percent of maximum droop for a descender */ |
| 64 | #ifndef BITDIR |
| 65 | #define BITDIR "/usr/lib/vfont" |
| 66 | #endif |
| 67 | #define POINTSIZE 36 /* this is the "unitwidth" point size */ |
| 68 | #define MINSIZE 6 /* the minimum and maximum point size values */ |
| 69 | #define MAXSIZE 36 /* acceptible for use as "unitwidth"s */ |
| 70 | #define RESOLUTION 200 /* resolution of versatec (dots/inch) */ |
| 71 | #define MINRES 10 /* check up on resolution input by setting */ |
| 72 | #define MAXRES 100000 /* absurdly out-of-range limits on them */ |
| 73 | #define APOINT 72 /* 1/APOINT inches = 1 point */ |
| 74 | #define SYNON 100 /* 2 * pairs allowed in synonym table */ |
| 75 | |
| 76 | |
| 77 | struct header FontHeader; |
| 78 | struct dispatch disptable[256]; |
| 79 | |
| 80 | int res = RESOLUTION; /* resolution of the device (units/inch) */ |
| 81 | int pointsize = POINTSIZE; /* point size being used for unitwidth */ |
| 82 | int factor = 100; /* percent for magnifying (shrinking) widths */ |
| 83 | int psize; /* point size of font actually used */ |
| 84 | int psizelist[] = { 36,24,22,20,18,16,14,28,12,11,10,9,8,7,6,0 }; |
| 85 | |
| 86 | char *fontname = "XX"; /* troff font name - set on command line */ |
| 87 | char *fontdir = BITDIR; /* place to look for fonts */ |
| 88 | char IName[100]; /* input file name put here */ |
| 89 | char *rdchar (); /* function makes strings for ascii */ |
| 90 | int FID = -1; /* input file number */ |
| 91 | |
| 92 | int maxdown = 0; /* size of the most "droopy" character */ |
| 93 | int maxup = 0; /* size of the tallest character */ |
| 94 | int type; /* 1, 2, or 3 for type of ascend/descending */ |
| 95 | int nullchar = -1; /* finds non-existant character in the font */ |
| 96 | int ligsf = 0; /* flag "does this font have ligatures?" */ |
| 97 | int constant = 0; /* flag constant width font (spacewidth, etc.)*/ |
| 98 | |
| 99 | /* following are the character maps for */ |
| 100 | /* ascii code-conversion to printables... */ |
| 101 | char **charmap; |
| 102 | char **synonyms; |
| 103 | int numsyn; |
| 104 | |
| 105 | char *vregular[] = { |
| 106 | |
| 107 | "??", "fi", "fl", "ff", "\\-", "ru", "em", "bu", "sq", "Fi", "Fl", "de", |
| 108 | "dg", "fm", "co", "rg", "ct", "14", "12", "34", "^T", "^U", "^V", "^W", |
| 109 | "^X", "^Y", "^Z", "^[", "^\\", "^]", "^^", "^_", "", "!", "\"", "#", |
| 110 | "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", |
| 111 | "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", |
| 112 | "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", |
| 113 | "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", |
| 114 | "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", |
| 115 | "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", |
| 116 | "x", "y", "z", "{", "|", "}", "~", "^?", |
| 117 | (char *) 0 |
| 118 | }; |
| 119 | int nregular = 2; |
| 120 | char *sregular[SYNON] = { |
| 121 | "-", "hy", "_", "\\_" |
| 122 | }; |
| 123 | |
| 124 | char *vspecial[] = { |
| 125 | |
| 126 | "??", "if", "ip", "pt", "rh", "cu", "rn", "bs", "+-", "<=", ">=", "sr", |
| 127 | "ts", "is", "sl", "bv", "lf", "rf", "lc", "rc", "lt", "lb", "rt", "rb", |
| 128 | "lk", "rk", "sb", "sp", "ca", "no", "lh", "mo", "", "!", "\"", "#", |
| 129 | "$", "%", "&", "aa", "gr", ")", "mu", "pl", ",", "mi", ".", "di", "==", |
| 130 | "~=", "ap", "!=", "<-", "->", "ua", "da", "sc", "**", ":", ";", "<", |
| 131 | "eq", ">", "?", "@", "*A", "*B", "*G", "*D", "*E", "*Z", "*Y", "*H", |
| 132 | "*I", "*K", "*L", "*M", "*N", "*C", "*O", "*P", "*R", "*S", "*T", "*U", |
| 133 | "*F", "*X", "*Q", "*W", "dd", "br", "ib", "\\", "ci", "^", "ul", "ga", |
| 134 | "*a", "*b", "*g", "*d", "*e", "*z", "*y", "*h", "*i", "*k", "*l", "*m", |
| 135 | "*n", "*c", "*o", "*p", "*r", "*s", "*t", "*u", "es", "*x", "*q", "*w", |
| 136 | "pd", "*f", "{", "|", "}", "~", "^?", |
| 137 | (char *) 0 |
| 138 | }; |
| 139 | int nspecial = 0; |
| 140 | char *sspecial[SYNON] = { |
| 141 | "","" |
| 142 | }; |
| 143 | |
| 144 | char *vtimes[] = { |
| 145 | |
| 146 | "??", "if", "ip", "pt", "rh", "cu", "rn", "bs", "+-", "<=", ">=", "mi", |
| 147 | "**", "pl", "eq", "gr", "lt", "lk", "lb", "rt", "rk", "rb", "ap", "mo", |
| 148 | "br", "rk", "sb", "sp", "ca", "no", "~=", "mo", "", "da", "no", "ua", |
| 149 | "sc", "dd", "if", "pd", "sb", "sp", "mu", "+-", "ca", "cu", "<-", "di", |
| 150 | "->", |
| 151 | "!=", "sr", "<=", ">=", "==", "or", "is", "bv", "lc", "rc", "lf", "rf", |
| 152 | "~=", "_", "ib", "ul", "rn", "ip", "*G", "*D", "*E", "*F", "*G", "*H", |
| 153 | "*I", "??", "*L", "*L", "*N", "*C", "*O", "*P", "*H", "*S", "*S", "*U", |
| 154 | "*U", "*X", "*W", "*C", "*Q", "br", "ib", "ga", "aa", "^", "ul", "ga", |
| 155 | "*a", "*b", "*g", "*d", "*e", "*z", "*y", "*h", "*i", "*k", "*l", "*m", |
| 156 | "*n", "*c", "*o", "*p", "*r", "*s", "*t", "*u", "es", "*x", "*q", "*w", |
| 157 | "pd", "*f", "{", "|", "}", "~", "^?", |
| 158 | (char *) 0 |
| 159 | }; |
| 160 | int ntimes = 0; |
| 161 | char *stimes[SYNON] = { |
| 162 | "","" |
| 163 | }; |
| 164 | |
| 165 | |
| 166 | char *vascii[] = { |
| 167 | "", "da", "*a", "*b", "an", "no", "mo", "*p", "*l", "*g", "*d", |
| 168 | "ua", "+-", "O+", "if", "pd", "sb", "sp", "ca", "cu", "fa", "te", |
| 169 | "OX", "<>", "<-", "->", "!=", "ap", "<=", ">=", "==", "or", "", |
| 170 | "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", |
| 171 | ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", |
| 172 | "<", "=", ">", "?", |
| 173 | "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", |
| 174 | "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", |
| 175 | "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", |
| 176 | "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", |
| 177 | "x", "y", "z", "{", "|", "}", "~", "??", |
| 178 | (char *)0 |
| 179 | }; |
| 180 | int nascii = 3; |
| 181 | char *sascii[SYNON] = { |
| 182 | "-", "hy", "-", "\\-", "_", "\\_" |
| 183 | }; |
| 184 | |
| 185 | |
| 186 | main (argc, argv) |
| 187 | int argc; |
| 188 | char **argv; |
| 189 | { |
| 190 | register int i; /* two indexes */ |
| 191 | register int j; |
| 192 | register char *ptr; /* string traveler */ |
| 193 | register char delimit; /* place for delimiters on command line */ |
| 194 | char *replacelist = NULL; /* string of character name replacements */ |
| 195 | char *synonymlist = NULL; /* string of synonym entries */ |
| 196 | char tostring(); /* function makes a string */ |
| 197 | char *nextstring(); /* moves to next string on list */ |
| 198 | char *operand(); |
| 199 | |
| 200 | |
| 201 | charmap = vregular; /* default character map */ |
| 202 | synonyms = sregular; |
| 203 | numsyn = nregular; |
| 204 | while (--argc > 0 && *(*(++argv)) == '-') { /* do options... */ |
| 205 | switch ((*argv)[1]) { |
| 206 | |
| 207 | case 's': charmap = vspecial; /* special font */ |
| 208 | synonyms = sspecial; |
| 209 | numsyn = nspecial; |
| 210 | break; |
| 211 | |
| 212 | case 'o': charmap = vtimes; /* times special font */ |
| 213 | synonyms = stimes; |
| 214 | numsyn = ntimes; |
| 215 | break; |
| 216 | |
| 217 | case 'a': charmap = vascii; /* ascii font */ |
| 218 | synonyms = sascii; |
| 219 | numsyn = nascii; |
| 220 | break; |
| 221 | |
| 222 | case 'c': constant = 1; /* constant width font */ |
| 223 | break; |
| 224 | |
| 225 | case 'l': ligsf = 1; /* ascii font */ |
| 226 | break; |
| 227 | |
| 228 | case 'n': fontname = operand(&argc, &argv); /* troff font name */ |
| 229 | break; |
| 230 | |
| 231 | case 'x': replacelist = operand(&argc, &argv); /* replacements */ |
| 232 | break; |
| 233 | |
| 234 | case 'y': synonymlist = operand(&argc, &argv); /* synonyms */ |
| 235 | break; |
| 236 | |
| 237 | case 'd': fontdir = operand(&argc, &argv); /* directory */ |
| 238 | break; |
| 239 | |
| 240 | case 'p': pointsize = atoi(operand(&argc, &argv)); /* point size */ |
| 241 | if (pointsize < MINSIZE || pointsize > MAXSIZE) |
| 242 | error("Illegal point size: %d", pointsize); |
| 243 | break; |
| 244 | |
| 245 | case 'f': factor = atoi(operand(&argc, &argv)); /* % reduction */ |
| 246 | if (factor < 1 || factor > 1000) |
| 247 | error("Illegal factor: %d", factor); |
| 248 | break; |
| 249 | |
| 250 | case 'r': res = atoi(operand(&argc, &argv)); /* resolution */ |
| 251 | if (res < MINRES || res > MAXRES) |
| 252 | error("Illegal resolution: %d", res); |
| 253 | break; |
| 254 | |
| 255 | default: error("Bad option: %c", **argv); |
| 256 | } |
| 257 | } |
| 258 | /* do character name replacements */ |
| 259 | if (replacelist != NULL) { |
| 260 | ptr = replacelist; |
| 261 | while (delimit = tostring(ptr, ',')) { /* get s1 */ |
| 262 | for (i = 0; charmap[i] != 0; i++) /* search for match */ |
| 263 | if (strcmp (charmap[i], ptr) == 0) |
| 264 | break; |
| 265 | if (!charmap[i]) error("-x option: no match"); |
| 266 | charmap[i] = ptr = nextstring(ptr); /* replace s1 */ |
| 267 | delimit = tostring(ptr, ':'); /* with string s2 */ |
| 268 | if (delimit) ptr = nextstring(ptr); |
| 269 | } |
| 270 | } |
| 271 | /* do the synonym list */ |
| 272 | if (synonymlist != NULL) { |
| 273 | ptr = synonymlist; |
| 274 | while (delimit = tostring(ptr, ',')) { /* get s1 */ |
| 275 | synonyms[2 * numsyn] = ptr; /* set on end of list */ |
| 276 | ptr = nextstring(ptr); /* get string s2 */ |
| 277 | delimit = tostring(ptr, ':'); |
| 278 | if (*ptr) { /* if something there */ |
| 279 | synonyms[2 * numsyn++ + 1] = ptr; /* add to list */ |
| 280 | } else { /* otherwise remove */ |
| 281 | for (i = 0; i < numsyn; i++) { /* from list */ |
| 282 | if (!strcmp(synonyms[2*i],synonyms[2*numsyn])) { |
| 283 | numsyn--; |
| 284 | for (j = i--; j < numsyn; j++) { |
| 285 | synonyms[2 * j] = synonyms[2 * (j+1)]; |
| 286 | synonyms[2*j + 1] = synonyms[2*j + 3]; |
| 287 | } |
| 288 | } |
| 289 | } |
| 290 | } |
| 291 | if (delimit) ptr = nextstring(ptr); |
| 292 | if (numsyn > SYNON) error("out of synonym space"); |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | if (argc != 1) /* open font file */ |
| 297 | error("A vfont filename must be the last operand."); |
| 298 | for (i = 0; FID < 0 && (psize = psizelist[i]) > 0; i++) { |
| 299 | sprintf (IName, "%s/%s.%d", fontdir, *argv, psize); |
| 300 | FID = open (IName, 0); |
| 301 | } |
| 302 | if (FID < 0) { |
| 303 | printf ("Can't find %s\n", *argv); |
| 304 | exit (8); |
| 305 | } |
| 306 | |
| 307 | /* read font width table */ |
| 308 | if (read (FID, &FontHeader, sizeof FontHeader) != sizeof FontHeader) |
| 309 | error("Bad header in Font file."); |
| 310 | if (read (FID, &disptable[0], sizeof disptable) != sizeof disptable) |
| 311 | error("Bad dispatch table in Font file"); |
| 312 | if (FontHeader.magic != MAGICN) |
| 313 | printf ("Magic number %o wrong\n", FontHeader.magic); |
| 314 | |
| 315 | |
| 316 | printf ("# Font %s, ", IName); /* head off the file */ |
| 317 | printf ("max width %d, max height %d\n", |
| 318 | FontHeader.maxx, FontHeader.maxy); |
| 319 | printf ("name %s\n", fontname); |
| 320 | if (ligsf) |
| 321 | printf ("ligatures ff fl fi ffl ffi 0\n"); |
| 322 | |
| 323 | /* pass 1 - set up maximums for ups and downs */ |
| 324 | for (j=0; j<256; j++) { /* and find out constant width if requested */ |
| 325 | if (disptable[j].nbytes != 0) { |
| 326 | if (disptable[j].up > maxup) maxup = disptable[j].up; |
| 327 | if (disptable[j].down > maxdown) maxdown = disptable[j].down; |
| 328 | if (constant && disptable[j].width) constant = disptable[j].width; |
| 329 | } else /* find a non-existant character to put \| in */ |
| 330 | if (nullchar < 0) nullchar = j; |
| 331 | } |
| 332 | if (maxdown == 0) maxdown = 1; |
| 333 | |
| 334 | if (constant) { |
| 335 | constant = (factor * (pointsize * constant + psize/2) / psize) / 100; |
| 336 | printf ("spacewidth %d\n", constant); |
| 337 | } |
| 338 | printf ("# char width u/d octal\ncharset\n"); |
| 339 | if (nullchar >= 0) { |
| 340 | printf ("\\| %4d 0 0%o\n\\^ %4d 0 0%o\n", |
| 341 | constant ? constant : (res*pointsize / APOINT + 4)/6, nullchar, |
| 342 | constant ? 0 : (res * pointsize / APOINT + 7) / 12, nullchar); |
| 343 | } |
| 344 | |
| 345 | /******************************************************************************* |
| 346 | |
| 347 | `type' is used to determine overhangs (up/down) from percentage of |
| 348 | the maximum heights and dips. Ascenders are higher than PCNTUP% |
| 349 | of the highest, as descenders are more than PCNTDOWN%. |
| 350 | widths [i = f(width)] are calculated from the definition point |
| 351 | size (pointsize) and the one from this font (psize). |
| 352 | |
| 353 | *******************************************************************************/ |
| 354 | |
| 355 | for (j=0; j<256; j++) { |
| 356 | if (disptable[j].nbytes != 0) { |
| 357 | type = (int) (((disptable[j].up * 100) / maxup) > PCNTUP) * 2 | |
| 358 | (int) (((disptable[j].down * 100) / maxdown) > PCNTDOWN); |
| 359 | if (*(ptr = charmap[j])) { |
| 360 | printf ("%s %4d %d 0%o\n", ptr, (factor * |
| 361 | (pointsize * disptable[j].width + psize/2) / psize)/100, |
| 362 | type, j); |
| 363 | for (i = 0; i < numsyn; i++) |
| 364 | if (strcmp (ptr, synonyms[2 * i]) == 0) |
| 365 | printf ("%s \"\n", synonyms[2 * i + 1]); |
| 366 | } |
| 367 | } |
| 368 | } /* for j */ |
| 369 | exit(0); |
| 370 | } |
| 371 | |
| 372 | |
| 373 | /*----------------------------------------------------------------------------* |
| 374 | | Routine: char * operand (& argc, & argv) |
| 375 | | |
| 376 | | Results: returns address of the operand given with a command-line |
| 377 | | option. It uses either "-Xoperand" or "-X operand", whichever |
| 378 | | is present. The program is terminated if no option is present. |
| 379 | | |
| 380 | | Side Efct: argc and argv are updated as necessary. |
| 381 | *----------------------------------------------------------------------------*/ |
| 382 | |
| 383 | char *operand(argcp, argvp) |
| 384 | int * argcp; |
| 385 | char ***argvp; |
| 386 | { |
| 387 | if ((**argvp)[2]) return(**argvp + 2); /* operand immediately follows */ |
| 388 | if ((--*argcp) <= 0) /* no operand */ |
| 389 | error("command-line option operand missing."); |
| 390 | return(*(++(*argvp))); /* operand next word */ |
| 391 | } |
| 392 | |
| 393 | |
| 394 | /*----------------------------------------------------------------------------* |
| 395 | | Routine: char tostring (pointer, delimitter) |
| 396 | | |
| 397 | | Results: checks string pointed to by pointer and turns it into a |
| 398 | | string at 'delimitter' by replacing it with '\0'. If the |
| 399 | | end of the string is found first, '\0' is returned; otherwise |
| 400 | | the delimitter found there is returned. |
| 401 | | |
| 402 | *----------------------------------------------------------------------------*/ |
| 403 | |
| 404 | char tostring(p, d) |
| 405 | register char *p; |
| 406 | register char d; |
| 407 | { |
| 408 | while (*p && *p != d) p++; |
| 409 | d = *p; |
| 410 | *p = '\0'; |
| 411 | return d; |
| 412 | } |
| 413 | |
| 414 | |
| 415 | /*----------------------------------------------------------------------------* |
| 416 | | Routine: char * nextstring (pointer) |
| 417 | | |
| 418 | | Results: returns address of next string after one pointed to by |
| 419 | | pointer. The next string is after the '\0' byte. |
| 420 | | |
| 421 | *----------------------------------------------------------------------------*/ |
| 422 | |
| 423 | char *nextstring(p) |
| 424 | register char *p; |
| 425 | { |
| 426 | while (*(p++)); |
| 427 | return p; |
| 428 | } |
| 429 | |
| 430 | |
| 431 | error(s, a1, a2, a3, a4, a5) |
| 432 | char *s; |
| 433 | { |
| 434 | fprintf(stderr, "makefont: "); |
| 435 | fprintf(stderr, s, a1, a2, a3, a4); |
| 436 | fprintf(stderr, "\n"); |
| 437 | exit(8); |
| 438 | } |