1. 程式人生 > >【Unix/Linux程式設計實踐】 動手實現簡單的more

【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程式設計,雖然還有很多不完善的地方,但是完善本程式並不是我們的目的!