编写Linux的more指令

more01是《Unix/Linux编程实践教程》中的一个例子,源程序注释我附在文末,这里有几个我觉得重要的地方:

1.对num_of_lines的理解

屏幕是分成24行的,这个变量就代表是从上往下第几行。

首次执行时,num_of_lines为初值0,此时while循环所做的就是其递增到24,同时输出24行内容。(若文本文件本身不足24行的话,显示结束程序就自动退出了。)

而只有当num_of_lines达到24时,才会执行see_more函数(未到24行时,就像程序正在运行,执行显示功能,而到了24行时,就像这一过程结束,等待用户下一步动作。),等待用户下一步动作。

当用户按了回车,num_of_lines变成了23,则要自增一次并输出一行,也就是新的24行。 当用户按了空格,num_of_lines变成了0,此时就代表是新一屏的第零行,因此执行了输出24行的操作,相当于新的一屏把旧的一屏顶了上去。

2.对这五行代码

[c]
if(ac == 1)
do_more(stdin);
else
while(--ac)
if((fp = fopen(* ++av, "r")) != NULL)
[/c]

这里涉及到传入到main函数的两个参数——变量ac和数组av[]。
ac代表一个数,当这条命令没有传入参数时,它就为1,此时av也只有一个元素,是命令的名称。而当有一个传入参数时ac值就为2,av在上述基础上,又多出来一个元素,是这个参数的名称。当参数大于一个时,以此类推。由此可见,ac具有某种指示功能。
而这段代码中正是通过判断ac是否为一来判断这条命令有没有传入参数,若没有就把标准输入传进来,若有就打开参数里指示的文件。特别地,如果有多个参数输入,程序并没有丢弃参数,而是打开一个,看完或者是用户退出,然后再打开下一个,直到所有参数都进行完。

以下是程序,被我注释得有点乱了。。。= =

[c]

#include<stdio.h>

#define PAGELEN 24 //每屏显示24行
#define LINELEN 512 //每行占512个字节

void do_more(FILE *);
int see_more();

int main( int ac,char * av[] )
{
FILE * fp; //声明文件指针

//此处的讨论是因为用户在调用指令是,会以不同方式传入参数。
//ac默认值为一,用户每传入一个参数,ac就相应地递增一。
//ac与av数组是对应的。av[1]表示程序名称,若有参数,av[2]
//表示第一个参数,以此类推。
if(ac == 1)
do_more(stdin); //当没有参数时,就从标准输入中找文本
else
while(--ac) //当有参数时,把参数一个一个提出来,
//按照顺序打开、阅读,待一个结束后,
//在进行下一个参数的。
if((fp = fopen(* ++av, "r")) != NULL)
{
do_more(fp); //把打开的文件,传给do_more
//来进行分屏算法,再利用
//see_more显示
fclose(fp); //从do_more里退出来,就代表
//阅读结束了,关闭文件。
}
else
exit(1);
return 0; //退出程序
}

void do_more(FILE *fp)
{
//代表每一行的内容,通过fgets( line,LINELEN,fp)缓冲进来
char line[LINELEN];

//num_of_lines表示的是当前行
int num_of_lines = 0;

//在do_more函数里声明了see_more,后者用于显示左下角的more,
//和处理用户的操作
int see_more(),reply;

//while内的操作代表缓冲512字节到line中,进行下面的显示、操作。而放在while中则代表,每次缓冲用完后,则自动再缓冲一次,若用户不在中途退出,则一直缓冲到文件结束。
while( fgets( line,LINELEN,fp) ){
if( num_of_lines == PAGELEN){
reply = see_more(); //获得用户的输入
if( reply == 0) //用户选择退出,直接中断这个循环即可
break;
num_of_lines -= reply; //如果用户按了空格,则see_more返回24,num_of_lines减到0了,则下面将重新输出24行,即是前进一页。
//如果用户按下了回车,则num_of_lines只变为23,只要再循环一次,又可补齐24,即是前进一行。
}
if( fputs( line,stdout ) == EOF )//用于输出一行的内容,若到头了,这个if条件成立,程序直接退出了
exit(1);
num_of_lines++; //最后,行数加一,通过while再缓冲一行内容,进行上述操作
}
}

//这个就比较简单了
int see_more()
{
int c;
//这里是显示左下角那个more的,加上“\033[7m \033[7m”就能反色了,printf语法里面有写,还能实现别的效果,比若显示别的颜色什么的
printf("\033[7m more? \033[7m");
while((c=getchar()) != EOF )
{
if( c == 'q')
return 0;
if( c == ' ')
return PAGELEN;
if( c == 'n')
return 1;
}
return 0;
}

[/c]