linux中more命令启动程序,linux下more命令的实现

本文只是学渣作者的学习经历,能帮到读者是作者的荣幸。功能没有实现完全,希望各位多多提意见。

more命令基本功能实现:‘q’--退出,空格--下一页,回车键--下一行,清屏幕显示,关闭回显,执行命令无需按键enter.

支持多种用法:         more file    ls /bin/ | more      more < file

在实现ls /bin/ | more 时,需要将显示输入和用户命令输入分开,即打开/dev/tty来实现命令输入。

不足:1.在每次空格或回车后,"more?"都会显示出来

2.没有显示百分数

3.没有对文件类型进行判断--可以通过magic number实现

1)读写函数的用法---在实现more命令时的总结

fopen\fclose

1.FILE *fopen(const char *filename, const char *mode)

fopen打开有filename指定的文件,并把它与一个文件流关联起来。

成功打开,返回一个非空FILE *指针,失败返回NULL。

filename可以是某个text文件,也可以是某个设备名,比如/dev/tty

mode 是打开模式,可以是 r--只读。w--写方式,新内容覆盖就的内容。a--写方式,新内容追加在文件尾。a+ -- 更新的方式打开,追加。其它。

2. int fclose(FILE *stream)

关闭指定的文件流stream

fread\fwrite

1. size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream)

fread 将文件流中的数据读到ptr所指空间中。

fread(buf,sizeof(char),strlen(buf),stream);

buf是空闲内存空间,一般是 char buf[1024]

sizeof(char)是一个char类型的大小,也是fread一次读取的大小

strlen(buf)是读取的次数,一般是数组长度。

stream是fopen返回的非空文件流指针。

读取与stream关联的文件,每次读sizeof(char)大小,读strlen(buf)次。

fread 返回的是成功读到数据缓冲区里的记录个数。这里是strlen(buf)个记录。

读到buf中的数据,系统自动在数据最后添加一个“\n”

2.size_t fwrite(const void *ptr,size_t size,size_t nitems, FILE *stream)

fwrite将ptr所指空间的内容写到文件流中。

用法与fread相似

fgets\fputs

1. char *fgets(char *s,int n,FILE *stream)

fgets把读到的字符写到s指向的字符串里,知道出现以下情况;遇到换行符,已经传输了n-1个字符,或者到达文件尾。

成功完成,返回一个指向字符串s的指针; 出错,返回一个空指针; 到达文件尾,fgets会设置这个文件流的EOF标识,并返回一个空指针。

2. int fputs(const char *s, FILE *stream)

fputs将s指向字符串写到文件流stream中(不自动写入字符串结束标记符'\0')。

成功完成,返回非负数; 失败返回EOF。

fseek----本实例中没有用到 ,但通过它读取文件magic number来实现对文件类型的判断

1. int fseek(FILE *stream,long int offset, int whence)

fseek在文件流里为下一次读写操作指定位置。

offset--指定位置,与whence联用

whence取值:

SEEK_SET --- 表明offset是相对于文件头的一个相对值,则从offset处读取数据(其实是相对于文件头的)

SEEK_CUR --- 表明offset是相对于当前位置的一个相对值,则从当前位置偏移offset出读取数据

SEEK_END --- 表明offset是相对于文件尾的一个相对值,则从距文件尾offset处开始读取数据。特别注意:此处的offset是负值

fseek 返回0表示成功 ,返回-1表示失败,并设置errno指出错误。

memset

1. void *memset(void *s, int ch, size_t n)

在一段内存中填充ch,以达到对较大结构体或数组进行初始化(清零操作)。

试验案例:在声明一个字符数组后 char buf[1024],系统会随机给buf赋值,如果没有进行memset(buf,0,1024)操作,则在进行fread之后,       用printf输出buf时会有乱码。

2)终端控制

(1)利用终端结构体termios实现回显关闭,非标准输入行处理设 置

termios可对终端接口进行控制,termios数据结构和相关函数调用定义在termios.h中

可以被调整来影响终端的值按照不同的模式被分成如下几组:输入模式,输出模式,控制模式 ,本地模式,特殊控制字符。

在本例中用到了本地模式,特殊控制字符,以下是运行本例的前期知识准备:

最小的termios结构的典型定义如下:

回显功能关闭:         c_lflag &= ~ECHO

非标准输入行处理: c_lflag &= ~ICANON;                                                  c_cc[VMIN] = 1;c_cc[VTIME] = 0

涉及到的函数原型:

int tcgetattr(int fd, struct termios *termios_p)

int tcsetattr(int fd,int actions,const struct termios *termios_p)

参数列表中:fd为文件流的文件描述符,可以通过函数fileno(FILE *)来得到。

(2)利用terminfo软件包完成清屏,光标定位。

terminfo使程序不必去迎合多变的终端类型,其只要通过查询终端类型数据库来找到正确的终端信息。

在多数现代UNIX系统(包括linux)中,这个软件包和另一个软件包curses集成在一起。

为了使用terminfo函数,通常需要包括curses头文件curses.h和terminfo自己的头文件term.h。

在本例中,我们利用terminfo获取屏幕信息,实现了清屏和光标定位的功能。

涉及到的函数原型为:

1. int setuptterm(char *term, int fd, int *errret);

设置终端类型,为当前的终端类型初始化一个TERMINAL结构。

char *term为NULL是则使用环境变量TERM值(其实我们的目的就是获取当前终端类型的TERMINAL结构体,所以此项一般设置为NULL)

2. int tigetnum(char *capname);

通过capname获取数值型terminfo数据项,如终端显示的最大行数,最大列数等数值型数据项。

3.char *tigetstr(char *capname);

通过capname获取字符型terminfo数据项,如清屏的命令字符串,光标移动的命令字符串,其是参数化字符串,即还需要通过tparm函数来输入具体的光标位置。

4.char *tparm(char *cap,long p1,long p2,..., long p9);

同过tparm函数实际的数值替换功能替换命令字符串中的参数,如光标移动的命令字符串。

5.int putp(char *const str);

putp将命令字符串发到终端,其针对的是标准输出流。如果不能通过标准输出stdout访问终端,则需要 tputs(char *const str,int affcnt, int (*putfunc)(int))来

指定一个用 于输出  字符的函数putfunc, putp(string)相当于tputs(string,1,putchar),int affcnt一般置为1。

(3)对于终端的控制还可以用ncurses库函数实现。

Referrences:

《Unix/Linux编程实践教程》

《Linux程序设计》 Edition 4

代码实现:(站在巨人的肩膀上)

运行平台:CentOS6.4 GCC 4.4.7

#include

#include

#include

#include

#include

typedef int Status;

int LINELEN,PAGELEN; //全局变量,在GetTermInfo中获得

/*more的具体实现*/

Status DoMore(FILE *);

/*用户命令输入处理*/

Status SeeMore(FILE *);

/*实现回显功能关闭和非标准行处理*/

Status EchoSet(struct termios *,FILE *);

/*恢复初始设置*/

Status EchoBack(struct termios *,FILE *);

/*实现清屏,光标定位*/

Status GetTermInfo();

Status DoMore(FILE *fp)

{

struct termios *initialrsettings,*newrsettings;

initialrsettings = (struct termios *)malloc(sizeof(struct termios));

newrsettings = (struct termios *)malloc(sizeof(struct termios));

char line[LINELEN];

int num_of_lines = 0;

int user_action;

FILE *fp_tty;

fp_tty = fopen("/dev/tty","r");

if(NULL == fp_tty)

{

exit(1);

}

tcgetattr(fileno(fp_tty),initialrsettings);

*newrsettings = *initialrsettings;//此处不要用指针赋值,否则无法恢复初始设置.

while(fgets(line,LINELEN,fp))

{

if(num_of_lines == PAGELEN)

{

EchoSet(newrsettings,fp_tty);

user_action = SeeMore(fp_tty);

if(user_action==0)

{

EchoBack(initialrsettings,fp_tty); //恢复终端初始设置

printf("\n");

break;

}

num_of_lines = num_of_lines - user_action;

}

if(fputs(line,stdout)==EOF)

{

exit(1);

}

num_of_lines++;

}

EchoBack(initialrsettings,fp_tty);//恢复终端初始设置

}

int SeeMore(FILE *cmd)

{

char c;

printf("\033[7m more? \033[m");

while((c=fgetc(cmd))!=EOF)

{

if(c == 'q')

{

return 0;

}

if(c == ' ')

{

return PAGELEN;

}

if(c == '\n')

{

return 1;

}

}

return 0;

}

/*关闭会显.需要termios.h*/

Status EchoSet(struct termios *newrsettings,FILE *fp_tty)

{

if(NULL == newrsettings||NULL == fp_tty)

{

return 1;

}

(*newrsettings).c_lflag &= ~ECHO;//关闭回显

(*newrsettings).c_lflag &= ~ICANON;//以下三行--无需输入回车即可执行用户命令

(*newrsettings).c_cc[VMIN] = 1;

(*newrsettings).c_cc[VTIME] = 0;

tcsetattr(fileno(fp_tty),TCSAFLUSH,newrsettings);

//free(newrsettings); //运行此行代码出错,因为 tcsetattr调用完毕后自动free.

//newrsettings = NULL;

return 0;

}

/*恢复回显功能*/

Status EchoBack(struct termios *initialrsettings,FILE *fp_tty)

{

if(NULL == initialrsettings||NULL == fp_tty)

{

return 1;

}

tcsetattr(fileno(fp_tty),TCSANOW,initialrsettings);

return 0;

}

Status GetTermInfo()

{

char *clear,*cursor;

setupterm(NULL,fileno(stdout),(int *)0);

clear = (char *)tigetstr("clear");

cursor = (char *)tigetstr("cup");

PAGELEN = tigetnum("lines")-1;

LINELEN = tigetnum("cols");

putp(clear);

putp(tparm(cursor,0,0));

return 0;

}

int main(int ac,char *av[])

{

FILE *fp;

if(ac == 1)

{

GetTermInfo();

DoMore(stdin);

}else

{

while(--ac)

{

if((fp=fopen(*++av,"r"))!=NULL)

{

GetTermInfo();

DoMore(fp);

fclose(fp);

}else

{

exit(1);

}

}

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值