Add JavaSrc: cobol-tna-system COBOL->Java conversion (ZAN01-06/KIN01-09/KYU01-09 + 变换规则 doc)

This commit is contained in:
opencode
2026-08-29 20:50:08 +08:00
parent c9ea370397
commit f99f6696a6
71 changed files with 15350 additions and 0 deletions
+413
View File
@@ -0,0 +1,413 @@
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import dto.Kyu04Rec;
import dto.Kyu05Rec;
import dto.Kyu99Rec;
import dto.ZandatacPar;
import dto.ZanendacPar;
import dto.ZanmsgacPar;
import util.ConvUtil;
/**
* ============================================================
* 【COBOL→Java】KYU08PRI 給与明細印刷処理
* ============================================================
* PROGRAM-ID. KYU08PRI → 类 Kyu08PriMainPGMパターン:レイアウト編集のみ GETPUT)
*
* 使用ファイル(SELECT ASSIGN → パス定数):
* R01INNFIL(KYU08R01 SALARY-NET F200B 入力) → R01INN_FILECOPY KYU04REC → dto.Kyu04Rec
* W01OUTFIL(KYU08W01 PAYSLIP F200B 出力) → W01OUT_FILECOPY KYU05REC → dto.Kyu05Rec
* W02OUTFIL(KYU08W02 ERROR-LOG VB200B 出力)→ W02OUT_FILECOPY KYU99REC → dto.Kyu99Rec、将来拡張・現状出力なし)
*
* 使用SUBCALL → 类#execute):
* SUB01DAT→Sub01DatSub / SUB02MSG→Sub02MsgSub / SUB03END→Sub03EndSub
*
* 段落対応:
* 0000MAJCOLSOR→run() 1000ITTSOR→initPara() 1100R01INNSOR→readR01Para()
* 2000MAJSOR→majPara() 3000STPSOR→termPara() 4000MSGOUTSOR→msgOutPara()
* 9999ABDSOR→abendPara()
*
* 処理要点(詳細設計書_KYU08PRI 準拠):
* - 1社員1ページ。ヘッダ行→明細行→フッタ行を 200B 固定長で順次出力(LINAGE 66行/ページ相当)。
* - ヘッダ行:HL-TITLE('========== 給与明細書 ==========') ページ番号(Z(03)9) 'PG'。
* - 明細行:DETAIL-LINE は KYU05REC 布局と一致(PAGE-TITLE=SPACE)するため Kyu05Rec で編集。
* EMP-NAME は X(020) JUSTIFIED RIGHT、BASIC/NET は Z(008)9 BLANK WHEN ZERO で編集。
* - フッタ行:FL-MSG('--- 明細終了 ---')。
* - COBOL は LINAGE/ADVANCING PAGE を用いるが、Java 平文テキスト出力では 200B 行の連続書出とし
* ページ制御(フォームフィード等)は行わない(設計上 1社員1ページのため実害なし)。
* - W02(ERROR-LOG) は OPEN OUTPUT のみ(現状 WRITE なし/将来拡張)。
*/
public class Kyu08PriMain {
// ==================== コンスタント領域 CNSARA ====================
/** 03 CNS-PRGIDX PIC X(008) VALUE 'KYU08PRI'. */
private static final String CST_PRGIDX = "KYU08PRI";
/** 03 CNS-MSGSTR PIC 9(003) VALUE 001. 開始メッセージ */
private static final int CST_MSGSTR = 1;
/** 03 CNS-MSGFIN PIC 9(003) VALUE 002. 終了メッセージ */
private static final int CST_MSGFIN = 2;
/** 03 CNS-MSGSUBEEK PIC 9(003) VALUE 005. サブエラーメッセージ */
private static final int CST_MSGSUBEEK = 5;
/** 03 CNS-MSGIINKES PIC 9(003) VALUE 006. 入力件数メッセージ */
private static final int CST_MSGIINKES = 6;
/** 03 CNS-MSGOUTKES PIC 9(003) VALUE 007. 出力件数メッセージ */
private static final int CST_MSGOUTKES = 7;
/** 03 CNS-MSGKEYINF PIC 9(003) VALUE 033. コンパイル日時メッセージ */
private static final int CST_MSGKEYINF = 33;
/** 03 CNS-KN0002 PIC 9(001) VALUE 2. */
private static final int CST_KN0002 = 2;
/** 03 CNS-ABD999 PIC 9(003) VALUE 999. */
private static final int CST_ABD999 = 999;
/** 03 CNS-HEADER-LINES PIC 9(002) VALUE 6. LINAGE TOP 相当・参照用) */
private static final int CST_HEADER_LINES = 6;
/** 03 CNS-DETAIL-LINES PIC 9(002) VALUE 54. LINAGE 明細相当・参照用) */
private static final int CST_DETAIL_LINES = 54;
/** 03 CNS-FOOTER-LINES PIC 9(002) VALUE 6. LINAGE BOTTOM 相当・参照用) */
private static final int CST_FOOTER_LINES = 6;
// ==================== ファイル定義(SELECT ASSIGN 相当) ====================
/** SELECT R01INNFIL ASSIGN TO KYU08R01.SALARY-NET 入力 F200B */
private static final String R01INN_FILE = "data/KYU08R01.txt";
/** SELECT W01OUTFIL ASSIGN TO KYU08W01.PAYSLIP 出力 F200B */
private static final String W01OUT_FILE = "data/KYU08W01.txt";
/** SELECT W02OUTFIL ASSIGN TO KYU08W02.ERROR-LOG 出力 VB200B・現状出力なし) */
private static final String W02OUT_FILE = "data/KYU08W02.txt";
// ==================== カウンタ領域 CUNARACOMP-3 → long ====================
/** 03 CUN-R01INN PIC S9(009) COMP-3 VALUE ZERO. */
private long cunR01Inn;
/** 03 CUN-W01OUT PIC S9(009) COMP-3 VALUE ZERO. */
private long cunW01Out;
/** 03 CUN-W02OUT PIC S9(009) COMP-3 VALUE ZERO. */
private long cunW02Out;
// ==================== 作業領域 WRKARA ====================
/** 03 WRK-EOF PIC X(001). 読込フラグ(88 WRK-EOF-Y VALUE '1' */
private String wrkEof = "0";
/** 03 WRK-LINE-NO PIC 9(002). */
private int wrkLineNo;
/** 03 WRK-PAGE-COUNTER PIC 9(004) VALUE 0. */
private int wrkPageCounter = 0;
/** 03 WS-PAD-CHAR PIC X(001) VALUE SPACE. */
private String wsPadChar = " ";
/** 03 WS-FILE-STATUS PIC X(002). */
private String wsFileStatus = "";
/** 03 WS-DISP-PG PIC Z(03)9. HL-PAGE-NO 編集用・参照用) */
private int wsDispPg;
/** 88 WRK-EOF-Y VALUE '1'. */
private boolean isEof() {
return "1".equals(wrkEof);
}
// ==================== サブプログラム連絡領域(LINKAGE COPY → DTO ====================
/** COPY ZANMSGAC.SUB02MSG用) */
private final ZanmsgacPar m00MhoPar = new ZanmsgacPar();
/** COPY ZANENDAC.SUB03END用) */
private final ZanendacPar e01AbdPar = new ZanendacPar();
/** COPY ZANDATAC.SUB01DAT用) */
private final ZandatacPar d01UbsPar = new ZandatacPar();
// ==================== 入出力レコード(FILE SECTION → DTO ====================
/** 01 R01INNREC.FD R01INNFIL / COPY KYU04REC */
private final Kyu04Rec r01 = new Kyu04Rec();
/** 01 W01OUTREC.FD W01OUTFIL / COPY KYU05REC */
private final Kyu05Rec w01 = new Kyu05Rec();
/** 01 W02OUTREC.FD W02OUTFIL / COPY KYU99REC */
private final Kyu99Rec w02 = new Kyu99Rec();
// ==================== ファイルハンドル(OPEN/CLOSE 相当) ====================
private BufferedReader r01InnFil;
private PrintWriter w01OutFil;
private PrintWriter w02OutFil;
// ==================== PROCEDURE DIVISION ====================
public static void main(final String[] args) {
new Kyu08PriMain().run();
}
/**
* 段落 0000MAJCOLSOR:制御処理。
* PERFORM 1000ITTSOR → PERFORM 2000MAJSOR UNTIL WRK-EOF-Y → PERFORM 3000STPSOR → GOBACK.
*/
private void run() {
try {
initPara();
while (!isEof()) { // PERFORM 2000MAJSOR UNTIL WRK-EOF = '1'
majPara();
}
termPara();
} finally {
closeFiles();
}
}
/**
* 段落 1000ITTSOR:初期処理。
* 開始メッセージ→コンパイル日時→ワーク初期化→SUB01DAT→OPEN→初回読込。
*/
private void initPara() {
// *** 開始メッセージ出力
// MOVE CNS-MSGSTR TO M00MSGCOD.PERFORM 4000MSGOUTSOR.
msgOutPara(CST_MSGSTR, null, null);
// *** コンパイル日時出力 ※FUNCTION WHEN-COMPILED→起動時刻で代用
// MOVE CNS-MSGKEYINF TO M00MSGCOD.
// MOVE FUNCTION WHEN-COMPILED TO M00UMKDATS22-01.
// MOVE 'COMPILED' TO M00UMKDATS22-02.
final String compiled = java.time.LocalDateTime.now()
.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
msgOutPara(CST_MSGKEYINF, compiled, "COMPILED");
// *** ワークエリア初期化 INITIALIZE WRKARA.
wrkEof = "0";
wrkLineNo = 0;
wrkPageCounter = 0;
wsPadChar = " ";
wsFileStatus = "";
wsDispPg = 0;
// *** 運用日付取得 SUB01DAT
// INITIALIZE D01UBSPAR.CALL 'SUB01DAT' USING D01UBSPAR.
d01UbsPar.reset();
Sub01DatSub.execute(d01UbsPar);
if (d01UbsPar.getD01FkiCod() != 0) {
// IF D01FKICOD NOT = ZERO
// MOVE CNS-MSGSUBEEK TO M00MSGCOD
// MOVE 'SUB01DAT' TO M00UMKDATS22-01
// MOVE D01FKICOD TO M00UMKDATS22-02
// PERFORM 4000MSGOUTSOR
// PERFORM 9999ABDSOR
msgOutPara(CST_MSGSUBEEK, "SUB01DAT",
ConvUtil.padLeftZero(d01UbsPar.getD01FkiCod(), 4));
abendPara();
return;
}
// *** 使用ファイルのオープン
// OPEN INPUT R01INNFIL.OPEN OUTPUT W01OUTFIL W02OUTFIL.
openFiles();
// *** R01 初回読込(1100R01INNSOR
readR01Para();
}
/**
* 段落 1100R01INNSORR01読込処理。
* READ R01INNFIL AT END SET WRK-EOF-Y / NOT AT END ADD 1 TO CUN-R01INN.
*/
private void readR01Para() {
try {
final String line = r01InnFil.readLine();
if (line == null) {
// AT END: SET WRK-EOF-Y TO TRUE.
wrkEof = "1";
} else {
// NOT AT END: 固定長解析 → R01INNREC、ADD 1 TO CUN-R01INN.
r01.parseRecord(line);
cunR01Inn++;
}
} catch (IOException e) {
throw new UncheckedIOException(e); // READ異常 ≈ ABEND
}
}
/**
* 段落 2000MAJSOR:主処理。
* ヘッダ出力(改ページ+ページ番号)→明細行編集・出力→フッタ出力(改ページ)→次レコード読込。
*/
private void majPara() {
// *** ページカウンタ加算
// ADD 1 TO WRK-PAGE-COUNTER.
wrkPageCounter++;
// MOVE WRK-PAGE-COUNTER TO HL-PAGE-NO.MOVE WRK-PAGE-COUNTER TO WS-DISP-PG.
wsDispPg = wrkPageCounter;
// *** ヘッダ出力(BEFORE ADVANCING PAGE
// WRITE W01OUTREC FROM HEADER-LINE BEFORE ADVANCING PAGE.
w01OutFil.println(buildHeaderLine(wrkPageCounter));
// *** 明細行編集(DETAIL-LINE ≡ KYU05REC 布局:PAGE-TITLE=SPACE
// MOVE R01EMP-ID TO DL-EMP-ID.
// MOVE R01EMP-NAME TO DL-EMP-NAME.
// MOVE R01GROSS-PAYMENT TO DL-BASIC-SALARY.
// MOVE R01NET-PAYMENT TO DL-NET-PAYMENT.
w01.reset();
w01.setW01EmpId(r01.getR01EmpId());
w01.setW01EmpName(r01.getR01EmpName());
w01.setW01BasicSalary((int) r01.getR01GrossPayment());
w01.setW01NetPayment((int) r01.getR01NetPayment());
w01.setW01PageTitle(""); // 明細行の PAGE-TITLE は SPACE
// WRITE W01OUTREC FROM DETAIL-LINE BEFORE ADVANCING 1 LINE
// AT END-OF-PAGE WRITE W01OUTREC FROM FOOTER-LINE BEFORE ADVANCING PAGE.
// 1社員1ページのため AT END-OF-PAGE は発動しない)
w01OutFil.println(w01.toRecordLine());
// ADD 1 TO CUN-W01OUT.
cunW01Out++;
// *** フッタ出力(BEFORE ADVANCING PAGE
// WRITE W01OUTREC FROM FOOTER-LINE BEFORE ADVANCING PAGE.
w01OutFil.println(buildFooterLine());
// *** 次レコード読込(1100R01INNSOR
readR01Para();
}
/**
* 段落 3000STPSOR:終了処理。
* CLOSE→入出力件数メッセージ×3→終了メッセージ。
*/
private void termPara() {
// *** 入出力ファイルのクローズ
// CLOSE R01INNFIL W01OUTFIL W02OUTFIL.
closeFiles();
// *** 入出力件数メッセージ出力
// MOVE CNS-MSGIINKES TO M00MSGCOD. MOVE 'KYU08R01' TO PARM1. MOVE CUN-R01INN TO PARM2.
msgOutPara(CST_MSGIINKES, "KYU08R01", ConvUtil.padLeftZero(cunR01Inn, 9));
// MOVE CNS-MSGOUTKES TO M00MSGCOD. MOVE 'KYU08W01' TO PARM1. MOVE CUN-W01OUT TO PARM2.
msgOutPara(CST_MSGOUTKES, "KYU08W01", ConvUtil.padLeftZero(cunW01Out, 9));
// MOVE CNS-MSGOUTKES TO M00MSGCOD. MOVE 'KYU08W02' TO PARM1. MOVE CUN-W02OUT TO PARM2.
msgOutPara(CST_MSGOUTKES, "KYU08W02", ConvUtil.padLeftZero(cunW02Out, 9));
// *** 終了メッセージ出力
// MOVE CNS-MSGFIN TO M00MSGCOD.PERFORM 4000MSGOUTSOR.
msgOutPara(CST_MSGFIN, null, null);
}
/**
* 段落 4000MSGOUTSOR:メッセージ編集出力処理。
* M00UMKDATS22-03(1:1)/-04(1:1) に '2'、-05 にプログラムIDを設定し SUB02MSG を呼ぶ。
*/
private void msgOutPara(final int msgCod, final String p1, final String p2) {
m00MhoPar.reset();
m00MhoPar.setM00MsgCod(msgCod);
if (p1 != null) {
m00MhoPar.setM00Umkdats2201(p1);
}
if (p2 != null) {
m00MhoPar.setM00Umkdats2202(p2);
}
// MOVE CNS-KN0002 TO M00UMKDATS22-03(1:1). → 先頭1桁 '2' 後続SPACE(30)
m00MhoPar.setM00Umkdats2203(ConvUtil.padRight(Integer.toString(CST_KN0002), 30));
// MOVE CNS-KN0002 TO M00UMKDATS22-04(1:1).
m00MhoPar.setM00Umkdats2204(ConvUtil.padRight(Integer.toString(CST_KN0002), 30));
// MOVE CNS-PRGIDX TO M00UMKDATS22-05.
m00MhoPar.setM00Umkdats2205(CST_PRGIDX);
Sub02MsgSub.execute(m00MhoPar);
}
/**
* 段落 9999ABDSORABEND処理。
* MOVE 999 TO E01ABDCOD.CALL 'SUB03END' USING E01ABDPAR.
*/
private void abendPara() {
e01AbdPar.reset();
e01AbdPar.setE01AbdCod(CST_ABD999);
Sub03EndSub.execute(e01AbdPar);
}
// ==================== 印刷行編集補助(HEADER-LINE / FOOTER-LINE ====================
/**
* 01 HEADER-LINE 編集(200B)。
* 05 HL-TITLE PIC X(040) VALUE '========== 給与明細書 =========='
* 05 FILLER PIC X(010) VALUE SPACES
* 05 HL-PAGE-NO PIC Z(03)9
* 05 FILLER PIC X(002) VALUE 'PG'
* 05 FILLER PIC X(144) VALUE SPACES
*/
private static String buildHeaderLine(final int pageNo) {
// PIC Z(03)9 編集(4桁、先頭3桁ゼロ抑制)
final String pageNoEd = editZ(pageNo, 3);
return ConvUtil.padRight("========== 給与明細書 ==========", 40)
+ ConvUtil.padRight("", 10)
+ pageNoEd
+ "PG"
+ ConvUtil.padRight("", 144);
}
/**
* 01 FOOTER-LINE 編集(200B)。
* 05 FL-MSG PIC X(040) VALUE '--- 明細終了 ---'
* 05 FILLER PIC X(160) VALUE SPACES
*/
private static String buildFooterLine() {
return ConvUtil.padRight("--- 明細終了 ---", 40)
+ ConvUtil.padRight("", 160);
}
/** PIC Z(n)9 BLANK WHEN ZERO 編集(編集桁数 = zCount + 1)。 */
private static String editZ(final int val, final int zCount) {
final int len = zCount + 1;
if (val == 0) {
// BLANK WHEN ZERO
return ConvUtil.padRight("", len);
}
final String s = ConvUtil.padLeftZero(val, len);
final char[] ca = s.toCharArray();
for (int i = 0; i < zCount; i++) {
if (ca[i] == '0') {
ca[i] = ' ';
} else {
break;
}
}
return new String(ca);
}
// ==================== ファイル操作補助(OPEN/CLOSE 相当) ====================
/** OPEN INPUT R01INNFIL / OUTPUT W01OUTFIL W02OUTFIL. */
private void openFiles() {
try {
r01InnFil = new BufferedReader(
new InputStreamReader(new FileInputStream(R01INN_FILE), StandardCharsets.UTF_8));
w01OutFil = new PrintWriter(
new OutputStreamWriter(new FileOutputStream(W01OUT_FILE), StandardCharsets.UTF_8));
w02OutFil = new PrintWriter(
new OutputStreamWriter(new FileOutputStream(W02OUT_FILE), StandardCharsets.UTF_8));
} catch (IOException e) {
throw new UncheckedIOException(e); // OPEN失敗 ≈ ABEND
}
}
/** CLOSE R01INNFIL W01OUTFIL W02OUTFIL. */
private void closeFiles() {
closeQuiet(r01InnFil);
closeQuiet(w01OutFil);
closeQuiet(w02OutFil);
r01InnFil = null;
w01OutFil = null;
w02OutFil = null;
}
private static void closeQuiet(final Object handle) {
try {
if (handle instanceof BufferedReader) {
((BufferedReader) handle).close();
} else if (handle instanceof PrintWriter) {
((PrintWriter) handle).close();
}
} catch (IOException e) {
// CLOSE異常は無視(原程序もFILE STATUS未管理)
}
}
}