电竞比分网-中国电竞赛事及体育赛事平台

分享

Understanding Unix/Linux Programming習(xí)題:tail命令...

 WUCANADA 2013-06-29

tail這個(gè)命令實(shí)在變態(tài),在參考了BSD和GNU的版本后,終于寫(xiě)出自己的版本。。。

ps:BSD那個(gè)版本很難看懂,可能是因?yàn)槭?977年寫(xiě)的關(guān)系吧。。。

下面是代碼,僅供參考(小弟水平有限,只實(shí)現(xiàn)了主要的功能:顯示倒數(shù)n行,顯示倒數(shù)n字節(jié),標(biāo)準(zhǔn)輸入顯示倒數(shù)10行)

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>

#define PIPE_FILE "/tmp/tail_fifo"

void tail_lines(int fd, int lines);
void tail_bytes(int fd, off_t bytes);
void pipe_lines();

/*
 * pipe_lines function is usef for read the 10 lines from the end of standard input
 * File description res is the file read from the standard input
 * Finally, call "tail_lines" function to aim the target.
 */
void pipe_lines()
{
    int nread;
    int res;
    char buf[BUFSIZ];
    res = open(PIPE_FILE, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
    if(res == -1)
    {
        fprintf(stderr, "Could not read the pipe file\n");
        exit(1);
    }
    while((nread = read(fileno(stdin), &buf, BUFSIZ)) > 0)
    {
        write(res, &buf, nread);
    }
    tail_lines(res, 10);
    close(res);
}

/*
 * tail_lines function is used for print the last "lines" lines from the end of file fd
 */
void tail_lines(int fd, int lines)
{
    char buf[BUFSIZ];/*buffer*/
    int nread;
    int i;/*for scanning the buf*/
    off_t pos = lseek(fd, (off_t)0, SEEK_END);/* locate the pos to the end of file */
    int size = (int)pos;
    nread = (int)pos % BUFSIZ; /* partitioning the file with BUFSIZ, get the remaining part */
    if(nread == 0)
        nread = BUFSIZ;
    pos -= nread;

    /*
     * Scanning the remaining part
     * It is also useful for the condition that file size is smaller than BUFSIZ
     */
    lseek(fd, pos, SEEK_SET);
    if((nread = read(fd, &buf, nread)) <= 0)
    {
        fprintf(stderr, "Could not open the file\n");
        exit(1);
    }
    for(i = nread - 1; i >= 0; i--)
    {
        if(buf[i] == '\n' || buf[i] == EOF)
            lines--;
        if(lines < 0)
        {
            pos += i + 1;
            break;
        }
    }
    /*
     * If lines is not enough, print all the file
     */
    if(lines >= 0)
        pos = (off_t)0;
    /*
     * scannning for N * BUFSIZ
     */
    while(lines >= 0 && size > BUFSIZ)
    {
        pos -=BUFSIZ;
        if(pos < 0)
        {
            pos = (off_t)0;
            break;
        }
        lseek(fd, pos, SEEK_SET);
        if((nread = read(fd, &buf, BUFSIZ)) <= 0)
        {
            perror("Could not read the file");
            exit(1);
        }
        for(i = nread - 1; i >=0; i--)
        {
            if(buf[i] == '\n'|| buf[i] == EOF)
                lines--;
            if(lines < 0)
            {
                pos += i + 1;
                break;
            }
        }
    }
    /*
     * Locate the target
     * Print the result
     */
    lseek(fd, pos, SEEK_SET);
    while((nread = read(fd, &buf, BUFSIZ)) > 0)
    {
        write(fileno(stdout), &buf, nread);
    }
}

/*
 * Tail_bytes function is used to print the last "bytes" bytes from the end of file fd
 */
void tail_bytes(int fd, off_t bytes)
{
    off_t pos;
    int nread;
    char buf[BUFSIZ];
   
    pos = lseek(fd, (off_t)0, SEEK_END);
    if(pos < bytes)
    {
        fprintf(stderr, "The offset %d is bigger than file's size\n", (int)bytes);
        exit(1);
    }

    pos -= bytes;
    lseek(fd, pos, SEEK_SET);
    while((nread = read(fd, &buf, BUFSIZ)) > 0)
    {
        write(fileno(stdout), &buf, nread);
    }
}





int main(int argc, char *argv[])
{
    int fd;
    int opt;
    int off_bytes = -1;
    int off_lines = -1;
    char *ep;
    char *path;

    if(argc == 1)
    {
        pipe_lines();
        exit(0);
    }

    struct option options[] = {
        {"bytes", 1, NULL, 'c'},
        {"lines", 1, NULL, 'n'},
        {0, 0, 0, 0}
    };


    while((opt = getopt_long(argc, argv, ":n:c:", options, NULL)) != -1)
    {
        switch(opt)
        {
            case 'c':
                off_bytes = strtoimax(optarg, &ep, 10);
                if(*ep || off_bytes == 0)
                {
                    fprintf(stderr, "Illegal bytes count\n");
                    exit(1);
                }
                break;
            case 'n':
                off_lines = strtol(optarg, &ep, 10);
                if(*ep || off_bytes == 0)
                {
                    fprintf(stderr, "Illegal lines count\n");
                    exit(1);
                }
                break;
            case ':':
                perror("Option needs a value");
                exit(1);
                break;
            case '?':
                perror("Unknown options");
                exit(1);
                break;
        }
    }
    path = argv[optind];
    if(access(path, F_OK) != 0)
    {
        fprintf(stderr, "File not found %s\n", path);
        exit(1);
    }
   
    fd = open(path, O_RDONLY);
    if(fd == -1)
    {
        perror(path);
        exit(1);
    }
   
    if(off_bytes == -1)
        tail_lines(fd, off_lines);
    else
        tail_bytes(fd, off_bytes);

    close(fd);
    exit(0);
}


收藏到:Del.icio.us


  struct option {
               const char *name;
               int         has_arg;
               int        *flag;
               int         val;
           };

       The meanings of the different fields are:

       name   is the name of the long option.

       has_arg
              is: no_argument (or 0) if the option does not take an argument; required_argument (or 1) if the option requires an argument; or optional_argument (or 2) if the  option  takes  an
              optional argument.

       flag   specifies  how  results  are  returned for a long option.  If flag is NULL, then getopt_long() returns val.  (For example, the calling program may set val to the equivalent short
              option character.)  Otherwise, getopt_long() returns 0, and flag points to a variable which is set to val if the option is found, but left unchanged if the option is not found.

       val    is the value to return, or to load into the variable pointed to by flag.

       The last element of the array has to be filled with zeros.

       If longindex is not NULL, it points to a variable which is set to the index of the long option relative to longopts.

       getopt_long_only() is like getopt_long(), but '-' as well as "--" can indicate a long option.  If an option that starts with '-' (not "--") doesn't match a long option, but does match a
       short option, it is parsed as a short option instead.

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多