APUE-分页读取文件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013139008/article/details/79432139

#include "ourhdir.h"
#include <sys/wait.h> // waitpid
#include <sys/types.h> // pid_t


#define DFL_PAGER  "/usr/bin/more"  // 默认的分页命令

int main(int argc, char *argv[]) {
    int fd[2]; // 使用全双工管道,父进程写入写端,子进程读取读端
    int n;     // 父进程读取文件的字符数
    char line[MAXLINE]; // MAXLINE=4096, ourhdir.h中定义
    char *pager;        // 从环境变量中获取分页命令的指针
    char *argv0;        // 调用exec函数使用的指针
    FILE *fp;
    pid_t pid;

    // 从命令行中获得待读取的文件
    if (argc != 2) {
        err_quit("usage: a.out <filename>");
    }

    // 打开输入的文件
    if ((fp = fopen(argv[1], "r")) == NULL) {
        err_sys("fopen %s error", argv[1]);
    }

    // 创建管道
    if (pipe(fd) < 0) {
        err_sys("pipe error");
    }

    // 创建子进程
    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid > 0) {
        close(fd[0]); // 关闭读端,管道返回的是文件描述符,所以使用close
        while (fgets(line, MAXLINE, fp) != NULL) {
            n = strlen(line);
            if (write(fd[1], line, n) < n) {
                err_sys("write error to pipe");
            }
        }

        // 如果是fgets函数出错退出,则打印出错信息
        if (ferror(fp)) {
            err_sys("fget error");
        }

        // 写端使用完之后,关闭
        close(fd[1]);

        // 等待子进程退出
        if (waitpid(pid, NULL, 0) < 0) {
            err_sys("waitpid error");
        }
    } else {
        close(fd[1]); // 子进程关闭写端
        // 将读端重定向到标准出错
        // 首先判断读端是否就是标准出错。如果不判断,而且读端已经是标准出错
        // 即使重定向执行成功,因为执行了close函数,就会把标准出错关闭掉
        if (fd[0] != STDIN_FILENO) {
            if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
                err_sys("dup2 error to stdin");
            }
            close(fd[0]);
        }

        // 获得环境变量:分页执行程序,获得失败,使用默认指定
        // 默认分页命令字符串:/usr/bin/more
        // 获得的环境变量分页命令:/usr/bin/more 或 more
        if ((pager = getenv("PAGER")) == NULL) {
            pager = DFL_PAGER;
        }

        // strrchr:返回字符串中从最后一个字符开始的指定字符的指针
        // 若未出现指定字符返回NULL
        // pager指向:/usr/bin/more
        if ((argv0 = strrchr(pager, '/')) != NULL) {
            argv0++;
        // pager指向:more
        } else {
            argv0 = pager;
        } // 该代码段执行结束,argv0指向的字符串是:more

        // 为什么执行了more命令就是将标准输出分页输出了?
        // 标准输出会作为more的输入进行分页显示?
        if (execl(pager, argv0, (char *)0) < 0) {
            err_sys("execl error for %s", pager);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013139008/article/details/79432139