最後にポインターを使った高度な機能としてキャストという概念を紹介しておこう。
QDFRTVFD などの大規模検索を複雑に行う高度なAPI の利用方法である。
C言語を初めとするオープン系の開発言語においてもキャストを理解している人は少ない。
RPGプログラマーにキャストを紹介する人は米国雑誌でも海外サイトでもないだろうと思う。
キャストはポインターの利用で最もエレガントな手法である。
キャストとは簡単に言えばプラスティックのテンプレートをかぶせてテンプレートごしに
計測する行為に良く似ている。
対象となるものは同じでも、それにかぶせるテンプレートによって見方や解釈も異なってくる。
場合によってはテンプレートがないと解釈ができない場合もある。
人はテンプレートごしに初めて対象物を解釈する。
これがキャストである。
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
によって既に定義されているので LIKEDS
で QDFFBASE2
を再定義するとそれは
QUALIFIED
で定義されたのと同じことである。
従って
0062.00 C* 取得した長さを調べて表示する 0063.00 C EVAL LEN = QDFFBASE2.QDFFRETN
のように DS: QDFFBASE2
の値を QDFFBASE2.QDFFRETN
で取得して LEN
に入れることができる。
ここまでの過程でもう一度、振り返って欲しいのは FMTBUF
を取得したのだが
MOVE 命令を使わずに QDFFBASE2
の値が入っているという事実である。
それは、つまり FMTBUF
も QDFFBASE2
も同じポインター: FMTPTR
を基底としているからである。
言い換えれば FMTBUF
を基底とするポインターを基底として QDFFBASE2
を見た、ということになる。
これがキャストである。
C言語で書けば
QDFFBASE2 = (QDFFBASE_t*)(char*)&FMTBUF;
てな感じであろう。
このように同じポインターであってもそこを基底とする別のDSを再定義することによって
変数を簡単に扱うことができる手法のことである。
キャストは C言語でも相当な熟練者が使う手法である。
これで API: QDFRTVFD で DSPF の内部を探索することも RPG でできる、というわけである。
DSPF の内部を RPG でキャストしながら探索することができたらあなたが恐らく世界で初めての人になるだろう。
RPG でキャストまで理解できれば RPG でのポインターの概念を理解したと言えるだろう。
是非、頑張って欲しい。