📄 17.htm
字号:
</p>
<p>入可以是打印机状态消息或者给用户的输出。 </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>#include "lprps.h" </p>
<p>static int eof_count; </p>
<p>static int ignore_input; </p>
<p>static enum parse_state { /* state of parsing input from printer */ </p>
<p>NORMAL, </p>
<p>HAD_ONE_PERCENT, </p>
<p>HAD_TWO_PERCENT, </p>
<p>IN_MESSAGE, </p>
<p>HAD_RIGHT_BRACKET, </p>
<p>HAD_RIGHT_BRACKET_AND_PERCENT </p>
<p>} parse_state; </p>
<p>/* Initialize our input machine. */ </p>
<p>void </p>
<p>init_input(int job) </p>
<p>{ </p>
<p>in_job = job; /* only true when send_file() calls us */ </p>
<p>parse_state = NORMAL; </p>
<p>ignore_input = 0; </p>
<p>} </p>
<p>/* Read from the printer until we encounter an EOF. </p>
<p>* Whether or not the input is processed depends on "ignore". */ </p>
<p>void </p>
<p>proc_upto_eof(int ignore) </p>
<p>{ </p>
<p>int ec; </p>
<p>ignore_input = ignore; </p>
<p>ec = eof_count; /* proc_input_char() increments eof_count */ </p>
<p>while (ec == eof_count) </p>
<p>proc_some_input(); </p>
<p>} </p>
<p>/* Wait for some data then read it. </p>
<p>* Call proc_input_char() for every character read. */ </p>
<p>void </p>
<p>proc_some_input(void) </p>
<p>{ </p>
<p>char ibuf[IBSIZE]; </p>
<p>char *ptr; </p>
<p>int nread; </p>
<p>fd_set rfds; </p>
<p>FD_ZERO(&rfds); </p>
<p>FD_SET(psfd, &rfds); </p>
<p>set_nonblock(); </p>
<p>if (intr_flag) </p>
<p>handle_intr(); </p>
<p>if (alrm_flag) </p>
<p>handle_alrm(); </p>
<p>while (select(psfd + 1, &rfds, NULL, NULL, NULL) < 0) { </p>
<p>if (errno == EINTR) { </p>
<p>if (alrm_flag) </p>
<p>handle_alrm(); /* doesn't return */ </p>
<p>else if (intr_flag) </p>
<p>handle_intr(); /* doesn't return */ </p>
<p>} else </p>
<p>log_sys("proc_some_input: select error"); </p>
<p>} </p>
<p>if ( (nread = read(psfd, ibuf, IBSIZE)) < 0) </p>
<p>log_sys("proc_some_input: read error"); </p>
<p>else if (nread == 0) </p>
<p>log_sys("proc_some_input: read returned 0"); </p>
<p>ptr = ibuf; </p>
<p>while (--nread >= 0) </p>
<p>proc_input_char(*ptr++); /* process each character */ </p>
<p>} </p>
<p>/* Called by proc_some_input() above after some input has been read. </p>
<p>* Also called by out_buf() whenever asynchronous input appears. */ </p>
<p>void </p>
<p>proc_input_char(int c) </p>
<p>{ </p>
<p>if (c == '\004') { </p>
<p>eof_count++; /* just count the EOFs */ </p>
<p>return; </p>
<p>} else if (ignore_input) </p>
<p>return; /* ignore everything except EOFs */ </p>
<p>switch (parse_state) { /* parse the input */ </p>
<p>case NORMAL: </p>
<p>if (c == '%') </p>
<p>parse_state = HAD_ONE_PERCENT; </p>
<p>else </p>
<p>mail_char(c); </p>
<p>break; </p>
<p>case HAD_ONE_PERCENT: </p>
<p>if (c == '%') </p>
<p>parse_state = HAD_TWO_PERCENT; </p>
<p>else { </p>
<p>mail_char('%'); mail_char(c); </p>
<p>parse_state = NORMAL; </p>
<p>} </p>
<p>break; </p>
<p>case HAD_TWO_PERCENT: </p>
<p>if (c == '[') { </p>
<p>msg_init(); /* message starting; init buffer */ </p>
<p>parse_state = IN_MESSAGE; </p>
<p>} else { </p>
<p>mail_char('%'); mail_char('%'); mail_char(c); </p>
<p>parse_state = NORMAL; </p>
<p>} </p>
<p>break; </p>
<p>case IN_MESSAGE: </p>
<p>if (c == ']') </p>
<p>parse_state = HAD_RIGHT_BRACKET; </p>
<p>else </p>
<p>msg_char(c); </p>
<p>break; </p>
<p>case HAD_RIGHT_BRACKET: </p>
<p>if (c == '%') </p>
<p>parse_state = HAD_RIGHT_BRACKET_AND_PERCENT; </p>
<p>else { </p>
<p>msg_char(']'); msg_char(c); </p>
<p>parse_state = IN_MESSAGE; </p>
<p>} </p>
<p>break; </p>
<p>case HAD_RIGHT_BRACKET_AND_PERCENT: </p>
<p>if (c == '%') { </p>
<p>parse_state = NORMAL; </p>
<p>proc_msg(); /* we have a message; process it */ </p>
<p>} else { </p>
<p>msg_char(']'); msg_char('%'); msg_char(c); </p>
<p>parse_state = IN_MESSAGE; </p>
<p>} </p>
<p>break; </p>
<p>default: </p>
<p>abort(); </p>
<p>} </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>程序17.13 input.c文件-读取和处理从打印机的输入 </p>
<p>每当我们等待从打印机返回EOF时就会调用函数proc_upto_eof。 </p>
<p>函数proc_some_input从串口读取。注意我们调用select
函数来确定什么时候 </p>
<p>该描述符是可以读取的。这是因为select
函数通常被一个捕捉到的信号所中断-它 </p>
<p>并不自动地重启动。因为select 函数能被SIGALRM或SIGINT所中断,我们并不希望
</p>
<p>它重启动。回忆一下在12.5节中我们关于select函数被正常中断的讨论。同样回忆
</p>
<p>在10.5节中我们设置SA_RESTART来说明当一个特定信号出现时,应当自动重启动的
</p>
<p>I/O函数。但是因为并不总是有一个附加的标志,使得我们可以说明I/O
函数不应 </p>
<p>当重启动。如果不设置SA_RESTART,我们只能倚赖系统的缺省值,而这可能是自动
</p>
<p>重新启动被中断的I/O函数。当从打印机返回输入时,我们以非阻塞模式读取,得
</p>
<p>到打印机准备就绪的数据。然后调用函数proc_input_char来处理每一个字符。
</p>
<p>处理打印机发送给我们的消息是由proc_input_char完成的。我们必须检查每
</p>
<p>一个字符并记住我们的状态。变量parse_state跟踪记录当前状态。调用msg_char
</p>
<p>函数把序列%%[以后所有的字符串储存在消息缓冲中。当遇到结束序列]%%时,我们
</p>
<p>调用proc_msg来处理消息。除了开始%%[ 和最后 ]%%序列以及二者之间的状态消息
</p>
<p>其他字符串,都被认为是用户的输出,被邮递给用户(调用mail_char)。
</p>
<p>我们现在查看那些处理由输入函数积累消息的函数。程序17.14是文件messag
</p>
<p>e.c。 </p>
<p>当检测到%%[ 后,调用函数msg_init。它只是初始化缓冲计数器。然后对于消
</p>
<p>息中的每一个字符都调用msg_char函数。 </p>
<p>函数proc_msg将消息分解为key:val对(关键字:值对),并检查key。调用A
</p>
<p>NSI C的strtok函数将消息分解为记号,每个key: val对用分号分隔。 </p>
<p>一个以下形式的消息 </p>
<p>%%[ Flushing : rest of job (to end-of-fiel) will be ignored ]%% </p>
<p>引起函数printer_flushing 被调用。它清理终端的缓冲,发送一个EOF给打印
</p>
<p>机,然后等待打印机返回一个EOF。 </p>
<p>如果收到一个以下形式的消息 </p>
<p>%%[ PrinterError: reason]%% </p>
<p>就调用log_msg函数来记录这个错误。带有Error Key的出错消息邮递传送回用
</p>
<p>户。这些一般是PostScript程序的错误。 </p>
<p>如果返回一个带有关键字status的状态消息,它很可能是由于函数get_statu
</p>
<p>s发送给打印机一个状态请求(Control-T)而引起的。我们查看val,并按照它来
</p>
<p>设置变量status。 </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>#include "lprps.h" </p>
<p>#include <ctype.h> </p>
<p>static char msgbuf[MBSIZE]; </p>
<p>static int msgcnt; </p>
<p>static void printer_flushing(void); </p>
<p>/* Called by proc_input_char() after it's seen the "%%[" that </p>
<p>* starts a message. */ </p>
<p>void </p>
<p>msg_init(void) </p>
<p>{ </p>
<p>msgcnt = 0; /* count of chars in message buffer */ </p>
<p>} </p>
<p>/* All characters received from the printer between the starting </p>
<p>* %%[ and the terminating ]%% are placed into the message buffer </p>
<p>* by proc_some_input(). This message will be examined by </p>
<p>* proc_msg() below. */ </p>
<p>void </p>
<p>msg_char(int c) </p>
<p>{ </p>
<p>if (c != '\0' && msgcnt < MBSIZE - 1) </p>
<p>msgbuf[msgcnt++] = c; </p>
<p>} </p>
<p>/* This function is called by proc_input_char() only after the final </p>
<p>* percent in a "%%[ <message> ]%%" has been seen. It parses the </p>
<p>* <message>, which consists of one or more "key: val" pairs. </p>
<p>* If there are multiple pairs, "val" can end in a semicolon. */ </p>
<p>void </p>
<p>proc_msg(void) </p>
<p>{ </p>
<p>char *ptr, *key, *val; </p>
<p>int n; </p>
<p>msgbuf[msgcnt] = 0; /* null terminate message */ </p>
<p>for (ptr = strtok(msgbuf, ";"); ptr != NULL; </p>
<p>ptr = strtok(NULL, ";")) { </p>
<p>while (isspace(*ptr)) </p>
<p>ptr++; /* skip leading spaces in key */ </p>
<p>key = ptr; </p>
<p>if ( (ptr = strchr(ptr, ':')) == NULL) </p>
<p>continue; /* missing colon, something wrong, ignore */ </p>
<p>*ptr++ = '\0'; /* null terminate key (overwrite colon) */ </p>
<p>while (isspace(*ptr)) </p>
<p>ptr++; /* skip leading spaces in val */ </p>
<p>val = ptr; </p>
<p>/* remove trailing spaces in val */ </p>
<p>ptr = strchr(val, '\0'); </p>
<p>while (ptr > val && isspace(ptr[-1])) </p>
<p>--ptr; </p>
<p>*ptr = '\0'; </p>
<p>if (strcmp(key, "Flushing") == 0) { </p>
<p>printer_flushing(); /* never returns */ </p>
<p>} else if (strcmp(key, "PrinterError") == 0) { </p>
<p>log_msg("proc_msg: printer error: %s", val); </p>
<p>} else if (strcmp(key, "Error") == 0) { </p>
<p>mail_line("Your PostScript printer job " </p>
<p>"produced the error `%s'.\n", val); </p>
<p>} else if (strcmp(key, "status") == 0) { </p>
<p>if (strcmp(val, "idle") == 0) </p>
<p>status = IDLE; </p>
<p>else if (strcmp(val, "busy") == 0) </p>
<p>status = BUSY; </p>
<p>else if (strcmp(val, "waiting") == 0) </p>
<p>status = WAITING; </p>
<p>else </p>
<p>status = UNKNOWN; /* "printing", "PrinterError", </p>
<p>"initializing", or "printing test page". */ </p>
<p>} else if (strcmp(key, "OffendingCommand") == 0) { </p>
<p>mail_line("The offending command was `%s'.\n", val); </p>
<p>} else if (strcmp(key, "pagecount") == 0) { </p>
<p>if (sscanf(val, "%d", &n) == 1 && n >= 0) { </p>
<p>if (start_page < 0) </p>
<p>start_page = n; </p>
<p>else </p>
<p>end_page = n; </p>
<p>} </p>
<p>} </p>
<p>} </p>
<p>} </p>
<p>/* Called only by proc_msg() when the "Flushing" message </p>
<p>* is received from the printer. We exit. */ </p>
<p>static void </p>
<p>printer_flushing(void) </p>
<p>{ </p>
<p>clear_intr(); /* don't catch SIGINT */ </p>
<p>tty_flush(); /* empty tty input and output queues */ </p>
<p>block_write(&eofc, 1); /* send an EOF to the printer */ </p>
<p>proc_upto_eof(1); /* this call won't be recursive, </p>
<p>since we specify to ignore input */ </p>
<p>get_page(&end_page); </p>
<p>do_acct(); </p>
<p>exit(EXIT_SUCCESS); </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>程序17.14 message.c文件,处理从打印机返回消息 </p>
<p>一个OffendingCommand的关键字一般总是与其它key : val对一起出现,如 </p>
<p>%% [ Error : stackunderflow ; OffendingCommand : pop ]%% </p>
<p>我们在送回给用户的邮件中就要添加一行。 </p>
<p>最后,在函数get_page(程序17.9)中的PostScript程序产生一个页面计数值
</p>
<p>。我们调用sscanf把val转换为二进制,设置起始或结束页面值变量。函数get_pa
</p>
<p>ge中的while循环就在等待这个变量变成非负值。 </p>
<p>17.5 摘要 </p>
<p>在这一章中实现一个完整的程序-它发送一个PostScript程序给连接在RS-232
</p>
<p>端口的PostScript打印机。这给我们一个实践机会,把前些章所介绍的很多函数用
</p>
<p>到一个实用的程序中:例如I/O多路转接、非阻塞的I/O、终端I/O和信号等。
</p>
<p>习题: </p>
<p>17.1 我们需要使用lprps来打印标准输入的文件,它也可能是一个管道。因为程序
</p>
<p>psif一定要查看输入文件的前两个字节,那么应当如何开发psif程序(图17.5)来
</p>
<p>处理这种情况呢? </p>
<p>17.2 实现psif过滤器,处理前一个练习中的实例。 </p>
<p>17.3 参考12.5节中Adobe Systems[1998]关于在Postscript程序中字体请求的处理
</p>
<p>,修改本章中的lprps程序以处理字体请求。 </p>
<p>-</font></p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -