Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 *
3
 * postdaisy - PostScript translator for Diablo 1640 files.
4
 *
5
 * A program that translates Diablo 1640 files into PostScript. Absolutely nothing
6
 * is guaranteed. Quite a few things haven't been implemented, and what's been
7
 * done isn't well tested. Most of the documentation used to write this program
8
 * was taken from the 'Diablo Emulator' section of a recent Imagen manual.
9
 *
10
 * Some of document comments that are generated may not be right. Most of the test
11
 * files I used produced a trailing blank page. I've put a check in formfeed() that
12
 * won't print the last page if it doesn't contain any text, but PAGES comments may
13
 * not be right. The DOCUMENTFONTS comment will also be wrong if auto underline or
14
 * bold printing have been turned on by escape commands.
15
 *
16
 * The brute force approach used to implement horizontal and vertical tabs leaves
17
 * much to be desired, and may not work for very small initial hmi and vmi values.
18
 * At the very least I should have used malloc() to get space for the two tabstop
19
 * arrays after hmi and vmi are known!
20
 *
21
 * Reverse printing mode hasn't been tested at all, but what's here should be
22
 * close even though it's not efficient.
23
 *
24
 * The PostScript prologue is copied from *prologue before any of the input files
25
 * are translated. The program expects that the following PostScript procedures
26
 * are defined in that file:
27
 *
28
 *	setup
29
 *
30
 *	  mark ... setup -
31
 *
32
 *	    Handles special initialization stuff that depends on how this program
33
 *	    was called. Expects to find a mark followed by key/value pairs on the
34
 *	    stack. The def operator is applied to each pair up to the mark, then
35
 *	    the default state is set up.
36
 *
37
 *	pagesetup
38
 *
39
 *	  page pagesetup -
40
 *
41
 *	    Does whatever is needed to set things up for the next page. Expects to
42
 *	    find the current page number on the stack.
43
 *
44
 *	t
45
 *
46
 *	  mark str1 x1 str2 x2 ... strn xn y hmi t mark
47
 *
48
 *	    Handles all the text on the stack. Characters in the strings are
49
 *	    printed using hmi as the character advance, and all strings are at
50
 *	    vertical position y. Each string is begins at the horizontal position
51
 *	    that preceeds it.
52
 *
53
 *	f
54
 *
55
 *	  font f -
56
 *
57
 *	    Use font f, where f is the full PostScript font name. Only used when
58
 *	    we switch to auto underline (Courier-Italic) or bold (Courier-Bold)
59
 *	    printing.
60
 *
61
 *	done
62
 *
63
 *	  done
64
 *
65
 *	    Makes sure the last page is printed. Only needed when we're printing
66
 *	    more than one page on each sheet of paper.
67
 *
68
 * Many default values, like the magnification and orientation, are defined in 
69
 * the prologue, which is where they belong. If they're changed (by options), an
70
 * appropriate definition is made after the prologue is added to the output file.
71
 * The -P option passes arbitrary PostScript through to the output file. Among
72
 * other things it can be used to set (or change) values that can't be accessed by
73
 * other options.
74
 *
75
 */
76
 
77
#include <stdio.h>
78
#include <signal.h>
79
#include <ctype.h>
80
#include <fcntl.h>
81
 
82
#include "comments.h"			/* PostScript file structuring comments */
83
#include "gen.h"			/* general purpose definitions */
84
#include "path.h"			/* for the prologue */
85
#include "ext.h"			/* external variable declarations */
86
#include "postdaisy.h"			/* a few special definitions */
87
 
88
char	*optnames = "a:c:f:h:l:m:n:o:p:r:s:v:x:y:A:C:E:J:L:P:DI";
89
 
90
char	*prologue = POSTDAISY;		/* default PostScript prologue */
91
char	*formfile = FORMFILE;		/* stuff for multiple pages per sheet */
92
 
93
int	formsperpage = 1;		/* page images on each piece of paper */
94
int	copies = 1;			/* and this many copies of each sheet */
95
 
96
char	htabstops[COLUMNS];		/* horizontal */
97
char	vtabstops[ROWS];		/* and vertical tabs */
98
 
99
int	res = RES;			/* input file resolution - sort of */
100
 
101
int	hmi = HMI;			/* horizontal motion index - 1/120 inch */
102
int	vmi = VMI;			/* vertical motion index - 1/48 inch */
103
int	ohmi = HMI;			/* original hmi */
104
int	ovmi = VMI;			/* and vmi - for tabs and char size */
105
 
106
int	hpos = 0;			/* current horizontal */
107
int	vpos = 0;			/* and vertical position */
108
 
109
int	lastx = -1;			/* printer's last horizontal */
110
int	lasty = -1;			/* and vertical position */
111
int	lasthmi = -1;			/* hmi for current text strings */
112
 
113
int	lastc = -1;			/* last printed character */
114
int	prevx = -1;			/* at this position */
115
 
116
int	leftmargin = LEFTMARGIN;	/* page margins */
117
int	rightmargin = RIGHTMARGIN;
118
int	topmargin = TOPMARGIN;
119
int	bottommargin = BOTTOMMARGIN;
120
 
121
int	stringcount = 0;		/* number of strings on the stack */
122
int	stringstart = 1;		/* column where current one starts */
123
int	advance = 1;			/* -1 if in backward print mode */
124
 
125
int	lfiscr = OFF;			/* line feed implies carriage return */
126
int	crislf = OFF;			/* carriage return implies line feed */
127
 
128
int	linespp = 0;			/* lines per page if it's positive */
129
int	markedpage = FALSE;		/* helps prevent trailing blank page */
130
int	page = 0;			/* page we're working on */
131
int	printed = 0;			/* printed this many pages */
132
 
133
Fontmap	fontmap[] = FONTMAP;		/* for translating font names */
134
char	*fontname = "Courier";		/* use this PostScript font */
135
int	shadowprint = OFF;		/* automatic bold printing if ON */
136
 
137
FILE	*fp_in;				/* read from this file */
138
FILE	*fp_out = stdout;		/* and write stuff here */
139
FILE	*fp_acct = NULL;		/* for accounting data */
140
 
141
/*****************************************************************************/
142
 
143
main(agc, agv)
144
 
145
    int		agc;
146
    char	*agv[];
147
 
148
{
149
 
150
/*
151
 *
152
 * A simple program that translates Diablo 1640 files into PostScript. Nothing
153
 * is guaranteed - the program not well tested and doesn't implement everything.
154
 *
155
 */
156
 
157
    argc = agc;				/* other routines may want them */
158
    argv = agv;
159
 
160
    prog_name = argv[0];		/* really just for error messages */
161
 
162
    init_signals();			/* sets up interrupt handling */
163
    header();				/* PostScript header comments */
164
    options();				/* handle the command line options */
165
    setup();				/* for PostScript */
166
    arguments();			/* followed by each input file */
167
    done();				/* print the last page etc. */
168
    account();				/* job accounting data */
169
 
170
    exit(x_stat);			/* not much could be wrong */
171
 
172
}   /* End of main */
173
 
174
/*****************************************************************************/
175
 
176
init_signals()
177
 
178
{
179
 
180
    int		interrupt();		/* signal handler */
181
 
182
/*
183
 *
184
 * Makes sure we handle interrupts.
185
 *
186
 */
187
 
188
    if ( signal(SIGINT, interrupt) == SIG_IGN )  {
189
	signal(SIGINT, SIG_IGN);
190
	signal(SIGQUIT, SIG_IGN);
191
	signal(SIGHUP, SIG_IGN);
192
    } else {
193
	signal(SIGHUP, interrupt);
194
	signal(SIGQUIT, interrupt);
195
    }   /* End else */
196
 
197
    signal(SIGTERM, interrupt);
198
 
199
}   /* End of init_signals */
200
 
201
/*****************************************************************************/
202
 
203
header()
204
 
205
{
206
 
207
    int		ch;			/* return value from getopt() */
208
    int		old_optind = optind;	/* for restoring optind - should be 1 */
209
 
210
/*
211
 *
212
 * Scans the option list looking for things, like the prologue file, that we need
213
 * right away but could be changed from the default. Doing things this way is an
214
 * attempt to conform to Adobe's latest file structuring conventions. In particular
215
 * they now say there should be nothing executed in the prologue, and they have
216
 * added two new comments that delimit global initialization calls. Once we know
217
 * where things really are we write out the job header, follow it by the prologue,
218
 * and then add the ENDPROLOG and BEGINSETUP comments.
219
 *
220
 */
221
 
222
    while ( (ch = getopt(argc, argv, optnames)) != EOF )
223
	if ( ch == 'L' )
224
	    prologue = optarg;
225
	else if ( ch == '?' )
226
	    error(FATAL, "");
227
 
228
    optind = old_optind;		/* get ready for option scanning */
229
 
230
    fprintf(stdout, "%s", CONFORMING);
231
    fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
232
    fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
233
    fprintf(stdout, "%s %s\n", PAGES, ATEND);
234
    fprintf(stdout, "%s", ENDCOMMENTS);
235
 
236
    if ( cat(prologue) == FALSE )
237
	error(FATAL, "can't read %s", prologue);
238
 
239
    if ( DOROUND )
240
	cat(ROUNDPAGE);
241
 
242
    fprintf(stdout, "%s", ENDPROLOG);
243
    fprintf(stdout, "%s", BEGINSETUP);
244
    fprintf(stdout, "mark\n");
245
 
246
}   /* End of header */
247
 
248
/*****************************************************************************/
249
 
250
options()
251
 
252
{
253
 
254
    int		ch;			/* return value from getopt() */
255
    int		n;			/* for CR and LF modes */
256
 
257
/*
258
 *
259
 * Reads and processes the command line options. Added the -P option so arbitrary
260
 * PostScript code can be passed through. Expect it could be useful for changing
261
 * definitions in the prologue for which options have not been defined.
262
 *
263
 * Although any PostScript font can be used, things will only work for constant
264
 * width fonts.
265
 *
266
 */
267
 
268
    while ( (ch = getopt(argc, argv, optnames)) != EOF )  {
269
	switch ( ch )  {
270
	    case 'a':			/* aspect ratio */
271
		    fprintf(stdout, "/aspectratio %s def\n", optarg);
272
		    break;
273
 
274
	    case 'c':			/* copies */
275
		    copies = atoi(optarg);
276
		    fprintf(stdout, "/#copies %s store\n", optarg);
277
		    break;
278
 
279
	    case 'f':			/* use this PostScript font */
280
		    fontname = get_font(optarg);
281
		    fprintf(stdout, "/font /%s def\n", fontname);
282
		    break;
283
 
284
	    case 'h':			/* default character spacing */
285
		    ohmi = hmi = atoi(optarg) * HSCALE;
286
		    fprintf(stdout, "/hmi %s def\n", optarg);
287
		    break;
288
 
289
	    case 'l':			/* lines per page */
290
		    linespp = atoi(optarg);
291
		    break;
292
 
293
	    case 'm':			/* magnification */
294
		    fprintf(stdout, "/magnification %s def\n", optarg);
295
		    break;
296
 
297
	    case 'n':			/* forms per page */
298
		    formsperpage = atoi(optarg);
299
		    fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
300
		    fprintf(stdout, "/formsperpage %s def\n", optarg);
301
		    break;
302
 
303
	    case 'o':			/* output page list */
304
		    out_list(optarg);
305
		    break;
306
 
307
	    case 'p':			/* landscape or portrait mode */
308
		    if ( *optarg == 'l' )
309
			fprintf(stdout, "/landscape true def\n");
310
		    else fprintf(stdout, "/landscape false def\n");
311
		    break;
312
 
313
	    case 'r':			/* set CR and LF modes */
314
		    n = atoi(optarg);
315
		    if ( n & 01 )
316
			lfiscr = ON;
317
		    else lfiscr = OFF;
318
		    if ( n & 02 )
319
			crislf = ON;
320
		    else crislf = OFF;
321
		    break;
322
 
323
	    case 's':			/* point size */
324
		    fprintf(stdout, "/pointsize %s def\n", optarg);
325
		    break;
326
 
327
	    case 'v':			/* default line spacing */
328
		    ovmi = vmi = atoi(optarg) * VSCALE;
329
		    break;
330
 
331
	    case 'x':			/* shift things horizontally */
332
		    fprintf(stdout, "/xoffset %s def\n", optarg);
333
		    break;
334
 
335
	    case 'y':			/* and vertically on the page */
336
		    fprintf(stdout, "/yoffset %s def\n", optarg);
337
		    break;
338
 
339
	    case 'A':			/* force job accounting */
340
	    case 'J':
341
		    if ( (fp_acct = fopen(optarg, "a")) == NULL )
342
			error(FATAL, "can't open accounting file %s", optarg);
343
		    break;
344
 
345
	    case 'C':			/* copy file straight to output */
346
		    if ( cat(optarg) == FALSE )
347
			error(FATAL, "can't read %s", optarg);
348
		    break;
349
 
350
	    case 'E':			/* text font encoding */
351
		    fontencoding = optarg;
352
		    break;
353
 
354
	    case 'L':			/* PostScript prologue file */
355
		    prologue = optarg;
356
		    break;
357
 
358
	    case 'P':			/* PostScript pass through */
359
		    fprintf(stdout, "%s\n", optarg);
360
		    break;
361
 
362
	    case 'R':			/* special global or page level request */
363
		    saverequest(optarg);
364
		    break;
365
 
366
	    case 'D':			/* debug flag */
367
		    debug = ON;
368
		    break;
369
 
370
	    case 'I':			/* ignore FATAL errors */
371
		    ignore = ON;
372
		    break;
373
 
374
	    case '?':			/* don't understand the option */
375
		    error(FATAL, "");
376
		    break;
377
 
378
	    default:			/* don't know what to do for ch */
379
		    error(FATAL, "missing case for option %c\n", ch);
380
		    break;
381
	}   /* End switch */
382
    }   /* End while */
383
 
384
    argc -= optind;			/* get ready for non-option args */
385
    argv += optind;
386
 
387
}   /* End of options */
388
 
389
/*****************************************************************************/
390
 
391
char *get_font(name)
392
 
393
    char	*name;			/* name the user asked for */
394
 
395
{
396
 
397
    int		i;			/* for looking through fontmap[] */
398
 
399
/*
400
 *
401
 * Called from options() to map a user's font name into a legal PostScript name.
402
 * If the lookup fails *name is returned to the caller. That should let you choose
403
 * any PostScript font, although things will only work well for constant width
404
 * fonts.
405
 *
406
 */
407
 
408
    for ( i = 0; fontmap[i].name != NULL; i++ )
409
	if ( strcmp(name, fontmap[i].name) == 0 )
410
	    return(fontmap[i].val);
411
 
412
    return(name);
413
 
414
}   /* End of get_font */
415
 
416
/*****************************************************************************/
417
 
418
setup()
419
 
420
{
421
 
422
/*
423
 *
424
 * Handles things that must be done after the options are read but before the
425
 * input files are processed.
426
 *
427
 */
428
 
429
    writerequest(0, stdout);		/* global requests eg. manual feed */
430
    setencoding(fontencoding);
431
    fprintf(stdout, "setup\n");
432
 
433
    if ( formsperpage > 1 )  {
434
	if ( cat(formfile) == FALSE )
435
	    error(FATAL, "can't read %s", formfile);
436
	fprintf(stdout, "%d setupforms\n", formsperpage);
437
    }	/* End if */
438
 
439
    fprintf(stdout, "%s", ENDSETUP);
440
 
441
}   /* End of setup */
442
 
443
/*****************************************************************************/
444
 
445
arguments()
446
 
447
{
448
 
449
/*
450
 *
451
 * Makes sure all the non-option command line arguments are processed. If we get
452
 * here and there aren't any arguments left, or if '-' is one of the input files
453
 * we'll process stdin.
454
 *
455
 */
456
 
457
    fp_in = stdin;
458
 
459
    if ( argc < 1 )
460
	text();
461
    else {				/* at least one argument is left */
462
	while ( argc > 0 )  {
463
	    if ( strcmp(*argv, "-") == 0 )
464
		fp_in = stdin;
465
	    else if ( (fp_in = fopen(*argv, "r")) == NULL )
466
		error(FATAL, "can't open %s", *argv);
467
	    text();
468
	    if ( fp_in != stdin )
469
		fclose(fp_in);
470
	    argc--;
471
	    argv++;
472
	}   /* End while */
473
    }   /* End else */
474
 
475
}   /* End of arguments */
476
 
477
/*****************************************************************************/
478
 
479
done()
480
 
481
{
482
 
483
/*
484
 *
485
 * Finished with all the input files, so mark the end of the pages, make sure the
486
 * last page is printed, and restore the initial environment.
487
 *
488
 */
489
 
490
    fprintf(stdout, "%s", TRAILER);
491
    fprintf(stdout, "done\n");
492
    fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
493
    fprintf(stdout, "%s %d\n", PAGES, printed);
494
 
495
}   /* End of done */
496
 
497
/*****************************************************************************/
498
 
499
account()
500
 
501
{
502
 
503
/*
504
 *
505
 * Writes an accounting record to *fp_acct provided it's not NULL. Accounting
506
 * is requested using the -A or -J options.
507
 *
508
 */
509
 
510
    if ( fp_acct != NULL )
511
	fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
512
 
513
}   /* End of account */
514
 
515
/*****************************************************************************/
516
 
517
text()
518
 
519
{
520
 
521
    int		ch;			/* next input character */
522
 
523
/*
524
 *
525
 * Translates the next input file into PostScript. The redirect(-1) call forces
526
 * the initial output to go to /dev/null - so the stuff formfeed() does at the
527
 * end of each page doesn't go to stdout.
528
 *
529
 */
530
 
531
    redirect(-1);			/* get ready for the first page */
532
    formfeed();				/* force PAGE comment etc. */
533
    inittabs();
534
 
535
    while ( (ch = getc(fp_in)) != EOF )
536
	switch ( ch )  {
537
	    case '\010':		/* backspace */
538
		    backspace();
539
		    break;
540
 
541
	    case '\011':		/* horizontal tab */
542
		    htab();
543
		    break;
544
 
545
	    case '\012':		/* new line */
546
		    linefeed();
547
		    break;
548
 
549
	    case '\013':		/* vertical tab */
550
		    vtab();
551
		    break;
552
 
553
	    case '\014':		/* form feed */
554
		    formfeed();
555
		    break;
556
 
557
	    case '\015':		/* carriage return */
558
		    carriage();
559
		    break;
560
 
561
	    case '\016':		/* extended character set - SO */
562
		    break;
563
 
564
	    case '\017':		/* extended character set - SI */
565
		    break;
566
 
567
	    case '\031':		/* next char from supplementary set */
568
		    break;
569
 
570
	    case '\033':		/* 2 or 3 byte escape sequence */
571
		    escape();
572
		    break;
573
 
574
	    default:
575
		    if ( isascii(ch) && isprint(ch) )
576
			oput(ch);
577
		    break;
578
	}   /* End switch */
579
 
580
    formfeed();				/* next file starts on a new page? */
581
 
582
}   /* End of text */
583
 
584
/*****************************************************************************/
585
 
586
inittabs()
587
 
588
{
589
 
590
    int		i;			/* loop index */
591
 
592
/*
593
 *
594
 * Initializes the horizontal and vertical tab arrays. The way tabs are handled is
595
 * quite inefficient and may not work for all initial hmi or vmi values.
596
 *
597
 */
598
 
599
    for ( i = 0; i < COLUMNS; i++ )
600
	htabstops[i] = ((i % 8) == 0) ? ON : OFF;
601
 
602
    for ( i = 0; i < ROWS; i++ )
603
	vtabstops[i] = ((i * ovmi) > BOTTOMMARGIN) ? ON : OFF;
604
 
605
}   /* End of inittabs */
606
 
607
/*****************************************************************************/
608
 
609
cleartabs()
610
 
611
{
612
 
613
    int		i;			/* loop index */
614
 
615
/*
616
 *
617
 * Clears all horizontal and vertical tab stops.
618
 *
619
 */
620
 
621
    for ( i = 0; i < ROWS; i++ )
622
	htabstops[i] = OFF;
623
 
624
    for ( i = 0; i < COLUMNS; i++ )
625
	vtabstops[i] = OFF;
626
 
627
}   /* End of cleartabs */
628
 
629
/*****************************************************************************/
630
 
631
formfeed()
632
 
633
{
634
 
635
/*
636
 *
637
 * Called whenever we've finished with the last page and want to get ready for the
638
 * next one. Also used at the beginning and end of each input file, so we have to
639
 * be careful about what's done. I've added a simple test before the showpage that
640
 * should eliminate the extra blank page that was put out at the end of many jobs,
641
 * but the PAGES comments may be wrong.
642
 *
643
 */
644
 
645
    if ( fp_out == stdout )		/* count the last page */
646
	printed++;
647
 
648
    endline();				/* print the last line */
649
 
650
    fprintf(fp_out, "cleartomark\n");
651
    if ( feof(fp_in) == 0 || markedpage == TRUE )
652
	fprintf(fp_out, "showpage\n");
653
    fprintf(fp_out, "saveobj restore\n");
654
    fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
655
 
656
    if ( ungetc(getc(fp_in), fp_in) == EOF )
657
	redirect(-1);
658
    else redirect(++page);
659
 
660
    fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
661
    fprintf(fp_out, "/saveobj save def\n");
662
    fprintf(fp_out, "mark\n");
663
    writerequest(printed+1, fp_out);
664
    fprintf(fp_out, "%d pagesetup\n", printed+1);
665
 
666
    vgoto(topmargin);
667
    hgoto(leftmargin);
668
 
669
    markedpage = FALSE;
670
 
671
}   /* End of formfeed */
672
 
673
/*****************************************************************************/
674
 
675
linefeed()
676
 
677
{
678
 
679
    int		line = 0;		/* current line - based on ovmi */
680
 
681
/*
682
 *
683
 * Adjust our current vertical position. If we've passed the bottom of the page
684
 * or exceeded the number of lines per page, print it and go to the upper left
685
 * corner of the next page. This routine is also called from carriage() if crislf
686
 * is ON.
687
 *
688
 */
689
 
690
    vmot(vmi);
691
 
692
    if ( lfiscr == ON )
693
	hgoto(leftmargin);
694
 
695
    if ( linespp > 0 )			/* means something so see where we are */
696
	line = vpos / ovmi + 1;
697
 
698
    if ( vpos > bottommargin || line > linespp )
699
	formfeed();
700
 
701
}   /* End of linefeed */
702
 
703
/*****************************************************************************/
704
 
705
carriage()
706
 
707
{
708
 
709
/*
710
 *
711
 * Handles carriage return character. If crislf is ON we'll generate a line feed
712
 * every time we get a carriage return character.
713
 *
714
 */
715
 
716
    if ( shadowprint == ON )		/* back to normal mode */
717
	changefont(fontname);
718
 
719
    advance = 1;
720
    shadowprint = OFF;
721
 
722
    hgoto(leftmargin);
723
 
724
    if ( crislf == ON )
725
	linefeed();
726
 
727
}   /* End of carriage */
728
 
729
/*****************************************************************************/
730
 
731
htab()
732
 
733
{
734
 
735
    int		col;			/* 'column' we'll be at next */
736
    int		i;			/* loop index */
737
 
738
/*
739
 *
740
 * Tries to figure out where the next tab stop is. Wasn't positive about this
741
 * one, since hmi can change. I'll assume columns are determined by the original
742
 * value of hmi. That fixes them on the page, which seems to make more sense than
743
 * letting them float all over the place.
744
 *
745
 */
746
 
747
    endline();
748
 
749
    col = hpos/ohmi + 1;
750
    for ( i = col; i < ROWS; i++ )
751
	if ( htabstops[i] == ON )  {
752
	    col = i;
753
	    break;
754
	}   /* End if */
755
 
756
    hgoto(col * ohmi);
757
    lastx = hpos;
758
 
759
}   /* End of htab */
760
 
761
/*****************************************************************************/
762
 
763
vtab()
764
 
765
{
766
 
767
    int		line;			/* line we'll be at next */
768
    int		i;			/* loop index */
769
 
770
/*
771
 *
772
 * Looks for the next vertical tab stop in the vtabstops[] array and moves to that
773
 * line. If we don't find a tab we'll just move down one line - shouldn't happen.
774
 *
775
 */
776
 
777
    endline();
778
 
779
    line = vpos/ovmi + 1;
780
    for ( i = line; i < COLUMNS; i++ )
781
	if ( vtabstops[i] == ON )  {
782
	    line = i;
783
	    break;
784
	}   /* End if */
785
 
786
    vgoto(line * ovmi);
787
 
788
}   /* End of vtab */
789
 
790
/*****************************************************************************/
791
 
792
backspace()
793
 
794
{
795
 
796
/*
797
 *
798
 * Moves backwards a distance equal to the current value of hmi, but don't go
799
 * past the left margin.
800
 *
801
 */
802
 
803
    endline();
804
 
805
    if ( hpos - leftmargin >= hmi )
806
	hmot(-hmi);
807
    else hgoto(leftmargin);		/* maybe just ignore the backspace?? */
808
 
809
    lastx = hpos;
810
 
811
}   /* End of backspace */
812
 
813
/*****************************************************************************/
814
 
815
escape()
816
 
817
{
818
 
819
    int		ch;			/* control character */
820
 
821
/*
822
 *
823
 * Handles special codes that are expected to follow an escape character. The
824
 * initial escape character is followed by one or two bytes.
825
 *
826
 */
827
 
828
    switch ( ch = getc(fp_in) ) {
829
	case 'T':			/* top margin */
830
		topmargin = vpos;
831
		break;
832
 
833
	case 'L':			/* bottom margin */
834
		bottommargin = vpos;
835
		break;
836
 
837
	case 'C':			/* clear top and bottom margins */
838
		bottommargin = BOTTOMMARGIN;
839
		topmargin = TOPMARGIN;
840
		break;
841
 
842
	case '9':			/* left margin */
843
		leftmargin = hpos;
844
		break;
845
 
846
	case '0':			/* right margin */
847
		rightmargin = hpos;
848
		break;
849
 
850
	case '1':			/* set horizontal tab */
851
		htabstops[hpos/ohmi] = ON;
852
		break;
853
 
854
	case '8':			/* clear horizontal tab at hpos */
855
		htabstops[hpos/ohmi] = OFF;
856
		break;
857
 
858
	case '-':			/* set vertical tab */
859
		vtabstops[vpos/ovmi] = ON;
860
		break;
861
 
862
	case '2':			/* clear all tabs */
863
		cleartabs();
864
		break;
865
 
866
	case '\014':			/* set lines per page */
867
		linespp = getc(fp_in);
868
		break;
869
 
870
	case '\037':			/* set hmi to next byte minus 1 */
871
		hmi = HSCALE * (getc(fp_in) - 1);
872
		break;
873
 
874
	case 'S':			/* reset hmi to default */
875
		hmi = ohmi;
876
		break;
877
 
878
	case '\011':			/* move to column given by next byte */
879
		hgoto((getc(fp_in)-1) * ohmi);
880
		break;
881
 
882
	case '?':			/* do carriage return after line feed */
883
		lfiscr = ON;
884
		break;
885
 
886
	case '!':			/* don't generate carriage return */
887
		lfiscr = OFF;
888
		break;
889
 
890
	case '5':			/* forward print mode */
891
		advance = 1;
892
		break;
893
 
894
	case '6':			/* backward print mode */
895
		advance = -1;
896
		break;
897
 
898
	case '\036':			/* set vmi to next byte minus 1 */
899
		vmi = VSCALE * (getc(fp_in) - 1);
900
		break;
901
 
902
	case '\013':			/* move to line given by next byte */
903
		vgoto((getc(fp_in)-1) * ovmi);
904
		break;
905
 
906
	case 'U':			/* positive half line feed */
907
		vmot(vmi/2);
908
		break;
909
 
910
	case 'D':			/* negative half line feed */
911
		vmot(-vmi/2);
912
		break;
913
 
914
	case '\012':			/* negative line feed */
915
		vmot(-vmi);
916
		break;
917
 
918
	case '\015':			/* clear all margins */
919
		bottommargin = BOTTOMMARGIN;
920
		topmargin = TOPMARGIN;
921
		leftmargin = BOTTOMMARGIN;
922
		rightmargin = RIGHTMARGIN;
923
		break;
924
 
925
	case 'E':			/* auto underscore - use italic font */
926
		changefont("/Courier-Oblique");
927
		break;
928
 
929
	case 'R':			/* disable auto underscore */
930
		changefont(fontname);
931
		break;
932
 
933
	case 'O':			/* bold/shadow printing */
934
	case 'W':
935
		changefont("/Courier-Bold");
936
		shadowprint = ON;
937
		break;
938
 
939
	case '&':			/* disable bold printing */
940
		changefont(fontname);
941
		shadowprint = OFF;
942
		break;
943
 
944
	case '/':			/* ignored 2 byte escapes */
945
	case '\\':
946
	case '<':
947
	case '>':
948
	case '%':
949
	case '=':
950
	case '.':
951
	case '4':
952
	case 'A':
953
	case 'B':
954
	case 'M':
955
	case 'N':
956
	case 'P':
957
	case 'Q':
958
	case 'X':
959
	case '\010':
960
		break;
961
 
962
	case ',':			/* ignored 3 byte escapes */
963
	case '\016':
964
	case '\021':
965
		getc(fp_in);
966
		break;
967
 
968
	case '3':			/* graphics mode - should quit! */
969
	case '7':
970
	case 'G':
971
	case 'V':
972
	case 'Y':
973
	case 'Z':
974
		error(FATAL, "graphics mode is not implemented");
975
		break;
976
 
977
	default:
978
		error(FATAL, "missing case for escape o%o\n", ch);
979
		break;
980
    }	/* End switch */
981
 
982
}   /* End of escape */
983
 
984
/*****************************************************************************/
985
 
986
vmot(n)
987
 
988
    int		n;			/* move this far vertically */
989
 
990
{
991
 
992
/*
993
 *
994
 * Move vertically n units from where we are.
995
 *
996
 */
997
 
998
    vpos += n;
999
 
1000
}   /* End of vmot */
1001
 
1002
/*****************************************************************************/
1003
 
1004
vgoto(n)
1005
 
1006
    int		n;			/* new vertical position */
1007
 
1008
{
1009
 
1010
/*
1011
 *
1012
 * Moves to absolute vertical position n.
1013
 *
1014
 */
1015
 
1016
    vpos = n;
1017
 
1018
}   /* End of vgoto */
1019
 
1020
/*****************************************************************************/
1021
 
1022
hmot(n)
1023
 
1024
    int		n;			/* move this horizontally */
1025
 
1026
{
1027
 
1028
/*
1029
 *
1030
 * Moves horizontally n units from our current position.
1031
 *
1032
 */
1033
 
1034
    hpos += n * advance;
1035
 
1036
    if ( hpos < leftmargin )
1037
	hpos = leftmargin;
1038
 
1039
}   /* End of hmot */
1040
 
1041
/*****************************************************************************/
1042
 
1043
hgoto(n)
1044
 
1045
    int		n;			/* go to this horizontal position */
1046
 
1047
{
1048
 
1049
/*
1050
 *
1051
 * Moves to absolute horizontal position n.
1052
 *
1053
 */
1054
 
1055
    hpos = n;
1056
 
1057
}   /* End of hgoto */
1058
 
1059
/*****************************************************************************/
1060
 
1061
changefont(name)
1062
 
1063
    char	*name;
1064
 
1065
{
1066
 
1067
/*
1068
 *
1069
 * Changes the current font. Used to get in and out of auto underscore and bold
1070
 * printing.
1071
 *
1072
 */
1073
 
1074
    endline();
1075
    fprintf(fp_out, "%s f\n", name);
1076
 
1077
}   /* End of changefont */
1078
 
1079
/*****************************************************************************/
1080
 
1081
startline()
1082
 
1083
{
1084
 
1085
/*
1086
 *
1087
 * Called whenever we want to be certain we're ready to start pushing characters
1088
 * into an open string on the stack. If stringcount is positive we've already
1089
 * started, so there's nothing to do. The first string starts in column 1.
1090
 *
1091
 */
1092
 
1093
    if ( stringcount < 1 )  {
1094
	putc('(', fp_out);
1095
	stringstart = lastx = hpos;
1096
	lasty = vpos;
1097
	lasthmi = hmi;
1098
	lastc = -1;
1099
	prevx = -1;
1100
	stringcount = 1;
1101
    }	/* End if */
1102
 
1103
}   /* End of startline */
1104
 
1105
/*****************************************************************************/
1106
 
1107
endline()
1108
 
1109
{
1110
 
1111
/*
1112
 *
1113
 * Generates a call to the PostScript procedure that processes the text on the
1114
 * the stack - provided stringcount is positive.
1115
 *
1116
 */
1117
 
1118
    if ( stringcount > 0 )
1119
	fprintf(fp_out, ")%d %d %d t\n", stringstart, lasty, lasthmi);
1120
 
1121
    stringcount = 0;
1122
 
1123
}   /* End of endline */
1124
 
1125
/*****************************************************************************/
1126
 
1127
endstring()
1128
 
1129
{
1130
 
1131
/*
1132
 *
1133
 * Takes the string we've been working on and adds it to the output file. Called
1134
 * when we need to adjust our horizontal position before starting a new string.
1135
 * Also called from endline() when we're done with the current line.
1136
 *
1137
 */
1138
 
1139
    if ( stringcount > 0 )  {
1140
	fprintf(fp_out, ")%d(", stringstart);
1141
	lastx = stringstart = hpos;
1142
	stringcount++;
1143
    }	/* End if */
1144
 
1145
}   /* End of endstring */
1146
 
1147
/*****************************************************************************/
1148
 
1149
oput(ch)
1150
 
1151
    int		ch;			/* next output character */
1152
 
1153
{
1154
 
1155
/*
1156
 *
1157
 * Responsible for adding all printing characters from the input file to the
1158
 * open string on top of the stack. The only other characters that end up in
1159
 * that string are the quotes required for special characters. Reverse printing
1160
 * mode hasn't been tested but it should be close. hpos and lastx should disagree
1161
 * each time (except after startline() does something), and that should force a
1162
 * call to endstring() for every character.
1163
 *
1164
 */
1165
 
1166
    if ( stringcount > 100 )		/* don't put too much on the stack */
1167
	endline();
1168
 
1169
    if ( vpos != lasty )
1170
	endline();
1171
 
1172
    if ( advance == -1 )		/* for reverse printing - move first */
1173
	hmot(hmi);
1174
 
1175
    startline();
1176
 
1177
    if ( lastc != ch || hpos != prevx )  {
1178
	if ( lastx != hpos )
1179
	    endstring();
1180
 
1181
	if ( ch == '\\' || ch == '(' || ch == ')' )
1182
	    putc('\\', fp_out);
1183
	putc(ch, fp_out);
1184
 
1185
	lastc = ch;
1186
	prevx = hpos;
1187
	lastx += lasthmi;
1188
    }	/* End if */
1189
 
1190
    if ( advance != -1 )
1191
	hmot(hmi);
1192
 
1193
    markedpage = TRUE;
1194
 
1195
}   /* End of oput */
1196
 
1197
/*****************************************************************************/
1198
 
1199
redirect(pg)
1200
 
1201
    int		pg;			/* next page we're printing */
1202
 
1203
{
1204
 
1205
    static FILE	*fp_null = NULL;	/* if output is turned off */
1206
 
1207
/*
1208
 *
1209
 * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
1210
 * otherwise output goes to stdout.
1211
 *
1212
 */
1213
 
1214
    if ( pg >= 0 && in_olist(pg) == ON )
1215
	fp_out = stdout;
1216
    else if ( (fp_out = fp_null) == NULL )
1217
	fp_out = fp_null = fopen("/dev/null", "w");
1218
 
1219
}   /* End of redirect */
1220
 
1221
/*****************************************************************************/
1222