FreeBSDのlsを読む fts(3)でlsを作ってみよう〜。
FreeBSDのlsで使われているfts(3)がやたら便利そうなので、試してみた。環境はFedora6です。
ls.c
#include <stdio.h> #include <stdlib.h> #include <fts.h> int main (int argc, char *argv[]) { FTS *ftsp; FTSENT *p; static char dot[] = "."; static char *dotav[] = {dot, NULL}; if (argc == 1) argv = dotav; else argv++; /* 無理矢理 */ ftsp = fts_open(argv, 0, NULL); while((p = fts_read(ftsp)) != NULL) { printf("%s\n", p->fts_path); } fts_close(ftsp); exit(EXIT_SUCCESS); }
たったこれだけで、ls完成。見た目はopendir(2),readdir(2)とさほど変わらない。
試す。
% gcc -o ls ls.c % ./ls . ./ls ./ls.c ./tags .
ドットを除いていないので、見栄えは悪い。
% ./ls / | head / /.autofsck /media /media/.hal-mtab-lock /media/.hal-mtab /media /boot /boot/lost+found /boot/lost+found
headは付けた方がいい
エラー処理を追加
やはり、ファイル名が見付からなかったときの位の処理は欲しい。
#include <stdio.h> #include <stdlib.h> #include <fts.h> #include <err.h> int main(int argc, char *argv[]) { FTS *ftsp; FTSENT *p; static char *dotav[] = {".", NULL}; if (argc == 1) argv = dotav; else argv++; /* 無理矢理 */ if ((ftsp = fts_open(argv, 0, NULL)) == NULL) err(EXIT_FAILURE, "fts_open"); while((p = fts_read(ftsp)) != NULL) { switch(p->fts_info) { case FTS_NS: case FTS_ERR: err(EXIT_FAILURE, "fts_info"); case FTS_DNR: /* 読み取り不可 */ case FTS_D: case FTS_F: case FTS_DP: case FTS_SL: case FTS_DEFAULT: printf("%s\n", p->fts_path); break; default: /* debug */ /* fprintf(stderr, "%d %s\n", p->fts_info, p->fts_path); */ /* exit(EXIT_FAILURE); */ break; } } fts_close(ftsp); exit(EXIT_SUCCESS); }
非標準にこだわってみた。
まとめ
- 実際コーディングすることで、traverse()の処理を把握できた。
- fts(3)はやたら便利。
- lsというよりfindに近い処理が可能である。
- err(3)も便利。
- 移植性はない。残念。