FreeBSD に続き、GNU coretutils の yes.c を前編、後編の2回に分けて読んでみる。対象のソースは Ubuntu 11.04 上で以下のコマンド実行してダウンロードできた coreutils-8.5 の yes.c。
$ apt-get source coreutils
今回は前編。yes.c の main() 関数の前半部分、yes(1) のメイン処理に移る前の部分を読む。
62 initialize_main (&argc, &argv);
63 set_program_name (argv[0]);
64 setlocale (LC_ALL, "");
65 bindtextdomain (PACKAGE, LOCALEDIR);
66 textdomain (PACKAGE);
67
68 atexit (close_stdout);
69
70 parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
71 usage, AUTHORS, (char const *) NULL);
72 if (getopt_long (argc, argv, "+", NULL, NULL) != -1)
73 usage (EXIT_FAILURE);
[initialize_main]
gnu.core-utils.bugs に Bernard Giroud さんが投稿したメイルによると、initialize_main() は VMS ていうシステム上で redirect を実現するためのアイデアが起源になってるらしい。VMS 上では必ずしも bash (シェル) 上でコマンドが実行されなくて、redirect するのにちょっと工夫がいるみたい。この VMS は
OpenVMS のことかな?
initialize_main() の定義は coreutils/src/system.h にある。さっきの VMS とか、そのほか、ちょっと変わった環境で redirect とか実現したい場合は、system.h 内の initialize_main() を適切な形で定義すればいい。こうすれば、それぞれのコマンドのソースを変えなくて済むからイケてる感じ。
/* Redirection and wildcarding when done by the utility itself.
Generally a noop, but used in particular for native VMS. */
#ifndef initialize_main
# define initialize_main(ac, av)
#endif
[set_program_name]
set_program_name() は argv[0] から実行されたコマンド名だけを取り出して program_name ていうグローバル変数に設定する。program_name 変数は lib/progname.h で extern 定義されてるから、set_program_name(argv[0]) した後は、program_name 変数にアクセスすることでコマンド名が取れるってこと。
/* String containing name the program is called with. */
extern const char *program_name;
[setlocale, bindtextdomain, textdomain]
このあたりは、ロケール関係。いままで使ったことないから、これはどっかで改めて勉強しよう。
[atexit]
atexit(3) はプロセスが通常終了するときに呼ばれるべき関数を登録する。yes.c だと、標準出力を閉じてそうな、close_stdout() を atexit(3) で登録してる。atexit(3) もいままで使ったことなかったけど、これは便利そうだ。
[parse_long_options]
yes(1) が --help か --version 付きで呼ばれたときの設定をする。--help と --version は coreutils のコマンドで共通みたい。このあたりの作りもかっこいいな。
[getopt_long]
第三引数の "+" の意味は man 3 getopt に書いてある。
If the first character of optstring is '+' or the environment variable POSIXLY_CORRECT is set, then option processing stops as soon as a nonoption argument is encountered.
yes.c の getopt_long(...) を呼び出してるところ、オプション以外の引数があったらそこで解析をやめるし、何かオプションが指定されてたらそれはエラーだよ、って意味。getopt_long(3) は正しく解析できたときに -1 を返すから。
---
後編に続く。