04.3複数行メッセージの出力
コンソールにメッセージを出すために、WTOマクロを使うことはすでに説明しました。一般には1つのメッセージが1つのWTOマクロによって出力されますが、オペレータ・コマンドの処理結果など、プログラムの処理結果を複数のメッセージで構成して出力したいこともよくあります。出したいメッセージが10行分あるなら、テキスト内容を変えてWTOマクロを10回出せば実現できます。しかしこの方法では、コンソール上の個々のメッセージの間に他のジョブのメッセージが割り込んで表示されてしまう場合もあります。これを防ぐためには1つのWTOで複数のメッセージを出すか、メッセージ毎にWTOを発行するものの、連続したメッセージ群であることをOSに示すことで、間に他のジョブのメッセージを割り込ませないようにします。
OSのディスプレイコマンドの表示結果のようなメッセージ出力を行う場合は複数行メッセージのためのWTO機能を利用します。予め出力するメッセージ行数が決まっているなら前者、処理の内容によって行数が可変になるような場合は後者の方法を使うといいでしょう。ただしコネクティングWTOと呼ばれる後者の方法ではプログラムはAPF許可されていなければなりません(VOS3の場合はさらにスーパーバイザーモードでなければなりません)。
一度に複数のメッセージをコンソールに出力する
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- WTO MF=(E,CMDRESLT) SHOW COMMAND PROCESSING RESULT : : : CMDRESLT WTO ('DATA LINE,MESSAGE-1',D), + ('DATA LINE,MESSAGE-2',D), + ('DATA LINE,MESSAGE-3',DE), + MCSFLAG=(RESP), + ROUTCDE=2,DESC=5,MF=L WTO TEXT=((MSG1,D), SHOW COMMAND PROCESSING RESULT + (MSG2,D),(MSG3,DE)), + MCSFLAG=(RESP), + ROUTCDE=2,DESC=5 : : : MSG1 DC AL2(L'MSG1TXT) MSG1TXT DC C'DATA LINE,MESSAGE-1' MSG2 DC AL2(L'MSG2TXT) MSG2TXT DC C'DATA LINE,MESSAGE-2' MSG3 DC AL2(L'MSG3TXT) MSG3TXT DC C'DATA LINE,MESSAGE-3'
最初の例は複数行WTOマクロの古典的なコーディングです。MSPとVOS3もこの書き方になります。1つのWTOで複数のメッセージをコンソールに出力できます。リスト形式のWTOマクロを組み合わせてますので、メッセージテキストはプログラムで修正することができます。長さは増やせないので、予め空白を埋めるなりして必要な最大長で定義しておきます。2番目はMVS(z/OS)で利用可能なメッセージ・テキストをマクロの外に記述する方法です。
※わかりにくいバグの例:
最初の例で、リスト形式のWTOマクロを以下のように書くとWTOは失敗することがあります。
CMDRESLT DS 0H WTO ('DATA LINE,MESSAGE-1',D), + : :
実行形式のWTOマクロではラベル名CMDRESLTを指定しますが、CMDRESLTはDS 0Hによってハーフワード境界に調整されます。しかし続くMF=L指定のWTOマクロの展開内でパラメーターリストの先頭がフルワード境界に調整されるため、ラベル名の位置と実際のWTOパラメーターが場合によっては2バイトずれてしまいます。ずれた場合は正しいパラメーターリストを指さなくなるので、実行形式のWTOマクロは失敗します。マクロそのものの使い方は誤っていないため、デバッグしてもなかなか原因が掴めません。実際の復帰コードは4となりますが、マニュアルでは行数が0あるいはメッセージ長が0などと説明されており、実際のコーディングと合わないため、「なんで??」となってしまいます。
一般に機械命令はDS 0Hで境界調整するのでついこのようなラベルをコーディングしがちですが、マクロ命令の多く(特にリスト形式)はフルワード境界に調整されますから、知っておくといいでしょう。わかってしまえばつまらない原因のバグですが、わかりにくい例でもあります。
複数のメッセージを連結してコンソールに出力する(OS/390,z/OS)
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- L R0,CIBXCNID LOAD CONSOLE ID ST R0,CMDCONID SAVE IT : コマンドが入力されたコンソールIDは : CIBXから得ることができる。 : SLR R0,R0 CLEAR GR0 WTO TEXT=((TITLE,)), SHOW TITLE(CONTROL LINE) + CONSID=CMDCONID, + MF=(E,WTOPARMC) ST R1,WTOTOKEN SAVE CONNECTING WTO TOKEN SLR R0,R0 CLEAR GR0 WTO TEXT=((MIDASHI,)), SHOW MIDASHI(LABEL LINE) + CONNECT=WTOTOKEN, + MF=(E,WTOPARML) : : LA R2,MSG1 LOAD MESSAGE TEXT FIELD SLR R0,R0 CLEAR GR0 WTO TEXT=(((2),)), SHOW COMMAND PROCESSING RESULT + CONNECT=WTOTOKEN, + MF=(E,WTOPARMD) : : 処理しながら必要なメッセージを出力していく。 (MSG1,MSG2,MSG3...) : : SLR R0,R0 CLEAR GR0 WTO CONNECT=WTOTOKEN, INDICATE END OF WTO OUTPUTTING + MF=(E,WTOPARME) : : : TITLE DC AL2(L'TITLTXT) TITLTXT DC C'CNTL LINE,TITLE' MIDASHI DC AL2(L'MIDSTXT) MIDSTXT DC C'LABEL LINE,MIDASHI' MSG1 DC AL2(L'MSG1TXT) MSG1TXT DC C'DATA LINE,MESSAGE-1' MSG2 DC AL2(L'MSG2TXT) MSG2TXT DC C'DATA LINE,MESSAGE-2' MSG3 DC AL2(L'MSG3TXT) MSG3TXT DC C'DATA LINE,MESSAGE-3' : WTOPARMC WTO TEXT=((,C)),CONSID=, WTO PLIST MODEL(TYPE=C) LEN=35 + MCSFLAG=(RESP), + DESC=(5,8,9),AREAID=Z,MF=L WTOPARML WTO TEXT=((,L)),CONNECT=, WTO PLIST MODEL(TYPE=L) LEN=71 + MF=L SPACE , WTOPARMD WTO TEXT=((,D)),CONNECT=, WTO PLIST MODEL(TYPE=D) LEN=71 + MF=L SPACE , WTOPARME WTO TEXT=((,E)),CONNECT=, WTO PLIST MODEL(TYPE=E) LEN=0 + MF=L
通常のWTO同様に1つのWTOで1つのメッセージを出力するものの、各々のメッセージはひとまとまりの複数行メッセージとして扱われる、コネクティングWTOです。AREAIDパラメーターでコンソール上の表示域を指定できます。サンプルでは一般メッセージが表示されるスクロール領域を出力するため、’Z’を指定していますが、OSのディスプレイコマンド同様に表示域(K Aコマンドで設定するAREA域)に出力する場合は’A’を指定し、DESCコードに最低でも(8,9)を指定します。表示域(AREA=A)に出力すればメッセージのスクロールはK D,Fコマンドで制御できるようになります。制御行(C)およびラベル行(L)はスクロールされないので、固定表示させたいタイトルや見出しに利用できます。なおAPF許可されていないプログラムでコネクティングWTOを使うと、2回目以降の連結されたWTOはSD23でABENDします。
サンプルのコーディングはMVS(z/OS)でのみ有効です。
複数のメッセージを連結してコンソールに出力する(MSP,VOS3)
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- SLR R0,R0 CLEAR WORKREG IC R0,CIBCONID LOAD CONSOLE ID ST R0,CMDCONID SAVE IT : コマンドが入力されたコンソールIDは : CIBから得ることができる。 : MVC WPL(LDLWTOC),MDLWTOC INIT WTO PLIST LA R1,TITLTXT LOAD MSG TEXT POINTER LH RF,TITLE LOAD MSG LENGTH BCTR RF,0 MAKE A S/370 LENGTH EX RF,MOVETXT SET MSG TEXT IN WTO PLIST LA R1,WPL+LDLWTOC-2 LOCATE AREAID FIELD MVC 0(1,R1),=CL1'Z' SET AREAID=Z SLR R0,R0 CLEAR GR0 ICM R0,B'0001',CMDCONID LOAD CONSOLE-ID INTO GR0 WTO MF=(E,WPL) SHOW TITLE(CONTROL LINE) SLL R1,8 SHIFT TO HI-ORDER 3BYTES ICM R1,B'0001',CMDCONID LOAD CONSOLE-ID FOR NEXT ST R1,WTOTOKEN SAVE CONNECTING WTO TOKEN SPACE , MVC WPL(LDLWTOL),MDLWTOL INIT WTO PLIST LA R1,MIDSTXT LOAD MSG TEXT POINTER LH RF,MIDASHI LOAD MSG LENGTH BCTR RF,0 MAKE A S/370 LENGTH EX RF,MOVETXT SET MSG TEXT IN WTO PLIST L R0,WTOTOKEN LOAD CONNECTING WTO TOKEN WTO MF=(E,WPL) SHOW MIDASHI(LABEL LINE) : : MVC WPL(LDLWTOD),MDLWTOD INIT WTO PLIST LA R1,MSG1TXT LOAD MSG TEXT POINTER LH RF,MSG1 LOAD MSG LENGTH BCTR RF,0 MAKE A S/370 LENGTH EX RF,MOVETXT SET MSG TEXT IN WTO PLIST L R0,WTOTOKEN LOAD CONNECTING WTO TOKEN WTO MF=(E,WPL) SHOW COMMAND PROCESSING RESULT : : 処理しながら必要なメッセージを出力していく。 (MSG1,MSG2,MSG3...) : : L R0,WTOTOKEN LOAD CONNECTING WTO TOKEN WTO (,E) INDICATE END OF WTO OUTPUTTING : : : MOVETXT MVC WPLTXT(0),0(R1) MOVE MESSAGE TEXT TO WPL : TITLE DC Y(L'TITLTXT) TITLTXT DC C'CNTL LINE,TITLE' MIDASHI DC Y(L'MIDSTXT) MIDSTXT DC C'LABEL LINE,MIDASHI' MSG1 DC Y(L'MSG1TXT) MSG1TXT DC C'DATA LINE,MESSAGE-1' MSG2 DC Y(L'MSG2TXT) MSG2TXT DC C'DATA LINE,MESSAGE-2' MSG3 DC Y(L'MSG3TXT) MSG3TXT DC C'DATA LINE,MESSAGE-3' : MDLWTOC WTO (' ',C), + MCSFLAG=(REG0,RESP), WTO PLIST MODEL(TYPE=C) LEN=35 + DESC=(5,8,9),AREAID=Z,MF=L LDLWTOC EQU *-MDLWTOC PLIST LENGTH SPACE , MDLWTOL WTO (' + ',L), WTO PLIST MODEL(TYPE=L) LEN=71 + MF=L LDLWTOL EQU *-MDLWTOL PLIST LENGTH SPACE , MDLWTOD WTO (' + ',D), WTO PLIST MODEL(TYPE=D) LEN=71 + MF=L LDLWTOD EQU *-MDLWTOD PLIST LENGTH : WPL DS 0F WTO PARAMETER MAP WPLTXTL DC AL2(129) TEXT LENGTH WPLMSCF DC XL2'0000' MCS FLAGS WPLTXT DC CL125' ' WTO MESSAGE WPLDSC DC XL2'0000' DESCRIPTOR CODES WPLRUTC DC XL2'0000' ROUTING CODES WPLLTYP DC XL2'0000' LINE TYPE WPLARID DC CL1'Z' AREA ID WPLTNL DC AL1(1) TOTAL NUMBER OF LINES WPLLGH EQU *-WPL
コネクティングWTOの古典的コーディング方法です。MSPおよびVOS3でも利用できます。サンプルでは省略していますが、行タイプがCであれば35文字、LまたはDであれば71文字が行あたりの最大文字数になりますので、それを超えたテキストは35ないしは71文字までしかパラメーター・リスト内にMOVEしないようなチェックを入れて、後続の制御フィールドを壊さないようにしなければなりません。
システム・プログラムの場合であれば、コネクティングWTOの方が応用範囲が広いので便利です。行数が固定された場合でも、処理内容やデータによって行数が変わる場合でも、どちらでも対応できます。なおコネクティングWTOを使う場合、出力する上限の行数を決めて、それを超えたらデータ行の出力を打ち切るべきです。例えば多くても100行しか出さないなど。ひとつのプログラムで大量のコネクティングWTOを使うと、コンソール資源を占有してしまいますし、万一WTO出力を伴うループを起こしてしまったら、コンソールバッファは、あっという間に枯渇してしまいます。要所要所にフェイルセーフとなるようなチェック処理を入れるのはシステム・プログラミングの基本でもあります。なお実際の処理結果が大量にあるような場合は、コンソール出力は途中で打ち切るが、SYSOUTなどのログリスト上には全データを出力するようなデザインをすればよいでしょう。