コマンド

61. コマンドの複合パラメータを処理するCPP

コマンドから呼び出されるプログラムのことをCPP(=Command Procee Program)
と呼ぶがここでは複合コマンドを処理するCPPの処理の方法について
説明する。
_

[コマンド: TESTPAGE ]

ソースはこちらから

0001.00              CMD        PROMPT(' テスト・ページ ')                           
0002.00              PARM       KWD(PAGEINFO) TYPE(PAGEINFO) +                       
0003.00                           PROMPT(' 印刷の範囲 ')                             
0004.00  PAGEINFO:   ELEM       TYPE(*DEC) LEN(6 3) DFT(1) +                         
0005.00                           PROMPT(' 開始ページ ')                             
0006.00              ELEM       TYPE(*DEC) LEN(6 3) DFT(*ENDPAGE) SPCVAL((*ENDPAGE + 
0007.00                           -1)) PROMPT(' 終了ページ ')                        


 

[コンパイル]

CRTCMD OBJLIB/TESTPAGE PGM(OBJLIB/TESTPAGECL) SRCFILE(SRCLIB/QCMDSRC) AUT(*ALL)

開始ページと終了ページというふたつのパラメータがあるが
実行はPAGEINFOというひとつの複合パラメータである。
CPPが受取るのもひとつのパラメータとして受取るのでそれをどのように処理するか
後で解説する。
また「 終了ページ」というパラメータは*ENDPAGEという文字列が入力されるとそれを
-1という特殊な数値に置換えている。
これは「 終了ページ」が数字として定義されているので数値の入力しか許されないが
*ENDPAGEという意味のある文字列を表示するためである。
このテクニックも有用でありIBM提供のユーティリティ・コマンドではこの手法が
数多く使われている。

[実行画面]

                          テスト・ページ  (TESTPAGE)             
                                                                 
選択項目を入力して,実行キーを押してください。                   
                                                                 
印刷の範囲 :                                                     
  開始ページ  . . . . . . . . .   1              数値            
  終了ページ  . . . . . . . . .   *ENDPAGE       数値 , *ENDPAGE 
                                                                 

[解説]

ご覧のような画面はIBMユーティリティで数多く見たことがあるはずである。
読者の会社では開始日~終了日のような入力の場合が多いかもしれない。
_

[CLP: TESTPAGECL ]

ソースはこちらから

0001.00              PGM        PARM(+                                              
0002.00                         &PAGEINFO +                                         
0003.00                         )                                                   
0004.00 /*----------------------------------------------------------------------*/  
0005.00 /*    TESTPAGECL: テスト・ページ                                        */  
0006.00 /*                                                                      */  
0007.00 /*     作成 : 2023/06/14                                                */  
0008.00 /*----------------------------------------------------------------------*/  
0009.00              DCL        VAR(&PAGEINFO) TYPE(*CHAR) LEN(10)                  
0010.00              DCL        VAR(&STRPAGEC) TYPE(*CHAR) STG(*DEFINED) +          
0011.00                           LEN(4) DEFVAR(&PAGEINFO 3)                        
0012.00              DCL        VAR(&STRPAGEP) TYPE(*PTR)                           
0013.00              DCL        VAR(&STRPAGE) TYPE(*DEC) STG(*BASED) LEN(6 +        
0014.00                           3) BASPTR(&STRPAGEP)                              
0015.00              DCL        VAR(&ENDPAGEC) TYPE(*CHAR) STG(*DEFINED) +          
0016.00                           LEN(4) DEFVAR(&PAGEINFO 7)                        
0017.00              DCL        VAR(&ENDPAGEP) TYPE(*PTR)                           
0018.00              DCL        VAR(&ENDPAGE) TYPE(*DEC) STG(*BASED) LEN(6 +        
0019.00                           3) BASPTR(&ENDPAGEP)                              
0020.00              DCL        VAR(&MSG) TYPE(*CHAR) LEN(132)                      
0021.00              DCL        VAR(&STMMSG) TYPE(*CHAR) LEN(132)                   
0022.00              DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)                      
0023.00              DCL        VAR(&MSGF) TYPE(*CHAR) LEN(10)                      
0024.00              DCL        VAR(&MSGFLIB) TYPE(*CHAR) LEN(10)              
0025.00              DCL        VAR(&MSGKEY) TYPE(*CHAR) LEN(4)                
0026.00              DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(132)              
0027.00              DCL        VAR(&ERRDTA) TYPE(*CHAR) LEN(132)              
0028.00              DCL        VAR(&TYPE) TYPE(*CHAR) LEN(1)                  
0029.00              DCL        VAR(&TOPGMQ) TYPE(*CHAR) LEN(10)               
0030.00              DCL        VAR(&MSGTYPE) TYPE(*CHAR) LEN(10) +            
0031.00                           VALUE('*ESCAPE   ')                          
0032.00              DCL        VAR(&ERR) TYPE(*CHAR) LEN(1)                   
0033.00              DCL        VAR(&NULL4) TYPE(*CHAR) LEN(4) +               
0034.00                           VALUE(X'00000000')                           
0035.00              DCL        VAR(&APIERR) TYPE(*CHAR) LEN(116) +            
0036.00                           VALUE(X'0000007400000000') /* 2 進数  */     
0037.00              MONMSG     MSGID(CPF9999) EXEC(GOTO CMDLBL(ERROR))        
0038.00                                                                        
0039.00 /*( 環境の取得 )*/                                                     
0040.00              RTVJOBA    TYPE(&TYPE)                                    
0041.00              IF         COND(&TYPE *EQ '0') THEN(DO) /*  バッチ  */    
0042.00              CHGVAR     VAR(&TOPGMQ) VALUE('*SYSOPR   ')               
0043.00              ENDDO      /*  バッチ  */                                 
0044.00              ELSE       CMD(DO) /*  対話式  */                         
0045.00              CHGVAR     VAR(&TOPGMQ) VALUE('*TOPGMQ   ')               
0046.00              ENDDO      /*  対話式  */                                 
0047.00                                                                        
0048.00 /*( 入力パラメータの検査 )*/                                           
0049.00              CHGVAR     VAR(&STRPAGEP) VALUE(%ADDR(&STRPAGEC))         
0050.00              CHGVAR     VAR(&ENDPAGEP) VALUE(%ADDR(&ENDPAGEC))         
0051.00                                                                        
0052.00              RETURN                                                    
0053.00                                                                        
0054.00  ERROR:      RCVMSG     MSGTYPE(*LAST) RMV(*NO) KEYVAR(&MSGKEY) +      
0055.00                           MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) +  
0056.00                           SNDMSGFLIB(&MSGFLIB)                         
0057.00              IF         COND(&MSGID *EQ 'CPF9999') THEN(DO)            
0058.00              CHGVAR     VAR(&ERRDTA) VALUE(&MSGDTA)                    
0059.00              RCVMSG     MSGTYPE(*PRV) MSGKEY(&MSGKEY) RMV(*NO) +       
0060.00                           MSG(&MSG) MSGDTA(&MSGDTA) MSGID(&MSGID) +    
0061.00                           MSGF(&MSGF) MSGFLIB(&MSGFLIB)                
0062.00              CHGVAR     VAR(&STMMSG) VALUE(' プログラム ' *CAT +       
0063.00                           %SST(&ERRDTA 8 10) *TCAT +                   
0064.00                           ' のステートメント ' *CAT %SST(&ERRDTA +     
0065.00                           24 4) *CAT ' で次のエラーが発生しました。 ') 
0066.00              SNDPGMMSG  MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&STMMSG) + 
0067.00                           TOMSGQ(&TOPGMQ) MSGTYPE(*DIAG)               
0068.00              ENDDO                                                     
0069.00  SNDMSG:     IF         COND(&MSGID *EQ ' ') THEN(DO)                  
0070.00              SNDPGMMSG  MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&MSG) +    
0071.00                           TOMSGQ(&TOPGMQ) MSGTYPE(&MSGTYPE)            
0072.00              MONMSG     MSGID(CPF2400) EXEC(RETURN)          
0073.00              ENDDO                                           
0074.00              ELSE       CMD(DO)                              
0075.00              SNDPGMMSG  MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) + 
0076.00                           MSGDTA(&MSGDTA) TOMSGQ(&TOPGMQ) +  
0077.00                           MSGTYPE(&MSGTYPE)                  
0078.00              MONMSG     MSGID(CPF2400) EXEC(RETURN)          
0079.00              ENDDO                                           
0080.00              ENDPGM      


                                                       

[コンパイル]

CRTCLPGM PGM(OBJLIB/TESTPAGECL) SRCFILE(SRCLIB/QCLSRC) OPTION(*SRCDBG) AUT(*ALL)

[解説]

このCLPは先のコマンド: TESTPAGEからToolsで紹介されている「117.コマンドからCLPを生成するCRTCMDCPP」を
使って生成したものに手修正を加えたものである。
CRTCMDCPPは本当に便利なコマンドでコマンドからCLPを作成するときにいちいちコマンドのパラメータを
チェックしながらコーディングしなくてもCLPの生成が一瞬でできるのである。
しかも正確なのでぜひ利用して頂きたい。

さてここで問題の複合パラメータは

0001.00              PGM        PARM(+                                                
0002.00                         &PAGEINFO +                                           
0003.00                         ) 

のようにひとつのパラメータとしてコマンドより値を受取り

0009.00              DCL        VAR(&PAGEINFO) TYPE(*CHAR) LEN(10)

として定義されている。
コマンドのパラメータは

0004.00  PAGEINFO:   ELEM       TYPE(*DEC) LEN(6 3) DFT(1) +                         
0005.00                           PROMPT(' 開始ページ ')                             
0006.00              ELEM       TYPE(*DEC) LEN(6 3) DFT(*ENDPAGE) SPCVAL((*ENDPAGE + 
0007.00                           -1)) PROMPT(' 終了ページ ')

として数字6.3のPACK形式で定義されているのでこれは各々4バイトである。
そこでCPPに渡される形式は

項目数2バイト(INT) + 開始ページ(4バイト) + 終了ページ(4バイト) = 10バイト

の受取りが必要である。
ここでもし開始ページや終了ページが文字列であれば

開始ページ = %SST(&PAGEINFO 3 4)

と実行するだけで簡単に値を取り出すことができるのだが
数字でしかもPACK形式(=CLPの数値: *DEC はすべてPACK形式として定義される。ZONE形式を
定義することはできない)
であるので容易ではない。
まず

0010.00              DCL        VAR(&STRPAGEC) TYPE(*CHAR) STG(*DEFINED) +          
0011.00                           LEN(4) DEFVAR(&PAGEINFO 3)

として開始ページを&STRPAGECという4バイトの文字列で*DEFINEDを使って
DEFVAR(&PAGEINFO 3)として &PAGEINFOの3桁目から4バイトとして定義している。
これによって

  CHGVAR VAR(&STRPAGEC) VALUE(%SST(&PAGEINFO 3 4))

という演算は必要ない。
*DEFINED のくわしい説明と使用方法はこちらで

次に

0012.00              DCL        VAR(&STRPAGEP) TYPE(*PTR)                    
0013.00              DCL        VAR(&STRPAGE) TYPE(*DEC) STG(*BASED) LEN(6 + 
0014.00                           3) BASPTR(&STRPAGEP)                       

として数字の開始ページ&STRPAGEはポインタ:&STRPAGEP を基底とするLEN(6 3)の
数字TYPE(*DEC)として定義している。
ポインタというと何やら難しく思えるかもしれないが
IBM iでもポインタの概念は導入されておりポインタとはひとことでいうと
「フィールドの開始位置」のことである。
よくポインタの説明に「番地」とかいう人がいるがあれは完全な間違いである。
「番地」ではボインタを理解できない。
ポインタは「変数の開始位置」であり
ここでは変数: &STRPAGEはポインタ&STRPAGEPを基底として定義されているが
基底となるポインタ:&STRPAGEPはまだ値が与えられていないので
変数: &STRPAGEもまだメモリのどの部分に配置するのか決められていないことになる。

これまで多くの変数はDCLなどで定義した途端にコンバイラーによってメモリの
どの位置からXXバイトというように静的に決定されている。
ところがポインタとは変数のメモリの位置であるので
ポインタが決まらないことには変数の位置も確保できない。
ボイタンが決まって初めてその変数も位置も値も確保することができる。
つまりポインタを使うということはメモリの動的な管理である。
そこで

0049.00              CHGVAR     VAR(&STRPAGEP) VALUE(%ADDR(&STRPAGEC))

によってポインタ&STRPAGEPを %ADDR(&STRPAGEC)によって変数 &STRPAGECの
開始位置を設定すると変数 &STRPAGEの位置が決定されて値を取り出すことが
できるというわけである。

このようにポインタはCLPから学習するとわかりやすい。
_