C言語入門(48) 実際にプログラムを読んで理解を深めよう tail編(3)

Posted: 2013年07月11日

今回は、実際の処理です。
関数で言うとfoward関数
エントリーポイントで呼ばれていた関数です。

foward.c foward関数

プログラムプログラム:

/*
 * forward -- display the file, from an offset, forward.
 *
 * There are eight separate cases for this -- regular and non-regular
 * files, by bytes or lines and from the beginning or end of the file.
 *
 * FBYTES   byte offset from the beginning of the file
 *  REG seek
 *  NOREG   read, counting bytes
 *
 * FLINES   line offset from the beginning of the file
 *  REG read, counting lines
 *  NOREG   read, counting lines
 *
 * RBYTES   byte offset from the end of the file
 *  REG seek
 *  NOREG   cyclically read characters into a wrap-around buffer
 *
 * RLINES
 *  REG mmap the file and step back until reach the correct offset.
 *  NOREG   cyclically read lines into a wrap-around array of buffers
 */
void
forward(FILE *fp, const char *fn, enum STYLE style, off_t off, struct stat *sbp)
{
    int ch;

    switch(style) {
    case FBYTES:
        if (off == 0)
            break;
        if (S_ISREG(sbp->st_mode)) {
            if (sbp->st_size < off)
                off = sbp->st_size;
            if (fseeko(fp, off, SEEK_SET) == -1) {
                ierr(fn);
                return;
            }
        } else while (off--)
            if ((ch = getc(fp)) == EOF) {
                if (ferror(fp)) {
                    ierr(fn);
                    return;
                }
                break;
            }
        break;
    case FLINES:
        if (off == 0)
            break;
        for (;;) {
            if ((ch = getc(fp)) == EOF) {
                if (ferror(fp)) {
                    ierr(fn);
                    return;
                }
                break;
            }
            if (ch == 'n' && !--off)
                break;
        }
        break;
    case RBYTES:
        if (S_ISREG(sbp->st_mode)) {
            if (sbp->st_size >= off &&
                fseeko(fp, -off, SEEK_END) == -1) {
                ierr(fn);
                return;
            }
        } else if (off == 0) {
            while (getc(fp) != EOF);
            if (ferror(fp)) {
                ierr(fn);
                return;
            }
        } else
            if (bytes(fp, fn, off))
                return;
        break;
    case RLINES:
        if (S_ISREG(sbp->st_mode))
            if (!off) {
                if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
                    ierr(fn);
                    return;
                }
            } else
                rlines(fp, fn, off, sbp);
        else if (off == 0) {
            while (getc(fp) != EOF);
            if (ferror(fp)) {
                ierr(fn);
                return;
            }
        } else
            if (lines(fp, fn, off))
                return;
        break;
    default:
        break;
    }

    while ((ch = getc(fp)) != EOF)
        if (putchar(ch) == EOF)
            oerr();
    if (ferror(fp)) {
        ierr(fn);
        return;
    }
    (void)fflush(stdout);
}

解説解説:

長々と記述されていますが

処理をざっくりと説明しますと
各STYLEのoffset分読み飛ばし

それ以降の文字列を表示します。

STYLEは以下のような意味です。

FBYTES
先頭から指定バイト読み飛ばす。

FLINES
先頭から指定行数読み飛ばす。

RBYTES
後方から指定バイトまで読み飛ばす。

RLINES
後方から指定行数まで読み飛ばす。

NOTSET(default)
読み飛ばし処理を行わない

状況により読み飛ばし方を切り替えています。
S_ISREGでファイルからのinputか判断します。
 ファイルの場合は、fseekにより読み飛ばします。

tailコマンドの独自関数
bytes,lines,rbytes,rlinesにより読み飛ばします。

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

コメント