04.2オペレーター応答とコマンドを受け取る(WTORとQEDIT)
プログラムがコンソール・オペレーターと通信(会話)を行うには2つの方法があります。1つはメッセージを出力して、そのメッセージに対する応答を受け取る方法です。もう1つはメッセージとは無関係にオペレーターがMODIFYコマンドやSTOPコマンドによってプログラムに指示を与える方法です。
前者はプログラムでオペレーターの判断を必要とする何らかの事態が起きたときに利用されます。例えばデータセットを初期化することがパラメーターで指定された時に、本当にクリアーしてもいいのかを再確認するような機能を持たせる場合や、誤った入力データを見つけたような時に、処理不能で異常終了するのか、誤ったデータを無視して処理を続けるのか、などを選択させるような場合に、その旨のメッセージをコンソールに出して、この後どう動くかをオペレーターに判断してもらうようなプログラムを作ることができます。
後者はオペレーターの都合によってプログラムに特定の動作を行わせたり、動きを変える場合などに利用されます。バッチ処理のように入力データが終わったらプログラムの処理も終わるのではなく、一定時間あるいはオペレーターが指示するまで動き続ける常駐型のプログラムを作る際に必要となる機能です。MODIFYコマンドでプログラムの動作や機能を変更し、STOPコマンドでプログラムを終了させるのが一般的です。
メッセージに対するオペレーター応答を受け取る
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- MVI WTORECB,0 CLEAR WTOR ECB WTOR 'MYP003D INVALID INPUT DATA FOUND, REPLY ''GO'' TO CONTI+ NUE OR ''CANCEL''', + RPLYAREA,L'RPLYAREA,WTORECB WAIT ECB=WTORECB WAIT UNTIL REPLIED BY OPERATOR : : : WTORECB DC F'0' ECB OF WTOR SERVICE RPLYAREA DC CL6' ' ENTERED REPLY COMMAND AREA MVI WTORECB,0 CLEAR WTOR ECB WTOR TEXT=(MSGLENG,RPLYAREA,L'RPLYAREA,WTORECB) WAIT ECB=WTORECB WAIT UNTIL REPLIED BY OPERATOR : : : WTORECB DC F'0' ECB OF WTOR SERVICE RPLYAREA DC CL6' ' ENTERED REPLY COMMAND AREA MSGLENG DC AL2(L'MSGTEXT) MSGTEXT DC C'MYP004A ENTER EXECUTE OPTIONS OR U'
WTORマクロはコンソールにメッセージを表示して、オペレーターからの応答を受け取ります。出力するメッセージの指定方法はWTOマクロと同じですが、オペレーターからの応答を受け取る領域とその長さ、および待ち受けのためのECBアドレスを追加で指定します。
WTORマクロの完了はオペレーターが応答を入力したときではありません。コンソールへのメッセージ出力がスケジュールされたら完了してプログラムに戻ってきます。この時返答領域にオペレーターからの応答が入力されているかはわかりません。WTORマクロで指定したECBでWAITマクロを発行して応答入力を待ち受けなければなりません。オペレーターが応答すればWAITマクロが完了します。
バッチ処理のプログラムではあまり必要ありませんが、WTORマクロの後ですぐにWAITを出さず、オペレーターが入力するまでの間も止まることなく別の処理を行うこともできます。またWTORもマクロ完了時にGR1にメッセージ識別番号が返ります。必要なら応答を待たずにメッセージを取り消すことも可能です。
最初の例は古典的なWTORマクロのコーディングです。MSPとVOS3もこの書き方になります。2番目はMVS(z/OS)で利用可能なメッセージ・テキストをマクロの外に記述する方法です。
オペレーター・コマンドを受け取る
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- MAINENTR CSECT , DEFINE CODE SECTION USING *,RC DEFINE BASE REGISTER STM 14,12,12(13) SAVE CALLER REGISTERS LA 12,0(,15) GR12 -> OUR 1ST BASE ADDRESS LR 15,13 SAVE CALLER SAVEAREA CNOP 0,4 INSURE FULL WORD BOUNDARY BAS 13,*+4+72 AROUND OUR SAVEAREA DC 18F'-1' OUR GPR SAVEAREA ST 15,4(,13) SAVE CALLER SAVEAREA POINTER ST 13,8(,15) SET BACK CHAIN FOR LINK TRACE *---------------------------------------------------------------------* 初期設定の処理 USING DCOM,2 ADDRESS TO COMM AREA(IEZCOM) USING DCIB,3 ADDRESS TO CIB EXTRACT ACOMLIST,FIELDS=COMM ISSUE EXTRACT COMM L R2,ACOMLIST LOAD COMLIST ADDRESS ICM R3,B'1111',COMCIBPT LOAD START COMMAND CIB BZ *+4+4+4+4+4 IF WE ARE NOT STC TASK LH R0,CIBDATLN LOAD COMMAND LENGTH LA R1,CIBDATA LOCATE TO COMMAND AREA STM R0,R1,LCMDPARM SAVE START COMMAND PARAMETER BAS RA,FREECIB FREE START COMMAND CIB SPACE , QEDIT ORIGIN=COMCIBPT, SET AVAILABLE COMMAND QUEUES + CIBCTR=10 DROP R2,R3 FORGET COMM-AREA AND CIB *---------------------------------------------------------------------* : : : : : : : *---------------------------------------------------------------------* オペレーターコマンドの待ち合わせと受け取りの処理 USING DCOM,2 ADDRESS TO COMM AREA(IEZCOM) USING DCIB,3 ADDRESS TO CIB CMNDWAIT DS 0H L R2,ACOMLIST LOAD COMLIST ADDRESS L R1,COMECBPT LOAD OP-COMMAND ECB ADDRESS WAIT ECB=(1) WAIT ANY OP-COMMAND CMNDNEXT DS 0H ICM R3,B'1111',COMCIBPT LOAD NEXT CIB BZ CMNDWAIT IF NOT, WAIT AGAIN CLI CIBVERB,CIBSTOP STOP COMMAND ? BE CMNDSTOP YES, PROGRAM DONE LH RF,CIBDATLN LOAD ENTERED OP-COMMAND LENGTH BAS RA,ECHOCMD ECHO ENTERED OP-COMMAND SPACE , ここに入力されたコマンドの処理を入れる。 SPACE , BAS RA,FREECIB FREE CURRENT CIB B CMNDNEXT PICKUP NEXT CIB DROP R2,R3 FORGET COMM-AREA AND CIB SPACE , *---------------------------------------------------------------------* STOPコマンドの処理 CMNDSTOP DS 0H WTO 'SAMPLE STC PROCESSOR, STOP COMMAND ACCEPTED.' SLR RF,RF SET CC=0 L RD,4(,RD) LOAD CALLER SAVEAREA L RE,12(,RD) RESTORE CALLER GPR14 LM R0,RC,20(RD) RESTORE CALLER GPR0-12 BR RE PROGRAM END SPACE , *---------------------------------------------------------------------* CIB解放の内部サブルーチン USING DCOM,2 ADDRESS TO COMM AREA(IEZCOM) FREECIB DS 0H GR2 --> COMMAREA + GR3 --> CIB QEDIT ORIGIN=COMCIBPT, FREE THIS CIB + BLOCK=(3) B 0(,RA) RETURN TO CALLER DROP R2 FORGET COMM-AREA SPACE , *---------------------------------------------------------------------* 入力されたコマンドをエコーする内部サブルーチン USING DCIB,3 ADDRESS TO CIB ECHOCMD DS 0H GR3 --> CIB + GR15 -> ENTERED COMMAND LENGTH MVC ECHOMSG(LCHOMDL),ECHOMDL INIT ECHO MESSAGE AREA CVD RF,DOUBLE EDIT ENTERED OP-COMMAND MSG UNPK ECHOMSG+4+33(2),DOUBLE I (MAX 32BYTES) OI ECHOMSG+4+34,C'0' I CH RF,=H'32' I BNH *+4+4 I LH RF,=H'32' I LH R0,ECHOMSG I SH R0,=H'32' I AR R0,RF I STH R0,ECHOMSG I LTR RF,RF I BZ *+4+4+4+4+2 I LA R0,ECHOMSG+4+36 I LA R1,32 I LA RE,CIBDATA I MVCL R0,RE I WTO MF=(E,ECHOMSG) INFORM IT B 0(,RA) RETURN TO CALLER DROP R3 FORGET CIB SPACE , *---------------------------------------------------------------------* DOUBLE DC D'0' DOUBLE WORD WORK AREA ACOMLIST DC A(0) POINTER TO COMLIST LCMDPARM DC F'0' LNG OF START CMD PARM ACMDPARM DC A(0) TXT POINTER OF START CMD PARM ECHOMDL WTO 'SAMPLE STC PROCESSOR, ENTR CMND=(XX) + ',MF=L LCHOMDL EQU *-ECHOMDL MESSAGE MODEL AND LENGTH ECHOMSG DC (LCHOMDL)X'00' MESSAGE EDIT AREA *---------------------------------------------------------------------* LTORG , USER LITERAL PLACE AT HERE *---------------------------------------------------------------------* DCOM DSECT IEZCOM , COMMUNICATION AREA DCIB DSECT IEZCIB , CIB *---------------------------------------------------------------------* : : END
アドレス空間に常駐してオペレーターが指示するまで一定の処理を行い続けるサーバー型のプログラムでは、「次に何を行うか?」と言ったことをオペレーターからのコマンドによって判定したい場合があります。このような場合にOSのMODIFYコマンドやSTOPコマンドでオペレーターの指示を受け取ることができます。このプログラムはMODIFYおよびSTOPコマンドを処理するサンプルです。WTORに比べるとロジックはやや複雑になりますが、STCタスクとして動かす常駐型のサーバープログラムでは必須となる機能です。
プログラムは起動時の初期設定として、EXTRACTマクロをサンプルのように発行してMVSのコマンドスケジューラーリスト(COMMAREA)のアドレスを得ます。STARTコマンドで起動されたSTCタスクの場合は、STARTコマンド用CIBがチェインされているのでそのアドレスを求めます。これはCOMMAREA内のCOMCIBPTフィールドにあります。バッチジョブなどSTARTコマンド以外の方法で起動された場合はチェインされていません。このアドレスを調べればSTARTコマンドで起動されたSTCタスクかそうでないかを判定できます。STC起動の場合はSTARTコマンド用CIBをBLOCK指定のQEDITマクロを発行してクリアーしておきます。(サンプルでは内部サブルーチンFREECIBで行っています)STARTコマンドでパラメーターを指定していなくてもCIBは作成されることを知っておいて下さい。
S procname,,,parameter
STARTコマンドでパラメーターを指定する場合はこのようにコマンドを入力します。例えば S MYSTC1,,,MODE=DEBUG とすれば MODE=DEBUG の文字列がSTARTコマンド用CIBで渡されます。CIBDATLNはパラメーターの長さ、CIBDATAがパラメーター文字列です。
次にMODIFYコマンド用のコマンドキューを作るため、CIBCTR指定のQEDITマクロを発行します。CIBCTRには同時に入力可能なコマンド数(最大255)を指定します。入力されたコマンドはいっぺんにプログラムに渡ってくるわけではありません。1つずつ順番に取り出し、1つずつ処理することができます。そのためCIBCTRは1でもかまいませんが、コマンド処理に時間が掛かるとオペレーターは次のコマンドを入力してもMVSにリジェクトされてしまいます。極端に多くする必要なありませんが、10個程度はあってもいいでしょう。CIBCTR=10は未処理のコマンドを10個分OS内でキューイングできることになります。ORIGINパラメーターにはCOMMAREAのCOMCIBPTフィールドを指定します。これでオペレーターコマンドを受け取る準備ができました。
EXTRACTを出した後QEDITも含めてOSのコントロールブロック(制御表)をプログラムで直接参照します。このためコントロールブロックをフィールド名でアクセスするためにコントロールブロックのマッピングマクロを使います。参照するコントロールブロックはCOMMAREAとCIBです。それぞれIEZCOMマクロとIEZCIBマクロでマッピングします。DSECT展開マクロでないためサンプルのように自分でDSECTを定義します。MSPではKDJCOMマクロとKDECIBマクロ、VOS3ではJDJCOMマクロとJDECOMIBマクロになります。このサンプルで参照しているものであればフィールド名は同じです。
プログラムはコマンドを受け取るタイミングになったら、COMMAREA内のCOMECBPTフィールドでポイントされているコマンド入力待ち合わせ用のECBを指定してWAITします。COMECBPTフィールドはECBそのものではなく、ECBアドレスが格納されたポインターフィールドです。
すでに何らかのコマンドが入力されていたり、新たなコマンドが入力された時点でWAITは解除されます。COMMAREA内のCOMCIBPTフィールドには次の処理すべきコマンドのCIBアドレスが入っています。ここが0ならすべてのCIBは処理済みなので再びWAITを発行してオペレーターコマンド入力待ちになります。CIBアドレスが入っていればそのCIBを調べることで入力されたコマンド文字列を求めることができます。CIBのCIBVERBフィールドは入力されたコマンド種類を示します。x44ならMODIFY、x40ならSTOPコマンドですが、サンプルのように必ずラベル名で参照します。CIBSTOPはSTOPコマンドを示すEQUラベルです。通常STOPコマンドはプログラムの終了を意味しますから、サンプルのように終了処理へ移ってしまってかまいません。MODIFYコマンドの場合は入力されたコマンド文字列と長さが必要なのでCIBから求めます。CIBDATLNはコマンド文字列の長さ、CIBDATAがコマンド文字列です。コマンドを入力したコンソールIDもわかります。MSPとVOS3ではCIBCONIDフィールド、z/OSではCIBX内のCIBXCNIDまたはCIBXCNNMフィールドを利用します。CIBXはCIBに連続して配置されている拡張CIBで、先頭アドレスはCIBアドレスにCIBXOFFフィールドの値を加えることで求められます。これによって特定のコンソールからのコマンド入力かどうかをチェックしたり、コマンド発行元コンソールを記録することなどもできます。
コマンド文字列が求められたら、対応するコマンド処理を行い、その後処理済みコマンドのCIBを解放します。(サンプルでは内部サブルーチンFREECIBで行っています)先にCIBを解放してもかまいませんが、その場合は入力されたコマンド文字列をプログラム側の領域に適宜コピーしておく必要があります。解放したCIB領域を後から参照してはなりません。このサンプルは入力されたコマンド文字列と長さを先頭の32バイト分コンソールにエコーしています。
コマンド処理が終わりCIBを解放したら、次のコマンドをチェックします。再びCOMCIBPTフィールドを参照して次のCIBがセットされているかを調べます。COMCIBPTはCIBを解放するためのBLOCK指定のQEDITマクロによって内容が更新されます。次のCIBがなければWAITへ回ります。このようなサイクルでオペレーターコマンドの処理を行っていきます。MODIFYコマンドで独自のコマンド処理をする場合であってもプログラムはSTCタスクである必要はありません。バッチで起動されても同じロジックで処理できます。異なる点は初期設定時にSTARTコマンド用CIBがあるかないかです。もしSTARTコマンドではパラメーターを受け取らないなら、少し乱暴ですが初期設定時にSTCかどうかを判定せずにSTARTコマンド用CIBをQEDITで無条件にクリアーしてもかまいません。バッチの場合はQEDITがエラーになるだけでABENDするようなことにはなりません。
STOPコマンド入力後もオペレーター・コマンドを受け取るには
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- CMNDSTOP DS 0H WTO 'SAMPLE STC PROCESSOR, STOP COMMAND ACCEPTED.' SPACE , L RF,STOPCTR INCREMENT NUM OF STOP ENTERED LA RF,1(,RF) I ST RF,STOPCTR V CH RF,=H'3' 3RD TIME ENTER ? BNL PROGDONE NO, CONTINUE PROCESSING SPACE , L R2,ACOMLIST LOAD COMLIST ADDRESS USING DCOM,2 ADDRESS TO COMM AREA(IEZCOM) BAS RA,FREECIB FREE STOP COMMAND CIB QEDIT ORIGIN=COMCIBPT, SET AVAILABLE COMMAND QUEUES + CIBCTR=10 B CMNDNEXT PICKUP NEXT CIB DROP R2 FORGET COMM-AREA SPACE , PROGDONE DS 0H SLR RF,RF SET CC=0 L RD,4(,RD) LOAD CALLER SAVEAREA L RE,12(,RD) RESTORE CALLER GPR14 LM R0,RC,20(RD) RESTORE CALLER GPR0-12 BR RE PROGRAM END
STOPコマンドが入るとQEDITで指定したCIBカウンターは0にされてしまいコマンドキューは無効になりMODIFYコマンドは受け付けられなくなります。(STOPコマンドだけは入力可能)
STOPコマンドが入った後も引き続きMODIFYコマンドでコマンドを受け取るためには改めてCIBCTR指定のQEDITマクロを発行する必要があります。