読者です 読者をやめる 読者になる 読者になる

ls の実装

C

Unix/Linuxプログラミング 理論と実践」を参考に ls を書いてみた。

  • 修正案
    • 行と列の整形表示をまともにする (Stack_print_format() を書きかえればできる)
    • 日本語のファイル名に対応
    • -l オプションを追加する

参考

C 言語によるオブジェクト記述法 COOL:Stack クラス(みたいなもの)を実装する際参考にした
関数から見た配列のサイズは? - わさっき:関数内から配列のサイズが分かるという勘違いに気づかせてもらった
Unix/Linuxプログラミング理論と実践:p.117 - p.119

ls1.c
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>

/* DEBUG */
//#define DEBUG        0

#define STRING_COUNT 256
#define ON           1
#define OFF          0

/* Stack Class */
typedef struct {
    int  count;
    char *string[STRING_COUNT];
} Stack;
void init_stack(Stack *this);
void Stack_push(Stack *this, char *str);
void Stack_print_all(Stack *this);
void Stack_print_format(Stack *this);
void Stack_sort(Stack *this);

/* GLOBAl VARIABLE */
/* option flags */
/* print "." ".." */
int aflag;

/* prototype */
void usage(void);
void do_ls(char *);

int compare_str(const void *a, const void *b)
{
    return strcmp(*(char**)a, *(char**)b);
}



/* Stack Class methods */
void init_stack(Stack *this) {
    this->count = 0;
}
void Stack_push(Stack *this, char *str) {
#ifdef DEBUG
printf("stackpush %d: %s\n", this->count, str);
#endif
    this->string[this->count] = str;
    this->count++;
}
void Stack_print_all(Stack *this) {
    int i;
    for (i = 0; i < this->count; i++) {
        printf("%s\n", this->string[i]);
    }
}
void Stack_print_format(Stack *this) {
    int i;
    char *format;
    for (i = 0; i < this->count; i++) {
        printf("%20s", this->string[i]);
        if ((i+1) % 4 == 0) {
            printf("\n");
        }
    }
    printf("\n");
}
void Stack_sort(Stack *this) {
    qsort(this->string, this->count, sizeof this->string[0], compare_str);
}


void do_ls(char dirname[])
{
    DIR *dir_ptr;
    struct dirent *direntp;

    if ( (dir_ptr = opendir( dirname ) ) == NULL )
        fprintf(stderr, "ls1: cannot open %s\n", dirname);
    else
    {
        Stack stack;
        init_stack(&stack);
        while ( ( direntp = readdir( dir_ptr ) ) != NULL ) {
            if (aflag == ON) {
                // DO NOTHING
            }
            else {
                // CHECK IF directory name IS "." or ".."
                if ( direntp->d_name[0] == '.' ) {
                    continue;
                }
            }
            Stack_push(&stack, direntp->d_name);
        }
        Stack_sort(&stack);
//        Stack_print_all(&stack);
        Stack_print_format(&stack);
        closedir(dir_ptr);
    }
}


void usage(void)
{
    fprintf(stderr, 
            "usage: ls.1 [-a] [file ...]\n");
    exit(EXIT_FAILURE);
    /* NOTREACHED */
}


int main(int ac, char *av[])
{
    int ch;
    aflag = 0;
    while ((ch = getopt(ac, av, "a")) != -1) {
        switch (ch) {
            case 'a':
                aflag = 1;
                break;
            case '?':
            default:
                usage();
        }
    }
    ac -= optind;
    av += optind;

#ifdef DEBUG
printf("optind:%d\naflag:%d\n", optind, aflag);
#endif

    if (ac == 0) 
        do_ls(".");
    else
        while (ac--) {
            printf("%s:\n", *av);
            do_ls(*av);
            ++av;
        }
}