2014-05-20 :-(
_ 午後
1300 デバッグしTARI
_ 夜
1700 残業アワー
2100 退勤 || ここんとこ無駄な時間が多いような || 以前は 17 時に退勤しないといけなかったから、どうすれば 17 時までに仕事を完了できるか、如何にして無駄をなくすか、ということに腐心していたんだが、最近の仕事場は【禁則事項です】なのでつい無制限に
2200 飯
_ [NetBSD][cat][コードリーディング]NetBSD /bin/cat を読む
src/bin/cat/cat.c
オプションなしで呼び出した場合を読む。
% cat file1 file2 file3
関数はこう呼ばれる
main raw_args raw_cat
main を読む。
(void)setlocale(LC_ALL, "");
マニュアルによると、"" を指定しているので環境変数 LC_ALL が使われる。
setlocale - NetBSD Manual Pages
Only three locales are defined by default, the empty string "" which denotes the native environment, and the "C" and "POSIX" locales, which denote the C language environment.
オプションを与えてないのでここは raw_args へ行く。
if (bflag || eflag || nflag || sflag || tflag || vflag) cook_args(argv); else raw_args(argv);
raw_args を読む。
全体が do while で囲まれている。
do { : } while (*argv);
argv には /bin/cat に渡された引数が入る。つまりファイル 1 つ以上である。ファイル 1 つ以上をすべて do while で処理する。
ファイルディスクリプタ fd に初期値設定。デフォルトでは標準入力。stdin はたぶん unistd.h で定義されてる。マニュアル stdin - NetBSD Manual Pages によると定数 STDIN_FILENO などらしいんだが。
fd = fileno(stdin); filename = "stdin";
条件分岐はここを通る。ようはファイルを open している。
else if ((fd = open(*argv, O_RDONLY, 0)) < 0) { skip: warn("%s", *argv); skipnomsg: rval = EXIT_FAILURE; ++argv; continue; }
open が返したファイルディスクリプタを raw_cat へ渡す。
raw_cat(fd);
raw_cat を読む。短いので関数を全部。ファイルから読んで標準出力 stdout へ書き出す。
void raw_cat(int rfd) { static char *buf; static char fb_buf[BUFSIZ]; static size_t bsize; ssize_t nr, nw, off; int wfd; wfd = fileno(stdout); // /bin/cat に渡されたファイル 1 つ以上を処理するので、buf は static であり最初だけ NULL チェックする if (buf == NULL) { struct stat sbuf; // ファイルサイズを取得する if (fstat(wfd, &sbuf) == 0 && sbuf.st_blksize > sizeof(fb_buf)) { bsize = sbuf.st_blksize; buf = malloc(bsize); } if (buf == NULL) { bsize = sizeof(fb_buf); buf = fb_buf; } } // 1 回の read で読みこみ完了するとは限らないのでループを回す while ((nr = read(rfd, buf, bsize)) > 0) // さらに write も 1 回で完了するとは限らないのでループする for (off = 0; nr; nr -= nw, off += nw) if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) err(EXIT_FAILURE, "stdout"); if (nr < 0) { warn("%s", filename); rval = EXIT_FAILURE; } }
read はマニュアルにベストプラクティスが書いてある read - NetBSD Manual Pages 面倒くさい。
Error checks should explicitly test for -1. Code such as while ((nr = read(fd, buf, sizeof(buf))) > 0) is not maximally portable, as some platforms allow for nbytes to range between SSIZE_MAX and SIZE_MAX - 2, in which case the return value of an error-free read() may appear as a negative number distinct from -1. Proper loops should use while ((nr = read(fd, buf, sizeof(buf))) != -1 && nr != 0)
write(2) も当然ある write(2) - NetBSD Manual Pages
Error checks should explicitly test for -1. Code such as while ((nr = write(fd, buf, sizeof(buf))) > 0) is not maximally portable, as some platforms allow for nbytes to range between SSIZE_MAX and SIZE_MAX - 2, in which case the return value of an error-free write() may appear as a negative number distinct from -1. Proper loops should use while ((nr = write(fd, buf, sizeof(buf))) != -1 && nr != 0)