UNIX编程学习——more指令实现

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值