APUE fig 1.10示例代码的完善对提示符及输入回车的优化

 APUE 第3版第15页的shell2.c示例程序,运行效果如下:

 1 gcc ol.shell.c -o origin_shell
 2 
 3 ./origin_shell
 4 % date
 5 2015年12月13日 星期日 22时04分48秒 CST
 6 % ^Cinterrupt
 7 ls
 8 Makefile    getcputc.c    mycat.c        myls_info.c    note.md        origin_shell    shell2.c    uidgid.c
 9 a.out        hello.c        myls.c        myls_sort.c    ol.shell.c    shell1.c    testerror.c
10 % %
11 couldn't execute: : No such file or directory
12 % ls
13 Makefile    getcputc.c    mycat.c        myls_info.c    note.md        origin_shell    shell2.c    uidgid.c
14 a.out        hello.c        myls.c        myls_sort.c    ol.shell.c    shell1.c    testerror.c
15 %

从上述示例中可以看出,存在2个小问题:

1. 当通过ctrl+C输入中断信号时,中断捕获程序的输出语句的“%”并没有立即输出来,等到下一次回车时才输出,导致第10行有两个%%号。

2. 当出现%提示符时,直接回车,会提示如11行所示的错误。因为此时传递给execlp函数的buf内容是空的。其中问题1是出现在程序中的如下一句:

while (fgets(buf, MAXLINE, stdin) != NULL) {
}
// 即中断信号中断的是fgets函数,此时系统正在请求输入中,而中断处理程序的输出:

printf("interrupt\n%% ");

// 在换行之后,%并没有立即出来。如果将其修改如下,

printf("interrupt\n%%\n"); // 则显示效果变成这样:
1 % ^Cinterrupt
2 %
3 ls
4 Makefile    mycat.c        note.md        shell2.c
5 a.out        myls.c        ol.shell.c    testerror.c
6 getcputc.c    myls_info.c    origin_shell    uidgid.c
7 hello.c        myls_sort.c    shell1.c

如上可见,上述增加一个'\n'后,虽然立即输出了%,但如第3行所见,光标移到%下一行了。

一个解决办法是使用fflush()函数。完整代码,新增为21-24行,以及46行:

 1 #include "../apue.h"
 2 #include <sys/wait.h>
 3 
 4 static void    sig_int(int);        /* our signal-catching function */
 5 
 6 int
 7 main(void)
 8 {
 9     char buf[MAXLINE];    /* from apue.h */
10     pid_t  pid;
11     int  status;
12 
13     if (signal(SIGINT, sig_int) == SIG_ERR)
14         err_sys("signal error");
15 
16     printf("%% ");    /* print prompt (printf requires %% to print %) */
17     while (fgets(buf, MAXLINE, stdin) != NULL) {
18         if (buf[strlen(buf) - 1] == '\n')
19             buf[strlen(buf) - 1] = 0; /* replace newline with null */
20 
21         if (strlen(buf) == 0) { // 此if语句用于处理直接回车
22             printf("%% ");  
23             continue;
24         }
25 
26         if ((pid = fork()) < 0) {
27             err_sys("fork error");
28         } else if (pid == 0) {        /* child */
29             execlp(buf, buf, (char *)0);
30             err_ret("couldn't execute: %s", buf);
31             exit(127);
32         }
33 
34         /* parent */
35         if ((pid = waitpid(pid, &status, 0)) < 0)
36             err_sys("waitpid error");
37         printf("%% ");
38     }
39     exit(0);
40 }
41 
42 void
43 sig_int(int signo)
44 {
45       printf(" interrupt!\n%%");
46       fflush(stdout);   //强制输出所有stdout中的字符流
47 }

 完善后效果如下:

1 % date
2 2015年12月13日 星期日 22时31分53秒 CST
3 % ^C interrupt!
4 % date
5 2015年12月13日 星期日 22时32分15秒 CST
6 %
7 %
原文地址:https://www.cnblogs.com/qinqiao/p/opt_apue_fig1_10_shell2.html