コマンドラインオプションを解析する

以下の環境で動作確認しました。

UWSC で、コマンドラインオプションを解析します。
オプションは、ハイフンで始まって 1 つの文字が続くものにしか対応していません。

コード

OPTION EXPLICIT


// コマンドラインオプションを解析する
//
// 引数  : argv - 配列 [入力] 解析対象の配列
// 引数  : optstr - 文字列 [入力] 認識させたいオプション文字の集合
//         引数が必要な場合には文字の後ろに `:' を付ける
// 引数  : opthash - 連想配列 [入力/出力] キーにオプション、値に引数をセットした
//         連想配列がセットされる
//         オプションに引数がない場合は値に空文字がセットされる
// 引数  : argary - 配列 [入力/出力] 解析対象のオプション以外の要素がセットされる
// 引数  : opterr - 真偽値 [入力] TRUE を指定すると、エラーが発生した場合にメッ
//         セージボックスを出し、終了コード 1 で直ちにスクリプトを終了する
//         エラーになるのは以下の場合
//           * 認識できないオプションがあった
//           * 引数が必要なオプションに引数が与えられなかった
//         FALSE を指定するとメッセージボックスを出さず、また、スクリプトも終了
//         せずに処理を続ける
//         省略時は TRUE を指定したものとして動作する
//
// `-' と `--' はオプションとみなされない。
// `--' 以降は解析対象から外され、`--' より後は全て argary にセットされる。
// 同じオプションは後のもので上書きされる。
// エラーが発生したオプションは、opthash と argary のどちらにもセットされない。
// 大文字小文字を区別したいときは `OPTION SAMESTR' を指定し、連想配列を宣言する
// ときに `HASH_CASECARE' を指定する。
PROCEDURE getopt(argv[], optstr, VAR opthash[], VAR argary[], opterr=TRUE)
  DIM argc, n, i, j, isstop

  RESIZE(argary, -1)
  argc = LENGTH(argv)
  n = LENGTH(optstr)
  i = 0 // argv
  j = 0 // argary
  isstop = FALSE
  WHILE i < argc
    IFB isstop THEN // 解析中止
      RESIZE(argary, j)
      argary[j] = argv[i]
      j = j + 1
    ELSEIF (argv[i] = "--") THEN
      isstop = TRUE
    ELSE
      DIM k = 1 // optstr

      WHILE k <= n
        DIM c, argflg

        c = COPY(optstr, k, 1)
        argflg = FALSE
        IFB COPY(optstr, k+1, 1) = ":" THEN
          argflg = TRUE
          k = k + 1
        ENDIF

        IFB argv[i] = ("-" + c) THEN
          IFB argflg THEN // 引数が必要なオプション
            IFB argc - i = 1 THEN
              IFB opterr THEN
                MSGBOX(argv[i] + ": 引数が必要")
                EXITEXIT 1
              ENDIF
              BREAK
            ELSEIF (argv[i+1] <> "-") AND (POS("-", argv[i+1]) = 1) THEN
              IFB opterr THEN
                MSGBOX(argv[i] + ": 引数が必要")
                EXITEXIT 1
              ENDIF
              BREAK
            ENDIF
            opthash[argv[i]] = argv[i+1]
            i = i + 1
            BREAK
          ENDIF
          opthash[argv[i]] = ""
          BREAK
        ELSEIF k = n THEN // optstr が最後までイった
          IFB (argv[i] <> "-") AND (POS("-", argv[i]) = 1) _
              AND (LENGTH(argv[i]) = 2) AND !CHKNUM(argv[i]) THEN
            IFB opterr THEN
              MSGBOX(argv[i] + ": 無効なオプション")
              EXITEXIT 1
            ENDIF
            BREAK
          ELSE
            RESIZE(argary, j)
            argary[j] = argv[i]
            j = j + 1
          ENDIF
        ENDIF

        k = k + 1
      WEND
    ENDIF

    i = i + 1
  WEND
FEND

使用例

上記のコードを『_getopt.uws』というファイル名で保存したとします。

// test.uws: テスト

OPTION EXPLICIT
OPTION LOGFILE = 2

CALL _getopt.uws

HASHTBL opthash
DIM argary[0], i

getopt(PARAM_STR, "a:b", opthash, argary)

IF opthash["-a", HASH_EXISTS] THEN PRINT "-a: "+opthash["-a"]
IF opthash["-b", HASH_EXISTS] THEN PRINT "-b: "+opthash["-b"]

FOR i=0 TO LENGTH(argary)-1
  PRINT argary[i]
NEXT

という内容のファイル『test.uws』を作成して、

UWSC test.uws -a aaa -b ccc d e f

というコマンドラインを実行すると、ログファイルに以下の文字列が印字されます。

-a: aaa
-b: 
ccc
d
e
f