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

Posted: 2013年04月04日

前回は、printlong関数を解説してきました。
今回はprintlong関数が表示処理に用いている各種print**関数を解説していきます。

print.c printdev関数です。

プログラムプログラム:

static void
printdev(size_t width, dev_t dev)
{

    (void)printf("%#*jx ", (u_int)width, (uintmax_t)dev);
}

解説解説:

シンプルすぎて何も言えない

print.c printsize関数です。

プログラムプログラム:

static void
printsize(size_t width, off_t bytes)
{

    if (f_humanval) {
        /*
         * Reserve one space before the size and allocate room for
         * the trailing '\0'.
         */
        char buf[HUMANVALSTR_LEN - 1 + 1];

        humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
            HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
        (void)printf("%*s ", (u_int)width, buf);
    } else if (f_thousands) {       /* with commas */
        /* This format assignment needed to work round gcc bug. */
        const char *format = "%*j'd ";
        (void)printf(format, (u_int)width, bytes);
    } else
        (void)printf("%*jd ", (u_int)width, bytes);
}

解説解説:

モードによって表示方法を切り替えています。

humanval // 最適な単位で最適化した文字列
f_thousand // 3桁カンマ区切り

humanvalの場合は、
humanize_number関数でフォーマット文字列を取得し
出力をします。

HN_Bは、 (byte)をBを表記
HN_NOSPACEは、100Bの数値と単位の間に空白を入れない設定

プログラムプログラム:

static void
printtime(time_t ftime)
{
    char longstring[80];
    static time_t now = 0;
    const char *format;
    static int d_first = -1;

    if (d_first < 0)
        d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
    if (now == 0)
        now = time(NULL);

#define SIXMONTHS   ((365 / 2) * 86400)
    if (f_timeformat)  /* user specified format */
        format = f_timeformat;
    else if (f_sectime)
        /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
        format = d_first ? "%e %b %T %Y" : "%b %e %T %Y";
    else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
        /* mmm dd hh:mm || dd mmm hh:mm */
        format = d_first ? "%e %b %R" : "%b %e %R";
    else
        /* mmm dd  yyyy || dd mmm  yyyy */
        format = d_first ? "%e %b  %Y" : "%b %e  %Y";
    strftime(longstring, sizeof(longstring), format, localtime(&ftime));
    fputs(longstring, stdout);
    fputc(' ', stdout);
}

解説解説:

指定されたフォーマット、指定フラグによって表示形式を変更しています。
strftimeでフォーマットに合う文字列の作成を行い
fputsで出力しています。

この関数の短さと、defineの近さならば、
たとえSIXMOUTHという名前でも問題ないのかもしれない
あるとしたらUNDEFをおこなっていないことくらい

個人的には、SIXMOUNTHよりもDISP_YEAR_FORMAT_PERIODとかのほうが
実際の機能の説明になり且つ6ヶ月ではなくなった場合でも使用出来るためBetterな名称と思います。

プログラムプログラム:

static int
printtype(u_int mode)
{

    if (f_slash) {
        if ((mode & S_IFMT) == S_IFDIR) {
            (void)putchar('/');
            return (1);
        }
        return (0);
    }

    switch (mode & S_IFMT) {
    case S_IFDIR:
        (void)putchar('/');
        return (1);
    case S_IFIFO:
        (void)putchar('|');
        return (1);
    case S_IFLNK:
        (void)putchar('@');
        return (1);
    case S_IFSOCK:
        (void)putchar('=');
        return (1);
    case S_IFWHT:
        (void)putchar('%');
        return (1);
    default:
        break;
    }
    if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
        (void)putchar('*');
        return (1);
    }
    return (0);
}

解説解説:

f_slashの場合はディレクトリのみ表示
それ以外は、様々なモードを表示します。

ここでは、下記のモードに対応しています。

  • ディレクトリ
  • パイプ
  • シンボリックリンク
  • ソケット
  • ホワイトアウト

ホワイトアウトは、
ユニオンファイルシステムに存在する特殊なモードらしい
解説を読みましたが詳しくは不明

プログラムプログラム:

static void
printlink(const FTSENT *p)
{
    int lnklen;
    char name[MAXPATHLEN + 1];
    char path[MAXPATHLEN + 1];

    if (p->fts_level == FTS_ROOTLEVEL)
        (void)snprintf(name, sizeof(name), "%s", p->fts_name);
    else
        (void)snprintf(name, sizeof(name),
            "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
    if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
        (void)fprintf(stderr, "nls: %s: %sn", name, strerror(errno));
        return;
    }
    path[lnklen] = '\0';
    (void)printf(" -> ");
    (void)printname(path);
}

解説解説:

シンボリックファイル(readlink)の場合は、
「ファイルパス」->「リンク先パス」を表示します。

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

コメント