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