試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

Vala言語でコマンド行オプションの解析と処理を行う(ページ1/3)

バージョン2.6以上のGLibにはPythonoptparseモジュールのような高度なコマンド行オプション解析/ヘルプ生成の仕組みが用意されており、国際化にも対応している。また、ヘルプ項目はグループ化でき、例えばZenityは大量のオプションが指定可能だが(--help-calendarなどのオプションで)種類ごとに詳細ヘルプを表示するようにもできる。
このオプション処理の仕組みはC言語で使えるのはもちろん、Vala言語でも標準の機能として(追加のライブラリに依存することなく)用いることができる。
(2014/10/13)URLを修正

  1. 基本的な流れ
  2. GLib.OptionEntry構造体について

基本的な流れ

  1. GLib.OptionContextオブジェクトを作成
  2. オプションごとの内容を記述するGLib.OptionEntry構造体の配列を作成(最後の項目は「{null}」にする必要がある)
  3. GLib.OptionContextオブジェクトのメンバ関数add_main_entries()に構造体配列を入れる・国際化をする場合は2番目の引数に翻訳ドメインを指定
  4. GLib.OptionContextオブジェクトのメンバ関数parse()main()の引数の参照(「ref」指定)を渡す

parse()が呼ばれた時点でコマンド行引数が処理され、GLib.OptionEntry構造体で指定した書き込み先の変数からデータが取り出し可能となる。また、コマンド行オプションとして処理されたコマンド行引数は削除され、残りのコマンド行引数だけがmain()の引数のstring型の配列(本記事の例では「args」)からアクセスできる状態となる。
C言語でもこれと基本的な要領は同じ(リファレンスのサンプルを参照)だが、g_option_context_new()で作成したGOptionContext構造体はg_option_context_free()で手動で解放する必要がある。Vala言語のGLib.OptionContextオブジェクトはこのオブジェクト変数の寿命とともに自動的に解放される。

GLib.OptionEntry構造体について

GLib.OptionEntry構造体に入れるのは以下の項目となる。

  1. 長い形式*1のオプション(例:--verboseオプションの場合は「verbose」)
  2. 短い形式*2のオプション(例:-vオプションの場合は「v」)ただしchar型なのでシングルクォートされた1文字の形をとる
  3. オプションの属性を示すフラグ(C言語のGOptionFlagsを参照)
  4. オプションがとる値の型(値をとらなければ「GLib.OptionArg.NONE」)
  5. オプションとして受け取った値の書き込み先の参照(「out」指定可)
  6. ヘルプにオプションの説明として表示する文字列
  7. オプションがとる値の部分の名前/説明についてヘルプの中に表示する文字列(例えば「--user=USERNAME」と表示したい場合は「USERNAME」とする)

[任意]ファイル名: optioncontexttest.vala

/*
 * OptionContextクラスのテスト
 * データやオプション設定を外の別の名前空間に定義する方法
 * valac --pkg posix optioncontexttest.vala -o optioncontexttest
 */

using Posix;

namespace OptionContextTest
{
  namespace Options
  {
    // データやオプション構造体配列は関数の外で定義する必要がある
    int size;
    bool verbose;
    // オプション定義の一覧
    // 最後は「{null}」が必要
    const GLib.OptionEntry[] option_entries =
    {
      // GLib.OptionEntry構造体
      // 1. 長いオプション(string)
      // 2. 短いオプション(char)
      // 3. フラグ(Glib.OptionFlags)
      // 4. オプションに対する引数の種類(GLib.OptionArg)
      // 5. 書き込み先(void *) out指定可
      // 6. 説明(string)
      // 7. オプション引数の表記(string)
      {"size", 's', 0, GLib.OptionArg.INT, out size, "set size", "SIZE"},
      {"verbose", 'v', 0, GLib.OptionArg.NONE, out verbose, "be verbose", null},
      {null}
    };
    void
    show ()
    {
      print ("size: %d, verbose: %s\n", size, verbose.to_string ());
    }
  }
  int
  main (string[] args)
  {
    // オプション解析に用いるオブジェクト
    var oc = new GLib.OptionContext ("- OptionContext test");
    // オプション定義を一括で追加
    // 国際化を用いる場合に2番目の引数に翻訳ドメインを指定
    oc.add_main_entries (Options.option_entries, null);
    // 解析実行
    try
    {
      oc.parse (ref args);
    }
    catch (GLib.OptionError e)
    {
      GLib.critical ("Failed to parse command line: %s", e.message);
      return EXIT_FAILURE;
    }
    // 受け取ったオプション指定の状態を表示
    Options.show ();
    return EXIT_SUCCESS;
  }
}

(2010/8/10)ocの宣言の記述を「var」を用いたものに変更
下は実行例。

(ヘルプ出力)
$ ./optioncontexttest -h
Usage:
  optioncontexttest [OPTION...] - OptionContext test

Help Options:
  -h, --help          Show help options

Application Options:
  -s, --size=SIZE     set size
  -v, --verbose       be verbose

(値を正しく入れて確認1)
$ ./optioncontexttest --size=12345 -v
size: 12345, verbose: true
(値を正しく入れて確認2)
$ ./optioncontexttest -s 6 --verbose
size: 6, verbose: true
(値が必要なオプションに値を入れない場合)
$ ./optioncontexttest -s

** (optioncontexttest:xxxxx): CRITICAL **: optioncontexttest.vala:53: Failed to parse command line: Missing argument for -s
$ echo ${?}
1

参考URL:

関連URL:

使用したバージョン:

  • Vala 0.9.4, 0.9.5
  • GLib 2.24.1

*1:ハイフン2つと長い文字列

*2:ハイフン1つと1文字