RPG

235. RPGプログラマーのためのポインター講座 (6)

最後にポインターを使った高度な機能としてキャストという概念を紹介しておこう。
QDFRTVFD などの大規模検索を複雑に行う高度なAPI の利用方法である。

C言語を初めとするオープン系の開発言語においてもキャストを理解している人は少ない。
RPGプログラマーにキャストを紹介する人は米国雑誌でも海外サイトでもないだろうと思う。
キャストはポインターの利用で最もエレガントな手法である。

キャストとは簡単に言えばプラスティックのテンプレートをかぶせてテンプレートごしに
計測する行為に良く似ている。
対象となるものは同じでも、それにかぶせるテンプレートによって見方や解釈も異なってくる。
場合によってはテンプレートがないと解釈ができない場合もある。
人はテンプレートごしに初めて対象物を解釈する。
これがキャストである。

【 例 】キャストのサンプル・ソース TESTRTVFD
0001.00 H DFTNAME(TESTRTVFD) DATEDIT(*YMD/)                                     
0002.00 F******** ファイル記述の検索 ****************************************** 
0003.00 F*                                                                      
0004.00 F*****************************************************************      
0005.00  /COPY QSYSINC/QRPGLESRC,QDFRTVFD                                       
0006.00 D PTR             S               *                                     
0007.00 D FORMAT          S              8A                                     
0008.00 D LEN             S             10I 0                                   
0009.00 D FMTSIZ          S             10I 0                                   
0010.00 D FORPTR          S               *                                     
0011.00 D FORPTR2         S               *                                     
0012.00 D FMTBUF          S             20A   VARYING DIM(32767)                
0013.00 D                                     BASED(FMTPTR)                     
0014.00 D QDFFBASE2       DS                  LIKEDS(QDFFBASE)                  
0015.00 D                                     BASED(FMTPTR)                     
0016.00                                                                         
0017.00 D DSPFFLIB        DS                                                    
0018.00 D  DSPF                   1     10A                                     
0019.00 D  DSPFLIB               11     20A                                     
0020.00                                                                         
0021.00 D APIERR          DS                                            
0022.00 D  GETBYT                 1      4B 0 INZ(116)                  
0023.00 D  AVLBYT                 5      8B 0 INZ(0)                    
0024.00 D  MSGID                  9     15                              
0025.00 D  ECP                   16     16                              
0026.00 D  MSGDTA                17    116                              
0027.00                                                                 
0028.00 C                   MOVEL(P)  'SMP106FM  '  DSPF                
0029.00 C                   MOVEL(P)  'QTROBJ    '  DSPFLIB             
0030.00 C                   EVAL      LEN = %SIZE(QDFFBASE)             
0031.00 C*----------------------------------------------------+         
0032.00 C                   CALL      'QDFRTVFD'                        
0033.00 C                   PARM                    QDFFBASE            
0034.00 C                   PARM                    LEN                 
0035.00 C                   PARM      'DSPF0100'    FORMAT              
0036.00 C                   PARM                    DSPFFLIB            
0037.00 C                   PARM                    APIERR              
0038.00 C*----------------------------------------------------+         
0039.00 C     AVLBYT        IFNE      *ZEROS                            
0040.00 C     'MSGID(1)='   CAT(P)    MSGID:0       DSP40            40 
0041.00 C     DSP40         DSPLY                   ANS               1 
0042.00 C                   GOTO      END                                      
0043.00 C                   ENDIF                                              
0044.00 C*( 必要な長さ QDFFSIZE を取得した )                                   
0045.00 C                   EVAL      FMTSIZ = QDFFSIZE                        
0046.00 C*     動的メモリ割り振り                                              
0047.00 C                   ALLOC     FMTSIZ        FMTPTR                     
0048.00 C*----------------------------------------------------+                
0049.00 C                   CALL      'QDFRTVFD'                               
0050.00 C                   PARM                    FMTBUF                     
0051.00 C                   PARM                    FMTSIZ                     
0052.00 C                   PARM      'DSPF0100'    FORMAT                     
0053.00 C                   PARM                    DSPFFLIB                   
0054.00 C                   PARM                    APIERR                     
0055.00 C*----------------------------------------------------+                
0056.00 C     AVLBYT        IFNE      *ZEROS                                   
0057.00 C     'MSGID(2)='   CAT(P)    MSGID:0       DSP40            40        
0058.00 C     DSP40         DSPLY                   ANS               1        
0059.00 C                   DEALLOC                 FMTPTR                     
0060.00 C                   GOTO      END                                      
0061.00 C                   ENDIF                                              
0062.00 C*    取得した長さを調べて表示する                                     
0063.00 C                   EVAL      LEN = QDFFBASE2.QDFFRETN                  
0064.00 C                   Z-ADD     LEN           DEC08             8 0       
0065.00 C                   MOVE      DEC08         FLD8              8         
0066.00 C                   DOW       %SUBST(FLD8:1:1) = '0'                    
0067.00 C                   EVAL      FLD8 = %SUBST(FLD8:2:7)                   
0068.00 C                   ENDDO                                               
0069.00 C     ' 長さ ='     CAT(P)    FLD8:0        DSP40            40         
0070.00 C                   CAT       ' バイト ':0  DSP40                       
0071.00 C     DSP40         DSPLY                   ANS               1         
0072.00 C*     動的メモリ解放                                                   
0073.00 C                   DEALLOC                 FMTPTR                      
0074.00 C     END           TAG                                                 
0075.00 C     '*  EOJ *'    DSPLY                   ANS               1         
0076.00 C                   SETON                                        LR     
0077.00 C                   RETURN                                              
【解説】

最初に、

0031.00 C*----------------------------------------------------+                
0032.00 C                   CALL      'QDFRTVFD'                               
0033.00 C                   PARM                    QDFFBASE                   
0034.00 C                   PARM                    LEN                        
0035.00 C                   PARM      'DSPF0100'    FORMAT                     
0036.00 C                   PARM                    DSPFFLIB                   
0037.00 C                   PARM                    APIERR                     
0038.00 C*----------------------------------------------------+ 

によって、DSPFFLIB つまり

0028.00 C                   MOVEL(P)  'SMP106FM  '  DSPF                       
0029.00 C                   MOVEL(P)  'QTROBJ    '  DSPFLIB 

による QTROBJ/SMP106FM *FILE (DSPF)QDSSBASE という構造体を取得している。

次に

0044.00 C*( 必要な長さ QDFFSIZE を取得した )                                   
0045.00 C                   EVAL      FMTSIZ = QDFFSIZE                        
0046.00 C*     動的メモリ割り振り                                              
0047.00 C                   ALLOC     FMTSIZ        FMTPTR 

によって取得した長さ QDFFSIZE に必要な同じ長さのメモリをポインター FMTPTR に割り振る。

これは C言語での

FMTPTR = (char*)malloc(FMTSIZ);

と同じ命令である。
また FMTPTR というポインターは

0012.00 D FMTBUF          S             20A   VARYING DIM(32767)                
0013.00 D                                     BASED(FMTPTR)

と定義されているように FMTPTR を基底とする初期 20バイトの可変長(ただし最大32767バイトまで拡張可能)
のフィールド FMTBUF と関連づけられて定義されているので

0046.00 C*     動的メモリ割り振り                                              
0047.00 C                   ALLOC     FMTSIZ        FMTPTR

の演算によって FMTBUF の長さは FMTSIZ バイトとなる。 そこで

0048.00 C*----------------------------------------------------+                
0049.00 C                   CALL      'QDFRTVFD'                               
0050.00 C                   PARM                    FMTBUF                     
0051.00 C                   PARM                    FMTSIZ                     
0052.00 C                   PARM      'DSPF0100'    FORMAT                     
0053.00 C                   PARM                    DSPFFLIB                   
0054.00 C                   PARM                    APIERR                     
0055.00 C*----------------------------------------------------+ 

を実行すると FMTBUF には FMTSIZ 分の長さが戻されてきている。
さて戻ってきた FMTBUF

0012.00 D FMTBUF          S             20A   VARYING DIM(32767)                
0013.00 D                                     BASED(FMTPTR)

と定義したようにポインター FMTPTR を基底とする変数であったが
FMTPTR を基底とする変数は、別にもうひとつあって、それは

0014.00 D QDFFBASE2       DS                  LIKEDS(QDFFBASE)                  
0015.00 D                                     BASED(FMTPTR) 

で定義されているように QDFFBASE に類似した DS である、QDFFBASE2 である。

ここで DS: QDFFBASE

0005.00  /COPY QSYSINC/QRPGLESRC,QDFRTVFD

によって既に定義されているので LIKEDSQDFFBASE2 を再定義するとそれは
QUALIFIED で定義されたのと同じことである。
従って

0062.00 C*    取得した長さを調べて表示する                                     
0063.00 C                   EVAL      LEN = QDFFBASE2.QDFFRETN 

のように DS: QDFFBASE2 の値を QDFFBASE2.QDFFRETN で取得して LEN に入れることができる。
ここまでの過程でもう一度、振り返って欲しいのは FMTBUF を取得したのだが
MOVE 命令を使わずに QDFFBASE2 の値が入っているという事実である。
それは、つまり FMTBUFQDFFBASE2 も同じポインター: FMTPTR を基底としているからである。
言い換えれば FMTBUF を基底とするポインターを基底として QDFFBASE2 を見た、ということになる。
これがキャストである。
C言語で書けば

QDFFBASE2 = (QDFFBASE_t*)(char*)&FMTBUF;

てな感じであろう。
このように同じポインターであってもそこを基底とする別のDSを再定義することによって
変数を簡単に扱うことができる手法のことである。
キャストは C言語でも相当な熟練者が使う手法である。
これで API: QDFRTVFD で DSPF の内部を探索することも RPG でできる、というわけである。
DSPF の内部を RPG でキャストしながら探索することができたらあなたが恐らく世界で初めての人になるだろう。

RPG でキャストまで理解できれば RPG でのポインターの概念を理解したと言えるだろう。
是非、頑張って欲しい。