1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 /*	from OpenSolaris "makedev.c	1.7	05/06/08 SMI"	*/
32 
33 /*
34  * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
35  *
36  * Sccsid @(#)makedev.c	1.3 (gritter) 8/9/05
37  */
38 
39 /*
40  * University Copyright- Copyright (c) 1982, 1986, 1988
41  * The Regents of the University of California
42  * All Rights Reserved
43  *
44  * University Acknowledgment- Portions of this document are derived from
45  * software developed by the University of California, Berkeley, and its
46  * contributors.
47  */
48 
49 /*
50  *  This is a special version of makedev, tailored for the font disk
51  *	of the APS-5 in the MH Computing Center.  It is not to be used
52  *	to set up font description files for other devices.
53  *
54  * makedev:
55  *	read text info about a particular device
56  *	(e.g., cat, 202, aps5) from file, convert
57  *	it into internal (binary) form suitable for
58  *	fast reading by troff initialization (ptinit()).
59  *
60  *	Usage:
61  *
62  *	makedev DESC [ F ... ]
63  *		uses DESC to create a description file
64  *		using the information therein.
65  *		It creates the file DESC.out.
66  *
67  *	makedev F ...
68  *		makes the font tables for fonts F only,
69  *		creates files F.out.
70  *
71  *	DESC.out contains:
72  *	dev structure with fundamental sizes
73  *	list of sizes (nsizes+1) terminated by 0, as short's
74  *	indices of char names (nchtab * sizeof (short))
75  *	char names as hy\0em\0... (lchname)
76  *	nfonts occurrences of
77  *		widths (nwidth)
78  *		kerning (nwidth) [ascender+descender only so far]
79  *		codes (nwidth) to drive actual typesetter
80  *		fitab (nchtab+128-32)
81  *	each of these is an array of char.
82  *
83  *	dev.filesize contains the number of bytes
84  *	in the file, excluding the dev part itself.
85  *
86  *	F.out contains the font header, width, kern, codes, and fitab.
87  *	Width, kern and codes are parallel arrays.
88  *	(Which suggests that they ought to be together?)
89  *	Later, we might allow for codes which are actually
90  *	sequences of formatting info so characters can be drawn.
91  */
92 
93 #include	<stdio.h>
94 #include	<stdlib.h>
95 #include	<unistd.h>
96 #include	<string.h>
97 #include	<fcntl.h>
98 #include	"dev.h"
99 
100 #define	BYTEMASK	0377
101 
102 #define	SLANT_BIT	1		/* slant flag is bit 0 */
103 #define	FONT_BIT	2		/* font flag is bit 1 */
104 #define	RANGE_BIT	4		/* range flag is bit 2 */
105 
106 #define	SLANT_VAL	3		/* slant angle starts in bit 3 */
107 #define	RANGE_VAL	5		/* max range starts in bit 5 */
108 
109 #define	skipline(f)	while (getc(f) != '\n')
110 
111 struct	dev	dev;
112 struct	Font	font;
113 
114 #define	NSIZE	100	/* maximum number of sizes */
115 short	size[NSIZE];
116 #define	NCH	256	/* max number of characters with funny names */
117 char	chname[5*NCH];	/* character names, including \0 for each */
118 short	chtab[NCH];	/* index of character in chname */
119 
120 #define	NFITAB	(NCH + 128-32)	/* includes ascii chars, but not non-graphics */
121 char	fitab[NFITAB];	/* font index table: position of char i on this font. */
122 			/* zero if not there */
123 
124 #define	FSIZE	256	/* size of a physical font (e.g., 102 for cat) */
125 char	width[FSIZE];	/* width table for a physical font */
126 char	kern[FSIZE];	/* ascender+descender info */
127 char	code[FSIZE];	/* actual device codes for a physical font */
128 char	alt_code[FSIZE];	/* code for alternate font */
129 int	alt_font[FSIZE];	/* alternate font to use */
130 
131 int	dbg = 0;		/* debug flag */
132 int	verbose = 0;
133 
134 #define	NFONT	60	/* max number of default fonts */
135 char	fname[NFONT][10];	/* temp space to hold default font names */
136 
137 int	fflag	= 0;	/* on if font table to be written */
138 int	fdout;	/* output file descriptor */
139 char	*fout	= "DESC.out";
140 
141 int dofont(char *name);
142 int getlig(FILE *fin);
143 void dump_font(void);
144 void finish_line(char *buf, int nw);
145 void add_font(char *name);
146 
147 int
main(int argc,char * argv[])148 main(int argc, char *argv[])
149 {
150 	FILE *fin;
151 	char cmd[100], *p;
152 	int i, totfont, v;
153 
154 	if (!strcmp(argv[1], "-v")) {
155 		verbose = 1;
156 		argv++;
157 		argc--;
158 	}
159 
160 	if (argc < 2) {
161 		fprintf(stderr, "Usage:  makedev [-v] [DESC] [fonts]\n");
162 		exit(1);
163 	}
164 
165 	if ((fin = fopen("DESC", "r")) == NULL) {
166 		fprintf(stderr, "makedev: can't open %s\n", argv[1]);
167 		exit(1);
168 	}
169 	while (fscanf(fin, "%s", cmd) != EOF) {
170 		if (cmd[0] == '#')	/* comment */
171 			skipline(fin);
172 		else if (strcmp(cmd, "debug") == 0)
173 			dbg++;
174 		else if (strcmp(cmd, "res") == 0) {
175 			fscanf(fin, "%hd", &dev.res);
176 		} else if (strcmp(cmd, "hor") == 0) {
177 			fscanf(fin, "%hd", &dev.hor);
178 		} else if (strcmp(cmd, "vert") == 0) {
179 			fscanf(fin, "%hd", &dev.vert);
180 		} else if (strcmp(cmd, "unitwidth") == 0) {
181 			fscanf(fin, "%hd", &dev.unitwidth);
182 		} else if (strcmp(cmd, "sizescale") == 0) {
183 			fscanf(fin, "%hd", &dev.sizescale);
184 		} else if (strcmp(cmd, "paperwidth") == 0) {
185 			fscanf(fin, "%hd", &dev.paperwidth);
186 		} else if (strcmp(cmd, "paperlength") == 0) {
187 			fscanf(fin, "%hd", &dev.paperlength);
188 		} else if (strcmp(cmd, "biggestfont") == 0) {
189 			fscanf(fin, "%hd", &dev.biggestfont);
190 		} else if (strcmp(cmd, "spare2") == 0) {
191 			fscanf(fin, "%hd", &dev.spare2);
192 		} else if (strcmp(cmd, "sizes") == 0) {
193 			dev.nsizes = 0;
194 			while (fscanf(fin, "%d", &v) != EOF && v != 0)
195 				size[dev.nsizes++] = v;
196 			size[dev.nsizes] = 0;	/* need an extra 0 at the end */
197 		} else if (strcmp(cmd, "fonts") == 0) {
198 			fscanf(fin, "%hd", &dev.nfonts);
199 			for (i = 0; i < dev.nfonts; i++)
200 				fscanf(fin, "%s", fname[i]);
201 		} else if (strcmp(cmd, "charset") == 0) {
202 			p = chname;
203 			dev.nchtab = 0;
204 			while (fscanf(fin, "%s", p) != EOF) {
205 				chtab[dev.nchtab++] = p - chname;
206 				while (*p++)	/* skip to end of name */
207 					;
208 			}
209 			dev.lchname = p - chname;
210 			chtab[dev.nchtab++] = 0;	/* terminate properly */
211 		} else
212 			fprintf(stderr, "makedev: unknown command %s\n", cmd);
213 	}
214 	if (argc > 0 && strcmp(argv[1], "DESC") == 0) {
215 		fdout = creat(fout, 0666);
216 		if (fdout < 0) {
217 			fprintf(stderr, "makedev: can't open %s\n", fout);
218 			exit(1);
219 		}
220 		write(fdout, &dev, sizeof (struct dev));
221 		/* we need a 0 on the end */
222 		write(fdout, size, (dev.nsizes+1) * sizeof (size[0]));
223 		write(fdout, chtab, dev.nchtab * sizeof (chtab[0]));
224 		write(fdout, chname, dev.lchname);
225 		totfont = 0;
226 		for (i = 0; i < dev.nfonts; i++) {
227 			totfont += dofont(fname[i]);
228 			write(fdout, &font, sizeof (struct Font));
229 			write(fdout, width, font.nwfont & BYTEMASK);
230 			write(fdout, kern, font.nwfont & BYTEMASK);
231 			write(fdout, code, font.nwfont & BYTEMASK);
232 			write(fdout, fitab, dev.nchtab+128-32);
233 		}
234 		/* back to beginning to install proper size */
235 		lseek(fdout, 0L, 0);
236 		dev.filesize =		/* excluding dev struct itself */
237 			(dev.nsizes+1) * sizeof (size[0])
238 			+ dev.nchtab * sizeof (chtab[0])
239 			+ dev.lchname * sizeof (char)
240 			+ totfont * sizeof (char);
241 		write(fdout, &dev, sizeof (struct dev));
242 		close(fdout);
243 		argc--;
244 		argv++;
245 	}
246 	for (i = 1; i < argc; i++)
247 		dofont(argv[i]);
248 	exit(0);
249 }
250 
251 
252 int
dofont(char * name)253 dofont(char *name)
254 	/* string containing name of font */
255 {
256 
257 
258 	FILE	*fin;			/* input file descriptor */
259 	int	fdout;			/* output file descriptor */
260 	int	i, nw = 0, spacewidth, n = 0, v;
261 	char 	buf[100], ch[10], s1[10], s2[10], s3[10], cmd[30];
262 	char	s4[10];			/* used to check for extra info */
263 	int	count;			/* value returned from sscanf() */
264 	int	dflt_range;		/* default maximum range for font */
265 	int	dflt_slant;		/* default slant for this font */
266 
267 	/*
268 	 * This routine is responsible for making the '.out' file for
269 	 * the font specified by the parameter name. It also sets up some
270 	 * of the data structures needed to make the DESC.out file in the
271 	 * main routine. In addition I have changed this routine so that
272 	 * we can add some typesetter dependent parameters to the font
273 	 * files and have this information dumped out to a 'add' file
274 	 * for this font, which can be read as needed by the aps driver.
275 	 */
276 	if ((fin = fopen(name, "r")) == NULL) {
277 		fprintf(stderr, "makedev: can't open font %s\n", name);
278 		exit(2);
279 	}	/* End if */
280 
281 	sprintf(cmd, "%s.out", name);	/* output file is name.out */
282 	fdout = creat(cmd, 0666);
283 
284 	font.specfont = 0;		/* by default it isn't special font */
285 	font.ligfont = 0;		/* and has no ligatures */
286 	font.spare1 = 0;		/* all the flags are initially off */
287 	spacewidth = 0;			/* really useful for CW font */
288 	dflt_range = 3;			/* max range available on our APS-5 */
289 	dflt_slant = 0;			/* no slant for this font yet */
290 
291 	for (i = 0; i < NFITAB; i++)	/* initialize font index table */
292 		fitab[i] = 0;
293 
294 	for (i = 0; i < FSIZE; i++)  {	/* initialize font index table */
295 		width[i] = kern[i] = code[i] = 0;
296 		alt_font[i] = 0;
297 		alt_code[i] = 0;
298 	}	/* End for */
299 
300 	while (fscanf(fin, "%s", cmd) != EOF)  {	/* read the font file */
301 
302 		if (cmd[0] == '#')
303 			skipline(fin);
304 		else if (strcmp(cmd, "name") == 0)
305 			fscanf(fin, "%s", font.namefont);
306 		else if (strcmp(cmd, "internalname") == 0)
307 			fscanf(fin, "%s", font.intname);
308 		else if (strcmp(cmd, "special") == 0)
309 			font.specfont = 1;
310 		else if (strcmp(cmd, "ligatures") == 0) {
311 			font.ligfont = getlig(fin);
312 		} else if (strcmp(cmd, "spacewidth") == 0) {
313 			fscanf(fin, "%d", &spacewidth);
314 			/* width of space on this font */
315 			width[0] = spacewidth;
316 		} else if (strcmp(cmd, "charset") == 0) {
317 			skipline(fin);
318 			nw = 0;
319 
320 			/* widths are origin 1 so fitab==0 can mean */
321 			/* "not there" */
322 
323 			while (fgets(buf, 100, fin) != NULL)  {
324 
325 				count = sscanf(buf, "%s %s %s %s %s", ch, s1,
326 				    s2, s3, s4);
327 
328 				if (s1[0] != '"') {
329 					/* it's a genuine new character */
330 
331 					nw++;
332 					width[nw] = atoi(s1);
333 					kern[nw] = atoi(s2);
334 
335 					/* temporarily, pick up one byte as */
336 					/* code */
337 
338 					if (s3[0] == '0')
339 						sscanf(s3, "%o", &i);
340 					else
341 						sscanf(s3, "%d", &i);
342 					code[nw] = i;
343 
344 					if (count > 4 && font.spare1)
345 						finish_line(buf, nw);
346 
347 				}	/* End if */
348 
349 				/* otherwise it's a synonym for previous */
350 				/* character, so leave previous values intact */
351 
352 				if (strlen(ch) == 1)	/* it's ascii */
353 					fitab[ch[0] - 32] = nw;
354 					/* fitab origin omits non-graphics */
355 				else {		/* it has a funny name */
356 					for (i = 0; i < dev.nchtab; i++)
357 						if (strcmp(&chname[chtab[i]],
358 						    ch) == 0) {
359 							/* starts after the */
360 							/* ascii */
361 							fitab[i + 128-32] = nw;
362 							break;
363 						}	/* End if */
364 
365 					if (i >= dev.nchtab)
366 						fprintf(stderr,
367 						    "makedev: font %s: %s not "
368 						    "in charset\n", name, ch);
369 				}	/* End else */
370 
371 			}	/* End while */
372 			nw++;
373 			if (dev.biggestfont >= nw)
374 				n = dev.biggestfont;
375 			else {
376 				if (dev.biggestfont > 0)
377 					fprintf(stderr, "font %s too big\n",
378 					    name);
379 				n = nw;
380 			}
381 			font.nwfont = n;
382 		} else if (strcmp(cmd, "alternate_font") == 0)
383 			font.spare1 |= FONT_BIT; /* set alternate font bit */
384 		else if (strcmp(cmd, "default_slant") == 0)  {
385 			/* clear two slant val bits */
386 			font.spare1 &= ~(3 << SLANT_VAL);
387 			/* set font slant bit */
388 			font.spare1 |= SLANT_BIT;
389 			/* read the default slant value */
390 			fscanf(fin, "%d", &dflt_slant);
391 			if (dflt_slant > 0)		/* encode it as 01 */
392 				font.spare1 |= (1 << SLANT_VAL);
393 			else if (dflt_slant < 0)	/* encode it as 10 */
394 				font.spare1 |= (1 << (SLANT_VAL + 1));
395 		} else if (strcmp(cmd, "max_range") == 0)  {
396 			/* set range bit in spare1 */
397 			font.spare1 |= RANGE_BIT;
398 			/* read default font slant */
399 			fscanf(fin, "%d", &dflt_range);
400 			if (dflt_range < 1 || dflt_range > 4)  {
401 				fprintf(stderr,
402 				    "makedev: illegal default range %d\n",
403 				    dflt_range);
404 				exit(1);
405 			}	/* End if */
406 			font.spare1 |= (dflt_range << RANGE_VAL);
407 		} else if (strcmp(cmd, "debug") == 0)
408 			dbg++;
409 
410 	}	/* End while */
411 
412 	if (spacewidth == 0)
413 		width[0] = dev.res * dev.unitwidth / 72 / 3;
414 	fclose(fin);
415 
416 	write(fdout, &font, sizeof (struct Font));
417 	write(fdout, width, font.nwfont & BYTEMASK);
418 	write(fdout, kern, font.nwfont & BYTEMASK);
419 	write(fdout, code, font.nwfont & BYTEMASK);
420 	write(fdout, fitab, dev.nchtab+128-32);
421 	close(fdout);
422 
423 	if (font.spare1)
424 		add_font(name);
425 
426 	if (dbg)
427 		dump_font();
428 
429 	v = sizeof (struct Font) + 3 * n + dev.nchtab + 128-32;
430 	if (verbose)
431 		fprintf(stderr, "%3s: %3d chars, width %3d, size %3d\n",
432 			font.namefont, nw, width[0], v);
433 	return (v);
434 
435 }	/* End of dofont */
436 
437 
438 /* pick up ligature list */
439 int
getlig(FILE * fin)440 getlig(FILE *fin)
441 {
442 
443 
444 	int	lig;
445 	char	temp[100];
446 
447 
448 	lig = 0;
449 	while (fscanf(fin, "%s", temp) != EOF && strcmp(temp, "0") != 0) {
450 		if (strcmp(temp, "fi") == 0)
451 			lig |= LFI;
452 		else if (strcmp(temp, "fl") == 0)
453 			lig |= LFL;
454 		else if (strcmp(temp, "ff") == 0)
455 			lig |= LFF;
456 		else if (strcmp(temp, "ffi") == 0)
457 			lig |= LFFI;
458 		else if (strcmp(temp, "ffl") == 0)
459 			lig |= LFFL;
460 		else
461 			fprintf(stderr, "illegal ligature %s\n", temp);
462 	}
463 
464 	skipline(fin);
465 	return (lig);
466 
467 }	/* End of getlg */
468 
469 
470 void
finish_line(char * buf,int nw)471 finish_line(
472 	char	*buf,			/* last input line */
473 	int	nw)			/* data for next char goes here */
474 {
475 
476 
477 	char	s[3][20];		/* used for special char commands */
478 	char	v[3][20];		/* and their values */
479 	int	count;			/* number of extra commands */
480 	int	range;			/* largest allowed master range */
481 	int	angle;			/* slant the character by this much */
482 	int	i;			/* loop index */
483 
484 
485 /*
486  *
487  * Called from dofont() to interpret any extra fields in the current input
488  * line. The additional stuff can include one or more of the following
489  *
490  *          slant n
491  *          max_range n
492  *          font n
493  *
494  * separated by white space and in any order. In all the above n is an
495  * integer. Comments will really screw things up so leave them out of the
496  * charset part in the APS-5 font files.
497  *
498  */
499 
500 
501 	count = sscanf(buf, "%*s %*s %*s %*s %s %s %s %s %s %s",
502 	    s[0], v[0], s[1], v[1], s[2], v[2]);
503 
504 	if ((count % 2 != 0) || (count == 0))  {
505 		fprintf(stderr, "makedev: format error in charset table\n");
506 		exit(1);
507 	}	/* End if */
508 
509 	alt_code[nw] = code[nw];	/* real code will go in .add file */
510 	code[nw] = 128;			/* tells daps it's not a real code */
511 
512 	for (i = 0; i < count/2; i++)  {
513 
514 		if (strcmp(s[i], "font") == 0)  {
515 			/* get char from another font */
516 			/* daps checks this bit */
517 			code[nw] |= FONT_BIT;
518 			alt_font[nw] = atoi(v[i]);	/* APS-5 font number */
519 		} else if (strcmp(s[i], "max_range") == 0)  {
520 			code[nw] &= ~(3 << RANGE_VAL);
521 			code[nw] |= RANGE_BIT;
522 			range = atoi(v[i]);
523 			if (range < 1 || range > 4)  {
524 				fprintf(stderr, "makedev: illegal range\n");
525 				exit(1);
526 			}	/* End if */
527 			code[nw] |= (range << RANGE_VAL);
528 		} else if (strcmp(s[i], "slant") == 0)  {
529 			code[nw] &= ~(3 << SLANT_VAL);
530 			code[nw] |= SLANT_BIT;
531 			angle = atoi(v[i]);
532 			if (angle > 0)	/* again daps understands these */
533 				code[nw] |= (1 << SLANT_VAL);
534 			else if (angle < 0)
535 				code[nw] |= (1 << (SLANT_VAL + 1));
536 		} else {
537 			fprintf(stderr, "makedev: illegal command\n");
538 			exit(1);
539 		}	/* End else */
540 
541 	}	/* End for */
542 	if (code[nw] & BYTEMASK == 128)  {
543 		fprintf(stderr, "makedev: char code %d less than 129\n",
544 		    code[nw]);
545 		exit(1);
546 	}	/* End if */
547 
548 }	/* End of finish_line */
549 
550 
551 void
add_font(char * name)552 add_font(char *name)
553 {
554 
555 
556 	int	fdout;			/* output file descriptor */
557 	int	k;			/* number of width entries */
558 	char	cmd[30];		/* used to create output file */
559 
560 
561 
562 /*
563  *
564  * If there were any special requests made in the current font file we'll
565  * want to save the real data (for daps) in a binary file that ends with
566  * the suffix ".add". When daps tries to print a character and finds that
567  * it's character code bigger than 129 it knows it will need to get more
568  * real data from the appropriate .add file.
569  *
570  */
571 
572 
573 
574 	sprintf(cmd, "%s.add", name);		/* file will be 'name'.add */
575 	fdout = creat(cmd, 0666);
576 
577 	k = font.nwfont & BYTEMASK;
578 
579 	write(fdout, alt_font, k * sizeof (alt_font[0]));
580 	write(fdout, alt_code, k);
581 
582 	close(fdout);
583 
584 }	/* End of add_font */
585 
586 
587 void
dump_font(void)588 dump_font(void)
589 {
590 
591 
592 	int	pos;			/* position in character tables */
593 	int	j;			/* for loop index */
594 	int	code_val;		/* number in code table */
595 
596 
597 
598 /*
599  *
600  * Just a debugging routine that's really not important anymore. It's
601  * called from dofont() after everything's been built for the current
602  * font file. Need to include the string "debug" in the font file that
603  * we want to check.
604  *
605  */
606 
607 
608 	printf("DATA FOR FONT %s:\n\n", font.namefont);
609 
610 	printf("  font structure data:\n");
611 	printf("\t\tfont.nwfont = %d\n", font.nwfont & BYTEMASK);
612 	printf("\t\tfont.specfont = %d\n", font.specfont & BYTEMASK);
613 	printf("\t\tfont.ligfont = %d\n", font.ligfont & BYTEMASK);
614 	printf("\t\tfont.spare1 = 0%o\n", font.spare1 & BYTEMASK);
615 	printf("\t\tfont.intname = %s\n\n", font.intname);
616 
617 	printf("  CHAR     WIDTH      KERN      CODE     INDEX\n");
618 
619 	for (j = 0; j < dev.nchtab + 128 - 32; j++)  {
620 
621 		if ((pos = fitab[j] & BYTEMASK) != 0)  {
622 			if (j >= 96)
623 				printf("%5s", &chname[chtab[j-96]]);
624 			else printf("%5c", (j + 32) & BYTEMASK);
625 			printf("%10d", width[pos] & BYTEMASK);
626 			printf("%10d", kern[pos] & BYTEMASK);
627 			code_val = code[pos] & BYTEMASK;
628 			printf("%10d", code_val & BYTEMASK);
629 			printf("%10d", j);
630 
631 			if (code_val > 128)  {
632 				printf("%5d", alt_code[pos] & BYTEMASK);
633 				if (code_val & SLANT_BIT)
634 					printf("  slant %d",
635 					    (code_val >> SLANT_VAL) & 03);
636 				if (code_val & FONT_BIT)
637 					printf("  font %d", alt_font[pos]);
638 				if (code_val & RANGE_BIT)
639 					printf("  range %d",
640 					    (code_val >> RANGE_VAL) & 03);
641 			}	/* End if */
642 
643 			printf("\n");
644 		}	/* End if */
645 
646 	}	/* End for */
647 
648 	printf("\n\n");
649 
650 }	/* End of dump_font */
651