6.1. kink/ARGV_PARSER

コマンドライン引数列、つまりargvをパースして、オプションスイッチ、オプション引数、非オプション要素に分解する。パースはglibcのgetopt_longのスタイルで行われる。

# filename: voxxx.kn

:ARGV_PARSER.require_from('kink/')
:PROCESS.require_from('kink/')

:parse_argv <- {(:Argv)
  :Depot = new_val('Loglevel' 'ERROR')
  :Non_opts = ARGV_PARSER.parse(Argv){(:P)
    P.no_arg(['-h' '--help']){
      stdout.print_line('USAGE: kink voxxx.kn [Options...] [--] [Args...]')
      PROCESS.exit(0)
    }
    P.req_arg(['-L' '--loglevel']){(:Arg)
      Depot:Loglevel <- Arg
    }
    P.on_error{(:Msg)
      stderr.print_line('voxxx: {}'.format(Msg))
      PROCESS.exit(64)
    }
  }
  [Depot.Loglevel Non_opts]
}

:main <- {(:Argv)
  [:Loglevel :Non_opts] = parse_argv(Argv)
  stdout.print_line('loglevel={} non-option-elements={}'.format(Loglevel Non_opts.repr))
}

# $ kink voxxx.kn --log INFO foo bar
# loglevel=INFO non-option-elements=["foo" "bar"]
#
# $ kink voxxx.kn --LDEBUG foo bar
# loglevel=DEBUG non-option-elements=["foo" "bar"]
#
# $ kink voxxx.kn foo bar
# loglevel=ERROR non-option-elements=["foo" "bar"]
#
# $ kink voxxx.kn --help
# USAGE: kink voxxx.kn [Options...] [--] [Args...]

オプションスイッチ

オプションスイッチには次の二種類がある。

• 短いスイッチ: 先頭の `-` と、引き続くひとつのコードポイントからなる。ただし `--` は除く。例: `-h`

• 長いスイッチ: 先頭の `--` と、引き続くひとつ以上のコードポイントからなる。 `=` を含んではならない。例: `--help`

それぞれのオプションスイッチは、引数の取り方によって、次の3つのカテゴリに分けられる。

• req_arg: ひとつのオプション引数を取る

• opt_arg: 0か1つのオプション引数を取る

• no_arg: オプション引数を取らない

ふたつのハイフン `--` からなるargv要素は、オプションスイッチではない。オプションと、非オプション要素を分けるセパレータとして使える。

短いreq_argオプションスイッチ

短いreq_argスイッチ `-p` が定義されているとする。このオプションスイッチは次のように使える。

• -pkink/ → オプション引数 = `kink/`

• -p kink/ → オプション引数 = `kink/`

長いreq_argオプションスイッチ

長いreq_argスイッチ `--prefix` が定義されているとする。このオプションスイッチは次のように使える。

• --prefix=kink/ → オプション引数 = `kink/`

• --prefix kink/ → オプション引数 = `kink/`

オプションスイッチは、曖昧でない場合、 `--pat`, `--pa`, `--p`` のように省略できる。詳細は後のセクションを見よう。

短いopt_argオプションスイッチ

短いopt_argスイッチ `-b` が定義されているとする。このオプションスイッチは次のように使える。

• -b4096 → オプション引数 = `4096`

• -b → オプション引数 = 空文字列 ``

長いopt_argオプションスイッチ

長いopt_argスイッチ `--buffer` が定義されているとする。このオプションスイッチは次のように使える。

• --buffer=4096 → オプション引数 = `4096`

• --buffer → オプション引数 = 空文字列 ``

短いno_argオプションスイッチ

短いno_argスイッチ `-h` が定義されているとする。このオプションスイッチは次のように使える。

• -h

オプションスイッチの後に1つ以上のコードポイントが続く場合、後続するコードポイントは別のオプションとして扱われる。たとえば、no_argオプションスイッチ `-x`, `-z` と、req_argスイッチ `-f` が定義されている場合、argv `-xzf./archive.tgz` は次のようにパースされる:

• -x (オプション引数なし)

• -z (オプション引数なし)

• -f (オプション引数 `./archive.tgz`)

長いno_argオプションスイッチ

長いno_argスイッチ `--help` が定義されているとする。このオプションスイッチは次のように使える。

• --help

長いオプションスイッチの省略

長いオプションスイッチは、曖昧でない限りで、先頭部分に省略できる。たとえば、長いオプションスイッチ `--verbose` と `--version` が定義されているとき、それぞれのオプションスイッチは次のように省略できる:

• --verbose: --verbos, --verbo, --verb

• --version: --versio, --versi, --vers

完全一致は省略形よりも常に優先される。たとえば、長いオプションスイッチ `--time` と `--time-style` が定義されているとき、argv `--time`は、 `--time-style` の省略ではなく、オプションスイッチ `--time` としてパースされる。

非オプション要素

argvの要素のうち、オプションスイッチでもオプション引数でもセパレータ `--` でもないものが、非オプション要素である。

オプションと非オプション要素を、ふたつのハイフン `--` で分けることができる。たとえば、no_argスイッチ `-x`, `-y`, `-z` が定義されているとき、argv `-x -y -- -z a b c` は次のようにパースされる:

• オプション: -x, -y

• 非オプション要素: -z, a, b, c

strict_orderモードが指定されていない場合、オプションは非オプション要素の後にも現れることができる。たとえば、no_argスイッチ `-x`, `-y`, `-z` が定義されているとき、argv `-x a b c -y -z` は次のようにパースされる:

• オプション: -x, -y, -z

• 非オプション要素: a b c

strict_orderモードが有効にされた場合、最初の非オプション要素以降の要素はすべて非オプション要素になる。これは、POSIXLY_CORRECTが設定された場合のgetopt_longの動作に相当する。たとえば、no_argスイッチ `-x`, `-y`, `-z` が定義されているとき、argv `-x a b c -y -z` は次のようにパースされる:

• オプション: -x

• 非オプション要素: a, b, c, -y, -z

getopt_longとの違い

1. getopt_longは、argv[0]がプログラム名であると想定する。ARGV_PARSERは、プログラム名の後の引数列を扱う。

2. getopt_longには、 `-W foo` を `--foo` として扱う機能がある。ARGV_PARSERにはそのような機能はない。

6.1.1. ARGV_PARSER.parse(Argv ...[$config={}])

parseは、$configによる設定にしたがい、Argvをパースしてオプションと非オプション要素に分解する。

パースがエラーなく完了した場合、parseは、非オプション要素のstr値のvec値を引数として、成功時継続(C.on_successを見よう)を末尾呼び出しする。

パースがエラーに終わった場合、parseは、エラーメッセージのstr値を引数としてエラー時継続(C.on_errorを見よう)を末尾呼び出しする。

事前条件

Argvは、str値のvecでなければならない。

$configは、argv_parser_configを取る関数でなければならない。

6.1.2. argv_parser_config型

argv_parser_configは、ARGV_PARSER.parseのコンフィグ値である。

6.1.2.1. C.req_arg(Switches $action)

req_argメソッドは、Switches中の要素をreq_argオプションスイッチとして定義する。

Switches内のオプションスイッチがパースされたら、対応するオプション引数のstr値を渡して$actionが呼び出される。

事前条件

Switchesは、長いオプションスイッチか短いオプションスイッチを表すstr値のvecでなければならない。

Switchesは空であってはならない。

オプションスイッチは、ARGV_PARSER.parseの呼び出しの中で一意でなければならない。

$actionは、strを取る関数でなければならない。

6.1.2.2. C.opt_arg(Switches $action)

opt_argメソッドは、Switches中の要素をopt_argオプションスイッチとして定義する。

Switches内のオプションスイッチがパースされたら、対応するオプション引数のstr値を渡して$actionが呼び出される。オプション引数が省略された場合、空文字列のstr値が$actionに渡される。

事前条件

Switchesは、長いオプションスイッチか短いオプションスイッチを表すstr値のvecでなければならない。

Switchesは空であってはならない。

オプションスイッチは、ARGV_PARSER.parseの呼び出しの中で一意でなければならない。

$actionは、strを取る関数でなければならない。

6.1.2.3. C.no_arg(Switches $action)

no_argメソッドは、Switches中の要素をno_argオプションスイッチとして定義する。

Switches内のオプションスイッチがパースされたら、引数なしで$actionが呼び出される。

事前条件

Switchesは、長いオプションスイッチか短いオプションスイッチを表すstr値のvecでなければならない。

Switchesは空であってはならない。

オプションスイッチは、ARGV_PARSER.parseの呼び出しの中で一意でなければならない。

$actionはサンクでなければならない。

6.1.2.4. C.strict_order

strict_orderメソッドは、パースがstrict_orderモードで行われることを指示する。

これは、getopt_longにPOSIXLY_CORRECTを設定することに対応する。

6.1.2.5. C.on_success($success)

on_successは、ARGV_PARSER.parseの成功時継続として$successを使うことを指示する。

on_successが呼ばれない場合は、VAL.identityがデフォルトとして使われる。

事前条件

$successは、str値のvecを取る関数でなければならない。このvecは、argvの非オプション要素列である。

6.1.2.6. C.on_error($error)

on_errorは、ARGV_PARSER.parseのエラー時継続として$errorを使うことを指示する。

on_errorが呼ばれない場合は、raiseがデフォルトとして使われる。

事前条件

$errorはstrを取る関数でなければならない。このstrはエラーメッセージである。