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