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