发现还是基本功要扎实才行,重新学习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就实现了。