C言語入門(49) 実際にプログラムを読んで理解を深めよう tail編(4)
Posted: 2013年07月18日前回は、ファイルの読み込み処理を取り上げました
実際には各フラグごとに読み込み処理関数を呼び分けていました。
今回は、その中の一つバイト単位の読み込み処理です。
read.c bytes関数
プログラム:
/* * bytes -- read bytes to an offset from the end and display. * * This is the function that reads to a byte offset from the end of the input, * storing the data in a wrap-around buffer which is then displayed. If the * rflag is set, the data is displayed in lines in reverse order, and this * routine has the usual nastiness of trying to find the newlines. Otherwise, * it is displayed from the character closest to the beginning of the input to * the end. */ int bytes(FILE *fp, const char *fn, off_t off) { int ch, len, tlen; char *ep, *p, *t; int wrap; char *sp; if ((sp = p = malloc(off)) == NULL) err(1, "malloc"); for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) { *p = ch; if (++p == ep) { wrap = 1; p = sp; } } if (ferror(fp)) { ierr(fn); free(sp); return 1; } if (rflag) { for (t = p - 1, len = 0; t >= sp; --t, ++len) if (*t == 'n' && len) { WR(t + 1, len); len = 0; } if (wrap) { tlen = len; for (t = ep - 1, len = 0; t >= p; --t, ++len) if (*t == 'n') { if (len) { WR(t + 1, len); len = 0; } if (tlen) { WR(sp, tlen); tlen = 0; } } if (len) WR(t + 1, len); if (tlen) WR(sp, tlen); } } else { if (wrap && (len = ep - p)) WR(p, len); len = p - sp; if (len) WR(sp, len); } free(sp); return 0; }
解説:
off(オフセット)分領域を確保し、データを読み込みます。
データがオフセットより大きい場合はwarpを1に設定します。
そして、配列の先頭へ上書きを行います。
データの最後からoff文のデータを表示するため
それよりも前のデータは不要なので上書きしています。
rflagは、reverse関数をから呼び出された時に立っているフラグ
※正確には、エントリーポイントでフラグ判断で立つフラグ
rflagはややこしいので後回し
まず、116行目のelseの方から
warpフラグが立っていれば先頭まで表示し
次に配列の最後からwarpをフラグを立てた位置までをWR関数にて表示します。
WARPが立っていない場合は
フラグを立てた位置が配列の先頭のため
データすべてを表示します。
では、rflagの処理について
一番下の行を先頭に表示するため
改行文字があった段階で表示します。
WARPが立っている場合は、先ほどと同様の処理を行いながら
改行文字を考慮して表示します。
最後に残ったデータを表示します。
WARPフラグが立っている場合はこの処理を行いますが
立っていない場合は、行わないので仕様なのかバグなのか不明な実装になってます
読み間違えなら指摘お願いします。
さんざん出てきたWRについて
extern.h WR関数
プログラム:
#define WR(p, size) do { if (write(STDOUT_FILENO, p, size) != (ssize_t)size) oerr(); } while(0)
解説:
STDOUTに対象のデータを出力しますが
謎のdo-whileがあります。
意味があるのか
以前は、oerrがcontinueだったのか
不明ですが‥
oerrでは、
err関数にてエラーメッセージを表示し処理を終了します。
do-whileが謎すぎて‥
コメント