【Unix/Linux编程实践】 动手实现简单的more

最近都在看一些理论方面的书,缺乏实践真的是云里雾里的,于是今天开始看《Unix/Linux编程实践教程》,理论实践相结合!

自己动手来实现linux的一些功能,确实挺有趣的,而且还能加深对系统的理解~

版本一

/*more01.c *read and print 24 lines then pause for a few special commands */

#include <stdio.h>

#define PAGELEN 24
#define LINELEN 512

/* *将数据显示在屏幕上,满一屏后,调用see_more函数接受用户的输入,以采取下一步动作。 */
void do_more(FILE *);   
int see_more();

int main(int argc, char * argv[])
{
    FILE *fp;
    //判断是文件还是标准输入,打开对应的数据源 
    if ( argc == 1)
        do_more(stdin);
    else
    {
        while (argc--)
        if ( (fp = fopen(* ++argv, "r")) != NULL) //第一个参数是more01,跳过
        {
            do_more(fp);
            fclose(fp);
        }
        else
            exit(1);
    }
    return 0;
}

void do_more(FILE *fp)
{
    char line[LINELEN];
    int num_of_lines = 0;
    int see_more(), reply;
    while ( fgets(line, LINELEN, fp) )  //逐行读
    {
        if (num_of_lines == PAGELEN)    //满屏
        {
            reply = see_more();
            if (reply == 0)
                break;
            num_of_lines -= reply;  //根据reply重置行数
        }
        if ( fputs(line, stdout) == EOF )
            exit(1);
        num_of_lines++;
    }
}

int see_more()
{
    int c;
    printf("\033[7m more? \033[m");
    while ( (c = getchar()) != EOF )    //获取用户输入
    {
        if ( c == 'q' )     //退出
            return 0;
        if ( c == ' ' )     //下一页
            return PAGELEN;
        if ( c == '\n' )    //下一行
            return 1;
    }
    return 0;
}

当然这个程序存在挺多问题的,比如输入q和空格后,需要按回车,而且输入是有回显的。

另外,一个比较严重的问题是,如果我们进行重定向:

ls /bin | more01

则more01的标准输入被重定向到ls的标准输出中,这样子用户的输入也从这个输入流中读取,明显有问题。用户的输入应该始终从键盘读取,而不应该被重定向。

所以版本二提供了直接从键盘设备读取的功能。

版本二

设备文件/dev/tty是键盘和显示器的设备描述文件,往该文件写则显示在用户屏幕上,读则从键盘获取用户输入。

/*  more02.c  - version 0.2 of more
 *  read and print 24 lines then pause for a few special commands
 *      feature of version 0.2: reads from /dev/tty for commands
 */
#include <stdio.h>

#define PAGELEN 24
#define LINELEN 512

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

int main( int ac , char *av[] )
{
    FILE    *fp;

    if ( ac == 1 )
        do_more( stdin );
    else
        while ( --ac )
            if ( (fp = fopen( *++av , "r" )) != NULL )
            {
                do_more( fp ) ; 
                fclose( fp );
            }
            else
                exit(1);
    return 0;
}

void do_more( FILE *fp )
/*
 *  read PAGELEN lines, then call see_more() for further instructions
 */
{
    char    line[LINELEN];
    int num_of_lines = 0;
    int see_more(FILE *), reply;
    FILE    *fp_tty;

    fp_tty = fopen( "/dev/tty", "r" );     /* NEW: cmd stream */
    if ( fp_tty == NULL )              /* if open fails     */
        exit(1);                           /* no use in running */

    while ( fgets( line, LINELEN, fp ) ){       
        if ( num_of_lines == PAGELEN ) {    
            reply = see_more(fp_tty);  /* NEW: pass FILE * */
            if ( reply == 0 )       
                break;
            num_of_lines -= reply;      /* reset count */
        }
        if ( fputs( line, stdout )  == EOF )    /* show line    */
            exit(1);            /* or die */
        num_of_lines++;             /* count it */
    }
}

int see_more(FILE *cmd)                /* NEW: accepts arg  */
/*
 *  print message, wait for response, return # of lines to advance
 *  q means no, space means yes, CR means one line
 */
{
    int c;

    printf("\033[7m more? \033[m");     /* reverse on a vt100 */
    while( (c=getc(cmd)) != EOF )       /* NEW: reads from tty  */
    {
        if ( c == 'q' )         
            return 0;
        if ( c == ' ' )         
            return PAGELEN;     
        if ( c == '\n' )        
            return 1;       
    }
    return 0;
}

通过一个直观的例子感受了下Linux编程,虽然还有很多不完善的地方,但是完善本程序并不是我们的目的!

你可能感兴趣的:(linux,more,编程实践)