Cat(Concatenate)

2013/03/01(Fri) 更新.

catコマンドに似せたものを作りました.
今回はロングオプションを対応させてみました.
行数を表示させる為に悠長な書き方をしてしまいましたが...

/* Pseudeo cat command
 * Author: Jin
 * Version: 2.0.0
 * Date: 2013/03/01(Fri)
 * *********************************/

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

#define BUFFSIZE 65536 /* Limit */

#ifdef EOF
    #define EOF (-1)
#else
    #define EOF (-1)
#endif

#define ON_MODE 1
#define OFF_MODE 0

static struct option longopt[] = {
    {"number",    optional_argument, 0, 'n'},
    {"help",      no_argument,       0, 'h'},
    {"version",   no_argument,       0, 'v'},
    {0, 0, 0, 0},
};

static char buff[BUFFSIZE] = {"\0"};

void no_arg_cat(void); /* No Argument Mode */
void print_cat(const char *name); /* No Option Mode */
void print_number(const char *name); /* Number Option Mode */
void print_help(void);
void print_version(void);
void error_message(const char *path);

int main(int argc, char **argv)
{
    int opt, optindex, i;
    int f_help, f_ver, f_number;
    f_help = f_ver = f_number = OFF_MODE;

    if(argc < 2) 
        no_arg_cat();

    while((opt = getopt_long(argc, argv, "hvna:",
                    longopt, &optindex)) != EOF) {
        switch(opt) {
            case 'h':
                f_help = ON_MODE;
                break;
            case 'v':
                f_ver = ON_MODE;
                break;
            case 'n':
                f_number = ON_MODE;
                break;
            case '?':
                f_help = ON_MODE;
                break;
            default:
                f_help = ON_MODE;
                break;
        }
    }

    if(f_help || f_ver) {
        if(f_help) print_help();
        if(f_ver) print_version();
        exit(EXIT_SUCCESS);
    }

    else if(f_number) {
        /* Option `n` Mode */
        if(argc == optind)
            no_arg_cat();

       for(i = optind; i < argc; i++)
            print_number(argv[i]);
    }

    else {
        for(i = 1; i < argc; i++)
            print_cat(argv[i]);
    }

    return 0;
}

void no_arg_cat(void) { /* No Argument Mode */
    /* Use System Call */
    int nbyte;

    while(1) {
        if((nbyte = read(0, buff, BUFFSIZE)) == EOF)
            error_message("read");
        if(nbyte == 0) break; /* Normality End */
        if(write(1, buff, nbyte) == EOF)
            error_message("write");
    }
}

void print_cat(const char *name) { /* No Option Mode */
    /* Use System Call */
    int fd, nbyte;

    if((fd = open(name, O_RDONLY)) == EOF)
        error_message("open");

    while(1) {
        if((nbyte = read(fd, buff, BUFFSIZE)) == EOF)
            error_message("read");
        if(nbyte == 0) break; /* Normality End */
        if(write(1, buff, nbyte) == EOF)
            error_message("write");
    }

    close(fd);
}

void print_number(const char *name) { /* Number Option Mode */
    /* Library Calls */
    FILE *fp;
    int i = 1;

    if((fp = fopen(name, "r")) == NULL)
        error_message("fopen");

    while(fgets(buff, sizeof(buff), fp))
        printf("%6d  %s", i++, buff);

    fclose(fp);
}

void print_help(void) {
    printf("Usage: cat [Option]... [File]...\n \
            \n \
            -n, --number  : Print Number.\n \
            -h, --help    : Print Help.\n \
            -v, --version : Print Version.\n\n");
}

void print_version(void) {
    printf("Version: 2.0.0\n");
}

void error_message(const char *path) {
    perror(path);
    exit(EXIT_FAILURE);
}
                        

実行例:

$ ./cat --help
Usage: cat [Option] [Filename]...
-n, --number : 全ての行に番号を付けて出力します.
-v, --version : バージョンを表示します.
-h, --help : catコマンドのヘルプを表示します.(このページ)