⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 17.htm

📁 UNIX环境下C编程的详细详细介绍
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<p>break; </p>

<p>case 'h': /* host name of user */ </p>

<p>hostname = optarg; </p>

<p>break; </p>

<p>case '?': </p>

<p>log_msg(&quot;unrecognized option: -%c&quot;, 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 &lt; 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) &lt; 0) /* register func for exit() */ </p>

<p>log_sys(&quot;main: atexit error&quot;); </p>

<p>get_status(); </p>

<p>get_page(&amp;start_page); </p>

<p>send_file(); /* copies stdin to printer */ </p>

<p>get_page(&amp;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(&quot;lprps: invalid arguments&quot;); </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 &quot;lprps.h&quot; </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 &gt; start_page &amp;&amp; </p>

<p>acct_file != NULL &amp;&amp; </p>

<p>(fp = fopen(acct_file, &quot;a&quot;)) != NULL) { </p>

<p>fprintf(fp, &quot;%7.2f %s:%s\n&quot;, </p>

<p>(double)(end_page - start_page), </p>

<p>hostname, loginname); </p>

<p>if (fclose(fp) == EOF) </p>

<p>log_sys(&quot;do_acct: fclose error&quot;); </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 &quot;lprps.h&quot; </p>

<p>#include &lt;fcntl.h&gt; </p>

<p>#include &lt;termios.h&gt; </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)) &lt; 0) </p>

<p>log_sys(&quot;set_block: fcntl F_GETFL error&quot;); </p>

<p>val &amp;= ~O_NONBLOCK; </p>

<p>if (fcntl(psfd, F_SETFL, val) &lt; 0) </p>

<p>log_sys(&quot;set_block: fcntl F_SETFL error&quot;); </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)) &lt; 0) </p>

<p>log_sys(&quot;set_nonblock: fcntl F_GETFL error&quot;); </p>

<p>val |= O_NONBLOCK; </p>

<p>if (fcntl(psfd, F_SETFL, val) &lt; 0) </p>

<p>log_sys(&quot;set_nonblock: fcntl F_SETFL error&quot;); </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(&quot;block_write: write error&quot;); </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) &lt; 0) </p>

<p>log_sys(&quot;tty_flush: tcflush error&quot;); </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)) &lt; 0) </p>

<p>log_sys(&quot;tty_open: open error&quot;); </p>

<p>if (tcgetattr(psfd, &amp;term) &lt; 0) /* fetch attributes */ </p>

<p>log_sys(&quot;tty_open: tcgetattr error&quot;); </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 &amp;= ~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(&amp;term, DEF_BAUD); </p>

<p>cfsetospeed(&amp;term, DEF_BAUD); </p>

<p>if (tcsetattr(psfd, TCSANOW, &amp;term) &lt; 0) /* set attributes */ </p>

<p>log_sys(&quot;tty_open: tcsetattr error&quot;); </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 &quot;lprps.h&quot; </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(&amp;c, 1); /* Control-C interrupts the PS job */ </p>

<p>block_write(&amp;eofc, 1); /* followed by EOF */ </p>

<p>proc_upto_eof(1); /* read &amp; ignore up through EOF */ </p>

<p>clear_alrm(); </p>

<p>get_page(&amp;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(&quot;set_intr: signal_intr error&quot;); </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(&quot;clear_intr: signal error&quot;); </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 &quot;lprps.h&quot; </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(&quot;printer not responding&quot;); </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(&quot;set_alrm: signal_intr error&quot;); </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(&quot;clear_alrm: signal error&quot;); </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 &quot;lprps.h&quot; </p>

<p>/* Called by main() before printing job. </p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -