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 1989 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 "daps.c	1.6	05/06/08 SMI"	*/
32 
33 /*
34  * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
35  *
36  * Sccsid @(#)daps.c	1.8 (gritter) 7/9/06
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 char *xxxvers = "troff.d/devaps/daps.c	1.2";
50 
51 
52 
53 /****************************************************************************
54  *																			*
55  *		This is the post-processor for the APS-5 phototypesetter. The 		*
56  *	language that is accepted by this program is produced by the new device	*
57  *	independent troff, and consists of the following statements,			*
58  *																			*
59  *																			*
60  *		sn			set the point size to n									*
61  *		fn			set the typesetter font to the one in position n		*
62  *		cx			output the ASCII character x 							*
63  *		Cxyz		output the code for the special character xyz. This		*
64  *					command is terminated by white space.					*
65  *		Hn			go to absolute horizontal position n					*
66  *		Vn			go to absolute vertical position n ( down is positive )	*
67  *		hn			go n units horizontally from current position			*
68  *		vn			go n units vertically from current position				*
69  *		nnc			move right nn units, then print the character c. This	*
70  *					command expects exactly two digits followed by the		*
71  *					character c.											*
72  *		w			paddable word space - no action needed					*
73  *		nb a		end of line ( information only - no action needed )		*
74  *		pn			begin page n											*
75  *		Dt ...\n	draw operation 't':										*
76  *																			*
77  *						Dl x y		line from here to x,y					*
78  *						Dc d		circle of diameter d, left side here	*
79  *						De x y		ellipse of axes x,y, left side here		*
80  *						Da u v x y	arc 									*
81  *						D~ x y x y	wiggly line by x,y then x,y				*
82  *																			*
83  *		x ... \n	device control functions:								*
84  *																			*
85  *						x i			initialize the typesetter				*
86  *						x T s		name of device is s						*
87  *						x r n h v	resolution is n units per inch. h is	*
88  *									min horizontal motion, v is min vert.	*
89  *									motion in machine units.				*
90  *						x p			pause - can restart the typesetter		*
91  *						x s			stop - done forever						*
92  *						x t			generate trailer - no-op for the APS	*
93  *						x f n s		load font position n with tables for 	*
94  *									font s. Referring to font n now means	*
95  *									font s.									*
96  *						x H n		set character height to n				*
97  *						x S n		set character slant to n				*
98  *																			*
99  *						Subcommands like i are often spelled out as "init"	*
100  *																			*
101  *		To get the post-processor running properly on your system, you may	*
102  *	have to make one or more of changes:									*
103  *																			*
104  *			Choose the appropriate description of your typesetter. These	*
105  *			values include the type of lens and the maximum master range	*
106  *			for your fonts. The values that you will need to adjust are		*
107  *			macros and defined constants located at the start of the		*
108  *			daps.h file.													*
109  *																			*
110  *			Make sure the variable 'typesetter' is properly initialized		*
111  *			to the APS-5 typesetter file on your system. If you are not		*
112  *			going to have daps directly drive the typesetter, you may 		*
113  *			want to set it to the null file, and/or initialize 'tf' to		*
114  *			be stdout. (file daps.g)										*
115  *																			*
116  *			Make sure that the accounting file pathname 'tracct' is the		*
117  *			the accounting file that you want. If no accounting is to be	*
118  *			done then initialize it to the null string. (file daps.g)		*
119  *																			*
120  *			Check to make sure that 'fontdir' is the directory that			*
121  *			contains the devaps directory where your font tables are		*
122  *			located. (file daps.g)											*
123  *																			*
124  *			If there are no characters on your font disk that need any		*
125  *			adjustment in their vertical placement, then make sure that		*
126  *			the conditional compilation flag ADJUST is undefined. I would	*
127  *			recommend that you start this way to see what your font disk	*
128  *			really looks like. (file daps.h)								*
129  *																			*
130  *																			*
131  ****************************************************************************/
132 
133 
134 
135 
136 
137 
138 #include	<stdio.h>
139 #include	<string.h>
140 #include	<ctype.h>
141 #include	<signal.h>
142 #include	<stdarg.h>
143 #include	<stdlib.h>
144 #include	<fcntl.h>
145 #include	<unistd.h>
146 #include	<pwd.h>
147 
148 #include	"aps.h"					/* APS-5 opcode definitions */
149 #include	"dev.h"					/* font and dev structure declarations */
150 
151 #include	"daps.h"				/* constant and macro definitions */
152 #include	"daps.g"				/* global variable definitions */
153 
154 
155 
156 
157 
158 /*****************************************************************************/
159 
160 
161 int
main(int argc,char * argv[])162 main (int argc, char *argv[])
163 
164 
165 {
166 
167 
168 	/********************************************************************
169 	 *																	*
170 	 *		This is the main program for the APS-5 post-processor. It 	*
171 	 *	is responsible for calling the sequence of routines that are	*
172 	 *	needed to translate troff's new typesetter independent output	*
173 	 *	language into a form that will be understood by the APS-5		*
174 	 *	phototypesetter.												*
175 	 *																	*
176 	 ********************************************************************/
177 
178 
179 	fp_debug = stderr;
180 	fp_error = stderr;
181 	fp_acct = stderr;
182 	tf = stdout;
183 
184 	get_options(argc, argv);		/* process the option list */
185 	if ( tf != stdout )				/* need to open the file */
186 		out_file();
187 	init_signals();					/* set up signal handling */
188 	acct_file();					/* open the accounting file */
189 	process_input(argc, argv);		/* translate the input files */
190 	account();						/* make sure we charge this guy */
191 	done();							/* finish up this job and reset the APS */
192 	/*NOTREACHED*/
193 	return 0;
194 
195 }	/* End of main */
196 
197 
198 /****************************************************************************/
199 
200 
201 void
get_options(int argc,char * argv[])202 get_options (int argc, char *argv[])
203 
204 
205 {
206 
207 
208 	int		save;					/* used to adjust arg_index */
209 	int		v_step = 0;				/* vertical step in -V option */
210 
211 
212 	int ch;
213 	int i, sharpsign = 0;
214 	extern char *optarg;
215 	extern int optind;
216 
217 
218 	/********************************************************************
219 	 *																	*
220 	 *		This is the routine that processes the command line option	*
221 	 *	list. The macro SET_ARGS uses the global variable arg_index to	*
222 	 *	properly initialize the local argc and argv values, while the	*
223 	 *	macro COUNT_ARGS adjusts the value of arg_index to account for	*
224 	 *	the number of arguments that were just processed.				*
225 	 *																	*
226 	 *		The options that are currently available in this driver 	*
227 	 *	are,															*
228 	 *																	*
229 	 *				-f dir	- 	use dir as the font directory			*
230 	 *				-F dir	-	same									*
231 	 *																	*
232 	 *				-t		-	use standard output						*
233 	 *																	*
234 	 *				-r		-	report the number of pages				*
235 	 *																	*
236 	 *				-A		-	do accounting even if there is no real	*
237 	 *							accounting file. If tracct is NULL then	*
238 	 *							the accounting information is written	*
239 	 *							to stderr. This is the way things are	*
240 	 *							done on our APS.						*
241 	 *																	*
242 	 *				-b		-	report whether typesetter is busy or	*
243 	 *							not. Nothing is printed.				*
244 	 *																	*
245 	 *				-w		-	wait until typesetter is available,		*
246 	 *							then procees the job.					*
247 	 *																	*
248 	 *				-o[str]	-	process only this list of pages. The	*
249 	 *							list may contain single pages or page	*
250 	 *							ranges, where the latter consists of 	*
251 	 *							a pair of pages separated by -.			*
252 	 *																	*
253 	 *				-s[num]	-	stop processing every num pages, and	*
254 	 *							HALT the typesetter.					*
255 	 *																	*
256 	 *				-v[num] -	use num as the maximum vertical step	*
257 	 *							size up or down the page. The argument	*
258 	 *							num is interpreted as 10ths of a point.	*
259 	 *																	*
260 	 *				-h[str]	-	use str as the string to be printed		*
261 	 *							in the header.							*
262 	 *																	*
263 	 *				-H[str]	-	use str as the pathname of the file		*
264 	 *							whose first line contains the string	*
265 	 *							to be printed in the header.			*
266 	 *																	*
267 	 *				-d[str] -	toggle the debug flags for each number	*
268 	 *							contained in the string str. If str		*
269 	 *							contains the character '*' then all of	*
270 	 *							the debug flags will be toggled.		*
271 	 *																	*
272 	 *				-D[str] -	dump all of the debug information into	*
273 	 *							file str. If this option is not used	*
274 	 *							then the debugging stuff is written to	*
275 	 *							stderr.									*
276 	 *																	*
277 	 *				-L[str] -	use the file str as the log file for	*
278 	 *							all error messages. If this option is	*
279 	 *							not used then all error messages will	*
280 	 *							be written to stderr.					*
281 	 *																	*
282 	 *				-I		-	ignore all FATAL errors. This option is	*
283 	 *							only to be used for debugging - it may	*
284 	 *							cause a core file to be written.		*
285 	 *																	*
286 	 ********************************************************************/
287 
288 
289 
290 	SET_ARGS(save);					/* MACRO - adjust internal argc and argv */
291 
292 	while ((ch = getopt(argc, argv, "f:F:trAbwo:s:h:H:d:D:L:Iv:c:#"))
293 		!= EOF) {				/*read options list*/
294 
295 		switch ( ch )  {					/* check option */
296 
297 			case 'f':								/* font directory */
298 			case 'F':
299 						fontdir = optarg;
300 						break;
301 
302 			case 't':								/* use standard output */
303 						tf = stdout;
304 						break;
305 
306 			case 'r':								/* print page report */
307 						report = YES;
308 						break;
309 
310 			case 'A':								/* do accounting! */
311 						if ( privelege == ON )
312 							x_stat |= DO_ACCT;
313 						break;
314 
315 			case 'b':								/* check if busy or not */
316 						busyflag = ON;
317 						break;
318 
319 			case 'w':								/* wait til APS is free */
320 						waitflag = ON;
321 						break;
322 
323 			case 'o':								/* process page list */
324 						outlist(optarg);
325 						break;
326 
327 			case 's':								/* stop every spage(s) */
328 						spage = atoi(optarg);
329 						if ( spage <= 0 )			/* illegal page number */
330 							spage = 9999;
331 						break;
332 
333 			case 'h':								/* banner is in argument */
334 						banner = optarg;
335 						print_banner = YES;
336 						break;
337 
338 			case 'H':								/* banner is in file */
339 						ban_file(optarg);
340 						print_banner = YES;
341 						break;
342 
343 			case 'd':								/* selective debug */
344 						debug_select(optarg);
345 						break;
346 
347 			case 'D':								/* set up debug file */
348 						debug_file(optarg);
349 						break;
350 
351 			case 'L':								/* set up log file */
352 						log_file(optarg);
353 						break;
354 
355 			case 'I':								/* ignore fatal errors */
356 						if ( privelege == ON )
357 							ignore = YES;
358 						break;
359 
360 			case 'v':								/* set max vertical step */
361 						v_step = atoi(optarg);
362 						if ( v_step != 0 )
363 							vert_step = ( v_step > 0 ) ? v_step
364 													   : -v_step;
365 						if ( vert_step > MAX_INT )	/* its too big */
366 							vert_step = MAX_INT;
367 						break;
368 
369 			case 'c':								/* set beam cutoff */
370 						if ( (cutoff = atof(optarg)) <= 0 )
371 							cutoff = CUTOFF;
372 						break;
373 
374 		case '#':
375 			sharpsign = 1;
376 			break;
377 			default:								/* didn't find it */
378 						error(NON_FATAL, "illegal option %c", argv[1][1]);
379 						break;
380 
381 		}	/* End of switch */
382 
383 	}	/* End while */
384 
385 	argc -= optind - 1;
386 	COUNT_ARGS(save);				/* MACRO - adjust arg_index */
387 	if (sharpsign == 1) {
388 		fprintf(stderr, "report = %d, x_stat = %o\n",
389 			report, x_stat);
390 		fprintf(stderr, "busyflag = %d, waitflag = %d, ignore = %d\n",
391 			busyflag, waitflag, ignore);
392 		fprintf(stderr, "fontdir = %s, spage = %d, banner = %s\n",
393 			fontdir, spage, banner);
394 		fprintf(stderr, "v_step = %d, cutoff = %g\n",
395 			v_step, cutoff);
396 		for (i=0; i<nolist; i+=2)
397 			fprintf (stderr, "olist[%d] is %d; olist[%d] is %d.\n",
398 				i, olist[i], i+1, olist[i+1]);
399 		for (i=0; i<MAX_DEBUG; i+=4)
400 			fprintf(stderr, "debug[%d] = %d, %d, %d, %d\n",
401 				i,debug[i],debug[i+1],debug[i+2],debug[i+3]);
402 		if (fp_debug != stderr)
403 			fprintf(stderr, "fp_debug is %p\n", fp_debug);
404 		if (fp_error != stderr)
405 			fprintf(stderr, "fp_error is %p\n", fp_error);
406 		if (tf != stdout)
407 			fprintf(stderr, "tf is %p\n", tf);
408 	}
409 
410 }	/* End of get_options */
411 
412 
413 /*****************************************************************************/
414 
415 
416 void
process_input(int argc,char * argv[])417 process_input (int argc, char *argv[])
418 
419 
420 {
421 
422 
423 	FILE	*fp_in;					/* input file descriptor */
424 	int 	save;					/* used to adjust arg_index before exit */
425 
426 
427 
428 	/********************************************************************
429 	 *																	*
430 	 *		This routine is called by main to handle the processing		*
431 	 *	of the input files from the command line. If there were no		*
432 	 *	files specified in the call then the post-processor will read	*
433 	 *	from the standard input. Otherwise it will process all of the	*
434 	 *	input files in the list, concatenating the output from each		*
435 	 *	one onto the output file. The only convention that is used for	*
436 	 *	input file names is that the character '-' as a file name will	*
437 	 *	cause the driver to read from the standard input, provided it	*
438 	 *	isn't the first 'file' in the list of input files. It would		*
439 	 *	probably be better if we chose some other character or sequence	*
440 	 *	of characters for this purpose.									*
441 	 *																	*
442 	 ********************************************************************/
443 
444 
445 
446 	SET_ARGS(save);						/* MACRO - adjust argc and argv */
447 
448 	if ( argc <= 1 ) conv(stdin);		/* no more args - use stdin */
449 	else  {								/* read input file list */
450 		while ( --argc > 0 )  {			/* rest of the args are input files */
451 
452 			if ( strcmp(*++argv, "-") == 0 )	/* use standard input */
453 				fp_in = stdin;
454 			else if ( (fp_in = fopen(*argv, "r")) == NULL )  {
455 					error(FATAL, "can't open input file %s", *argv);
456 					continue;			/* in case we ignore this error */
457 			}	/* End else */
458 
459 			conv(fp_in);				/* translate the file */
460 			if ( fp_in != stdin )		/* probably don't need it anymore */
461 				fclose(fp_in);
462 
463 		}	/* End of while */
464 	}	/* End else */
465 
466 	COUNT_ARGS(save);					/* MACRO - adjust arg_index */
467 
468 }	/* End of process_input */
469 
470 
471 /****************************************************************************/
472 
473 
474 void
init_signals(void)475 init_signals (void)
476 
477 
478 {
479 
480 
481 
482 
483 
484 	/********************************************************************
485 	 *																	*
486 	 *		This routine is called by main to set up the appropriate	*
487 	 *	handling of external signals for the post-processor. As 		*
488 	 *	currently written interrupts, quits and hangups are all either	*
489 	 *	ignored or processed by the routine wrap_up().					*
490 	 *																	*
491 	 ********************************************************************/
492 
493 
494 
495 	signal(SIGFPE, float_err);			/* catch floating point errors */
496 
497 	if ( signal(SIGINT, wrap_up) == SIG_IGN )  {	/* ignoring interrupts */
498 		signal(SIGINT, SIG_IGN);					/* so reset SIGINT */
499 		signal(SIGQUIT, SIG_IGN);					/* and ignore the rest */
500 		signal(SIGHUP, SIG_IGN);
501 	} else {										/* wrap_up() handles them */
502 		signal(SIGQUIT, wrap_up);
503 		signal(SIGHUP, wrap_up);
504 	}	/* End if */
505 
506 }	/* End of init_signals */
507 
508 
509 /*****************************************************************************/
510 
511 
512 void
debug_select(char * str)513 debug_select (
514     char *str						/* string of debug flags */
515 )
516 
517 
518 {
519 
520 
521 	int		index;						/* single debug flag to toggle */
522 	int		i;							/* for loop index */
523 
524 
525 
526 	/********************************************************************
527 	 *																	*
528 	 *		This routine is called by main() when it finds the -d		*
529 	 *	option.	The parameter str is a pointer to a string of comma		*
530 	 *	separated tokens from the command line that specify which of 	*
531 	 *	the debug flags is to be toggled. As currently implemented the	*
532 	 *	tokens in str may consist of numbers, which specify the actual	*
533 	 *	flag to be toggled, or the character '*', which stands for all	*
534 	 *	of the available debug flags.									*
535 	 *																	*
536 	 ********************************************************************/
537 
538 
539 
540 	while ( *str )  {
541 
542 		if ( isdigit(*str) )  {			/* have a single debug flag */
543 			STR_CONVERT(str, index);	/* MACRO - get the debug flag */
544 			if ( index >= 0  &&  index < MAX_DEBUG )
545 				TOGGLE(debug[index]);	/* MACRO - toggle it */
546 		} else if ( *str == '*' )		/* toggle all the debug flags */
547 			for ( i = 0; i < MAX_DEBUG; i++ )
548 				TOGGLE(debug[i]);		/* MACRO */
549 
550 		if ( *str != '\0' ) str++;		/* skip the comma */
551 
552 	}	/* End while */
553 
554 }	/* End of debug_select */
555 
556 
557 /*****************************************************************************/
558 
559 
560 void
debug_file(char * str)561 debug_file (
562     char *str						/* debug file pathname */
563 )
564 
565 
566 {
567 
568 
569 
570 	/********************************************************************
571 	 *																	*
572 	 *		This routine is called by get_options() when it finds the	*
573 	 *	-D option in the command line. The parameter str is a pointer	*
574 	 *	to the pathname of the file to be used for all of the debugging	*
575 	 *	output. If the -D option is not specified then by default all	*
576 	 *	the debug output is written to stderr.							*
577 	 *																	*
578 	 ********************************************************************/
579 
580 
581 
582 	if ( (fp_debug = fopen(str, "w")) == NULL )  {
583 		fp_debug = stderr;
584 		error(NON_FATAL, "can't open debug file %s", str);
585 	}	/* End if */
586 
587 }	/* End of debug_file */
588 
589 
590 /*****************************************************************************/
591 
592 
593 void
log_file(char * str)594 log_file (
595     char *str						/* log file pathname */
596 )
597 
598 
599 {
600 
601 
602 
603 	/********************************************************************
604 	 *																	*
605 	 *		This routine is called to open the log file for the APS-5	*
606 	 *	post-processor. The pathname of the file is passed in the		*
607 	 *	parameter str when this routine is called from get_options().	*
608 	 *	If the log file isn't specified then the post-processor will	*
609 	 *	write all of it's error messages to stderr.						*
610 	 *																	*
611 	 ********************************************************************/
612 
613 
614 
615 	if ( (fp_error = fopen(str, "a")) == NULL )  {
616 		fp_error = stderr;
617 		error(FATAL, "can't open log file %s", str);
618 	}	/* End if */
619 
620 }	/* End of log_file */
621 
622 
623 /*****************************************************************************/
624 
625 
626 void
acct_file(void)627 acct_file (void)
628 
629 
630 {
631 
632 
633 
634 	/********************************************************************
635 	 *																	*
636 	 *		This routine is called to open the accounting file whose	*
637 	 *	pathname is pointed to by the variable tracct. If there is no	*
638 	 *	pathname in tracct then nothing is done in this routine, while	*
639 	 *	if we are unable to open the accounting file then an error		*
640 	 *	message is printed out and we quit.								*
641 	 *																	*
642 	 ********************************************************************/
643 
644 
645 
646 	if ( *tracct )  {					/* we have an accnt file pathname */
647 
648 		if ( (fp_acct = fopen(tracct, "a")) == NULL )  {	/* so open it */
649 			fp_acct = stderr;			/* couldn't open accounting file */
650 			x_stat |= NO_ACCTFILE;		/* indicate this in the exit status */
651 			error(FATAL, "unable to open accounting file");
652 			exit(x_stat);				/* in case we ignore this error */
653 		}	/* End if */
654 		x_stat |= DO_ACCT;				/* accounting needs to be done */
655 
656 	}	/* End if */
657 
658 }	/* End of acct_file */
659 
660 
661 /*****************************************************************************/
662 
663 
664 void
ban_file(char * str)665 ban_file (
666     char *str						/* banner file pathname */
667 )
668 
669 
670 {
671 
672 
673 	FILE	*fp_ban;					/* banner file descriptor */
674 
675 
676 
677 	/********************************************************************
678 	 *																	*
679 	 *		This routine is called from get_options() to read the 		*
680 	 *	banner string from the first line of the file whose pathname is	*
681 	 *	contained in the string str.									*
682 	 *																	*
683 	 ********************************************************************/
684 
685 
686 
687 	if ( (fp_ban = fopen(str, "r")) == NULL )  {
688 		error(NON_FATAL, "can't open the banner file %s", str);
689 		return;
690 	}	/* End if */
691 
692 	GET_LINE(fp_ban, ban_buf);			/* MACRO - banner is first line only */
693 	banner = ban_buf;					/* t_banner() prints string *banner */
694 
695 	fclose(fp_ban);						/* shouldn't need this file again */
696 
697 }	/* End of ban_file */
698 
699 
700 /*****************************************************************************/
701 
702 
703 void
out_file(void)704 out_file (void)
705 
706 
707 {
708 
709 
710 
711 	/********************************************************************
712 	 *																	*
713 	 *		This routine is called from the main program to open the	*
714 	 *	file pointed to by typesetter.									*
715 	 *																	*
716 	 ********************************************************************/
717 
718 
719 
720 	do  {
721 		tf = fopen(typesetter, "w");	/* typesetter output file */
722 		if ( busyflag == ON )  {		/* report status and then exit */
723 			printf(tf == NULL ? "Busy.\n" : "Available.\n");
724 			exit(0);
725 		}	/* End if */
726 
727 		if ( tf == NULL )  {			/* didn't open on last try */
728 			if ( waitflag == OFF )  {	/* he doesn't want to wait */
729 				error(NON_FATAL, "can't open typesetter");
730 				exit(NO_OUTFILE);
731 			}	/* End if */
732 			else sleep(60);				/* try again later */
733 		}	/* End if */
734 	}  while ( tf == NULL );
735 
736 }	/* End of out_file */
737 
738 
739 /*****************************************************************************/
740 
741 
742 void
outlist(char * str)743 outlist (
744     char *str						/* string of pages to process */
745 )
746 
747 
748 {
749 
750 
751 	int		start, stop;				/* page range end points */
752 	int		i;							/* loop index - debug only */
753 
754 
755 
756 	/********************************************************************
757 	 *																	*
758 	 *		This routine is called when the -o option is read in		*
759 	 *	the command line. The parameter str points to a list of page	*
760 	 *	numbers to be processed. This list consists single pages or 	*
761 	 *	page ranges, separated by commas. A page range is specified by	*
762 	 *	separating two page numbers by the character '-'. In this case	*
763 	 *	all pages in this closed interval will be processed by daps.	*
764 	 *																	*
765 	 ********************************************************************/
766 
767 
768 
769 	while ( *str  &&  nolist < MAX_OUTLIST - 2 )  {
770 
771 		start = 0;
772 
773 		if ( isdigit(*str) )				/* page number should begin here */
774 			STR_CONVERT(str,start);			/* MACRO - get left end point */
775 		else start = -9999;					/* use lowest possible page */
776 
777 		stop = start;						/* in case it is a single page */
778 
779 		if ( *str == '-' )  {				/* have a page range */
780 			str++;							/* so skip the minus sign */
781 			if ( isdigit(*str) )			/* page number begins here */
782 				STR_CONVERT(str,stop);		/* MACRO - get right end point */
783 			else stop = 9999;				/* use largest possible page */
784 		}	/* End if */
785 
786 		if ( start > stop )
787 			error(FATAL,"illegal range %d-%d",start,stop);
788 
789 		olist[nolist++] = start;			/* save the page range */
790 		olist[nolist++] = stop;
791 
792 		if ( *str != '\0' ) str++;			/* skip the comma */
793 
794 	}	/* End while */
795 
796 	olist[nolist] = 0;						/* terminate the page list */
797 
798 	if ( *str )							/* too many pages for olist array */
799 		error(NON_FATAL, "skipped pages %s", str);
800 
801 	if ( debug[1] )							/* dump the olist[] array */
802 		for ( i = 0; i < nolist; i += 2 )
803 			fprintf(fp_debug,"%3d  %3d\n", olist[i], olist[i+1]);
804 
805 }	/* End of outlist */
806 
807 
808 /*****************************************************************************/
809 
810 
811 void
error(int kind,char * str,...)812 error (
813     int kind,					/* kind of error ie. FATAL or NON_FATAL */
814     char *str,					/* pointer to message to be printed */
815     ...
816 )
817 
818 
819 {
820 
821 
822 	/********************************************************************
823 	 *																	*
824 	 *		This routine is called when the post-processor has found	*
825 	 *	an internal error. The parameter kind has the value FATAL or	*
826 	 *	NON_FATAL, and accordingly determines whether processing will	*
827 	 *	continue or not. The parameter str is a pointer to the error	*
828 	 *	message that is to be printed. All the remaining parameters		*
829 	 *	are the arguments that may be referenced in the control string	*
830 	 *	str.															*
831 	 *																	*
832 	 *		The global variable ignore is initialized to NO in the		*
833 	 *	file daps.globals, and can be set to YES by using the -I option	*
834 	 *	in the command line. This will allow the post-processor to		*
835 	 *	continue after a normally FATAL error has been encountered. 	*
836 	 *	This is only a debugging feature and should not generally be	*
837 	 *	used.															*
838 	 *																	*
839 	 ********************************************************************/
840 
841 
842 	va_list ap;
843 
844 	fprintf(fp_error, "daps: ");
845 	if ( (kind == NON_FATAL) && (line_number > 0) )
846 		fprintf(fp_error, "warning - ");
847 	va_start(ap, str);
848 	vfprintf(fp_error, str, ap);
849 	va_end(ap);
850 
851 	if ( line_number > 0 )
852 		fprintf(fp_error, " ( line = %ld )", line_number);
853 	fprintf(fp_error, "\n");
854 
855 	if ( ignore == YES  &&  privelege == ON )
856 		return;
857 
858 	if ( kind == FATAL )			/* can't ignore this error */
859 		wrap_up(0);					/* so quit */
860 
861 }	/* End of error */
862 
863 
864 /*****************************************************************************/
865 
866 
867 int
done(void)868 done (void)
869 
870 
871 {
872 
873 
874 
875 	/********************************************************************
876 	 *																	*
877 	 *		This routine is called to do the final processing for the	*
878 	 *	current job. If there is to be any accounting for this job we	*
879 	 *	need to be sure that the account function is called first		*
880 	 *	because there is nothing more we can do when we get here.		*
881 	 *																	*
882 	 ********************************************************************/
883 
884 
885 
886 	if ( tf == NULL ) 					/* Nowhere to write */
887 		exit(x_stat | NO_OUTFILE);		/* so set the bit in x_stat and quit */
888 
889 	t_reset('s');						/* get APS ready for the next job */
890 	exit(x_stat);						/* quit with status x_stat */
891 
892 }	/* End of done */
893 
894 
895 /*****************************************************************************/
896 
897 
898 void
float_err(int sig)899 float_err (
900     int sig						/* signal number - not used */
901 )
902 
903 
904 {
905 
906 
907 
908 	/********************************************************************
909 	 *																	*
910 	 *		Called when a floating point error has been detected.		*
911 	 *	Needed because we want to make sure we exit gracefully if a		*
912 	 *	users job would normally dump a core file.						*
913 	 *																	*
914 	 ********************************************************************/
915 
916 
917 
918 	error(FATAL, "floating point exception");
919 
920 }	/* End of float_err */
921 
922 
923 /*****************************************************************************/
924 
925 
926 void
wrap_up(int sig)927 wrap_up (
928     int sig						/* signal number - not used */
929 )
930 
931 
932 {
933 
934 
935 
936 	/********************************************************************
937 	 *																	*
938 	 *		This routine is called to make sure that all the necessary	*
939 	 *	stuff is done when the driver finishes its job because of some	*
940 	 *	external signal or because it encountered a FATAL syntax error.	*
941 	 *																	*
942 	 ********************************************************************/
943 
944 
945 
946 	account();							/* keep some kind of record for this job */
947 	done();								/* get the APS ready for next job */
948 
949 }	/* End of wrap_up */
950 
951 
952 /*****************************************************************************/
953 
954 
955 void
conv(register FILE * fp)956 conv(
957 
958 
959 	register FILE	*fp				/* input file descriptor */
960 )
961 
962 
963 {
964 
965 
966 	register int	ch;					/* first character of the command */
967 	int		c;							/* used only as a character */
968 	int		n;							/* general purpose integer variable */
969 	char	str[100], buf[300];			/* buffers for fscanf and fgets */
970 
971 
972 
973 	/********************************************************************
974 	 *																	*
975 	 *		This is the main interpreter for the post-processor. It is	*
976 	 *	called from routine process_input with the single parameter		*
977 	 *	fp, which is the file descriptor for the current input file.	*
978 	 *																	*
979 	 *		The global variable line_number is used to keep track of	*
980 	 *	the current line in the input file fp. Its value is adjusted	*
981 	 *	in both conv() and devcntrl() and it is used in the routine		*
982 	 *	error() when error messages are written to the file fp_error.	*
983 	 *																	*
984 	 *		The bits in the global variable x_stat are used to keep 	*
985 	 *	track of the progress of the post-processor, and when the 		*
986 	 *	program exits it will return x_stat as its termination status.	*
987 	 *																	*
988 	 *																	*
989 	 *		NOTE - In order to improve the speed of this routine we may	*
990 	 *	want to declare more register variables. When we do this we 	*
991 	 *	need to be sure that the macros that are being used will accept	*
992 	 *	register variables as arguments. For example if a macro takes	*
993 	 *	the address of one of its arguments, then we can't assign this	*
994 	 *	variable to a register.											*
995 	 *																	*
996 	 ********************************************************************/
997 
998 
999 
1000 	x_stat |= FILE_STARTED;					/* indicate this in x_stat */
1001 	line_number = 1;						/* line in current input file */
1002 
1003 	while ( (ch = getc(fp) ) != EOF )  {
1004 
1005 		switch ( ch )  {					/* ch determines the command */
1006 
1007 			case 'w':						/* don't do anything for these */
1008 			case ' ':
1009 			case  0:
1010 						break;
1011 
1012 			case '\n':						/* just increment line_number */
1013 						line_number++;
1014 						break;
1015 
1016 			case '0':						/* two motion digits and a char */
1017 			case '1':
1018 			case '2':
1019 			case '3':
1020 			case '4':
1021 			case '5':
1022 			case '6':
1023 			case '7':
1024 			case '8':
1025 			case '9':
1026 						GET_DIG(fp, c);		/* MACRO - get the second digit */
1027 						hmot((ch - '0') * 10 + c - '0');
1028 
1029 				/* Be careful - we need to fall through here */
1030 
1031 			case 'c':						/* single ASCII character */
1032 						GET_CHAR(fp, c);	/* MACRO - read the character */
1033 						put1(c);			/* output c's APS-5 code */
1034 						break;
1035 
1036 			case 'h':						/* relative horizontal motion */
1037 			case 'H':						/* absolute horizontal motion */
1038 			case 'v':						/* relative vertical motion */
1039 			case 'V':						/* absolute vertical motion */
1040 			case 's':						/* set point size */
1041 			case 'p':						/* start a new page */
1042 						GET_INT(fp, n);		/* MACRO - first get an integer */
1043 						switch( ch )  {		/* and then process the command */
1044 
1045 							case 'h':	hmot(n);
1046 										break;
1047 
1048 							case 'H':	hgoto(n);
1049 										break;
1050 
1051 							case 'v':	vmot(n);
1052 										break;
1053 
1054 							case 'V':	vgoto(n);
1055 										break;
1056 
1057 							case 's':	setsize(t_size(n));
1058 										break;
1059 
1060 							case 'p':	t_page(n);
1061 										break;
1062 
1063 						}	/* End switch */
1064 						break;
1065 
1066 			case 'C':						/* process special char string */
1067 			case 'f':						/* set font */
1068 						GET_STR(fp, str);	/* MACRO - first get a string */
1069 						if ( ch == 'C' )
1070 							 put1s(str);
1071 						else setfont(t_font(str));
1072 						break;
1073 
1074 			case 'x':						/* device control function */
1075 						devcntrl(fp);
1076 						break;
1077 
1078 			case 'D':						/* drawing operation */
1079 			case 't':						/* text string upto newline */
1080 						GET_LINE(fp, buf);	/* MACRO - get rest of the line */
1081 						if ( ch == 'D' )
1082 							 drawfunct(buf, fp);
1083 						else t_text(buf);
1084 						line_number++;		/* finished with this line */
1085 						break;
1086 
1087 			case 'n':						/* end of line */
1088 			case '#':						/* comment */
1089 						SKIP_LINE(fp,c);	/* MACRO - skip rest of this line */
1090 						if ( ch == 'n' )
1091 							t_newline();
1092 						line_number++;
1093 						break;
1094 
1095 			default:						/* illegal command - quit */
1096 						error(FATAL,"unknown input character 0%o %c", ch, ch);
1097 						break;				/* in case we ignore this error */
1098 
1099 		}	/* End switch */
1100 
1101 	}	/* End while */
1102 
1103 	x_stat &= ~FILE_STARTED;				/* turn off FILE_STARTED bit in x_stat */
1104 
1105 }	/* End of conv */
1106 
1107 
1108 /*****************************************************************************/
1109 
1110 
1111 void
drawfunct(char buf[],FILE * fp)1112 drawfunct(
1113 
1114 
1115 	char	buf[],						/* drawing command */
1116 	FILE	*fp
1117 )
1118 
1119 
1120 {
1121 
1122 
1123 	int		n1, n2, n3, n4;				/* values are set in the MACROS */
1124 
1125 
1126 
1127 	/********************************************************************
1128 	 *																	*
1129 	 *		This routine interprets the drawing functions that are 		*
1130 	 *	provided by troff. The array buf[] has been filled in by the	*
1131 	 *	function conv(), and it contains the drawing command line from	*
1132 	 *	the input file. 												*
1133 	 *																	*
1134 	 ********************************************************************/
1135 
1136 
1137 
1138 	switch ( buf[0] )  {					/* process the command */
1139 
1140 		case 'l':							/* draw a line */
1141 					SCAN2(buf+1, n1, n2);	/* MACRO - get two integers */
1142 					drawline(n1, n2, ".");
1143 					break;
1144 
1145 		case 'c':							/* draw a circle */
1146 					SCAN1(buf+1, n1);		/* MACRO - get one integer */
1147 					drawcirc(n1);
1148 					break;
1149 
1150 		case 'e':							/* draw an ellipse */
1151 					SCAN2(buf+1, n1, n2);	/* MACRO - get two integers */
1152 					drawellip(n1, n2);
1153 					break;
1154 
1155 		case 'a':							/* draw an arc */
1156 					SCAN4(buf+1,n1,n2,n3,n4);	/* MACRO - get four integers */
1157 					drawarc(n1, n2, n3, n4);
1158 					break;
1159 
1160 		case '~':							/* draw spline curve */
1161 					drawwig(buf+1);
1162 					break;
1163 
1164 #ifdef PLOT
1165 		case 'p':							/* plot these points */
1166 					plot_points(buf+1, fp);
1167 					break;
1168 #endif
1169 		default:							/* don't understand the command */
1170 					error(FATAL, "unknown drawing function %s", buf);
1171 					break;					/* in case we ignore this error */
1172 
1173 	}	/* End switch */
1174 
1175 }	/* End of drawfunct */
1176 
1177 
1178 /*****************************************************************************/
1179 
1180 
1181 void
devcntrl(FILE * fp)1182 devcntrl(
1183 
1184 
1185 	FILE	*fp						/* input file descriptor */
1186 )
1187 
1188 
1189 {
1190 
1191 
1192 	int		c;							/* character used in SKIP_LINE */
1193 	int		n;							/* integer used in GET_INT */
1194 	char	str[20];					/* used to hold different strings */
1195 	char	file[50];					/* load from this font file - maybe */
1196 	char	buf[4096];					/* buffer used in GET_LINE etc. */
1197 
1198 
1199 
1200 	/********************************************************************
1201 	 *																	*
1202 	 *		This is the interpreter for the device control language		*
1203 	 *	that is produced by the new troff. The parameter fp is the file	*
1204 	 *	descriptor for the current input file.							*
1205 	 *																	*
1206 	 ********************************************************************/
1207 
1208 
1209 
1210 	GET_STR(fp, str);						/* read command from input file */
1211 
1212 	switch ( str[0] )  {					/* str[0] determines the command */
1213 
1214 		case 'i':							/* initialize the device */
1215 					fileinit();				/* read data from DESC.out */
1216 					t_init();				/* initialize the typesetter */
1217 					if ( print_banner == YES )	 /* print the job's banner */
1218 						t_banner();
1219 					break;
1220 
1221 		case 'T':							/* set device name */
1222 					GET_STR(fp, devname);	/* MACRO - get device string */
1223 					if ( strcmp(devname, "aps") != SAME_STR )
1224 						error(FATAL, "illegal typesetter %s", devname);
1225 					break;
1226 
1227 		case 't':							/* trailer - do nothing on APS-5 */
1228 					break;
1229 
1230 		case 'p':							/* pause - we can restart */
1231 		case 's':							/* stop - done with this job */
1232 					t_reset(str[0]);		/* reset the typesetter */
1233 					break;
1234 
1235 		case 'r':							/* set resolution */
1236 					GET_INT(fp, res);		/* MACRO - get one integer */
1237 					hcutoff = cutoff * res;	/* beam cutoff in device units */
1238 					break;
1239 
1240 		case 'f':							/* load a font */
1241 					GET_INT(fp, n);			/* MACRO - put font number in n */
1242 					GET_STR(fp, str);		/* MACRO - put font name in str */
1243 					GET_LINE(fp, buf);		/* MACRO - use this filename */
1244 					ungetc('\n', fp);		/* put '\n' back for SKIP_LINE */
1245 					file[0] = 0;			/* in case there is no file name */
1246 					SCAN_STR(buf, file);	/* MACRO - may have a file name */
1247 					loadfont(n, str, file);
1248 					break;
1249 
1250 		case 'H':							/* set character height */
1251 					GET_INT(fp, n);			/* MACRO - read vertical point size */
1252 					t_charht(t_size(n));
1253 					break;
1254 
1255 		case 'S':							/* set character slant */
1256 					GET_INT(fp, n);			/* MACRO - read APS slant angle */
1257 					t_slant(n);				/* set the APS slant to n */
1258 					last_req_slant = n;		/* and remember this angle */
1259 					break;
1260 
1261 		case 'X':
1262 					GET_STR(fp, buf);
1263 					if (strcmp(buf, "LC_CTYPE") == 0)
1264 						break;
1265 					/*FALLTHRU*/
1266 
1267 		default:							/* don't understand the command */
1268 					error(FATAL, "unknown device command %c", str[0]);
1269 					break;					/* in case we ignore this error */
1270 
1271 	}	/* End switch */
1272 
1273 	SKIP_LINE(fp, c);						/* finished with this line */
1274 	line_number++;
1275 
1276 }	/* End of devcntrl */
1277 
1278 
1279 /*****************************************************************************/
1280 
1281 
1282 void
t_init(void)1283 t_init (void)
1284 
1285 
1286 {
1287 
1288 
1289 	int		i;							/* for loop variable */
1290 
1291 
1292 
1293 	/********************************************************************
1294 	 *																	*
1295 	 *		This routine is called from devcntrl() when the command		*
1296 	 *	x init is read. It produces the instructions that initialize	*
1297 	 *	the APS, and then it sets up the picture drawing variables		*
1298 	 *	drawdot and drawsize.											*
1299 	 *																	*
1300 	 *																	*
1301 	 *		NOTE - the opcode STRTJOB is defined to be octal 272 in the	*
1302 	 *	file aps.h, although on our APS-5 typesetter it is one of the	*
1303 	 *	reserved but not implemented opcodes. 							*
1304 	 *																	*
1305 	 ********************************************************************/
1306 
1307 
1308 
1309 	PUTC(STRTJOB, tf);					/* MACRO - output STRTJOB opcode */
1310 	putint(1);							/* dummy argument for STRTJOB? */
1311 	PUTC(STRTPG, tf);					/* MACRO - start page 0 */
1312 	putint(0);
1313 
1314 	hpos = vpos = 0;					/* initialize page coordinates */
1315 
1316 	for ( i = 0; i < nchtab; i++ )		/* find drawing character index */
1317 		if ( strcmp(&chname[chtab[i]], "l.") == SAME_STR )
1318 			break;
1319 
1320 	if ( i < nchtab )  {				/* found it in the table */
1321 		drawdot = i + 128;				/* so use these values for drawing */
1322 		drawsize = 1;
1323 	} else  {							/* didn't find it - use default */
1324 		drawdot = '.';
1325 		drawsize = 3;
1326 	}	/* End if */
1327 
1328 }	/* End of t_init */
1329 
1330 
1331 /*****************************************************************************/
1332 
1333 
1334 void
t_banner(void)1335 t_banner (void)
1336 
1337 
1338 {
1339 
1340 
1341 	int		i;							/* while loop counter */
1342 	char 	*bp;						/* temp pointer to banner string */
1343 
1344 
1345 
1346 	/********************************************************************
1347 	 *																	*
1348 	 *		This routine is called from devcntrl() when the device		*
1349 	 *	initialization command is read. It is responsible for printing	*
1350 	 *	the job's header. This includes checking and then writing out	*
1351 	 *	the string pointed to by banner. The user may set this string	*
1352 	 *	by using either the -h or the -H options on the command line.	*
1353 	 *																	*
1354 	 ********************************************************************/
1355 
1356 
1357 
1358 	output = ON;						/* ON for routine put1() etc. */
1359 	bp = banner;						/* point to start of banner string */
1360 	i = 0;								/* characters looked at so far */
1361 
1362 	while ( *bp )						/* check at most BAN_LENGTH chars */
1363 		if ( *bp++ < ' '  ||  ++i > BAN_LENGTH )	/* unprintable or too long */
1364 			*(--bp) = '\0';				/* so last char is as far as we go */
1365 
1366 	setsize(t_size(BAN_SIZE));			/* use font 1 and point size BAN_SIZE */
1367 
1368 	vmot(VSPACE0);						/* space down for banner cut marks */
1369 	t_text(cut_marks);					/* print first set of cut marks */
1370 	hmot(HSPACE0);						/* space right for more cut marks */
1371 	t_text(cut_marks);					/* print second set of cut marks */
1372 
1373 	vmot(VSPACE1);						/* skip this far before banner */
1374 	hgoto(HSPACE1);						/* indent */
1375 	t_text(ban_sep);					/* start of banner */
1376 
1377 	vmot(VSPACE2);						/* space down for banner string */
1378 	hgoto(HSPACE2);						/* indent */
1379 	t_text(banner);						/* print the user's banner */
1380 
1381 	vmot(VSPACE3);						/* skip down for next separator */
1382 	hgoto(HSPACE3);						/* indent */
1383 	t_text(ban_sep);					/* print the second separator */
1384 
1385 	vmot(VSPACE4);						/* skip down for banner cut marks */
1386 	hgoto(HSPACE4);						/* position for first cut marks */
1387 	t_text(cut_marks);					/* print first set of cut marks */
1388 	hmot(HSPACE0);						/* skip right for second cut marks */
1389 	t_text(cut_marks);					/* print second set */
1390 
1391 	hpos = vpos = 0;					/* reset these guys again */
1392 	cur_vpos = max_vpos = 0;			/* user doesn't own the banner */
1393 	print_banner = NO;					/* don't print it again */
1394 	output = OFF;						/* output is controlled in t_page() */
1395 
1396 }	/* End of t_banner */
1397 
1398 
1399 /*****************************************************************************/
1400 
1401 
1402 void
t_page(int n)1403 t_page (int n)
1404 
1405 
1406 {
1407 
1408 
1409 	int		i;							/* for loop index */
1410 
1411 
1412 
1413 	/********************************************************************
1414 	 *																	*
1415 	 *		This routine is called from conv() to do the work that is	*
1416 	 *	necessary when we begin a new page. The STRTPG command to the	*
1417 	 *	APS-5 invokes the RESET command which sets the font to 0000,	*
1418 	 *	the master range to 1, and sets the oblique mode to normal and	*
1419 	 *	the oblique angle to 14 degrees. To reset the font and range	*
1420 	 *	properly we call setsize(), while if we were in oblique mode	*
1421 	 *	the variable aps_slant will be non-zero and so in this case		*
1422 	 *	we call routine t_slant() with aps_slant as the parameter.		*
1423 	 *																	*
1424 	 ********************************************************************/
1425 
1426 
1427 
1428 	if ( output == ON  &&  ++scount >= spage )  {	/* reached stop page */
1429 		t_reset('p');					/* so reset the APS and then HALT */
1430 		scount = 0;						/* and start counting over again */
1431 	}	/* End if */
1432 
1433 	vpos = 0;							/* we are at the top of new page */
1434 	output = ON;						/* enable output in put1() etc. */
1435 	last_slant = POS_SLANT;				/* this will be the stored angle */
1436 
1437 	PUTC(STRTPG, tf);					/* MACRO - start page n */
1438 	putint(n);
1439 	++pageno;							/* update user's page number */
1440 
1441 	setsize(size);						/* reset both the font and size */
1442 	if ( aps_slant )					/* then the APS was in oblique mode */
1443 		t_slant(aps_slant);				/* so go back to previous slant */
1444 
1445 	if ( nolist == 0 ) return;			/* no -o option, so print every page */
1446 	output = OFF;						/* otherwise -o option was specified */
1447 	for ( i = 0; i < nolist; i += 2 )	/* so check page pairs in olist[] */
1448 		if ( n >= olist[i]  &&  n <= olist[i+1] )  {
1449 			output = ON;				/* enable output for this page */
1450 			break;
1451 		}	/* End if */
1452 
1453 }	/* End of t_page */
1454 
1455 
1456 /*****************************************************************************/
1457 
1458 
1459 void
t_newline(void)1460 t_newline (void)
1461 
1462 
1463 {
1464 
1465 
1466 
1467 	/********************************************************************
1468 	 *																	*
1469 	 *		This routine is called from conv() when it has read the		*
1470 	 *	start new line command. This command has the form "n a b" where	*
1471 	 *	a and b are integers that we can safely ignore for the APS-5.	*
1472 	 *																	*
1473 	 ********************************************************************/
1474 
1475 
1476 
1477 	hpos = 0;							/* return to left margin */
1478 
1479 }	/* End of t_newline */
1480 
1481 
1482 /*****************************************************************************/
1483 
1484 
1485 int
t_size(int n)1486 t_size (
1487     int n							/* convert this point size */
1488 )
1489 
1490 
1491 {
1492 
1493 	int		i;							/* for loop index */
1494 
1495 
1496 
1497 	/********************************************************************
1498 	 *																	*
1499 	 *		This routine is called to convert the point size n to an	*
1500 	 *	internal size, which is defined as one plus the index of the	*
1501 	 *	least upper bound for n in the array pstab[]. If n is larger	*
1502 	 *	than all the entries in pstab[] then nsizes is returned.		*
1503 	 *																	*
1504 	 *																	*
1505 	 *		NOTE - this routine expects the entries in pstab[] to be in	*
1506 	 *	increasing numerical order, but it doesn't require this list to	*
1507 	 *	be terminated by a 0 point size entry.							*
1508 	 *																	*
1509 	 ********************************************************************/
1510 
1511 
1512 
1513 	if ( n >= pstab[nsizes-1] )			/* greater than all entries */
1514 		return(nsizes);					/* so use largest internal size */
1515 
1516 	for ( i = 0; n > pstab[i]; i++ )	/* otherwise find the LUB for n */
1517 		;
1518 	return(i+1);						/* internal size is i+1 */
1519 
1520 }	/* End of t_size */
1521 
1522 
1523 /*****************************************************************************/
1524 
1525 
1526 void
t_charht(int n)1527 t_charht (
1528     int n							/* set height to this internal size */
1529 )
1530 
1531 
1532 {
1533 
1534 
1535 	int		max;						/* max internal size for current range */
1536 
1537 
1538 
1539 	/********************************************************************
1540 	 *																	*
1541 	 *		This routine is called by devcntrl() to set the height of	*
1542 	 *	the characters that are being printed to the internal size		*
1543 	 *	specified by the parameter n. If the requested size is too 		*
1544 	 *	large for the current range then an error message is written	*
1545 	 *	and the requested size is set to the maximum allowed in the		*
1546 	 *	current range. Since the APS-5 apparently allows us to decrease	*
1547 	 *	the height as far as we want, no lower limit checks are made on	*
1548 	 *	the requested size. The global variable range is set by the		*
1549 	 *	routine setfont() to the current master range that is being		*
1550 	 *	used.															*
1551 	 *																	*
1552 	 ********************************************************************/
1553 
1554 
1555 
1556 	if ( range < 1  ||  range > MAX_RANGE )  {	/* something is wrong here */
1557 		error(FATAL, "illegal master range %d", range);
1558 		return;							/* in case this error is ignored */
1559 	}	/* End if */
1560 
1561 	max = upper_limit(range);			/* internal upper limit for range */
1562 
1563 	if ( n > max )  {					/* requested size is too big */
1564 		error(NON_FATAL, "size %d too large for range %d", pstab[n-1], range);
1565 		n = max;						/* reset n to largest allowed size */
1566 	}	/* End if */
1567 
1568 	PUTC(VSIZE, tf);					/* MACRO - set character height */
1569 	putint(10 * pstab[n-1]);			/* vertical size - in decipoints */
1570 
1571 }	/* End of t_charht */
1572 
1573 
1574 /*****************************************************************************/
1575 
1576 
1577 int
upper_limit(int n)1578 upper_limit (
1579     int n							/* find upper limit for this range */
1580 )
1581 
1582 
1583 {
1584 
1585 
1586 	int		bsize;						/* master range base size */
1587 	int		max;						/* maximum point size for range n */
1588 	int		max_internal;				/* maximum internal size for range n */
1589 
1590 
1591 
1592 	/********************************************************************
1593 	 *																	*
1594 	 *		This routine is called by t_charht() and possibly others to	*
1595 	 *	find the maximum internal size that is allowed for master range	*
1596 	 *	n. The value returned to the caller is the largest internal		*
1597 	 *	size that is allowed in this range.								*
1598 	 *																	*
1599 	 ********************************************************************/
1600 
1601 
1602 
1603 	bsize = BASE_SIZE(n);				/* base size for master range n */
1604 	max = bsize;						/* max point size if n > 3 */
1605 	if ( n <= 3 )						/* can scale these ranges up */
1606 		max = SCALE_UP(bsize);			/* to this limit on our APS-5 */
1607 
1608 	max_internal = t_size(max);			/* first try at max internal size */
1609 	if ( pstab[max_internal -1] > max )	/* take next lower internal size */
1610 		max_internal--;
1611 
1612 	return(max_internal);
1613 
1614 }	/* End of upper_limit */
1615 
1616 
1617 /*****************************************************************************/
1618 
1619 
1620 void
t_slant(int n)1621 t_slant (
1622     int n							/* set the APS slant to this value */
1623 )
1624 
1625 
1626 {
1627 
1628 
1629 
1630 	/********************************************************************
1631 	 *																	*
1632 	 *		Called to set the slant angle to the value of the parameter	*
1633 	 *	n. On the APS-5 we can only set positive or negative 14 degree	*
1634 	 *	slants, even though in TROFF any slant angle can be requested.	*
1635 	 *	The global variable last_slant is the value of the last angle	*
1636 	 *	that was stored in the APS-5 using either the SETOBLIQUE or		*
1637 	 *	STRTPG commands, while aps_slant is the last angle we set in	*
1638 	 *	this routine.													*
1639 	 *																	*
1640 	 *		Originally we only set the oblique angle if last_slant		*
1641 	 *	was not equal to n. This really didn't work too well, because	*
1642 	 *	appaerntly the APS-5 resets the oblique angle to +14 degrees	*
1643 	 *	when it returns to normal mode.									*
1644 	 *																	*
1645 	 ********************************************************************/
1646 
1647 
1648 
1649 	if ( n != 0 )  {					/* need to slant type being set */
1650 
1651 		n = ( n > 0 ) ? POS_SLANT		/* use +14 degree slant */
1652 					  : NEG_SLANT;		/* otherwise slant at -14 degrees */
1653 
1654 		PUTC(SETOBLIQUE, tf);			/* MACRO - store new angle n */
1655 		putint(10 * n);					/* APS expects 10 times the angle */
1656 		last_slant = n;					/* remember this stored angle */
1657 
1658 		PUTC(XOBLIQUE, tf);				/* MACRO - execute oblique mode */
1659 
1660 	}	/* End if */
1661 	else PUTC(XNORMAL, tf);				/* MACRO - otherwise use normal mode */
1662 
1663 	aps_slant = n;						/* angle that type is being set at */
1664 
1665 }	/* End of t_slant */
1666 
1667 
1668 /*****************************************************************************/
1669 
1670 
1671 int
t_font(char * str)1672 t_font (
1673     char *str						/* convert this string to font number */
1674 )
1675 
1676 
1677 {
1678 
1679 
1680 	int		n;							/* integer value for number in str */
1681 
1682 
1683 
1684 	/********************************************************************
1685 	 *																	*
1686 	 *		This routine is called from conv() to convert the ASCII		*
1687 	 *	string *str to an integer that represents a legal font number.	*
1688 	 *	If the resulting number is outside the allowed range for fonts	*
1689 	 *	on this typesetter then an error message is printed out and		*
1690 	 *	the program is aborted.											*
1691 	 *																	*
1692 	 ********************************************************************/
1693 
1694 
1695 
1696 	n = atoi(str);						/* font number */
1697 	if ( n < 0  ||  n > nfonts )  {		/* illegal font - abort */
1698 		error(FATAL, "illegal font number %d", n);
1699 		n = font;						/* in case we don't quit on an error */
1700 	}	/* End if */
1701 
1702 	return(n);							/* legal value so return it */
1703 
1704 }	/* End of t_font */
1705 
1706 
1707 /*****************************************************************************/
1708 
1709 
1710 void
t_text(char * str)1711 t_text (
1712     char *str						/* typeset this string of characters */
1713 )
1714 
1715 
1716 {
1717 
1718 
1719 	int		ch;							/* internal character variable */
1720 	char	buf[4];						/* buffer used for special chars */
1721 
1722 
1723 
1724 	/********************************************************************
1725 	 *																	*
1726 	 *		This routine is called by conv() to process the text string	*
1727 	 *	that is in the array str. Characters are read from str and		*
1728 	 *	written to the output file until the end of the string is		*
1729 	 *	reached.														*
1730 	 *																	*
1731 	 *		After the character has been put in the output file the		*
1732 	 *	current horizontal position is adjusted by a call to hmot()		*
1733 	 *	using the global variable lastw as the parameter. lastw is set	*
1734 	 *	in put1() and represents the width of the last character that	*
1735 	 *	was printed.													*
1736 	 *																	*
1737 	 ********************************************************************/
1738 
1739 
1740 
1741 	if ( debug[2] )
1742 		fprintf(fp_debug,"input string = %s\n", str);
1743 
1744 	if ( output == OFF ) return;		/* not doing output on this page */
1745 
1746 	while ( (ch = *str++) != '\n'  &&  ch != '\0' )  {
1747 
1748 		if ( ch == '\\' )  {			/* this is a special char sequence */
1749 			switch ( ch = *str++ )  {	/* so check the next character */
1750 
1751 				case '(':				/* special troff character sequence */
1752 							buf[0] = *str++;
1753 							buf[1] = *str++;
1754 							buf[2] = '\0';
1755 							put1s(buf);
1756 							break;
1757 
1758 				case '\\':				/* backslash character */
1759 				case 'e':
1760 							put1('\\');
1761 							break;
1762 
1763 				default:				/* illegal character sequence */
1764 							error(FATAL,"illegal character sequence \\%c", ch);
1765 							break;
1766 
1767 			}	/* End switch */
1768 		} else put1(ch);				/* otherwise it is a simple character */
1769 		hmot(lastw);					/* beam has moved right lastw units */
1770 
1771 		if ( debug[3] )
1772 			fprintf(fp_debug,"char = %c  width = %d\n", ch, lastw);
1773 
1774 	}	/* End while */
1775 
1776 }	/* End of t_text */
1777 
1778 
1779 /*****************************************************************************/
1780 
1781 
1782 void
t_reset(int ch)1783 t_reset (
1784     int ch							/* pause or stop */
1785 )
1786 
1787 
1788 {
1789 
1790 
1791 	int		n;							/* for loop variable */
1792 	long	dist;						/* distance to end of job */
1793 	int		opcode;						/* ENDJOB or HALT */
1794 
1795 
1796 
1797 	/********************************************************************
1798 	 *																	*
1799 	 *		This routine is called to produce the typesetter commands	*
1800 	 *	that are required at the end of a job. If the parameter ch has	*
1801 	 *	the value 's' then we have reached the end of the current job	*
1802 	 *	and so we output the ENDJOB opcode, otherwise ch should be		*
1803 	 *	equal to 'p', and so we produce the HALT command. This enables	*
1804 	 *	the operator to restart the current job by pressing the PROCEED	*
1805 	 *	button on the front panel, while if he hits the INITIAL button	*
1806 	 *	the current job will be terminated.								*
1807 	 *																	*
1808 	 *		If we have finished this job, but we are not currently at	*
1809 	 *	position max_vpos, we step the job forward to this position so	*
1810 	 *	that the next job begins on unexposed paper.					*
1811 	 *																	*
1812 	 ********************************************************************/
1813 
1814 
1815 
1816 	output = ON;						/* probably not needed here? */
1817 
1818 	if ( ((dist = max_vpos - cur_vpos) > 0) && (ch == 's') )  {
1819 		dist += (pstab[nsizes-1] / 2) * 10;		/* try to get whole last line */
1820 		while ( dist > 0 )  {			/* go to the end of the job */
1821 			vmot(dist > MAX_INT ? MAX_INT : dist);
1822 			dist -= (dist > MAX_INT) ? MAX_INT : dist;
1823 		}	/* End while */
1824 	}	/* End if */
1825 
1826 	PUTC(STRTPG, tf);					/* MACRO - output STRTPG opcode */
1827 	putint(9000+pageno);				/* can't possibly be a page number */
1828 
1829 	for ( n = 0; n < 10; n++ )			/* flush out APS internal buffer */
1830 		PUTC(APSNOOP, tf);				/* MACRO - put out a few no-op's */
1831 
1832 	opcode = ( ch == 'p' ) ? HALT		/* may want to restart this job */
1833 						   : ENDJOB;	/* done with this guy */
1834 
1835 	PUTC(opcode, tf);					/* MACRO - stop */
1836 
1837 	fflush(tf);							/* flush any buffered output */
1838 
1839 }	/* End of t_reset */
1840 
1841 
1842 /*****************************************************************************/
1843 
1844 
1845 void
hflush(void)1846 hflush (void)
1847 
1848 
1849 {
1850 
1851 
1852 
1853 	/********************************************************************
1854 	 *																	*
1855 	 *		This routine is called in put1() and t_push() to make sure 	*
1856 	 *	that the two variables hpos and htrue aren't too different. If	*
1857 	 *	they differ by more than the constant SLOP then a tab is set 	*
1858 	 *	and then executed to position the beam properly.				*
1859 	 *																	*
1860 	 *		The variable hpos is the current horizontal position as 	*
1861 	 *	determined by troff, while htrue is the horizontal position as	*
1862 	 *	calculated by the post-processor.								*
1863 	 *																	*
1864 	 ********************************************************************/
1865 
1866 
1867 
1868 	if ( output == OFF ) return;		/* not doing output for this page */
1869 
1870 	if ( abs(hpos - htrue) > SLOP )  {	/* positions are too different */
1871 		PUTC(SETTAB, tf);				/* MACRO - so set a tab */
1872 		putint(hpos);					/* to the current value of hpos */
1873 		PUTC(XTAB, tf);					/* MACRO - then execute the tab */
1874 		htrue = hpos;					/* the positions are the same now */
1875 	}	/* End if */
1876 
1877 }	/* End of hflush */
1878 
1879 
1880 /*****************************************************************************/
1881 
1882 
1883 void
hmot(int n)1884 hmot (
1885     int n							/* move this far from here */
1886 )
1887 
1888 
1889 {
1890 
1891 
1892 
1893 	/********************************************************************
1894 	 *																	*
1895 	 *		This routine is called from conv() to handle a relative		*
1896 	 *	horizontal motion of n units. If n is positive then we move to	*
1897 	 *	the right on the current line. If the final horizontal position	*
1898 	 *	hpos is negative then something has gone wrong and so we print	*
1899 	 *	out an error message and if we return from error() we set hpos	*
1900 	 *	to 0.															*
1901 	 *																	*
1902 	 ********************************************************************/
1903 
1904 
1905 
1906 	if ( (hpos += n ) < 0 || hpos > hcutoff )  {		/* bad beam position */
1907 		error(FATAL, "illegal horizontal position %d", hpos);
1908 		hpos = 0;						/* in case we ignore this error */
1909 	}	/* End if */
1910 
1911 }	/* End of hmot */
1912 
1913 
1914 /*****************************************************************************/
1915 
1916 
1917 void
hgoto(int n)1918 hgoto (
1919     int n							/* move to this horizontal position */
1920 )
1921 
1922 
1923 {
1924 
1925 
1926 
1927 	/********************************************************************
1928 	 *																	*
1929 	 *		This routine is called by conv() to set the absolute		*
1930 	 *	horizontal position of the beam to the position n, where n		*
1931 	 *	must be a positive integer.										*
1932 	 *																	*
1933 	 ********************************************************************/
1934 
1935 
1936 
1937 	if ( (hpos = n) < 0 || hpos > hcutoff )  {		/* bad beam position */
1938 		error(FATAL, "illegal horizontal position %d", hpos);
1939 		hpos = 0;						/* in case we ignore this error */
1940 	}	/* End if */
1941 
1942 }	/* End of hgoto */
1943 
1944 
1945 /*****************************************************************************/
1946 
1947 
1948 void
vgoto(int n)1949 vgoto (
1950     int n							/* final absolute vert position */
1951 )
1952 
1953 
1954 {
1955 
1956 
1957 
1958 	/********************************************************************
1959 	 *																	*
1960 	 *		This routine is called from conv() to position the beam at	*
1961 	 *	the absolute vertical position n. The unit used in all of the	*
1962 	 *	APS absolute spacing commands is 1/10 of a point.				*
1963 	 *																	*
1964 	 *																	*
1965 	 *		NOTE - it is important to check that a job doesn't try to	*
1966 	 *	write on a previous job by using the vertical spacing commands.	*
1967 	 *	Currently this check is made in the routine vmot().				*
1968 	 *																	*
1969 	 ********************************************************************/
1970 
1971 
1972 
1973 	vmot(n - vpos);						/* move n-vpos units from here */
1974 
1975 }	/* End of vgoto */
1976 
1977 
1978 /*****************************************************************************/
1979 
1980 
1981 void
vmot(int n)1982 vmot (
1983     int n							/* move n units vertically from here */
1984 )
1985 
1986 
1987 {
1988 
1989 
1990 	int		sign;						/* sign of the requested motion */
1991 	int		dist;						/* distance left to move */
1992 
1993 
1994 	/********************************************************************
1995 	 *																	*
1996 	 *		This routine is called to move the vertical position of the	*
1997 	 *	beam n units from the current position. The global variable 	*
1998 	 *	cur_vpos is the typesetter's current vertical position as 		*
1999 	 *	measured from the start of the job. If the user has requested	*
2000 	 *	a relative vertical motion that would make cur_vpos negative	*
2001 	 *	we print an error message and then abort. The variable max_vpos	*
2002 	 *	is the maximum vertical position that this job has reached. It 	*
2003 	 *	is used to calculate the amount of paper that has been used.	*
2004 	 *																	*
2005 	 ********************************************************************/
2006 
2007 
2008 
2009 	if ( output == OFF ) return;		/* not doing output on this page */
2010 
2011 	if ( cur_vpos + n < 0 )  {			/* trying to write on last job! */
2012 		error(FATAL, "can't backup past start of job");
2013 		return;							/* in case we ignore this error */
2014 	}	/* End if */
2015 
2016 	sign = ( n > 0 ) ? 1 : -1;			/* up or down the page */
2017 	dist = sign * n;					/* total distance to move */
2018 
2019 	while ( dist > 0 )  {				/* not done yet */
2020 		PUTC(VSPABS, tf);				/* MACRO - absolute vert motion */
2021 		putint(sign * ((dist > vert_step) ? vert_step : dist));
2022 		dist -= ( dist > vert_step ) ? vert_step : dist ;
2023 	}	/* End while */
2024 
2025 	vpos += n;							/* record our new vertical position */
2026 	cur_vpos += n;
2027 	if ( cur_vpos > max_vpos )			/* this is the farthest we have gone */
2028 		max_vpos = cur_vpos;
2029 
2030 }	/* End of vmot */
2031 
2032 
2033 /*****************************************************************************/
2034 
2035 
2036 void
put1s(char * s)2037 put1s (
2038     char *s							/* print this special character */
2039 )
2040 
2041 
2042 {
2043 
2044 
2045 	int		i;							/* for loop index */
2046 
2047 
2048 
2049 	/********************************************************************
2050 	 *																	*
2051 	 *		This routine is called to produce the typesetter output		*
2052 	 *	for the special character string pointed to by s. All of the	*
2053 	 *	special characters are listed in the charset portion of the 	*
2054 	 *	typsetter's DESC file, and the program makedev reads this part	*
2055 	 *	of the DESC file and produces two tables called chtab[] and		*
2056 	 *	chname[]. The character array chname[] contains the special		*
2057 	 *	character strings separated by '\0', while chtab[i] gives us 	*
2058 	 *	the starting position in chname[] for the special character i.	*
2059 	 *																	*
2060 	 *																	*
2061 	 *		NOTE - Since we just do a sequential search of the strings	*
2062 	 *	in chname[] when looking for a special character, the speed of	*
2063 	 *	the post-processor could be improved if we had the most common	*
2064 	 *	special characters at the start of the list in the DESC file.	*
2065 	 *	However before doing this we should find out how troff does 	*
2066 	 *	the lookup.														*
2067 	 *																	*
2068 	 ********************************************************************/
2069 
2070 
2071 
2072 	if ( output == OFF ) return;		/* not doing output for this page */
2073 
2074 	for ( i = 0; i < nchtab; i++ )		/* lookup the special character */
2075 		if ( strcmp(&chname[chtab[i]], s) == SAME_STR )
2076 			break;
2077 
2078 	if ( i < nchtab )  {				/* found it */
2079 #ifdef ADJUST
2080 		t_adjust(s);					/* adjust vertical positions */
2081 #endif
2082 		put1(i + 128);					/* special characters start at 128 */
2083 	}	/* End if */
2084 	else								/* didn't find it - abort */
2085 		if ( newfile(s, pstab[size-1]) )
2086 			error(FATAL, "special character %s not found", s);
2087 
2088 	if ( debug[4] )  {
2089 		fprintf(fp_debug,"string = %s  ", s);
2090 		fprintf(fp_debug,"index = %d\n", i);
2091 	}	/* End if */
2092 
2093 }	/* End of put1s */
2094 
2095 
2096 /*****************************************************************************/
2097 
2098 
2099 #ifdef ADJUST
2100 
2101 
2102 void
t_adjust(char * s)2103 t_adjust (
2104     char *s							/* look for this string */
2105 )
2106 
2107 
2108 {
2109 
2110 
2111 	int		i;							/* for loop index */
2112 	int		incr;						/* incrment v_adjust by this much */
2113 
2114 
2115 
2116 	/********************************************************************
2117 	 *																	*
2118 	 *		Called from put1s() to look for the string *s in adj_tbl[]	*
2119 	 *	and if found it is used to set the appropriate vertical for the	*
2120 	 *	character.														*
2121 	 *																	*
2122 	 ********************************************************************/
2123 
2124 
2125 	v_adjust = 0;
2126 
2127 	for ( i = 0; adj_tbl[i] != '\0'; i++ )
2128 		if ( strcmp(s, adj_tbl[i]) == 0 )  {
2129 			incr = (vadjustment[i] < 0) ? -1 : 1;
2130 			v_adjust = (vadjustment[i] * pstab[size-1]) /dev.unitwidth + incr;
2131 			break;
2132 		}	/* End if */
2133 
2134 }	/* End of t_adjust */
2135 
2136 #endif
2137 
2138 
2139 /*****************************************************************************/
2140 
2141 
2142 void
put1(int c)2143 put1 (
2144     int c							/* print this character */
2145 )
2146 
2147 
2148 {
2149 
2150 
2151 	register int	i = 0;					/* c's index in font data structures */
2152 	register int	k;					/* look for c on this font */
2153 	int		j;							/* lookup failed on this many fonts */
2154 	int		k1;							/* if not found check this font next */
2155 	int		code;						/* APS-5 code for this character */
2156 	int		old_font;					/* original font number (1..nfonts) */
2157 	int		old_range;					/* original master range setting */
2158 	int		last_range;					/* last master range setting */
2159 	int		old_slant;					/* original device slant angle */
2160 
2161 
2162 
2163 	/********************************************************************
2164 	 *																	*
2165 	 *		This routine is responsible for producing the output codes	*
2166 	 *	for the characters to be printed by the APS. The integer c		*
2167 	 *	is the ASCII code for the character if c < 128. Otherwise it 	*
2168 	 *	refers to one of troff's special character sequences. Since we	*
2169 	 *	are not concerned with unprintable ASCII characters we subtract	*
2170 	 *	32 from c to get the right index to use when we do the lookup	*
2171 	 *	in array fitab[][]. If the character isn't found on the current	*
2172 	 *	font then we search all the remaining fonts, starting with the	*
2173 	 *	first special font. If we haven't found the character after we	*
2174 	 *	search the last font then an error message is written out and	*
2175 	 *	we quit. Since we can't be guarenteed that font position 0 has	*
2176 	 *	been loaded with a valid font, we need to make sure that the	*
2177 	 *	circular search skips this position.							*
2178 	 *																	*
2179 	 *		If we find the character c, but it has an APS code that is	*
2180 	 *	larger than 128, then the makedev program has encoded some		*
2181 	 *	extra information in this field. Therefore we call the routine	*
2182 	 *	special_case() to decode this info, and return the correct APS	*
2183 	 *	code for c.														*
2184 	 *																	*
2185 	 ********************************************************************/
2186 
2187 
2188 
2189 	if ( output == OFF ) return;		/* not doing output on this page */
2190 
2191 	old_font = font;					/* may find c on a different font */
2192 	old_range = last_range = range;		/* and in a different master range */
2193 	old_slant = aps_slant;				/* and may change the slant for c */
2194 
2195 	k = font;							/* while loop looks for c on font k */
2196 	k1 = smnt - 1;						/* get the next font from this guy */
2197 	j = 0;								/* c not found on this many fonts */
2198 
2199 	c -= 32;							/* tables don't include unprintable chars */
2200 
2201 	if ( c <= 0 )  {					/* c is a space or unprintable */
2202 		if ( c < 0 )   					/* can't be in any of our font tables */
2203 			error(FATAL, "non-printable character 0%o\n", c+32);
2204 
2205 		lastw = (widthtab[font][0] & BMASK) * pstab[size-1] / dev.unitwidth;
2206 		return;							/* lastw = space width (see t_text()) */
2207 	}	/* End if */
2208 
2209 
2210 	/* Look for character c in current font and then on the special fonts */
2211 
2212 
2213 	while ( (j < nfonts + 1) && ((i = fitab[k][c] & BMASK) == 0) )  {
2214 		k = (k1++) % nfonts + 1;		/* now check all other fonts */
2215 		j++;
2216 	}	/* End while */
2217 
2218 
2219 	/* If j > nfonts or i == 0 then char c not found. no-op if code = 0 */
2220 
2221 
2222 	if ( j > nfonts || i == 0 || (code = codetab[k][i] & BMASK) == 0 )  {
2223 		if ( i == 0  ||  j > nfonts )
2224 			if ( c+32 < 128 || newfile(&chname[chtab[c+32-128]], pstab[size-1]) )
2225 				error(FATAL, "character 0%o not found", c+32);
2226 		return;
2227 	}	/* End if */
2228 
2229 	if ( aps_font != fontname[k].number )	/* probably need a new font */
2230 		if ( (code < 129) || (fontbase[font]->spare1 != fontbase[k]->spare1) )
2231 			CHANGE_FONT(k, last_range);
2232 
2233 	if ( code > 128  &&  fontbase[k]->spare1 )  {	/* got some more stuff to do */
2234 		code = special_case(i, k);		/* this is the real APS code for c */
2235 		last_range = range;				/* in case the range was changed */
2236 	}	/* End if */
2237 
2238 #ifdef ADJUST
2239 
2240 	if ( v_adjust != 0 )
2241 		vmot(v_adjust);
2242 
2243 #endif
2244 
2245 	hflush();							/* get to right horizontal position */
2246 	PUTC(code, tf);						/* MACRO - then print the character */
2247 
2248 #ifdef ADJUST
2249 
2250 	if ( v_adjust != 0 )  {
2251 		vmot(-v_adjust);
2252 		v_adjust = 0;
2253 	}	/* End if */
2254 
2255 #endif
2256 
2257 	if ( (last_range != old_range) || (aps_slant != old_slant) )
2258 		CHANGE_FONT(old_font, last_range);	/* MACRO - back to the old font */
2259 
2260 	lastw = ((widthtab[k][i] & BMASK) * pstab[size-1] + dev.unitwidth/2) / dev.unitwidth;
2261 	htrue += lastw;						/* approximate right side of char */
2262 
2263 }	/* End of put1 */
2264 
2265 
2266 /*****************************************************************************/
2267 
2268 
2269 void
putint(int n)2270 putint (
2271     int n							/* write out this integer */
2272 )
2273 
2274 
2275 {
2276 
2277 
2278 
2279 	/********************************************************************
2280 	 *																	*
2281 	 *		This routine is called to write the integer n out in the	*
2282 	 *	last two bytes of a type two command on the APS-5 typesetter.	*
2283 	 *																	*
2284 	 ********************************************************************/
2285 
2286 
2287 
2288 	PUTC(n >> 8, tf);
2289 	PUTC(n, tf);
2290 
2291 }	/* End of putint */
2292 
2293 
2294 /*****************************************************************************/
2295 
2296 
2297 void
setsize(int n)2298 setsize (
2299     int n							/* new internal size */
2300 )
2301 
2302 
2303 {
2304 
2305 
2306 
2307 	/********************************************************************
2308 	 *																	*
2309 	 *		This routine is called to set the current internal size to	*
2310 	 *	the value n, and then output the commands needed to change the	*
2311 	 *	APS-5 point size. The internal size n is an index into the		*
2312 	 *	array pstab[], which contains the actual point size that is to	*
2313 	 *	be used.														*
2314 	 *																	*
2315 	 *																	*
2316 	 *		NOTE - This routine always calls setfont in case the range	*
2317 	 *	has changed, but it may be the case that the range doesn't		*
2318 	 *	really change even though the point size has changed. Always 	*
2319 	 *	making this call definitely produces some unnecessary APS-5		*
2320 	 *	code. Probably fix it in setfont routine.						*
2321 	 *																	*
2322 	 ********************************************************************/
2323 
2324 
2325 
2326 	if ( output == OFF ) return;		/* not doing output on this page */
2327 
2328 	if ( n <= 0  ||  n > nsizes )  {	/* internal size out of range */
2329 		error(FATAL, "illegal internal size %d", n);
2330 		n = size;						/* in case we return from this error */
2331 	}	/* End if */
2332 
2333 	size = n;							/* must preceed call to setfont() */
2334 	change_font(font);					/* in case the range has changed */
2335 	PUTC(HVSIZE, tf);					/* MACRO - set the new point size */
2336 	putint(10 * pstab[n-1]);			/* APS expects 10 times the size */
2337 
2338 }	/* End of setsize */
2339 
2340 
2341 /*****************************************************************************/
2342 
2343 
2344 void
setfont(int n)2345 setfont (
2346     int n							/* new font's internal number */
2347 )
2348 
2349 
2350 {
2351 
2352 
2353 	int		oldrange;					/* current master range */
2354 
2355 
2356 
2357 	/********************************************************************
2358 	 *																	*
2359 	 *		This routine is called to set the current typesetter font	*
2360 	 *	to the one that corresponds to the parameter n. These internal	*
2361 	 *	font numbers are determined by the way the font tables are set	*
2362 	 *	up for the typesetter in the DESC file.							*
2363 	 *																	*
2364 	 *		Our APS-5 typesetter typically has only master ranges 1, 2,	*
2365 	 *	and 3. The actual font that we want to set is determined by the	*
2366 	 *	current value of the global variable size. Remember that this	*
2367 	 *	value is an internal size, which is an index into the array		*
2368 	 *	pstab[]. The following table gives the point sizes that can be	*
2369 	 *	used in the different master ranges,							*
2370 	 *																	*
2371 	 *																	*
2372 	 *					MASTER RANGE 1:   0 to 12						*
2373 	 *					MASTER RANGE 2:  12 to 24						*
2374 	 *					MASTER RANGE 3:  24 to 48						*
2375 	 *					MASTER RANGE 4:  48 to 96						*
2376 	 *																	*
2377 	 *																	*
2378 	 *	although any range can actually print characters up to size,	*
2379 	 *																	*
2380 	 *																	*
2381 	 *						1.5 * limit - 1								*
2382 	 *																	*
2383 	 *																	*
2384 	 *	where the value of limit is obtained from the above table.		*
2385 	 *																	*
2386 	 ********************************************************************/
2387 
2388 
2389 
2390 	if ( output == OFF ) return;		/* not doing output for this page */
2391 
2392 	if ( n < 0  ||  n > nfonts )  {
2393 		error(FATAL, "requested font number %d out of range", n);
2394 		n = font;						/* in case we ignore this error */
2395 	}	/* End if */
2396 
2397 	oldrange = range;					/* new range may be different */
2398 	CHANGE_FONT(n, oldrange);			/* change the APS font */
2399 	font = n;							/* current internal font number */
2400 
2401 }	/* End of setfont */
2402 
2403 
2404 /*****************************************************************************/
2405 
2406 
2407 void
change_font(int n)2408 change_font (
2409     int n							/* new font's internal number */
2410 )
2411 
2412 
2413 {
2414 
2415 
2416 
2417 	int		angle;						/* slant angle - used in SETSLANT */
2418 	int		max_range;					/* largest range allowed on font n */
2419 	int		max_size;					/* largest size allowed in max_range */
2420 	char	f_spare1;					/* value of font flags */
2421 
2422 
2423 
2424 	/********************************************************************
2425 	 *																	*
2426 	 *		This routine is called to change the font that the APS is	*
2427 	 *	currently setting type in. Some extra stuff is done if the font	*
2428 	 *	has any of its special flags set.								*
2429 	 *																	*
2430 	 ********************************************************************/
2431 
2432 
2433 
2434 	range = get_range(pstab[size-1]);	/* probably the new range */
2435 
2436 	f_spare1 = fontbase[n]->spare1;		/* get special case font flags */
2437 	if ( f_spare1 & RANGE_BIT )  {		/* have a maximum range for font n */
2438 
2439 		max_range = DECODE(f_spare1, RANGE_VAL, TWO_BITS);	/* decode this range */
2440 		if ( range > max_range )  {		/* current range is too big */
2441 			max_size = upper_limit(max_range);
2442 			if ( size > max_size )		/* can't blow max_range up to size */
2443 				error(FATAL, "size %d too big for range %d", pstab[size-1], max_range);
2444 			range = max_range;			/* use the biggest possible range */
2445 		}	/* End if */
2446 
2447 	}	/* End if */
2448 
2449 	if ( f_spare1 & SLANT_BIT )			/* this font has a default slant */
2450 		SETSLANT(f_spare1, angle);		/* MACRO - so use it */
2451 	else if ( aps_slant != last_req_slant )		/* back to the last requested slant */
2452 		t_slant(last_req_slant);
2453 
2454 
2455 	PUTC(FONT, tf);						/* MACRO - set the new font and range */
2456 	if ( range < 3 )					/* APS expects a positive number */
2457 		 putint(fontname[n].number + range-1);
2458 	else putint(-(fontname[n].number + range-1));
2459 
2460 	aps_font = fontname[n].number;		/* font that the APS is using */
2461 
2462 }	/* End of change_font */
2463 
2464 
2465 /*****************************************************************************/
2466 
2467 
2468 void
t_fp(int n,char * s,char * si)2469 t_fp (
2470     int n,							/* update this font position */
2471     char *s,							/* font's external name (eg. R) */
2472     char *si						/* font number used by the APS */
2473 )
2474 
2475 
2476 {
2477 
2478 
2479 
2480 	/********************************************************************
2481 	 *																	*
2482 	 *		This routine is called to update the data structures that	*
2483 	 *	are maintained by the post-processor to keep track of fonts.	*
2484 	 *	The parameter n is the font position that we are going to		*
2485 	 *	update, while s and si are the font's external and internal		*
2486 	 *	names.															*
2487 	 *																	*
2488 	 ********************************************************************/
2489 
2490 
2491 
2492 	fontname[n].name = s;
2493 	fontname[n].number = atoi(si);
2494 	fontname[n].nwfont = fontbase[n]->nwfont;
2495 
2496 }	/* End of t_fp */
2497 
2498 /*****************************************************************************/
2499 
2500 void
getuserid(char * buf,size_t size)2501 getuserid(char *buf, size_t size)
2502 {
2503 	struct passwd	*pwd;
2504 
2505 	if ((pwd = getpwuid(getuid())) != NULL)
2506 		strncpy(buf, pwd->pw_name, size)[size-1] = '\0';
2507 }
2508 
2509 /*****************************************************************************/
2510 
2511 
2512 void
account(void)2513 account (void)
2514 
2515 
2516 {
2517 
2518 
2519 	char	user[100];				/* user's login name */
2520 	float	pages;						/* will charge for this many pages */
2521 
2522 
2523 
2524 	/********************************************************************
2525 	 *																	*
2526 	 *		This is the accounting routine for the post-processor. It	*
2527 	 *	may have to be changed for your particular system.				*
2528 	 *																	*
2529 	 *		NOTE - since the variable res can be changed we better use	*
2530 	 *	the constant RES to determine how many pages were printed.		*
2531 	 *																	*
2532 	 ********************************************************************/
2533 
2534 
2535 
2536 	paper = max_vpos;						/* used this much paper */
2537 	pages = paper / (RES * PAGE_LENGTH);	/* pages that we think were used */
2538 
2539 	if ( x_stat & DO_ACCT )  {				/* got accounting to do */
2540 		getuserid(user, sizeof user);
2541 		fprintf(fp_acct, " user = %-10s", user);
2542 		fprintf(fp_acct, " paper = %-10.1f", pages);
2543 		x_stat &= ~DO_ACCT;					/* done the important accounting */
2544 		fprintf(fp_acct, "exit status = 0%-6o", x_stat);
2545 		if ( tf == stdout )
2546 			fprintf(fp_acct, "  ??");
2547 		fprintf(fp_acct, "\n");
2548 	}	/* End if */
2549 
2550 	if ( report == YES )
2551 		fprintf(stderr, " %-3.1f pages\n", pages);
2552 
2553 }	/* End of account */
2554 
2555 
2556 /*****************************************************************************/
2557 
2558 
2559 int
special_case(int index,int font)2560 special_case (
2561     int index,						/* char position in tables */
2562     int font						/* char info is on this font */
2563 )
2564 
2565 
2566 {
2567 
2568 
2569 	int		old_range;					/* saved value of current range */
2570 	int		old_font;					/* present APS-5 font number */
2571 	int		req_font;					/* requested APS-5 font number */
2572 	int		max_range;					/* max allowed range for character */
2573 	int		max_size;					/* max size allowed for max_range */
2574 	int		angle;						/* special char angle to set */
2575 	int		code;						/* old code - with bits set */
2576 
2577 
2578 
2579 	/********************************************************************
2580 	 *																	*
2581 	 *		This routine is called by put1() to handle the special any	*
2582 	 *	special case characters for the APS-5. 							*
2583 	 *																	*
2584 	 *		Taken on its own, this is a very confusing routine, but one	*
2585 	 *	which I found from my experience with the APS-5 at Murray Hill	*
2586 	 *	was definitely needed. I'll try to give a brief, but hopefully	*
2587 	 *	complete explination here.										*
2588 	 *																	*
2589 	 *		The additions that I made here needed to be completely		*
2590 	 *	transparent to troff, and so the only field in the font tables	*
2591 	 *	that could be changed was the actual charater code, since troff	*
2592 	 *	can't possibly need this stuff (it's device independent!). On	*
2593 	 *	the APS-5, character codes lie between 1 and 128 (inclusive) -	*
2594 	 *	anything else is an actual function code. Therefore when we are	*
2595 	 *	ready to print a character in put1(), and we find that its code	*
2596 	 *	is larger than 128 we know something more has to be done. This	*
2597 	 *	routine is then called to try to make sense out of the code,	*
2598 	 *	do any of the special stuff required for this character, and	*
2599 	 *	finially return its real code. This extra stuff can include		*
2600 	 *	changing the character's slant, ensuring that the current		*
2601 	 *	master range is not larger than a given value (max_range), and	*
2602 	 *	finially getting the actual character from a completely			*
2603 	 *	different font (alternate_font). What we actually do for each	*
2604 	 *	special character is determined by its code in the current		*
2605 	 *	set of font tables. This code is produced by a special version	*
2606 	 *	of the makedev program, which I changed to interpret some 		*
2607 	 *	extra fields in the ASCII font tables.					 		*
2608 	 *																	*
2609 	 *																	*
2610 	 *		NOTE - This extra stuff is costly, and should only be used	*
2611 	 *	when absolutely necessary. The alternate font stuff can			*
2612 	 *	cause many extra font changes, which in turn will force extra	*
2613 	 *	disk accesses. We found this to be one of the main reasons for	*
2614 	 *	slow jobs on our APS, not to mention the extra wear on the disk	*
2615 	 *	drive.															*
2616 	 *																	*
2617 	 ********************************************************************/
2618 
2619 
2620 
2621 	if ( fontname[font].number != alt_tables )	/* don't have font's table */
2622 		load_alt(font);							/* load font's '.add' tables */
2623 
2624 	code = codetab[font][index] & BMASK;	/* encoded character information */
2625 	old_range = range;						/* current typesetter range */
2626 	old_font = aps_font;					/* quick change - fix it later */
2627 	req_font = old_font;
2628 
2629 	if ( code & SLANT_BIT )				/* special slant for this character */
2630 		SETSLANT(code, angle);			/* MACRO - set slant to encoded value */
2631 
2632 	if ( code & RANGE_BIT )  {			/* maximum range specified */
2633 
2634 		max_range = DECODE(code, RANGE_VAL, TWO_BITS);
2635 		range = get_range(pstab[size-1]);	/* get range for current size */
2636 		if ( range > max_range )  {		/* check current size first */
2637 			max_size = upper_limit(max_range);
2638 			if ( size > max_size )		/* too big for max_range - abort */
2639 				error(FATAL, "size %d too large for range %d", pstab[size-1], max_range);
2640 			else range = max_range;		/* set the range */
2641 		}	/* End if */
2642 
2643 	}	/* End if */
2644 
2645 	if ( code & FONT_BIT )				/* alternate font specified */
2646 		req_font = alt_font[index];		/* APS-5 alternate font number */
2647 
2648 	if ( (old_range != range) || (req_font != old_font) )  {
2649 
2650 		aps_font = req_font;
2651 		PUTC(FONT, tf);					/* set new font */
2652 		if ( range < 3 )				/* output positive number */
2653 			putint(req_font + range - 1);
2654 		else putint(-(req_font + range - 1));
2655 		if ( range != old_range )  {	/* Need to set the size */
2656 			PUTC(HVSIZE, tf);			/* MACRO - set the point size */
2657 			putint(10 * pstab[size-1]);
2658 		}	/* End if */
2659 
2660 	}	/* End if */
2661 
2662 	return(alt_code[index] & BMASK);
2663 
2664 }	/* End of special_case */
2665 
2666 
2667 /*****************************************************************************/
2668 
2669 
2670 int
get_range(int n)2671 get_range (
2672     int n							/* find the range for this point size */
2673 )
2674 
2675 
2676 {
2677 
2678 
2679 	int		val;						/* return this as the range */
2680 	int		msize;						/* size for master range val */
2681 
2682 
2683 
2684 	/********************************************************************
2685 	 *																	*
2686 	 *		This routine is called to return the range corresponding to	*
2687 	 *	the point size n. Note that n is not an internal size for this	*
2688 	 *	routine.														*
2689 	 *																	*
2690 	 ********************************************************************/
2691 
2692 
2693 
2694 	val = 0;
2695 
2696 	while ( ++val <= MAX_RANGE )  {
2697 		msize = BASE_SIZE(val);			/* base size for master range val */
2698 		if ( (val == MAX_RANGE) && (val <= 3) )		/* scale it up */
2699 			msize = SCALE_UP(msize);
2700 		if ( n <= msize ) return(val);	/* found the correct master range */
2701 	}	/* End while */
2702 
2703 	error(FATAL, "size %d too large", n);
2704 	return(1);							/* in case we ignore this error */
2705 
2706 }	/* End of get_range */
2707 
2708 
2709 /*****************************************************************************/
2710 
2711 
2712 void
fileinit(void)2713 fileinit (void)
2714 
2715 
2716 {
2717 
2718 
2719 	int		fin;						/* input file descriptor */
2720 	int		nw;							/* number of font table entries */
2721 	int		i;							/* for loop index */
2722 	char	*filebase;					/* pointer to memory block */
2723 	char	*p;							/* pointer used to set up tables */
2724 	char	temp[60];					/* pathname of the DESC.out file */
2725 
2726 
2727 
2728 	/********************************************************************
2729 	 *																	*
2730 	 *		This routine is responsible for reading the DESC.out file	*
2731 	 *	for the APS-5 typesetter, and then initializing the appropriate	*
2732 	 *	data structures for the device and all of the default fonts		*
2733 	 *	that were mentioned in the typesetter description file DESC.	*
2734 	 *																	*
2735 	 *		First the DESC.out file is opened and the structure dev is	*
2736 	 *	initialized from the first part of the file. This structure 	*
2737 	 *	then contains all the information needed to enable us to finish	*
2738 	 *	the initialization process. Next the rest of the file is read	*
2739 	 *	in and the device tables pstab[], chtab[], and chname[] are set	*
2740 	 *	up. After this has been done we enter a loop which handles the	*
2741 	 *	initialization for all of the fonts that were mentioned in the	*
2742 	 *	DESC file. Finially we allocate enough memory so that font		*
2743 	 *	position 0 can be loaded with the tables from any valid font 	*
2744 	 *	in the library.													*
2745 	 *																	*
2746 	 *																	*
2747 	 *		NOTE - the program 'makedev' creates all of the '.out' 		*
2748 	 *	files in the troff font library. This routine quite obviously	*
2749 	 *	depends on how 'makedev' has written these files. In addition	*
2750 	 *	the troff program also reads the '.out' files and it too 		*
2751 	 *	expects the same format as we do here! To really understand		*
2752 	 *	this routine you need to look at 'makedev.c' and the ASCII		*
2753 	 *	tables in the troff font library.								*
2754 	 *																	*
2755 	 ********************************************************************/
2756 
2757 
2758 
2759 	sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname);
2760 	if ( (fin = open(temp, O_RDONLY)) < 0 )	/* file didn't open - abort */
2761 		error(FATAL, "can't open tables for %s", temp);
2762 
2763 	READ(fin, &dev, sizeof(struct dev));	/* init dev structure */
2764 
2765 	nsizes = dev.nsizes;				/* number of point sizes specified */
2766 	nchtab = dev.nchtab;				/* number of char table entries */
2767 	nfonts = dev.nfonts;				/* number of default fonts */
2768 
2769 	if ( nfonts > NFONT )				/* need to redefine NFONT */
2770 		error(FATAL, "internal error - constant NFONT too small");
2771 
2772 	filebase = malloc(dev.filesize);	/* space for rest of the file */
2773 	READ(fin, filebase, dev.filesize);	/* read in the rest of the file */
2774 
2775 	pstab = (short *) filebase;			/* point size list is first */
2776 	chtab = pstab + nsizes + 1;			/* next comes chtab list */
2777 	chname = (char *) (chtab + dev.nchtab);	/* then the char table list */
2778 
2779 	p = chname + dev.lchname;			/* start of font table info */
2780 
2781 	for (i = 1; i <= nfonts; i++)  {	/* set up default font tables */
2782 
2783 		fontbase[i] = (struct Font *) p;
2784 		nw = *p & BMASK;				/* width count comes first */
2785 
2786 		if (smnt == 0  &&  fontbase[i]->specfont == 1)
2787 			smnt = i;					/* this is first special font */
2788 
2789 		p += sizeof(struct Font);		/* font structure was written first */
2790 		widthtab[i] = p;				/* next is this font's width table */
2791 		codetab[i] = p + 2 * nw;		/* skip kern to get the code table */
2792 		fitab[i] = p + 3 * nw;			/* last is the font index table */
2793 
2794 		p += 3 * nw + dev.nchtab + 128 - 32;	/* point to next font */
2795 
2796 		t_fp(i, fontbase[i]->namefont, fontbase[i]->intname);
2797 
2798 		if ( debug[5] ) fontprint(i);	/* dump font tables */
2799 
2800 	}	/* End for */
2801 
2802 	if ( smnt == 0 ) 					/* no special fonts specified */
2803 		smnt = nfonts + 1;				/* used in routine put1() */
2804 
2805 	fontbase[0] = (struct Font *) malloc(3*255 + dev.nchtab + (128-32) + sizeof(struct Font));
2806 	widthtab[0] = (char *) fontbase[0] + sizeof(struct Font);
2807 	fontbase[0]->nwfont = 255;
2808 	close(fin);
2809 
2810 }	/* End of fileinit */
2811 
2812 
2813 /*****************************************************************************/
2814 
2815 
2816 void
fontprint(int i)2817 fontprint (
2818     int i							/* index of font to print out */
2819 )
2820 
2821 
2822 {
2823 
2824 
2825 	int		j;							/* for loop variable */
2826 	int		n;							/* number of width entries */
2827 	int		pos;						/* position of char from fitab array */
2828 	int		count;						/* count of characters in this font */
2829 
2830 
2831 
2832 	/********************************************************************
2833 	 *																	*
2834 	 *		This is a debugging routine that is used to dump all of the	*
2835 	 *	information about font i that was loaded from the '.out' file.	*
2836 	 *	It is called from fileinit() when the debug flag 5 is turned 	*
2837 	 *	on, and from loadfont when flag 6 is set.						*
2838 	 *																	*
2839 	 ********************************************************************/
2840 
2841 
2842 
2843 	n = fontbase[i]->nwfont & BMASK;	/* number of width entries */
2844 
2845 	fprintf(fp_debug, "\nDUMP FOR FONT %s ", fontbase[i]->namefont);
2846 	fprintf(fp_debug, "   FONT POSITION = %d\n\n", i);
2847 	fprintf(fp_debug, "  font structure data:\n");
2848 	fprintf(fp_debug, "\t\tfont.nwfont = %d\n", fontbase[i]->nwfont & BMASK);
2849 	fprintf(fp_debug, "\t\tfont.specfont = %d\n", fontbase[i]->specfont & BMASK);
2850 	fprintf(fp_debug, "\t\tfont.ligfont = %d\n", fontbase[i]->ligfont & BMASK);
2851 	fprintf(fp_debug, "\t\tfont.spare1 = %d\n", fontbase[i]->spare1 & BMASK);
2852 	fprintf(fp_debug, "\t\tfont.intname = %s\n\n", fontbase[i]->intname);
2853 
2854 	fprintf(fp_debug, "  CHAR     WIDTH      CODE     INDEX\n");
2855 	count = 0;
2856 
2857 	for (j = 0; j < dev.nchtab + 128 - 32; j++)  {
2858 
2859 		if ( (pos = fitab[i][j] & BMASK) != 0 )  {
2860 			count++;
2861 			if ( j >= 96 )					/* special chars start at 128-32 */
2862 				 fprintf(fp_debug, "%5s", &chname[chtab[j-96]]);
2863 			else fprintf(fp_debug, "%5c", (j + 32) & BMASK);
2864 			fprintf(fp_debug, "%10d", widthtab[i][pos] & BMASK);
2865 			fprintf(fp_debug, "%10d", codetab[i][pos] & BMASK);
2866 			fprintf(fp_debug, "%10d", j);
2867 			if ( alt_tables == fontname[i].number )		/* print extra info */
2868 				fprintf(fp_debug, "%10d%10d", alt_code[pos] & BMASK, alt_font[pos]);
2869 			fprintf(fp_debug,"\n");
2870 		}	/* End if */
2871 
2872 	}	/* End for */
2873 
2874 	fprintf(fp_debug, "\n CHARACTER COUNT FOR THIS FONT = %d\n", count);
2875 	fprintf(fp_debug, "\n\n");
2876 
2877 }	/* End of fontprint */
2878 
2879 
2880 /*****************************************************************************/
2881 
2882 
2883 void
loadfont(int num,char * name,char * fdir)2884 loadfont (
2885     int num,						/* font position to load */
2886     char *name,						/* name of the font to load */
2887     char *fdir						/* name of directory to load from? */
2888 )
2889 
2890 
2891 {
2892 
2893 
2894 	int		fin;						/* font file descriptor */
2895 	int		nw;							/* width entries in new font file */
2896 	int		norig;						/* width entries in old font file */
2897 	char	temp[60];					/* path name of font file */
2898 
2899 
2900 
2901 	/********************************************************************
2902 	 *																	*
2903 	 *		This routine is called to load the font position num with	*
2904 	 *	the data for the font name. If the string fdir is not null then	*
2905 	 *	it is taken as the pathname of the directory that contains the	*
2906 	 *	'.out' file for the font that we are to load, otherwise we load	*
2907 	 *	this data from the standard font library.						*
2908 	 *																	*
2909 	 ********************************************************************/
2910 
2911 
2912 
2913 	if ( num < 0  ||  num > NFONT )		/* illegal font number - abort */
2914 		error(FATAL, "illegal fp command %d %s", num, name);
2915 
2916 	if ( strcmp(name, fontbase[num]->namefont) == SAME_STR )	/* in already */
2917 		return;
2918 
2919 	if ( fdir == NULL  ||  fdir[0] == '\0' )	/* no alternate directory */
2920 		 sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, name);
2921 	else sprintf(temp, "%s/%s.out", fdir, name);
2922 
2923 	if ( (fin = open(temp, O_RDONLY)) < 0 )			/* open the font file */
2924 		error(FATAL, "can't open font table %s", temp);
2925 
2926 	norig = fontbase[num]->nwfont & BMASK;	/* 'space' available in pos num */
2927 	READ(fin, fontbase[num], 3*norig + nchtab+128-32 + sizeof(struct Font));
2928 	nw = fontbase[num]->nwfont & BMASK;		/* 'space' needed for new font */
2929 	if ( nw > norig )						/* new font is too big - abort */
2930 		error(FATAL, "font %s too big for position %d", name, num);
2931 
2932 	close(fin);
2933 	widthtab[num] = (char *) fontbase[num] + sizeof(struct Font);
2934 	codetab[num] = (char *) widthtab[num] + 2 * nw;
2935 	fitab[num] = (char *) widthtab[num] + 3 * nw;
2936 	t_fp(num, fontbase[num]->namefont, fontbase[num]->intname);
2937 
2938 	fontbase[num]->nwfont = norig;			/* save size of position num */
2939 
2940 	if ( debug[6] ) fontprint(num);			/* dump font position num */
2941 
2942 }	/* End of loadfont */
2943 
2944 
2945 /*****************************************************************************/
2946 
2947 
2948 void
load_alt(int font)2949 load_alt (
2950     int font						/* load '.add' tables for this font */
2951 )
2952 
2953 
2954 {
2955 
2956 
2957 	int		nw;							/* number of width entries for font */
2958 	int		fin;						/* font file descriptor */
2959 	char	cmd[60];					/* room for font's .add file */
2960 
2961 
2962 
2963 	/********************************************************************
2964 	 *																	*
2965 	 *		This routine is called to read in the '.add' file for the	*
2966 	 *	font that is loaded in the position specified by the parameter	*
2967 	 *	font. These '.add' files are created by the special version of	*
2968 	 *	the makedev program, which reads and interprets several extra	*
2969 	 *	fields in the APS font tables. Included in the '.add' files are	*
2970 	 *	the alternate font table and the APS-5 character code table.	*
2971 	 *																	*
2972 	 ********************************************************************/
2973 
2974 
2975 
2976 	sprintf(cmd, "%s/dev%s/%s.add", fontdir, devname, fontname[font].name);
2977 
2978 	if ( (fin = open(cmd, O_RDONLY)) < 0 )	/* couldn't open the file */
2979 		error(FATAL, "can't open file %s", cmd);
2980 
2981 	nw = fontname[font].nwfont & BMASK;			/* number of width entries */
2982 
2983 	READ(fin, alt_font, nw * sizeof(alt_font[0]));
2984 	READ(fin, alt_code, nw);			/* read alternate code table */
2985 
2986 	close(fin);
2987 	alt_tables = fontname[font].number;	/* read in tables for this font */
2988 
2989 	if ( debug[7] )						/* print all the font information */
2990 		fontprint(font);
2991 
2992 }	/* End of load_alt */
2993 
2994 
2995 /*****************************************************************************/
2996