レガシーの深淵を歩く:PL/I STREAM I/Oと帳票制御の「作法」
メインフレームの現場に長くいると、「なぜ今さらPL/Iなのか」と問われることがある。だが、COBOLの固定長処理では表現しきれない複雑な構造体や、再帰呼び出し、そして何よりこの「言語としての懐の深さ」を一度知ると、他の言語がひどく薄っぺらく見えるものだ。
今日は、若手エンジニアがつまずきがちな、PL/IのSTREAM I/Oにおけるフォーマット制御について語ろうと思う。特に`GET/PUT EDIT`を用いた帳票出力やテキストファイルの制御は、システム移行や大規模改修の際、古いソースコードの「意図」を読み解くための最大の鍵になる。
—
予約語なき自由と、その代償
まず大前提として、PL/Iには厳密な「予約語」が存在しない。`IF`や`THEN`といったキーワードすら、変数名として使用できてしまう。これは非常に強力な柔軟性だが、同時に「可読性の破壊」という劇薬にもなる。
実務では、標準的な命名規則(例:接頭辞に型を付けるなど)をチームで徹底しなければ、メンテナンス時に地獄を見る。コンパイラは動くが、人間が読めないコード。それだけは避けてくれ。
—
STREAM I/Oの真髄:カラムとスキップの制御
バッチ処理で帳票を出力する際、あるいは外部システムから渡されるフラットファイルを読み込む際、`PUT EDIT`や`GET EDIT`のフォーマット制御項目は、まさに帳票の「設計図」そのものだ。
特に意識すべきは、以下の制御項目である。
- COLUMN(n): 指定した桁位置までスペースで埋める。
- SKIP(n): n行スキップする(改行)。
- PAGE: ページを改行し、制御を先頭へ。
これらを駆使することで、複雑なレイアウトをコード上の定義と密接にリンクさせることができる。
実践:帳票出力のコード例
以下に、実務でよく見かける「ヘッダ付き明細出力」のパターンを示す。
1
/ ———————————————————– /
/ 帳票出力サンプル:ヘッダ制御とカラム指定 /
/ ———————————————————– /
REPORT_PROC: PROCEDURE OPTIONS(MAIN);
DCL REC_DATA CHAR(80);
DCL PAGE_CNT FIXED BIN(15) INIT(0);
DCL LINE_CNT FIXED BIN(15) INIT(0);
/ 出力ファイルへのSTREAM入出力 /
OPEN FILE(PRINT_FILE) OUTPUT PAGESIZE(60);
/ ページ制御とカラム位置指定の活用 /
PUT FILE(PRINT_FILE) PAGE;
PUT FILE(PRINT_FILE) EDIT
(‘売上明細リスト’, ‘ページ:’, PAGE_CNT + 1)
(COLUMN(1), A(15), COLUMN(60), A(8), F(3));
PUT FILE(PRINT_FILE) SKIP(2); / 2行空けて明細へ /
/ 明細行の出力ループ(例) /
DO I = 1 TO 10;
PUT FILE(PRINT_FILE) EDIT
(I, ‘商品コード’, 12345)
(COLUMN(1), F(4), COLUMN(10), A(10), COLUMN(25), F(8));
PUT FILE(PRINT_FILE) SKIP(1);
END;
CLOSE FILE(PRINT_FILE);
END REPORT_PROC;
—
実務上の落とし穴:ONユニットとI/Oエラー
STREAM I/Oを扱う際、忘れてはならないのが`ON ENDFILE`や`ON ENDPAGE`といったONユニットの制御フローだ。
特に帳票出力で`PAGESIZE`を指定している場合、限界行数に達すると自動的に`ENDPAGE`条件が発生する。ここで「改ページ処理とヘッダの再出力」を記述しておかないと、帳票が悲惨なレイアウトで出力され、運用担当者から呼び出されることになる。
1
/ ページ溢れ時の自動制御 /
ON ENDPAGE(PRINT_FILE) BEGIN;
PUT FILE(PRINT_FILE) PAGE;
PAGE_CNT = PAGE_CNT + 1;
PUT FILE(PRINT_FILE) EDIT(‘ヘッダ情報再出力…’) (A);
PUT FILE(PRINT_FILE) SKIP(1);
END;
—
ベテランからのアドバイス:BUILTIN関数を愛せ
PL/Iの強力な武器の一つに、豊富な`BUILTIN`関数がある。`SUBSTR`, `TRIM`, `INDEX`はもちろんのこと、`DATETIME`や`LENGTH`を使いこなすことで、冗長なコードを劇的に削減できる。
特に、可変長文字列の処理を`EDIT`文の中で`TRIM`して`COLUMN`指定と組み合わせると、桁ズレのない美しい帳票が実現できる。逆に、これらを面倒臭がってハードコーディング(マジックナンバー)で埋め尽くすと、後任者が修正するたびにズレが発生する「バグの温床」が出来上がる。
最後に
メインフレームのコードは、先人たちが何十年もかけて磨き上げてきた知恵の結晶だ。`GET/PUT EDIT`という古くからある機能であっても、その裏には「いかに正確に、いかに美しくデータを表現するか」という執念が詰まっている。
この記事を読んでいる君が、もし今、難解なPL/Iのバッチ処理と格闘しているなら、まずは`COLUMN`や`SKIP`の定義を一つずつ紐解いてみてほしい。コードは必ず、設計者の意図を静かに語りかけてくるはずだ。
困ったことがあれば、いつでもまた聞きに来なさい。レガシーの海を渡るためのコンパスなら、いくらでも貸してやる。
