ヌル終了パラメーターのCLでの処理
System iNetwork フォーラムの最近の討論で、誰かがヌル終了パラメーターを受信する CL プログラムの作成方法をたずねていました。私の最初の反応は、CL でこれをやるのはばかげているということでした。しかし、考えてみると、ずっと意味があることがわかってきました。
結局、C から CL プログラムまたはプロシージャーを呼び出すと、明らかにヌル終了文字列を処理できるようになると考えるでしょう。しかし、おそらくもっと便利な事実があるのですが、QShell コマンドまたはスクリプトから呼び出される CL プログラムを作成すると、ヌル終了文字列を渡すのです。そして、QShell から CL を呼び出すのは非常に便利であると言えます。
この概念に不慣れな場合は、ヌル終了文字列は x'00' (「ヌル」と呼ばれる) という特殊値が検出されると終了する、可変長文字列であると言わせてください。したがって、ヌル終了文字列は x'00' が検出されると最終的に終了する任意の長さの連続バイトに過ぎません。
フォーラムのスレッドで、Bruce Vining は親切にも、自分が推奨するヌル終了文字列の処理方法を掲載してくれました。以下がそのコードです。
Pgm Parm(&String_In) Dcl Var(&String_In) Type(*Char) Len(32767) Dcl Var(&Data) Type(*Char) Len(50) Dcl Var(&Length) Type(*UInt) CallPrc Prc('__strlen') Parm(&String_In) + RtnVal(&Length) ChgVar Var(&Data) Value(%sst(&String_In 1 &Length)) SndPgmMsg Msg(&Data) Return EndPgm
Bruce の例でいくつか注目すべき重要な点があります。
- &String_in パラメーターの長さは、プログラムが処理できる最大文字列の長さでなければなりません。
- このコードは ILE CL で、ソース・メンバー・タイプは CLLE でなければなりません。CallPrc が許可されないというエラーを受信したら、ILE CL を使用することを忘れたことを意味します。
- コードは、外部関数として__strlen を呼び出しているように見えますが、実際は__strlen MI 関数がプログラムにインラインで挿入されます。
Bruce は、特殊な処理をしなくてもヌル終了文字列を CL プログラムの別の場所で使用できるよう、ヌル終了文字列を通常のタイプ *CHAR の CL 変数にコピーしています。彼の例では、文字列の内容を表示するため、単なるテストとしてヌル終了文字列を SNDPGMMSG に渡しています。
QShell の最も用途が広いツールの中に find というユーティリティーがあります。find ユーティリティーは、さまざまな基準に基づきファイルの IFS の特定のサブツリーを検索できます。find が検索できる部分リストを示します。
- ファイルが最後に変更された日時
- ファイルが最後にアクセスされた日時 (read from)
- 特定のユーザーにより所有されているファイル
- 特定のグループにより所有されているファイル
- ファイル名にある文字を含むファイル
- あるタイプのファイル (ディレクトリーまたはデータ・ファイル)
- 特定のサイズ以上のファイル
find の検索基準に一致する各ファイルで特定のプログラムを実行するよう find に任意に指示できます。これが、CL プログラムが出現する場所です。特定の基準に一致する IFS ファイルで動作する必要がある CL プログラムが必要な場合、find ユーティリティーに簡単に CL プログラムを起動させ、ファイル名をパラメーターとして渡させることができます。検索される各ファイル別々にプログラムを起動します。
QShell の find ユーティリティーの構文は次のとおりです。
find start-path(s) criteria action
- start-path(s): 検索する 1 つまたは複数の IFS パス名。QShell は指定する各パス名下のすべてのディレクトリーおよびサブディレクトリーを検索します。
- criteria: どのファイルを検索しているか指定する式。
- action: 検索するファイルで何をしたいのか。デフォルトでは、-print アクションが取られます。これは、ファイル名を stdout に印刷しますが、各ファイルにプログラムを実行する場合は -exec を指定できます。
たとえば、過去に変更された /upload1 ディレクトリー内のすべてのファイルのリストを印刷する場合は、以下のようにコーディングできます。
find /upload1 -type f -mtime 1 -print
-type スイッチは基準の一部です。タイプ f を指定したため、(ディレクトリー、ソケット、他の特殊オブジェクトとは違う) IFS が「ファイル」として扱うオブジェクトのみ組み込みます。-mtime スイッチは、(この例では) 1 日以内に変更されたファイルのみ組み込むよう指示しています。-print スイッチは標準出力に印刷するよう指示しています。デフォルトでは、これによりデータはディスプレイに印刷されます。
ディスプレイに印刷するのではなく、-exec スイッチを使用して find にプログラムを実行するよう指示できます。-exec スイッチの構文を以下に示します。
find start-path(s) criteria -exec command \;
最後の \; に注意してください。これは重要な点です。コマンド・ストリングは 1 単語より長い場合があるためです。find ユーティリティーはコマンドの一部としての -exec の後から \ に達するまでのすべてを組み込みます。\; は、コマンド・ストリングが完了したことを指示します。
ユーティリティーにパス名を挿入させたい場所に特殊文字列 {} を挿入できます。{} がどこで見つかっても、パス名をコマンド・ストリングに挿入します。例えば、過去に /upload1 ディレクトリーに追加された各ファイルについて SCOTT/ADDTOPF という CL プログラムを実行する場合、次のようにします。
find /upload1 -type f -mtime 1 -exec /qsys.lib/scott.lib/addtopf.pgm "{}" \;
CL プログラム名に IFS 構文を使用しなければならなかった点に注目してください。IFS 構文では、従来のライブラリーとそのオブジェクトは階層で配列されており、あらゆるライブラリーが QSYS ライブラリー内にあり、あらゆるオブジェクトにそのオブジェクト・タイプの接尾部が付いています。したがってこの例では、/qsys.lib が QSYS ライブラリーです。その中に SCOTT ライブラリーがあり、SCOTT ライブラリーの中に ADDTOPF というプログラムがあります。Unix では、別のコマンドで先行させずにパスとプログラム名をリストするだけの場合、Unix はそのプログラムを実行しようとします (プログラムの実行はデフォルト動作であるため、「呼び出す」と言う必要はありません)。したがって、コマンドが /qsys.lib/scott.lib/addtopf.pgm であると指示すれば、QShell はそのプログラムを実行するよう指示されます。
例があるので、これらのファイルが顧客によりアップロードされているとしましょう。顧客のデータは常に UTF-16 Unicode にありますが、アップロードすると、FTP により CCSID 819 とマークされます。ADDTOPF プログラムはファイルで CCSID を修正する必要があり、CPYFRMIMPF を実行してそれをデータベースに挿入します。
PGM PARM(&STMFNULL) DCL VAR(&STMFNULL) TYPE(*CHAR) LEN(5000) DCL VAR(&STMF) TYPE(*CHAR) LEN(5000) DCL VAR(&LEN) TYPE(*UINT) LEN(4) /* ヌル終了文字列を非ヌルに変換 */ CALLPRC PRC('__strlen') PARM(&STMFNULL) + RTNVAL(&LEN) IF (&LEN *GE 1) DO CHGVAR VAR(&STMF) VALUE(%SST(&STMFNULL 1 &LEN)) ENDDO /* 強制的に CCSID を一般的なアップロード・エラー 1200 に指定 */ CHGATR OBJ(&STMF) ATR(*CCSID) VALUE(1200) /* ストリーム・ファイル・データを MYFILE ファイルに追加 */ CPYFRMIMPF FROMSTMF(&STMF) TOFILE(MYFILE) + MBROPT(*UPDADD) ERRRCDOPT(*ADD) + RPLNULLVAL(*FLDDFT) ENDPGM