Hatena::ブログ(Diary)

純粋関数型雑記帳 このページをアンテナに追加 RSSフィード Twitter

このページはHaskellを愛でるページです。
日刊形式でHaskellなどについての記事をだらだらと掲載しとります。
2004 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 06 | 07 | 08 | 09 | 11 |
2007 | 03 | 04 | 05 | 07 | 08 | 09 | 12 |
2008 | 02 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 03 | 05 | 06 | 09 | 10 | 11 | 12 |
2010 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 12 |
2011 | 01 | 02 | 05 |
本体サイト

2009年10月28日(水) C++向け簡易コマンドラインパーザ cmdline

[] C++向け簡易コマンドラインパーザ cmdline  C++向け簡易コマンドラインパーザ cmdlineを含むブックマーク  C++向け簡易コマンドラインパーザ cmdlineのブックマークコメント

を作りました。

http://github.com/tanakh/cmdline

何か

コマンドライン引き数の解析を助けるライブラリです。同じ目的ライブラリに、Cの標準関数であるgetoptgooglegflagsなどがありますが、cmdlineは適当に使えてそこそこ便利というのを目指しています。getoptは使いにくいし、usageも自分で書く必要がある。gflagsはライブラリインストールしたり、リンクしたりちょっと大掛かり。cmdlineは、1ヘッダファイルで、コピーするだけで使えて、修正BSDライセンスで公開しているので、自由にプログラムに取り込んでいただけます。

コードサンプル

#include "cmdline.h"

int main(int argc, char *argv[])
{
  cmdline::parser p;
  p.add("hoge", 'h', "hoge flag with no value");
  p.add<int>("moge", 'm', "moge flag with int value", false, 123);
  p.add("help", 0, "print help");
  // add other flags...

  if (!p.parse(argc, argv)||p.exist("help")){
    std::cout<<p.error_full()<<p.usage();
    return 0;
  }

  // main code...

  if (p.exist("hoge"))
     std::cout<<"there is hoge flag"<<std::endl;

  std::cout<<"moge value: "<<p.get<int>("moge")<<std::endl;

  // ...
}

プログラムのように、cmdline::parserのオブジェクトを生成してやり、parser::add()によりフラグを追加し、parser::parse()を呼び出します。実行例です。

> ./a.out --help
usage: ./a.out [options] ...
options:
  -h, --hoge    hoge flag with no value
  -m, --moge    moge flag with int value (int [=123])
      --help    print help

> ./a.out --moge=777 -h
there is hoge flag
moge value: 777

>  ./a.out --moge=huga
option value is invalid: --moge=huga
usage: ./a.out [options] ...
options:
  -h, --hoge    hoge flag with no value
  -m, --moge    moge flag with int value (int [=123])
      --help    print help

マニュアル

parser::add(const string &name, char short_name, const string &description)

値を持たないフラグ定義します。フルネーム、短縮名、フラグの説明、の順です。短縮名に0を指定すると、短縮名なしになります。

template <class T> void parser::add(const std::string &name, char short_name=0, const std::string &desc="", bool need=true, const T def=T())

値を持つフラグ定義します。必須なのは、フルネーム、短縮名、フラグの説明(と、テンプレートパラメータである型)です。オプショナルな引き数として、そのフラグが必須か(必須ならば、コマンドラインで与えられないときにparseがエラーになります)と、フラグ値が与えられなかったときのデフォルトの値があります。短縮名を0にすると短縮名なしになるのは上と同じです。

template <class T, class F> void parser::add(const std::string &name, char short_name=0, const std::string &desc="", bool need=true, const T def=T(), F reader=F())

上と同じく、値を持つフラグ定義します。値に対するカスタムreaderをセットできます。上のメソッドでは、デフォルトreaderとして、lexical_cast<T>が使われます。stringから型Tへの任意の関数もしくは関数オブジェクトが渡せます。この関数が例外を投げる場合、失敗とみなされ、parser::parse()は失敗になります。

bool parser::parse(int argc, char *argv[])

コマンドライン引き数を解析します。mainの引き数をそのまま渡します。失敗したらfalse、成功したらtrueが返ります。失敗した場合、parser::error()で具体的なエラーメッセージが取得できます。

bool parser::exist(const string &name)

コマンドライン引き数に与えられたフラグが存在していたかを返します。parser::parse()した後に使います。

template <class T> const T &parser::get(const std::string &name)

与えられたフラグの値を返します。parser::parse()した後に使います。フラグ名が不正(addされていない)、もしくは型がaddしたときとかみ合わない場合、cmdline::cmdline_error例外が投げられます。

const std::vector<std::string> &parser::rest()

コマンドライン引き数のうち、コマンドラインオプション認識されなかった引き数が格納される配列が返されます。オプションのほかにファイル名などを引き数として取りたい場合などに使えます。

std::string parser::error()

一つ目のエラーメッセージを返します。

std::string parser::error_full()

すべてのエラーメッセージを返します。

std::string parser::usage()

usageを返します。

void parser::footer(const std::string &f)

usageが返す文字列のusageの行の後ろに文字列を追加できます。

void parser::set_progam_name(const std::string &name)

usageのusageの行に表示されるプログラム名をセットできます。この関数でセットしない場合、プログラム名としてはargv[0]が使われます。

カスタムreader

デフォルトでは、フラグの値を読むのに、lexical_cast(のような自前のもの)が使われます。このため、add<int>などとすると、コマンドライン引き数が10進整数として読まれ、不正な値ならばparseが失敗するなどの動作になります。この処理はオプションで変更することができ、lexical_castの代わりに任意の関数オブジェクトを渡すことができます。なので、16進で読ませることや、特定のレンジにある値、のような指定もできます。cmdlineでは、簡便のために、レンジ付き値、択一などのreaderがあらかじめ用意されています。デフォルトの動作は、cmdline::default_reader<T>として参照できます。

  p.add<int>("hoge", 'h', "int value (100 - 999)", cmdline::range(100, 999));
  p.add<string>("moge", 'm', "one of abd, def, ghi", cmdline::oneof<string>("abc", "def", "ghi"));

関数合成的な演算子を用意して、ごりごりと合成できるほうがいいかなとも思いましたが、独自の演算子定義して、それを覚えてもらうのもよくないかなと思ってやめました。とにかく覚えること少なくて、ぬるく使えるように。