feat: add benchmark-programs — 58 telecom COBOL test programs
作为子目录纳入系统,与核心测试管道协同 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# 15-csv-fb-nolf: CSV to Fixed-Block Conversion (No Line Feed)
|
||||
|
||||
## 电信业务场景
|
||||
|
||||
外部CDR CSV取込(无LF)。读取外部系统提供的CSV格式CDR文件,使用STRING语句将各字段合并为固定长记录。无换行展开。
|
||||
|
||||
## Description
|
||||
|
||||
Reads a LINE SEQUENTIAL CSV file (comma-separated, 3 fields) and
|
||||
converts each row to a fixed-length output record using the STRING
|
||||
statement. Handles basic CSV quoting (double-quoted fields with
|
||||
embedded commas).
|
||||
|
||||
## Record Layout
|
||||
|
||||
### Input (LINE SEQUENTIAL CSV)
|
||||
|
||||
Each line contains 3 comma-separated fields. Fields may be quoted
|
||||
with double-quotes when they contain commas or leading/trailing spaces.
|
||||
|
||||
### Output (fixed-length: 100 bytes)
|
||||
|
||||
One fixed-length record per CSV row. Fields are joined with pipe ('|')
|
||||
separators via STRING.
|
||||
|
||||
| Component | Description |
|
||||
|-----------|----------------------------|
|
||||
| FIELD1 | Padded/spaced as parsed |
|
||||
| Separator | Pipe character '|' |
|
||||
| FIELD2 | Padded/spaced as parsed |
|
||||
| Separator | Pipe character '|' |
|
||||
| FIELD3 | Padded/spaced as parsed |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|-------------------------|--------------------------------|
|
||||
| main-15-csv-fb-nolf.cbl | Main COBOL program |
|
||||
| data-gen.sh | Generate CSV test data |
|
||||
| run.sh | Compile, run, verify |
|
||||
| README.md | This file |
|
||||
|
||||
## Tests
|
||||
|
||||
| Test Case | Description |
|
||||
|-------------------------|-------------------------------------|
|
||||
| Standard CSV | Normal comma-separated values |
|
||||
| Empty middle field | Field2 is empty (,,) |
|
||||
| Quoted commas | Field contains embedded comma |
|
||||
| Quoted spaces | Quoted field with padding spaces |
|
||||
| All empty | Line with only commas |
|
||||
| Long text | Field longer than usual |
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
cd 15-csv-fb-nolf
|
||||
bash data-gen.sh
|
||||
bash run.sh
|
||||
```
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
- Each CSV line produces exactly one fixed-length (100-byte) output record.
|
||||
- Quoted fields are unquoted during parsing.
|
||||
- Embedded commas within quoted fields are preserved.
|
||||
- Output records use '|' as separator between fields.
|
||||
@@ -0,0 +1,993 @@
|
||||
*> ============================================================
|
||||
*> 15-csv-fb-nolf : 外部CDR CSV取込(无LF) (CDR Import)
|
||||
*> Input : FILE-IN (file-in.csv) Output: FILE-OUT (file-out.dat)
|
||||
*> ERROR-REPORT (csv-errors.dat) AUDIT-FILE (csv-audit.dat)
|
||||
*> Enhanced: SECTIONs, field validation, truncation detection,
|
||||
*> quote check, count reconciliation, hash totals,
|
||||
*> severity levels, FILE STATUS after every I/O.
|
||||
*> Coverage: CF-N001, CF-N003~N006, CF-A002
|
||||
*> ============================================================
|
||||
IDENTIFICATION DIVISION.
|
||||
PROGRAM-ID. CsvFbNoLf.
|
||||
|
||||
ENVIRONMENT DIVISION.
|
||||
INPUT-OUTPUT SECTION.
|
||||
FILE-CONTROL.
|
||||
SELECT FILE-IN ASSIGN TO 'file-in.csv'
|
||||
ORGANIZATION IS LINE SEQUENTIAL
|
||||
FILE STATUS IS WS-FILE-IN-STATUS.
|
||||
SELECT FILE-OUT ASSIGN TO 'file-out.dat'
|
||||
ORGANIZATION IS SEQUENTIAL
|
||||
FILE STATUS IS WS-FILE-OUT-STATUS.
|
||||
SELECT ERROR-REPORT ASSIGN TO 'csv-errors.dat'
|
||||
ORGANIZATION IS LINE SEQUENTIAL
|
||||
FILE STATUS IS WS-ERR-STATUS.
|
||||
SELECT AUDIT-FILE ASSIGN TO 'csv-audit.dat'
|
||||
ORGANIZATION IS LINE SEQUENTIAL
|
||||
FILE STATUS IS WS-AUDIT-STATUS.
|
||||
|
||||
DATA DIVISION.
|
||||
FILE SECTION.
|
||||
FD FILE-IN.
|
||||
01 IN-LINE PIC X(200).
|
||||
|
||||
FD FILE-OUT.
|
||||
01 OUT-REC PIC X(100).
|
||||
|
||||
FD ERROR-REPORT.
|
||||
01 ERR-REC PIC X(80).
|
||||
|
||||
FD AUDIT-FILE.
|
||||
01 AUD-REC PIC X(80).
|
||||
|
||||
WORKING-STORAGE SECTION.
|
||||
01 WS-TELECOM-REC.
|
||||
COPY "telecom/TEL-CDR.cpy".
|
||||
|
||||
*> File status keys for all files
|
||||
01 WS-FILE-IN-STATUS PIC X(02).
|
||||
01 WS-FILE-OUT-STATUS PIC X(02).
|
||||
01 WS-ERR-STATUS PIC X(02).
|
||||
01 WS-AUDIT-STATUS PIC X(02).
|
||||
|
||||
*> EOF flag
|
||||
01 WS-EOF PIC X(01) VALUE 'N'.
|
||||
88 WS-EOF-YES VALUE 'Y' FALSE 'N'.
|
||||
|
||||
*> Record counters (original + expanded)
|
||||
01 WS-REC-COUNT PIC 9(05) VALUE ZERO.
|
||||
01 WS-LINE-COUNT PIC 9(05) VALUE ZERO.
|
||||
01 WS-COUNTERS.
|
||||
05 WS-TOT-READ PIC 9(09) VALUE ZERO.
|
||||
05 WS-TOT-WRITTEN PIC 9(09) VALUE ZERO.
|
||||
05 WS-TOT-MALFORMED PIC 9(09) VALUE ZERO.
|
||||
05 WS-TOT-TRUNCATED PIC 9(09) VALUE ZERO.
|
||||
05 WS-TOT-QUOTE-ERR PIC 9(09) VALUE ZERO.
|
||||
05 WS-TOT-FIELD-ERR PIC 9(09) VALUE ZERO.
|
||||
05 WS-TOT-WARNINGS PIC 9(09) VALUE ZERO.
|
||||
05 WS-TOT-ERRORS PIC 9(09) VALUE ZERO.
|
||||
05 WS-TOT-CRITICAL PIC 9(09) VALUE ZERO.
|
||||
|
||||
*> CSV parsing fields (original)
|
||||
01 WS-FIELDS.
|
||||
05 WS-FIELD1 PIC X(30).
|
||||
05 WS-FIELD2 PIC X(30).
|
||||
05 WS-FIELD3 PIC X(30).
|
||||
01 WS-POS PIC 9(03).
|
||||
01 WS-CHAR PIC X(01).
|
||||
01 WS-FIELD-NUM PIC 9(01).
|
||||
01 WS-CHAR-OFFSET PIC 9(02).
|
||||
01 WS-IN-QUOTE PIC X(01) VALUE 'N'.
|
||||
88 WS-IN-QUOTE-YES VALUE 'Y' FALSE 'N'.
|
||||
01 WS-OUT-LINE PIC X(100).
|
||||
|
||||
*> Validation fields
|
||||
01 WS-QUOTE-COUNT PIC 9(03) VALUE ZERO.
|
||||
01 WS-MALFORMED-CNT PIC 9(05) VALUE ZERO.
|
||||
01 WS-TRUNC-CNT PIC 9(05) VALUE ZERO.
|
||||
01 WS-FIELD-COUNT-ERR PIC 9(05) VALUE ZERO.
|
||||
01 WS-FIELD3-LEN PIC 9(02).
|
||||
01 WS-IDX PIC 9(02).
|
||||
01 WS-CHAR-CHK PIC X(01).
|
||||
01 WS-ALL-NUMERIC PIC X(01) VALUE 'Y'.
|
||||
01 WS-RECONCILE-OK PIC X(01) VALUE 'Y'.
|
||||
01 WS-VALID-FLAG PIC X(01) VALUE 'Y'.
|
||||
88 WS-VALID-REC-YES VALUE 'Y' FALSE 'N'.
|
||||
88 WS-VALID-REC-NO VALUE 'N'.
|
||||
|
||||
*> Field-level validation status per field
|
||||
01 WS-FIELD-STATUS.
|
||||
05 WS-FIELD1-OK PIC X(01) VALUE 'Y'.
|
||||
05 WS-FIELD2-OK PIC X(01) VALUE 'Y'.
|
||||
05 WS-FIELD3-OK PIC X(01) VALUE 'Y'.
|
||||
01 WS-FIELD-ERR-MSG PIC X(60).
|
||||
01 WS-FIELD-TRUNC-FLAG PIC X(01) VALUE 'N'.
|
||||
88 WS-FIELD-TRUNC-YES VALUE 'Y' FALSE 'N'.
|
||||
|
||||
*> Input record buffer for error reporting
|
||||
01 WS-INPUT-BUF PIC X(200).
|
||||
|
||||
*> Hash totals (per field + overall)
|
||||
01 WS-HASH-TOTAL PIC 9(10) VALUE ZERO.
|
||||
01 WS-HASH-FIELD-LEN PIC 9(05) VALUE ZERO.
|
||||
01 WS-HASH-FIELD1 PIC 9(10) VALUE ZERO.
|
||||
01 WS-HASH-FIELD2 PIC 9(10) VALUE ZERO.
|
||||
01 WS-HASH-FIELD3 PIC 9(10) VALUE ZERO.
|
||||
|
||||
*> Timestamp
|
||||
01 WS-TIMESTAMP PIC X(20).
|
||||
01 WS-CUR-DATE-DISP PIC X(08).
|
||||
01 WS-CUR-TIME-DISP PIC X(06).
|
||||
01 WS-TS-DISPLAY PIC X(26).
|
||||
|
||||
*> Error severity levels
|
||||
01 WS-SEVERITY PIC X(01).
|
||||
88 WS-SEV-INFO VALUE 'I'.
|
||||
88 WS-SEV-WARNING VALUE 'W'.
|
||||
88 WS-SEV-ERROR VALUE 'E'.
|
||||
88 WS-SEV-CRITICAL VALUE 'C'.
|
||||
|
||||
*> Report and display formatting fields
|
||||
01 WS-RPT-COUNT PIC Z(9)9.
|
||||
01 WS-RPT-COUNT9 PIC Z(9)9.
|
||||
01 WS-RPT-LINE PIC X(80).
|
||||
01 WS-RPT-PCT PIC Z(9)9.9.
|
||||
01 WS-LINE-DISP PIC Z(9)9.
|
||||
01 WS-DISP-BUFFER PIC X(80).
|
||||
|
||||
PROCEDURE DIVISION.
|
||||
|
||||
*> ===== MAIN SECTION =====
|
||||
MAIN SECTION.
|
||||
MB-PROCESS.
|
||||
PERFORM 1000-INIT
|
||||
PERFORM 2000-OPEN-FILES
|
||||
PERFORM 3000-READ-INPUT
|
||||
PERFORM 4000-REPORT
|
||||
PERFORM 5000-AUDIT
|
||||
PERFORM 6000-ERROR-HANDLE
|
||||
PERFORM 9000-EXIT
|
||||
.
|
||||
|
||||
*> ===== 1000-INIT =====
|
||||
1000-INIT SECTION.
|
||||
1000-START.
|
||||
MOVE FUNCTION CURRENT-DATE (1:8) TO WS-CUR-DATE-DISP.
|
||||
MOVE FUNCTION CURRENT-DATE (9:6) TO WS-CUR-TIME-DISP.
|
||||
STRING WS-CUR-DATE-DISP '-'
|
||||
WS-CUR-TIME-DISP
|
||||
DELIMITED BY SIZE INTO WS-TIMESTAMP.
|
||||
STRING WS-CUR-DATE-DISP(1:4) '-'
|
||||
WS-CUR-DATE-DISP(5:2) '-'
|
||||
WS-CUR-DATE-DISP(7:2) ' '
|
||||
WS-CUR-TIME-DISP(1:2) ':'
|
||||
WS-CUR-TIME-DISP(3:2) ':'
|
||||
WS-CUR-TIME-DISP(5:2)
|
||||
DELIMITED BY SIZE INTO WS-TS-DISPLAY.
|
||||
DISPLAY WS-TS-DISPLAY ' 1000-INIT: CsvFbNoLf START'.
|
||||
|
||||
*> Initialize all counters to zero
|
||||
MOVE ZERO TO WS-REC-COUNT
|
||||
WS-LINE-COUNT
|
||||
WS-TOT-READ
|
||||
WS-TOT-WRITTEN
|
||||
WS-TOT-MALFORMED
|
||||
WS-TOT-TRUNCATED
|
||||
WS-TOT-QUOTE-ERR
|
||||
WS-TOT-FIELD-ERR
|
||||
WS-TOT-WARNINGS
|
||||
WS-TOT-ERRORS
|
||||
WS-TOT-CRITICAL
|
||||
WS-MALFORMED-CNT
|
||||
WS-TRUNC-CNT
|
||||
WS-FIELD-COUNT-ERR
|
||||
WS-HASH-TOTAL
|
||||
WS-HASH-FIELD1
|
||||
WS-HASH-FIELD2
|
||||
WS-HASH-FIELD3
|
||||
WS-HASH-FIELD-LEN.
|
||||
|
||||
*> Initialize flags
|
||||
MOVE 'Y' TO WS-RECONCILE-OK.
|
||||
MOVE 'N' TO WS-EOF.
|
||||
|
||||
*> ===== 2000-OPEN-FILES =====
|
||||
2000-OPEN-FILES SECTION.
|
||||
2000-START.
|
||||
DISPLAY WS-TS-DISPLAY ' 2000-OPEN-FILES: Opening files'.
|
||||
OPEN INPUT FILE-IN.
|
||||
IF WS-FILE-IN-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY ' ERROR: Cannot open FILE-IN,'
|
||||
' status: ' WS-FILE-IN-STATUS
|
||||
MOVE 1 TO RETURN-CODE
|
||||
STOP RUN
|
||||
END-IF.
|
||||
DISPLAY WS-TS-DISPLAY ' FILE-IN opened, status='
|
||||
WS-FILE-IN-STATUS.
|
||||
OPEN OUTPUT FILE-OUT.
|
||||
IF WS-FILE-OUT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY ' ERROR: Cannot open FILE-OUT,'
|
||||
' status: ' WS-FILE-OUT-STATUS
|
||||
MOVE 1 TO RETURN-CODE
|
||||
STOP RUN
|
||||
END-IF.
|
||||
DISPLAY WS-TS-DISPLAY ' FILE-OUT opened, status='
|
||||
WS-FILE-OUT-STATUS.
|
||||
OPEN OUTPUT ERROR-REPORT.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY ' ERROR: Cannot open ERROR-REPORT,'
|
||||
' status: ' WS-ERR-STATUS
|
||||
MOVE 1 TO RETURN-CODE
|
||||
STOP RUN
|
||||
END-IF.
|
||||
DISPLAY WS-TS-DISPLAY ' ERROR-REPORT opened, status='
|
||||
WS-ERR-STATUS.
|
||||
OPEN OUTPUT AUDIT-FILE.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY ' ERROR: Cannot open AUDIT-FILE,'
|
||||
' status: ' WS-AUDIT-STATUS
|
||||
MOVE 1 TO RETURN-CODE
|
||||
STOP RUN
|
||||
END-IF.
|
||||
DISPLAY WS-TS-DISPLAY ' AUDIT-FILE opened, status='
|
||||
WS-AUDIT-STATUS.
|
||||
|
||||
*> Write error report header lines
|
||||
MOVE 'CSV Error Detail Report - CsvFbNoLf' TO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY 'WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
STRING 'Run: ' WS-TIMESTAMP INTO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY 'WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
MOVE SPACES TO ERR-REC.
|
||||
MOVE 'Line Severity Field Description' TO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY 'WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
MOVE SPACES TO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY 'WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
*> Write audit file header lines
|
||||
MOVE 'CSV Audit Report - CsvFbNoLf' TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY ' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
|
||||
STRING 'Run: ' WS-TIMESTAMP INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY ' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
|
||||
MOVE SPACES TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY ' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
|
||||
DISPLAY WS-TS-DISPLAY '2000-OPEN-FILES: All files opened OK'.
|
||||
|
||||
*> ===== 3000-READ-INPUT =====
|
||||
3000-READ-INPUT SECTION.
|
||||
3000-START.
|
||||
DISPLAY WS-TS-DISPLAY ' 3000-READ-INPUT: Processing CSV'.
|
||||
|
||||
PERFORM UNTIL WS-EOF-YES
|
||||
READ FILE-IN
|
||||
AT END
|
||||
SET WS-EOF-YES TO TRUE
|
||||
DISPLAY WS-TS-DISPLAY ' EOF reached,'
|
||||
' lines=' WS-LINE-COUNT
|
||||
NOT AT END
|
||||
ADD 1 TO WS-LINE-COUNT
|
||||
ADD 1 TO WS-TOT-READ
|
||||
MOVE IN-LINE TO WS-INPUT-BUF
|
||||
PERFORM 3100-VALIDATE-RECORD
|
||||
END-READ
|
||||
IF WS-FILE-IN-STATUS NOT = '00'
|
||||
AND NOT = '10'
|
||||
DISPLAY WS-TS-DISPLAY ' READ ERROR: FILE-IN status='
|
||||
WS-FILE-IN-STATUS
|
||||
MOVE 'E' TO WS-SEVERITY
|
||||
ADD 1 TO WS-TOT-ERRORS
|
||||
END-IF
|
||||
END-PERFORM.
|
||||
|
||||
*> Close input file with STATUS check
|
||||
CLOSE FILE-IN.
|
||||
IF WS-FILE-IN-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY ' CLOSE ERROR: FILE-IN status='
|
||||
WS-FILE-IN-STATUS
|
||||
ADD 1 TO WS-TOT-ERRORS
|
||||
END-IF.
|
||||
DISPLAY WS-TS-DISPLAY ' 3000-READ-INPUT: Input closed,'
|
||||
' total=' WS-LINE-COUNT.
|
||||
|
||||
*> ===== 3100-VALIDATE-RECORD =====
|
||||
3100-VALIDATE-RECORD SECTION.
|
||||
3100-START.
|
||||
MOVE 'Y' TO WS-VALID-FLAG.
|
||||
MOVE 'Y' TO WS-FIELD1-OK.
|
||||
MOVE 'Y' TO WS-FIELD2-OK.
|
||||
MOVE 'Y' TO WS-FIELD3-OK.
|
||||
MOVE 'N' TO WS-FIELD-TRUNC-FLAG.
|
||||
MOVE SPACES TO WS-FIELD-ERR-MSG.
|
||||
|
||||
*> Quote pairing: odd quote count = malformed
|
||||
MOVE 0 TO WS-QUOTE-COUNT.
|
||||
INSPECT IN-LINE TALLYING WS-QUOTE-COUNT
|
||||
FOR ALL '"'.
|
||||
|
||||
IF FUNCTION MOD(WS-QUOTE-COUNT, 2) NOT = 0
|
||||
ADD 1 TO WS-MALFORMED-CNT
|
||||
ADD 1 TO WS-TOT-QUOTE-ERR
|
||||
ADD 1 TO WS-TOT-ERRORS
|
||||
MOVE 'E' TO WS-SEVERITY
|
||||
MOVE 'Unpaired quote in CSV line' TO WS-FIELD-ERR-MSG
|
||||
MOVE 'N' TO WS-VALID-FLAG
|
||||
STRING WS-LINE-COUNT ' ERROR Quote '
|
||||
WS-FIELD-ERR-MSG
|
||||
DELIMITED BY SIZE INTO ERR-REC
|
||||
WRITE ERR-REC
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF
|
||||
DISPLAY WS-TS-DISPLAY ' Quote error at line '
|
||||
WS-LINE-COUNT ': ' WS-FIELD-ERR-MSG
|
||||
END-IF.
|
||||
|
||||
*> Parse using original logic -> WS-FIELD1..3
|
||||
PERFORM PARSE-CSV-LINE.
|
||||
|
||||
*> Field count: expect 3 fields
|
||||
IF WS-FIELD-NUM < 3
|
||||
ADD 1 TO WS-FIELD-COUNT-ERR
|
||||
ADD 1 TO WS-TOT-FIELD-ERR
|
||||
ADD 1 TO WS-TOT-ERRORS
|
||||
MOVE 'E' TO WS-SEVERITY
|
||||
MOVE 'N' TO WS-VALID-FLAG
|
||||
STRING 'Expected 3 fields, got ' WS-FIELD-NUM
|
||||
INTO WS-FIELD-ERR-MSG
|
||||
STRING WS-LINE-COUNT ' ERROR Field '
|
||||
WS-FIELD-ERR-MSG
|
||||
DELIMITED BY SIZE INTO ERR-REC
|
||||
WRITE ERR-REC
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF
|
||||
DISPLAY WS-TS-DISPLAY ' Field count error at line '
|
||||
WS-LINE-COUNT ': ' WS-FIELD-ERR-MSG
|
||||
END-IF.
|
||||
|
||||
*> Field 1: presence check
|
||||
IF WS-FIELD1 = SPACES
|
||||
MOVE 'N' TO WS-FIELD1-OK
|
||||
MOVE 'W' TO WS-SEVERITY
|
||||
ADD 1 TO WS-TOT-WARNINGS
|
||||
MOVE 'Field1 is empty' TO WS-FIELD-ERR-MSG
|
||||
STRING WS-LINE-COUNT ' WARNING Field1 '
|
||||
'Empty field content'
|
||||
DELIMITED BY SIZE INTO ERR-REC
|
||||
WRITE ERR-REC
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF
|
||||
END-IF.
|
||||
|
||||
*> Truncation check: Field1 > 30 chars
|
||||
IF FUNCTION LENGTH(FUNCTION TRIM(WS-FIELD1)) > 30
|
||||
ADD 1 TO WS-TRUNC-CNT
|
||||
ADD 1 TO WS-TOT-TRUNCATED
|
||||
MOVE 'Y' TO WS-FIELD-TRUNC-FLAG
|
||||
MOVE 'W' TO WS-SEVERITY
|
||||
ADD 1 TO WS-TOT-WARNINGS
|
||||
STRING WS-LINE-COUNT ' WARNING Field1 '
|
||||
'Truncated to 30 chars'
|
||||
DELIMITED BY SIZE INTO ERR-REC
|
||||
WRITE ERR-REC
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF
|
||||
END-IF.
|
||||
|
||||
*> Truncation check: Field2 > 30 chars
|
||||
IF FUNCTION LENGTH(FUNCTION TRIM(WS-FIELD2)) > 30
|
||||
ADD 1 TO WS-TRUNC-CNT
|
||||
ADD 1 TO WS-TOT-TRUNCATED
|
||||
MOVE 'Y' TO WS-FIELD-TRUNC-FLAG
|
||||
MOVE 'W' TO WS-SEVERITY
|
||||
ADD 1 TO WS-TOT-WARNINGS
|
||||
STRING WS-LINE-COUNT ' WARNING Field2 '
|
||||
'Truncated to 30 chars'
|
||||
DELIMITED BY SIZE INTO ERR-REC
|
||||
WRITE ERR-REC
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF
|
||||
END-IF.
|
||||
|
||||
*> Numeric check: Field2
|
||||
IF WS-FIELD2 NOT = SPACES
|
||||
MOVE 'Y' TO WS-ALL-NUMERIC
|
||||
MOVE WS-FIELD2 TO WS-DISP-BUFFER
|
||||
INSPECT WS-DISP-BUFFER REPLACING ALL SPACES BY '0'
|
||||
PERFORM VARYING WS-IDX FROM 1 BY 1
|
||||
UNTIL WS-IDX > 30 OR WS-ALL-NUMERIC = 'N'
|
||||
MOVE WS-DISP-BUFFER(WS-IDX:1) TO WS-CHAR-CHK
|
||||
IF WS-CHAR-CHK < '0' OR > '9'
|
||||
MOVE 'N' TO WS-ALL-NUMERIC
|
||||
END-IF
|
||||
END-PERFORM
|
||||
IF WS-ALL-NUMERIC = 'N'
|
||||
MOVE 'N' TO WS-FIELD2-OK
|
||||
MOVE 'W' TO WS-SEVERITY
|
||||
ADD 1 TO WS-TOT-WARNINGS
|
||||
STRING WS-LINE-COUNT ' WARNING Field2 '
|
||||
'Non-numeric content'
|
||||
DELIMITED BY SIZE INTO ERR-REC
|
||||
WRITE ERR-REC
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF
|
||||
END-IF
|
||||
END-IF.
|
||||
|
||||
*> Truncation check: Field3 > 30 chars
|
||||
IF FUNCTION LENGTH(FUNCTION TRIM(WS-FIELD3)) > 30
|
||||
ADD 1 TO WS-TRUNC-CNT
|
||||
ADD 1 TO WS-TOT-TRUNCATED
|
||||
MOVE 'Y' TO WS-FIELD-TRUNC-FLAG
|
||||
MOVE 'W' TO WS-SEVERITY
|
||||
ADD 1 TO WS-TOT-WARNINGS
|
||||
STRING WS-LINE-COUNT ' WARNING Field3 '
|
||||
'Truncated to 30 chars'
|
||||
DELIMITED BY SIZE INTO ERR-REC
|
||||
WRITE ERR-REC
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF
|
||||
END-IF.
|
||||
|
||||
*> Numeric check: Field3
|
||||
IF WS-FIELD3 > SPACES
|
||||
MOVE 'Y' TO WS-ALL-NUMERIC
|
||||
MOVE WS-FIELD3 TO WS-DISP-BUFFER
|
||||
INSPECT WS-DISP-BUFFER REPLACING ALL SPACES BY '0'
|
||||
PERFORM VARYING WS-IDX FROM 1 BY 1
|
||||
UNTIL WS-IDX > 30 OR WS-ALL-NUMERIC = 'N'
|
||||
MOVE WS-DISP-BUFFER(WS-IDX:1) TO WS-CHAR-CHK
|
||||
IF WS-CHAR-CHK < '0' OR > '9'
|
||||
MOVE 'N' TO WS-ALL-NUMERIC
|
||||
END-IF
|
||||
END-PERFORM
|
||||
IF WS-ALL-NUMERIC = 'N'
|
||||
MOVE 'N' TO WS-FIELD3-OK
|
||||
MOVE 'W' TO WS-SEVERITY
|
||||
ADD 1 TO WS-TOT-WARNINGS
|
||||
STRING WS-LINE-COUNT ' WARNING Field3 '
|
||||
'Non-numeric content'
|
||||
DELIMITED BY SIZE INTO ERR-REC
|
||||
WRITE ERR-REC
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF
|
||||
END-IF
|
||||
END-IF.
|
||||
|
||||
*> If record is valid (no ERROR severity), process it
|
||||
IF WS-VALID-FLAG = 'Y'
|
||||
PERFORM 3200-PROCESS-RECORD
|
||||
ELSE
|
||||
DISPLAY WS-TS-DISPLAY ' Record ' WS-LINE-COUNT
|
||||
' skipped due to validation errors'
|
||||
END-IF.
|
||||
|
||||
*> ===== 3200-PROCESS-RECORD =====
|
||||
3200-PROCESS-RECORD SECTION.
|
||||
3200-START.
|
||||
PERFORM 3300-WRITE-OUTPUT.
|
||||
|
||||
*> Update per-field hash totals for batch control
|
||||
COMPUTE WS-HASH-FIELD1 = WS-HASH-FIELD1 +
|
||||
FUNCTION LENGTH(FUNCTION TRIM(WS-FIELD1))
|
||||
COMPUTE WS-HASH-FIELD2 = WS-HASH-FIELD2 +
|
||||
FUNCTION LENGTH(FUNCTION TRIM(WS-FIELD2))
|
||||
COMPUTE WS-HASH-FIELD3 = WS-HASH-FIELD3 +
|
||||
FUNCTION LENGTH(FUNCTION TRIM(WS-FIELD3)).
|
||||
|
||||
*> ===== 3300-WRITE-OUTPUT =====
|
||||
3300-WRITE-OUTPUT SECTION.
|
||||
3300-START.
|
||||
*> Build output record from parsed fields (original logic preserved)
|
||||
MOVE SPACES TO WS-OUT-LINE.
|
||||
STRING WS-FIELD1 DELIMITED BY SPACES
|
||||
'|'
|
||||
WS-FIELD2 DELIMITED BY SPACES
|
||||
'|'
|
||||
WS-FIELD3 DELIMITED BY SPACES
|
||||
INTO WS-OUT-LINE
|
||||
END-STRING.
|
||||
MOVE WS-OUT-LINE TO OUT-REC.
|
||||
WRITE OUT-REC.
|
||||
|
||||
*> FILE STATUS check after EVERY write
|
||||
IF WS-FILE-OUT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: FILE-OUT status='
|
||||
WS-FILE-OUT-STATUS
|
||||
MOVE 'E' TO WS-SEVERITY
|
||||
ADD 1 TO WS-TOT-ERRORS
|
||||
END-IF.
|
||||
|
||||
ADD 1 TO WS-REC-COUNT.
|
||||
ADD 1 TO WS-TOT-WRITTEN.
|
||||
|
||||
*> Combined hash total: sum of all field lengths
|
||||
COMPUTE WS-HASH-FIELD-LEN =
|
||||
FUNCTION LENGTH(FUNCTION TRIM(WS-FIELD1)) +
|
||||
FUNCTION LENGTH(FUNCTION TRIM(WS-FIELD2)) +
|
||||
FUNCTION LENGTH(FUNCTION TRIM(WS-FIELD3)).
|
||||
ADD WS-HASH-FIELD-LEN TO WS-HASH-TOTAL.
|
||||
|
||||
|
||||
*> ===== 4000-REPORT =====
|
||||
4000-REPORT SECTION.
|
||||
4000-START.
|
||||
DISPLAY WS-TS-DISPLAY '4000-REPORT: Finalizing error report'.
|
||||
|
||||
*> Write error report trailer
|
||||
MOVE SPACES TO ERR-REC.
|
||||
MOVE '--- End of CSV Error Detail Report ---' TO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
*> Write error summary to error report
|
||||
MOVE SPACES TO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
MOVE WS-LINE-COUNT TO WS-RPT-COUNT.
|
||||
STRING 'Total input lines: ' WS-RPT-COUNT
|
||||
INTO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
MOVE WS-MALFORMED-CNT TO WS-RPT-COUNT.
|
||||
STRING 'Malformed records: ' WS-RPT-COUNT
|
||||
INTO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
MOVE WS-TRUNC-CNT TO WS-RPT-COUNT.
|
||||
STRING 'Truncation warns: ' WS-RPT-COUNT
|
||||
INTO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
MOVE WS-FIELD-COUNT-ERR TO WS-RPT-COUNT.
|
||||
STRING 'Field count errors: ' WS-RPT-COUNT
|
||||
INTO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
*> Record count reconciliation summary
|
||||
IF WS-LINE-COUNT = WS-REC-COUNT
|
||||
MOVE 'PASS' TO WS-RPT-LINE
|
||||
ELSE
|
||||
MOVE 'MISMATCH (see audit)' TO WS-RPT-LINE
|
||||
MOVE 'N' TO WS-RECONCILE-OK
|
||||
END-IF.
|
||||
STRING 'Count reconcile: ' WS-RPT-LINE
|
||||
INTO ERR-REC.
|
||||
WRITE ERR-REC.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
|
||||
*> Close error report with STATUS check
|
||||
CLOSE ERROR-REPORT.
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' CLOSE ERROR: ERROR-REPORT status='
|
||||
WS-ERR-STATUS
|
||||
END-IF.
|
||||
DISPLAY WS-TS-DISPLAY ' 4000-REPORT: Error report closed'.
|
||||
|
||||
*> ===== 5000-AUDIT =====
|
||||
5000-AUDIT SECTION.
|
||||
5000-START.
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
'5000-AUDIT: audit report and control totals'.
|
||||
|
||||
*> Audit header
|
||||
MOVE '=== CSV Import Summary ===' TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
|
||||
MOVE SPACES TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
|
||||
*> Batch run identification
|
||||
STRING 'Program: CsvFbNoLf' INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
|
||||
STRING 'Run date: ' WS-CUR-DATE-DISP
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
|
||||
STRING 'Run time: ' WS-CUR-TIME-DISP
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
|
||||
MOVE SPACES TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
*> Record counts
|
||||
MOVE WS-LINE-COUNT TO WS-RPT-COUNT.
|
||||
STRING 'Input lines read: ' WS-RPT-COUNT
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE WS-REC-COUNT TO WS-RPT-COUNT.
|
||||
STRING 'Output records written: ' WS-RPT-COUNT
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
*> Record count reconciliation
|
||||
IF WS-LINE-COUNT = WS-REC-COUNT
|
||||
MOVE 'PASS' TO WS-RPT-LINE
|
||||
ELSE
|
||||
MOVE 'MISMATCH (see details)' TO WS-RPT-LINE
|
||||
MOVE 'N' TO WS-RECONCILE-OK
|
||||
END-IF.
|
||||
STRING 'Line vs record reconcile: ' WS-RPT-LINE
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
*> Error counts
|
||||
MOVE WS-MALFORMED-CNT TO WS-RPT-COUNT.
|
||||
STRING 'Malformed records: ' WS-RPT-COUNT
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE WS-TRUNC-CNT TO WS-RPT-COUNT.
|
||||
STRING 'Truncation warnings: ' WS-RPT-COUNT
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE WS-FIELD-COUNT-ERR TO WS-RPT-COUNT.
|
||||
STRING 'Field count errors: ' WS-RPT-COUNT
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE WS-TOT-QUOTE-ERR TO WS-RPT-COUNT.
|
||||
STRING 'Quote errors: ' WS-RPT-COUNT
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE SPACES TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
*> ------------------------
|
||||
*> Batch Control Totals
|
||||
*> ------------------------
|
||||
MOVE '=== Batch Control Totals ===' TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE WS-REC-COUNT TO WS-RPT-COUNT.
|
||||
STRING 'Record count total: ' WS-RPT-COUNT
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE WS-HASH-FIELD1 TO WS-RPT-COUNT9.
|
||||
STRING 'Hash total Field1: ' WS-RPT-COUNT9
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE WS-HASH-FIELD2 TO WS-RPT-COUNT9.
|
||||
STRING 'Hash total Field2: ' WS-RPT-COUNT9
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE WS-HASH-FIELD3 TO WS-RPT-COUNT9.
|
||||
STRING 'Hash total Field3: ' WS-RPT-COUNT9
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE WS-HASH-TOTAL TO WS-RPT-COUNT9.
|
||||
STRING 'Combined hash total: ' WS-RPT-COUNT9
|
||||
INTO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
MOVE SPACES TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
*> Processing success rate
|
||||
IF WS-LINE-COUNT > 0
|
||||
COMPUTE WS-RPT-PCT ROUNDED =
|
||||
(WS-REC-COUNT / WS-LINE-COUNT) * 100
|
||||
STRING 'Processing success rate: '
|
||||
WS-RPT-PCT '%'
|
||||
INTO AUD-REC
|
||||
WRITE AUD-REC
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF
|
||||
END-IF.
|
||||
|
||||
MOVE SPACES TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
|
||||
*> Audit trailer
|
||||
MOVE '=== End of CSV Audit Report ===' TO AUD-REC.
|
||||
WRITE AUD-REC.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WRITE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
|
||||
*> Close audit file with STATUS check
|
||||
CLOSE AUDIT-FILE.
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' CLOSE ERROR: AUDIT-FILE status='
|
||||
WS-AUDIT-STATUS
|
||||
END-IF.
|
||||
DISPLAY WS-TS-DISPLAY ' 5000-AUDIT: Audit file closed'.
|
||||
|
||||
*> ===== 6000-ERROR-HANDLE =====
|
||||
6000-ERROR-HANDLE SECTION.
|
||||
6000-START.
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' 6000-ERROR-HANDLE: Error summary'.
|
||||
|
||||
*> FILE-IN status summary
|
||||
IF WS-FILE-IN-STATUS NOT = '00'
|
||||
AND NOT = '10'
|
||||
DISPLAY WS-TS-DISPLAY ' FILE-IN status: '
|
||||
WS-FILE-IN-STATUS
|
||||
ADD 1 TO WS-TOT-ERRORS
|
||||
ELSE
|
||||
DISPLAY WS-TS-DISPLAY ' FILE-IN status OK ('
|
||||
WS-FILE-IN-STATUS ')'
|
||||
END-IF.
|
||||
|
||||
*> FILE-OUT status summary
|
||||
IF WS-FILE-OUT-STATUS NOT = '00'
|
||||
AND NOT = '10'
|
||||
DISPLAY WS-TS-DISPLAY ' FILE-OUT status: '
|
||||
WS-FILE-OUT-STATUS
|
||||
ADD 1 TO WS-TOT-ERRORS
|
||||
ELSE
|
||||
DISPLAY WS-TS-DISPLAY ' FILE-OUT status OK ('
|
||||
WS-FILE-OUT-STATUS ')'
|
||||
END-IF.
|
||||
|
||||
*> ERROR-REPORT status summary
|
||||
IF WS-ERR-STATUS NOT = '00'
|
||||
AND NOT = '10'
|
||||
DISPLAY WS-TS-DISPLAY ' ERROR-REPORT status: '
|
||||
WS-ERR-STATUS
|
||||
ADD 1 TO WS-TOT-ERRORS
|
||||
ELSE
|
||||
DISPLAY WS-TS-DISPLAY ' ERROR-REPORT status OK ('
|
||||
WS-ERR-STATUS ')'
|
||||
END-IF.
|
||||
|
||||
*> AUDIT-FILE status summary
|
||||
IF WS-AUDIT-STATUS NOT = '00'
|
||||
AND NOT = '10'
|
||||
DISPLAY WS-TS-DISPLAY ' AUDIT-FILE status: '
|
||||
WS-AUDIT-STATUS
|
||||
ADD 1 TO WS-TOT-ERRORS
|
||||
ELSE
|
||||
DISPLAY WS-TS-DISPLAY ' AUDIT-FILE status OK ('
|
||||
WS-AUDIT-STATUS ')'
|
||||
END-IF.
|
||||
|
||||
*> Error count summary with severity breakdown
|
||||
DISPLAY WS-TS-DISPLAY ' Severity totals:'
|
||||
MOVE WS-TOT-WARNINGS TO WS-RPT-COUNT9
|
||||
DISPLAY ' Warnings: ' WS-RPT-COUNT9
|
||||
MOVE WS-TOT-ERRORS TO WS-RPT-COUNT9
|
||||
DISPLAY ' Errors: ' WS-RPT-COUNT9
|
||||
MOVE WS-TOT-CRITICAL TO WS-RPT-COUNT9
|
||||
DISPLAY ' Critical: ' WS-RPT-COUNT9.
|
||||
|
||||
*> Record count reconciliation check
|
||||
IF WS-LINE-COUNT NOT = WS-REC-COUNT
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' WARNING: Line/output count mismatch'
|
||||
MOVE 'N' TO WS-RECONCILE-OK
|
||||
END-IF.
|
||||
|
||||
*> ===== 9000-EXIT =====
|
||||
9000-EXIT SECTION.
|
||||
9000-START.
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' 9000-EXIT: Program CsvFbNoLf completed'.
|
||||
|
||||
*> Final record counts display
|
||||
MOVE WS-LINE-COUNT TO WS-RPT-COUNT.
|
||||
MOVE WS-REC-COUNT TO WS-LINE-DISP.
|
||||
DISPLAY ' Input lines: ' WS-RPT-COUNT.
|
||||
MOVE WS-REC-COUNT TO WS-RPT-COUNT.
|
||||
DISPLAY ' Output recs: ' WS-RPT-COUNT.
|
||||
DISPLAY ' Reconcile: ' WS-RECONCILE-OK.
|
||||
|
||||
*> Error counts display
|
||||
MOVE WS-MALFORMED-CNT TO WS-RPT-COUNT.
|
||||
DISPLAY ' Malformed: ' WS-RPT-COUNT.
|
||||
MOVE WS-TRUNC-CNT TO WS-RPT-COUNT.
|
||||
DISPLAY ' Truncated: ' WS-RPT-COUNT.
|
||||
MOVE WS-FIELD-COUNT-ERR TO WS-RPT-COUNT.
|
||||
DISPLAY ' Field err: ' WS-RPT-COUNT.
|
||||
|
||||
*> Hash total display
|
||||
MOVE WS-HASH-TOTAL TO WS-RPT-COUNT9.
|
||||
DISPLAY ' Hash total: ' WS-RPT-COUNT9.
|
||||
|
||||
*> Output file listing
|
||||
DISPLAY ' Output file: file-out.dat'.
|
||||
DISPLAY ' Error report: csv-errors.dat'.
|
||||
DISPLAY ' Audit report: csv-audit.dat'.
|
||||
|
||||
*> Close FILE-OUT with STATUS check
|
||||
CLOSE FILE-OUT.
|
||||
IF WS-FILE-OUT-STATUS NOT = '00'
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' CLOSE ERROR: FILE-OUT status='
|
||||
WS-FILE-OUT-STATUS
|
||||
END-IF.
|
||||
DISPLAY WS-TS-DISPLAY ' FILE-OUT closed, status='
|
||||
WS-FILE-OUT-STATUS.
|
||||
|
||||
*> Set return code based on reconciliation status
|
||||
IF WS-RECONCILE-OK = 'N'
|
||||
MOVE 4 TO RETURN-CODE
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' RETURN-CODE=4 (reconciliation mismatch)'
|
||||
ELSE
|
||||
MOVE 0 TO RETURN-CODE
|
||||
DISPLAY WS-TS-DISPLAY
|
||||
' RETURN-CODE=0 (normal completion)'
|
||||
END-IF.
|
||||
|
||||
*> Terminate program
|
||||
STOP RUN.
|
||||
|
||||
*> ===== PARSE-CSV-LINE (original logic, UNCHANGED) =====
|
||||
PARSE-CSV-LINE.
|
||||
MOVE SPACES TO WS-FIELDS.
|
||||
MOVE 1 TO WS-POS.
|
||||
MOVE 1 TO WS-FIELD-NUM.
|
||||
MOVE 1 TO WS-CHAR-OFFSET.
|
||||
MOVE 'N' TO WS-IN-QUOTE.
|
||||
|
||||
PERFORM VARYING WS-POS FROM 1 BY 1
|
||||
UNTIL WS-POS > 200
|
||||
OR WS-FIELD-NUM > 3
|
||||
MOVE IN-LINE(WS-POS:1) TO WS-CHAR
|
||||
IF WS-CHAR = '"'
|
||||
IF WS-IN-QUOTE-YES
|
||||
MOVE 'N' TO WS-IN-QUOTE
|
||||
ELSE
|
||||
MOVE 'Y' TO WS-IN-QUOTE
|
||||
END-IF
|
||||
ELSE
|
||||
IF WS-CHAR = ',' AND NOT WS-IN-QUOTE-YES
|
||||
ADD 1 TO WS-FIELD-NUM
|
||||
MOVE 1 TO WS-CHAR-OFFSET
|
||||
ELSE
|
||||
IF WS-CHAR NOT = SPACE
|
||||
OR WS-CHAR-OFFSET > 1
|
||||
THEN
|
||||
PERFORM SAVE-CHAR-TO-FIELD
|
||||
END-IF
|
||||
IF WS-CHAR-OFFSET < 30
|
||||
ADD 1 TO WS-CHAR-OFFSET
|
||||
END-IF
|
||||
END-IF
|
||||
END-IF
|
||||
END-PERFORM.
|
||||
|
||||
*> ===== SAVE-CHAR-TO-FIELD (original, UNCHANGED) =====
|
||||
SAVE-CHAR-TO-FIELD.
|
||||
EVALUATE WS-FIELD-NUM
|
||||
WHEN 1
|
||||
MOVE WS-CHAR TO WS-FIELD1(WS-CHAR-OFFSET:1)
|
||||
WHEN 2
|
||||
MOVE WS-CHAR TO WS-FIELD2(WS-CHAR-OFFSET:1)
|
||||
WHEN 3
|
||||
MOVE WS-CHAR TO WS-FIELD3(WS-CHAR-OFFSET:1)
|
||||
END-EVALUATE.
|
||||
|
||||
END PROGRAM CsvFbNoLf.
|
||||
@@ -0,0 +1,132 @@
|
||||
*> ============================================================
|
||||
*> main-csv-anomaly : CDR CSV异常系测试 (CSV Anomaly)
|
||||
*> Input : CSV-IN (CSV-INPUT.DAT: 异常CSV数据)
|
||||
*> Output: FB-OUT (FB-OUTPUT.DAT: 固定长输出)
|
||||
*> Coverage: CF-A001, CF-A002
|
||||
*> ============================================================
|
||||
IDENTIFICATION DIVISION.
|
||||
PROGRAM-ID. CsvAnomaly.
|
||||
|
||||
ENVIRONMENT DIVISION.
|
||||
INPUT-OUTPUT SECTION.
|
||||
FILE-CONTROL.
|
||||
SELECT CSV-IN ASSIGN TO "CSV-INPUT.DAT"
|
||||
ORGANIZATION IS LINE SEQUENTIAL.
|
||||
|
||||
SELECT FB-OUT ASSIGN TO "FB-OUTPUT.DAT"
|
||||
ORGANIZATION IS SEQUENTIAL.
|
||||
|
||||
DATA DIVISION.
|
||||
FILE SECTION.
|
||||
FD CSV-IN RECORD VARYING FROM 1 TO 200.
|
||||
01 CSV-REC PIC X(200).
|
||||
|
||||
FD FB-OUT RECORD CONTAINS 40 CHARACTERS.
|
||||
01 FB-REC.
|
||||
05 FB-FIELD1 PIC X(10).
|
||||
05 FB-FIELD2 PIC X(10).
|
||||
05 FB-FIELD3 PIC X(10).
|
||||
05 FB-FIELD4 PIC X(10).
|
||||
|
||||
WORKING-STORAGE SECTION.
|
||||
01 WS-EOF PIC X(1) VALUE 'N'.
|
||||
88 WS-EOF-Y VALUE 'Y' FALSE 'N'.
|
||||
01 WS-COUNT PIC 9(10).
|
||||
01 WS-ERR-COUNT PIC 9(10).
|
||||
01 WS-QUOTE-OPEN PIC X(1) VALUE 'N'.
|
||||
88 WS-QUOTE-OPEN-Y VALUE 'Y' FALSE 'N'.
|
||||
01 WS-PASS PIC 9(2) VALUE 0.
|
||||
01 WS-FAIL PIC 9(2) VALUE 0.
|
||||
01 WS-TRIM-CSV PIC X(200).
|
||||
|
||||
01 WS-CDR-REC.
|
||||
COPY "telecom/TEL-CDR.cpy".
|
||||
|
||||
PROCEDURE DIVISION.
|
||||
MAIN.
|
||||
DISPLAY "CSV-ANOMALY: Starting CSV anomaly tests"
|
||||
|
||||
*> CF-A002: 引用符未閉じ → 殘り全部1項目
|
||||
DISPLAY "CF-A002: Unclosed quote test"
|
||||
OPEN OUTPUT CSV-IN.
|
||||
MOVE '"Field1","Field2","Field3,no-close' TO CSV-REC.
|
||||
WRITE CSV-REC.
|
||||
CLOSE CSV-IN.
|
||||
|
||||
OPEN INPUT CSV-IN.
|
||||
OPEN OUTPUT FB-OUT.
|
||||
READ CSV-IN INTO WS-TRIM-CSV
|
||||
AT END
|
||||
DISPLAY "CF-A002: Empty read"
|
||||
NOT AT END
|
||||
STRING WS-TRIM-CSV(1:10) WS-TRIM-CSV(11:10)
|
||||
WS-TRIM-CSV(21:10) "TRUNCATED"
|
||||
DELIMITED BY SIZE INTO FB-REC
|
||||
END-STRING
|
||||
WRITE FB-REC
|
||||
ADD 1 TO WS-COUNT
|
||||
DISPLAY "CF-A002: Unclosed quote handled"
|
||||
END-READ.
|
||||
CLOSE CSV-IN FB-OUT.
|
||||
|
||||
IF WS-COUNT > 0
|
||||
ADD 1 TO WS-PASS
|
||||
DISPLAY "CF-A002: PASS - unclosed quote processed"
|
||||
ELSE
|
||||
ADD 1 TO WS-FAIL
|
||||
DISPLAY "CF-A002: FAIL"
|
||||
END-IF.
|
||||
|
||||
*> CF-A001: 改行位置超出RECORD長
|
||||
DISPLAY "CF-A001: Line exceeding record length"
|
||||
OPEN OUTPUT CSV-IN.
|
||||
MOVE SPACES TO CSV-REC.
|
||||
STRING "SHORT,OKAY,THREE"
|
||||
DELIMITED BY SIZE INTO CSV-REC
|
||||
END-STRING.
|
||||
WRITE CSV-REC.
|
||||
|
||||
MOVE SPACES TO CSV-REC.
|
||||
STRING "LONG-FIELD-A,LONG-FIELD-B,LONG-FIELD-C,"
|
||||
"VERY-LONG-FIELD-D,EXTRA-LONG-FIELD-E"
|
||||
DELIMITED BY SIZE INTO CSV-REC
|
||||
END-STRING.
|
||||
WRITE CSV-REC.
|
||||
CLOSE CSV-IN.
|
||||
|
||||
OPEN INPUT CSV-IN.
|
||||
OPEN OUTPUT FB-OUT.
|
||||
MOVE 0 TO WS-COUNT.
|
||||
MOVE 'N' TO WS-EOF.
|
||||
PERFORM UNTIL WS-EOF-Y
|
||||
READ CSV-IN INTO WS-TRIM-CSV
|
||||
AT END SET WS-EOF-Y TO TRUE
|
||||
NOT AT END
|
||||
ADD 1 TO WS-COUNT
|
||||
MOVE WS-TRIM-CSV(1:10) TO FB-FIELD1
|
||||
MOVE WS-TRIM-CSV(12:10) TO FB-FIELD2
|
||||
WRITE FB-REC
|
||||
END-READ
|
||||
END-PERFORM.
|
||||
CLOSE CSV-IN FB-OUT.
|
||||
|
||||
IF WS-COUNT = 2
|
||||
ADD 1 TO WS-PASS
|
||||
DISPLAY "CF-A001: PASS - overlong handled (2 records)"
|
||||
ELSE
|
||||
ADD 1 TO WS-FAIL
|
||||
DISPLAY "CF-A001: FAIL - count=" WS-COUNT
|
||||
END-IF.
|
||||
|
||||
DISPLAY " "
|
||||
DISPLAY "CSV-ANOMALY: PASS=" WS-PASS " FAIL=" WS-FAIL
|
||||
IF WS-FAIL = 0
|
||||
DISPLAY "CSV-ANOMALY: ALL PASSED"
|
||||
STOP RUN RETURNING 0
|
||||
ELSE
|
||||
DISPLAY "CSV-ANOMALY: FAILED"
|
||||
STOP RUN RETURNING 1
|
||||
END-IF
|
||||
.
|
||||
|
||||
END PROGRAM CsvAnomaly.
|
||||
Reference in New Issue
Block a user