?? 17.htm
字號:
<p>break; </p>
<p>case 'h': /* host name of user */ </p>
<p>hostname = optarg; </p>
<p>break; </p>
<p>case '?': </p>
<p>log_msg("unrecognized option: -%c", optopt); </p>
<p>usage(); </p>
<p>} </p>
<p>} </p>
<p>if (hostname == NULL || loginname == NULL) </p>
<p>usage(); /* require both hostname and loginname */ </p>
<p>if (optind < argc) </p>
<p>acct_file = argv[optind]; /* remaining arg = acct file */ </p>
<p>if (debug) </p>
<p>tty_open(); </p>
<p>if (atexit(close_mailfp) < 0) /* register func for exit() */ </p>
<p>log_sys("main: atexit error"); </p>
<p>get_status(); </p>
<p>get_page(&start_page); </p>
<p>send_file(); /* copies stdin to printer */ </p>
<p>get_page(&end_page); </p>
<p>do_acct(); </p>
<p>exit(EXIT_SUCCESS); </p>
<p>} </p>
<p>static void </p>
<p>usage(void) </p>
<p>{ </p>
<p>log_msg("lprps: invalid arguments"); </p>
<p>exit(EXIT_THROW_AWAY); </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>________ </p>
<p>程序17.3 main函數 </p>
<p>然后處理命令行參數,很多參數會被PostScript打印機所忽略。我們使用-d標
</p>
<p>志指示這個程序是交互運行,而不是作為精靈進程。如果設置了這個標志,我們需
</p>
<p>要初始化終端模式(tty_open)。然后我們將函數close_mailfp指定為退出處理程
</p>
<p>序。 </p>
<p>我們就可以調用在圖17.6中提到的函數:取得打印機狀態保證它是就緒的(ge
</p>
<p>t_status),得到打印機的起始頁碼(get_page),發送文件(PostScript程序)到
</p>
<p>打印機(send_file),得到打印機的結束頁碼(get_page),寫記帳記錄(do_acct),
</p>
<p>然后終止。 </p>
<p>文件acct.c定義了函數do_acct(程序17。4)。它在main函數的結尾處被調用,
</p>
<p>用來寫下記帳記錄。記帳文件的路徑和名字從printcap文件中的相應記錄項(圖1
</p>
<p>7.4)獲得,并作為命令行的最后一個參數。 </p>
<p>_______________________________________________________________________ </p>
<p>________ </p>
<p>#include "lprps.h" </p>
<p>/* Write the number of pages, hostname, and loginname to the </p>
<p>* accounting file. This function is called by main() at the end </p>
<p>* (if all was OK, by printer_flushing(), and by handle_intr() if </p>
<p>* an interrupt is received. */ </p>
<p>void </p>
<p>do_acct(void) </p>
<p>{ </p>
<p>FILE *fp; </p>
<p>if (end_page > start_page && </p>
<p>acct_file != NULL && </p>
<p>(fp = fopen(acct_file, "a")) != NULL) { </p>
<p>fprintf(fp, "%7.2f %s:%s\n", </p>
<p>(double)(end_page - start_page), </p>
<p>hostname, loginname); </p>
<p>if (fclose(fp) == EOF) </p>
<p>log_sys("do_acct: fclose error"); </p>
<p>} </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>________ </p>
<p>程序17.4 do_acct函數 </p>
<p>從歷史上看,所有的BSD打印過濾器都使用%7.2f的printf格式,把輸出的頁數
</p>
<p>寫到記帳文件中。這樣就允許光柵設備不使用頁數,而以英尺為單位報告輸出長度
</p>
<p>。 </p>
<p>下面一個文件是tty.c(程序17.5),它包含了所有的終端I/O函數。它們調用
</p>
<p>我們在第三章中提到的函數(fcntl, write和open)和第11章中的POSIX..1終端函
</p>
<p>數(tcflush, tcgetattr, tcsetattr, cfsetispeed 和cfsetospeed)。如果我們 </p>
<p>允許發生寫阻塞,那么要調用block_write函數。如果我們不希望發生阻塞,則調
</p>
<p>用set_nonblock函數,然后再調用read或者write函數。因為PostScript是一個全
</p>
<p>雙工的設備,打印機有可能發送數據回來(例如出錯消息等),所以我們不希望阻
</p>
<p>塞一個方向的寫操作。如果打印機發送錯誤消息時,我們正因向其發送數據而處于
</p>
<p>阻塞狀態,則會出現死鎖。 </p>
<p>一般是核心為終端輸入和輸出進行緩沖,所以如果發生錯誤,我們可以調用t
</p>
<p>ty_flush來刷清輸入和輸出隊列。 </p>
<p>如果以交互方式運行該程序,那么main函數將調用函數tty_open。我們需要把
</p>
<p>終端設為非規范模式,設置波特率和其他一些終端標志。注意各種PostScript打印
</p>
<p>機的這些設置并不都一樣。檢查你的打印機手冊確定它的設置。(數據的位數可能
</p>
<p>是7位或8位,起始位、停止位的數目以及奇偶校驗等都可能因打印機而異。)
</p>
<p>_______________________________________________________________________ </p>
<p>_______ </p>
<p>#include "lprps.h" </p>
<p>#include <fcntl.h> </p>
<p>#include <termios.h> </p>
<p>static int block_flag = 1; /* default is blocking I/O */ </p>
<p>void </p>
<p>set_block(void) /* turn off nonblocking flag */ </p>
<p>{ /* called only by block_write() below */ </p>
<p>int val; </p>
<p>if (block_flag == 0) { </p>
<p>if ( (val = fcntl(psfd, F_GETFL, 0)) < 0) </p>
<p>log_sys("set_block: fcntl F_GETFL error"); </p>
<p>val &= ~O_NONBLOCK; </p>
<p>if (fcntl(psfd, F_SETFL, val) < 0) </p>
<p>log_sys("set_block: fcntl F_SETFL error"); </p>
<p>block_flag = 1; </p>
<p>} </p>
<p>} </p>
<p>void </p>
<p>set_nonblock(void) /* set descriptor nonblocking */ </p>
<p>{ </p>
<p>int val; </p>
<p>if (block_flag) { </p>
<p>if ( (val = fcntl(psfd, F_GETFL, 0)) < 0) </p>
<p>log_sys("set_nonblock: fcntl F_GETFL error"); </p>
<p>val |= O_NONBLOCK; </p>
<p>if (fcntl(psfd, F_SETFL, val) < 0) </p>
<p>log_sys("set_nonblock: fcntl F_SETFL error"); </p>
<p>block_flag = 0; </p>
<p>} </p>
<p>} </p>
<p>void </p>
<p>block_write(const char *buf, int n) </p>
<p>{ </p>
<p>set_block(); </p>
<p>if (write(psfd, buf, n) != n) </p>
<p>log_sys("block_write: write error"); </p>
<p>} </p>
<p>void </p>
<p>tty_flush(void) /* flush (empty) tty input and output queues */ </p>
<p>{ </p>
<p>if (tcflush(psfd, TCIOFLUSH) < 0) </p>
<p>log_sys("tty_flush: tcflush error"); </p>
<p>} </p>
<p>void </p>
<p>tty_open(void) </p>
<p>{ </p>
<p>struct termios term; </p>
<p>if ( (psfd = open(DEF_DEVICE, O_RDWR)) < 0) </p>
<p>log_sys("tty_open: open error"); </p>
<p>if (tcgetattr(psfd, &term) < 0) /* fetch attributes */ </p>
<p>log_sys("tty_open: tcgetattr error"); </p>
<p>term.c_cflag = CS8 | /* 8-bit data */ </p>
<p>CREAD | /* enable receiv </p>
<p>r */ </p>
<p>CLOCAL; /* ignore modem </p>
<p>tatus lines */ </p>
<p>/* no pa </p>
<p>ity, 1 stop bit */ </p>
<p>term.c_oflag &= ~OPOST; /* turn off post processing */ </p>
<p>term.c_iflag = IXON | IXOFF | /* Xon/Xoff flow control */ </p>
<p>IGNBRK | /* ignore breaks </p>
<p>*/ </p>
<p>ISTRIP | /* strip input t </p>
<p>7 bits */ </p>
<p>IGNCR; /* ignore receiv </p>
<p>d CR */ </p>
<p>term.c_lflag = 0; /* everything off in local flag: </p>
<p>disables canonical mo </p>
<p>e, disables </p>
<p>signal generation, di </p>
<p>ables echo */ </p>
<p>term.c_cc[VMIN] = 1; /* 1 byte at a time, no timer */ </p>
<p>term.c_cc[VTIME] = 0; </p>
<p>cfsetispeed(&term, DEF_BAUD); </p>
<p>cfsetospeed(&term, DEF_BAUD); </p>
<p>if (tcsetattr(psfd, TCSANOW, &term) < 0) /* set attributes */ </p>
<p>log_sys("tty_open: tcsetattr error"); </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>_______ </p>
<p>程序17.5 終端函數 </p>
<p>這個程序處理兩個信號:SIGINT和SIGALRM。處理SIGINT是對BSD假脫機系統調
</p>
<p>用的任何一種過濾器的要求。如果打印機作業被lprm(1)命令刪除,那么這個信號
</p>
<p>被發送給過濾器。我們使用SIGALRM來設置超時,對這兩個信號用類似的方式處理
</p>
<p>:我們提供了set_XXX函數來建立信號處理器,clear_XXX函數來取消這個信號處理
</p>
<p>器。如果有信號傳送給這個進程,信號處理器在設置一個全局的標記intr_flag和
</p>
<p>alrm_flag后返回。程序的其它部分可在適當的時間來檢測這些標記。有一個明顯
</p>
<p>的時間是在I/O函數返回錯誤EINTR時,該程序然后調用handle_intr或者handle_a
</p>
<p>lrm來處理這種情況,調用signal_intr函數(程序10.13)來中斷一個慢速的系統
</p>
<p>調用。程序17.6是處理SIGINT信號的interrupt.c文件。 </p>
<p>當一個中斷發生時,我們必須發送PostScript的中斷字符(Control-C)給打
</p>
<p>印機,接著發送一個文件終止符(EOF)。這通常引起PostScript解釋器終止它正在
</p>
<p>解釋的程序。然后我們等待從打印機返回的EOF(我們稍后將描述proc_upto_eof函
</p>
<p>數)。我們讀取最后的頁碼,寫下記帳記錄,然后就可以終止了。
</p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>#include "lprps.h" </p>
<p>static void </p>
<p>sig_int(int signo) /* SIGINT handler */ </p>
<p>{ </p>
<p>intr_flag = 1; </p>
<p>return; </p>
<p>} </p>
<p>/* This function is called after SIGINT has been delivered, </p>
<p>* and the main loop has recognized it. (It not called as </p>
<p>* a signal handler, set_intr() above is the handler.) */ </p>
<p>void </p>
<p>handle_intr(void) </p>
<p>{ </p>
<p>char c; </p>
<p>intr_flag = 0; </p>
<p>clear_intr(); /* turn signal off */ </p>
<p>set_alrm(30); /* 30 second timeout to interrupt printer */ </p>
<p>tty_flush(); /* discard any queued output */ </p>
<p>c = '\003'; </p>
<p>block_write(&c, 1); /* Control-C interrupts the PS job */ </p>
<p>block_write(&eofc, 1); /* followed by EOF */ </p>
<p>proc_upto_eof(1); /* read & ignore up through EOF */ </p>
<p>clear_alrm(); </p>
<p>get_page(&end_page); </p>
<p>do_acct(); </p>
<p>exit(EXIT_SUCCESS); /* success since user lprm'ed the job */ </p>
<p>} </p>
<p>void </p>
<p>set_intr(void) /* enable signal handler */ </p>
<p>{ </p>
<p>if (signal_intr(SIGINT, sig_int) == SIG_ERR) </p>
<p>log_sys("set_intr: signal_intr error"); </p>
<p>} </p>
<p>void </p>
<p>clear_intr(void) /* ignore signal */ </p>
<p>{ </p>
<p>if (signal(SIGINT, SIG_IGN) == SIG_ERR) </p>
<p>log_sys("clear_intr: signal error"); </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>程序17.6 處理中斷信號的interrupt.c文件 </p>
<p>圖17.6寫明了哪些函數設置超時時間。我們只是在以下情況下設置超時:查詢
</p>
<p>打印機狀態(get_status)、讀取打印機的頁碼(get_page)或者當我們正中斷打印機
</p>
<p>時(handle_intr)。如果發生了超時,我們只需要記錄下錯誤,過一段時間后終
</p>
<p>止。程序17.7是alarm.c文件。 </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>#include "lprps.h" </p>
<p>static void </p>
<p>sig_alrm(int signo) /* SIGALRM handler */ </p>
<p>{ </p>
<p>alrm_flag = 1; </p>
<p>return; </p>
<p>} </p>
<p>void </p>
<p>handle_alrm(void) </p>
<p>{ </p>
<p>log_ret("printer not responding"); </p>
<p>sleep(60); /* it will take at least this long to warm up */ </p>
<p>exit(EXIT_REPRINT); </p>
<p>} </p>
<p>void /* Establish the signal handler and set the alarm. */ </p>
<p>set_alrm(unsigned int nsec) </p>
<p>{ </p>
<p>alrm_flag = 0; </p>
<p>if (signal_intr(SIGALRM, sig_alrm) == SIG_ERR) </p>
<p>log_sys("set_alrm: signal_intr error"); </p>
<p>alarm(nsec); </p>
<p>} </p>
<p>void </p>
<p>clear_alrm(void) </p>
<p>{ </p>
<p>alarm(0); </p>
<p>if (signal(SIGALRM, SIG_IGN) == SIG_ERR) </p>
<p>log_sys("clear_alrm: signal error"); </p>
<p>alrm_flag = 0; </p>
<p>} </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>程序17.7 處理超時的alarm.c文件 </p>
<p>程序17.8是函數get_status,這個函數由main函數調用。它發送一個Control
</p>
<p>-T到打印機以獲取打印機的狀態消息。打印機回送一行消息。如果我們接到的消息
</p>
<p>是: </p>
<p>%%[ status : idle]%% </p>
<p>這意味著打印機準備好執行一個新的作業。這個消息被函數proc_some_input
</p>
<p>讀取和處理(下面我們會討論這個函數)。 </p>
<p>_______________________________________________________________________ </p>
<p>______ </p>
<p>#include "lprps.h" </p>
<p>/* Called by main() before printing job. </p>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -