📄 17.htm
字号:
<p>* We send a Control-T to the printer to fetch its status. </p>
<p>* If we timeout before reading the printer's status, something </p>
<p>* is wrong. */ </p>
<p>void </p>
<p>get_status(void) </p>
<p>{ </p>
<p>char c; </p>
<p>set_alrm(5); /* 5 second timeout to fetch status */ </p>
<p>tty_flush(); </p>
<p>c = '\024'; </p>
<p>block_write(&c, 1); /* send Control-T to printer */ </p>
<p>init_input(0); </p>
<p>while (status == INVALID) </p>
<p>proc_some_input(); /* wait for something back */ </p>
<p>switch (status) { </p>
<p>case IDLE: /* this is what we're looking for ... */ </p>
<p>clear_alrm(); </p>
<p>return; </p>
<p>case WAITING: /* printer thinks it's in the middle of a job */ </p>
<p>block_write(&eofc, 1); /* send EOF to printer */ </p>
<p>sleep(5); </p>
<p>exit(EXIT_REPRINT); </p>
<p>case BUSY: </p>
<p>case UNKNOWN: </p>
<p>sleep(15); </p>
<p>exit(EXIT_REPRINT); </p>
<p>} </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>程序17.8 get_status函数 </p>
<p>如果我们收到下列消息: </p>
<p>%%[ status: waiting ]%% </p>
<p>这说明打印机正等待我们发送更多的数据以用于当前正打印的作业,这很可能
</p>
<p>是前一打印作业出了些问题。为了清除这个状态,我们发送给打印机一个EOF终止
</p>
<p>符。 </p>
<p>PostScript打印机维护着一个页码计数器。这个计数器每打印一页就会增加,
</p>
<p>它即使在关闭电源时也会保存着。为了读此计数器,我们需要发送给打印机一个P
</p>
<p>ostScript程序。文件pagecount.c(程序17.9)包含了这个小PostScript程序(含
</p>
<p>有大约10个PostScript操作符)和函数get_page。 </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>#include "lprps.h" </p>
<p>/* PostScript program to fetch the printer's pagecount. </p>
<p>* Notice that the string returned by the printer: </p>
<p>* %%[ pagecount: N ]%% </p>
<p>* will be parsed by proc_msg(). */ </p>
<p>static char pagecount_string[] = </p>
<p>"(%%[ pagecount: ) print " /* print writes to current output file * </p>
<p>"statusdict begin pagecount end " /* push pagecount onto stack */ </p>
<p>"20 string " /* creates a string of length 20 */ </p>
<p>"cvs " /* convert to string */ </p>
<p>"print " /* write to current output file */ </p>
<p>"( ]%%) print " </p>
<p>"flush\n"; /* flush current output file */ </p>
<p>/* Read the starting or ending pagecount from the printer. </p>
<p>* The argument is either &start_page or &end_page. */ </p>
<p>void </p>
<p>get_page(int *ptrcount) </p>
<p>{ </p>
<p>set_alrm(30); /* 30 second timeout to read pagecount * </p>
<p>tty_flush(); </p>
<p>block_write(pagecount_string, sizeof(pagecount_string) - 1); </p>
<p>/* send query to printer </p>
<p>*/ </p>
<p>init_input(0); </p>
<p>*ptrcount = -1; </p>
<p>while (*ptrcount < 0) </p>
<p>proc_some_input(); /* read results from printer */ </p>
<p>block_write(&eofc, 1); /* send EOF to printer */ </p>
<p>proc_upto_eof(0); /* wait for EOF from printer */ </p>
<p>clear_alrm(); </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>程序17.9 pagecount.c文件-得到打印机的计数器值 </p>
<p>pagecount_string数组包含了这个小PostScript程序。虽然我们可以用如下方
</p>
<p>法得到并打印页码: </p>
<p>statusdict begin pagecuont end = flush </p>
<p>但我们希望得到类似于打印机返回的状态消息的输出格式: </p>
<p>%% [ pagecount: N]%% </p>
<p>然后,proc_some_input函数处理这个消息,其方式与处理打印机的状态消息
</p>
<p>相类似。 </p>
<p>程序17.10中的函数send_file由main函数调用,它将用户的PostScript程序发
</p>
<p>送到打印机上。 </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>#include "lprps.h" </p>
<p>void </p>
<p>send_file(void) /* called by main() to copy stdin to printer */ </p>
<p>{ </p>
<p>int c; </p>
<p>init_input(1); </p>
<p>set_intr(); /* we catch SIGINT */ </p>
<p>while ( (c = getchar()) != EOF) /* main loop of program */ </p>
<p>out_char(c); /* output each character */ </p>
<p>out_char(EOF); /* output final buffer */ </p>
<p>block_write(&eofc, 1); /* send EOF to printer */ </p>
<p>proc_upto_eof(0); /* wait for printer to send EOF back */ </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>程序17.10 send_file函数 </p>
<p>这个函数主要是一个while循环,其中先读取标准输入(getchar),然后调用
</p>
<p>函数out_char把字符发送给打印机。当在标准输入上遇到EOF时,就发送一个EOF给
</p>
<p>打印机(指示作业完成),然后我们就等待从打印机返回一个EOF(proc_upto_eof
</p>
<p>)。 </p>
<p>回忆图17.2中,连接在串口的PostScript解释器的输出可能是打印机状态消息
</p>
<p>或者是PostScript的print操作符的输出。所以,我们所认为的"文件被打印"甚至
</p>
<p>可能一页都不输出。这个PostScript程序文件执行后,把它的结果送回主机。Pos
</p>
<p>tScript不是一种编程语言。但是,有时我们确实需要发送一个PostScript程序到
</p>
<p>打印机并将结果返回主机,而不是打印在纸上。一个例子是取页码数的PostScrip
</p>
<p>t程序,用其可以了解打印机的使用情况。 </p>
<p>%! </p>
<p>statusdict begin pagecount end = </p>
<p>如果从PostScript解释器返回的不是状态消息,就以电子邮件形式发送给用户
</p>
<p>。程序17.11的mail.c完成这一功能。 </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>#include "lprps.h" </p>
<p>static FILE *mailfp; </p>
<p>static char temp_file[L_tmpnam]; </p>
<p>static void open_mailfp(void); </p>
<p>/* Called by proc_input_char() when it encounters characters </p>
<p>* that are not message characters. We have to send these </p>
<p>* characters back to the user. */ </p>
<p>void </p>
<p>mail_char(int c) </p>
<p>{ </p>
<p>static int done_intro = 0; </p>
<p>if (in_job && (done_intro || c != '\n')) { </p>
<p>open_mailfp(); </p>
<p>if (done_intro == 0) { </p>
<p>fputs("Your PostScript printer job " </p>
<p>"produced the following output:\n", mailfp); </p>
<p>done_intro = 1; </p>
<p>} </p>
<p>putc(c, mailfp); </p>
<p>} </p>
<p>} </p>
<p>/* Called by proc_msg() when an "Error" or "OffendingCommand" key </p>
<p>* is returned by the PostScript interpreter. Send the key and </p>
<p>* val to the user. */ </p>
<p>void </p>
<p>mail_line(const char *msg, const char *val) </p>
<p>{ </p>
<p>if (in_job) { </p>
<p>open_mailfp(); </p>
<p>fprintf(mailfp, msg, val); </p>
<p>} </p>
<p>} </p>
<p>/* Create and open a temporary mail file, if not already open. </p>
<p>* Called by mail_char() and mail_line() above. */ </p>
<p>static void </p>
<p>open_mailfp(void) </p>
<p>{ </p>
<p>if (mailfp == NULL) { </p>
<p>if ( (mailfp = fopen(tmpnam(temp_file), "w")) == NULL) </p>
<p>log_sys("open_mailfp: fopen error"); </p>
<p>} </p>
<p>} </p>
<p>/* Close the temporary mail file and send it to the user. </p>
<p>* Registered to be called on exit() by atexit() in main(). */ </p>
<p>void </p>
<p>close_mailfp(void) </p>
<p>{ </p>
<p>char command[1024]; </p>
<p>if (mailfp != NULL) { </p>
<p>if (fclose(mailfp) == EOF) </p>
<p>log_sys("close_mailfp: fclose error"); </p>
<p>sprintf(command, MAILCMD, loginname, hostname, temp_file); </p>
<p>system(command); </p>
<p>unlink(temp_file); </p>
<p>} </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>程序17.11 mail.c文件 </p>
<p>每次在打印机返回一个字符,而且这个字符不是状态消息的一部分时,那么就
</p>
<p>调用函数mail_char(下面我们会讨论函数proc_input_char,它调用mail_char)
</p>
<p>。只有当函数send_file正发送一个文件给打印机时,变量in_job才被设置。在其
</p>
<p>它时候,例如我们正在读取打印机的状态消息或者打印机的页码计数器值时,它都
</p>
<p>不会被设置。然后调用函数mail_line,它将一行写入邮件文件中。 </p>
<p>当第一次调用函数open_mailfp时,它生成一个临时文件并把它打开。函数cl
</p>
<p>ose_mailfp由main函数设置为终止处理程序,当调用exit时就会调用该函数。如果
</p>
<p>此时临时邮件文件已经产生,那么关闭这个文件,邮件传给用户。
</p>
<p>如果我们发送一行的PostScript程序 </p>
<p>%! </p>
<p>statusdict begin pagecount end = </p>
<p>来获得打印机的页码计数,那么返回给我们的邮件消息是 </p>
<p>Your postscript printer job produced the following output: </p>
<p>11185 </p>
<p>output.c(程序17.12)包含了函数out_char,send_file调用此函数以便将字
</p>
<p>符输出到打印机。 </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>#include "lprps.h" </p>
<p>static char outbuf[OBSIZE]; </p>
<p>static int outcnt = OBSIZE; /* #bytes remaining */ </p>
<p>static char *outptr = outbuf; </p>
<p>static void out_buf(void); </p>
<p>/* Output a single character. </p>
<p>* Called by main loop in send_file(). */ </p>
<p>void </p>
<p>out_char(int c) </p>
<p>{ </p>
<p>if (c == EOF) { </p>
<p>out_buf(); /* flag that we're all done */ </p>
<p>return; </p>
<p>} </p>
<p>if (outcnt <= 0) </p>
<p>out_buf(); /* buffer is full, write it first */ </p>
<p>*outptr++ = c; /* just store in buffer */ </p>
<p>outcnt--; </p>
<p>} </p>
<p>/* Output the buffer that out_char() has been storing into. </p>
<p>* We have our own output function, so that we never block on a write </p>
<p>* to the printer. Each time we output our buffer to the printer, </p>
<p>* we also see if the printer has something to send us. If so, </p>
<p>* we call proc_input_char() to process each character. */ </p>
<p>static void </p>
<p>out_buf(void) </p>
<p>{ </p>
<p>char *wptr, *rptr, ibuf[IBSIZE]; </p>
<p>int wcnt, nread, nwritten; </p>
<p>fd_set rfds, wfds; </p>
<p>FD_ZERO(&wfds); </p>
<p>FD_ZERO(&rfds); </p>
<p>set_nonblock(); /* don't want the write() to block */ </p>
<p>wptr = outbuf; /* ptr to first char to output */ </p>
<p>wcnt = outptr - wptr; /* #bytes to output */ </p>
<p>while (wcnt > 0) { </p>
<p>FD_SET(psfd, &wfds); </p>
<p>FD_SET(psfd, &rfds); </p>
<p>if (intr_flag) </p>
<p>handle_intr(); </p>
<p>while (select(psfd + 1, &rfds, &wfds, NULL, NULL) < 0) { </p>
<p>if (errno == EINTR) { </p>
<p>if (intr_flag) </p>
<p>handle_intr(); /* no return */ </p>
<p>} else </p>
<p>log_sys("out_buf: select error"); </p>
<p>} </p>
<p>if (FD_ISSET(psfd, &rfds)) { /* printer is readable */ </p>
<p>if ( (nread = read(psfd, ibuf, IBSIZE)) < 0) </p>
<p>log_sys("out_buf: read error"); </p>
<p>rptr = ibuf; </p>
<p>while (--nread >= 0) </p>
<p>proc_input_char(*rptr++); </p>
<p>} </p>
<p>if (FD_ISSET(psfd, &wfds)) { /* printer is writeable */ </p>
<p>if ( (nwritten = write(psfd, wptr, wcnt)) < 0) </p>
<p>log_sys("out_buf: write error"); </p>
<p>wcnt -= nwritten; </p>
<p>wptr += nwritten; </p>
<p>} </p>
<p>} </p>
<p>outptr = outbuf; /* reset buffer pointer and count */ </p>
<p>outcnt = OBSIZE; </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>程序17.12 output.c 文件 </p>
<p>当传送给out_char的参数是EOF,那表明输入已经结束,最后的输出缓冲内容
</p>
<p>应当发送到打印机。 </p>
<p>函数out_char把每个字符放到输出缓冲中,当缓冲满了时调用out_buf函数。
</p>
<p>我们必须小心编写out_buf函数:我们发送数据到打印机,打印机也可能同时送回
</p>
<p>数据。为了避免写操作的阻塞,必须把描述符设置为非阻塞的。(可回忆程序12.
</p>
<p>1的例子。)我们使用select 函数来多路转接双向的I/O:输入和输出。我们在读
</p>
<p>取和写入时都设置同一个描述符。还有一种可能是select函数可能会被一个信号(
</p>
<p>SIGINT)所中断,所以我们必须在任何错误返回时对此进行检查。 </p>
<p>如果我们从打印机收到异步输入,我们调用proc_input_char来处理每一个字
</p>
<p>符。这个输入可能是打印机状态消息或者发送给用户的邮件。 </p>
<p>当我们写打印机时,我们必须处理write返回的计数比期望的数量少的情况。
</p>
<p>同样,回忆程序12.1的例子,其中在每次写入时终端可以接收任意数量的数据。
</p>
<p>文件input.c(见程序17.13),定义了处理所有从打印机输入的函数。这种输
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -