94400d50d4
作为子目录纳入系统,与核心测试管道协同 Co-Authored-By: Claude <noreply@anthropic.com>
697 lines
25 KiB
COBOL
697 lines
25 KiB
COBOL
*> ============================================================
|
|
*> 10-divide-50 : 请求书50分割 (Invoice 50-Split)
|
|
*> Input : FILE-IN.DAT (请求书记录: 50件毎分割)
|
|
*> Output: FILE-OUT-NN (50件毎の分割出力文件: FILE-OUT-01, 02...)
|
|
*> Coverage: S-N001~N003, S-N006, S-N007, S-R001, S-R002
|
|
*> EXTENDED: Added file recovery, hash totals, boundary checks,
|
|
*> split statistics, audit trail, inventory records,
|
|
*> file status checking, error severity levels,
|
|
*> header/trailer records, file-naming validation
|
|
*> ============================================================
|
|
IDENTIFICATION DIVISION.
|
|
PROGRAM-ID. Divide50.
|
|
|
|
ENVIRONMENT DIVISION.
|
|
INPUT-OUTPUT SECTION.
|
|
FILE-CONTROL.
|
|
SELECT FILE-IN
|
|
ASSIGN TO WS-FILE-IN-NAME
|
|
ORGANIZATION IS LINE SEQUENTIAL
|
|
FILE STATUS IS WS-FILE-IN-STATUS.
|
|
|
|
SELECT FILE-OUT
|
|
ASSIGN TO WS-OUT-FILE
|
|
ORGANIZATION IS LINE SEQUENTIAL
|
|
FILE STATUS IS WS-FILE-OUT-STATUS.
|
|
|
|
SELECT FILE-AUDIT
|
|
ASSIGN TO "AUDIT-OUT.DAT"
|
|
ORGANIZATION IS LINE SEQUENTIAL
|
|
FILE STATUS IS WS-FILE-AUDIT-STATUS.
|
|
|
|
DATA DIVISION.
|
|
FILE SECTION.
|
|
FD FILE-IN.
|
|
01 FILE-IN-REC.
|
|
05 IN-RECORD PIC X(30).
|
|
|
|
FD FILE-OUT.
|
|
01 FILE-OUT-REC.
|
|
05 OUT-RECORD PIC X(30).
|
|
|
|
FD FILE-AUDIT.
|
|
01 FILE-AUDIT-REC PIC X(80).
|
|
|
|
WORKING-STORAGE SECTION.
|
|
01 WS-TELECOM-REC.
|
|
COPY "telecom/TEL-INVOICE.cpy".
|
|
01 WS-STATUS.
|
|
05 WS-EOF-FLAG PIC X VALUE 'N'.
|
|
88 WS-EOF VALUE 'Y' FALSE 'N'.
|
|
|
|
01 WS-COUNTERS.
|
|
05 WS-REC-COUNT PIC 9(5) VALUE 0.
|
|
05 WS-FILE-NUM PIC 9(2) VALUE 0.
|
|
05 WS-DIVISOR PIC 9(2) VALUE 50.
|
|
05 WS-QUOTIENT PIC 9(5).
|
|
05 WS-REMAINDER PIC 9(5).
|
|
|
|
01 WS-OUT-FILE PIC X(30).
|
|
01 WS-FILE-NUM-ED PIC 99.
|
|
|
|
01 WS-DISPLAY-COUNT PIC Z(9)9.
|
|
01 WS-INVOICE-REC.
|
|
COPY "telecom/TEL-INVOICE.cpy".
|
|
|
|
*> ===== EXPANDED: Dynamic input file name =====
|
|
01 WS-FILE-IN-NAME PIC X(30) VALUE "FILE-IN.DAT".
|
|
|
|
*> ===== EXPANDED: File status fields =====
|
|
01 WS-FILE-STATUS-VARS.
|
|
05 WS-FILE-IN-STATUS PIC X(2).
|
|
05 WS-FILE-OUT-STATUS PIC X(2).
|
|
05 WS-FILE-AUDIT-STATUS PIC X(2).
|
|
|
|
*> ===== EXPANDED: Error handling with severity levels =====
|
|
01 WS-ERROR-HANDLING.
|
|
05 WS-OPEN-RETRY-COUNT PIC 9(2) VALUE 0.
|
|
05 WS-OPEN-RETRY-MAX PIC 9(2) VALUE 3.
|
|
05 WS-ALT-SUFFIX PIC X(3) VALUE "ALT".
|
|
05 WS-ALT-OUT-FILE PIC X(30).
|
|
05 WS-SEVERITY PIC X(7).
|
|
88 WS-SEVERITY-WARNING VALUE 'WARNING'.
|
|
88 WS-SEVERITY-ERROR VALUE 'ERROR'.
|
|
88 WS-SEVERITY-FATAL VALUE 'FATAL'.
|
|
|
|
*> ===== EXPANDED: File name validation flag =====
|
|
01 WS-FILE-NAME-FLAGS.
|
|
05 WS-FILE-NAME-VALID PIC X VALUE 'Y'.
|
|
88 WS-FILE-NAME-OK VALUE 'Y' FALSE 'N'.
|
|
88 WS-FILE-NAME-BAD VALUE 'N'.
|
|
05 WS-NAME-CHAR-IDX PIC 9(2).
|
|
05 WS-NAME-CHAR-VAL PIC X(1).
|
|
|
|
*> ===== EXPANDED: Hash totals for data integrity =====
|
|
01 WS-HASH-TOTALS.
|
|
05 WS-HASH-TOTAL-IN PIC 9(12) VALUE 0.
|
|
05 WS-HASH-TOTAL-OUT PIC 9(12) VALUE 0.
|
|
05 WS-HASH-VERIFIED PIC X VALUE 'N'.
|
|
88 WS-HASH-MATCH VALUE 'Y' FALSE 'N'.
|
|
|
|
*> ===== EXPANDED: Split statistics per output file =====
|
|
01 WS-SPLIT-STATS.
|
|
05 WS-SPLIT-REC-COUNT PIC 9(5) VALUE 0.
|
|
05 WS-SPLIT-HASH-TOTAL PIC 9(12) VALUE 0.
|
|
05 WS-SPLIT-REC-MIN PIC X(30).
|
|
05 WS-SPLIT-REC-MAX PIC X(30).
|
|
05 WS-SPLIT-FIRST-REC PIC X(30).
|
|
05 WS-SPLIT-LAST-REC PIC X(30).
|
|
|
|
*> ===== EXPANDED: Boundary condition flags =====
|
|
01 WS-BOUNDARY-FLAG PIC X VALUE 'N'.
|
|
88 WS-BOUNDARY-EMPTY VALUE 'E'.
|
|
88 WS-BOUNDARY-SINGLE VALUE 'S'.
|
|
88 WS-BOUNDARY-EXACT VALUE 'X'.
|
|
88 WS-BOUNDARY-TRAILING VALUE 'T'.
|
|
01 WS-TRAILER-COUNT PIC 9(5) VALUE 0.
|
|
|
|
*> ===== EXPANDED: Inventory table for output files =====
|
|
01 WS-INVENTORY-TABLE.
|
|
05 WS-INVENTORY-ENTRIES PIC 9(2) VALUE 0.
|
|
05 WS-INVENTORY-ENTRY OCCURS 99 TIMES
|
|
INDEXED BY WS-INV-IDX.
|
|
10 WS-INV-FILE-NUM PIC 9(2).
|
|
10 WS-INV-REC-COUNT PIC 9(5).
|
|
10 WS-INV-HASH-TOTAL PIC 9(12).
|
|
|
|
*> ===== EXPANDED: Timestamp for display tracing =====
|
|
01 WS-TIMESTAMP PIC X(14).
|
|
|
|
*> ===== EXPANDED: Batch control totals =====
|
|
01 WS-BATCH-CONTROLS.
|
|
05 WS-BATCH-TOTAL-RECS PIC 9(5) VALUE 0.
|
|
|
|
*> ===== EXPANDED: Display edited fields =====
|
|
01 WS-DISPLAY-EDITED.
|
|
05 WS-DISP-HASH-IN PIC Z(11)9.
|
|
05 WS-DISP-HASH-OUT PIC Z(11)9.
|
|
05 WS-DISP-SPLIT-COUNT PIC Z(9)9.
|
|
05 WS-DISP-SPLIT-HASH PIC Z(11)9.
|
|
05 WS-DISP-RETRY PIC Z9.
|
|
05 WS-DISP-TRAILER PIC Z(9)9.
|
|
05 WS-DISP-INV-RECS PIC Z(9)9.
|
|
05 WS-DISP-INV-HASH PIC Z(11)9.
|
|
|
|
*> ===== EXPANDED: Hash computation work fields =====
|
|
01 WS-HASH-WORK.
|
|
05 WS-HASH-VAL PIC 9(3).
|
|
05 WS-HASH-IDX PIC 9(2).
|
|
05 WS-HASH-ALLOC PIC 9(12).
|
|
|
|
*> ===== EXPANDED: Inventory sum work fields =====
|
|
01 WS-INVENTORY-SUM.
|
|
05 WS-INV-SUM-COUNT PIC 9(5) VALUE 0.
|
|
05 WS-INV-SUM-HASH PIC 9(12) VALUE 0.
|
|
|
|
*> ===== EXPANDED: Audit report fields =====
|
|
01 WS-AUDIT-LINE.
|
|
05 WS-AUDIT-TYPE PIC X(15).
|
|
05 WS-AUDIT-DATA PIC X(65).
|
|
|
|
*> ===== EXPANDED: File name check constants =====
|
|
01 WS-INVALID-CHARS.
|
|
05 WS-INVALID-CHAR PIC X(18) VALUE
|
|
"!@#$%^&*()+=[]{}|;':<>?,/".
|
|
|
|
PROCEDURE DIVISION.
|
|
MAIN SECTION.
|
|
MAIN-PROCEDURE.
|
|
PERFORM 1000-INIT-SECTION
|
|
PERFORM 2000-OPEN-FILES-SECTION
|
|
PERFORM 3000-PROCESS-SECTION
|
|
PERFORM 4000-REPORT-SECTION
|
|
PERFORM 5000-AUDIT-SECTION
|
|
PERFORM 9000-EXIT-SECTION
|
|
STOP RUN.
|
|
*
|
|
1000-INIT-SECTION.
|
|
*
|
|
1000-INIT-PROC.
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
|
|
DISPLAY "=== 50-DIVISION PROCESSING ==="
|
|
DISPLAY "Records per file: " WS-DIVISOR
|
|
DISPLAY "Init: " WS-TIMESTAMP
|
|
DISPLAY " "
|
|
|
|
INITIALIZE WS-FILE-STATUS-VARS WS-ERROR-HANDLING
|
|
INITIALIZE WS-HASH-TOTALS WS-SPLIT-STATS
|
|
INITIALIZE WS-BOUNDARY-FLAG WS-TRAILER-COUNT
|
|
INITIALIZE WS-INVENTORY-TABLE WS-BATCH-CONTROLS
|
|
INITIALIZE WS-INVENTORY-SUM WS-HASH-WORK
|
|
|
|
MOVE "FILE-IN.DAT" TO WS-FILE-IN-NAME
|
|
.
|
|
*
|
|
2000-OPEN-FILES-SECTION.
|
|
*
|
|
2000-OPEN-FILES-PROC.
|
|
*> Open input file with status check
|
|
OPEN INPUT FILE-IN
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
|
|
IF WS-FILE-IN-STATUS = "00"
|
|
DISPLAY "[" WS-TIMESTAMP "] OPEN: FILE-IN.DAT OK"
|
|
ELSE
|
|
MOVE 'ERROR' TO WS-SEVERITY
|
|
DISPLAY "[" WS-TIMESTAMP "] ERROR: FILE-IN open "
|
|
"failed status=" WS-FILE-IN-STATUS
|
|
MOVE "FILE-IN.ALT" TO WS-FILE-IN-NAME
|
|
ADD 1 TO WS-OPEN-RETRY-COUNT
|
|
OPEN INPUT FILE-IN
|
|
IF WS-FILE-IN-STATUS = "00"
|
|
DISPLAY "[" WS-TIMESTAMP "] OPEN: FILE-IN.ALT OK "
|
|
"(retry=" WS-OPEN-RETRY-COUNT ")"
|
|
ELSE
|
|
MOVE 'FATAL' TO WS-SEVERITY
|
|
DISPLAY "[" WS-TIMESTAMP "] FATAL: Cannot open "
|
|
"FILE-IN after retry"
|
|
PERFORM 6000-ERROR-HANDLE-SECTION
|
|
END-IF
|
|
END-IF
|
|
|
|
OPEN OUTPUT FILE-AUDIT
|
|
IF WS-FILE-AUDIT-STATUS = "00"
|
|
DISPLAY "[" WS-TIMESTAMP "] OPEN: AUDIT-OUT.DAT OK"
|
|
ELSE
|
|
DISPLAY "[" WS-TIMESTAMP "] WARNING: AUDIT open "
|
|
"failed status=" WS-FILE-AUDIT-STATUS
|
|
END-IF
|
|
|
|
MOVE "AUDIT-START" TO WS-AUDIT-TYPE
|
|
STRING "Session started " WS-TIMESTAMP
|
|
" divisor=" WS-DIVISOR
|
|
" input=" WS-FILE-IN-NAME
|
|
INTO WS-AUDIT-DATA
|
|
END-STRING
|
|
MOVE WS-AUDIT-LINE TO FILE-AUDIT-REC
|
|
WRITE FILE-AUDIT-REC
|
|
.
|
|
*
|
|
3000-PROCESS-SECTION.
|
|
*
|
|
3000-PROCESS-PROC.
|
|
MOVE "AUDIT-PROCESS" TO WS-AUDIT-TYPE
|
|
STRING "Processing started, input="
|
|
WS-FILE-IN-NAME
|
|
INTO WS-AUDIT-DATA
|
|
END-STRING
|
|
MOVE WS-AUDIT-LINE TO FILE-AUDIT-REC
|
|
WRITE FILE-AUDIT-REC
|
|
|
|
PERFORM VARYING WS-REC-COUNT FROM 1 BY 1
|
|
UNTIL WS-EOF
|
|
PERFORM 3100-READ-INPUT-SECTION
|
|
IF NOT WS-EOF
|
|
PERFORM 3200-VALIDATE-SECTION
|
|
PERFORM 3300-APPLY-RULES-SECTION
|
|
PERFORM 3400-WRITE-OUTPUT-SECTION
|
|
END-IF
|
|
END-PERFORM
|
|
|
|
*> Close and finalize the last output file
|
|
IF WS-FILE-NUM > 0
|
|
PERFORM 3500-FINALIZE-FILE-SECTION
|
|
CLOSE FILE-OUT
|
|
IF WS-FILE-OUT-STATUS NOT = "00"
|
|
DISPLAY "WARNING: FILE-OUT close status="
|
|
WS-FILE-OUT-STATUS
|
|
END-IF
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
DISPLAY "[" WS-TIMESTAMP "] Closed final file: "
|
|
WS-OUT-FILE
|
|
END-IF
|
|
.
|
|
*
|
|
3100-READ-INPUT-SECTION.
|
|
*
|
|
3100-READ-INPUT-PROC.
|
|
READ FILE-IN INTO FILE-IN-REC
|
|
AT END SET WS-EOF TO TRUE
|
|
NOT AT END
|
|
ADD 1 TO WS-BATCH-TOTAL-RECS
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
DISPLAY "[" WS-TIMESTAMP "] Read record "
|
|
WS-REC-COUNT
|
|
END-READ
|
|
|
|
IF WS-FILE-IN-STATUS NOT = "00"
|
|
AND WS-FILE-IN-STATUS NOT = "10"
|
|
MOVE 'ERROR' TO WS-SEVERITY
|
|
DISPLAY "ERROR: FILE-IN read failed, status="
|
|
WS-FILE-IN-STATUS " at record "
|
|
WS-REC-COUNT
|
|
PERFORM 6000-ERROR-HANDLE-SECTION
|
|
END-IF
|
|
.
|
|
*
|
|
3200-VALIDATE-SECTION.
|
|
*
|
|
3200-VALIDATE-PROC.
|
|
*> Check for empty record
|
|
IF IN-RECORD = SPACES
|
|
MOVE 'WARNING' TO WS-SEVERITY
|
|
DISPLAY "WARNING: Record " WS-REC-COUNT
|
|
" is empty"
|
|
PERFORM 6000-ERROR-HANDLE-SECTION
|
|
END-IF
|
|
|
|
*> Compute input hash total contribution
|
|
PERFORM VARYING WS-HASH-IDX FROM 1 BY 1
|
|
UNTIL WS-HASH-IDX > 30
|
|
COMPUTE WS-HASH-VAL = FUNCTION ORD(
|
|
IN-RECORD(WS-HASH-IDX:1))
|
|
ADD WS-HASH-VAL TO WS-HASH-TOTAL-IN
|
|
END-PERFORM
|
|
.
|
|
*
|
|
3300-APPLY-RULES-SECTION.
|
|
*
|
|
*> === ORIGINAL DIVIDE LOGIC — preserved intact ===
|
|
3300-APPLY-RULES-PROC.
|
|
DIVIDE WS-REC-COUNT BY WS-DIVISOR
|
|
GIVING WS-QUOTIENT REMAINDER WS-REMAINDER
|
|
|
|
IF WS-REMAINDER = 1
|
|
IF WS-FILE-NUM > 0
|
|
PERFORM 3500-FINALIZE-FILE-SECTION
|
|
CLOSE FILE-OUT
|
|
IF WS-FILE-OUT-STATUS NOT = "00"
|
|
DISPLAY "WARNING: Close status="
|
|
WS-FILE-OUT-STATUS
|
|
END-IF
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
DISPLAY "[" WS-TIMESTAMP "] Closed: "
|
|
WS-OUT-FILE
|
|
END-IF
|
|
ADD 1 TO WS-FILE-NUM
|
|
MOVE WS-FILE-NUM TO WS-FILE-NUM-ED
|
|
STRING "FILE-OUT-" DELIMITED BY SIZE
|
|
WS-FILE-NUM-ED DELIMITED BY SIZE
|
|
".DAT" DELIMITED BY SIZE
|
|
INTO WS-OUT-FILE
|
|
PERFORM 3310-VALIDATE-FILE-NAME
|
|
PERFORM 3320-OPEN-OUTPUT-WITH-RETRY
|
|
PERFORM 3330-WRITE-SPLIT-HEADER
|
|
END-IF
|
|
.
|
|
*
|
|
3310-VALIDATE-FILE-NAME.
|
|
*
|
|
3310-VALIDATE-NAME-PROC.
|
|
MOVE 'Y' TO WS-FILE-NAME-VALID
|
|
|
|
*> Check for empty name
|
|
IF WS-OUT-FILE = SPACES
|
|
MOVE 'N' TO WS-FILE-NAME-VALID
|
|
MOVE 'ERROR' TO WS-SEVERITY
|
|
DISPLAY "ERROR: Empty output file name"
|
|
PERFORM 6000-ERROR-HANDLE-SECTION
|
|
EXIT PARAGRAPH
|
|
END-IF
|
|
|
|
*> Check for invalid characters in file name
|
|
PERFORM VARYING WS-NAME-CHAR-IDX FROM 1 BY 1
|
|
UNTIL WS-NAME-CHAR-IDX > 30
|
|
OR WS-FILE-NAME-VALID = 'N'
|
|
IF WS-OUT-FILE(WS-NAME-CHAR-IDX:1) = SPACE
|
|
EXIT PERFORM
|
|
END-IF
|
|
MOVE WS-OUT-FILE(WS-NAME-CHAR-IDX:1)
|
|
TO WS-NAME-CHAR-VAL
|
|
MOVE 0 TO WS-HASH-ALLOC
|
|
INSPECT WS-INVALID-CHARS TALLYING WS-HASH-ALLOC
|
|
FOR ALL WS-NAME-CHAR-VAL
|
|
IF WS-HASH-ALLOC > 0
|
|
MOVE 'N' TO WS-FILE-NAME-VALID
|
|
MOVE 'ERROR' TO WS-SEVERITY
|
|
DISPLAY "ERROR: Invalid char in file name '"
|
|
WS-OUT-FILE "'"
|
|
PERFORM 6000-ERROR-HANDLE-SECTION
|
|
EXIT PARAGRAPH
|
|
END-IF
|
|
END-PERFORM
|
|
.
|
|
*
|
|
3320-OPEN-OUTPUT-WITH-RETRY.
|
|
*
|
|
3320-RETRY-PROC.
|
|
MOVE 0 TO WS-OPEN-RETRY-COUNT
|
|
MOVE WS-OUT-FILE TO WS-ALT-OUT-FILE
|
|
.
|
|
|
|
3320-RETRY-LOOP.
|
|
OPEN OUTPUT FILE-OUT
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
|
|
IF WS-FILE-OUT-STATUS = "00"
|
|
DISPLAY "[" WS-TIMESTAMP "] Opened: "
|
|
WS-OUT-FILE
|
|
ELSE
|
|
ADD 1 TO WS-OPEN-RETRY-COUNT
|
|
IF WS-OPEN-RETRY-COUNT <= WS-OPEN-RETRY-MAX
|
|
DISPLAY "[" WS-TIMESTAMP "] RETRY "
|
|
WS-OPEN-RETRY-COUNT ": "
|
|
WS-OUT-FILE " status="
|
|
WS-FILE-OUT-STATUS
|
|
STRING "FILE-OUT-" WS-FILE-NUM-ED
|
|
"-" WS-ALT-SUFFIX ".DAT"
|
|
DELIMITED BY SIZE
|
|
INTO WS-OUT-FILE
|
|
END-STRING
|
|
GO TO 3320-RETRY-LOOP
|
|
ELSE
|
|
MOVE 'FATAL' TO WS-SEVERITY
|
|
DISPLAY "[" WS-TIMESTAMP "] FATAL: "
|
|
"Open failed after "
|
|
WS-OPEN-RETRY-MAX " retries"
|
|
PERFORM 6000-ERROR-HANDLE-SECTION
|
|
END-IF
|
|
END-IF
|
|
.
|
|
*
|
|
3330-WRITE-SPLIT-HEADER.
|
|
*
|
|
3330-HEADER-PROC.
|
|
*> Initialize split statistics for new output file
|
|
MOVE 0 TO WS-SPLIT-REC-COUNT
|
|
MOVE 0 TO WS-SPLIT-HASH-TOTAL
|
|
MOVE SPACES TO WS-SPLIT-REC-MIN
|
|
MOVE SPACES TO WS-SPLIT-REC-MAX
|
|
MOVE SPACES TO WS-SPLIT-FIRST-REC
|
|
MOVE SPACES TO WS-SPLIT-LAST-REC
|
|
|
|
*> Write header record to output file
|
|
MOVE SPACES TO FILE-OUT-REC
|
|
STRING "HDR" WS-FILE-NUM-ED
|
|
" SPLIT START"
|
|
INTO OUT-RECORD
|
|
END-STRING
|
|
WRITE FILE-OUT-REC
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
DISPLAY "[" WS-TIMESTAMP "] Header: HDR"
|
|
WS-FILE-NUM-ED " written to "
|
|
WS-OUT-FILE
|
|
.
|
|
*
|
|
3400-WRITE-OUTPUT-SECTION.
|
|
*
|
|
*> === ORIGINAL WRITE LOGIC — preserved intact ===
|
|
3400-WRITE-OUTPUT-PROC.
|
|
MOVE IN-RECORD TO OUT-RECORD
|
|
WRITE FILE-OUT-REC
|
|
|
|
PERFORM 3410-UPDATE-SPLIT-STATS
|
|
.
|
|
*
|
|
3410-UPDATE-SPLIT-STATS.
|
|
*
|
|
3410-STATS-PROC.
|
|
ADD 1 TO WS-SPLIT-REC-COUNT
|
|
|
|
*> Accumulate hash total for this split file
|
|
PERFORM VARYING WS-HASH-IDX FROM 1 BY 1
|
|
UNTIL WS-HASH-IDX > 30
|
|
COMPUTE WS-HASH-VAL = FUNCTION ORD(
|
|
OUT-RECORD(WS-HASH-IDX:1))
|
|
ADD WS-HASH-VAL TO WS-SPLIT-HASH-TOTAL
|
|
ADD WS-HASH-VAL TO WS-HASH-TOTAL-OUT
|
|
END-PERFORM
|
|
|
|
*> Track min, max, first, last records per split
|
|
IF WS-SPLIT-REC-COUNT = 1
|
|
MOVE IN-RECORD TO WS-SPLIT-REC-MIN
|
|
MOVE IN-RECORD TO WS-SPLIT-REC-MAX
|
|
MOVE IN-RECORD TO WS-SPLIT-FIRST-REC
|
|
ELSE
|
|
IF IN-RECORD < WS-SPLIT-REC-MIN
|
|
MOVE IN-RECORD TO WS-SPLIT-REC-MIN
|
|
END-IF
|
|
IF IN-RECORD > WS-SPLIT-REC-MAX
|
|
MOVE IN-RECORD TO WS-SPLIT-REC-MAX
|
|
END-IF
|
|
END-IF
|
|
MOVE IN-RECORD TO WS-SPLIT-LAST-REC
|
|
.
|
|
*
|
|
3500-FINALIZE-FILE-SECTION.
|
|
*
|
|
*> Write trailer record and update inventory for closing file
|
|
3500-FINALIZE-PROC.
|
|
MOVE SPACES TO FILE-OUT-REC
|
|
MOVE WS-SPLIT-REC-COUNT TO WS-DISP-SPLIT-COUNT
|
|
MOVE WS-SPLIT-HASH-TOTAL TO WS-DISP-SPLIT-HASH
|
|
STRING "TRL" WS-FILE-NUM-ED
|
|
" R=" WS-DISP-SPLIT-COUNT
|
|
" H=" WS-DISP-SPLIT-HASH
|
|
INTO OUT-RECORD
|
|
END-STRING
|
|
WRITE FILE-OUT-REC
|
|
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
DISPLAY "[" WS-TIMESTAMP "] Trailer: TRL"
|
|
WS-FILE-NUM-ED " R=" WS-DISP-SPLIT-COUNT
|
|
" H=" WS-DISP-SPLIT-HASH
|
|
|
|
*> Update inventory table for this output file
|
|
ADD 1 TO WS-INVENTORY-ENTRIES
|
|
MOVE WS-FILE-NUM
|
|
TO WS-INV-FILE-NUM(WS-INVENTORY-ENTRIES)
|
|
MOVE WS-SPLIT-REC-COUNT
|
|
TO WS-INV-REC-COUNT(WS-INVENTORY-ENTRIES)
|
|
MOVE WS-SPLIT-HASH-TOTAL
|
|
TO WS-INV-HASH-TOTAL(WS-INVENTORY-ENTRIES)
|
|
|
|
*> Write inventory record to audit file
|
|
MOVE "INVENTORY" TO WS-AUDIT-TYPE
|
|
STRING "File=F" WS-FILE-NUM-ED
|
|
" Recs=" WS-DISP-SPLIT-COUNT
|
|
" Hash=" WS-DISP-SPLIT-HASH
|
|
INTO WS-AUDIT-DATA
|
|
END-STRING
|
|
MOVE WS-AUDIT-LINE TO FILE-AUDIT-REC
|
|
WRITE FILE-AUDIT-REC
|
|
.
|
|
*
|
|
4000-REPORT-SECTION.
|
|
*
|
|
4000-REPORT-PROC.
|
|
MOVE WS-REC-COUNT TO WS-DISPLAY-COUNT
|
|
DISPLAY " "
|
|
DISPLAY "=== SPLIT REPORT ==="
|
|
DISPLAY "Total records: " WS-DISPLAY-COUNT
|
|
DISPLAY "Output files: " WS-FILE-NUM
|
|
DISPLAY " "
|
|
|
|
*> Boundary condition detection
|
|
IF WS-BATCH-TOTAL-RECS = 0
|
|
SET WS-BOUNDARY-EMPTY TO TRUE
|
|
DISPLAY "BOUNDARY: Empty input file"
|
|
END-IF
|
|
IF WS-BATCH-TOTAL-RECS = 1
|
|
SET WS-BOUNDARY-SINGLE TO TRUE
|
|
DISPLAY "BOUNDARY: Single-record file"
|
|
END-IF
|
|
DIVIDE WS-BATCH-TOTAL-RECS BY WS-DIVISOR
|
|
GIVING WS-QUOTIENT REMAINDER WS-REMAINDER
|
|
IF WS-REMAINDER = 0
|
|
SET WS-BOUNDARY-EXACT TO TRUE
|
|
DISPLAY "BOUNDARY: Exact multiple of " WS-DIVISOR
|
|
ELSE
|
|
SET WS-BOUNDARY-TRAILING TO TRUE
|
|
MOVE WS-REMAINDER TO WS-TRAILER-COUNT
|
|
MOVE WS-TRAILER-COUNT TO WS-DISP-TRAILER
|
|
DISPLAY "BOUNDARY: Trailing records=" WS-DISP-TRAILER
|
|
END-IF
|
|
DISPLAY " "
|
|
|
|
*> Hash total verification
|
|
MOVE WS-HASH-TOTAL-IN TO WS-DISP-HASH-IN
|
|
MOVE WS-HASH-TOTAL-OUT TO WS-DISP-HASH-OUT
|
|
DISPLAY "Hash IN: " WS-DISP-HASH-IN
|
|
DISPLAY "Hash OUT: " WS-DISP-HASH-OUT
|
|
MOVE 0 TO WS-INV-SUM-HASH
|
|
PERFORM VARYING WS-INV-SUM-COUNT FROM 1 BY 1
|
|
UNTIL WS-INV-SUM-COUNT > WS-INVENTORY-ENTRIES
|
|
ADD WS-INV-HASH-TOTAL(WS-INV-SUM-COUNT)
|
|
TO WS-INV-SUM-HASH
|
|
END-PERFORM
|
|
MOVE WS-INV-SUM-HASH TO WS-DISP-INV-HASH
|
|
DISPLAY "Hash INV: " WS-DISP-INV-HASH
|
|
IF WS-HASH-TOTAL-IN = WS-HASH-TOTAL-OUT
|
|
AND WS-HASH-TOTAL-IN = WS-INV-SUM-HASH
|
|
MOVE 'Y' TO WS-HASH-VERIFIED
|
|
DISPLAY "HASH: VERIFIED"
|
|
ELSE
|
|
DISPLAY "HASH: MISMATCH!"
|
|
END-IF
|
|
DISPLAY " "
|
|
|
|
*> Per-file inventory summary
|
|
DISPLAY "-- Split File Inventory --"
|
|
PERFORM VARYING WS-INV-SUM-COUNT FROM 1 BY 1
|
|
UNTIL WS-INV-SUM-COUNT > WS-INVENTORY-ENTRIES
|
|
MOVE WS-INV-REC-COUNT(WS-INV-SUM-COUNT)
|
|
TO WS-DISP-INV-RECS
|
|
MOVE WS-INV-HASH-TOTAL(WS-INV-SUM-COUNT)
|
|
TO WS-DISP-INV-HASH
|
|
DISPLAY " F" WS-INV-FILE-NUM(WS-INV-SUM-COUNT)
|
|
" recs=" WS-DISP-INV-RECS
|
|
" hash=" WS-DISP-INV-HASH
|
|
END-PERFORM
|
|
.
|
|
*
|
|
5000-AUDIT-SECTION.
|
|
*
|
|
5000-AUDIT-PROC.
|
|
MOVE "AUDIT-END" TO WS-AUDIT-TYPE
|
|
STRING "Records=" WS-DISPLAY-COUNT
|
|
" Files=" WS-FILE-NUM
|
|
INTO WS-AUDIT-DATA
|
|
END-STRING
|
|
MOVE WS-AUDIT-LINE TO FILE-AUDIT-REC
|
|
WRITE FILE-AUDIT-REC
|
|
|
|
IF WS-HASH-MATCH
|
|
MOVE "HASH-VERIFIED" TO WS-AUDIT-TYPE
|
|
ELSE
|
|
MOVE "HASH-MISMATCH" TO WS-AUDIT-TYPE
|
|
END-IF
|
|
STRING "IN=" WS-DISP-HASH-IN " OUT=" WS-DISP-HASH-OUT
|
|
INTO WS-AUDIT-DATA
|
|
END-STRING
|
|
MOVE WS-AUDIT-LINE TO FILE-AUDIT-REC
|
|
WRITE FILE-AUDIT-REC
|
|
|
|
EVALUATE TRUE
|
|
WHEN WS-BOUNDARY-EMPTY
|
|
MOVE "BOUNDARY-EMPTY" TO WS-AUDIT-TYPE
|
|
WHEN WS-BOUNDARY-SINGLE
|
|
MOVE "BOUNDARY-SINGLE" TO WS-AUDIT-TYPE
|
|
WHEN WS-BOUNDARY-EXACT
|
|
MOVE "BOUNDARY-EXACT" TO WS-AUDIT-TYPE
|
|
WHEN WS-BOUNDARY-TRAILING
|
|
MOVE "BOUNDARY-TRAILING" TO WS-AUDIT-TYPE
|
|
WHEN OTHER
|
|
MOVE "BOUNDARY-NORMAL" TO WS-AUDIT-TYPE
|
|
END-EVALUATE
|
|
STRING "Records=" WS-DISPLAY-COUNT
|
|
" Divisor=" WS-DIVISOR
|
|
INTO WS-AUDIT-DATA
|
|
END-STRING
|
|
MOVE WS-AUDIT-LINE TO FILE-AUDIT-REC
|
|
WRITE FILE-AUDIT-REC
|
|
|
|
PERFORM VARYING WS-INV-SUM-COUNT FROM 1 BY 1
|
|
UNTIL WS-INV-SUM-COUNT > WS-INVENTORY-ENTRIES
|
|
MOVE WS-INV-FILE-NUM(WS-INV-SUM-COUNT)
|
|
TO WS-FILE-NUM-ED
|
|
MOVE WS-INV-REC-COUNT(WS-INV-SUM-COUNT)
|
|
TO WS-DISP-INV-RECS
|
|
MOVE WS-INV-HASH-TOTAL(WS-INV-SUM-COUNT)
|
|
TO WS-DISP-INV-HASH
|
|
STRING "FILE=FILE-OUT-" WS-FILE-NUM-ED
|
|
".DAT RECS=" WS-DISP-INV-RECS
|
|
" HASH=" WS-DISP-INV-HASH
|
|
INTO WS-AUDIT-DATA
|
|
END-STRING
|
|
MOVE "SPLIT-FILE" TO WS-AUDIT-TYPE
|
|
MOVE WS-AUDIT-LINE TO FILE-AUDIT-REC
|
|
WRITE FILE-AUDIT-REC
|
|
END-PERFORM
|
|
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
DISPLAY "[" WS-TIMESTAMP "] AUDIT: written"
|
|
.
|
|
*
|
|
6000-ERROR-HANDLE-SECTION.
|
|
*
|
|
6000-ERROR-PROC.
|
|
IF WS-SEVERITY = SPACES
|
|
MOVE 'ERROR' TO WS-SEVERITY
|
|
END-IF
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
DISPLAY "[" WS-TIMESTAMP "] " WS-SEVERITY
|
|
|
|
IF WS-SEVERITY-FATAL
|
|
DISPLAY "FATAL: Terminating at record " WS-REC-COUNT
|
|
MOVE "FATAL-ERROR" TO WS-AUDIT-TYPE
|
|
STRING "Fatal at record=" WS-REC-COUNT
|
|
INTO WS-AUDIT-DATA
|
|
END-STRING
|
|
MOVE WS-AUDIT-LINE TO FILE-AUDIT-REC
|
|
WRITE FILE-AUDIT-REC
|
|
PERFORM 9000-EXIT-SECTION
|
|
STOP RUN
|
|
END-IF
|
|
.
|
|
*
|
|
9000-EXIT-SECTION.
|
|
*
|
|
9000-EXIT-PROC.
|
|
MOVE FUNCTION CURRENT-DATE TO WS-TIMESTAMP
|
|
CLOSE FILE-IN
|
|
IF WS-FILE-IN-STATUS NOT = "00"
|
|
DISPLAY "WARNING: FILE-IN close status="
|
|
WS-FILE-IN-STATUS
|
|
END-IF
|
|
CLOSE FILE-AUDIT
|
|
IF WS-FILE-AUDIT-STATUS NOT = "00"
|
|
AND WS-FILE-AUDIT-STATUS NOT = "42"
|
|
DISPLAY "WARNING: AUDIT close status="
|
|
WS-FILE-AUDIT-STATUS
|
|
END-IF
|
|
DISPLAY "[" WS-TIMESTAMP "] Divide50 session ended"
|
|
EXIT PROGRAM.
|
|
.
|