?? 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 + -