コマンドライン引数の取得 その2

関数getopt_longは長い形式のオプションの取得に便利な関数である.これはGNU拡張らしい.長いオプションは大抵–で始まる.
getopt_long
外部変数
オプションの設定
サンプル
getopt_long_only

getopt_long

getopt_longはgetoptを拡張して–で始まる長い形式のオプションを解釈できるようにした関数である.POSIX準拠ではなく,GNU独自のものらしい.長い形式のオプションは一意に決まる限り短く省略できる.例えば,
–foo –foovar
の二つのみをオプションに持つコマンドがあった場合,–foovarは一意に決まる省略形–foovでも解釈される.
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int longindex); 各引数について以下に示す. argc,argv[]
main関数の引数をそのまま渡す.
*optstring
getoptと同様,短い形式のオプションを示す.
*longopts
長い形式のオプションを示す構造体optionの配列.
longindex マッチした長い形式のオプションに対するlongoptsのインデクス.
getopt_longのさらなる説明はオプションを示す構造体optionの説明が中心になる.
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
各フィールドの説明を以下に示す.
*name
オプション名.
has_arg
このオプションが値を持つかどうかを示す.
no_argument
値を持たない
required_argument
値を必ず持つ
optional_argument
値を持っても持たなくてもよい
*flag
次のフィールドvalを設定する変数へのポインタ.これがNULLの場合はgetopt_longはvalを返す.NULL以外ならvalをflagに設定して0を返す.もちろんオプションが見付からない場合,flagは設定されない.
val
*flagに設定する値.

外部変数

前項のgetopでは外部変数の説明がやっつけだったので,ここで改めて記述する.
char *optarg
次に検査するargv要素.これはgetoptを呼んだあとでは,次のオプション,またはオプションに続くテキストを指す.
int optind
オプションを順に読み込むためにgetoptが使用する.オプションの処理が終ったとき,optind < argcなら,不正なオプションがあることになる.
int opterr
0にするとgetoptが表示するエラーメッセージを抑制する.
optopt
引数でない文字を検出したときに,その文字を格納する.
やっぱりなんかやっつけだが,manがあるからいいか.

オプションの設定

getoptの引数optstringで,処理するオプションをgetoptに伝える.これも前項でやっつけたので,ここで改めてやっつける.
例1:”abc”
a,b,cがオプション
例2:”ab:c”
a,b,cがオプション.bは値を取る.
例3:”ab::c”
a,b,cがオプション.bは値を取ってもとらなくてもよい.
例4:”+abc”
a,b,cがオプションで,非オプション文字列を検出するとただちにプログラムを終了する.環境変数POSIXLY_CORRECTが設定されている場合も同様の動作をする.
例5:”-abc”
a,b,cがオプションで.非オプション文字は文字コード1の文字として扱われる.オプションの順番は任意だが,その順番は意味を持つようにする必要がある(よくわからない).

サンプル

以上を踏まえてgetopt_longを使用したサンプルを以下にしめす.

include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

#define OPTION_NUM 5

int main(int argc, char **argv){
  struct option *options;
  /*  int first_value; */
  int second_value;
  int third_value;
  int option_index;
  int opt;

  options = malloc(sizeof(struct option) * OPTION_NUM);

  /* Ĺ�������Υ��ץ����1 */
  options[0].name = "first_long_option";
  /* ���Υ��ץ����ϰ�����Ȥ�ʤ� */
  options[0].has_arg = no_argument;
  /* ���Υ��ץ���󤬸��դ��ä���getopt_long��val���֤� */
  options[0].flag = NULL;
  options[0].val = 1;

  /* Ĺ�������Υ��ץ����2 */
  options[1].name = "second_long_option";
  /* ���Υ��ץ����ϰ�����ɬ��ɬ�פȤ��� */
  options[1].has_arg = required_argument;
  /* ���Υ��ץ���󤬸��դ��ä���getopt_long��0���֤�,
     flag��val�����ꤹ�� */
  options[1].flag = NULL;
  options[1].val = 1;

  /* Ĺ�������Υ��ץ����3 */
  options[2].name = "third_long_option";
  /* ���Υ��ץ����ϰ�����ɬ��ɬ�פȤ��� */
  options[2].has_arg = required_argument;
  /* ���Υ��ץ���󤬸��դ��ä���getopt_long��0���֤�,
     flag��val�����ꤹ�� */
  options[2].flag = &second_value;
  options[2].val = 2;

  /* Ĺ�������Υ��ץ����4 */
  options[3].name = "fourth_long_option";
  /* ���Υ��ץ����ϰ�����ȤäƤ�Ȥ�ʤ��Ƥ�褤 */
  options[3].has_arg = optional_argument;
  /* ���Υ��ץ���󤬸��դ��ä���getopt_long��0���֤�,
     flag��val�����ꤹ�� */
  options[3].flag = &third_value;
  options[3].val = 3;

  /* ����κǸ�����Ƥ�0�ˤ��Ƥ��� */
  options[OPTION_NUM - 1].name = 0;
  options[OPTION_NUM - 1].has_arg = 0;
  options[OPTION_NUM - 1].flag = 0;
  options[OPTION_NUM - 1].val = 0;

  while(1){
    fprintf(stdout, "=====================================\n");
    /* ���ץ����μ��� */
    opt = getopt_long(argc, argv, "abc", options, &option_index);
    fprintf(stdout, "opt = %d\n", opt);
    /* ���ץ����ʸ�������դ���ʤ� */
    if(opt == -1){
      break;
    }

    switch(opt){
    case 0:
      /* flag��NULL�ʳ�,�⤷����flag��NULL��val��0�ξ�� */
      fprintf(stdout, "options[%d] : %s\n", option_index, options[option_index].name);
      /* ���ץ�����ͤ�Ȥ��� */
      if(optarg){
	fprintf(stdout, "\toptarg = %s\n", optarg);
      }
      fprintf(stdout, "\tflag = %d\n", *options[option_index].flag);
      break;
    case 1:
      /* flag��NULL��val��1�� */
      fprintf(stdout, "options[%d] : %s\n", option_index, options[option_index].name);
      /* ���ץ�����ͤ�Ȥ��� */
      if(optarg){
	fprintf(stdout, "\toptarg = %s\n", optarg);
      }
      break;

    /* û�������Υ��ץ���� */
    case 'a':
    case 'b':
    case 'c':
      fprintf(stdout, "short option %c\n", opt);
      break;
    case '?':
      fprintf(stdout, "unknown argment %c\n", optopt);
      break;
    default:

    }
  }

  exit(EXIT_SUCCESS);
}

以下に実行結果を示す.

./a.out --first_long_option --sec 5 --t 6 --four
=====================================
opt = 1
options[0] : first_long_option
=====================================
opt = 1
options[1] : second_long_option
        optarg = 5
=====================================
opt = 0
options[2] : third_long_option
        optarg = 6
        flag = 2
=====================================
opt = 0
options[3] : fourth_long_option
        flag = 3
=====================================
opt = -1
./a.out --first_long_option --sec 5 --t 6 --f
=====================================
opt = 1
options[0] : first_long_option
=====================================
opt = 1
options[1] : second_long_option
        optarg = 5
=====================================
opt = 0
options[2] : third_long_option
        optarg = 6
        flag = 2
=====================================
./a.out: option `--f' is ambiguous
opt = 63
unknown argment 
=====================================
opt = -1

二番目実行では--fとしたが,--first_long_optionと--fourth_long_optionの判別できないので怒られた.他にもいろんなオプションの渡し方が可能だが省略.

getopt_long_only

getopt_long_onlyは,-で始まるオプションも長い形式のオプションとして扱われる.そして-で始まって長い形式のオプションとカブらないときに,短いオプションとして扱われる.

This article was written by Fujiko