For Development HEAD DRAFTSearch (procedure/syntax/module):

Next: , Previous: , Up: ライブラリモジュール - Gauche拡張モジュール   [Contents][Index]

9.25 gauche.parseopt - コマンドライン引数の解析

Module: gauche.parseopt

このモジュールでは、コマンドラインオプションをパースするための便利な方法を定義 しています。インタフェースは Perl にヒントを受けたもので、複数のオプション引数を 伴う長い形式のオプションを便利に扱うことができます。

実際、Gauche でコマンドラインオプションをパースするにはいくつかの選択肢が あります。SRFI-37 (srfi.37 - args-fold プログラム引数処理参照)では、 POSIX/GNU 互換の引数構文をパースするための関数的なインタフェースを提供しています。 SLIB は、getopt 互換のユーティリティを持っています。 要求される機能はアプリケーションごとに異なるので、 あなたの要求にフィットするものを選んで下さい。

High-level API

Macro: let-args args (bind-spec … [. rest]) body …

{gauche.parseopt} このマクロはコマンドライン引数処理の最も典型的なパターンを扱います。 引数のリストargsを取り、bind-specで示される仕様をもとに コマンドラインオプションを探してその値を変数に束縛し、それから body …を実行します。

まず簡単な例を見てみましょう。このフォームが何をするか、だいたい想像できるのでは ないかと思います。(より多くの例については下の“Examples”の項を参照して ください)。

(define (main args)
  (let-args (cdr args)
      ((verbose     "v|verbose")
       (outfile     "o|outfile=s")
       (debug-level "d|debug-level=i" 0)
       (help        "h|help" => (cut show-help (car args)))
       . restargs
      )
    ....))

(define (show-help progname)
  ...)

ローカル変数verboseは、コマンドラインオプション-v--verbose が与えられれば#tに、そうでなければ#fに束縛されます。 変数outputはオプション引数を取ると指定されており、例えば -o out.txtのようにコマンドラインに指定されれば値"out.txt"が 束縛されます。debug-levelも似ていますが、オプション引数は 整数へと変換され、またデフォルト値0が指定されています。 help節では、単に値を束縛するだけでなくアクションを起動しています。

(註: 今のところlet-args-v--vを区別しません。 -verbose--verboseも同様です。将来、getopt_long(3)と 互換になるオプションを追加するかもしれません。)

最後のドットの後のrestargsは、オプションでないコマンドライン引数のリストを 受け取ります。

bind-specについて詳しく見てみましょう。 bind-specは次のいずれかの形式でなければなりません。

1. (var option-spec)
2. (var option-spec default)
3. (var option-spec => callback)
4. (var option-spec default => callback)

5. (else => handler)
6. (else formals body ...)

コマンドライン引数のリストがargsに渡されると、それが option-specに基づいてパーズされます。該当するオプションが見付かれば、 変数varが次に述べる値に束縛されます:

(a) bind-specの形式が上の1. または2. の場合:
  (a1) option-specが引数を要求しない場合は、#t。
  (a2) option-specがひとつの引数を要求する場合は、その引数の値。
  (a3) option-specがそれ以上の引数を要求する場合は、引数の値のリスト。
(b) bind-specの形式が上の3. または4. の場合、callbackを
  引数の値を伴って呼び出し、その戻り値。

option-specの詳細については後で説明します。

特別な場合として、var#fとすることもできます。 その場合、値は無視されます。 callbackでの副作用だけに関心がある場合に使えるでしょう。

対応するオプションがargsに与えられなかった場合、 vardefaultが与えられていればその値に、 そうでなければ#fに束縛されます。

最後のbind-specには5か6の形式も許されます。 この節は、どのoption-specにもマッチしないコマンドラインオプションが 与えられた場合に選択されます。 5番目の形式では、handlerが3つの引数を伴って呼び出されます。 引数は、マッチしなかったコマンドラインオプション、 残りのコマンドライン引数、そして引数処理に戻るための継続手続きです。 handlerは与えられたコマンドラインオプションを処理した後、 オプション処理を続けたければ継続手続きに残りのコマンドライン引数を渡し、 オプション処理を打ちきりたければ残りのコマンドライン引数を戻り値として 返します。返された値は通常の(オプションでない)コマンドライン引数として扱われます。

束縛リストは、最後のcdrにシンボルを持つ不完全なリストであっても良く、 その場合はコマンドライン引数の残りのリストがその変数にと束縛されます。

defaultcallbackelse節のフォーム等は varの束縛の外側のスコープで評価されることに注意して下さい。

C における典型的な getoptgetopt_long の実装とは異なり、 let-args は与えられたコマンドライン引数の順番を変えません。 オプションでない引数(ハイフンで始まらない引数)に遭遇した時点でパースを 中止します。

パーサは、ハイフン2つのみの引数 ‘--’ に遭遇すると、引数パーシングを 中止して‘--’ の後の引数のリストを返します。

全ての束縛が終了した後、body … が評価されます。 bodyは内部defineで始まっていても構いません。

Option spec

option-spec は、オプションの名前とそのオプションがどのように引数を取るか を指定する文字列です。オプションの名前には、アルファベット文字、数字、 アンダースコア、プラス記号、ハイフンが許されますが、ハイフンは最初の文字としては 使えません。すなわち、有効なオプションの名前は、#/[\w+][-\w+]*/ という 正規表現にマッチするものです。

オプションが引数を取る場合、名前の後ろに等号文字と引数の型を表現する文字を 付けることで指定できます。オプションは一つ以上の引数を取ることができます。 以下の文字がオプションの引数の型を表現するものとして認識されます。

s

文字列。

n

数値。

f

実数 (flonumに変換されます)。

i

正確な整数。

e

S式。

y

シンボル (引数はstring->symbolにより変換される)。

option-specの例を見てみましょう:

"name"

引数を取らないオプションの name を指定します。

"name=s"

オプション name は引数を一つ取り、それは文字列として渡されます。

"name=i"

オプション name は引数を一つ取り、それは正確整数として渡されます。

"name=ss"

オプション name は引数を二つ取り、両方とも文字列です。

"name=iii"

オプション name は3つの整数の引数を取ります。

"name=sf"

オプション name は2つの引数を取ります。一つ目は文字列で、 二つ目は数値です。

オプションにいくつかの別名がある場合は、"|" でつなげて書いておくことができます。 例えば"h|help"というoption-specは "h"にも"help"にもマッチします。

コマンドラインでは、オプションは一つか二つのハイフンに続いて与えられます。 オプションの引数は、オプションそのものと等号記号でつながれていても構いません。 例えば、以下の全てのコマンドライン引数は、オプションの仕様、"prefix=s" に マッチします。

-prefix /home/shiro
-prefix=/home/shiro
--prefix /home/shiro
--prefix=/home/shiro

オプションが一文字からなり、引数を取る場合、 最初の引数はスペースなしでオプション文字の直後に置かれても構いません。 例えばオプション仕様"I=s"は、以下のコマンドライン引数のいずれも認識します。

-I/foo
-I /foo
-I=/foo
--I/foo
--I /foo
--I=/foo

長いオプション名と、一文字のオプション+引数、の間で曖昧性が生じた場合は、 長いオプションの方が優先されます。例えば"long"および"l=s"という オプション仕様があった場合、コマンドライン引数-long-lオプション+引数ongではなく、ひとつのオプション-longと 解釈されます。

Error handling

Condition Type: <parseopt-error>

{gauche.parseopt} let-argsが、option-specに従わない引数を見つけた場合は、 コンディションタイプ<parseopt-error>のエラーを投げます。 例えば、必須のオプション引数が与えられていなかったり、異なる型であった 場合などです。

(let-args '("-a" "foo") ((a "a=i")) ; option a requires integer
  (list a))
 ⇒ parseopt-error

このコンディションはあくまでargsに渡された引数をパーズする際に発生するものです。 option-specが不正であった場合は通常のエラーが投げられます。

Examples

これはgauche-installスクリプトから取った例です。 modeオプションは8進数のオプション引数を取るので、コールバック 手続きを使って変換しています。また、認識できないオプションをelse節で 処理しています。

  (let-args (cdr args)
      ((#f      "c")        ;; ignore for historical reason
       (mkdir   "d|directory")
       (mode    "m|mode=s" #o755 => (cut string->number <> 8))
       (owner   "o|owner=s")
       (group   "g|group=s")
       (srcdir  "S|srcdir=s")
       (target  "T|target=s")
       (utarget "U|uninstall=s")
       (shebang "shebang=s")
       (verb    "v")
       (dry     "n|dry-run")
       (#f      "h|help" => usage)
       (else (opt . _) (print "Unknown option : " opt) (usage))
       . args)
    ...)

次の例はelse節の使い方を示す小さなプログラムです。 コマンドラインオプションを変数rに集めてゆきますが、 オプション -c に出会うとオプション処理を中止して残りを restargsへと渡します。

(use gauche.parseopt)

(define (main args)
  (let1 r '()
    (let-args (cdr args)
      ((else (opt rest cont)
         (cond [(equal? opt "c") rest]
               [else (push! r opt) (cont rest)]))
       . restargs)
     (print "options: " (reverse r))
     (print "restargs: " restargs)
     0)))

上のスクリプトの実行例です (exampleというファイル名で保存されていると します)。

$ ./example -a -b -c -d -e foo
options: (a b)
restargs: (-d -e foo)
$ ./example -a -b -d -e foo
options: (a b d e)
restargs: (foo)

Low-level API

The followings are lower-level API used to build let-args macro.

Macro: parse-options args (option-clause …)

{gauche.parseopt} args は、コマンドライン引数のリストを含む式です。 このマクロは、コマンドラインオプション(‘-’ で始まる引数)をスキャンし、 option-clause の指定に従って処理し、残りの引数を返します。

それぞれの option-clause は、option-spec とそのアクションのペアで 構成されます。

与えられたコマンドラインオプションが option-spec の一つにマッチすると、 関連付けられたアクションが評価されます。アクションは以下のフォームの一つです。

bind-spec body

bind-spec は、ラムダリストのような変数の正しいリストかドット対リストです。 オプションの引数は bind-spec に束縛され、body … が評価されます。

=> proc

コマンドラインオプションが option-spec にマッチすると、 proc がオプションの引数のリストとともに呼び出されます。

シンボル elseoption-spec の位置にある場合、その節は、 与えられたコマンドラインオプションにマッチする他のオプション節が ない場合に選択されます。その節には3つの“引数”が関連付けられます。 それらは、マッチしなかったオプション、引数の残り、オプションパーサを 表す手続きです。

Macro: make-option-parser (option-clause …)

{gauche.parseopt} これは低レベルのインタフェースです。option-clause は、 parse-options と同じです。このマクロは、コマンドラインオプションを 後でパースするために使うことができる手続きを返します。

返される手続きは、一つの必須の引数と一つのオプション引数を取ります。 必須の引数は、与えられたコマンドライン引数としての文字列のリストです。 オプションの引数は、三つ以上の引数を取る手続きで、それが与えられると 手続きはそれが else オプション節のボディであるかのように使われます。


Next: , Previous: , Up: ライブラリモジュール - Gauche拡張モジュール   [Contents][Index]


For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT