|
|
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: /* name should be no more than L_FNAME characters */
817: while ( fscanf(fp, "%10s", sizedata[maxrast].name) != EOF ) {
818: i = 0;
819: while ( fscanf(fp, "%d", &n) != EOF && n < 100 )
820: sizedata[maxrast].sizes[i++] = n;
821: sizedata[maxrast].sizes[i] = 999;
822: if ( ++maxrast >= MAXFONTS )
823: error(FATAL, "too many fonts in %s", name);
824: } /* End while */
825:
826: fclose(fp);
827:
828: } /* End of rastlist */
829:
830:
831: /*****************************************************************************/
832:
833:
834: arguments()
835:
836:
837: {
838:
839:
840: FILE *fp; /* next input file */
841:
842:
843: /*
844: *
845: * All the rest of the command line options are input files we want to
846: * translate. If we get here and there are no more arguments, or if '-' is
847: * in the list of file names, we'll process stdin.
848: *
849: */
850:
851:
852: if (argc < 1)
853: conv(stdin);
854: else
855: while (argc > 0) {
856: if (strcmp(*argv, "-") == 0)
857: fp = stdin;
858: else if ((fp = fopen(*argv, "r")) == NULL)
859: error(FATAL, "can't open %s", *argv);
860: conv(fp);
861: fclose(fp);
862: argc--;
863: argv++;
864: }
865:
866: } /* End of arguments */
867:
868:
869: /*****************************************************************************/
870:
871:
872: print_file()
873:
874:
875: {
876:
877:
878: char buf[BUFSIZ]; /* IPR command line built up here */
879:
880:
881: /*
882: *
883: * Finished with all the input files and everything the printer needs to
884: * know is in FILE *tf. We'll close the file because we're all done with
885: * it, and then call IPR if we haven't been writing to stdout.
886: *
887: */
888:
889:
890: fclose(tf); /* everything's in the file */
891:
892: if ( tf != stdout || debug ) {
893: sprintf(buf, "%s -Limpress -r -o '-Downer \"'\"%s\"'\"'\", jobheader on, pagecollation on, pagereversal on\" %s 0</dev/null 1>/dev/null 2>&1 &",
894: IPR, username, tempfile);
895: if ( debug )
896: fprintf(stderr, "executing %s\n", buf);
897: else system(buf);
898: } /* End if */
899:
900: } /* End of print_file */
901:
902:
903: /*****************************************************************************/
904:
905:
906: acct_file()
907:
908:
909: {
910:
911:
912: /*
913: *
914: * If we want to do accounting *acctfile will be the name of the file where
915: * we put the accounting data. If for some reason we can't open the file
916: * we'll just quit. I've called the routine from main() before anything is
917: * written to the output file.
918: *
919: */
920:
921:
922: if ( acctfile != NULL && *acctfile != '\0' ) {
923: if ( (fp_acct = fopen(acctfile, "a")) == NULL ) {
924: fp_acct = stderr;
925: x_stat |= NO_ACCTFILE;
926: error(FATAL, "can't open accounting file");
927: exit(x_stat);
928: }
929: if ( tf != stdout )
930: x_stat |= DO_ACCT;
931: }
932:
933: } /* End of acct_file */
934:
935:
936: /*****************************************************************************/
937:
938:
939: account()
940:
941:
942: {
943:
944:
945: FILE *f; /* just the job's page count */
946:
947:
948: /*
949: *
950: * Writes an accounting record, usually to *fp_acct, for the current job.
951: * All this stuff is set up for our MHCC printers. In some cases we'll
952: * know most everything about the job (called with -J option) and all
953: * we'll do is write a page count to *jacctfile. In other cases we'll want
954: * a more complete record and all the stuff will go to *fp_acct. You'll
955: * undoubtedly want to change this stuff to suit your own needs.
956: *
957: */
958:
959: if ( x_stat & DO_ACCT ) {
960: if ( jacctfile == NULL || *jacctfile == '\0' ) {
961: fprintf(fp_acct, " user = %-10s", username);
962: fprintf(fp_acct, " paper = %-10d", acctpages * copies);
963: x_stat &= ~DO_ACCT;
964: fprintf(fp_acct, " exit_status = 0%-6o", x_stat);
965: fprintf(fp_acct, " type = t ");
966: if ( tf == stdout )
967: fprintf(fp_acct, " ??");
968: fprintf(fp_acct, "\n");
969: } else {
970: if ( (f = fopen(jacctfile, "a")) != NULL ) {
971: fprintf(f, "%d\n", acctpages);
972: fclose(f);
973: }
974: x_stat &= ~DO_ACCT;
975: } /* End else */
976: }
977:
978: } /* End of account */
979:
980:
981: /*****************************************************************************/
982:
983:
984: done()
985:
986:
987: {
988:
989:
990: /*
991: *
992: * Finished with everything so we want to make sure accounting is handled
993: * properly and the right exit status is returned to the caller. We'll also
994: * delete the temporary file if x_stat != 0.
995: *
996: */
997:
998:
999: account();
1000:
1001: if ( tf != stdout && x_stat != 0 )
1002: unlink(tempfile);
1003:
1004: exit(x_stat);
1005:
1006: } /* End of done */
1007:
1008:
1009: /*****************************************************************************/
1010:
1011:
1012: conv(fp)
1013:
1014:
1015: register FILE *fp;
1016:
1017:
1018: {
1019:
1020:
1021: register int c, k;
1022: int m, n, i, n1, m1;
1023: char str[100];
1024:
1025:
1026: /*
1027: *
1028: * Controls the translation of troff's device independent output language
1029: * to Impress. Some of the commands, like slant and height, are no-ops
1030: * on Imagen's bitmap printers even though routines are called to do the
1031: * processing.
1032: *
1033: */
1034:
1035:
1036: lineno = 1; /* line in current file */
1037: x_stat |= FILE_STARTED; /* we'll clear it when done with *fp */
1038:
1039: while ((c = getc(fp)) != EOF) {
1040:
1041: switch (c) {
1042:
1043: case '\n': /* just count this line */
1044: lineno++;
1045: break;
1046:
1047: case ' ': /* when input is text */
1048: case 0: /* occasional noise creeps in */
1049: break;
1050:
1051: case '0': case '1': case '2': case '3': case '4':
1052: case '5': case '6': case '7': case '8': case '9':
1053: /* two motion digits plus a character */
1054: hmot((c-'0')*10 + getc(fp)-'0');
1055: put1(getc(fp));
1056: break;
1057:
1058: case 'c': /* single ascii character */
1059: put1(getc(fp));
1060: break;
1061:
1062: case 'C': /* special character */
1063: fscanf(fp, "%s", str);
1064: put1s(str);
1065: break;
1066:
1067: case 'N': /* character at position n */
1068: fscanf(fp, "%d", &m);
1069: oput(m);
1070: break;
1071:
1072: case 'D': /* drawing function */
1073: lineno++;
1074: switch ((c=getc(fp))) {
1075: case 'p': /* draw a path */
1076: while (fscanf(fp, "%d %d", &n, &m) == 2)
1077: drawline(n, m);
1078: break;
1079:
1080: case 'l': /* draw a line */
1081: fscanf(fp, "%d %d %c", &n, &m, &n1);
1082: drawline(n, m);
1083: break;
1084:
1085: case 'c': /* circle */
1086: fscanf(fp, "%d", &n);
1087: drawcirc(n);
1088: break;
1089:
1090: case 'e': /* ellipse */
1091: fscanf(fp, "%d %d", &m, &n);
1092: drawellip(m, n);
1093: break;
1094:
1095: case 'a': /* arc */
1096: fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1);
1097: drawarc(n, m, n1, m1);
1098: break;
1099:
1100: case 'q': /* spline */
1101: drawspline(fp, 1);
1102: break;
1103:
1104: case '~': /* wiggly line */
1105: drawspline(fp, 2);
1106: break;
1107:
1108: default:
1109: error(FATAL, "unknown drawing function %c", c);
1110: break;
1111: }
1112: break;
1113:
1114: case 's': /* use this point size */
1115: fscanf(fp, "%d", &n); /* ignore fractional sizes */
1116: setsize(t_size(n));
1117: break;
1118:
1119: case 'f': /* use font mounted here */
1120: fscanf(fp, "%s", str);
1121: setfont(t_font(str));
1122: break;
1123:
1124: case 'H': /* absolute horizontal motion */
1125: /*
1126: *
1127: * The simple scan I've commented out didn't handle negative numbers right
1128: * and believe it or not we did get jobs that asked for negative absolute
1129: * positions. Even though negative absolute coordinates probably are a
1130: * mistake it makes more sense to handle the numbers properly.
1131: *
1132: while ((c = getc(fp)) == ' ')
1133: ;
1134: k = 0;
1135: do {
1136: k = 10 * k + c - '0';
1137: } while (isdigit(c = getc(fp)));
1138: ungetc(c, fp);
1139: hgoto(k);
1140: *
1141: */
1142: fscanf(fp, "%d", &n);
1143: hgoto(n);
1144: break;
1145:
1146: case 'h': /* relative horizontal motion */
1147: /*
1148: *
1149: * Again the same potential problem with negative numbers exists here. In
1150: * fact it makes a lot more sense to expect negative relative motions even
1151: * though I never did see them. Anyway just to be safe I've made the same
1152: * change - take it out if you want.
1153: *
1154: while ((c = getc(fp)) == ' ')
1155: ;
1156: k = 0;
1157: do {
1158: k = 10 * k + c - '0';
1159: } while (isdigit(c = getc(fp)));
1160: ungetc(c, fp);
1161: hmot(k);
1162: *
1163: */
1164: fscanf(fp, "%d", &n);
1165: hmot(n);
1166: break;
1167:
1168: case 'w': /* word space */
1169: break;
1170:
1171: case 'V': /* absolute vertical position */
1172: fscanf(fp, "%d", &n);
1173: vgoto(n);
1174: break;
1175:
1176: case 'v': /* relative vertical motion */
1177: fscanf(fp, "%d", &n);
1178: vmot(n);
1179: break;
1180:
1181: case 'p': /* new page */
1182: fscanf(fp, "%d", &n);
1183: t_page(n);
1184: break;
1185:
1186: case 'n': /* end of line */
1187: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
1188: t_newline();
1189: lineno++;
1190: break;
1191:
1192: case '#': /* comment */
1193: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
1194: lineno++;
1195: break;
1196:
1197: case 'x': /* device control function */
1198: devcntrl(fp);
1199: break;
1200:
1201: default:
1202: error(!FATAL, "unknown input character %o %c", c, c);
1203: done();
1204: }
1205: }
1206:
1207: x_stat &= ~FILE_STARTED;
1208:
1209: } /* End of conv */
1210:
1211:
1212: /*****************************************************************************/
1213:
1214:
1215: devcntrl(fp)
1216:
1217:
1218: FILE *fp; /* current input file */
1219:
1220:
1221: {
1222:
1223:
1224: char str[20], str1[50], buf[50];
1225: int c, n, x, y;
1226:
1227:
1228: /*
1229: *
1230: * Called from conv() to process the rest of a device control function.
1231: * There's a whole family of them and they all begin with the string
1232: * "x ". The rest of the command consists of the function name followed
1233: * by zero or more arguments that depend on the particular command. We've
1234: * already read the "x" from the input file, that's why the routine was
1235: * called. The whole rest of the input line is assumed to be part of the
1236: * device control command.
1237: *
1238: */
1239:
1240:
1241: fscanf(fp, "%s", str); /* get the control function name */
1242:
1243: switch ( str[0] ) { /* only the first character counts now */
1244: case 'i': /* initialize */
1245: fileinit();
1246: t_init(0);
1247: break;
1248:
1249: case 'T': /* device name */
1250: fscanf(fp, "%s", devname);
1251: break;
1252:
1253: case 't': /* trailer */
1254: t_trailer();
1255: break;
1256:
1257: case 'p': /* pause -- can restart */
1258: t_reset('p');
1259: break;
1260:
1261: case 's': /* stop */
1262: t_reset('s');
1263: break;
1264:
1265: case 'r': /* resolution assumed when prepared */
1266: fscanf(fp, "%d", &res);
1267: break;
1268:
1269: case 'f': /* load font in a position */
1270: fscanf(fp, "%d %s", &n, str);
1271: fgets(buf, sizeof buf, fp); /* in case there's a filename */
1272: ungetc('\n', fp); /* fgets goes too far */
1273: str1[0] = 0; /* in case there's nothing to come in */
1274: sscanf(buf, "%s", str1);
1275: loadfont(n, str, str1);
1276: break;
1277:
1278: /* these don't belong here... */
1279: case 'H': /* char height */
1280: fscanf(fp, "%d", &n);
1281: t_charht(n);
1282: break;
1283:
1284: case 'S': /* slant */
1285: fscanf(fp, "%d", &n);
1286: t_slant(n);
1287: break;
1288:
1289: case 'I':
1290: case 'B':
1291: x = hpos * xfac + xoffset + .5;
1292: y = vpos * yfac + yoffset + .5;
1293:
1294: /* force 32x32 alignment, imagen 3.2 software does this
1295: ** anyway, but this should fix others
1296: */
1297: putc(ASETAV, tf); putint(y&~0x1f, tf);
1298: putc(ASETAH, tf); putint(x&~0x1f, tf);
1299:
1300: if (str[0] == 'I') {
1301: fscanf(fp, "%d %s", &n, buf);
1302: iglyphpage(tf, buf, n, x&0x1f, y&0x1f);
1303: } else if (str[0] == 'B') {
1304: fscanf(fp, "%d %s", &n, buf);
1305: glyphpage(tf, buf, n, x&0x1f, y&0x1f);
1306: }
1307:
1308: /* position back where it belongs */
1309: putc(ASETAV, tf); putint(y, tf); lasty = y;
1310: putc(ASETAH, tf); putint(x, tf); lastx = x;
1311: break;
1312:
1313: case 'X':
1314: fscanf(fp, "%s", str); /* line style */
1315: break;
1316: }
1317:
1318: while ( (c = getc(fp)) != '\n' && c != EOF ) ;
1319:
1320: lineno++;
1321:
1322: } /* End of devcntrl */
1323:
1324:
1325: /*****************************************************************************/
1326:
1327:
1328: fileinit()
1329:
1330:
1331: {
1332:
1333:
1334: int i, fin;
1335: char *filebase;
1336: char temp[100];
1337:
1338:
1339: /*
1340: *
1341: * Called from t_init(), which in turn is called from devcntrl(), whenever we get
1342: * an "x init" command. There are a few lines of code here that set things up for
1343: * emulating another device.
1344: *
1345: */
1346:
1347:
1348: sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname);
1349: if ( (fin = open(temp, 0)) < 0 )
1350: error(FATAL, "can't open tables for %s", temp);
1351:
1352: read(fin, &dev, sizeof(struct dev));
1353:
1354: nfonts = dev.nfonts;
1355:
1356: if ( strcmp(devname, realdev) != 0 ) { /* device emulation */
1357: close(fin);
1358: strcpy(devname, realdev);
1359: sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname);
1360: if ( (fin = open(temp, 0)) < 0 )
1361: error(FATAL, "can't open tables for %s", temp);
1362: read(fin, &dev, sizeof(struct dev));
1363: } /* End if */
1364:
1365: nsizes = dev.nsizes;
1366: nchtab = dev.nchtab;
1367:
1368: if ( (filebase = malloc(dev.filesize)) == NULL )
1369: error(FATAL, "no memory for description file");
1370:
1371: read(fin, filebase, dev.filesize); /* all at once */
1372:
1373: pstab = (short *) filebase;
1374: chtab = pstab + nsizes + 1;
1375: chname = (char *) (chtab + dev.nchtab);
1376:
1377: for ( i = 1; i <= nfonts; i++ ) {
1378: fontbase[i] = NULL;
1379: widthtab[i] = codetab[i] = fitab[i] = NULL;
1380: } /* End for */
1381:
1382: close(fin);
1383:
1384: } /* End of fileinit */
1385:
1386:
1387: /*****************************************************************************/
1388:
1389:
1390: fontprint(i)
1391:
1392:
1393: int i; /* font's index in fontbase[] */
1394:
1395:
1396: {
1397:
1398:
1399: int j, n;
1400: char *p;
1401:
1402:
1403: /*
1404: *
1405: * Just a debugging routine that dumps most of the important information about
1406: * the font that's mounted in position i.
1407: *
1408: */
1409:
1410:
1411: fprintf(tf, "font %d:\n", i);
1412:
1413: p = (char *) fontbase[i];
1414: n = fontbase[i]->nwfont & BMASK;
1415:
1416: /* name should be no more than L_FNAME characters long */
1417: fprintf(tf, "base=0%o, nchars=%d, spec=%d, name=%.10s, widtab=0%o, fitab=0%o\n",
1418: p, n, fontbase[i]->specfont, fontbase[i]->namefont, widthtab[i], fitab[i]);
1419:
1420: fprintf(tf, "widths:\n");
1421: for ( j = 0; j <= n; j++ ) {
1422: fprintf(tf, " %2d", widthtab[i][j] & BMASK);
1423: if ( j % 20 == 19 ) putc('\n', tf);
1424: } /* End for */
1425:
1426: fprintf(tf, "\ncodetab:\n");
1427: for ( j = 0; j <= n; j++ ) {
1428: fprintf(tf, " %2d", codetab[i][j] & BMASK);
1429: if ( j % 20 == 19 ) putc('\n', tf);
1430: } /* End for */
1431:
1432: fprintf(tf, "\nfitab:\n");
1433: for ( j = 0; j <= dev.nchtab + 128-32; j++ ) {
1434: fprintf(tf, " %2d", fitab[i][j] & BMASK);
1435: if ( j % 20 == 19 ) putc('\n', tf);
1436: } /* End for */
1437:
1438: putc('\n', tf);
1439:
1440: } /* End of fontprint */
1441:
1442:
1443: /*****************************************************************************/
1444:
1445:
1446: loadfont(n, s, s1)
1447:
1448:
1449: int n;
1450: char *s, *s1;
1451:
1452:
1453: {
1454:
1455:
1456: char temp[80];
1457: int fin, nw;
1458:
1459:
1460: /*
1461: *
1462: * Called to to load font info for font *s on position n using the binary tables
1463: * located in directory *s1 (if it's not NULL or the empty string).
1464: *
1465: */
1466:
1467:
1468: if ( n < 0 || n > NFONT ) /* make sure it's a legal position */
1469: error(FATAL, "illegal fp command %d %s", n, s);
1470:
1471: /*
1472: *
1473: * If the font's already loaded on position n there's nothing to do.
1474: *
1475: */
1476:
1477: if ( fontbase[n] != NULL && strncmp(s, fontbase[n]->namefont, L_FNAME) == 0 )
1478: return;
1479:
1480: /*
1481: *
1482: * If *s1 isn't NULL or the NULL string that's what we'll use for the font
1483: * directory, otherwise use *fontdir.
1484: *
1485: */
1486:
1487: if ( s1 == NULL || s1[0] == '\0' )
1488: sprintf(temp, "%s/dev%s/%.10s.out", fontdir, devname, s);
1489: else sprintf(temp, "%s/%.10s.out", s1, s);
1490:
1491: if ( (fin = open(temp, 0)) < 0 ) {
1492: sprintf(temp, "%s/dev%s/%.10s.out", fontdir, devname, mapfont(s));
1493: if ( (fin = open(temp, 0)) < 0 )
1494: error(FATAL, "can't open font table %s", temp);
1495: } /* End if */
1496:
1497: if ( fontbase[n] != NULL ) /* something's already there */
1498: free(fontbase[n]); /* so release the memory first */
1499:
1500: fontbase[n] = (struct Font *) malloc(3*255 + dev.nchtab + (128-32) + sizeof(struct Font));
1501: if ( fontbase[n] == NULL )
1502: error(FATAL, "Out of space in loadfont %s", s);
1503:
1504: read(fin, fontbase[n], 3*255 + nchtab+128-32 + sizeof(struct Font));
1505: close(fin);
1506:
1507: if ( smnt == 0 && fontbase[n]->specfont == 1 )
1508: smnt = n;
1509:
1510: nw = fontbase[n]->nwfont & BMASK;
1511: widthtab[n] = (char *) fontbase[n] + sizeof(struct Font);
1512: codetab[n] = (char *) widthtab[n] + 2 * nw;
1513: fitab[n] = (char *) widthtab[n] + 3 * nw;
1514:
1515: t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
1516:
1517: if ( debug == ON )
1518: fontprint(n);
1519:
1520: } /* End of loadfont */
1521:
1522:
1523: /*****************************************************************************/
1524:
1525:
1526: char *mapfont(name)
1527:
1528:
1529: char *name; /* name of the font troff wants */
1530:
1531:
1532: {
1533:
1534:
1535: int i; /* loop index for fontmap[] */
1536:
1537:
1538: /*
1539: *
1540: * Only called from loadfont() when we haven't been able to open the font file
1541: * that troff asked for. We take the font name and map it into an appropriate
1542: * substitute. If the initial lookup fails we do a simple mapping that should
1543: * be good enough most of the time.
1544: *
1545: * This stuff should only be needed when we're emulating another printer like
1546: * the APS-5.
1547: *
1548: */
1549:
1550:
1551: for ( i = 0; fontmap[i].name != NULL && i < L_FNAME; i++ )
1552: if ( strncmp(name, fontmap[i].name, L_FNAME) == 0 )
1553: return(fontmap[i].use);
1554:
1555: switch ( *++name ) {
1556: case 'I':
1557: case 'B':
1558: return(name);
1559:
1560: case 'X':
1561: return("BI");
1562:
1563: default:
1564: return("R");
1565: } /* End switch */
1566:
1567: } /* End of mapfont */
1568:
1569:
1570: /*****************************************************************************/
1571:
1572:
1573: convint(c)
1574:
1575:
1576: unsigned char c;
1577:
1578:
1579: {
1580:
1581:
1582: /*
1583: *
1584: * Converts a character to a proper 2's complement integer. Really just used
1585: * on 3b's when we're reading raster tables in the old format. There's
1586: * really no need to make this a separate routine - at least I don't
1587: * think there is. Should just redefine CONVINT() macro so it does this
1588: * stuff.
1589: *
1590: */
1591:
1592:
1593: return((c & 0200) ? ((256 - c) * -1) : c);
1594:
1595: } /* End of convint */
1596:
1597:
1598: /*****************************************************************************/
1599:
1600:
1601: t_init(reinit)
1602:
1603:
1604: int reinit;
1605:
1606:
1607: {
1608:
1609:
1610: int i;
1611: FILE *tmpfile();
1612:
1613:
1614: /*
1615: *
1616: * Called to initialize the printer and associated variables. reinit will
1617: * be zero when the "x init" command was found in the output file, while
1618: * it will be non-zero when the routine is called to set things up for a
1619: * new page.
1620: *
1621: */
1622:
1623:
1624: if (! reinit) {
1625: for (i = 0; i < nchtab; i++)
1626: if (strcmp(&chname[chtab[i]], "l.") == 0)
1627: break;
1628: if (i < nchtab) {
1629: drawdot = i + 128;
1630: drawsize = 1;
1631: } else {
1632: drawdot = '.';
1633: drawsize = 2; /* half size */
1634: }
1635:
1636: xfac = (float) pres / res * aspect;
1637: yfac = (float) pres / res;
1638:
1639: putc(ASETPEN, tf);
1640: putc(penwidth, tf);
1641:
1642: if ( mode == LANDSCAPE ) {
1643: putc(ASETHV, tf);
1644: putc(0107, tf);
1645: angle = ROT_270;
1646: } /* End if */
1647: }
1648:
1649: hpos = vpos = 0;
1650: setsize(t_size(10)); /* start somewhere */
1651:
1652: } /* End of t_init */
1653:
1654:
1655: /*****************************************************************************/
1656:
1657:
1658: t_page(pg)
1659:
1660:
1661: {
1662:
1663:
1664: register int i, j, n;
1665: register unsigned char *p;
1666:
1667:
1668: /*
1669: *
1670: * Get the printer and everything else ready for a new page. If the -o
1671: * option has been used only selected pages will be printed. If output
1672: * is ON when this routine is called we'll write the endpage Impress
1673: * command to the output file. If we're supposed to be doing output for
1674: * page pg we'll write the APAGE command out, and that will cause the
1675: * horizontal and vertical positions (in Impress) to be set to zero. hpos
1676: * and vpos are initialized in routine t_init(), although I really don't
1677: * see any reason why we couldn't just skip the call and do it here.
1678: *
1679: */
1680:
1681:
1682: if ( debug == ON )
1683: fprintf(stderr, "t_page %d, output=%d\n", pg, output);
1684:
1685: pageno = pg;
1686:
1687: if ( output == ON ) /* doing output for last page */
1688: putc(AENDP, tf);
1689:
1690: if ( (output = in_olist(pg)) == ON ) { /* print this page */
1691: putc(APAGE, tf);
1692: acctpages++;
1693: }
1694:
1695: lastx = lasty = -1;
1696: t_init(1); /* setup for this page */
1697:
1698: } /* End of t_page */
1699:
1700:
1701: /*****************************************************************************/
1702:
1703:
1704: t_newline()
1705:
1706:
1707: {
1708:
1709:
1710: /*
1711: *
1712: * Read an "n a b" command in the input file and are ready to start a new
1713: * line. There really isn't much else this routine can do besides set the
1714: * horizontal position to zero. Anyway troff takes care of any needed
1715: * positioning before it starts printing text.
1716: *
1717: */
1718:
1719:
1720: hpos = 0;
1721:
1722: } /* End of t_newline */
1723:
1724:
1725: /*****************************************************************************/
1726:
1727:
1728: t_size(n)
1729:
1730:
1731: int n; /* convert this point size */
1732:
1733:
1734: {
1735:
1736:
1737: int i;
1738:
1739:
1740: /*
1741: *
1742: * Converts a point size into an internal size that can be used as an
1743: * index into the pstab[] array. Actually the internal size is defined as
1744: * one plus the index of the least upper bound of n in pstab[] or nsizes
1745: * if n is larger than all the listed sizes.
1746: *
1747: */
1748:
1749: if (n <= pstab[0])
1750: return(1);
1751: else if (n >= pstab[nsizes-1])
1752: return(nsizes);
1753: for (i = 0; n > pstab[i]; i++) ;
1754:
1755: return(i+1);
1756:
1757: } /* End of t_size */
1758:
1759:
1760: /*****************************************************************************/
1761:
1762:
1763: t_charht(n)
1764:
1765:
1766: int n; /* use this as the character height */
1767:
1768:
1769: {
1770:
1771:
1772: /*
1773: *
1774: * Although it can be done on some typesetters, like the APS-5, it's ignored
1775: * on Imagen's bitmap printers like the Imprint-10 and the 8/300. It would
1776: * be absurd to keep any extra raster files around just so we could implement
1777: * this command, and right now there's no Impress command to do it to
1778: * downloaded glyphs.
1779: *
1780: */
1781:
1782:
1783: } /* End of t_charht */
1784:
1785:
1786: /*****************************************************************************/
1787:
1788:
1789: t_slant(n)
1790:
1791:
1792: int n; /* slant characters this many degrees */
1793:
1794:
1795: {
1796:
1797:
1798: /*
1799: *
1800: * As with troff's height command, there's no simple way to slant characters
1801: * on Imagen's bitmap printers and it's really not worth any effort to try
1802: * and make it work.
1803: *
1804: */
1805:
1806:
1807: } /* End of t_slant */
1808:
1809:
1810: /*****************************************************************************/
1811:
1812:
1813: t_font(s)
1814:
1815:
1816: char *s;
1817:
1818:
1819: {
1820:
1821:
1822: int n;
1823:
1824:
1825: /*
1826: *
1827: * Just converts the string *s into an integer and checks to make sure the
1828: * number is a legal font position. If it's not we'll print an error message
1829: * and then quit. di10 handled bad requests a little differently. Instead
1830: * of treating mistakes as FATAL errors it would return 1 as the font
1831: * number.
1832: *
1833: */
1834:
1835:
1836: if ( (n = atoi(s)) < 0 || n > nfonts )
1837: error(FATAL, "illegal font position %d", n);
1838:
1839: return(n);
1840:
1841: } /* End of t_font */
1842:
1843:
1844: /*****************************************************************************/
1845:
1846:
1847: t_reset(c)
1848:
1849:
1850: int c; /* pause or restart */
1851:
1852:
1853: {
1854:
1855:
1856: /*
1857: *
1858: * Called from devcntrl() when we've found an "x stop" or "x pause" command.
1859: * There's really nothing we need to do for Imagen's bitmap printers, and
1860: * leaving the final cleanup (ie. AEOF code etc.) to someone else means
1861: * we should be able to cat a bunch of troff output files together and
1862: * have them all printed properly.
1863: *
1864: */
1865:
1866:
1867: } /* End of t_reset */
1868:
1869:
1870: /*****************************************************************************/
1871:
1872:
1873: t_wrapup()
1874:
1875:
1876: {
1877:
1878:
1879: /*
1880: *
1881: * We're finished with all the input files and all that's left to do is
1882: * end the last page we were working on and then mark the end of the Impress
1883: * file.
1884: *
1885: */
1886:
1887:
1888: putc(AENDP, tf);
1889: putc(AEOF, tf);
1890:
1891: } /* End of t_wrapup */
1892:
1893:
1894: /*****************************************************************************/
1895:
1896:
1897: t_trailer()
1898:
1899:
1900: {
1901:
1902:
1903: /*
1904: *
1905: * Called from devcntrl() when an "x trailer" command is found. There's
1906: * nothing we need to do here for Imagen's printers.
1907: *
1908: */
1909:
1910:
1911:
1912: } /* End of t_trailer */
1913:
1914:
1915: /*****************************************************************************/
1916:
1917:
1918: hgoto(n)
1919:
1920:
1921: int n; /* where we want to be */
1922:
1923:
1924: {
1925:
1926:
1927: /*
1928: *
1929: * Want to be at this absolute horizontal position next - usually will
1930: * get these motion commands right before printing a character.
1931: *
1932: */
1933:
1934:
1935: hpos = n;
1936:
1937: } /* End of hgoto */
1938:
1939:
1940: /*****************************************************************************/
1941:
1942:
1943: hmot(n)
1944:
1945:
1946: int n; /* move this far from where we are */
1947:
1948:
1949: {
1950:
1951:
1952: /*
1953: *
1954: * Handles relative horizontal motion. troff's current positon as recorded
1955: * in hpos is changed by n units.
1956: *
1957: */
1958:
1959:
1960: hpos += n;
1961:
1962: } /* End of hmot */
1963:
1964:
1965: /*****************************************************************************/
1966:
1967:
1968: vgoto(n)
1969:
1970:
1971: int n; /* new vertical position */
1972:
1973:
1974: {
1975:
1976:
1977: /*
1978: *
1979: * Moves vertically in troff's coordinate system to absolute position n.
1980: *
1981: */
1982:
1983:
1984: vpos = n;
1985:
1986: } /* End of vgoto */
1987:
1988:
1989: /*****************************************************************************/
1990:
1991:
1992: vmot(n)
1993:
1994:
1995: int n; /* move this far vertically */
1996:
1997:
1998: {
1999:
2000:
2001: /*
2002: *
2003: * Handles relative vertical motion of n units in troff's coordinate system.
2004: *
2005: */
2006:
2007:
2008: vpos += n;
2009:
2010: } /* End of vmot */
2011:
2012:
2013: /*****************************************************************************/
2014:
2015:
2016: put1s(s)
2017:
2018:
2019: register char *s;
2020:
2021:
2022: {
2023:
2024:
2025: static int i = 0; /* last one we found - usually */
2026:
2027:
2028: /*
2029: *
2030: * Does whatever is necessary to have special character *s printed. If we're
2031: * doing output on this page we'll look the character up using chname[] and
2032: * chtab[]. The first array contains all the special character names
2033: * separated by '\0' that are mentioned in the typesetter's DESC file, while
2034: * chname[i] points to the start of character i in chname[]. Both arrays
2035: * come from the DESC.out file for printer *devname which is found in
2036: * *fontdir (wherever that might be).
2037: *
2038: */
2039:
2040:
2041: if ( output == OFF )
2042: return;
2043:
2044: if ( debug )
2045: printf("%s", s);
2046:
2047: if (strcmp(s, &chname[chtab[i]]) != 0)
2048: for (i = 0; i < nchtab; i++)
2049: if (strcmp(&chname[chtab[i]], s) == 0)
2050: break;
2051: if (i < nchtab)
2052: put1(i + 128);
2053: else
2054: i = 0;
2055:
2056: } /* End of put1s */
2057:
2058:
2059: /*****************************************************************************/
2060:
2061:
2062: put1(c)
2063:
2064:
2065: register int c; /* print this character */
2066:
2067:
2068: {
2069:
2070:
2071: char *pw;
2072: register char *p;
2073: register int i, j, k;
2074: int ofont, code;
2075:
2076:
2077: /*
2078: *
2079: * Arranges to have character c printed. If c < 128 it's a simple ASCII character,
2080: * otherwise it's a special character. We subtract 32 from c because non-graphic
2081: * ASCII characters aren't included in the tables.
2082: *
2083: */
2084:
2085:
2086: lastc = c; /* charlib() may need the real name */
2087: c -= 32;
2088:
2089: if ( c <= 0 ) {
2090: if ( debug == ON )
2091: fprintf(tf, "non-exist 0%o\n", lastc);
2092: return;
2093: } /* End if */
2094:
2095: k = ofont = font;
2096: i = fitab[font][c] & BMASK;
2097:
2098: if ( i != 0 ) { /* it's on this font */
2099: p = codetab[font];
2100: pw = widthtab[font];
2101: } else if ( smnt > 0 ) { /* on special (we hope) */
2102: for ( k=smnt, j=0; j <= nfonts; j++, k = (k+1) % (nfonts+1) ) {
2103: if ( k == 0 ) continue;
2104: if ( (i = fitab[k][c] & BMASK) != 0 ) {
2105: p = codetab[k];
2106: pw = widthtab[k];
2107: setfont(k);
2108: break;
2109: } /* End if */
2110: } /* End for */
2111: } /* End else */
2112:
2113: if ( i == 0 || (code = p[i] & BMASK) == 0 || k > nfonts ) {
2114: if ( debug == ON )
2115: fprintf(tf, "not found 0%o\n", lastc);
2116: if ( font != ofont ) setfont(ofont);
2117: return;
2118: } /* End if */
2119:
2120: lastw = ((pw[i] & BMASK) * pstab[size-1] + dev.unitwidth/2) / dev.unitwidth;
2121:
2122: if ( debug == ON ) {
2123: if ( isprint(lastc) )
2124: fprintf(tf, "%c %d\n", lastc, code);
2125: else fprintf(tf, "%03o %d\n", lastc, code);
2126: } else oput(code);
2127:
2128: if ( font != ofont )
2129: setfont(ofont);
2130:
2131: } /* End of put1 */
2132:
2133:
2134: /*****************************************************************************/
2135:
2136:
2137: setsize(n)
2138:
2139:
2140: int n; /* new internal size */
2141:
2142:
2143: {
2144:
2145:
2146: /*
2147: *
2148: * We want to use internal size n for now, where n is an index into *pstab
2149: * where we can find the closest available approximation to the requested
2150: * point size.
2151: *
2152: */
2153:
2154:
2155: size = n;
2156:
2157: } /* End of setsize */
2158:
2159:
2160: /*****************************************************************************/
2161:
2162:
2163: t_fp(n, s, si)
2164:
2165:
2166: int n; /* font position to update */
2167: char *s; /* it now contains this font */
2168: char *si; /* and this is its internal number */
2169:
2170:
2171: {
2172:
2173:
2174: /*
2175: *
2176: * Called when we've loaded font *s in position n. The font position info
2177: * is recorded in fontname[].
2178: *
2179: */
2180:
2181:
2182: fontname[n].name = s;
2183: fontname[n].number = atoi(si);
2184: if ( n == lastfont ) lastfont = -1; /* force getfontdata() call */
2185:
2186: } /* End of t_fp */
2187:
2188:
2189: /*****************************************************************************/
2190:
2191:
2192: setfont(n)
2193:
2194:
2195: int n; /* this will be the current font */
2196:
2197:
2198: {
2199:
2200:
2201: /*
2202: *
2203: * Job now wants to use the font loaded in position n. The variable font
2204: * keeps track of which one we're currently using. If the requested positon
2205: * is out of range we'll just quit.
2206: *
2207: */
2208:
2209:
2210: if ( output == OFF )
2211: return;
2212:
2213: if (n < 0 || n > NFONT)
2214: error(FATAL, "illegal font %d", n);
2215:
2216: font = n;
2217:
2218: } /* End of setfont */
2219:
2220:
2221: /*****************************************************************************/
2222:
2223:
2224: oput(c)
2225:
2226:
2227: int c; /* want to print this character */
2228:
2229:
2230: {
2231:
2232:
2233: int x, y; /* current scaled position */
2234: int member; /* glyph number for c in current family */
2235:
2236:
2237: /*
2238: *
2239: * Arranges to print the character whose code is c in the current font.
2240: * The old and new raster file formats are supported.
2241: *
2242: */
2243:
2244:
2245: if ( output == OFF )
2246: return;
2247:
2248: if ( rastformat == OLD_FORMAT ) {
2249: xychar(c, fontname[font].name, pstab[size-1], lastw, tf);
2250: return;
2251: } /* End if */
2252:
2253: if ( font != lastfont || size != lastsize ) {
2254: if ( isresident(fontname[font].name) == FALSE )
2255: getrastdata(fontname[font].name, mapsize(fontname[font].name, pstab[size-1]));
2256: else getresdata(fontname[font].name, mapsize(fontname[font].name, pstab[size-1]), tf);
2257: lastfont = font;
2258: lastsize = size;
2259: } /* End if */
2260:
2261: member = download(c, lastw, angle, tf);
2262:
2263: x = hpos * xfac + xoffset + .5;
2264: y = vpos * yfac + yoffset + .5;
2265:
2266: if ( y != lasty ) {
2267: putc(ASETAV, tf);
2268: putint(y, tf);
2269: lasty = y;
2270: } /* End if */
2271:
2272: if ( ABS(x - lastx) > SLOP ) {
2273: putc(ASETAH, tf);
2274: putint(x, tf);
2275: lastx = x + fam->advance[member];
2276: } else lastx += fam->advance[member];
2277:
2278: putc(member, tf);
2279:
2280: } /* End of oput */
2281:
2282:
2283: /*****************************************************************************/
2284:
2285:
2286: mapsize(name, ps)
2287: char *name; /* name of the font */
2288: int ps; /* point size troff wants to use */
2289: {
2290: int i, j;
2291: /*
2292: * Uses the data that's been filled in from RASTLIST to map point size
2293: * ps font font *name into the best size available in our raster tables.
2294: * If no RASTLIST file was used rastsize will be zero and we'll just
2295: * assume that any size that's aske for is available.
2296: */
2297: if ( maxrast == 0 ) /* don't have any size data */
2298: return(ps);
2299:
2300: for ( i = 0; i < maxrast; i++ )
2301: if ( strncmp(name, sizedata[i].name, L_FNAME) == 0 )
2302: break;
2303:
2304: if ( i >= maxrast ) /* didn't find the font */
2305: error(FATAL, "missing raster list data for font %s", name);
2306:
2307: for ( j = 1, ps = (ps * pres) / rres; ps >= sizedata[i].sizes[j]; j++ ) ;
2308:
2309: return(sizedata[i].sizes[--j]);
2310:
2311: } /* End of mapsize */
2312:
2313:
2314: /*****************************************************************************/
2315:
2316:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.