summaryrefslogtreecommitdiff
path: root/dviware/beebe/utils/lw78.c
blob: 3f30e01f9b76b0c28b0869d6ab812dab32fae242 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
/* -*-C-*- lw78.c */
/*-->lw78*/
/**********************************************************************/
/******************************** lw78 ********************************/
/**********************************************************************/
/* <BEEBE.TEX.DVI>LW78.C.27, 29-Oct-87 16:01:55, Edit by BEEBE */
/* Added DOBE JSYS (dismiss process until output buffer empty) in */
/* Put_Packet(); this seems to have completely eliminated the I/O error */
/* conditions previously experienced; they were probably due to ALW+ */
/* buffer overruns.  A straight "COPY foo.ps ttynn:" got only 3 pages */
/* out before the ALW+ said "I/O error", which is what led me to */
/* suspect that overrun might be responsible for our ALW+ miserable */
/* performance. */
/* <BEEBE.TEX.DVI.NEW>LW78.C.9, 24-Sep-86 22:49:07, Edit by BEEBE */
/* Add -n (notify user) option */
/* <BEEBE.TEX.DVI.NEW>LW78.C.5, 19-Aug-86 14:13:53, Edit by BEEBE */
/* Change check for PostScript header to "%!" and add PShdrfile (-h) */
/* option support. */
/* <BEEBE.TEX.DVI>LW78.C.15,  2-Dec-85 18:41:26, Edit by BEEBE */
/* Add check for PostScript header in Copy_File */
/* <BEEBE.TEX.DVI>LW78.C.11, 21-Nov-85 12:05:20, Edit by BEEBE */
/* Add Time_Stamp() and calls thereto for each output line */
/***********************************************************************
Apple LaserWriter copy utility.

Copy one or more 7-bit files in binary mode to an 8-bit file, halting on
input from the output  device after printing the  contents of the  input
buffer.

Usage:
        lw78 [-aAcctFile] [-d] [-en] [-hPShdrfile] [-n] [-r] \
		-oOutfile infile1 [infile2] ... [infilek]

Letter case on the  switch is ignored.

The optional  -a switch  specifies a  page accounting  file to  which  a
single entry will be  made recording a time  stampe, username, and  page
count for each file processed.

The -d switch causes a delete and expunge of each file after  processing
it.

The -en switch optionally sends ASCII character n after each file.

The -h switch defines an optional header file which will be prefixed
to non-PostScript files to allow them to be printed.

The -n switch requests that each file owner be sent a message when the
file has been printed.

The -r switch causes the files to be processed in reverse order  (useful
because of the reversed stacking of the LaserWriter).

[24-Sep-86]
***********************************************************************/

#include <stdio.h>

#ifndef KCC_20
#define KCC_20 0
#endif

#ifndef PCC_20
#define PCC_20 0
#endif

#if    (KCC_20 | PCC_20)
#else
#undef PCC_20
#define PCC_20 1
#endif

#if    KCC_20
#include <jsys.h>

/* KCC-20 and PCC-20  have similar enough JSYS  interfaces that we  just
define values for KCC-20 using PCC-20 names,  and copy in definitions of
a few macros from PCC-20's tops20.h */
#define JSbin	BIN
#define JSbkjfn	BKJFN
#define JSbout	BOUT
#define JSbout	BOUT
#define JSclosf	CLOSF
#define JSdisms	DISMS
#define JSdobe	DOBE
#define JSdvchr	DVCHR
#define JSgfust	GFUST
#define JSgfust	GFUST
#define JSjfns	JFNS
#define JSmtopr	MTOPR
#define JSmtopr	MTOPR
#define JSmtopr	MTOPR
#define JSopenf	OPENF
#define JSsfcoc	SFCOC
#define JSsfmod	SFMOD
#define JSsibe	SIBE
#define JSsout	SOUT
#define JSstpar	STPAR

#define DVtty 012		/* terminal */
#define DV_typ 0777:35-17	/* device type field */

#define GFlwr 01		/* get file last writer */

#define GJ_fou 01:35-0		/* file is for output use */
#define GJ_sht 01:35-17		/* short call format */

#define MOslw 031		/* set width */
#define MOsll 033		/* set length */
#define MOsnt 034		/* set tty non-terminal status */
#define MOsmn 01		/* no system messages(i.e. suppress) */

#define OF_bsz 077:35-5		/* byte size */
#define OF_rd 01:35-19		/* read */
#define OF_wr 01:35-20		/* write */

#define TT_mff 01:35-1		/* mechanical formfeed present */
#define TT_tab 01:35-2		/* mechanical tab present */
#define TT_lca 01:35-3		/* lower case capabilities present */
#define TT_eco 01:35-24		/* echos on */
#define TT_dam 03:35-29		/* data mode */
#define TTbin 00		/* binary */
#define TT_pgm 01:35-34		/* page mode */

#define Absmask(name) ( (1?name) << (0?name) )    /* maybe use this one */
#define Getmask(name) 	 ( 1?name )
#define Getshift(name)	 ( 0?name )

#define getfield(var, name)	( (var) >> Getshift(name) & Getmask(name) )
#define getright(b)	( (b) & 0777777 )
#define makefield(name, value)	( ((value) & Getmask(name)) << Getshift(name) )
#define makeword(l, r)	( ((l) << 18) | (r) )
#define setfield(var, name, value) ( (var) = ((var) & ~Absmask(name)) |\
	makefield(name, value) )
#else /* must be PCC_20 */
#include <file.h>
#include <monsym.h>
#endif /* KCC_20 */

typedef int BOOLEAN;

#define ACCOUNTING 1			/* define for accounting code */

#define TRUE 1
#define FALSE 0

/* global constants */

#define INTERVAL (5*512)                /* how often to check input buffer */
#define MAXERRMSG 512                   /* error message size */
#define MAXFILENAME 144			/* longest filename */
#define MAXIDLE (10*1000)               /* msec to wait for idle status */
#define MAXLINE 128			/* maximum id line size */
#define MAXPACKET (5*512)               /* packet size to output */
#define MAXPAUSE (500)                  /* msec to wait for new byte */
#define MAXUSERNAME 256			/* longest username */
#define MAXWAIT (5*1000)                /* msec to wait after each file */

#define PSHEADER "%!"			/* what every PostScript file has */

/* global variables */

char author[MAXUSERNAME+1];
BOOLEAN del_flag;                       /* file delete flag */
int eof_char;                           /* end-of-file character */
char errmsg[MAXERRMSG+1];               /* string from output device */
int nbytes;                             /* global input byte count */
BOOLEAN notify_owner;			/* notify file owner when printed */
int npacket;				/* packet[] index */
int packet[MAXPACKET+1];		/* want space for 1 extra eof_char */
char timestr[27];
long timeval;

#if    ACCOUNTING
FILE *acctfile;				/* accounting file */
#endif

FILE *PShdrfile = (FILE *)NULL;		/* PostScript header file */

/* Function macro definitions */

#define BYTEPTR(x) (0004400000000 | (int)((x)-1)) /* x must be int*, not int */
                                        /* PCC uses 36-bit bytes */
#define CTL(c) ((char)(((int)(c)) & 037))
#define GETBYTE(thejfn) (ac1 = thejfn, (void)jsys(JSbin, acs), ac2)
#define HAVE_INPUT(thejfn) (ac1 = thejfn, (void)jsys(JSsibe, acs), (ac2 > 0))
#define MAX(a,b) ((a) > (b) ? (a) : (b))

/* Procedure macro definitions */

#define WAITMS(msec) {ac1 = msec; (void)jsys(JSdisms, acs);}

/* Function/Procedure declarations */

void Copy_File();
char *ctime();
char *fgetname();
int Get_Byte();
void Get_Msg();
void Init_Terminal();
BOOLEAN Input_Error();
void Put_Packet();
long time();
void Time_Stamp();
void Wait_For_Printer_Ready();

/***********************************************************************
It would be nice  to have done this  entirely with getc/putc, but  alas,
PCC will not open an  8-bit file to a  terminal, because it attempts  to
issue an  illegal SFBSZ%  JSYS to  set the  file byte  size, instead  of
checking to see if it is a terminal, and then just setting the byte size
in the OPENF% JSYS.  We therefore use the JSYS interface routines to  do
our own GTJFN%, OPENF%, and BOUT% calls.

Sigh....

***********************************************************************/

main(argc,argv)
int argc;
char* argv[];
{
        BOOLEAN reverse_order;
        register int c,k,len;
        int fp,outjfn,nfile,kfile;
        register FILE* infile;          /* 7-bit file */

        if (argc < 2)
        {
            (void)fprintf(stderr,
              "%%Usage: %s [-aAcctFile] [-d] [-en] [-hPShdrfile] [-n] [-r] \
-ooutfile infile1 [infile2] ... [infilek]\n",
                argv[0]);
            exit(1);
        }

        del_flag = FALSE;
        eof_char = -1;
        nfile = 0;
	notify_owner = FALSE;
        outjfn = -1;
        reverse_order = FALSE;
	PShdrfile = (FILE *)NULL;

#if    ACCOUNTING
	acctfile = (FILE *)NULL;
#endif

        for (k = 1; k < argc; ++k)
        {
            if (*argv[k] != '-')        /* not switch, must be file name */
                nfile++;
#if    ACCOUNTING
            else if ((strncmp("-a",argv[k],2) == 0) ||
                (strncmp("-A",argv[k],2) == 0))
            {
		if ((acctfile = fopen(argv[k]+2,"a")) == (FILE *)NULL)
		{
		    (void)fprintf(stderr,"?Cannot open accounting file [%s]\n",
		        argv[k]+2);
		    exit(1);
		}
	    }
#endif
            else if ((strncmp("-d",argv[k],2) == 0) ||
                (strncmp("-D",argv[k],2) == 0))
                del_flag = TRUE;
            else if ((strncmp("-e",argv[k],2) == 0) ||
                (strncmp("-E",argv[k],2) == 0))
                eof_char = atoi(argv[k]+2);
            else if ((strncmp("-h",argv[k],2) == 0) ||
                (strncmp("-H",argv[k],2) == 0))
            {
		if ((PShdrfile = fopen(argv[k]+2,"r")) == (FILE *)NULL)
		{
		    (void)fprintf(stderr,"?Cannot open PShdrfile [%s]\n",
		        argv[k]+2);
		    exit(1);
		}
	    }
            else if ((strncmp("-n",argv[k],2) == 0) ||
                (strncmp("-N",argv[k],2) == 0))
		notify_owner = TRUE;
            else if ((strncmp("-r",argv[k],2) == 0) ||
                (strncmp("-R",argv[k],2) == 0))
                reverse_order = TRUE;
            else if ((strncmp("-o",argv[k],2) == 0) ||
                (strncmp("-O",argv[k],2) == 0))
            {
                if ((outjfn = _gtjfn(argv[k]+2, makefield(GJ_fou,1) |
                    makefield(GJ_sht,1))) != -1)      /* then got valid jfn */
                {
                    ac1 = outjfn = getright(outjfn);
                    ac2 = makefield(OF_bsz, 8);
                    ac2 = setfield(ac2,OF_wr,1);
                    ac2 = setfield(ac2,OF_rd,1);
                    if (jsys(JSopenf, acs) != JSok)
                        outjfn = -1;    /* open failed */
                }
            }
            else
            {
                (void)fprintf(stderr,"?Unknown switch [%s]\n",argv[k]);
                exit(1);
            }
        }
        if (outjfn == -1)
        {
            (void)fprintf(stderr,"?Cannot open output file\n");
            exit(1);
        }
        else                /* open okay */
            Init_Terminal(outjfn);

        kfile = 0;
        for (k = (reverse_order ? (argc-1) : 1);
            (0 < k) && (k < argc);
            (reverse_order ? --k : ++k))
        {
            if (*argv[k] == '-')
                ;                       /* ignore switch field */

#if    KCC_20
            else if ((infile = fopen(argv[k],"rb7")) != (FILE*)NULL)
#endif
#if    PCC_20
            else if ((fp = open(argv[k],
                FATT_RDONLY | FATT_SETSIZE | FATT_BINARY,7)) >= 0)
#endif
            {
#if    PCC_20
                infile = fdopen(fp,"rb");
#endif
                Wait_For_Printer_Ready(outjfn);

		Time_Stamp(stderr);
                (void)fprintf(stderr,"[%d of %d: %s]",++kfile,nfile,argv[k]);
                Copy_File(infile,outjfn);
		if (notify_owner)
		{
		    ac1 = makeword(GFlwr,jfnof(fileno(infile)));
		    ac2 = POINT(author);
		    (void)jsys(JSgfust, acs);
		    timeval = time((long*)NULL);
		    strcpy(timestr,ctime(&timeval));
		    len = strlen(timestr) - 1;	/* ctime has its own \n */
		    timestr[len] = '\0';        /* so kill it */
		    (void)sprintf(errmsg,
		        "send %s %s: %s printed on LaserWriter\n",
		        author,timestr,argv[k]);
		    (void)system(errmsg);
		}
                (void)fclose(infile);

                if (del_flag)
                {
                    (void)unlink(argv[k]);      /* delete the file */
                    (void)fprintf(stderr," [OK - deleted]");
                }
                else
                    (void)fprintf(stderr," [OK]");

                if (kfile < nfile)      /* delay next output to try to */
                    WAITMS(MAXWAIT);      /* avoid timeout bug! */
            }
            else
	    {
	        Time_Stamp(stderr);
                (void)fprintf(stderr,"?Cannot open input file [%s]",argv[k]);
	    }
        }

        ac1 = outjfn;
        (void)jsys(JSclosf, acs);
	Time_Stamp(stderr);
	(void)fprintf(stderr,"Spooler terminated\n\n\n\n");
}

void
Copy_File(infile,outjfn)
register FILE* infile;
register int outjfn;
{
    register int c;
    register int k;
    char filename[MAXFILENAME+1];
    char idline[MAXLINE+1];

#if    ACCOUNTING
    int page_count;
    int *pbyte;
#endif

    (void)
    fgets(idline,MAXLINE,infile);	/* peek at first line */
    rewind(infile);

    if (strncmp(idline,PSHEADER,strlen(PSHEADER)) != 0)
    {
	if (PShdrfile != (FILE *)NULL)
	{
		rewind(PShdrfile);
		nbytes = 0;
		while ((npacket = read(fileno(PShdrfile),packet,MAXPACKET)) > 0)
		{
		    nbytes += npacket;
		    Put_Packet(outjfn,packet,npacket);
		    if (Input_Error(PShdrfile,outjfn))
		        return;
		}
	}
	else /* reject non-PostScript file */
	{
            k = MAX(2,strlen(idline));
	    if (idline[k-1] == '\n')
	        idline[k-1] = '\0';		/* kill NL */
	    if (idline[k-2] == '\r')
		idline[k-2] = '\0';		/* kill CR */
	    Time_Stamp(stderr);
	    (void)fprintf(stderr,
	        "?File may not contain PostScript.  First line has\n");
	    (void)fprintf(stderr,"\t[%s] instead of [%s] -- file discarded",
		idline,PSHEADER);
	    return;
	}
    }

#if    ACCOUNTING
    page_count = 0;
#endif

    nbytes = 0;
#if    (INTERVAL-MAXPACKET)		/* copy one at a time */
    npacket = 0;
    while ((c = getc(infile)) != EOF)
    {
#if    ACCOUNTING
        if (c == '\f')
	    page_count++;		/* each FF counts one page */
#endif
        if ((!((++nbytes) % INTERVAL)) && Input_Error(infile,outjfn))
            return;
        if (npacket >= MAXPACKET)
        {
            Put_Packet(outjfn,packet,npacket);
            npacket = 0;
        }
        packet[npacket++] = c;
    }
#else           /* copy in block mode */
    while ((npacket = read(fileno(infile),packet,MAXPACKET)) > 0)
    {
        nbytes += npacket;
        Put_Packet(outjfn,packet,npacket);

#if    ACCOUNTING
	if (acctfile != (FILE*)NULL)
	{
	    for ((pbyte = packet, k = npacket); k; (--k, ++pbyte))
	        if (*pbyte == '\f')
		    page_count++;	/* each FF counts one page */
	}
#endif

        if (Input_Error(infile,outjfn))
            return;
    }
    if (npacket < 0)
    {
        Time_Stamp(stderr);
	(void)fprintf(stderr,"?I/O error on input file");
    }
    npacket = 0;
#endif

    if (eof_char >= 0)
        packet[npacket++] = eof_char;
    if (npacket > 0)

        Put_Packet(outjfn,packet,npacket);

#if    ACCOUNTING
    if (acctfile != (FILE*)NULL)
    {
	ac1 = makeword(GFlwr,jfnof(fileno(infile)));
	ac2 = POINT(author);
	(void)jsys(JSgfust, acs);
	Time_Stamp(acctfile);
	(void)fprintf(acctfile,"%8d\t%s\t%s",
	    MAX(1,page_count),author,fgetname(infile,filename));
    }
#endif

}

int
Get_Byte(thejfn)                        /* get byte (maybe waiting) */
register int thejfn;                    /* returns EOF if no input */
{
    if (HAVE_INPUT(thejfn))
        return(GETBYTE(thejfn));

    WAITMS(MAXPAUSE);

    if (HAVE_INPUT(thejfn))
        return(GETBYTE(thejfn));
    else                                /* still no input */
        return(EOF);
}

void
Get_Msg(thejfn)
int thejfn;
{
    register int cm1,cm2,c,k;

    Time_Stamp(stderr);
    k = 0;
    c = 0;
    cm1 = 0;
    cm2 = 0;
    while (!((cm2 == ']') && (cm1 == '%') && (c == '%'))) /* until "]%%" */
    {   /* skip <garbage> and collect %%[ ... ]%% */
        cm2 = cm1;
        cm1 = c;
        if ((c = Get_Byte(thejfn)) == EOF)
            break;                      /* no input yet */
        if ((cm2 == '%') && (cm1 == '%') && (c == '['))
        {                               /* restart message collection */
            k = 2;
            errmsg[0] = '%';
            errmsg[1] = '%';
        }
        if (k < MAXERRMSG)
            errmsg[k++] = c;
        putc(c,stderr);
    }


    errmsg[k] = '\0';                   /* terminate string */

    while (TRUE)                        /* "infinite" loop to discard any */
                                        /* remaining input up to start of */
                                        /* next message */
    {

        if ((c = Get_Byte(thejfn)) == EOF)
            break;                      /* no input, so exit loop */

        if (c == '%')                   /* if start of new message then */
        {                               /* put character back and exit */
            ac1 = thejfn;
            (void)jsys(JSbkjfn,acs);
            break;
        }

	if (!((c == '\r') || (c == '\n')))/* echo the character */
	    putc(c,stderr);		/* but discard terminal CR LF */
    }					/* to avoid unwanted blank lines */
}

void
Init_Terminal(thejfn)
register int thejfn;
{
    ac1 = thejfn;
    (void)jsys(JSdvchr, acs);           /* get device characteristics */

    if (getfield(ac2,DV_typ) == DVtty)
    {                                   /* have terminal, set its features */
        ac1 = thejfn;
        ac2 = MOsnt;
        ac3 = MOsmn;                    /* no system messages */
        (void)jsys(JSmtopr, acs);

        ac1 = thejfn;
        ac2 = makefield(TT_mff,1);      /* has formfeed */
        ac2 = setfield(ac2,TT_tab,1);   /* has tab */
        ac2 = setfield(ac2,TT_lca,1);   /* has lowercase */
        ac2 = setfield(ac2,TT_pgm,1);   /* has X-on/X-off */
        (void)jsys(JSstpar, acs);

        ac1 = thejfn;
        ac2 = makefield(TT_dam,TTbin);  /* binary output */
        ac2 = setfield(ac2,TT_eco,0);   /* no echo */
        (void)jsys(JSsfmod, acs);

        ac1 = thejfn;
        ac2 = 0525252525252;
        ac3 = 0525252525252;            /* no CTL-char translation */
        (void)jsys(JSsfcoc, acs);

        ac1 = thejfn;
        ac2 = MOslw;
        ac3 = 0;                        /* line width = 0 */
        (void)jsys(JSmtopr, acs);

        ac1 = thejfn;
        ac2 = MOsll;
        ac3 = 0;                        /* page length = 0 */
        (void)jsys(JSmtopr, acs);
    }
}

BOOLEAN
Input_Error(infile,thejfn)		/* return TRUE if error */
register FILE* infile;
register int thejfn;
{
    register int c;

    if (HAVE_INPUT(thejfn))
    {
        Get_Msg(thejfn);
        if (strncmp(errmsg,"%%[ Error: timeout;",19) == 0)
        {
            Time_Stamp(stderr);
	    (void)fprintf(stderr,"[Error occurred in input byte range %d..%d]",
                MAX(0,nbytes-32),nbytes);
            Time_Stamp(stderr);
	    (void)fprintf(stderr,
            "Attempting to recover from Apple LaserWriter BUG of \
timeout error");
            (void)fflush(stderr);
            return(FALSE);
        }
	else if (strncmp(errmsg,"%%[ PrinterError: out of paper",30) == 0)
	{
	    Time_Stamp(stderr);
	    (void)fprintf(stderr,"\t[Waiting 10 sec for paper]");
	    (void)fflush(stderr);
	    WAITMS(10000);
	    return(FALSE);
	}
	else if (strncmp(errmsg,"%%[ PrinterError: no paper tray",31) == 0)
	{
	    Time_Stamp(stderr);
	    (void)fprintf(stderr,"\t[Waiting 10 sec for paper tray]");
	    (void)fflush(stderr);
	    WAITMS(10000);
	    return(FALSE);
	}
        else if (strncmp(errmsg,"%%[ Error: VMerror;",19) == 0)
        {
            Time_Stamp(stderr);
	    (void)fprintf(stderr,
            "Attempting to recover from Apple LaserWriter BUG of VMerror");
            (void)fflush(stderr);
	    Wait_For_Printer_Ready(thejfn);
	    do				/* skip to next page or end-of-job */
	    {
		c = getc(infile);
	    }
	    while ((c != EOF) && (c != CTL('D')) && (c != CTL('L')));
	    npacket = 0;		/* discard last packet */
            return(FALSE);
        }
        else if (strcmp(errmsg,"%%[ status: idle ]%%") == 0)
            return(FALSE);
        else
        {
            Time_Stamp(stderr);
	    (void)fprintf(stderr,"[Error occurred in input byte range %d..%d]",
                MAX(0,nbytes-32),nbytes);
	    Time_Stamp(stderr);
            (void)fprintf(stderr,"[Job flushed]");
            (void)fflush(stderr);
            return(TRUE);
        }
    }
    else                                /* no input yet */
        return(FALSE);
}

void
Put_Packet(thejfn,packet,n)
int thejfn;
int packet[];
int n;
{
    ac1 = thejfn;
    (void)jsys(JSdobe, acs);		/* wait until output buffer empty */

    ac1 = thejfn;
    ac2 = BYTEPTR(packet);
    ac3 = -n;                           /* exact byte count */
    ac4 = 0;
    if (n > 0)
    {
        if (jsys(JSsout, acs) != JSok)
        {
	    Time_Stamp(stderr);
            (void)fprintf(stderr,"?SOUT error");
            exit(1);
        }
    }

}

void
Time_Stamp(fp)
FILE *fp;
{
    int k;

    timeval = time((long*)NULL);
    strcpy(timestr,ctime(&timeval));
    k = strlen(timestr) - 1;	/* ctime has its own \n */
    timestr[k] = '\0';          /* so kill it */
    (void)fprintf(fp,"\n%s\t",timestr);
}

void
Wait_For_Printer_Ready(thejfn)
register int thejfn;
{
    while (TRUE)                        /* "infinite" loop */
    {
        ac1 = thejfn;
        ac2 = CTL('T');                 /* CTL-T for status message */
        (void)jsys(JSbout, acs);

        ac1 = thejfn;
        (void)jsys(JSdobe, acs);        /* wait until output sent */

        Get_Msg(thejfn);
        if (strcmp(errmsg,"%%[ status: idle ]%%") == 0)
            break;                      /* printer ready to go */

        ac1 = thejfn;
        ac2 = CTL('D');                 /* CTL-D to terminate previous job */
        (void)jsys(JSbout, acs);

	Time_Stamp(stderr);
        (void)fprintf(stderr,"\t[Waiting %d sec]",MAXIDLE/1000);

        WAITMS(MAXIDLE);
    }
}

char *
fgetname(fp,buffer)
FILE *fp;
char buffer[];
{
    ac1 = POINT(buffer);
    ac2 = jfnof(fileno(fp));
    ac3 = 0;
    ac4 = 0;
    buffer[0] = '\0';
    (void)jsys(JSjfns, acs);
    return(buffer);
}