📄 postio.c
字号:
setupline(); /* configure the communications line */ setupstdin(0); /* save current stdin terminal settings */} /* End of initialize *//*****************************************************************************/start(){/* * * Tries to put the printer in the IDLE state before anything important is sent. * Run as a single process no matter what has been assigned to splitme. Separate * read and write processes, if requested, will be created after we're done here. * */ logit("printer startup\n"); currentstate = START; clearline(); while ( 1 ) switch ( getstatus(1) ) { case IDLE: case INTERACTIVE: if ( postbegin != NULL && *postbegin != '\0' ) Write(ttyo, postbegin, strlen(postbegin)); clearline(); return; case BUSY: if ( sendctrlC == TRUE ) { Write(ttyo, "\003", 1); Rest(1); } /* End if */ break; case WAITING: case ERROR: case FLUSHING: Write(ttyo, "\004", 1); Rest(1); break; case PRINTERERROR: Rest(15); break; case DISCONNECT: error(FATAL, "Disconnected - printer may be offline"); break; case ENDOFJOB: case UNKNOWN: clearline(); break; default: Rest(1); break; } /* End switch */} /* End of start *//*****************************************************************************/split(){ int pid; void interrupt();/* * * If splitme is TRUE we fork a process, make the parent handle reading, and let * the child take care of writing. resetline() (file ifdef.c) contains all the * system dependent code needed to reset the communications line for separate * read and write processes. For now it's expected to return TRUE or FALSE and * that value controls whether we try the fork. I've only tested the two process * stuff for System V. Other versions of resetline() may just be dummy procedures * that always return FALSE. If the fork() failed previous versions continued as * a single process, although the implementation wasn't quite right, but I've now * decided to quit. The main reason is a Datakit channel may be configured to * flow control data in both directions, and if we run postio over that channel * as a single process we likely will end up in deadlock. * */ if ( splitme == TRUE ) if ( resetline() == TRUE ) { pid = getpid(); signal(joinsig, interrupt); if ( (otherpid = fork()) == -1 ) error(FATAL, "can't fork"); else if ( otherpid == 0 ) { whatami = WRITE; nostatus = WRITEPROCESS; otherpid = pid; setupstdin(1); } else whatami = READ; } else if ( interactive == TRUE || tostdout == TRUE ) error(FATAL, "can't create two process - check resetline()"); else error(NON_FATAL, "running as a single process - check resetline()"); canread = (whatami & READ) ? TRUE : FALSE; canwrite = (whatami & WRITE) ? TRUE : FALSE;} /* End of split *//*****************************************************************************/arguments(){ int fd_in; /* next input file *//* * * Makes sure all the non-option command line arguments are processed. If there * aren't any arguments left when we get here we'll send stdin. Input files are * only read and sent to the printer if canwrite is TRUE. Checking it here means * we won't have to do it in send(). If interactive mode is TRUE we'll stay here * forever sending stdin when we run out of files - exit with a break. Actually * the loop is bogus and used at most once when we're in interactive mode because * stdin is in a pseudo raw mode and the read() in readblock() should never see * the end of file. * */ if ( canwrite == TRUE ) do /* loop is for interactive mode */ if ( argc < 1 ) send(fileno(stdin), "pipe.end"); else { while ( argc > 0 ) { if ( (fd_in = open(*argv, O_RDONLY)) == -1 ) error(FATAL, "can't open %s", *argv); send(fd_in, *argv); close(fd_in); argc--; argv++; } /* End while */ } /* End else */ while ( interactive == TRUE );} /* End of arguments *//*****************************************************************************/send(fd_in, name) int fd_in; /* next input file */ char *name; /* and it's pathname */{/* * * Sends file *name to the printer. There's nothing left here that depends on * sending and receiving status reports, although it can be reassuring to know * the printer is responding and processing our job. Only the writer gets here * in the two process implementation, and in that case split() has reset nostatus * to WRITEPROCESS and that's what getstatus() always returns. For now we accept * the IDLE state and ENDOFJOB as legitimate and ignore the INITIALIZING state. * */ if ( interactive == FALSE ) logit("sending file %s\n", name); currentstate = SEND; if ( useslowsend == TRUE ) { slowsend(fd_in); return; } /* End if */ while ( readblock(fd_in) ) switch ( getstatus(0) ) { case IDLE: case BUSY: case WAITING: case PRINTING: case ENDOFJOB: case PRINTERERROR: case UNKNOWN: case NOSTATUS: case WRITEPROCESS: case INTERACTIVE: writeblock(); break; case ERROR: fprintf(stderr, "%s", mesg); /* for csw */ error(USER_FATAL, "PostScript Error"); break; case FLUSHING: error(USER_FATAL, "Flushing Job"); break; case DISCONNECT: error(FATAL, "Disconnected - printer may be offline"); break; } /* End switch */} /* End of send *//*****************************************************************************/done(){ int sleeptime = 15; /* for 'out of paper' etc. *//* * * Tries to stay connected to the printer until we're reasonably sure the job is * complete. It's the only way we can recover error messages or data generated by * the PostScript program and returned over the communication line. Actually doing * it correctly for all possible PostScript jobs is more difficult that it might * seem. For example if we've sent several jobs, each with their own EOF mark, then * waiting for ENDOFJOB won't guarantee all the jobs have completed. Even waiting * for IDLE isn't good enough. Checking for the WAITING state after all the files * have been sent and then sending an EOF may be the best approach, but even that * won't work all the time - we could miss it or might not get there. Even sending * our own special PostScript job after all the input files has it's own different * set of problems, but probably could work (perhaps by printing a fake status * message or just not timing out). Anyway it's probably not worth the trouble so * for now we'll quit if writedone is TRUE and we get ENDOFJOB or IDLE. * * If we're running separate read and write processes the reader gets here after * after split() while the writer goes to send() and only gets here after all the * input files have been transmitted. When they're both here the writer sends the * reader signal joinsig and that forces writedone to TRUE in the reader. At that * point the reader can begin looking for an indication of the end of the job. * The writer hangs around until the reader kills it (usually in cleanup()) sending * occasional status requests. * */ if ( canwrite == TRUE ) logit("waiting for end of job\n"); currentstate = DONE; writedone = (whatami == READWRITE) ? TRUE : FALSE; while ( 1 ) { switch ( getstatus(1) ) { case WRITEPROCESS: if ( writedone == FALSE ) { sendsignal(joinsig); Write(ttyo, "\004", 1); writedone = TRUE; sleeptime = 1; } /* End if */ Rest(sleeptime++); break; case WAITING: Write(ttyo, "\004", 1); Rest(1); sleeptime = 15; break; case IDLE: case ENDOFJOB: if ( writedone == TRUE ) { logit("job complete\n"); return; } /* End if */ break; case BUSY: case PRINTING: case INTERACTIVE: sleeptime = 15; break; case PRINTERERROR: Rest(sleeptime++); break; case ERROR: fprintf(stderr, "%s", mesg); /* for csw */ error(USER_FATAL, "PostScript Error"); return; case FLUSHING: error(USER_FATAL, "Flushing Job"); return; case DISCONNECT: error(FATAL, "Disconnected - printer may be offline"); return; default: Rest(1); break; } /* End switch */ if ( sleeptime > 60 ) sleeptime = 60; } /* End while */} /* End of done *//*****************************************************************************/cleanup(){ int w;/* * * Only needed if we're running separate read and write processes. Makes sure the * write process is killed after the read process has successfully finished with * all the jobs. sendsignal() returns a -1 if there's nobody to signal so things * work when we're running a single process. * */ while ( sendsignal(SIGKILL) != -1 && (w = wait((int *)0)) != otherpid && w != -1 ) ;} /* End of cleanup *//*****************************************************************************/readblock(fd_in) int fd_in; /* current input file */{ static long blocknum = 1;/* * * Fills the input buffer with the next block, provided we're all done with the * last one. Blocks from fd_in are stored in array block[]. head is the index * of the next byte in block[] that's supposed to go to the printer. tail points * one past the last byte in the current block. head is adjusted in writeblock() * after each successful write, while head and tail are reset here each time * a new block is read. Returns the number of bytes left in the current block. * Read errors cause the program to abort. The fake status message that's put out * in quiet mode is only so you can look at the log file and know something's * happening - take it out if you want. * */ if ( head >= tail ) { /* done with the last block */ if ( (tail = read(fd_in, block, blocksize)) == -1 ) error(FATAL, "error reading input file"); if ( quiet == TRUE && tail > 0 ) /* put out a fake message? */ logit("%%%%[ status: busy; block: %d ]%%%%\n", blocknum++); head = 0; } /* End if */ return(tail - head);} /* End of readblock *//*****************************************************************************/writeblock(){ int count; /* bytes successfully written *//* * * Called from send() when it's OK to send the next block to the printer. head * is adjusted after the write, and the number of bytes that were successfully * written is returned to the caller. * */ if ( (count = write(ttyo, &block[head], tail - head)) == -1 ) error(FATAL, "error writing to %s", line); else if ( count == 0 ) error(FATAL, "printer appears to be offline"); head += count; return(count);} /* End of writeblock *//*****************************************************************************/getstatus(t) int t; /* sleep time after sending '\024' */{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -