C/400

52. 表示装置ファイル記述の検索 API (QDFRTVFD)

表示装置ファイル (DSPF) のオブジェクト内部を検索することのできる API : QDFRTVFD が
IBM によって提供されている。
IBM API 解説書の中でも QDFRTVFD の解説は 70ページにも及ぶ壮大な記述であり
データベース・ファイル記述API( QDBRTVFD ) と並ぶ莫大な API である。

QDFRTVFD API は弊社にとってまちがいなく最も重要な API である。
QDFRTVFD がなぜ弊社にとって重要であるかと言うと、このAPI を使えば DSPF オブジェクトの
内容をすべて調べることができるからである。
DSPF ソースは全く必要ない。 この API によってDSPFオブジェクトの表示レコード、
使用フィールド、編集、 ... などをすべて取得することができる。
仮に DSPFソースがアクセス可能であったてしてもソースの場合はユーザーによって記述の方法が
個々に個性があり、到底すべてのパターンを扱うことができないからでもある。
またオブジェクトの解析であれば、すべて同一のパターンで生成されており、
なおかつ高速にアクセスすることができる。

ところが QDFRTVFD API は扱うには非常に困難である。
IBM サイトには、わずか一本のサンプル・ソースがあるが参考程度と言えるものである。
DSPFオブジェクトは、DDSソースの通りに単純に構成されているわけではない。
ありとあらゆるケースに備えて徹底的に無駄なく圧縮されて、極めて合理的に組み立てられている
のである。
QDFRTVFD API によって DSPF の構造を調べるのには C言語に精通している開発者でも、
丹念に調べてこのAPIを理解するまでは、恐らくは数ケ月〜数年は要するであろう。
しかも単純な変数の組み立てではなく構造体のポインターによるキャストを理解していなければ
ならない。
C言語としてもかなり洗練された技術と知識が必要となってくるのである。
さすがに QDFRTVFD API に関しては米国誌を始めとして、世界中のサイトにもサンプルや
例や解説すら皆無である。それほど難易度は高い。
ここまでやってくると参考は世界中のサイトのどこにも見当たらない。

弊社では QDFRTVFD API は HTMLドライバーとして RPG# や TONAKAI/2.0 での
HTML とのインターフェースに利用している。
HTML とのインターフェースのオブジェクトとして DSPF を参照用として生成して、
HTMLドライバーが DSPF オブジェクトの内部をリアルタイムで参照しながら、
HTML への読み書きを行うのに利用している。
いわば、この HTMLドライバーが RPG# と TONAKAI/2.0 の心臓部でもある。

それほど重要な HTMLドライバーであるが、合理的に全く無駄なく構成された DSPFオブジェクトの
中身を見ていくと、最初にこれをアイデアとして設計した人間が IBM にいるはずであり、
恐らくかなりの超優秀な人間が、それもかなりの大人数でこの DSPF の構成にあたったはずであろうと
容易に想像することができる。
複雑なように見えるが実は将来の拡張にも備えた非常に緻密な計算が考慮がされるていることが伺える。
全くスゴイ人間がそれもかなりの人数で開発に当たったことを、この API が物語っている。

前置きが長くなったが、それではこの宇宙のように莫大な構造を持つAPIの使用方法の入り口を
紹介してみよう。

#include <QDFRTVFD.h>
   :
#define FORMAT_SIZE   181256 
int     format_size;         
char formatBuf[FORMAT_SIZE + 1];  /* QDFRTVFD の結果を入れる作業域 */
char DSPFFLIB[21]                 /* DSPF + DSPFLIB = DSPFの名前とライブラリー名 */
QDFFBASE_t  *qdffbase;     /* 基本ファイル・セクション */          
QDFFINFO_t  *qdffinfo;    /* ファイル見出しセクション */           
QDFWFLEI_t  *qdfwflei;    /* 使用するファイル構造 28-154 */        
QDFFDPDD_t  *qdffdpdd;     /* ファイル・レベル装置依存セクション */
QDFARFTE_t  *qdfarfte;    /* レコード様式テーブル */               
QDFFRINF_t  *qdffrinf;    /* レコード見出しセクション */           

   :
/* QDFRTVFD :  表示装置ファイル記述の検索 */                             
QDFRTVFD((char*)formatBuf, format_size, "DSPF0100",  DSPFFLIB, &errcode);
   :
/*[ 基本ファイル・セクション ]*/                                
qdffbase = (QDFFBASE_t*)(char*)formatBuf;                       
m_record_su = qdffbase->WDFFRCS;      /* レコード数を取得 */    
if(qdffbase->WDFFDPAT.WDFFSEPI != 0) m_FIL_INDARA = TRUE;       
                                                             
/*[ ファイル見出しセクション ]*/                                
qdffinfo = (QDFFINFO_t*)(formatBuf + qdffbase->WDFFINOF);       
                                                             
/* 使用するファイル構造 */                                      
qdfwflei = (QDFWFLEI_t*)((char*)qdffinfo + qdffinfo->WDFFWUOF); 
                                                             
/*[ ファイル装置依存セクション ]*/                              
qdffdpdd = (QDFFDPDD_t*)((char*)qdffinfo + qdffinfo->WDFFXDOF); 
                                                             
/*[ レコード様式テーブル ]*/                                    
qdfarfte = (QDFARFTE_t*)((char*)qdffinfo +qdffinfo->WDFFDFLO);  
   :
   :
【 解説 】

最初に QDFRTVFD を起動して DSPFオブジェクトの情報を formatBuf という作業域に
入れる。
QDFRTVFD を実際に使用するのは、この一回限りであって、後は莫大なキャストによって
formatBuf バッファーの中を旅行することになる。
例えば 基本セクション : QDFFBASE_t *qdffbase は型つきのポインターとして
定義されており、それは formatBuf の先頭から始まっているので

qdffbase = (QDFFBASE_t*)(char*)formatBuf;

のように 型キャスト することによって ポインターとしての qdffbase を取得することが
できる。
すると基本セクションのポインター qdffbase によって

m_record_su = qdffbase->WDFFRCS;      /* レコード数を取得 */

のようにして DSPF の中の総レコード数を取得することができる。
次にファイル見出しセクション(これもポインター) への formatBuf からのオフセットが
qdffbase 内の WDFFINOF として定義されているので

/*[ ファイル見出しセクション ]*/
qdffinfo = (QDFFINFO_t*)(formatBuf + qdffbase->WDFFINOF);

としてファイル見出しセクションのポインター : qdffinfo を手に入れることができる。
後はこのようにしてポインターの型キャストを繰り返して、求めるオブジェクト内を
丹念にさまようことになる。
この緻密な作業を根気よく行うには

ソース・メンバー : QSYSINC/H(QDFRTVFD)

をその都度、調べて API解説書には書かれていない構造体を調べる必要がある。
これもかなりの難易度の高い作業であり、ユーザー独自の構造体を適切に追加で定義する
必要が出てくる。

調べていくうちに必ず迷いそうなので警告しておくが、フィールドの一覧は
各表示レコード毎にこれこれ ... と単純に並べたような構造はしていない。
DSPF 全体のフィールドが一覧表となって別のテーブル構造体として独立しているのである。
つまり DSPF 上に同じ名前で同じ属性のフィールドが定義されていたとしても
オブジェクト内では唯一であり、重複は一切ない。
それでいて同じフィールド名が異なる表示レコード上に存在しえるのである。
また、元の編集コードや編集語は DSPFオブジェクトには原形は全くない。
編集API によって編集マスクに置き換えられて編集の速度が速くなるように考慮されている。
また「... 依存構造」という名前が良く出てくるが、これは共通属性の構造のあとに続く、
個別の属性のことを意味している。

このようにわずかな無駄も許さないように徹底的に、無駄が排除されて定義されているのである。
後は丹念に API 解説書を見ながら進めていくしかない。
しかし上記のように型キャストを繰り返すだけであるので新しい変数をその都度、定義するような
必要はない。
ここでもポインターによる移動だけで済むように徹底した合理化が図られているのである。
このような DSPFオブジェクトの構造を作った IBM もすごいが、API で公開しているのは
さらにスゴイ話である。
ところでこのAPI を使った弊社の HTMLドライバーは、わずかソースで約 1600 ステップ数である。
この考え抜かれた構造のおかげでユーザー・プログラムもこれだけのステップ数で済んでいる。
オブジェクトを解析することによって弊社製品のパフォーマンスと品質の向上に大いに役立っている。

QDFRTVFD を設計した開発者はスゴイと今さらながらに思ってしまう。
しかし、これは IBM System i のほんの小さな一部に過ぎないのだ。