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

unix.superglobalmegacorp.com

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