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が謎すぎて‥

カテゴリー: プログラム, 入門 | タグ: , , | コメント無し »

コメント