实现more

发现还是基本功要扎实才行,重新学习linux, 做好读书笔记

程序要访问设备,必须要通过内核才能实现。 编写普通程序可以认为程序是直接访问键盘,显示器等。但是在进行inux系统编程的时候,就必须知道内核提供了哪些服务,如何使用它们。系统有哪些资源和设备,应该要如何操作。

本次编写的more,按照3个问题来实现

1. more能做什么

2. more是如何实现的

3. 能不能自己编写一个more

1. more能做什么?

more,cat,less,pg都是属于查看文件内容的。 cat是整个一期显示。more是当文件很多的时候,分屏显示。

more有3种用法:

$more filename      //显示filename的内容

$command | more  //将command命令的输出分页显示

$more < filename   //more的输入被重定向为filename

2. more是如何实现的

A 显示24行的输出

B 左下角显示more?

C 用户输入 回车,空格,或者q,分别代表下一页,下一行和退出

3. 能不能自己编写一个more。

按照2的思路,完全可以用c写一个简单的more

伪代码如下:

do_more(FIIE):

循环读取文件:

显示24行的内容

获取more的输入命令

根据输入命令,继续处理显示内容

获取more的输入命令:

Enter-> 返回读取下一行请求

空格 -> 返回读取下一页请求

q    -> 返回 退出

#include<stdio.h>

#define LINELEN 512
#define PAGELEN  24
#define QUIT     -1
#define NEXTLINE  1

int get_cmd_more();
void do_more(FILE* fp);

int main(int ac, char* av[]){
    FILE * fp= NULL;

    if(ac == 1){
        do_more(stdin);
    }else{
        //如果输入多个文件,依次打开文件
        while (--ac) {
            if(fp = fopen(*++av,"r")){
                do_more(fp);
            }else{
                exit(1);
            }
        }//end while
    }

    return 0;
}

//do_more(FIIE):
void do_more(FILE* fp){
    char line[LINELEN];
    int lineCount =0;
    int cmdLineNum =0;
    //    循环读取文件,fgets每次读取一行,每行512个字节:
    while (fgets(line,LINELEN,fp)) {
        //读一行显示一行
        if( fputs(line,stdout) == EOF)
            exit(1);

        //当读取行数满足24行后,显示more?
        if(lineCount == PAGELEN){
            //获取more的输入命令
            cmdLineNum = get_cmd_more();
            //根据输入命令,继续处理显示内容
            if(cmdLineNum == QUIT)
                break;
            lineCount -= cmdLineNum;
        }

        //这行的数据处理完后,数量+1
        lineCount++;

    }//end while

}

//获取more的输入命令:
int get_cmd_more(){
    //    Enter-> 返回读取下一行请求
    //空格 -> 返回读取下一页请求
    //q    -> 返回 退出
    int getCmd=0;
    printf("\033[7m more?\033[m");

    getCmd = getchar();
    switch (getCmd) {
    case ‘\n‘:
        return NEXTLINE;
    case ‘ ‘:
        return PAGELEN;
    case ‘q‘:
        return QUIT;
    default:
        return 0;
    };
}

在main中检查了参数, 如果没有参数,就从标准输入中读取,运行程序ls | myMore,发现是全部数据一次性输出的,没有出现期望的分页。

当more 读入第24行后,打印了more?然后是用getchar,从标准输入中读入数据,但是我们现在重定向到ls的标准输出了。 所以more现在至少有2个输入源。我们使用键盘和显示器的设备描述符,对输入和输出进行抽象, 更新代码如下

#include<stdio.h>

#define LINELEN 512
#define PAGELEN  24
#define QUIT     -1
#define NEXTLINE  1

int get_cmd_more(FILE* );
void do_more(FILE* fp);

int main(int ac, char* av[]){
    FILE * fp= NULL;

    if(ac == 1){
        do_more(stdin);
    }else{
        //如果输入多个文件,依次打开文件
        while (--ac) {
            if(fp = fopen(*++av,"r")){
                do_more(fp);
            }else{
                exit(1);
            }
        }//end while
    }

    return 0;
}

//do_more(FIIE):
void do_more(FILE* fp){
    char line[LINELEN];
    int lineCount =0;
    int cmdLineNum =0;
    //开启键盘和显示器的设备描述文件
    FILE* fp_tty;
    fp_tty = fopen("/dev/tty","r");
    if(!fp_tty)
        exit(1);

    //    循环读取文件,fgets每次读取一行,每行512个字节:
    while (fgets(line,LINELEN,fp)) {
        //读一行显示一行
        if( fputs(line,stdout) == EOF)
            exit(1);

        //当读取行数满足24行后,显示more?
        if(lineCount == PAGELEN){
            //获取more的输入命令
            cmdLineNum = get_cmd_more(fp_tty);
            //根据输入命令,继续处理显示内容
            if(cmdLineNum == QUIT)
                break;
            lineCount -= cmdLineNum;
        }

        //这行的数据处理完后,数量+1
        lineCount++;

    }//end while

}

//获取more的输入命令:
int get_cmd_more(FILE* cmd){
    //    Enter-> 返回读取下一行请求
    //空格 -> 返回读取下一页请求
    //q    -> 返回 退出
    int getCmd=0;
    printf("\033[7m more?\033[m");

    getCmd = getc(cmd);
    switch (getCmd) {
    case ‘\n‘:
        return NEXTLINE;
    case ‘ ‘:
        return PAGELEN;
    case ‘q‘:
        return QUIT;
    default:
        return 0;
    };
}

基本上一个简单的more就实现了。

时间: 2024-11-04 19:33:07