more指令
more指令是unix操作系统中的自带指令,其功能是将文件中的内容输出到终端上。相似功能的指令还有cat、less。
cat:将文件中所有内容全部输出到终端上。
more:将文件中的内容逐页显示到终端上,用户按空格键显示下一页,按b键退出,按回车键显示下一行。
less:比more拥有更多的功能,可以实现向前翻页。
实现more指令
在实现more指令之前,需要搞清楚,more指令的工作流程:将指定文件内容显示一页(24行)后,等待用户指令,如果指令‘q’则推出,是‘\n’则显示下一行,是‘ ’则显示下一页。直到文件内容全部输出完。
代码
#include"apue.h"
#include<stdio.h>
#define LINELEN 512
#define pagelen 23
int see_more(FILE* cmd)//获取指令
{
char c;
printf("\033[7m more?\033[m");
while((c=getc(cmd))!=EOF)
{
if(c=='q')
return 0;
if(c==' ')
return pagelen;
if(c=='\n')
return 1;
}
return 0;
}
void do_more(FILE *fp)//执行
{
char line[LINELEN];
int num=0;
int relay;
FILE* fp_tty;
if((fp_tty=fopen("/dev/tty","r"))==NULL)//读/dev/tty相当于从键盘获得输入,写/dev/tty相当于向屏幕输出。
exit(1);
while(fgets(line,LINELEN,fp))//使用fgets逐行读入
{
if(num==pagelen)
{
relay=see_more(fp_tty); //等待用户响应
if(relay==0)
exit(0);
num-=relay;
}
if(fputs(line,stdout)==EOF)
exit(1);
num++;
}
}
int main(int argc,char* argv[])
{
FILE *fp;
if(argc==1)
do_more(stdin);
else
{
while(--argc)
{
if((fp=fopen(*++argv,"rb"))!=NULL) //将指定文件逐个输出
{
do_more(fp);
fclose(fp);
}
else
exit(1);
}
}
return 0;
}
程序中还存在很多问题,其中在键入指令时需要回车才能让程序得到指令,但是在系统自带的more指令中是不需要的。而且也未添加显示百分比的功能。
这是写过的第一篇博客,希望每天能进步一点,加油,坚持!
-----------------------------------------------------分割线------------------------------------------------------在《unix/linux编程实践》书中第六章讲到了对终端进行编程。
在unix操作系统中,终端也只是一个特殊的文件。在上一次编写的more程序中,存在一个问题就是,每当用户输入指令时,需要按回车键,程序才能获得我们所输入的指令,而且回车键也会被作为一个指令处理。这与unix中的more指令肯定是不一样的。现在我们就通过修改终端文件来实现这个功能。需要用到两个函数:
int tcgetaddr(int fd,struct termios* info);
int tcsetaddr(int fd,int when,struct termios* info);
第一个函数获取fd文件描述符所关联的终端驱动程序的属性,并将其存放在info指向的地址中。
第二个函数将fd关联的终端驱动程序的属性设置为info所指属性。标志位when可以是:TCSANOW:立即修改
TCSADRAIN:等待驱动程序中的所有输出被传到终端后再修改。
TCSAFLUSH:待所有输出被传出去,释放所有输入,再修改。
代码
#include"apue.h"
#include<stdio.h>
#include<termios.h>
#define LINELEN 512
#define pagelen 23
static struct termios mode;
void tty_mode(int how)//获取当前终端属性,用于程序结束后将终端驱动属性恢复
{
if(how==0)
{
tcgetattr(0,&mode);
}
else
{
tcsetattr(0,TCSANOW,&mode);
}
}
void set_mode()
{
struct termios ttystate;
tcgetattr(0,&ttystate);
ttystate.c_lflag&=~ICANON;//关闭缓冲,不在需要回车才能让程序获得指令
ttystate.c_lflag&=~ECHO;//关闭回显
ttystate.c_cc[VMIN]=1;//终端每次获取字符数为1
tcsetattr(0,TCSANOW,&ttystate);
}
int see_more(FILE* cmd)
{
char c;
printf("\033[7m more?\033[m");
set_mode();
while((c=getc(cmd))!=EOF)
{
if(c=='q')
{
tty_mode(1);
return 0;
}
else if(c==' ')
{
tty_mode(1);
return pagelen;
}
else if(c=='\n')
{
tty_mode(1);
return 1;
}
else
continue;
}
return 0;
}
void do_more(FILE *fp)
{
char line[LINELEN];
int num=0;
int relay;
FILE* fp_tty;
if((fp_tty=fopen("/dev/tty","r"))==NULL)
exit(1);
while(fgets(line,LINELEN,fp))
{
if(num==pagelen)
{
relay=see_more(fp_tty); //wait user
if(relay==0)
exit(0);
num-=relay;
}
if(fputs(line,stdout)==EOF)
exit(1);
num++;
}
}
int main(int argc,char* argv[])
{
FILE *fp;
tty_mode(0);
if(argc==1)
do_more(stdin);
else
{
while(--argc)
{
if((fp=fopen(*++argv,"rb"))!=NULL)
{
tty_mode(0);
set_mode();
do_more(fp);
fclose(fp);
tty_mode(1);
}
else
exit(1);
}
}
return 0;
}