Annotation of researchv10no/cmd/post.src/postio/postio.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *
        !             3:  * postio - RS-232 serial interface for PostScript printers
        !             4:  *
        !             5:  * A simple program that manages input and output for PostScript printers. Much
        !             6:  * has been added and changed from early versions of the program, but the basic
        !             7:  * philosophy is still the same. Don't send real data until we're certain we've
        !             8:  * connected to a PostScript printer that's in the idle state and try to hold the
        !             9:  * connection until the job is completely done. It's more work than you might
        !            10:  * expect is necessary, but should provide a reasonably reliable spooler interface
        !            11:  * that can return error indications to the caller via the program's exit status.
        !            12:  *
        !            13:  * I've added code that will let you split the program into separate read/write
        !            14:  * processes. Although it's not the default it should be useful if you have a file
        !            15:  * that will be returning useful data from the printer. The two process stuff was
        !            16:  * laid down on top of the single process code and both methods still work. The
        !            17:  * implementation isn't as good as it could be, but didn't require many changes
        !            18:  * to the original program (despite the fact that there are now many differences).
        !            19:  *
        !            20:  * By default the program still runs as a single process. The -R2 option forces
        !            21:  * separate read and write processes after the intial connection is made. If you
        !            22:  * want that as the default initialize splitme (below) to TRUE. In addition the
        !            23:  * -t option that's used to force stuff not recognized as status reports to stdout
        !            24:  * also tries to run as two processes (by setting splitme to TRUE). It will only
        !            25:  * work if the required code (ie. resetline() in ifdef.c) has been implemented
        !            26:  * for your Unix system. I've only tested the System V code.
        !            27:  *
        !            28:  * Code needed to support interactive mode has also been added, although again it's
        !            29:  * not as efficient as it could be. It depends on the system dependent procedures
        !            30:  * resetline() and setupstdin() (file ifdef.c) and for now is only guaranteed to
        !            31:  * work on System V. Can be requested using the -i option.
        !            32:  *
        !            33:  * Quiet mode (-q option) is also new, but was needed for some printers connected
        !            34:  * to RADIAN. If you're running in quiet mode no status requests will be sent to
        !            35:  * the printer while files are being transmitted (ie. in send()).
        !            36:  *
        !            37:  * The program expects to receive printer status lines that look like,
        !            38:  *
        !            39:  *     %%[ status: idle; source: serial 25 ]%%
        !            40:  *     %%[ status: waiting; source: serial 25 ]%%
        !            41:  *     %%[ status: initializing; source: serial 25 ]%%
        !            42:  *     %%[ status: busy; source: serial 25 ]%%
        !            43:  *     %%[ status: printing; source: serial 25 ]%%
        !            44:  *     %%[ status: PrinterError: out of paper; source: serial 25 ]%%
        !            45:  *     %%[ status: PrinterError: no paper tray; source: serial 25 ]%%
        !            46:  *
        !            47:  * although this list isn't complete. Sending a '\024' (control T) character forces
        !            48:  * the return of a status report. PostScript errors detected on the printer result
        !            49:  * in the immediate transmission of special error messages that look like,
        !            50:  *
        !            51:  *     %%[ Error: undefined; OffendingCommand: xxx ]%%
        !            52:  *     %%[ Flushing: rest of job (to end-of-file) will be ignored ]%%
        !            53:  *
        !            54:  * although we only use the Error and Flushing keywords. Finally conditions, like
        !            55:  * being out of paper, result in other messages being sent back from the printer
        !            56:  * over the communications line. Typical PrinterError messages look like,
        !            57:  *
        !            58:  *     %%[ PrinterError: out of paper; source: serial 25 ]%%
        !            59:  *     %%[ PrinterError: paper jam; source: serial 25 ]%%
        !            60:  *
        !            61:  * although we only use the PrinterError keyword rather than trying to recognize
        !            62:  * all possible printer errors.
        !            63:  *
        !            64:  * The implications of using one process and only flow controlling data going to
        !            65:  * the printer are obvious. Job transmission should be reliable, but there can be
        !            66:  * data loss in stuff sent back from the printer. Usually that only caused problems
        !            67:  * with jobs designed to run on the printer and return useful data back over the
        !            68:  * communications line. If that's the kind of job you're sending call postio with
        !            69:  * the -t option. That should force the program to split into separate read and
        !            70:  * write processes and everything not bracketed by "%%[ " and " ]%%" strings goes
        !            71:  * to stdout. In otherwords the data you're expecting should be separated from the
        !            72:  * status stuff that goes to the log file (or stderr). The -R2 option does almost
        !            73:  * the same thing (ie. separate read and write processes), but everything that
        !            74:  * comes back from the printer goes to the log file (stderr by default) and you'll
        !            75:  * have to separate your data from any printer messages.
        !            76:  *
        !            77:  * A typical command line might be,
        !            78:  *
        !            79:  *     postio -l /dev/tty01 -b 9600 -L log file1 file2
        !            80:  *
        !            81:  * where -l selects the line, -b sets the baud rate, and -L selects the printer
        !            82:  * log file. Since there's no default line, at least not right now, you'll always
        !            83:  * need to use the -l option, and if you don't choose a log file stderr will be
        !            84:  * used. If you have a program that will be returning data the command line might
        !            85:  * look like,
        !            86:  *
        !            87:  *     postio -t -l/dev/tty01 -b9600 -Llog file >results
        !            88:  *
        !            89:  * Status stuff goes to file log while the data you're expecting back from the
        !            90:  * printer gets put in file results.
        !            91:  *
        !            92:  */
        !            93: 
        !            94: #include <stdio.h>
        !            95: #include <ctype.h>
        !            96: #include <fcntl.h>
        !            97: #include <signal.h>
        !            98: #include <sys/types.h>
        !            99: #include <errno.h>
        !           100: 
        !           101: #include "ifdef.h"                     /* conditional compilation stuff */
        !           102: #include "gen.h"                       /* general purpose definitions */
        !           103: #include "postio.h"                    /* some special definitions */
        !           104: 
        !           105: char   **argv;                         /* global so everyone can use them */
        !           106: int    argc;
        !           107: 
        !           108: char   *prog_name = "";                /* really just for error messages */
        !           109: int    x_stat = 0;                     /* program exit status */
        !           110: int    debug = OFF;                    /* debug flag */
        !           111: int    ignore = OFF;                   /* what's done for FATAL errors */
        !           112: 
        !           113: char   *line = NULL;                   /* printer is on this tty line */
        !           114: short  baudrate = BAUDRATE;            /* and running at this baud rate */
        !           115: Baud   baudtable[] = BAUDTABLE;        /* converts strings to termio values */
        !           116: 
        !           117: int    stopbits = 1;                   /* number of stop bits */
        !           118: int    tostdout = FALSE;               /* non-status stuff goes to stdout? */
        !           119: int    quiet = FALSE;                  /* no status queries in send() if TRUE */
        !           120: int    interactive = FALSE;            /* interactive mode */
        !           121: char   *postbegin = POSTBEGIN;         /* preceeds all the input files */
        !           122: int    useslowsend = FALSE;            /* not recommended! */
        !           123: int    sendctrlC = TRUE;               /* interrupt with ctrl-C when BUSY */
        !           124: int    window_size = -1;               /* for Datakit - use -w */
        !           125: 
        !           126: char   *block = NULL;                  /* input file buffer */
        !           127: int    blocksize = BLOCKSIZE;          /* and its size in bytes */
        !           128: int    head = 0;                       /* block[head] is the next character */
        !           129: int    tail = 0;                       /* one past the last byte in block[] */
        !           130: 
        !           131: int    splitme = FALSE;                /* into READ and WRITE processes if TRUE */
        !           132: int    whatami = READWRITE;            /* a READ or WRITE process - or both */
        !           133: int    canread = TRUE;                 /* allow reads */
        !           134: int    canwrite = TRUE;                /* and writes if TRUE */
        !           135: int    otherpid = -1;                  /* who gets signals if greater than 1 */
        !           136: int    joinsig = SIGTRAP;              /* reader gets this when writing is done */
        !           137: int    writedone = FALSE;              /* and then sets this to TRUE */
        !           138: 
        !           139: char   mesg[MESGSIZE];                 /* exactly what came back on ttyi */
        !           140: char   sbuf[MESGSIZE];                 /* for parsing the message */
        !           141: int    next = 0;                       /* next character goes in mesg[next] */
        !           142: char   *mesgptr = NULL;                /* printer message starts here in mesg[] */
        !           143: char   *endmesg = NULL;                /* as far as readline() can go in mesg[] */
        !           144: 
        !           145: Status status[] = STATUS;              /* for converting status strings */
        !           146: int    nostatus = NOSTATUS;            /* default getstatus() return value */
        !           147: 
        !           148: int    currentstate = NOTCONNECTED;    /* what's happening START, SEND, or DONE */
        !           149: 
        !           150: int    ttyi = 0;                       /* input */
        !           151: int    ttyo = 2;                       /* and output file descriptors */
        !           152: 
        !           153: FILE   *fp_log = stderr;               /* log file for stuff from the printer */
        !           154: 
        !           155: /*****************************************************************************/
        !           156: 
        !           157: main(agc, agv)
        !           158: 
        !           159:     int                agc;
        !           160:     char       *agv[];
        !           161: 
        !           162: {
        !           163: 
        !           164: /*
        !           165:  *
        !           166:  * A simple program that manages input and output for PostScript printers. Can run
        !           167:  * as a single process or as separate read/write processes. What's done depends on
        !           168:  * the value assigned to splitme when split() is called.
        !           169:  *
        !           170:  */
        !           171: 
        !           172:     argc = agc;                                /* other routines may want them */
        !           173:     argv = agv;
        !           174: 
        !           175:     prog_name = argv[0];               /* really just for error messages */
        !           176: 
        !           177:     init_signals();                    /* sets up interrupt handling */
        !           178:     options();                         /* get command line options */
        !           179:     initialize();                      /* must be done after options() */
        !           180:     start();                           /* make sure the printer is ready */
        !           181:     split();                           /* into read/write processes - maybe */
        !           182:     arguments();                       /* then send each input file */
        !           183:     done();                            /* wait until the printer is finished */
        !           184:     cleanup();                         /* make sure the write process stops */
        !           185: 
        !           186:     exit(x_stat);                      /* everything probably went OK */
        !           187: 
        !           188: }   /* End of main */
        !           189: 
        !           190: /*****************************************************************************/
        !           191: 
        !           192: init_signals()
        !           193: 
        !           194: {
        !           195: 
        !           196:     void       interrupt();            /* handles them if we catch signals */
        !           197: 
        !           198: /*
        !           199:  *
        !           200:  * Makes sure we handle interrupts. The proper way to kill the program, if
        !           201:  * necessary, is to do a kill -15. That forces a call to interrupt(), which in
        !           202:  * turn tries to reset the printer and then exits with a non-zero status. If the
        !           203:  * program is running as two processes, sending SIGTERM to either the parent or
        !           204:  * child should clean things up.
        !           205:  *
        !           206:  */
        !           207: 
        !           208:     if ( signal(SIGINT, interrupt) == SIG_IGN )  {
        !           209:        signal(SIGINT, SIG_IGN);
        !           210:        signal(SIGQUIT, SIG_IGN);
        !           211:        signal(SIGHUP, SIG_IGN);
        !           212:     } else {
        !           213:        signal(SIGHUP, interrupt);
        !           214:        signal(SIGQUIT, interrupt);
        !           215:     }  /* End else */
        !           216: 
        !           217:     signal(SIGTERM, interrupt);
        !           218: 
        !           219: }   /* End of init_sig */
        !           220: 
        !           221: /*****************************************************************************/
        !           222: 
        !           223: options()
        !           224: 
        !           225: {
        !           226: 
        !           227:     int                ch;                     /* return value from getopt() */
        !           228:     char       *optnames = "b:cil:qs:tw:B:L:P:R:SDI";
        !           229: 
        !           230:     extern char        *optarg;                /* used by getopt() */
        !           231:     extern int optind;
        !           232: 
        !           233: /*
        !           234:  *
        !           235:  * Reads and processes the command line options. The -R2, -t, and -i options all
        !           236:  * force separate read and write processes by eventually setting splitme to TRUE
        !           237:  * (check initialize()). The -S option is not recommended and should only be used
        !           238:  * as a last resort!
        !           239:  *
        !           240:  */
        !           241: 
        !           242:     while ( (ch = getopt(argc, argv, optnames)) != EOF )  {
        !           243:        switch ( ch )  {
        !           244:            case 'b':                   /* baud rate string */
        !           245:                    baudrate = getbaud(optarg);
        !           246:                    break;
        !           247: 
        !           248:            case 'c':                   /* no ctrl-C's */
        !           249:                    sendctrlC = FALSE;
        !           250:                    break;
        !           251: 
        !           252:            case 'i':                   /* interactive mode */
        !           253:                    interactive = TRUE;
        !           254:                    break;
        !           255: 
        !           256:            case 'l':                   /* printer line */
        !           257:                    line = optarg;
        !           258:                    break;
        !           259: 
        !           260:            case 'q':                   /* no status queries - for RADIAN? */
        !           261:                    quiet = TRUE;
        !           262:                    break;
        !           263: 
        !           264:            case 's':                   /* use 2 stop bits - for UNISON? */
        !           265:                    if ( (stopbits = atoi(optarg)) < 1 || stopbits > 2 )
        !           266:                        stopbits = 1;
        !           267:                    break;
        !           268: 
        !           269:            case 't':                   /* non-status stuff goes to stdout */
        !           270:                    tostdout = TRUE;
        !           271:                    break;
        !           272: 
        !           273:            case 'w':                   /* Datakit window size */
        !           274:                    window_size = atoi(optarg);
        !           275:                    break;
        !           276: 
        !           277:            case 'B':                   /* set the job buffer size */
        !           278:                    if ( (blocksize = atoi(optarg)) <= 0 )
        !           279:                        blocksize = BLOCKSIZE;
        !           280:                    break;
        !           281: 
        !           282:            case 'L':                   /* printer log file */
        !           283:                    if ( (fp_log = fopen(optarg, "w")) == NULL )  {
        !           284:                        fp_log = stderr;
        !           285:                        error(NON_FATAL, "can't open log file %s", optarg);
        !           286:                    }   /* End if */
        !           287:                    break;
        !           288: 
        !           289:            case 'P':                   /* initial PostScript code */
        !           290:                    postbegin = optarg;
        !           291:                    break;
        !           292: 
        !           293:            case 'R':                   /* run as one or two processes */
        !           294:                    if ( atoi(optarg) == 2 )
        !           295:                        splitme = TRUE;
        !           296:                    else splitme = FALSE;
        !           297:                    break;
        !           298: 
        !           299:            case 'S':                   /* slow and kludged up version of send */
        !           300:                    useslowsend = TRUE;
        !           301:                    break;
        !           302: 
        !           303:            case 'D':                   /* debug flag */
        !           304:                    debug = ON;
        !           305:                    break;
        !           306: 
        !           307:            case 'I':                   /* ignore FATAL errors */
        !           308:                    ignore = ON;
        !           309:                    break;
        !           310: 
        !           311:            case '?':                   /* don't understand the option */
        !           312:                    error(FATAL, "");
        !           313:                    break;
        !           314: 
        !           315:            default:                    /* don't know what to do for ch */
        !           316:                    error(FATAL, "missing case for option %c\n", ch);
        !           317:                    break;
        !           318:        }   /* End switch */
        !           319:     }   /* End while */
        !           320: 
        !           321:     argc -= optind;                    /* get ready for non-option args */
        !           322:     argv += optind;
        !           323: 
        !           324: }   /* End of options */
        !           325: 
        !           326: /*****************************************************************************/
        !           327: 
        !           328: getbaud(rate)
        !           329: 
        !           330:     char       *rate;                  /* string representing the baud rate */
        !           331: 
        !           332: {
        !           333: 
        !           334:     int                i;                      /* for looking through baudtable[] */
        !           335: 
        !           336: /*
        !           337:  *
        !           338:  * Called from options() to convert a baud rate string into an appropriate termio
        !           339:  * value. *rate is looked up in baudtable[] and if it's found, the corresponding
        !           340:  * value is returned to the caller.
        !           341:  *
        !           342:  */
        !           343: 
        !           344:     for ( i = 0; baudtable[i].rate != NULL; i++ )
        !           345:        if ( strcmp(rate, baudtable[i].rate) == 0 )
        !           346:            return(baudtable[i].val);
        !           347: 
        !           348:     error(FATAL, "don't recognize baud rate %s", rate);
        !           349: 
        !           350: }   /* End of getbaud */
        !           351: 
        !           352: /*****************************************************************************/
        !           353: 
        !           354: initialize()
        !           355: 
        !           356: {
        !           357: 
        !           358: /*
        !           359:  *
        !           360:  * Initialization, a few checks, and a call to setupline() (file ifdef.c) to open
        !           361:  * and configure the communications line. Settings for interactive mode always
        !           362:  * take precedence. The setupstdin() call with an argument of 0 saves the current
        !           363:  * terminal settings if interactive mode has been requested - otherwise nothing's
        !           364:  * done. Unbuffering stdout (via the setbuf() call) isn't really needed on System V
        !           365:  * since it's flushed whenever terminal input is requested. It's more efficient if
        !           366:  * we buffer the stdout (on System V) but safer (for other versions of Unix) if we
        !           367:  * include the setbuf() call.
        !           368:  *
        !           369:  */
        !           370: 
        !           371:     whatami = READWRITE;               /* always run start() as one process */
        !           372:     canread = canwrite = TRUE;
        !           373: 
        !           374:     if ( tostdout == TRUE )            /* force separate read/write processes */
        !           375:        splitme = TRUE;
        !           376: 
        !           377:     if ( interactive == TRUE )  {      /* interactive mode settings always win */
        !           378:        quiet = FALSE;
        !           379:        tostdout = FALSE;
        !           380:        splitme = TRUE;
        !           381:        blocksize = 1;
        !           382:        postbegin = NULL;
        !           383:        useslowsend = FALSE;
        !           384:        nostatus = INTERACTIVE;
        !           385:        setbuf(stdout, NULL);
        !           386:     }  /* End if */
        !           387: 
        !           388:     if ( useslowsend == TRUE )  {      /* last resort only - not recommended */
        !           389:        quiet = FALSE;
        !           390:        splitme = FALSE;
        !           391:        if ( blocksize > 1024 )         /* don't send too much all at once */
        !           392:            blocksize = 1024;
        !           393:     }  /* End if */
        !           394: 
        !           395:     if ( tostdout == TRUE && fp_log == stderr )
        !           396:        fp_log = NULL;
        !           397: 
        !           398:     if ( line == NULL && (interactive == TRUE || tostdout == TRUE) )
        !           399:        error(FATAL, "a printer line must be supplied - use the -l option");
        !           400: 
        !           401:     if ( (block = malloc(blocksize)) == NULL )
        !           402:        error(FATAL, "no memory");
        !           403: 
        !           404:     endmesg = mesg + sizeof mesg - 2;  /* one byte from last position in mesg */
        !           405: 
        !           406:     setupline();                       /* configure the communications line */
        !           407:     setupstdin(0);                     /* save current stdin terminal settings */
        !           408: 
        !           409: }   /* End of initialize */
        !           410: 
        !           411: /*****************************************************************************/
        !           412: 
        !           413: start()
        !           414: 
        !           415: {
        !           416: 
        !           417: /*
        !           418:  *
        !           419:  * Tries to put the printer in the IDLE state before anything important is sent.
        !           420:  * Run as a single process no matter what has been assigned to splitme. Separate
        !           421:  * read and write processes, if requested, will be created after we're done here.
        !           422:  *
        !           423:  */
        !           424: 
        !           425:     logit("printer startup\n");
        !           426: 
        !           427:     currentstate = START;
        !           428:     clearline();
        !           429: 
        !           430:     while ( 1 )
        !           431:        switch ( getstatus(1) )  {
        !           432:            case IDLE:
        !           433:            case INTERACTIVE:
        !           434:                    if ( postbegin != NULL && *postbegin != '\0' )
        !           435:                        Write(ttyo, postbegin, strlen(postbegin));
        !           436:                    clearline();
        !           437:                    return;
        !           438: 
        !           439:            case BUSY:
        !           440:                    if ( sendctrlC == TRUE ) {
        !           441:                        Write(ttyo, "\003", 1);
        !           442:                        Rest(1);
        !           443:                    }   /* End if */
        !           444:                    break;
        !           445: 
        !           446:            case WAITING:
        !           447:            case ERROR:
        !           448:            case FLUSHING:
        !           449:                    Write(ttyo, "\004", 1);
        !           450:                    Rest(1);
        !           451:                    break;
        !           452: 
        !           453:            case PRINTERERROR:
        !           454:                    Rest(15);
        !           455:                    break;
        !           456: 
        !           457:            case DISCONNECT:
        !           458:                    error(FATAL, "Disconnected - printer may be offline");
        !           459:                    break;
        !           460: 
        !           461:            case ENDOFJOB:
        !           462:            case UNKNOWN:
        !           463:                    clearline();
        !           464:                    break;
        !           465: 
        !           466:            default:
        !           467:                    Rest(1);
        !           468:                    break;
        !           469:        }   /* End switch */
        !           470: 
        !           471: }   /* End of start */
        !           472: 
        !           473: /*****************************************************************************/
        !           474: 
        !           475: split()
        !           476: 
        !           477: {
        !           478: 
        !           479:     int                pid;
        !           480:     void       interrupt();
        !           481: 
        !           482: /*
        !           483:  *
        !           484:  * If splitme is TRUE we fork a process, make the parent handle reading, and let
        !           485:  * the child take care of writing. resetline() (file ifdef.c) contains all the
        !           486:  * system dependent code needed to reset the communications line for separate
        !           487:  * read and write processes. For now it's expected to return TRUE or FALSE and
        !           488:  * that value controls whether we try the fork. I've only tested the two process
        !           489:  * stuff for System V. Other versions of resetline() may just be dummy procedures
        !           490:  * that always return FALSE. If the fork() failed previous versions continued as
        !           491:  * a single process, although the implementation wasn't quite right, but I've now
        !           492:  * decided to quit. The main reason is a Datakit channel may be configured to
        !           493:  * flow control data in both directions, and if we run postio over that channel
        !           494:  * as a single process we likely will end up in deadlock.
        !           495:  *
        !           496:  */
        !           497: 
        !           498:     if ( splitme == TRUE )
        !           499:        if ( resetline() == TRUE )  {
        !           500:            pid = getpid();
        !           501:            signal(joinsig, interrupt);
        !           502:            if ( (otherpid = fork()) == -1 )
        !           503:                error(FATAL, "can't fork");
        !           504:            else if ( otherpid == 0 )  {
        !           505:                whatami = WRITE;
        !           506:                nostatus = WRITEPROCESS;
        !           507:                otherpid = pid;
        !           508:                setupstdin(1);
        !           509:            } else whatami = READ;
        !           510:        } else if ( interactive == TRUE || tostdout == TRUE )
        !           511:            error(FATAL, "can't create two process - check resetline()");
        !           512:        else error(NON_FATAL, "running as a single process - check resetline()");
        !           513: 
        !           514:     canread = (whatami & READ) ? TRUE : FALSE;
        !           515:     canwrite = (whatami & WRITE) ? TRUE : FALSE;
        !           516: 
        !           517: }   /* End of split */
        !           518: 
        !           519: /*****************************************************************************/
        !           520: 
        !           521: arguments()
        !           522: 
        !           523: {
        !           524: 
        !           525:     int                fd_in;                  /* next input file */
        !           526: 
        !           527: /*
        !           528:  *
        !           529:  * Makes sure all the non-option command line arguments are processed. If there
        !           530:  * aren't any arguments left when we get here we'll send stdin. Input files are
        !           531:  * only read and sent to the printer if canwrite is TRUE. Checking it here means
        !           532:  * we won't have to do it in send(). If interactive mode is TRUE we'll stay here
        !           533:  * forever sending stdin when we run out of files - exit with a break. Actually
        !           534:  * the loop is bogus and used at most once when we're in interactive mode because
        !           535:  * stdin is in a pseudo raw mode and the read() in readblock() should never see
        !           536:  * the end of file.
        !           537:  *
        !           538:  */
        !           539: 
        !           540:     if ( canwrite == TRUE )
        !           541:        do                              /* loop is for interactive mode */
        !           542:            if ( argc < 1 )
        !           543:                send(fileno(stdin), "pipe.end");
        !           544:            else  {
        !           545:                while ( argc > 0 )  {
        !           546:                    if ( (fd_in = open(*argv, O_RDONLY)) == -1 )
        !           547:                        error(FATAL, "can't open %s", *argv);
        !           548:                    send(fd_in, *argv);
        !           549:                    close(fd_in);
        !           550:                    argc--;
        !           551:                    argv++;
        !           552:                }   /* End while */
        !           553:            }   /* End else */
        !           554:        while ( interactive == TRUE );
        !           555: 
        !           556: }   /* End of arguments */
        !           557: 
        !           558: /*****************************************************************************/
        !           559: 
        !           560: send(fd_in, name)
        !           561: 
        !           562:     int                fd_in;                  /* next input file */
        !           563:     char       *name;                  /* and it's pathname */
        !           564: 
        !           565: {
        !           566: 
        !           567: /*
        !           568:  *
        !           569:  * Sends file *name to the printer. There's nothing left here that depends on
        !           570:  * sending and receiving status reports, although it can be reassuring to know
        !           571:  * the printer is responding and processing our job. Only the writer gets here
        !           572:  * in the two process implementation, and in that case split() has reset nostatus
        !           573:  * to WRITEPROCESS and that's what getstatus() always returns. For now we accept
        !           574:  * the IDLE state and ENDOFJOB as legitimate and ignore the INITIALIZING state.
        !           575:  *
        !           576:  */
        !           577: 
        !           578:     if ( interactive == FALSE )
        !           579:        logit("sending file %s\n", name);
        !           580: 
        !           581:     currentstate = SEND;
        !           582: 
        !           583:     if ( useslowsend == TRUE )  {
        !           584:        slowsend(fd_in);
        !           585:        return;
        !           586:     }  /* End if */
        !           587: 
        !           588:     while ( readblock(fd_in) )
        !           589:        switch ( getstatus(0) )  {
        !           590:            case IDLE:
        !           591:            case BUSY:
        !           592:            case WAITING:
        !           593:            case PRINTING:
        !           594:            case ENDOFJOB:
        !           595:            case PRINTERERROR:
        !           596:            case UNKNOWN:
        !           597:            case NOSTATUS:
        !           598:            case WRITEPROCESS:
        !           599:            case INTERACTIVE:
        !           600:                    writeblock();
        !           601:                    break;
        !           602: 
        !           603:            case ERROR:
        !           604:                    fprintf(stderr, "%s", mesg);        /* for csw */
        !           605:                    error(USER_FATAL, "PostScript Error");
        !           606:                    break;
        !           607: 
        !           608:            case FLUSHING:
        !           609:                    error(USER_FATAL, "Flushing Job");
        !           610:                    break;
        !           611: 
        !           612:            case DISCONNECT:
        !           613:                    error(FATAL, "Disconnected - printer may be offline");
        !           614:                    break;
        !           615:        }   /* End switch */
        !           616: 
        !           617: }   /* End of send */
        !           618: 
        !           619: /*****************************************************************************/
        !           620: 
        !           621: done()
        !           622: 
        !           623: {
        !           624: 
        !           625:     int                sleeptime = 15;         /* for 'out of paper' etc. */
        !           626: 
        !           627: /*
        !           628:  *
        !           629:  * Tries to stay connected to the printer until we're reasonably sure the job is
        !           630:  * complete. It's the only way we can recover error messages or data generated by
        !           631:  * the PostScript program and returned over the communication line. Actually doing
        !           632:  * it correctly for all possible PostScript jobs is more difficult that it might
        !           633:  * seem. For example if we've sent several jobs, each with their own EOF mark, then
        !           634:  * waiting for ENDOFJOB won't guarantee all the jobs have completed. Even waiting
        !           635:  * for IDLE isn't good enough. Checking for the WAITING state after all the files
        !           636:  * have been sent and then sending an EOF may be the best approach, but even that
        !           637:  * won't work all the time - we could miss it or might not get there. Even sending
        !           638:  * our own special PostScript job after all the input files has it's own different
        !           639:  * set of problems, but probably could work (perhaps by printing a fake status
        !           640:  * message or just not timing out). Anyway it's probably not worth the trouble so
        !           641:  * for now we'll quit if writedone is TRUE and we get ENDOFJOB or IDLE.
        !           642:  *
        !           643:  * If we're running separate read and write processes the reader gets here after
        !           644:  * after split() while the writer goes to send() and only gets here after all the
        !           645:  * input files have been transmitted. When they're both here the writer sends the
        !           646:  * reader signal joinsig and that forces writedone to TRUE in the reader. At that
        !           647:  * point the reader can begin looking for an indication of the end of the job.
        !           648:  * The writer hangs around until the reader kills it (usually in cleanup()) sending
        !           649:  * occasional status requests.
        !           650:  *
        !           651:  */
        !           652: 
        !           653:     if ( canwrite == TRUE )
        !           654:        logit("waiting for end of job\n");
        !           655: 
        !           656:     currentstate = DONE;
        !           657:     writedone = (whatami == READWRITE) ? TRUE : FALSE;
        !           658: 
        !           659:     while ( 1 )  {
        !           660:        switch ( getstatus(1) )  {
        !           661: 
        !           662:            case WRITEPROCESS:
        !           663:                    if ( writedone == FALSE )  {
        !           664:                        sendsignal(joinsig);
        !           665:                        Write(ttyo, "\004", 1);
        !           666:                        writedone = TRUE;
        !           667:                        sleeptime = 1;
        !           668:                    }   /* End if */
        !           669:                    Rest(sleeptime++);
        !           670:                    break;
        !           671: 
        !           672:            case WAITING:
        !           673:                    Write(ttyo, "\004", 1);
        !           674:                    Rest(1);
        !           675:                    sleeptime = 15;
        !           676:                    break;
        !           677: 
        !           678:            case IDLE:
        !           679:            case ENDOFJOB:
        !           680:                    if ( writedone == TRUE )  {
        !           681:                        logit("job complete\n");
        !           682:                        return;
        !           683:                    }   /* End if */
        !           684:                    break;
        !           685: 
        !           686:            case BUSY:
        !           687:            case PRINTING:
        !           688:            case INTERACTIVE:
        !           689:                    sleeptime = 15;
        !           690:                    break;
        !           691: 
        !           692:            case PRINTERERROR:
        !           693:                    Rest(sleeptime++);
        !           694:                    break;
        !           695: 
        !           696:            case ERROR:
        !           697:                    fprintf(stderr, "%s", mesg);        /* for csw */
        !           698:                    error(USER_FATAL, "PostScript Error");
        !           699:                    return;
        !           700: 
        !           701:            case FLUSHING:
        !           702:                    error(USER_FATAL, "Flushing Job");
        !           703:                    return;
        !           704: 
        !           705:            case DISCONNECT:
        !           706:                    error(FATAL, "Disconnected - printer may be offline");
        !           707:                    return;
        !           708: 
        !           709:            default:
        !           710:                    Rest(1);
        !           711:                    break;
        !           712:        }   /* End switch */
        !           713: 
        !           714:        if ( sleeptime > 60 )
        !           715:            sleeptime = 60;
        !           716:     }  /* End while */
        !           717: 
        !           718: }   /* End of done */
        !           719: 
        !           720: /*****************************************************************************/
        !           721: 
        !           722: cleanup()
        !           723: 
        !           724: {
        !           725: 
        !           726:     int                w;
        !           727: 
        !           728: /*
        !           729:  *
        !           730:  * Only needed if we're running separate read and write processes. Makes sure the
        !           731:  * write process is killed after the read process has successfully finished with
        !           732:  * all the jobs. sendsignal() returns a -1 if there's nobody to signal so things
        !           733:  * work when we're running a single process.
        !           734:  *
        !           735:  */
        !           736: 
        !           737:     while ( sendsignal(SIGKILL) != -1 && (w = wait((int *)0)) != otherpid && w != -1 ) ;
        !           738: 
        !           739: }   /* End of cleanup */
        !           740: 
        !           741: /*****************************************************************************/
        !           742: 
        !           743: readblock(fd_in)
        !           744: 
        !           745:     int                fd_in;                  /* current input file */
        !           746: 
        !           747: {
        !           748: 
        !           749:     static long        blocknum = 1;
        !           750: 
        !           751: /*
        !           752:  *
        !           753:  * Fills the input buffer with the next block, provided we're all done with the
        !           754:  * last one. Blocks from fd_in are stored in array block[]. head is the index
        !           755:  * of the next byte in block[] that's supposed to go to the printer. tail points
        !           756:  * one past the last byte in the current block. head is adjusted in writeblock()
        !           757:  * after each successful write, while head and tail are reset here each time
        !           758:  * a new block is read. Returns the number of bytes left in the current block.
        !           759:  * Read errors cause the program to abort. The fake status message that's put out
        !           760:  * in quiet mode is only so you can look at the log file and know something's
        !           761:  * happening - take it out if you want.
        !           762:  *
        !           763:  */
        !           764: 
        !           765:     if ( head >= tail )  {             /* done with the last block */
        !           766:        if ( (tail = read(fd_in, block, blocksize)) == -1 )
        !           767:            error(FATAL, "error reading input file");
        !           768:        if ( quiet == TRUE && tail > 0 )        /* put out a fake message? */
        !           769:            logit("%%%%[ status: busy; block: %d ]%%%%\n", blocknum++);
        !           770:        head = 0;
        !           771:     }  /* End if */
        !           772: 
        !           773:     return(tail - head);
        !           774: 
        !           775: }   /* End of readblock */
        !           776: 
        !           777: /*****************************************************************************/
        !           778: 
        !           779: writeblock()
        !           780: 
        !           781: {
        !           782: 
        !           783:     int                count;                  /* bytes successfully written */
        !           784: 
        !           785: /*
        !           786:  *
        !           787:  * Called from send() when it's OK to send the next block to the printer. head
        !           788:  * is adjusted after the write, and the number of bytes that were successfully
        !           789:  * written is returned to the caller.
        !           790:  *
        !           791:  */
        !           792: 
        !           793:     if ( (count = write(ttyo, &block[head], tail - head)) == -1 )
        !           794:        error(FATAL, "error writing to %s", line);
        !           795:     else if ( count == 0 )
        !           796:        error(FATAL, "printer appears to be offline");
        !           797: 
        !           798:     head += count;
        !           799:     return(count);
        !           800: 
        !           801: }   /* End of writeblock */
        !           802: 
        !           803: /*****************************************************************************/
        !           804: 
        !           805: getstatus(t)
        !           806: 
        !           807:     int                t;                      /* sleep time after sending '\024' */
        !           808: 
        !           809: {
        !           810: 
        !           811:     int                gotline = FALSE;        /* value returned by readline() */
        !           812:     int                state = nostatus;       /* representation of the current state */
        !           813:     int                mesgch;                 /* to restore mesg[] when tostdout == TRUE */
        !           814: 
        !           815:     static int laststate = NOSTATUS;   /* last state recognized */
        !           816: 
        !           817: /*
        !           818:  *
        !           819:  * Looks for things coming back from the printer on the communications line, parses
        !           820:  * complete lines retrieved by readline(), and returns an integer representation
        !           821:  * of the current printer status to the caller. If nothing was available a status
        !           822:  * request (control T) is sent to the printer and nostatus is returned to the
        !           823:  * caller (provided quiet isn't TRUE). Interactive mode either never returns from
        !           824:  * readline() or returns FALSE.
        !           825:  * 
        !           826:  */
        !           827: 
        !           828:     if ( canread == TRUE && (gotline = readline()) == TRUE )  {
        !           829:        state = parsemesg();
        !           830:        if ( state != laststate || state == UNKNOWN || mesgptr != mesg || debug == ON )
        !           831:            logit("%s", mesg);
        !           832: 
        !           833:        if ( tostdout == TRUE && currentstate != START )  {
        !           834:            mesgch = *mesgptr;
        !           835:            *mesgptr = '\0';
        !           836:            fprintf(stdout, "%s", mesg);
        !           837:            fflush(stdout);
        !           838:            *mesgptr = mesgch;          /* for ERROR in send() and done() */
        !           839:        }   /* End if */
        !           840:        return(laststate = state);
        !           841:     }  /* End if */
        !           842: 
        !           843:     if ( (quiet == FALSE || currentstate != SEND) &&
        !           844:         (tostdout == FALSE || currentstate == START) && interactive == FALSE )  {
        !           845:        if ( Write(ttyo, "\024", 1) != 1 )
        !           846:            error(FATAL, "printer appears to be offline");
        !           847:        if ( t > 0 ) Rest(t);
        !           848:     }  /* End if */
        !           849: 
        !           850:     return(nostatus);
        !           851: 
        !           852: }   /* End of getstatus */
        !           853: 
        !           854: /*****************************************************************************/
        !           855: 
        !           856: parsemesg()
        !           857: 
        !           858: {
        !           859: 
        !           860:     char       *e;                     /* end of printer message in mesg[] */
        !           861:     char       *key, *val;             /* keyword/value strings in sbuf[] */
        !           862:     char       *p;                     /* for converting to lower case etc. */
        !           863:     int                i;                      /* where *key was found in status[] */
        !           864: 
        !           865: /*
        !           866:  *
        !           867:  * Parsing the lines that readline() stores in mesg[] is messy, and what's done
        !           868:  * here isn't completely correct nor as fast as it could be. The general format
        !           869:  * of lines that come back from the printer (assuming no data loss) is:
        !           870:  *
        !           871:  *             str%%[ key: val; key: val; key: val ]%%\n
        !           872:  *
        !           873:  * where str can be most anything not containing a newline and printer reports
        !           874:  * (eg. status or error messages) are bracketed by "%%[ " and " ]%%" strings and
        !           875:  * end with a newline. Usually we'll have the string or printer report but not
        !           876:  * both. For most jobs the leading string will be empty, but could be anything
        !           877:  * generated on a printer and returned over the communications line using the
        !           878:  * PostScript print operator. I'll assume PostScript jobs are well behaved and
        !           879:  * never bracket their messages with "%%[ " and " ]%%" strings that delimit status
        !           880:  * or error messages.
        !           881:  *
        !           882:  * Printer reports consist of one or more key/val pairs, and what we're interested
        !           883:  * in (status or error indications) may not be the first pair in the list. In
        !           884:  * addition we'll sometimes want the value associated with a keyword (eg. when
        !           885:  * key = status) and other times we'll want the keyword (eg. when key = Error or
        !           886:  * Flushing). The last pair isn't terminated by a semicolon and a value string
        !           887:  * often contains many space separated words and it can even include colons in
        !           888:  * meaningful places. I've also decided to continue converting things to lower
        !           889:  * case before doing the lookup in status[]. The isupper() test is for Berkeley
        !           890:  * systems.
        !           891:  *
        !           892:  */
        !           893: 
        !           894:     if ( *(mesgptr = find("%%[ ", mesg)) != '\0' && *(e = find(" ]%%", mesgptr+4)) != '\0' )  {
        !           895:        strcpy(sbuf, mesgptr+4);                /* don't change mesg[] */
        !           896:        sbuf[e-mesgptr-4] = '\0';               /* ignore the trailing " ]%%" */
        !           897: 
        !           898:        for ( key = strtok(sbuf, " :"); key != NULL; key = strtok(NULL, " :") )  {
        !           899:            if ( (val = strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0 )
        !           900:                key = val;
        !           901: 
        !           902:            for ( ; *key == ' '; key++ ) ;      /* skip any leading spaces */
        !           903:            for ( p = key; *p; p++ )            /* convert to lower case */
        !           904:                if ( *p == ':' )  {
        !           905:                    *p = '\0';
        !           906:                    break;
        !           907:                } else if ( isupper(*p) ) *p = tolower(*p);
        !           908: 
        !           909:            for ( i = 0; status[i].state != NULL; i++ )
        !           910:                if ( strcmp(status[i].state, key) == 0 )
        !           911:                    return(status[i].val);
        !           912:        }   /* End for */
        !           913:     } else if ( strcmp(mesg, "CONVERSATION ENDED.\n") == 0 )
        !           914:        return(DISCONNECT);
        !           915: 
        !           916:     return(mesgptr == '\0' ? nostatus : UNKNOWN);
        !           917: 
        !           918: }   /* End of parsemesg */
        !           919: 
        !           920: /*****************************************************************************/
        !           921: 
        !           922: char *find(str1, str2)
        !           923: 
        !           924:     char       *str1;                  /* look for this string */
        !           925:     char       *str2;                  /* in this one */
        !           926: 
        !           927: {
        !           928: 
        !           929:     char       *s1, *s2;               /* can't change str1 or str2 too fast */
        !           930: 
        !           931: /*
        !           932:  *
        !           933:  * Looks for *str1 in string *str2. Returns a pointer to the start of the substring
        !           934:  * if it's found or to the end of string str2 otherwise.
        !           935:  *
        !           936:  */ 
        !           937: 
        !           938:     for ( ; *str2 != '\0'; str2++ )  {
        !           939:        for ( s1 = str1, s2 = str2; *s1 != '\0' && *s1 == *s2; s1++, s2++ ) ;
        !           940:        if ( *s1 == '\0' )
        !           941:            break;
        !           942:     }  /* End for */
        !           943: 
        !           944:     return(str2);
        !           945: 
        !           946: }   /* End of find */
        !           947: 
        !           948: /*****************************************************************************/
        !           949: 
        !           950: clearline()
        !           951: 
        !           952: {
        !           953: 
        !           954: /*
        !           955:  *
        !           956:  * Reads characters from the input line until nothing's left. Don't do anything if
        !           957:  * we're currently running separate read and write processes.
        !           958:  * 
        !           959:  */
        !           960: 
        !           961:     if ( whatami == READWRITE )
        !           962:        while ( readline() != FALSE ) ;
        !           963: 
        !           964: }   /* End of clearline */
        !           965: 
        !           966: /*****************************************************************************/
        !           967: 
        !           968: sendsignal(sig)
        !           969: 
        !           970:     int                sig;                    /* this goes to the other process */
        !           971: 
        !           972: {
        !           973: 
        !           974: /*
        !           975:  *
        !           976:  * Sends signal sig to the other process if we're running as separate read and
        !           977:  * write processes. Returns the result of the kill if there's someone else to
        !           978:  * signal or -1 if we're running alone.
        !           979:  *
        !           980:  */
        !           981: 
        !           982:     if ( whatami != READWRITE && otherpid > 1 )
        !           983:        return(kill(otherpid, sig));
        !           984: 
        !           985:     return(-1);
        !           986: 
        !           987: }   /* End of sendsignal */
        !           988: 
        !           989: /*****************************************************************************/
        !           990: 
        !           991: void interrupt(sig)
        !           992: 
        !           993:     int                sig;                    /* signal that we caught */
        !           994: 
        !           995: {
        !           996: 
        !           997: /*
        !           998:  *
        !           999:  * Caught a signal - all except joinsig cause the program to quit. joinsig is the
        !          1000:  * signal sent by the writer to the reader after all the jobs have been transmitted.
        !          1001:  * Used to tell the read process when it can start looking for the end of the job.
        !          1002:  *
        !          1003:  */
        !          1004: 
        !          1005:     signal(sig, SIG_IGN);
        !          1006: 
        !          1007:     if ( sig != joinsig )  {
        !          1008:        x_stat |= FATAL;
        !          1009:        if ( canread == TRUE )
        !          1010:            if ( interactive == FALSE )
        !          1011:                error(NON_FATAL, "signal %d abort", sig);
        !          1012:            else error(NON_FATAL, "quitting");
        !          1013:        quit(sig);
        !          1014:     }  /* End if */
        !          1015: 
        !          1016:     writedone = TRUE;
        !          1017:     signal(joinsig, interrupt);
        !          1018: 
        !          1019: }   /* End of interrupt */
        !          1020: 
        !          1021: /*****************************************************************************/
        !          1022: 
        !          1023: logit(mesg, a1, a2, a3)
        !          1024: 
        !          1025:     char       *mesg;                  /* control string */
        !          1026:     unsigned   a1, a2, a3;             /* and possible arguments */
        !          1027: 
        !          1028: {
        !          1029: 
        !          1030: /*
        !          1031:  *
        !          1032:  * Simple routine that's used to write a message to the log file.
        !          1033:  *
        !          1034:  */
        !          1035: 
        !          1036:     if ( mesg != NULL && fp_log != NULL )  {
        !          1037:        fprintf(fp_log, mesg, a1, a2, a3);
        !          1038:        fflush(fp_log);
        !          1039:     }  /* End if */
        !          1040: 
        !          1041: }   /* End of logit */
        !          1042: 
        !          1043: /*****************************************************************************/
        !          1044: 
        !          1045: error(kind, mesg, a1, a2, a3)
        !          1046: 
        !          1047:     int                kind;                   /* FATAL or NON_FATAL error */
        !          1048:     char       *mesg;                  /* error message control string */
        !          1049:     unsigned   a1, a2, a3;             /* control string arguments */
        !          1050: 
        !          1051: {
        !          1052: 
        !          1053:     FILE       *fp_err;
        !          1054: 
        !          1055: /*
        !          1056:  *
        !          1057:  * Called when we've run into some kind of program error. First *mesg is printed
        !          1058:  * using the control string arguments a?. If kind is FATAL and we're not ignoring
        !          1059:  * errors the program will be terminated. If mesg is NULL or *mesg is the NULL
        !          1060:  * string nothing will be printed.
        !          1061:  *
        !          1062:  */
        !          1063: 
        !          1064:     fp_err = (fp_log != NULL) ? fp_log : stderr;
        !          1065: 
        !          1066:     if ( mesg != NULL && *mesg != '\0' )  {
        !          1067:        fprintf(fp_err, "%s: ", prog_name);
        !          1068:        fprintf(fp_err, mesg, a1, a2, a3);
        !          1069:        putc('\n', fp_err);
        !          1070:     }  /* End if */
        !          1071: 
        !          1072:     x_stat |= kind;
        !          1073: 
        !          1074:     if ( kind != NON_FATAL && ignore == OFF )
        !          1075:        quit(SIGTERM);
        !          1076: 
        !          1077: }   /* End of error */
        !          1078: 
        !          1079: /*****************************************************************************/
        !          1080: 
        !          1081: quit(sig)
        !          1082: 
        !          1083:     int                sig;
        !          1084: 
        !          1085: {
        !          1086: 
        !          1087:     int                w;
        !          1088: 
        !          1089: /*
        !          1090:  *
        !          1091:  * Makes sure everything is properly cleaned up if there's a signal or FATAL error
        !          1092:  * that should cause the program to terminate. The sleep by the write process is
        !          1093:  * to help give the reset sequence a chance to reach the printer before we break
        !          1094:  * the connection - primarily for printers connected to Datakit. There's a very
        !          1095:  * slight chance the reset sequence that's sent to the printer could get us stuck
        !          1096:  * here. Simplest solution is don't bother to send it - everything works without it.
        !          1097:  * Flushing ttyo would be better, but means yet another system dependent procedure
        !          1098:  * in ifdef.c! I'll leave things be for now.
        !          1099:  *
        !          1100:  * Obscure problem on PS-810 turbos says wait a bit after sending an interrupt.
        !          1101:  * Seem to remember the printer getting into a bad state immediately after the
        !          1102:  * top was opened when the toner light was on. A sleep after sending the ctrl-C
        !          1103:  * seemed to fix things.
        !          1104:  *
        !          1105:  */
        !          1106: 
        !          1107:     signal(sig, SIG_IGN);
        !          1108:     ignore = ON;
        !          1109: 
        !          1110:     while ( sendsignal(sig) != -1 && (w = wait((int *)0)) != otherpid && w != -1 ) ;
        !          1111: 
        !          1112:     setupstdin(2);
        !          1113: 
        !          1114:     if ( currentstate != NOTCONNECTED ) {
        !          1115:        if ( sendctrlC == TRUE ) {
        !          1116:            Write(ttyo, "\003", 1);
        !          1117:            Rest(1);                    /* PS-810 turbo problem?? */
        !          1118:        }   /* End if */
        !          1119:        Write(ttyo, "\004", 1);
        !          1120:     }  /* End if */
        !          1121: 
        !          1122:     alarm(0);                          /* prevents sleep() loop on V9 systems */
        !          1123:     Rest(2);
        !          1124: 
        !          1125:     exit(x_stat);
        !          1126: 
        !          1127: }   /* End of quit */
        !          1128: 
        !          1129: /*****************************************************************************/
        !          1130: 
        !          1131: Rest(t)
        !          1132: 
        !          1133:     int                t;
        !          1134: 
        !          1135: {
        !          1136: 
        !          1137: /*
        !          1138:  *
        !          1139:  * Used to replace sleep() calls. Only needed if we're running the program as
        !          1140:  * a read and write process and don't want to have the read process sleep. Most
        !          1141:  * sleeps are in the code because of the non-blocking read used by the single
        !          1142:  * process implementation. Probably should be a macro.
        !          1143:  *
        !          1144:  */
        !          1145: 
        !          1146:     if ( t > 0 && canwrite == TRUE )
        !          1147:        sleep(t);
        !          1148: 
        !          1149: }   /* End of Rest */
        !          1150: 
        !          1151: /*****************************************************************************/
        !          1152: 
        !          1153: Read(fd, buf, n)
        !          1154: 
        !          1155:     int                fd;
        !          1156:     char       *buf;
        !          1157:     int                n;
        !          1158: 
        !          1159: {
        !          1160: 
        !          1161:     int                count;
        !          1162: 
        !          1163: /*
        !          1164:  *
        !          1165:  * Used to replace some of the read() calls. Only needed if we're running separate
        !          1166:  * read and write processes. Should only be used to replace read calls on ttyi.
        !          1167:  * Always returns 0 to the caller if the process doesn't have its READ flag set.
        !          1168:  * Probably should be a macro.
        !          1169:  *
        !          1170:  */
        !          1171: 
        !          1172:     if ( canread == TRUE )  {
        !          1173:        if ( (count = read(fd, buf, n)) == -1 && errno == EINTR )
        !          1174:            count = 0;
        !          1175:     } else count = 0;
        !          1176: 
        !          1177:     return(count);
        !          1178: 
        !          1179: }   /* End of Read */
        !          1180: 
        !          1181: /*****************************************************************************/
        !          1182: 
        !          1183: Write(fd, buf, n)
        !          1184: 
        !          1185:     int                fd;
        !          1186:     char       *buf;
        !          1187:     int                n;
        !          1188: 
        !          1189: {
        !          1190: 
        !          1191:     int                count;
        !          1192: 
        !          1193: /*
        !          1194:  *
        !          1195:  * Used to replace some of the write() calls. Again only needed if we're running
        !          1196:  * separate read and write processes. Should only be used to replace write calls
        !          1197:  * on ttyo. Always returns n to the caller if the process doesn't have its WRITE
        !          1198:  * flag set. Should also probably be a macro.
        !          1199:  *
        !          1200:  */
        !          1201: 
        !          1202:     if ( canwrite == TRUE )  {
        !          1203:        if ( (count = write(fd, buf, n)) == -1 && errno == EINTR )
        !          1204:            count = n;
        !          1205:     } else count = n;
        !          1206: 
        !          1207:     return(count);
        !          1208: 
        !          1209: }   /* End of Write */
        !          1210:  
        !          1211: /*****************************************************************************/
        !          1212: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.