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

Posted: 2013年02月28日

前回は、traverse関数を解説してきました。
今回はtraverse関数が表示処理に用いているdisplay関数を解説していきます。

ls.c display関数です。

プログラムプログラム:

    initmax = getenv("LS_COLWIDTHS");
    /* Fields match -lios order.  New ones should be added at the end. */
    maxlabelstr = maxblock = maxlen = maxnlink = 0;
        maxuser = maxgroup = maxflags = maxsize = 0;
    maxinode = 0;
    if (initmax != NULL && *initmax != '\0') {
        char *initmax2, *jinitmax;
        int ninitmax;

        /* Fill-in "::" as "0:0:0" for the sake of scanf. */
        jinitmax = malloc(strlen(initmax) * 2 + 2);
        if (jinitmax == NULL)
            err(1, "malloc");
        initmax2 = jinitmax;
        if (*initmax == ':')
            strcpy(initmax2, "0:"), initmax2 += 2;
        else
            *initmax2++ = *initmax, *initmax2 = '\0';
        for (initmax++; *initmax != '\0'; initmax++) {
            if (initmax[-1] == ':' && initmax[0] == ':') {
                *initmax2++ = '0';
                *initmax2++ = initmax[0];
                initmax2[1] = '\0';
            } else {
                *initmax2++ = initmax[0];
                initmax2[1] = '\0';
            }
        }
        if (initmax2[-1] == ':')
            strcpy(initmax2, "0");

        ninitmax = sscanf(jinitmax,
            " %ju : %ld : %lu : %u : %u : %i : %jd : %lu : %lu ",
            &maxinode, &maxblock, &maxnlink, &maxuser,
            &maxgroup, &maxflags, &maxsize, &maxlen, &maxlabelstr);
        f_notabs = 1;
        switch (ninitmax) {
        case 0:
        // 省略
        }
        MAKENINES(maxinode);
        MAKENINES(maxblock);
        MAKENINES(maxnlink);
        MAKENINES(maxsize);
        free(jinitmax);
    }

解説解説:

環境変数LS_COLWIDTHSに記述されている値を取得しています。
LS_COLWIDTHSでは幅0の場合省略できるため、その値を保管して数値に変換しています。

例) 「::1:0:5:」->「0:0:1:0:5:0」

switch(ninitmax)内では、変換できなかった値を代入する予定だった変数を初期化します。

プログラムプログラム:

    d.s_size = 0;
    sizelen = 0;
    flags = NULL;
    for (cur = list, entries = 0; cur; cur = cur->fts_link) {
        // 省略
    }

解説解説:

引数listはディレクトリ内のファイルリストが設定されているため
ファイル数分処理を行います。
ファイルリストの最後には、NULLが設定されているため条件は、

cur;

つまり

cur != NULL

と同意

プログラムプログラム:

        if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
            warnx("%s: %s",
                cur->fts_name, strerror(cur->fts_errno));
            cur->fts_number = NO_PRINT;
            rval = 1;
            continue;
        }
        /*
         * P is NULL if list is the argv list, to which different rules
         * apply.
         */
        if (p == NULL) {
            /* Directories will be displayed later. */
            if (cur->fts_info == FTS_D && !f_listdir) {
                cur->fts_number = NO_PRINT;
                continue;
            }
        } else {
            /* Only display dot file if -a/-A set. */
            if (cur->fts_name[0] == '.' && !f_listdot) {
                cur->fts_number = NO_PRINT;
                continue;
            }
        }

解説解説:

対象外のファイルは除外しています。

  • FTS_ERRやFTS_NS
  • 親フォルダが指定されず(NULL)自身がフォルダの場合
  • 「.」ファイル(自身のフォルダ)

プログラムプログラム:

        if (cur->fts_namelen > maxlen)
            maxlen = cur->fts_namelen;
        if (f_octal || f_octal_escape) {
            u_long t = len_octal(cur->fts_name, cur->fts_namelen);

            if (t > maxlen)
                maxlen = t;
        }
        if (needstats) {
            // 省略
        }
        ++entries;

解説解説:

maxlen(ファイル名の最大長)を計算しています。
またneedstatsでファイルの詳細な情報を取得します。

プログラムプログラム:

            sp = cur->fts_statp;
            if (sp->st_blocks > maxblock)
                maxblock = sp->st_blocks;
            if (sp->st_ino > maxinode)
                maxinode = sp->st_ino;
            if (sp->st_nlink > maxnlink)
                maxnlink = sp->st_nlink;
            if (sp->st_size > maxsize)
                maxsize = sp->st_size;

            btotal += sp->st_blocks;
            if (f_longform) {
                if (f_numericonly) {
                    (void)snprintf(nuser, sizeof(nuser),
                        "%u", sp->st_uid);
                    (void)snprintf(ngroup, sizeof(ngroup),
                        "%u", sp->st_gid);
                    user = nuser;
                    group = ngroup;
                } else {
                    user = user_from_uid(sp->st_uid, 0);
                    group = group_from_gid(sp->st_gid, 0);
                }
                if ((ulen = strlen(user)) > maxuser)
                    maxuser = ulen;
                if ((glen = strlen(group)) > maxgroup)
                    maxgroup = glen;
                if (f_flags) {
                    flags = fflagstostr(sp->st_flags);
                    if (flags != NULL && *flags == '\0') {
                        free(flags);
                        flags = strdup("-");
                    }
                    if (flags == NULL)
                        err(1, "fflagstostr");
                    flen = strlen(flags);
                    if (flen > (size_t)maxflags)
                        maxflags = flen;
                } else
                    flen = 0;
                labelstr = NULL;
                if (f_label) {
                    char name[PATH_MAX + 1];
                    mac_t label;
                    int error;

                    error = mac_prepare_file_label(&label);
                    if (error == -1) {
                        warn("MAC label for %s/%s",
                            cur->fts_parent->fts_path,
                            cur->fts_name);
                        goto label_out;
                    }

                    if (cur->fts_level == FTS_ROOTLEVEL)
                        snprintf(name, sizeof(name),
                            "%s", cur->fts_name);
                    else
                        snprintf(name, sizeof(name),
                            "%s/%s", cur->fts_parent->
                            fts_accpath, cur->fts_name);

                    if (options & FTS_LOGICAL)
                        error = mac_get_file(name,
                            label);
                    else
                        error = mac_get_link(name,
                            label);
                    if (error == -1) {
                        warn("MAC label for %s/%s",
                            cur->fts_parent->fts_path,
                            cur->fts_name);
                        mac_free(label);
                        goto label_out;
                    }

                    error = mac_to_text(label,
                        &labelstr);
                    if (error == -1) {
                        warn("MAC label for %s/%s",
                            cur->fts_parent->fts_path,
                            cur->fts_name);
                        mac_free(label);
                        goto label_out;
                    }
                    mac_free(label);
label_out:
                    if (labelstr == NULL)
                        labelstr = strdup("-");
                    labelstrlen = strlen(labelstr);
                    if (labelstrlen > maxlabelstr)
                        maxlabelstr = labelstrlen;
                } else
                    labelstrlen = 0;

                if ((np = malloc(sizeof(NAMES) + labelstrlen +
                    ulen + glen + flen + 4)) == NULL)
                    err(1, "malloc");

                np->user = &np->data[0];
                (void)strcpy(np->user, user);
                np->group = &np->data[ulen + 1];
                (void)strcpy(np->group, group);

                if (S_ISCHR(sp->st_mode) ||
                    S_ISBLK(sp->st_mode)) {
                    sizelen = snprintf(NULL, 0,
                        "%#jx", (uintmax_t)sp->st_rdev);
                    if (d.s_size < sizelen)
                        d.s_size = sizelen;
                }

                if (f_flags) {
                    np->flags = &np->data[ulen + glen + 2];
                    (void)strcpy(np->flags, flags);
                    free(flags);
                }
                if (f_label) {
                    np->label = &np->data[ulen + glen + 2
                        + (f_flags ? flen + 1 : 0)];
                    (void)strcpy(np->label, labelstr);
                    free(labelstr);
                }
                cur->fts_pointer = np;
            }

解説解説:

ざっくり書くとファイルの詳細情報を取得しています。
取得対象のファイル属性のみを取得しています。

プログラムプログラム:

    /*
     * If there are no entries to display, we normally stop right
     * here.  However, we must continue if we have to display the
     * total block count.  In this case, we display the total only
     * on the second (p != NULL) pass.
     */
    if (!entries && (!(f_longform || f_size) || p == NULL))
        return;

    d.list = list;
    d.entries = entries;
    d.maxlen = maxlen;
    if (needstats) {
        d.btotal = btotal;
        d.s_block = snprintf(NULL, 0, "%lu", howmany(maxblock, blocksize));
        d.s_flags = maxflags;
        d.s_label = maxlabelstr;
        d.s_group = maxgroup;
        d.s_inode = snprintf(NULL, 0, "%ju", maxinode);
        d.s_nlink = snprintf(NULL, 0, "%lu", maxnlink);
        sizelen = f_humanval ? HUMANVALSTR_LEN :
            snprintf(NULL, 0, "%ju", maxsize);
        if (d.s_size < sizelen)
            d.s_size = sizelen;
        d.s_user = maxuser;
    }
    if (f_thousands)            /* make space for commas */
        d.s_size += (d.s_size - 1) / 3;
    printfcn(&d);
    output = 1;

    if (f_longform)
        for (cur = list; cur; cur = cur->fts_link)
            free(cur->fts_pointer);
}

解説解説:

取得した情報を表示します。
表示用データdに文字列化したデータを詰めprintfcnで表示を行います。
文字列化にはsnprintfを用いて各変数に設定をしています。

最後に、終了処理をおこないます。

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

コメント