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

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

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

Vala言語でコマンド行オプションの解析と処理を行う(ページ1/3)」の続きだが、ここからはサンプルの作成段階で気になった部分に関するメモとなる。
Vala言語でコマンド行オプションの解析と処理を行う(ページ1/3)」の例ではオプション定義とそのデータを格納する変数は子の名前空間を作ってその中に入れていたが、これを作成していた途中の段階ではクラスの中にまとめようとしていた。

クラスのインスタンスメンバを書き込み先にする書き方がない?

オプション関係のデータをクラスにまとめた場合、そのクラスのインスタンスを生成してオプション解析結果を個別のオブジェクトの中のメンバ(インスタンスメンバ/静的でないメンバ)に格納するようにしようとすると、GLib.OptionEntry構造体の配列を作るところで文法エラーが出てしまう(書き方の問題?)。
[任意]ファイル名: optioncontexttest_ng.vala

/*
 * OptionContextクラスのテスト
 * ビルドできない例
 * valac --pkg posix optioncontexttest_ng.vala -o optioncontexttest_ng
 */

using Posix;

namespace OptionContextTestNG
{
  class Options
  {
    GLib.OptionContext oc;
    int size;
    bool verbose;
    GLib.OptionEntry[] option_entries;
    public
    Options ()
    {
      this.oc = new GLib.OptionContext ("- OptionContext test");
      // ここでエラーになる
      // Expected array element, got array initializer list
      this.option_entries =
      {
        {"size", 's', 0, GLib.OptionArg.INT, out this.size, "set size", "SIZE"},
        {"verbose", 'v', 0, GLib.OptionArg.NONE, out this.verbose, "be verbose", null},
        {null}
      };
      this.oc.add_main_entries (this.option_entries, null);
    }
/*
    // このように書いてもダメ
    // This access invalid outside of instance methods
    const GLib.OptionEntry[] option_entries2 =
    {
      {"size", 's', 0, GLib.OptionArg.INT, out this.size, "set size", "SIZE"},
      {"verbose", 'v', 0, GLib.OptionArg.NONE, out this.verbose, "be verbose", null},
      {null}
    };
*/
    public void
    parse (ref unowned string[] args) throws GLib.OptionError
    {
      this.oc.parse (ref args);
    }
    public void
    show ()
    {
      print ("size: %d, verbose: %s\n", this.size, this.verbose.to_string ());
    }
  }
  int
  main (string[] args)
  {
    var opts = new Options ();
    try
    {
      opts.parse (ref args);
    }
    catch (GLib.OptionError e)
    {
      GLib.critical ("Failed to parse cmdline: %s", e.message);
      return Posix.EXIT_FAILURE;
    }
    opts.show ();
    return Posix.EXIT_SUCCESS;
  }
}

エラーが出ないようにする場合、GLib.OptionEntry構造体を1つずつ作成して下のように書くことになってしまい、綺麗に整理するのが難しい。実行結果は「Vala言語でコマンド行オプションの解析と処理を行う(ページ1/3)」の例と同様。
[任意]ファイル名: optioncontexttest2.vala

/*
 * OptionContextクラスのテスト
 * オプション処理用のクラスのインスタンスを生成しデータをインスタンスメンバに格納する方法
 * valac --pkg posix optioncontexttest2.vala -o optioncontexttest2
 */

using Posix;

namespace OptionContextTest2
{
  // GLib.OptionContextはCompactなクラスで継承してインスタンスメンバを作ることはできないため
  // 別のクラスを作ることにする
  class Options
  {
    GLib.OptionContext oc;
    int size;
    bool verbose;
    public
    Options ()
    {
      this.oc = new GLib.OptionContext ("- OptionContext test");
      // GLib.OptionEntry構造体
      // 1. 長いオプション(string)
      // 2. 短いオプション(char)
      // 3. フラグ(Glib.OptionFlags)
      // 4. オプションに対する引数の種類(GLib.OptionArg)
      // 5. 書き込み先(void *) out指定可
      // 6. 説明(string)
      // 7. オプション引数の表記(string)
      GLib.OptionEntry entry_size = {"size", 's', 0, GLib.OptionArg.INT, out this.size, "set size", "SIZE"};
      GLib.OptionEntry entry_verbose = {"verbose", 'v', 0, GLib.OptionArg.NONE, out this.verbose, "be verbose", null};
      GLib.OptionEntry entry_null = {null};
      // 「{null}」の項目(entry_null)も作って最後に入れないとおかしな項目が処理される
      this.oc.add_main_entries ({entry_size, entry_verbose, entry_null}, null);
    }
    public void
    parse (ref unowned string[] args) throws GLib.OptionError
    {
      this.oc.parse (ref args);
    }
    public void
    show ()
    {
      print ("size: %d, verbose: %s\n", this.size, this.verbose.to_string ());
    }
  }
  int
  main (string[] args)
  {
    var opts = new Options ();
    try
    {
      opts.parse (ref args);
    }
    catch (GLib.OptionError e)
    {
      GLib.critical ("Failed to parse command line: %s", e.message);
      return EXIT_FAILURE;
    }
    opts.show ();
    return EXIT_SUCCESS;
  }
}

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

関連記事:

使用したバージョン:

  • Vala 0.9.4, 0.9.5
  • GLib 2.24.1