|
|
1.1 root 1:
2: /*
3: *
4: * dimpress - cleaned up and modified code borrowed from di10.
5: *
6: *
7: * troff post-processor for Imagen printers. Output is written in
8: * version 2.0 Impress, although it does still work for earlier versions.
9: * Raster files in either the old format or in Imagen's Rst format can
10: * be used for character generation. Drawing functions are handled by
11: * the routines in file impdraw.c. I rewrote most of those routines so they
12: * use the graphics primitives avaliable in version 1.9 (and later) Impress.
13: * If you're printer is still running older systems you'll probably need
14: * to get the original version of draw.c and use it instead.
15: *
16: * All the code should work properly for any printer that accepts Impress.
17: * By default I've got things set up for the 8/300, but you can use the
18: * -T option to select a different printer. If you choose a new printer
19: * name not supported under the -T option you'll probably want to add code
20: * to do the proper initialization. There really are only six variables
21: * that need to be changed for different printers. They include realdev,
22: * penwidth, pres, xoff, yoff, and possibly bitdir. The printer variables
23: * are defined in dimpress.h (PR_INIT) and that's what's used to initialize
24: * the prdata[] array. If you make changes just be sure that the list ends
25: * with an entry that has its prname field set to NULL.
26: *
27: *
28: * output language from troff:
29: * all numbers are character strings
30: *
31: * sn size in points
32: * fn font as number from 1-n
33: * cx ascii character x
34: * Cxyz funny char xyz. terminated by white space
35: * Hn go to absolute horizontal position n
36: * Vn go to absolute vertical position n (down is positive)
37: * hn go n units horizontally (relative)
38: * vn ditto vertically
39: * nnc move right nn, then print c (exactly 2 digits!)
40: * (this wart is an optimization that shrinks output file size
41: * about 35% and run-time about 15% while preserving ascii-ness)
42: * Dt ...\n draw operation 't':
43: * Dl x y line from here by x,y
44: * Dc d circle of diameter d with left side here
45: * De x y ellipse of axes x,y with left side here
46: * Da x y r arc counter-clockwise by x,y of radius r
47: * D~ x y x y ... wiggly line by x,y then x,y ...
48: * nb a end of line (information only -- no action needed)
49: * b = space before line, a = after
50: * p new page begins -- set v to 0
51: * #...\n comment
52: * x ...\n device control functions:
53: * x i init
54: * x T s name of device is s
55: * x r n h v resolution is n/inch
56: * h = min horizontal motion, v = min vert
57: * x p pause (can restart)
58: * x s stop -- done for ever
59: * x t generate trailer
60: * x f n s font position n contains font s
61: * x H n set character height to n
62: * x S n set slant to N
63: *
64: * Subcommands like "i" are often spelled out like "init".
65: *
66: */
67:
68: #include <stdio.h>
69: #include <signal.h>
70: #include <math.h>
71: #include <ctype.h>
72: #include <time.h>
73:
74: #include "gen.h" /* general purpose definitions */
75: #include "ext.h" /* external variable definitions */
76: #include "init.h" /* just used for BITDIR definition */
77: #include "rast.h" /* raster file definitions */
78: #include "dev.h" /* typesetter and font descriptions */
79: #include "impcodes.h" /* Impress 2.0 opcode definitions */
80: #include "dimpress.h" /* defs just used by this program */
81: #include "spectab.h"
82:
83:
84: /*
85: *
86: * A few names we'll need when we're printing files. devname[] is what troff
87: * thought was going to be the output device while realdev[] is the name
88: * of the printer we're really going to be using. There may be occasions when
89: * we want to send the output to a given printer (*realdev) but we want to
90: * use the raster tables that were built for a different one (*rastdev). If
91: * rastdev isn't NULL we'll assume that this is the name of the device's
92: * raster files that we want to use. In otherwords if *rastdev hasn't been
93: * set by an option *realdev will be used in combination with *bitdir to
94: * define *rastdir.
95: *
96: */
97:
98:
99: char devname[20] = ""; /* troff's target printer */
100: char *realdev = NULL; /* name of the printer we're really using */
101: char *rastdev = NULL; /* use raster tables made for this guy */
102:
103:
104: /*
105: *
106: * There's a bunch of stuff we'll want to know about the raster files we're
107: * planning on using for this job. The most important, obviously is where
108: * they're located. The routines that access the raster files all assume
109: * they're in directory *rastdir, so it better be set up right before we
110: * try to print anything. I've decided to have this program build up the
111: * *rastdir string from *bitdir and either *rastdev or *realdev. All this
112: * stuff will be done after the options are read. One of the reasons I'm
113: * doing things this way is because we could want to do something like
114: * print a troff file generated for the APS-5 on an Imprint-10 using the
115: * raster files built for an 8/300. While that may sound rediculous the
116: * raster tables can use up a lot of disk space and we may not want to
117: * waste the space keeping complete sets of raster files for two or three
118: * different devices. Anyway we should be able to do something reasonable
119: * no matter what devices and raster files are requested.
120: *
121: * *bitdir is initialized to BITDIR (file init.h) and can be changed using
122: * the -B option. The raster files for a particular device, say the 8/300
123: * which is being called i300, will be found in directory *bitdir/rasti300.
124: * It's defined in file glob.c because resident font routines need the
125: * directory.
126: *
127: * We'll also need to know the format of the raster files we're using before
128: * we can have any characters printed. rastformat keeps track of which
129: * style is being used. It's initialized in routine rastsetup() using
130: * info in file *rastdir/RASTDATA - if it exists. Right now if rastsetup()
131: * can't read the RASTDATA file it assumes that the raster files are the
132: * old versetec format and have a resolution of 240 dots per inch. I've
133: * done things this way just to make sure we can use the post-processor
134: * with the old raster files without having to add an appropriate RASTDATA
135: * file to the directory. Eventually it may not be a bad idea to just
136: * quit if we can't read the file.
137: *
138: */
139:
140:
141: int rastformat;
142:
143:
144: /*
145: *
146: * Although I originally had ideas about not using a RASTERLIST file, I now
147: * think it's probably a pretty good idea to use one. We could get around the
148: * missing size problems by linking raster files for unavailble sizes to ones
149: * we really have. That approach would cost more in downloading glyphs, but
150: * more we'd probably be able to place the glyphs a little better because
151: * we'd be able to set the character advance separately. Anyway it's really
152: * not all that clear which approach is better. I've allowed for use of a
153: * RASTERLIST file (routine rastlist()) but I've also decided that if it's
154: * not there we'll continue on with the program assuming we have every size
155: * that jobs ask for. If the job asks for a non-existent file it will die
156: * in routine getrastdata().
157: *
158: * The following data structures are used to keep track of any RASTLIST
159: * data we may have read. If maxrast is zero then there isn't any data
160: * and we'll assume, when we do the lookups, that all fonts can be printed
161: * in any size.
162: *
163: */
164:
165:
166: int maxrast = 0; /* number of RASTERLIST font entries */
167: Sizedata sizedata[MAXFONTS]; /* available raster size data */
168:
169:
170: /*
171: *
172: * Standard things needed after we've read troff's font and device tables.
173: * The binary files are all built by makedev and will be looked for in the
174: * target printer's dev directory located in *fontdir. Actually that's not
175: * quite right. There are mapping problems, both for fonts and characters,
176: * that will exist if we try and use font files for a device that don't
177: * exactly map into the raster files that are being used. For example if
178: * we used the character code field in the normal APS-5 font tables when
179: * we print jobs generated for the APS-5 we'd be guaranteed to get garbage.
180: * To get around that problem I have the post-processor first look in
181: * *rastdir for the dev directory. If it's not there then we look in *fontdir.
182: *
183: */
184:
185:
186: struct dev dev; /* DESC.out starts this way */
187: struct Font *fontbase[NFONT+1]; /* starts each FONT.out file */
188: short *pstab; /* typesetter knows these sizes */
189: int nsizes = 1; /* sizes in *pstab list */
190: int nfonts; /* number of font positions */
191: int smnt; /* index of first special font */
192: int nchtab; /* number of special character names */
193: char *chname; /* special character strings */
194: short *chtab; /* used to locate character names */
195: char *fitab[NFONT+1]; /* locates char info on each font */
196: char *widthtab[NFONT+1]; /* widtab would be a better name */
197: char *codetab[NFONT+1]; /* codes to get characters printed */
198:
199:
200: /*
201: *
202: * Variables that we use to keep track of troff's requests. All these
203: * guys are set from values in the input files.
204: *
205: */
206:
207:
208: int size = 1; /* current size - internal value */
209: int font = 1; /* font position we're using now */
210: int hpos = 0; /* troff's current horizontal position */
211: int vpos = 0; /* same but vertically */
212: int lastw = 0; /* width of the last input character */
213: int lastc = 0; /* and its name (or index) */
214:
215:
216: /*
217: *
218: * We'll also want to keep track of some of the same things, but for the
219: * target printer.
220: *
221: */
222:
223:
224: int lastsize = -1; /* last internal size we used */
225: int lastfont = -1; /* last font we told printer about */
226: int lastx = -1; /* printer's current position */
227: int lasty = -1;
228:
229:
230: /*
231: *
232: * The following structure is used to keep track of the fonts that are
233: * loaded in various positions. Both fields are filled in by routine t_fp()
234: * using values in the binary font files.
235: *
236: */
237:
238:
239: struct {
240: char *name; /* name of the font loaded here */
241: int number; /* its internal number */
242: } fontname[NFONT+1];
243:
244:
245: /*
246: *
247: * A few variables that are really just used for drawing things. Although
248: * they're declared here most are only really used in draw.c. The pen
249: * width and the step sizes can be changed by options. The step sizes DX
250: * and DY control how far we move horizontally or vertically between
251: * adjacent dots when drawing curves. They'll have no effect if we're
252: * using Impress graphics commands for all graphics. Decreasing DX and DY
253: * improves pictures but increases the size and complexity of the output
254: * files. Because Impress complies and prints pages on the fly you may
255: * not be able to draw fairly simple figures if the step sizes are too
256: * small.
257: *
258: */
259:
260:
261: int drawdot = '.'; /* draw with this character */
262: int drawsize = 1; /* shrink size by this factor */
263: int penwidth = 1; /* use this as the pen diameter */
264: int DX = 6; /* horiz step when using drawdot */
265: int DY = 6; /* same but for vertical step */
266:
267:
268: /*
269: *
270: * We may want to shift things around on the output page a little. In
271: * particular moving everything right on the output pages is normal because
272: * the left 3/8 inch or so of each page on an Imprint-10 isn't visible.
273: * All this stuff could be done more efficiently by defining a new
274: * coordinate system to match the requested offsets rather than doing
275: * the calculations each time. I've left things this way for now because
276: * that's the way we originally did stuff in di10.
277: *
278: * The xoff and yoff values are in inches while the xoffset and yoffset
279: * numbers are pixels. We'll set the pixel values after we're sure about
280: * the target printer's resolution. xoff and yoff can be changed by options.
281: * xfac and yfac are scaling factors used to convert coordinates in the
282: * input files to appropiate values in the target printers coordinate
283: * system. Their values are set in t_init() because we can only do it
284: * properly after we've gotten the printer's resolution (from options)
285: * and read the "x res" command in each input file.
286: *
287: */
288:
289:
290: float xoff; /* shift right by this many inches */
291: float yoff; /* and down by this much */
292:
293: int xoffset; /* pixel values = xoff * pres */
294: int yoffset; /* = yoff * pres */
295: float xfac = 1.0; /* scaling factor for x */
296: float yfac = 1.0; /* scaling factor for y */
297:
298:
299: /*
300: *
301: * A few miscellaneous variable declarations. I've added landscape mode
302: * to the post-processor. It's requested using the -l option. Might also
303: * be reasonable to add a new device control command to request landscape
304: * mode, although I haven't done it yet. None of this stuff will work with
305: * printer resident fonts.
306: *
307: */
308:
309:
310: int mode = PORTRAIT; /* landscape or portrait mode */
311: int angle = ROT_0; /* ROT_270 for LNADSCAPE mode */
312: int output = 0; /* do we do output at all? */
313: int pageno = -1; /* output page number */
314: int copies = 1; /* ask IPR for this many */
315: float aspect = 1; /* default aspect ratio */
316: int cancenter = TRUE; /* try to improve char placement? */
317: int center = 0; /* for alphanumeric characters only */
318:
319:
320: /*
321: *
322: * We'll really need to deal with three possibly different resolutions
323: * when we're printing files. The first is the resolution used by troff in
324: * preparing the input file. Next is the resolution of the target printer.
325: * Imprint-10s are 240 and 8/300s are 300 dots per inch. Finially we'll need
326: * or at least want to know the resolution of the raster files we're using
327: * to print the file. Obviously we'll get the best results when all three
328: * numbers agree, but no matter what we should be able to do something
329: * reasonable with any set of numbers.
330: *
331: */
332:
333:
334: int res; /* resolution assumed in input file */
335: int pres; /* resolution of the target printer */
336: int rres; /* raster file resolution */
337:
338:
339: /*
340: *
341: * The data about the different printers supported by the program is
342: * stored in prdata[]. It's initialized using PR_INIT which is defined
343: * in dimpress.h. The fields in structure Prdata are used to define the
344: * printer name, resolution, x and y offsets (in inches), and the string
345: * that should be used for *bitdir.
346: *
347: */
348:
349:
350: Prdata prdata[] = PR_INIT; /* printer data */
351:
352: int pr_num = PR_NUM; /* printer we're using - index in prdata[] */
353:
354:
355: /*
356: *
357: * Many of the printer dependent variables can be set by several different
358: * options. Most times we'll want to use the -T option, but there may be
359: * occasions when we want to override one or more of the default values.
360: * These variables keep track of whether we've tried to set values by other
361: * options.
362: *
363: */
364:
365:
366: int setpenwidth = FALSE; /* changed by the -P option */
367: int setxoff = FALSE; /* -x option */
368: int setyoff = FALSE; /* -y option */
369: int setpres = FALSE; /* -r option */
370:
371:
372: /*
373: *
374: * A few variables that are really only used if we're doing accounting.
375: * Much of the accounting stuff has been designed for our own use at
376: * MHCC and may not suit your needs.
377: *
378: */
379:
380:
381: char *acctfile = NULL; /* append accounting record to this file */
382: char *jacctfile = NULL; /* just a page count for this job */
383: int acctpages = 0; /* charge for this many pages */
384: char *username = NULL; /* guy whose running this program */
385:
386:
387: /*
388: *
389: * If we're emulating another device we'll want to use the following array to
390: * help map font names available on that device into PostScript fonts. It's
391: * initialized using FONTMAP (file dpost.h) and may be changed in routine
392: * getfontmap(). In particular if there's a file that matches the device name
393: * in directory *fontdir/devpost/fontmaps, getfontmap() will use it instead of
394: * the default - haven't implemented it and probably never will.
395: *
396: */
397:
398:
399: Fontmap fontmap[100] = FONTMAP; /* just for device emulation */
400:
401:
402: /*
403: *
404: * Output and accounting FILE definitions. If you invoke this program with
405: * the -t option everything goes to stdout, otherwise it will be written
406: * to *tempfile and then passed along to Imagen's spooler using IPR.
407: *
408: */
409:
410: char *tempfile = NULL; /* output file name if no -t option used */
411:
412: FILE *tf = NULL; /* and Impress output goes here */
413: FILE *fp_acct = stderr; /* accounting stuff written here */
414:
415:
416: extern int maxdots; /* defined and used in draw.c */
417:
418:
419: /*****************************************************************************/
420:
421:
422: main(agc, agv)
423:
424:
425: int agc;
426: char *agv[];
427:
428:
429: {
430:
431:
432: /*
433: *
434: * Post-processor that's used to translate troff's device independent
435: * output language into Impress (version 2.0 right now). A call to Imagen's
436: * spooling package, through IPR, is made in print_file() provided
437: * the output hasn't gone to stdout. Using the -t option or initializing
438: * tf to be stdout forces output to stdout. If there are any processing
439: * errors x_stat will be non-zero and done() will remove *tempfile before
440: * quitting.
441: *
442: */
443:
444:
445: argc = agc; /* global so everyone can use them */
446: argv = agv;
447:
448: prog_name = argv[0]; /* just used for error messages */
449:
450: init_signals(); /* sets up interrupt handling */
451: options(); /* command line options */
452: initialize(); /* must be done after options */
453: rastsetup(); /* set all the raster file stuff up */
454: rastlist(); /* get availble font and size list */
455: resfonts(tf); /* setup for any resident fonts */
456: acct_file(); /* open accounting file - maybe */
457:
458: arguments(); /* translate all the input files */
459: t_wrapup(); /* mark the end of job for Impress */
460: print_file(); /* print the file we just built */
461:
462: done(); /* everything probably went OK */
463:
464: } /* End of main */
465:
466:
467: /*****************************************************************************/
468:
469:
470: init_signals()
471:
472:
473: {
474:
475:
476: int done(); /* handles them if we're catching sigs */
477:
478:
479: /*
480: *
481: * Makes sure we handle any interrupts properly. It wasn't done right
482: * in di10.
483: *
484: */
485:
486:
487: if ( signal(SIGINT, done) == SIG_IGN ) {
488: signal(SIGINT, SIG_IGN);
489: signal(SIGQUIT, SIG_IGN);
490: signal(SIGHUP, SIG_IGN);
491: } else {
492: signal(SIGHUP, done);
493: signal(SIGQUIT, done);
494: } /* End else */
495:
496: } /* End of init_signals */
497:
498:
499: /*****************************************************************************/
500:
501:
502: options()
503:
504:
505: {
506:
507:
508: int ch; /* option name returned from getopt */
509: char *names = "u:c:tx:y:r:a:o:p:LP:n:d:F:f:B:f:R:T:AJ:";
510:
511: extern char *optarg; /* option argument set by getopt() */
512: extern int optind;
513:
514:
515: /*
516: *
517: * Processes the command line options. The original stuff stuff done in
518: * di10 has been changed a little. I've also used getopt() to scan the
519: * options.
520: *
521: * The most confusing options are -B and -R. The *bitdir string is the
522: * directory where we expect to find the raster file directories. They all
523: * start with "rast" and end with a device name. I've got things set up so
524: * that they're in /usr/lib/raster, but di10 looked for directory rasti10
525: * in *fontdir (/usr/lib/font/devi10). The -B option changes the value
526: * of *bitdir. If you're running DWB and want this program to replace di10
527: * call it using the option "-B /usr/lib/font/devi10". The -R option
528: * sets the value of string *rastdev. If that string isn't NULL then
529: * "/rast*rastdev" will be appended to the end of *bitdir to locate the
530: * raster file directory that we really want to use. By default rastdev is
531: * NULL so *realdev will be used in its place.
532: *
533: * The -c option doesn't work right now. If you want to implement it you'll
534: * probably just need to change the IPR system() call that's made in
535: * print_file().
536: *
537: */
538:
539:
540: while ( (ch = getopt(argc, argv, names)) != EOF ) {
541: switch ( ch ) {
542: case 'u':
543: username = optarg;
544: break;
545:
546: case 'c':
547: copies = atoi(optarg);
548: break;
549:
550: case 't':
551: tf = stdout;
552: break;
553:
554: case 'x':
555: xoff = atof(optarg);
556: setxoff = TRUE;
557: break;
558:
559: case 'y':
560: yoff = atof(optarg);
561: setyoff = TRUE;
562: break;
563:
564:
565: case 'r':
566: pres = atoi(optarg);
567: setpres = TRUE;
568: break;
569:
570: case 'a':
571: aspect = atof(optarg);
572: break;
573:
574: case 'o':
575: out_list(optarg);
576: break;
577:
578: case 'p': /* pixels of resolution */
579: if ( (DX = DY = atoi(optarg)) <= 0 )
580: DX = DY = 1;
581: break;
582:
583: case 'L': /* landscape mode */
584: mode = LANDSCAPE;
585: break;
586:
587: case 'P': /* pen diameter for drawing */
588: if ( (penwidth = atoi(optarg)) > 20 )
589: penwidth = 20;
590: else if ( penwidth < 1 ) penwidth = 1;
591: setpenwidth = TRUE;
592: break;
593:
594: case 'n': /* a limit for drawing routines */
595: if ( (maxdots = atoi(optarg)) <= 0 )
596: maxdots = 32000;
597: break;
598:
599: case 'd':
600: if ( (debug = atoi(optarg)) == 0 )
601: debug = 1;
602: tf = stdout;
603: break;
604:
605: case 'F': /* font table directory */
606: fontdir = optarg;
607: break;
608:
609: case 'B': /* rast* directories found here */
610: bitdir = optarg;
611: break;
612:
613: case 'f': /* use this resident font file */
614: resfile = optarg;
615: break;
616:
617: case 'R': /* use this guys raster files */
618: rastdev = optarg;
619: break;
620:
621: case 'T': /* target printer */
622: for ( pr_num = 0; prdata[pr_num].prname != NULL; pr_num++ )
623: if ( strcmp(optarg, prdata[pr_num].prname) == 0 )
624: break;
625: if ( prdata[pr_num].prname == NULL )
626: error(FATAL, "don't know printer %s", optarg);
627: break;
628:
629: /* These options were added for the MHCC */
630:
631: case 'A':
632: x_stat |= DO_ACCT;
633: break;
634:
635: case 'J':
636: jacctfile = optarg;
637: x_stat |= DO_ACCT;
638: break;
639:
640: case '?':
641: error(FATAL, "");
642: break;
643:
644: default:
645: error(FATAL, "don't know option %s", argv[1]);
646: break;
647: }
648: }
649:
650: argc -= optind; /* get ready for non-options args */
651: argv += optind;
652:
653: } /* End of options */
654:
655:
656: /*****************************************************************************/
657:
658:
659: initialize()
660:
661:
662: {
663:
664:
665: char *mktemp();
666: #ifdef V9
667: char *getlogin();
668: #endif
669:
670:
671: /*
672: *
673: * Much of this stuff can only be done properly after the command line
674: * options have been processed, so make sure it's called (from main())
675: * after options().
676: *
677: */
678:
679: #ifdef V9
680: if (username == NULL && (username = getlogin()) == NULL )
681: #endif
682: #ifdef SYSV
683: if ( (username = cuserid((char *) 0)) == NULL )
684: #endif
685: username = "???";
686:
687: if (tf != stdout) {
688: tempfile = mktemp("/tmp/dimpXXXXX");
689: if ((tf = fopen(tempfile, "w")) == NULL)
690: error(FATAL, "can't open temporary file %s", tempfile);
691: } /* End if */
692:
693: if ( realdev == NULL )
694: realdev = prdata[pr_num].prname;
695:
696: if ( setpres == FALSE )
697: pres = prdata[pr_num].pres;
698:
699: if ( setxoff == FALSE )
700: xoff = prdata[pr_num].xoff;
701:
702: if ( setyoff == FALSE )
703: yoff = prdata[pr_num].yoff;
704:
705: if ( setpenwidth == FALSE )
706: penwidth = prdata[pr_num].penwidth;
707:
708: if ( bitdir == NULL )
709: bitdir = prdata[pr_num].bitdir;
710:
711: if ( resfile == NULL )
712: resfile = prdata[pr_num].prname;
713:
714: res = rres = pres; /* just to be safe */
715:
716: xoffset = pres * xoff; /* set the pixel offsets */
717: yoffset = pres * yoff;
718:
719: } /* End of initialize */
720:
721:
722: /*****************************************************************************/
723:
724:
725: rastsetup()
726:
727:
728: {
729:
730:
731: static char rastname[100]; /* rastdir string saved here */
732: char temp[100]; /* for pathnames and reads from *fp */
733: FILE *fp; /* RASTDATA and RASTLIST files */
734: int ch; /* just used to skip lines in *fp */
735:
736:
737: /*
738: *
739: * We'll need to know a bunch of stuff about the raster files before we can
740: * actually use them. First of all we need to figure out where they are.
741: * Strings *bitdir and either *rastdev or *realdev will be used to initialize
742: * *rastdir. Once we've got rastname set up we'll need to determine the
743: * format of the raster files and their resolution. All that stuff should
744: * be in file *rastdir/RASTDATA. If the file's not there or we can't read
745: * it we'll assume the files are written in the old format at a resolution
746: * of 240 dots per inch. I've done things this way because RASTDATA is new
747: * and won't be part of the of raster file directory unless you add it.
748: * This way nothing has to be done to the old raster file directory.
749: *
750: */
751:
752:
753: sprintf(rastname, "%s/rast%s", bitdir, (rastdev == NULL) ? realdev : rastdev);
754: rastdir = rastname;
755:
756: sprintf(temp, "%s/%s", rastdir, RASTDATA);
757: if ( (fp = fopen(temp, "r")) == NULL ) {
758: rastformat = OLD_FORMAT;
759: rres = 240;
760: return;
761: } /* End if */
762:
763: while ( fscanf(fp, "%s", temp) != EOF )
764: if ( strcmp(temp, "format") == 0 ) {
765: fscanf(fp, "%s", temp);
766: if ( strcmp(temp, "old") == 0 )
767: rastformat = OLD_FORMAT;
768: else rastformat = RST_FORMAT;
769: } else if ( strcmp(temp, "resolution") == 0 )
770: fscanf(fp, "%d", &rres);
771: else while ( (ch = getc(fp)) != '\n' && ch != EOF ) ;
772:
773: fclose(fp);
774:
775: } /* End of rastsetup */
776:
777:
778: /*****************************************************************************/
779:
780:
781: rastlist()
782:
783:
784: {
785:
786:
787: int n; /* next size for current font */
788: int i; /* next size goes here */
789: char name[100]; /* pathname for RASTERLIST file */
790: FILE *fp;
791:
792:
793: /*
794: *
795: * If we're not using the old format raster files we'll want to read the
796: * list of available fonts and sizes in *rastdir. The file that's got all
797: * the info is called RASTLIST (defined in init.h). The format is exactly
798: * the same as Brian's original file. Under the old format all this stuff
799: * is done in routine initfontdata().
800: *
801: * For now if we can't open RASTERLIST and were not using the old format
802: * raster files we'll just return to the caller. That really just means
803: * we'll assume we can handle any font + size request that may come our
804: * way. If that's not the case we better make up a complete RASTERLIST file.
805: *
806: */
807:
808:
809: if ( rastformat == OLD_FORMAT ) /* don't bother doing it here */
810: return;
811:
812: sprintf(name, "%s/%s", rastdir, RASTLIST);
813: if ( (fp = fopen(name, "r")) == NULL )
814: return;
815:
816: while ( fscanf(fp, "%s", sizedata[maxrast].name) != EOF ) {
817: i = 0;
818: while ( fscanf(fp, "%d", &n) != EOF && n < 100 )
819: sizedata[maxrast].sizes[i++] = n;
820: sizedata[maxrast].sizes[i] = 999;
821: if ( ++maxrast >= MAXFONTS )
822: error(FATAL, "too many fonts in %s", name);
823: } /* End while */
824:
825: fclose(fp);
826:
827: } /* End of rastlist */
828:
829:
830: /*****************************************************************************/
831:
832:
833: arguments()
834:
835:
836: {
837:
838:
839: FILE *fp; /* next input file */
840:
841:
842: /*
843: *
844: * All the rest of the command line options are input files we want to
845: * translate. If we get here and there are no more arguments, or if '-' is
846: * in the list of file names, we'll process stdin.
847: *
848: */
849:
850:
851: if (argc < 1)
852: conv(stdin);
853: else
854: while (argc > 0) {
855: if (strcmp(*argv, "-") == 0)
856: fp = stdin;
857: else if ((fp = fopen(*argv, "r")) == NULL)
858: error(FATAL, "can't open %s", *argv);
859: conv(fp);
860: fclose(fp);
861: argc--;
862: argv++;
863: }
864:
865: } /* End of arguments */
866:
867:
868: /*****************************************************************************/
869:
870:
871: print_file()
872:
873:
874: {
875:
876:
877: char buf[BUFSIZ]; /* IPR command line built up here */
878:
879:
880: /*
881: *
882: * Finished with all the input files and everything the printer needs to
883: * know is in FILE *tf. We'll close the file because we're all done with
884: * it, and then call IPR if we haven't been writing to stdout.
885: *
886: */
887:
888:
889: fclose(tf); /* everything's in the file */
890:
891: if ( tf != stdout || debug ) {
892: sprintf(buf, "%s -Limpress -r -o '-Downer \"'\"%s\"'\"'\", jobheader on, pagecollation on, pagereversal on\" %s 0</dev/null 1>/dev/null 2>&1 &",
893: IPR, username, tempfile);
894: if ( debug )
895: fprintf(stderr, "executing %s\n", buf);
896: else system(buf);
897: } /* End if */
898:
899: } /* End of print_file */
900:
901:
902: /*****************************************************************************/
903:
904:
905: acct_file()
906:
907:
908: {
909:
910:
911: /*
912: *
913: * If we want to do accounting *acctfile will be the name of the file where
914: * we put the accounting data. If for some reason we can't open the file
915: * we'll just quit. I've called the routine from main() before anything is
916: * written to the output file.
917: *
918: */
919:
920:
921: if ( acctfile != NULL && *acctfile != '\0' ) {
922: if ( (fp_acct = fopen(acctfile, "a")) == NULL ) {
923: fp_acct = stderr;
924: x_stat |= NO_ACCTFILE;
925: error(FATAL, "can't open accounting file");
926: exit(x_stat);
927: }
928: if ( tf != stdout )
929: x_stat |= DO_ACCT;
930: }
931:
932: } /* End of acct_file */
933:
934:
935: /*****************************************************************************/
936:
937:
938: account()
939:
940:
941: {
942:
943:
944: FILE *f; /* just the job's page count */
945:
946:
947: /*
948: *
949: * Writes an accounting record, usually to *fp_acct, for the current job.
950: * All this stuff is set up for our MHCC printers. In some cases we'll
951: * know most everything about the job (called with -J option) and all
952: * we'll do is write a page count to *jacctfile. In other cases we'll want
953: * a more complete record and all the stuff will go to *fp_acct. You'll
954: * undoubtedly want to change this stuff to suit your own needs.
955: *
956: */
957:
958: if ( x_stat & DO_ACCT ) {
959: if ( jacctfile == NULL || *jacctfile == '\0' ) {
960: fprintf(fp_acct, " user = %-10s", username);
961: fprintf(fp_acct, " paper = %-10d", acctpages * copies);
962: x_stat &= ~DO_ACCT;
963: fprintf(fp_acct, " exit_status = 0%-6o", x_stat);
964: fprintf(fp_acct, " type = t ");
965: if ( tf == stdout )
966: fprintf(fp_acct, " ??");
967: fprintf(fp_acct, "\n");
968: } else {
969: if ( (f = fopen(jacctfile, "a")) != NULL ) {
970: fprintf(f, "%d\n", acctpages);
971: fclose(f);
972: }
973: x_stat &= ~DO_ACCT;
974: } /* End else */
975: }
976:
977: } /* End of account */
978:
979:
980: /*****************************************************************************/
981:
982:
983: done()
984:
985:
986: {
987:
988:
989: /*
990: *
991: * Finished with everything so we want to make sure accounting is handled
992: * properly and the right exit status is returned to the caller. We'll also
993: * delete the temporary file if x_stat != 0.
994: *
995: */
996:
997:
998: account();
999:
1000: if ( tf != stdout && x_stat != 0 )
1001: unlink(tempfile);
1002:
1003: exit(x_stat);
1004:
1005: } /* End of done */
1006:
1007:
1008: /*****************************************************************************/
1009:
1010:
1011: conv(fp)
1012:
1013:
1014: register FILE *fp;
1015:
1016:
1017: {
1018:
1019:
1020: register int c, k;
1021: int m, n, i, n1, m1;
1022: char str[100], buf[300];
1023:
1024:
1025: /*
1026: *
1027: * Controls the translation of troff's device independent output language
1028: * to Impress. Some of the commands, like slant and height, are no-ops
1029: * on Imagen's bitmap printers even though routines are called to do the
1030: * processing.
1031: *
1032: */
1033:
1034:
1035: lineno = 1; /* line in current file */
1036: x_stat |= FILE_STARTED; /* we'll clear it when done with *fp */
1037:
1038: while ((c = getc(fp)) != EOF) {
1039:
1040: switch (c) {
1041:
1042: case '\n': /* just count this line */
1043: lineno++;
1044: break;
1045:
1046: case ' ': /* when input is text */
1047: case 0: /* occasional noise creeps in */
1048: break;
1049:
1050: case '0': case '1': case '2': case '3': case '4':
1051: case '5': case '6': case '7': case '8': case '9':
1052: /* two motion digits plus a character */
1053: hmot((c-'0')*10 + getc(fp)-'0');
1054: put1(getc(fp));
1055: break;
1056:
1057: case 'c': /* single ascii character */
1058: put1(getc(fp));
1059: break;
1060:
1061: case 'C': /* special character */
1062: fscanf(fp, "%s", str);
1063: put1s(str);
1064: break;
1065:
1066: case 'N': /* character at position n */
1067: fscanf(fp, "%d", &m);
1068: oput(m);
1069: break;
1070:
1071: case 'D': /* drawing function */
1072: fgets(buf, sizeof(buf), fp);
1073: lineno++;
1074: switch (buf[0]) {
1075: case 'l': /* draw a line */
1076: sscanf(buf+1, "%d %d", &n, &m);
1077: drawline(n, m);
1078: break;
1079:
1080: case 'c': /* circle */
1081: sscanf(buf+1, "%d", &n);
1082: drawcirc(n);
1083: break;
1084:
1085: case 'e': /* ellipse */
1086: sscanf(buf+1, "%d %d", &m, &n);
1087: drawellip(m, n);
1088: break;
1089:
1090: case 'a': /* arc */
1091: sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
1092: drawarc(n, m, n1, m1);
1093: break;
1094:
1095: case '~': /* wiggly line */
1096: drawwig(buf+1);
1097: break;
1098:
1099: default:
1100: error(FATAL, "unknown drawing function %s", buf);
1101: break;
1102: }
1103: break;
1104:
1105: case 's': /* use this point size */
1106: fscanf(fp, "%d", &n); /* ignore fractional sizes */
1107: setsize(t_size(n));
1108: break;
1109:
1110: case 'f': /* use font mounted here */
1111: fscanf(fp, "%s", str);
1112: setfont(t_font(str));
1113: break;
1114:
1115: case 'H': /* absolute horizontal motion */
1116: /*
1117: *
1118: * The simple scan I've commented out didn't handle negative numbers right
1119: * and believe it or not we did get jobs that asked for negative absolute
1120: * positions. Even though negative absolute coordinates probably are a
1121: * mistake it makes more sense to handle the numbers properly.
1122: *
1123: while ((c = getc(fp)) == ' ')
1124: ;
1125: k = 0;
1126: do {
1127: k = 10 * k + c - '0';
1128: } while (isdigit(c = getc(fp)));
1129: ungetc(c, fp);
1130: hgoto(k);
1131: *
1132: */
1133: fscanf(fp, "%d", &n);
1134: hgoto(n);
1135: break;
1136:
1137: case 'h': /* relative horizontal motion */
1138: /*
1139: *
1140: * Again the same potential problem with negative numbers exists here. In
1141: * fact it makes a lot more sense to expect negative relative motions even
1142: * though I never did see them. Anyway just to be safe I've made the same
1143: * change - take it out if you want.
1144: *
1145: while ((c = getc(fp)) == ' ')
1146: ;
1147: k = 0;
1148: do {
1149: k = 10 * k + c - '0';
1150: } while (isdigit(c = getc(fp)));
1151: ungetc(c, fp);
1152: hmot(k);
1153: *
1154: */
1155: fscanf(fp, "%d", &n);
1156: hmot(n);
1157: break;
1158:
1159: case 'w': /* word space */
1160: break;
1161:
1162: case 'V': /* absolute vertical position */
1163: fscanf(fp, "%d", &n);
1164: vgoto(n);
1165: break;
1166:
1167: case 'v': /* relative vertical motion */
1168: fscanf(fp, "%d", &n);
1169: vmot(n);
1170: break;
1171:
1172: case 'p': /* new page */
1173: fscanf(fp, "%d", &n);
1174: t_page(n);
1175: break;
1176:
1177: case 'n': /* end of line */
1178: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
1179: t_newline();
1180: lineno++;
1181: break;
1182:
1183: case '#': /* comment */
1184: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
1185: lineno++;
1186: break;
1187:
1188: case 'x': /* device control function */
1189: devcntrl(fp);
1190: break;
1191:
1192: default:
1193: error(!FATAL, "unknown input character %o %c", c, c);
1194: done();
1195: }
1196: }
1197:
1198: x_stat &= ~FILE_STARTED;
1199:
1200: } /* End of conv */
1201:
1202:
1203: /*****************************************************************************/
1204:
1205:
1206: devcntrl(fp)
1207:
1208:
1209: FILE *fp; /* current input file */
1210:
1211:
1212: {
1213:
1214:
1215: char str[20], str1[50], buf[50];
1216: int c, n, x, y;
1217:
1218:
1219: /*
1220: *
1221: * Called form conv() to process the rest of a device control function.
1222: * There's a whole family of them and they all begin with the string
1223: * "x ". The rest of the command consists of the function name followed
1224: * by zero or more arguments that depend on the particular command. We've
1225: * already read the "x" from the input file, that's why the routine was
1226: * called. The whole rest of the input line is assumed to be part of the
1227: * device control command.
1228: *
1229: */
1230:
1231:
1232: fscanf(fp, "%s", str); /* get the control function name */
1233:
1234: switch ( str[0] ) { /* only the first character counts now */
1235: case 'i': /* initialize */
1236: fileinit();
1237: t_init(0);
1238: break;
1239:
1240: case 'T': /* device name */
1241: fscanf(fp, "%s", devname);
1242: break;
1243:
1244: case 't': /* trailer */
1245: t_trailer();
1246: break;
1247:
1248: case 'p': /* pause -- can restart */
1249: t_reset('p');
1250: break;
1251:
1252: case 's': /* stop */
1253: t_reset('s');
1254: break;
1255:
1256: case 'r': /* resolution assumed when prepared */
1257: fscanf(fp, "%d", &res);
1258: break;
1259:
1260: case 'f': /* load font in a position */
1261: fscanf(fp, "%d %s", &n, str);
1262: fgets(buf, sizeof buf, fp); /* in case there's a filename */
1263: ungetc('\n', fp); /* fgets goes too far */
1264: str1[0] = 0; /* in case there's nothing to come in */
1265: sscanf(buf, "%s", str1);
1266: loadfont(n, str, str1);
1267: break;
1268:
1269: /* these don't belong here... */
1270: case 'H': /* char height */
1271: fscanf(fp, "%d", &n);
1272: t_charht(n);
1273: break;
1274:
1275: case 'S': /* slant */
1276: fscanf(fp, "%d", &n);
1277: t_slant(n);
1278: break;
1279:
1280: case 'I':
1281: case 'B':
1282: x = hpos * xfac + xoffset + .5;
1283: y = vpos * yfac + yoffset + .5;
1284:
1285: /* force 32x32 alignment, imagen 3.2 software does this
1286: ** anyway, but this should fix others
1287: */
1288: putc(ASETAV, tf); putint(y&~0x1f, tf);
1289: putc(ASETAH, tf); putint(x&~0x1f, tf);
1290:
1291: if (str[0] == 'I') {
1292: fscanf(fp, "%d %s", &n, buf);
1293: iglyphpage(tf, buf, n, x&0x1f, y&0x1f);
1294: } else if (str[0] == 'B') {
1295: fscanf(fp, "%d %s", &n, buf);
1296: glyphpage(tf, buf, n, x&0x1f, y&0x1f);
1297: }
1298:
1299: /* position back where it belongs */
1300: putc(ASETAV, tf); putint(y, tf); lasty = y;
1301: putc(ASETAH, tf); putint(x, tf); lastx = x;
1302: break;
1303: }
1304:
1305: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
1306:
1307: lineno++;
1308:
1309: } /* End of devcntrl */
1310:
1311:
1312: /*****************************************************************************/
1313:
1314:
1315: fileinit()
1316:
1317:
1318: {
1319:
1320:
1321: int i, fin;
1322: char *filebase;
1323: char temp[100];
1324:
1325:
1326: /*
1327: *
1328: * Called from t_init(), which in turn is called from devcntrl(), whenever we get
1329: * an "x init" command. There are a few lines of code here that set things up for
1330: * emulating another device.
1331: *
1332: */
1333:
1334:
1335: sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname);
1336: if ( (fin = open(temp, 0)) < 0 )
1337: error(FATAL, "can't open tables for %s", temp);
1338:
1339: read(fin, &dev, sizeof(struct dev));
1340:
1341: nfonts = dev.nfonts;
1342:
1343: if ( strcmp(devname, realdev) != 0 ) { /* device emulation */
1344: close(fin);
1345: strcpy(devname, realdev);
1346: sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname);
1347: if ( (fin = open(temp, 0)) < 0 )
1348: error(FATAL, "can't open tables for %s", temp);
1349: read(fin, &dev, sizeof(struct dev));
1350: } /* End if */
1351:
1352: nsizes = dev.nsizes;
1353: nchtab = dev.nchtab;
1354:
1355: if ( (filebase = malloc(dev.filesize)) == NULL )
1356: error(FATAL, "no memory for description file");
1357:
1358: read(fin, filebase, dev.filesize); /* all at once */
1359:
1360: pstab = (short *) filebase;
1361: chtab = pstab + nsizes + 1;
1362: chname = (char *) (chtab + dev.nchtab);
1363:
1364: for ( i = 1; i <= nfonts; i++ ) {
1365: fontbase[i] = NULL;
1366: widthtab[i] = codetab[i] = fitab[i] = NULL;
1367: } /* End for */
1368:
1369: close(fin);
1370:
1371: } /* End of fileinit */
1372:
1373:
1374: /*****************************************************************************/
1375:
1376:
1377: fontprint(i)
1378:
1379:
1380: int i; /* font's index in fontbase[] */
1381:
1382:
1383: {
1384:
1385:
1386: int j, n;
1387: char *p;
1388:
1389:
1390: /*
1391: *
1392: * Just a debugging routine that dumps most of the important information about
1393: * the font that's mounted in position i.
1394: *
1395: */
1396:
1397:
1398: fprintf(tf, "font %d:\n", i);
1399:
1400: p = (char *) fontbase[i];
1401: n = fontbase[i]->nwfont & BMASK;
1402:
1403: fprintf(tf, "base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",
1404: p, n, fontbase[i]->specfont, fontbase[i]->namefont, widthtab[i], fitab[i]);
1405:
1406: fprintf(tf, "widths:\n");
1407: for ( j = 0; j <= n; j++ ) {
1408: fprintf(tf, " %2d", widthtab[i][j] & BMASK);
1409: if ( j % 20 == 19 ) putc('\n', tf);
1410: } /* End for */
1411:
1412: fprintf(tf, "\ncodetab:\n");
1413: for ( j = 0; j <= n; j++ ) {
1414: fprintf(tf, " %2d", codetab[i][j] & BMASK);
1415: if ( j % 20 == 19 ) putc('\n', tf);
1416: } /* End for */
1417:
1418: fprintf(tf, "\nfitab:\n");
1419: for ( j = 0; j <= dev.nchtab + 128-32; j++ ) {
1420: fprintf(tf, " %2d", fitab[i][j] & BMASK);
1421: if ( j % 20 == 19 ) putc('\n', tf);
1422: } /* End for */
1423:
1424: putc('\n', tf);
1425:
1426: } /* End of fontprint */
1427:
1428:
1429: /*****************************************************************************/
1430:
1431:
1432: loadfont(n, s, s1)
1433:
1434:
1435: int n;
1436: char *s, *s1;
1437:
1438:
1439: {
1440:
1441:
1442: char temp[80];
1443: int fin, nw;
1444:
1445:
1446: /*
1447: *
1448: * Called to to load font info for font *s on position n using the binary tables
1449: * located in directory *s1 (if it's not NULL or the empty string).
1450: *
1451: */
1452:
1453:
1454: if ( n < 0 || n > NFONT ) /* make sure it's a legal position */
1455: error(FATAL, "illegal fp command %d %s", n, s);
1456:
1457: /*
1458: *
1459: * If the font's already loaded on position n there's nothing to do.
1460: *
1461: */
1462:
1463: if ( fontbase[n] != NULL && strcmp(s, fontbase[n]->namefont) == 0 )
1464: return;
1465:
1466: /*
1467: *
1468: * If *s1 isn't NULL or the NULL string that's what we'll use for the font
1469: * directory, otherwise use *fontdir.
1470: *
1471: */
1472:
1473: if ( s1 == NULL || s1[0] == '\0' )
1474: sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, s);
1475: else sprintf(temp, "%s/%s.out", s1, s);
1476:
1477: if ( (fin = open(temp, 0)) < 0 ) {
1478: sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, mapfont(s));
1479: if ( (fin = open(temp, 0)) < 0 )
1480: error(FATAL, "can't open font table %s", temp);
1481: } /* End if */
1482:
1483: if ( fontbase[n] != NULL ) /* something's already there */
1484: free(fontbase[n]); /* so release the memory first */
1485:
1486: fontbase[n] = (struct Font *) malloc(3*255 + dev.nchtab + (128-32) + sizeof(struct Font));
1487: if ( fontbase[n] == NULL )
1488: error(FATAL, "Out of space in loadfont %s", s);
1489:
1490: read(fin, fontbase[n], 3*255 + nchtab+128-32 + sizeof(struct Font));
1491: close(fin);
1492:
1493: if ( smnt == 0 && fontbase[n]->specfont == 1 )
1494: smnt = n;
1495:
1496: nw = fontbase[n]->nwfont & BMASK;
1497: widthtab[n] = (char *) fontbase[n] + sizeof(struct Font);
1498: codetab[n] = (char *) widthtab[n] + 2 * nw;
1499: fitab[n] = (char *) widthtab[n] + 3 * nw;
1500:
1501: t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
1502:
1503: if ( debug == ON )
1504: fontprint(n);
1505:
1506: } /* End of loadfont */
1507:
1508:
1509: /*****************************************************************************/
1510:
1511:
1512: char *mapfont(name)
1513:
1514:
1515: char *name; /* name of the font troff wants */
1516:
1517:
1518: {
1519:
1520:
1521: int i; /* loop index for fontmap[] */
1522:
1523:
1524: /*
1525: *
1526: * Only called from loadfont() when we haven't been able to open the font file
1527: * that troff asked for. We take the font name and map it into an appropriate
1528: * substitute. If the initial lookup fails we do a simple mapping that should
1529: * be good enough most of the time.
1530: *
1531: * This stuff should only be needed when we're emulating another printer like
1532: * the APS-5.
1533: *
1534: */
1535:
1536:
1537: for ( i = 0; fontmap[i].name != NULL; i++ )
1538: if ( strcmp(name, fontmap[i].name) == 0 )
1539: return(fontmap[i].use);
1540:
1541: switch ( *++name ) {
1542: case 'I':
1543: case 'B':
1544: return(name);
1545:
1546: case 'X':
1547: return("BI");
1548:
1549: default:
1550: return("R");
1551: } /* End switch */
1552:
1553: } /* End of mapfont */
1554:
1555:
1556: /*****************************************************************************/
1557:
1558:
1559: convint(c)
1560:
1561:
1562: unsigned char c;
1563:
1564:
1565: {
1566:
1567:
1568: /*
1569: *
1570: * Converts a character to a proper 2's complement integer. Really just used
1571: * on 3b's when we're reading raster tables in the old format. There's
1572: * really no need to make this a separate routine - at least I don't
1573: * think there is. Should just redefine CONVINT() macro so it does this
1574: * stuff.
1575: *
1576: */
1577:
1578:
1579: return((c & 0200) ? ((256 - c) * -1) : c);
1580:
1581: } /* End of convint */
1582:
1583:
1584: /*****************************************************************************/
1585:
1586:
1587: t_init(reinit)
1588:
1589:
1590: int reinit;
1591:
1592:
1593: {
1594:
1595:
1596: int i;
1597: FILE *tmpfile();
1598:
1599:
1600: /*
1601: *
1602: * Called to initialize the printer and associated variables. reinit will
1603: * be zero when the "x init" command was found in the output file, while
1604: * it will be non-zero when the routine is called to set things up for a
1605: * new page.
1606: *
1607: */
1608:
1609:
1610: if (! reinit) {
1611: for (i = 0; i < nchtab; i++)
1612: if (strcmp(&chname[chtab[i]], "l.") == 0)
1613: break;
1614: if (i < nchtab) {
1615: drawdot = i + 128;
1616: drawsize = 1;
1617: } else {
1618: drawdot = '.';
1619: drawsize = 2; /* half size */
1620: }
1621:
1622: xfac = (float) pres / res * aspect;
1623: yfac = (float) pres / res;
1624:
1625: putc(ASETPEN, tf);
1626: putc(penwidth, tf);
1627:
1628: if ( mode == LANDSCAPE ) {
1629: putc(ASETHV, tf);
1630: putc(0107, tf);
1631: angle = ROT_270;
1632: } /* End if */
1633: }
1634:
1635: hpos = vpos = 0;
1636: setsize(t_size(10)); /* start somewhere */
1637:
1638: } /* End of t_init */
1639:
1640:
1641: /*****************************************************************************/
1642:
1643:
1644: t_page(pg)
1645:
1646:
1647: {
1648:
1649:
1650: register int i, j, n;
1651: register unsigned char *p;
1652:
1653:
1654: /*
1655: *
1656: * Get the printer and everything else ready for a new page. If the -o
1657: * option has been used only selected pages will be printed. If output
1658: * is ON when this routine is called we'll write the endpage Impress
1659: * command to the output file. If we're supposed to be doing output for
1660: * page pg we'll write the APAGE command out, and that will cause the
1661: * horizontal and vertical positions (in Impress) to be set to zero. hpos
1662: * and vpos are initialized in routine t_init(), although I really don't
1663: * see any reason why we couldn't just skip the call and do it here.
1664: *
1665: */
1666:
1667:
1668: if ( debug == ON )
1669: fprintf(stderr, "t_page %d, output=%d\n", pg, output);
1670:
1671: pageno = pg;
1672:
1673: if ( output == ON ) /* doing output for last page */
1674: putc(AENDP, tf);
1675:
1676: if ( (output = in_olist(pg)) == ON ) { /* print this page */
1677: putc(APAGE, tf);
1678: acctpages++;
1679: }
1680:
1681: lastx = lasty = -1;
1682: t_init(1); /* setup for this page */
1683:
1684: } /* End of t_page */
1685:
1686:
1687: /*****************************************************************************/
1688:
1689:
1690: t_newline()
1691:
1692:
1693: {
1694:
1695:
1696: /*
1697: *
1698: * Read an "n a b" command in the input file and are ready to start a new
1699: * line. There really isn't much else this routine can do besides set the
1700: * horizontal position to zero. Anyway troff takes care of any needed
1701: * positioning before it starts printing text.
1702: *
1703: */
1704:
1705:
1706: hpos = 0;
1707:
1708: } /* End of t_newline */
1709:
1710:
1711: /*****************************************************************************/
1712:
1713:
1714: t_size(n)
1715:
1716:
1717: int n; /* convert this point size */
1718:
1719:
1720: {
1721:
1722:
1723: int i;
1724:
1725:
1726: /*
1727: *
1728: * Converts a point size into an internal size that can be used as an
1729: * index into the pstab[] array. Actually the internal size is defined as
1730: * one plus the index of the least upper bound of n in pstab[] or nsizes
1731: * if n is larger than all the listed sizes.
1732: *
1733: */
1734:
1735: if (n <= pstab[0])
1736: return(1);
1737: else if (n >= pstab[nsizes-1])
1738: return(nsizes);
1739: for (i = 0; n > pstab[i]; i++) ;
1740:
1741: return(i+1);
1742:
1743: } /* End of t_size */
1744:
1745:
1746: /*****************************************************************************/
1747:
1748:
1749: t_charht(n)
1750:
1751:
1752: int n; /* use this as the character height */
1753:
1754:
1755: {
1756:
1757:
1758: /*
1759: *
1760: * Although it can be done on some typesetters, like the APS-5, it's ignored
1761: * on Imagen's bitmap printers like the Imprint-10 and the 8/300. It would
1762: * be absurd to keep any extra raster files around just so we could implement
1763: * this command, and right now there's no Impress command to do it to
1764: * downloaded glyphs.
1765: *
1766: */
1767:
1768:
1769: } /* End of t_charht */
1770:
1771:
1772: /*****************************************************************************/
1773:
1774:
1775: t_slant(n)
1776:
1777:
1778: int n; /* slant characters this many degrees */
1779:
1780:
1781: {
1782:
1783:
1784: /*
1785: *
1786: * As with troff's height command, there's no simple way to slant characters
1787: * on Imagen's bitmap printers and it's really not worth any effort to try
1788: * and make it work.
1789: *
1790: */
1791:
1792:
1793: } /* End of t_slant */
1794:
1795:
1796: /*****************************************************************************/
1797:
1798:
1799: t_font(s)
1800:
1801:
1802: char *s;
1803:
1804:
1805: {
1806:
1807:
1808: int n;
1809:
1810:
1811: /*
1812: *
1813: * Just converts the string *s into an integer and checks to make sure the
1814: * number is a legal font position. If it's not we'll print an error message
1815: * and then quit. di10 handled bad requests a little differently. Instead
1816: * of treating mistakes as FATAL errors it would return 1 as the font
1817: * number.
1818: *
1819: */
1820:
1821:
1822: if ( (n = atoi(s)) < 0 || n > nfonts )
1823: error(FATAL, "illegal font position %d", n);
1824:
1825: return(n);
1826:
1827: } /* End of t_font */
1828:
1829:
1830: /*****************************************************************************/
1831:
1832:
1833: t_reset(c)
1834:
1835:
1836: int c; /* pause or restart */
1837:
1838:
1839: {
1840:
1841:
1842: /*
1843: *
1844: * Called from devcntrl() when we've found an "x stop" or "x pause" command.
1845: * There's really nothing we need to do for Imagen's bitmap printers, and
1846: * leaving the final cleanup (ie. AEOF code etc.) to someone else means
1847: * we should be able to cat a bunch of troff output files together and
1848: * have them all printed properly.
1849: *
1850: */
1851:
1852:
1853: } /* End of t_reset */
1854:
1855:
1856: /*****************************************************************************/
1857:
1858:
1859: t_wrapup()
1860:
1861:
1862: {
1863:
1864:
1865: /*
1866: *
1867: * We're finished with all the input files and all that's left to do is
1868: * end the last page we were working on and then mark the end of the Impress
1869: * file.
1870: *
1871: */
1872:
1873:
1874: putc(AENDP, tf);
1875: putc(AEOF, tf);
1876:
1877: } /* End of t_wrapup */
1878:
1879:
1880: /*****************************************************************************/
1881:
1882:
1883: t_trailer()
1884:
1885:
1886: {
1887:
1888:
1889: /*
1890: *
1891: * Called from devcntrl() when an "x trailer" command is found. There's
1892: * nothing we need to do here for Imagen's printers.
1893: *
1894: */
1895:
1896:
1897:
1898: } /* End of t_trailer */
1899:
1900:
1901: /*****************************************************************************/
1902:
1903:
1904: hgoto(n)
1905:
1906:
1907: int n; /* where we want to be */
1908:
1909:
1910: {
1911:
1912:
1913: /*
1914: *
1915: * Want to be at this absolute horizontal position next - usually will
1916: * get these motion commands right before printing a character.
1917: *
1918: */
1919:
1920:
1921: hpos = n;
1922:
1923: } /* End of hgoto */
1924:
1925:
1926: /*****************************************************************************/
1927:
1928:
1929: hmot(n)
1930:
1931:
1932: int n; /* move this far from where we are */
1933:
1934:
1935: {
1936:
1937:
1938: /*
1939: *
1940: * Handles relative horizontal motion. troff's current positon as recorded
1941: * in hpos is changed by n units.
1942: *
1943: */
1944:
1945:
1946: hpos += n;
1947:
1948: } /* End of hmot */
1949:
1950:
1951: /*****************************************************************************/
1952:
1953:
1954: vgoto(n)
1955:
1956:
1957: int n; /* new vertical position */
1958:
1959:
1960: {
1961:
1962:
1963: /*
1964: *
1965: * Moves vertically in troff's coordinate system to absolute position n.
1966: *
1967: */
1968:
1969:
1970: vpos = n;
1971:
1972: } /* End of vgoto */
1973:
1974:
1975: /*****************************************************************************/
1976:
1977:
1978: vmot(n)
1979:
1980:
1981: int n; /* move this far vertically */
1982:
1983:
1984: {
1985:
1986:
1987: /*
1988: *
1989: * Handles relative vertical motion of n units in troff's coordinate system.
1990: *
1991: */
1992:
1993:
1994: vpos += n;
1995:
1996: } /* End of vmot */
1997:
1998:
1999: /*****************************************************************************/
2000:
2001:
2002: put1s(s)
2003:
2004:
2005: register char *s;
2006:
2007:
2008: {
2009:
2010:
2011: static int i = 0; /* last one we found - usually */
2012:
2013:
2014: /*
2015: *
2016: * Does whatever is necessary to have special character *s printed. If we're
2017: * doing output on this page we'll look the character up using chname[] and
2018: * chtab[]. The first array contains all the special character names
2019: * separated by '\0' that are mentioned in the typesetter's DESC file, while
2020: * chname[i] points to the start of character i in chname[]. Both arrays
2021: * come from the DESC.out file for printer *devname which is found in
2022: * *fontdir (wherever that might be).
2023: *
2024: */
2025:
2026:
2027: if ( output == OFF )
2028: return;
2029:
2030: if ( debug )
2031: printf("%s", s);
2032:
2033: if (strcmp(s, &chname[chtab[i]]) != 0)
2034: for (i = 0; i < nchtab; i++)
2035: if (strcmp(&chname[chtab[i]], s) == 0)
2036: break;
2037: if (i < nchtab)
2038: put1(i + 128);
2039: else
2040: i = 0;
2041:
2042: } /* End of put1s */
2043:
2044:
2045: /*****************************************************************************/
2046:
2047:
2048: put1(c)
2049:
2050:
2051: register int c; /* print this character */
2052:
2053:
2054: {
2055:
2056:
2057: char *pw;
2058: register char *p;
2059: register int i, j, k;
2060: int ofont, code;
2061:
2062:
2063: /*
2064: *
2065: * Arranges to have character c printed. If c < 128 it's a simple ASCII character,
2066: * otherwise it's a special character. We subtract 32 from c because non-graphic
2067: * ASCII characters aren't included in the tables.
2068: *
2069: */
2070:
2071:
2072: lastc = c; /* charlib() may need the real name */
2073: c -= 32;
2074:
2075: if ( c <= 0 ) {
2076: if ( debug == ON )
2077: fprintf(tf, "non-exist 0%o\n", lastc);
2078: return;
2079: } /* End if */
2080:
2081: k = ofont = font;
2082: i = fitab[font][c] & BMASK;
2083:
2084: if ( i != 0 ) { /* it's on this font */
2085: p = codetab[font];
2086: pw = widthtab[font];
2087: } else if ( smnt > 0 ) { /* on special (we hope) */
2088: for ( k=smnt, j=0; j <= nfonts; j++, k = (k+1) % (nfonts+1) ) {
2089: if ( k == 0 ) continue;
2090: if ( (i = fitab[k][c] & BMASK) != 0 ) {
2091: p = codetab[k];
2092: pw = widthtab[k];
2093: setfont(k);
2094: break;
2095: } /* End if */
2096: } /* End for */
2097: } /* End else */
2098:
2099: if ( i == 0 || (code = p[i] & BMASK) == 0 || k > nfonts ) {
2100: if ( debug == ON )
2101: fprintf(tf, "not found 0%o\n", lastc);
2102: if ( font != ofont ) setfont(ofont);
2103: return;
2104: } /* End if */
2105:
2106: lastw = ((pw[i] & BMASK) * pstab[size-1] + dev.unitwidth/2) / dev.unitwidth;
2107:
2108: if ( debug == ON ) {
2109: if ( isprint(lastc) )
2110: fprintf(tf, "%c %d\n", lastc, code);
2111: else fprintf(tf, "%03o %d\n", lastc, code);
2112: } else oput(code);
2113:
2114: if ( font != ofont )
2115: setfont(ofont);
2116:
2117: } /* End of put1 */
2118:
2119:
2120: /*****************************************************************************/
2121:
2122:
2123: setsize(n)
2124:
2125:
2126: int n; /* new internal size */
2127:
2128:
2129: {
2130:
2131:
2132: /*
2133: *
2134: * We want to use internal size n for now, where n is an index into *pstab
2135: * where we can find the closest available approximation to the requested
2136: * point size.
2137: *
2138: */
2139:
2140:
2141: size = n;
2142:
2143: } /* End of setsize */
2144:
2145:
2146: /*****************************************************************************/
2147:
2148:
2149: t_fp(n, s, si)
2150:
2151:
2152: int n; /* font position to update */
2153: char *s; /* it now contains this font */
2154: char *si; /* and this is its internal number */
2155:
2156:
2157: {
2158:
2159:
2160: /*
2161: *
2162: * Called when we've loaded font *s in position n. The font position info
2163: * is recorded in fontname[].
2164: *
2165: */
2166:
2167:
2168: fontname[n].name = s;
2169: fontname[n].number = atoi(si);
2170: if ( n == lastfont ) lastfont = -1; /* force getfontdata() call */
2171:
2172: } /* End of t_fp */
2173:
2174:
2175: /*****************************************************************************/
2176:
2177:
2178: setfont(n)
2179:
2180:
2181: int n; /* this will be the current font */
2182:
2183:
2184: {
2185:
2186:
2187: /*
2188: *
2189: * Job now wants to use the font loaded in position n. The variable font
2190: * keeps track of which one we're currently using. If the requested positon
2191: * is out of range we'll just quit.
2192: *
2193: */
2194:
2195:
2196: if ( output == OFF )
2197: return;
2198:
2199: if (n < 0 || n > NFONT)
2200: error(FATAL, "illegal font %d", n);
2201:
2202: font = n;
2203:
2204: } /* End of setfont */
2205:
2206:
2207: /*****************************************************************************/
2208:
2209:
2210: oput(c)
2211:
2212:
2213: int c; /* want to print this character */
2214:
2215:
2216: {
2217:
2218:
2219: int x, y; /* current scaled position */
2220: int member; /* glyph number for c in current family */
2221:
2222:
2223: /*
2224: *
2225: * Arranges to print the character whose code is c in the current font.
2226: * The old and new raster file formats are supported.
2227: *
2228: */
2229:
2230:
2231: if ( output == OFF )
2232: return;
2233:
2234: if ( rastformat == OLD_FORMAT ) {
2235: xychar(c, fontname[font].name, pstab[size-1], lastw, tf);
2236: return;
2237: } /* End if */
2238:
2239: if ( font != lastfont || size != lastsize ) {
2240: if ( isresident(fontname[font].name) == FALSE )
2241: getrastdata(fontname[font].name, mapsize(fontname[font].name, pstab[size-1]));
2242: else getresdata(fontname[font].name, mapsize(fontname[font].name, pstab[size-1]), tf);
2243: lastfont = font;
2244: lastsize = size;
2245: } /* End if */
2246:
2247: member = download(c, lastw, angle, tf);
2248:
2249: x = hpos * xfac + xoffset + .5;
2250: y = vpos * yfac + yoffset + .5;
2251:
2252: if ( y != lasty ) {
2253: putc(ASETAV, tf);
2254: putint(y, tf);
2255: lasty = y;
2256: } /* End if */
2257:
2258: if ( ABS(x - lastx) > SLOP ) {
2259: putc(ASETAH, tf);
2260: putint(x, tf);
2261: lastx = x + fam->advance[member];
2262: } else lastx += fam->advance[member];
2263:
2264: putc(member, tf);
2265:
2266: } /* End of oput */
2267:
2268:
2269: /*****************************************************************************/
2270:
2271:
2272: mapsize(name, ps)
2273:
2274:
2275: char *name; /* name of the font */
2276: int ps; /* point size troff wants to use */
2277:
2278:
2279: {
2280:
2281:
2282: int i, j;
2283:
2284:
2285: /*
2286: *
2287: * Uses the data that's been filled in from RASTLIST to map point size
2288: * ps font font *name into the best size available in our raster tables.
2289: * If no RASTLIST file was used rastsize will be zero and we'll just
2290: * assume that any size that's aske for is available.
2291: *
2292: */
2293:
2294:
2295: if ( maxrast == 0 ) /* don't have any size data */
2296: return(ps);
2297:
2298: for ( i = 0; i < maxrast; i++ )
2299: if ( strcmp(name, sizedata[i].name) == 0 )
2300: break;
2301:
2302: if ( i >= maxrast ) /* didn't find the font */
2303: error(FATAL, "missing raster list data for font %s", name);
2304:
2305: for ( j = 1, ps = (ps * pres) / rres; ps >= sizedata[i].sizes[j]; j++ ) ;
2306:
2307: return(sizedata[i].sizes[--j]);
2308:
2309: } /* End of mapsize */
2310:
2311:
2312: /*****************************************************************************/
2313:
2314:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.