、デフォルトls -1
動作をエミュレートあなたmain()
の先頭近く
setlocale(LC_ALL, "");
を呼び出すことで、プログラムのロケール対応を行い、my_filter()
は0を返す関数である
count = scandir(dir, &array, my_filter, alphasort);
を使用するにはドットで始まる名前は.
、それ以外はすべて1です。 alphasort()
は、strcoll()
と同じ順序のロケール照合順序を使用するPOSIX関数です。
基本的な実装では、私はあなただけのコードをコピー&ペーストしたくなかったので、私は意図的に、厳密にあなたの目的のために必要とされるより、これはより複雑に
#define _POSIX_C_SOURCE 200809L
#define _ATFILE_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <locale.h>
#include <string.h>
#include <dirent.h>
#include <stdio.h>
#include <errno.h>
static void my_print(const char *name, const struct stat *info)
{
/* TODO: Better output; use info too, for 'ls -l' -style output? */
printf("%s\n", name);
}
static int my_filter(const struct dirent *ent)
{
/* Skip entries that begin with '.' */
if (ent->d_name[0] == '.')
return 0;
/* Include all others */
return 1;
}
static int my_ls(const char *dir)
{
struct dirent **list = NULL;
struct stat info;
DIR *dirhandle;
int size, i, fd;
size = scandir(dir, &list, my_filter, alphasort);
if (size == -1) {
const int cause = errno;
/* Is dir not a directory, but a single entry perhaps? */
if (cause == ENOTDIR && lstat(dir, &info) == 0) {
my_print(dir, &info);
return 0;
}
/* Print out the original error and fail. */
fprintf(stderr, "%s: %s.\n", dir, strerror(cause));
return -1;
}
/* We need the directory handle for fstatat(). */
dirhandle = opendir(dir);
if (!dirhandle) {
/* Print a warning, but continue. */
fprintf(stderr, "%s: %s\n", dir, strerror(errno));
fd = AT_FDCWD;
} else {
fd = dirfd(dirhandle);
}
for (i = 0; i < size; i++) {
struct dirent *ent = list[i];
/* Try to get information on ent. If fails, clear the structure. */
if (fstatat(fd, ent->d_name, &info, AT_SYMLINK_NOFOLLOW) == -1) {
/* Print a warning about it. */
fprintf(stderr, "%s: %s.\n", ent->d_name, strerror(errno));
memset(&info, 0, sizeof info);
}
/* Describe 'ent'. */
my_print(ent->d_name, &info);
}
/* Release the directory handle. */
if (dirhandle)
closedir(dirhandle);
/* Discard list. */
for (i = 0; i < size; i++)
free(list[i]);
free(list);
return 0;
}
int main(int argc, char *argv[])
{
int arg;
setlocale(LC_ALL, "");
if (argc > 1) {
for (arg = 1; arg < argc; arg++) {
if (my_ls(argv[arg])) {
return EXIT_FAILURE;
}
}
} else {
if (my_ls(".")) {
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
ノートの線に沿って何かです。このプログラムをコンパイル、実行、調査してから、必要な変更を移植する方が簡単です - おそらくはsetlocale("", LC_ALL);
行! - 自分のプログラムに、教師/講師/ TAになぜコードが他の場所からそのままコピーされたように見えるかを説明してみてください。
上記のコードは、コマンドライン(cause == ENOTDIR
の部分)で指定されたファイルに対しても機能します。また、単一の機能my_print(const char *name, const struct stat *info)
を使用して各ディレクトリエントリを出力します。これを行うには、各エントリに対してstat
を呼び出します。
代わりのディレクトリエントリへのパスを構築し、lstat()
を呼び出し、my_ls()
ディレクトリハンドルを開き、lstat()
と同じように基本的に同じ方法で情報を収集するfstatat(descriptor, name, struct stat *, AT_SYMLINK_NOFOLLOW)
を使用するが、name
は、指定されたディレクトリから始まる相対パスでありますdescriptor
(dirfd(handle)
、handle
が開かれている場合はDIR *
)。
各ディレクトリエントリのstat関数のうちの1つを呼び出すのが "遅い"ことは事実です(特に/bin/ls -1
スタイル出力を行う場合)。しかし、ls
の出力は人間が消費することを意図したものです。人間が余暇に見られるように、非常に頻繁にmore
またはless
にパイプされます。これは、私が個人的には、 "余分な" stat()コール(実際には必要ない場合でも)がここで問題になるとは思わない理由です。私が知っているほとんどの人間のユーザーはls -l
または(私のお気に入り)ls -laF --color=auto
を使用する傾向があります。 (auto
意味ANSIカラーが標準出力が端末である場合にのみ使用されている;すなわちときisatty(fileno(stdout)) == 1
)
言い換えれば、今あなたがls -1
順序を持っていることを、私はあなたがls -l
に似ているように出力を変更することをお勧め(ダッシュええ、ダッシュワンではない)。そのためにはmy_print()
を変更する必要があります。
'ls'は独自のカスタム文字列比較を使用していますが、' alphasort'は 'strcmp'の実装にすぎません。 –
@MDXF alphasortについて/ /あなたはlsのカスタム文字列比較の詳細を知っていますか?それについてもっと読む?私はlsの出力を模倣する必要があるので、alphasort/strcmpとは違うことを学びたいと思っています。 – cl001
lsは基本的なデフォルトのソートを持っていますが、これはstrcmpの順番になりますが、ロケールの影響を受ける可能性があります。ロケールを理解するには、http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.htmlから始め、文字列の比較はhttp://pubs.opengroup.org/onlinepubs/9699919799/functions/strcollから始めることができます。 html –