OpenCOBOL-1.1は印刷に関しては改行または改ページ程度しかケアしてくれません。そのままでは業務では使いづらいので色々と拡張して弊社では使っています。印刷機能というとREPORT caluse でREPORT IS hogeなどで定義して使うのが一般的ですが、このあたりは各社拡張しているようです。
弊社で対応した先では、定義にCHARACTER TYPE fontname COLUMN pos 形式で書ける拡張がされていましたのでcobc/parser.y 他に手を入れて同様の構文が処理できるように拡張しています(つまり、元の汎用機機種のCOBOLソースによってはそのままコンパイルが通ります)。
02 FILLER PIC N(13) CHARACTER TYPE KM-12P
VALUE "ダンプリスト" .
02 FILLER PIC X(14) VALUE SPACE.
02 FILLER PIC N(04) CHARACTER TYPE KM-7P
VALUE "作成日" .
02 H01-YY PIC Z9.
02 FILLER PIC N(02) CHARACTER TYPE KM-7P
VALUE "年 " .
02 H01-MM PIC Z9.
02 FILLER PIC N(02) CHARACTER TYPE KM-7P
VALUE "月 " .
上記ではKM-7PまたはKM-12Pというフォント名で対応する文字列を印字するように定義されています。
また、
01 W-WORK.
02 W-SEIRNO PIC ZZZZZZZ9 COLUMN 4.
02 W-YMD PIC X(08) COLUMN 13.
02 W-KIN PIC ZZZZ,ZZZ,ZZZ,ZZ9 COLUMN 22.
上記では印字位置を COLUMNで指定しています。
さて、これらを内部的にどのように処理しているのかと言いますと、当初(2010〜2011年頃)取りかかった頃は文字フォント指定や文字位置指定をコンパイル中に「隠れFILLER」として定義を埋め込んでいたのですが、GROUP項目をMOVEするときにサイズが異なってしまうという問題にあたりました。そこで、WRITE時にCHARACTER TYPEまたはCOLUMNに対応する情報にしたがって別のバッファに値を詰め直すようにしています。これは印刷に係わる出力へのWRITE時だけ効くようにしていますので、通常のMOVE時や印刷に関連しない出力では影響を受けないようになっています。
この印刷機能は印刷用のWRITEを呼び出す前に、以下の様な関数を呼び出すことで実現しており、この関数は元の印刷定義にしたがってコンパイル時に自動生成されています。
cob_move_with_W_WORK (cob_field *from, cob_field *to, const int size)
{
unsigned char *fp = from->data;
unsigned char *tp = to->data;
unsigned int i1 = 0;
unsigned int i2 = 0;
unsigned int i3 = 0;
// name= W-SEIRNO
memcpy(tp, "\x1b[4G", 4);
tp += 4;
memcpy(tp, fp, 8);
tp += 8;
fp += 8;
// name= W-YMD
memcpy(tp, "\x1b[13G", 5);
tp += 5;
memcpy(tp, fp, 8);
tp += 8;
fp += 8;
// name= W-KIN
memcpy(tp, "\x1b[22G", 5);
tp += 5;
memcpy(tp, fp, 16);
tp += 16;
fp += 16;
// 以下略
「\x1b [ col G」のようなエスケープシーケンス(多分若い人はご存じない?)を印刷出力用の中間データに吐き出すことで「colカラム目に移動」のような指示を仮想ラインプリンタ(PDF出力用)に送り出しています。仮想ラインプリンタ側ではこのようなエスケープシーケンス以外にも、プリンタのカーソル位置を直接指定するようなバイナリコードにも対応させましたので、印刷帳票に関連するCOBOLプログラムの移植についてかなり柔軟に対応出来るようになりました。
そして、「何行出力したら改ページ」「データが続いていたら連続出力、変わったら改ページ」のような印刷帳票にありがちな処理についてロジックに手を入れること無くそのまま移植出来てしまうと言う利点があり、COBOLで帳票を利用しているプログラムの移植にお困りの方には大変有用なソリューションだと思います。