11/06/2011

GNU coreutils の yes(1) を読む(前編)

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 を返すから。

---
後編に続く。

0 件のコメント:

コメントを投稿