*> ============================================================ *> 27-validation-halfwidth : Phone Number Validation *> Extended with SECTION structure, prefix validation, *> phone length rules, audit/report files, severity levels, *> batch control totals, FILE STATUS checks, DISPLAY tracing. *> Input : FILE-IN (file-in.dat) *> Output: FILE-OUT-GOOD, -BAD, -REPORT, -AUDIT *> Coverage: VF-N005, VF-N006, VF-A001, VF-A002, VF-R001 *> VF-P001, VF-P002, VF-P003, VF-L001, VF-S001 *> ============================================================ IDENTIFICATION DIVISION. PROGRAM-ID. ValidationHalfwidth. *> ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT FILE-IN ASSIGN TO 'file-in.dat' ORGANIZATION IS SEQUENTIAL ACCESS MODE IS SEQUENTIAL FILE STATUS IS WS-FILE-IN-STATUS. SELECT FILE-OUT-GOOD ASSIGN TO 'file-out-good.dat' ORGANIZATION IS SEQUENTIAL FILE STATUS IS WS-FILE-GOOD-STATUS. SELECT FILE-OUT-BAD ASSIGN TO 'file-out-bad.dat' ORGANIZATION IS SEQUENTIAL FILE STATUS IS WS-FILE-BAD-STATUS. SELECT FILE-OUT-REPORT ASSIGN TO 'file-out-report.dat' ORGANIZATION IS SEQUENTIAL FILE STATUS IS WS-FILE-REPORT-STATUS. SELECT FILE-OUT-AUDIT ASSIGN TO 'file-out-audit.dat' ORGANIZATION IS SEQUENTIAL FILE STATUS IS WS-FILE-AUDIT-STATUS. *> DATA DIVISION. FILE SECTION. FD FILE-IN. 01 IN-REC. 05 IN-TEXT PIC X(30). *> FD FILE-OUT-GOOD. 01 GOOD-REC. 05 GOOD-TEXT PIC X(30). *> FD FILE-OUT-BAD. 01 BAD-REC. 05 BAD-TEXT PIC X(30). 05 BAD-ERR-CODE PIC X(02). *> FD FILE-OUT-REPORT. 01 REPORT-REC. 05 REPORT-LINE PIC X(80). *> FD FILE-OUT-AUDIT. 01 AUDIT-REC. 05 AUDIT-LINE PIC X(80). *> WORKING-STORAGE SECTION. 01 WS-TELECOM-REC. COPY "telecom/TEL-BILLING.cpy". *> File status fields 01 WS-FILE-IN-STATUS PIC X(02). 01 WS-FILE-GOOD-STATUS PIC X(02). 01 WS-FILE-BAD-STATUS PIC X(02). 01 WS-FILE-REPORT-STATUS PIC X(02). 01 WS-FILE-AUDIT-STATUS PIC X(02). *> EOF and loop control 01 WS-EOF PIC X(01) VALUE 'N'. 88 WS-EOF-YES VALUE 'Y' FALSE 'N'. *> Record counts 01 WS-TOTAL-READ PIC 9(09) VALUE ZERO. 01 WS-GOOD-COUNT PIC 9(09) VALUE ZERO. 01 WS-BAD-COUNT PIC 9(09) VALUE ZERO. 01 WS-SKIP-COUNT PIC 9(09) VALUE ZERO. 01 WS-WARN-COUNT PIC 9(09) VALUE ZERO. 01 WS-ERROR-COUNT PIC 9(09) VALUE ZERO. *> Batch control totals 01 WS-TOTAL-CHARS PIC 9(15) VALUE ZERO. 01 WS-TOTAL-DIGITS PIC 9(15) VALUE ZERO. 01 WS-HASH-TOTAL PIC 9(15) VALUE ZERO. *> Validation fields 01 WS-IDX PIC 9(02). 01 WS-CHAR PIC X(01). 01 WS-ALL-HALF PIC X(01) VALUE 'Y'. 88 WS-ALL-HALF-YES VALUE 'Y' FALSE 'N'. 01 WS-TEXT-LEN PIC 9(02). *> Multiple validation results 01 WS-VALID-RESULT. 05 WS-V-FORMAT PIC X(01) VALUE 'P'. 88 WS-V-FORMAT-PASS VALUE 'P'. 88 WS-V-FORMAT-FAIL VALUE 'F'. 05 WS-V-LENGTH PIC X(01) VALUE 'P'. 88 WS-V-LENGTH-PASS VALUE 'P'. 88 WS-V-LENGTH-FAIL VALUE 'F'. 05 WS-V-PREFIX PIC X(01) VALUE 'P'. 88 WS-V-PREFIX-PASS VALUE 'P'. 88 WS-V-PREFIX-FAIL VALUE 'F'. 05 WS-V-HALF PIC X(01) VALUE 'P'. 88 WS-V-HALF-PASS VALUE 'P'. 88 WS-V-HALF-FAIL VALUE 'F'. 01 WS-V-FORMAT-ERR PIC X(02). 01 WS-V-LENGTH-ERR PIC X(02). 01 WS-V-PREFIX-ERR PIC X(02). 01 WS-V-HALF-ERR PIC X(02). *> Error codes and severity 01 WS-ERROR-CODE PIC X(02). 01 WS-ERROR-SEVERITY PIC X(01). 88 WS-SEVERITY-WARNING VALUE 'W'. 88 WS-SEVERITY-ERROR VALUE 'E'. 01 WS-ERROR-DETAIL PIC X(50). *> Half-width range constants 01 WS-HW-LOWER PIC X(01) VALUE X'20'. 01 WS-HW-UPPER PIC X(01) VALUE X'7E'. *> Phone number analysis 01 WS-PHONE-TYPE PIC X(01). 88 WS-PHONE-MOBILE VALUE 'M'. 88 WS-PHONE-LANDLINE VALUE 'L'. 88 WS-PHONE-UNKNOWN VALUE 'U'. 01 WS-PHONE-DIGITS PIC X(30). 01 WS-PHONE-DIGIT-COUNT PIC 9(02). 01 WS-PREFIX-STR PIC X(06). 01 WS-PREFIX-LEN PIC 9(02). 01 WS-HAS-LEADING-PLUS PIC X(01) VALUE 'N'. 88 WS-LEADING-PLUS-YES VALUE 'Y' FALSE 'N'. *> *> Known prefixes — China mobile (8613x, 8615x, 8618x) 01 WS-MOBILE-PREFIX-TBL. 05 FILLER PIC X(05) VALUE '86130'. 05 FILLER PIC X(05) VALUE '86131'. 05 FILLER PIC X(05) VALUE '86132'. 05 FILLER PIC X(05) VALUE '86133'. 05 FILLER PIC X(05) VALUE '86135'. 05 FILLER PIC X(05) VALUE '86136'. 05 FILLER PIC X(05) VALUE '86137'. 05 FILLER PIC X(05) VALUE '86138'. 05 FILLER PIC X(05) VALUE '86139'. 05 FILLER PIC X(05) VALUE '86150'. 05 FILLER PIC X(05) VALUE '86151'. 05 FILLER PIC X(05) VALUE '86152'. 05 FILLER PIC X(05) VALUE '86153'. 05 FILLER PIC X(05) VALUE '86155'. 05 FILLER PIC X(05) VALUE '86156'. 05 FILLER PIC X(05) VALUE '86157'. 05 FILLER PIC X(05) VALUE '86158'. 05 FILLER PIC X(05) VALUE '86159'. 05 FILLER PIC X(05) VALUE '86180'. 05 FILLER PIC X(05) VALUE '86181'. 05 FILLER PIC X(05) VALUE '86182'. 05 FILLER PIC X(05) VALUE '86183'. 05 FILLER PIC X(05) VALUE '86185'. 05 FILLER PIC X(05) VALUE '86186'. 05 FILLER PIC X(05) VALUE '86187'. 05 FILLER PIC X(05) VALUE '86188'. 05 FILLER PIC X(05) VALUE '86189'. 01 WS-MOBILE-TABLE REDEFINES WS-MOBILE-PREFIX-TBL. 05 WS-MOBILE-ITEM PIC X(05) OCCURS 27 TIMES. 01 WS-MOBILE-PREFIX-COUNT PIC 9(02) VALUE 27. *> *> Known prefixes — China landline (city codes) 01 WS-LL-PREFIX-TBL. 05 FILLER PIC X(05) VALUE '86010'. 05 FILLER PIC X(05) VALUE '86020'. 05 FILLER PIC X(05) VALUE '86021'. 05 FILLER PIC X(05) VALUE '86022'. 05 FILLER PIC X(05) VALUE '86023'. 05 FILLER PIC X(05) VALUE '86024'. 05 FILLER PIC X(05) VALUE '86025'. 05 FILLER PIC X(05) VALUE '86027'. 05 FILLER PIC X(05) VALUE '86028'. 05 FILLER PIC X(05) VALUE '86029'. 05 FILLER PIC X(05) VALUE '86031'. 05 FILLER PIC X(05) VALUE '86041'. 05 FILLER PIC X(05) VALUE '86051'. 05 FILLER PIC X(05) VALUE '86052'. 05 FILLER PIC X(05) VALUE '86053'. 05 FILLER PIC X(05) VALUE '86054'. 05 FILLER PIC X(05) VALUE '86055'. 05 FILLER PIC X(05) VALUE '86056'. 05 FILLER PIC X(05) VALUE '86057'. 05 FILLER PIC X(05) VALUE '86058'. 05 FILLER PIC X(05) VALUE '86059'. 05 FILLER PIC X(05) VALUE '86063'. 05 FILLER PIC X(05) VALUE '86066'. 05 FILLER PIC X(05) VALUE '86067'. 05 FILLER PIC X(05) VALUE '86069'. 05 FILLER PIC X(05) VALUE '86071'. 05 FILLER PIC X(05) VALUE '86072'. 05 FILLER PIC X(05) VALUE '86073'. 05 FILLER PIC X(05) VALUE '86074'. 05 FILLER PIC X(05) VALUE '86075'. 05 FILLER PIC X(05) VALUE '86076'. 05 FILLER PIC X(05) VALUE '86077'. 05 FILLER PIC X(05) VALUE '86078'. 05 FILLER PIC X(05) VALUE '86079'. 05 FILLER PIC X(05) VALUE '86081'. 05 FILLER PIC X(05) VALUE '86082'. 05 FILLER PIC X(05) VALUE '86083'. 05 FILLER PIC X(05) VALUE '86084'. 05 FILLER PIC X(05) VALUE '86085'. 05 FILLER PIC X(05) VALUE '86086'. 05 FILLER PIC X(05) VALUE '86087'. 05 FILLER PIC X(05) VALUE '86088'. 05 FILLER PIC X(05) VALUE '86089'. 05 FILLER PIC X(05) VALUE '86091'. 05 FILLER PIC X(05) VALUE '86092'. 05 FILLER PIC X(05) VALUE '86093'. 05 FILLER PIC X(05) VALUE '86094'. 05 FILLER PIC X(05) VALUE '86095'. 05 FILLER PIC X(05) VALUE '86096'. 05 FILLER PIC X(05) VALUE '86097'. 05 FILLER PIC X(05) VALUE '86098'. 05 FILLER PIC X(05) VALUE '86099'. 01 WS-LL-TABLE REDEFINES WS-LL-PREFIX-TBL. 05 WS-LL-ITEM PIC X(05) OCCURS 51 TIMES. 01 WS-LL-PREFIX-COUNT PIC 9(02) VALUE 51. *> *> Timestamp and trace fields 01 WS-CURRENT-TIME. 05 WS-CURR-YEAR PIC X(04). 05 WS-CURR-MONTH PIC X(02). 05 WS-CURR-DAY PIC X(02). 05 WS-CURR-HOUR PIC X(02). 05 WS-CURR-MIN PIC X(02). 05 WS-CURR-SEC PIC X(02). 01 WS-TIMESTAMP PIC X(20). 01 WS-TRACE-TS PIC X(20). *> Report editing fields 01 WS-ED-PASS PIC Z(09)9. 01 WS-ED-FAIL PIC Z(09)9. 01 WS-ED-SKIP PIC Z(09)9. 01 WS-ED-WARN PIC Z(09)9. 01 WS-ED-ERROR PIC Z(09)9. 01 WS-ED-TOTAL PIC Z(09)9. 01 WS-ED-HASH PIC Z(14)9. *> Local variables 01 WS-J PIC 9(02). 01 WS-K PIC 9(02). *> *> ============================================================ PROCEDURE DIVISION. *> ============================================================ MAIN SECTION. MB-PROCESS. PERFORM 1000-INIT. PERFORM 2000-OPEN-FILES. PERFORM 3000-READ-INPUT UNTIL WS-EOF-YES. PERFORM 4000-REPORT. PERFORM 5000-AUDIT. PERFORM 9000-EXIT. STOP RUN. *> *> ============================================================ *> 1000-INIT : Initialize counters, tables, batch timestamp *> ============================================================ 1000-INIT SECTION. I1000-START. DISPLAY 'ValidationHalfwidth: 1000-INIT starting...'. MOVE ZERO TO WS-TOTAL-READ WS-GOOD-COUNT WS-BAD-COUNT WS-SKIP-COUNT WS-WARN-COUNT WS-ERROR-COUNT WS-TOTAL-CHARS WS-TOTAL-DIGITS WS-HASH-TOTAL. MOVE 'N' TO WS-EOF. MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-TIME. STRING WS-CURR-YEAR '-' WS-CURR-MONTH '-' WS-CURR-DAY ' ' WS-CURR-HOUR ':' WS-CURR-MIN ':' WS-CURR-SEC INTO WS-TIMESTAMP. DISPLAY 'ValidationHalfwidth: Batch started at ' WS-TIMESTAMP. EXIT. *> *> ============================================================ *> 2000-OPEN-FILES : Open all files with FILE STATUS checks *> ============================================================ 2000-OPEN-FILES SECTION. I2000-START. DISPLAY 'ValidationHalfwidth: 2000-OPEN-FILES starting...'. OPEN INPUT FILE-IN. IF WS-FILE-IN-STATUS NOT = '00' MOVE 'E' TO WS-ERROR-SEVERITY MOVE '10' TO WS-ERROR-CODE STRING 'FILE-IN open failed, status=' WS-FILE-IN-STATUS INTO WS-ERROR-DETAIL PERFORM 6000-ERROR-HANDLE END-IF. OPEN OUTPUT FILE-OUT-GOOD. IF WS-FILE-GOOD-STATUS NOT = '00' MOVE 'E' TO WS-ERROR-SEVERITY MOVE '11' TO WS-ERROR-CODE STRING 'FILE-OUT-GOOD open failed, status=' WS-FILE-GOOD-STATUS INTO WS-ERROR-DETAIL PERFORM 6000-ERROR-HANDLE END-IF. OPEN OUTPUT FILE-OUT-BAD. IF WS-FILE-BAD-STATUS NOT = '00' MOVE 'E' TO WS-ERROR-SEVERITY MOVE '12' TO WS-ERROR-CODE STRING 'FILE-OUT-BAD open failed, status=' WS-FILE-BAD-STATUS INTO WS-ERROR-DETAIL PERFORM 6000-ERROR-HANDLE END-IF. OPEN OUTPUT FILE-OUT-REPORT. IF WS-FILE-REPORT-STATUS NOT = '00' MOVE 'E' TO WS-ERROR-SEVERITY MOVE '13' TO WS-ERROR-CODE STRING 'FILE-OUT-REPORT open failed, status=' WS-FILE-REPORT-STATUS INTO WS-ERROR-DETAIL PERFORM 6000-ERROR-HANDLE END-IF. OPEN OUTPUT FILE-OUT-AUDIT. IF WS-FILE-AUDIT-STATUS NOT = '00' MOVE 'E' TO WS-ERROR-SEVERITY MOVE '14' TO WS-ERROR-CODE STRING 'FILE-OUT-AUDIT open failed, status=' WS-FILE-AUDIT-STATUS INTO WS-ERROR-DETAIL PERFORM 6000-ERROR-HANDLE END-IF. DISPLAY 'ValidationHalfwidth: All files opened OK'. EXIT. *> *> ============================================================ *> 3000-READ-INPUT : Read loop — read record and dispatch *> ============================================================ 3000-READ-INPUT SECTION. I3000-START. PERFORM 3100-VALIDATE-RECORD THRU I3100-EXIT. IF NOT WS-EOF-YES PERFORM 3200-PROCESS-RECORD PERFORM 3300-WRITE-OUTPUT END-IF. EXIT. *> *> ============================================================ *> 3100-VALIDATE-RECORD : Full validation pipeline *> R1: Half-width check *> R2: Character set (digits 0-9, optional leading +) *> R3: Length check (mobile=11, landline=10-12) *> R4: Prefix lookup (China mobile/landline) *> R5: Format rules for mobile vs landline *> ============================================================ 3100-VALIDATE-RECORD SECTION. I3100-START. MOVE 'P' TO WS-V-FORMAT WS-V-LENGTH WS-V-PREFIX WS-V-HALF. MOVE SPACES TO WS-V-FORMAT-ERR WS-V-LENGTH-ERR WS-V-PREFIX-ERR WS-V-HALF-ERR WS-ERROR-CODE WS-ERROR-DETAIL WS-PHONE-TYPE. MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-TIME. STRING WS-CURR-HOUR ':' WS-CURR-MIN ':' WS-CURR-SEC INTO WS-TRACE-TS. DISPLAY '3100-VALIDATE-RECORD: [' WS-TRACE-TS '] Processing: "' FUNCTION TRIM(IN-TEXT) '"'. READ FILE-IN AT END SET WS-EOF-YES TO TRUE DISPLAY '3100-VALIDATE-RECORD: EOF reached' EXIT PARAGRAPH NOT AT END DISPLAY '3100-VALIDATE-RECORD: Read OK status=' WS-FILE-IN-STATUS END-READ. IF WS-EOF-YES EXIT END-IF. IF WS-FILE-IN-STATUS NOT = '00' MOVE 'E' TO WS-ERROR-SEVERITY MOVE '15' TO WS-ERROR-CODE STRING 'READ failed, status=' WS-FILE-IN-STATUS INTO WS-ERROR-DETAIL PERFORM 6000-ERROR-HANDLE END-IF. ADD 1 TO WS-TOTAL-READ. *> *> R1: Half-width check (original logic preserved) MOVE 'Y' TO WS-ALL-HALF. PERFORM VARYING WS-IDX FROM 1 BY 1 UNTIL WS-IDX > 30 MOVE IN-TEXT(WS-IDX:1) TO WS-CHAR IF WS-CHAR = SPACE CONTINUE ELSE IF WS-CHAR < WS-HW-LOWER MOVE 'N' TO WS-ALL-HALF END-IF IF WS-CHAR > WS-HW-UPPER MOVE 'N' TO WS-ALL-HALF END-IF END-IF END-PERFORM. IF NOT WS-ALL-HALF-YES MOVE 'F' TO WS-V-HALF MOVE '01' TO WS-V-HALF-ERR MOVE 'E' TO WS-ERROR-SEVERITY DISPLAY '3100-VALIDATE-RECORD: HALF-WIDTH FAIL' END-IF. *> *> R2: Character set check — extract digits, allow leading + MOVE SPACES TO WS-PHONE-DIGITS. MOVE ZERO TO WS-PHONE-DIGIT-COUNT. MOVE 'N' TO WS-HAS-LEADING-PLUS. PERFORM VARYING WS-IDX FROM 1 BY 1 UNTIL WS-IDX > 30 MOVE IN-TEXT(WS-IDX:1) TO WS-CHAR IF WS-CHAR = SPACE EXIT PERFORM END-IF IF WS-IDX = 1 AND WS-CHAR = '+' MOVE 'Y' TO WS-HAS-LEADING-PLUS CONTINUE END-IF IF WS-CHAR >= '0' AND WS-CHAR <= '9' ADD 1 TO WS-PHONE-DIGIT-COUNT MOVE WS-CHAR TO WS-PHONE-DIGITS(WS-PHONE-DIGIT-COUNT:1) ELSE IF WS-CHAR NOT = SPACE MOVE 'F' TO WS-V-FORMAT MOVE '02' TO WS-V-FORMAT-ERR MOVE 'E' TO WS-ERROR-SEVERITY END-IF END-IF END-PERFORM. ADD WS-PHONE-DIGIT-COUNT TO WS-TOTAL-DIGITS. ADD FUNCTION NUMVAL(WS-PHONE-DIGITS) TO WS-HASH-TOTAL ON SIZE ERROR ADD 1 TO WS-HASH-TOTAL END-ADD. *> *> R3: Determine phone type from prefix, validate length MOVE SPACES TO WS-PREFIX-STR. MOVE ZERO TO WS-PREFIX-LEN. IF WS-PHONE-DIGIT-COUNT >= 5 MOVE WS-PHONE-DIGITS(1:5) TO WS-PREFIX-STR MOVE 5 TO WS-PREFIX-LEN END-IF. MOVE 'U' TO WS-PHONE-TYPE. IF WS-PREFIX-LEN = 5 PERFORM VARYING WS-J FROM 1 BY 1 UNTIL WS-J > WS-MOBILE-PREFIX-COUNT IF WS-PREFIX-STR = WS-MOBILE-ITEM(WS-J) MOVE 'M' TO WS-PHONE-TYPE DISPLAY '3100-VALIDATE-RECORD: Mobile prefix: ' WS-PREFIX-STR EXIT PERFORM END-IF END-PERFORM IF WS-PHONE-TYPE = 'U' PERFORM VARYING WS-K FROM 1 BY 1 UNTIL WS-K > WS-LL-PREFIX-COUNT IF WS-PREFIX-STR = WS-LL-ITEM(WS-K) MOVE 'L' TO WS-PHONE-TYPE DISPLAY '3100-VALIDATE-RECORD: Landline ' 'prefix: ' WS-PREFIX-STR EXIT PERFORM END-IF END-PERFORM END-IF END-IF. *> *> R4: Length validation per phone type EVALUATE TRUE WHEN WS-PHONE-MOBILE IF WS-PHONE-DIGIT-COUNT NOT = 11 MOVE 'F' TO WS-V-LENGTH MOVE '03' TO WS-V-LENGTH-ERR MOVE 'E' TO WS-ERROR-SEVERITY DISPLAY '3100-VALIDATE-RECORD: LENGTH FAIL ' 'mobile expected 11 got ' WS-PHONE-DIGIT-COUNT END-IF WHEN WS-PHONE-LANDLINE IF WS-PHONE-DIGIT-COUNT < 10 OR WS-PHONE-DIGIT-COUNT > 12 MOVE 'F' TO WS-V-LENGTH MOVE '04' TO WS-V-LENGTH-ERR MOVE 'E' TO WS-ERROR-SEVERITY DISPLAY '3100-VALIDATE-RECORD: LENGTH FAIL ' 'landline expected 10-12 got ' WS-PHONE-DIGIT-COUNT END-IF WHEN WS-PHONE-UNKNOWN MOVE 'W' TO WS-ERROR-SEVERITY MOVE '05' TO WS-V-PREFIX-ERR DISPLAY '3100-VALIDATE-RECORD: PREFIX UNKNOWN for "' FUNCTION TRIM(IN-TEXT) '"' IF WS-PHONE-DIGIT-COUNT > 0 IF WS-PHONE-DIGIT-COUNT NOT >= 10 AND WS-PHONE-DIGIT-COUNT NOT <= 12 MOVE 'F' TO WS-V-LENGTH MOVE '06' TO WS-V-LENGTH-ERR MOVE 'E' TO WS-ERROR-SEVERITY END-IF END-IF END-EVALUATE. *> *> Compute content length — trim trailing spaces (original) MOVE 30 TO WS-TEXT-LEN. PERFORM VARYING WS-IDX FROM 30 BY -1 UNTIL WS-IDX = 0 IF IN-TEXT(WS-IDX:1) = SPACE SUBTRACT 1 FROM WS-TEXT-LEN ELSE EXIT PERFORM END-IF END-PERFORM. ADD WS-TEXT-LEN TO WS-TOTAL-CHARS. *> *> Apply original validation rules (preserved) MOVE SPACES TO WS-ERROR-CODE. IF NOT WS-ALL-HALF-YES MOVE '01' TO WS-ERROR-CODE ELSE IF WS-TEXT-LEN > 20 MOVE '02' TO WS-ERROR-CODE END-IF END-IF. *> *> Combine all rule results — priority: HALF > FORMAT > LENGTH IF WS-V-HALF-FAIL IF WS-ERROR-CODE = SPACES MOVE '01' TO WS-ERROR-CODE END-IF END-IF. IF WS-V-FORMAT-FAIL MOVE '07' TO WS-ERROR-CODE END-IF. IF WS-V-LENGTH-FAIL MOVE '08' TO WS-ERROR-CODE END-IF. IF WS-V-PREFIX-FAIL IF WS-ERROR-CODE = SPACES MOVE '09' TO WS-ERROR-CODE END-IF END-IF. IF WS-SEVERITY-ERROR ADD 1 TO WS-ERROR-COUNT END-IF. IF WS-SEVERITY-WARNING ADD 1 TO WS-WARN-COUNT END-IF. I3100-EXIT. EXIT. *> *> ============================================================ *> 3200-PROCESS-RECORD : Route to GOOD/BAD/SKIP *> ============================================================ 3200-PROCESS-RECORD SECTION. I3200-START. DISPLAY '3200-PROCESS-RECORD: error-code=' WS-ERROR-CODE ' severity=' WS-ERROR-SEVERITY. EVALUATE TRUE WHEN WS-ERROR-CODE = SPACES ADD 1 TO WS-GOOD-COUNT DISPLAY '3200-PROCESS-RECORD: -> GOOD' WHEN WS-SEVERITY-WARNING ADD 1 TO WS-WARN-COUNT ADD 1 TO WS-GOOD-COUNT DISPLAY '3200-PROCESS-RECORD: -> GOOD (warn)' WHEN WS-SEVERITY-ERROR ADD 1 TO WS-ERROR-COUNT ADD 1 TO WS-BAD-COUNT DISPLAY '3200-PROCESS-RECORD: -> BAD code=' WS-ERROR-CODE WHEN OTHER ADD 1 TO WS-SKIP-COUNT DISPLAY '3200-PROCESS-RECORD: -> SKIP' END-EVALUATE. EXIT. *> *> ============================================================ *> 3300-WRITE-OUTPUT : Write record to GOOD or BAD file *> ============================================================ 3300-WRITE-OUTPUT SECTION. I3300-START. IF WS-ERROR-CODE = SPACES MOVE IN-TEXT TO GOOD-TEXT WRITE GOOD-REC DISPLAY '3300-WRITE-OUTPUT: Wrote GOOD record' IF WS-FILE-GOOD-STATUS NOT = '00' MOVE 'E' TO WS-ERROR-SEVERITY MOVE '20' TO WS-ERROR-CODE STRING 'WRITE GOOD-REC failed, status=' WS-FILE-GOOD-STATUS INTO WS-ERROR-DETAIL PERFORM 6000-ERROR-HANDLE END-IF ELSE MOVE IN-TEXT TO BAD-TEXT MOVE WS-ERROR-CODE TO BAD-ERR-CODE WRITE BAD-REC DISPLAY '3300-WRITE-OUTPUT: Wrote BAD record code=' WS-ERROR-CODE IF WS-FILE-BAD-STATUS NOT = '00' MOVE 'E' TO WS-ERROR-SEVERITY MOVE '21' TO WS-ERROR-CODE STRING 'WRITE BAD-REC failed, status=' WS-FILE-BAD-STATUS INTO WS-ERROR-DETAIL PERFORM 6000-ERROR-HANDLE END-IF END-IF. EXIT. *> *> ============================================================ *> 4000-REPORT : Generate validation report *> ============================================================ 4000-REPORT SECTION. I4000-START. DISPLAY 'ValidationHalfwidth: 4000-REPORT starting...'. MOVE WS-GOOD-COUNT TO WS-ED-PASS. MOVE WS-BAD-COUNT TO WS-ED-FAIL. MOVE WS-SKIP-COUNT TO WS-ED-SKIP. MOVE WS-WARN-COUNT TO WS-ED-WARN. MOVE WS-ERROR-COUNT TO WS-ED-ERROR. MOVE WS-TOTAL-READ TO WS-ED-TOTAL. MOVE WS-HASH-TOTAL TO WS-ED-HASH. MOVE SPACES TO REPORT-LINE. STRING '=== VALIDATION REPORT ===' INTO REPORT-LINE. WRITE REPORT-REC. IF WS-FILE-REPORT-STATUS NOT = '00' DISPLAY '4000-REPORT: WRITE header failed, status=' WS-FILE-REPORT-STATUS END-IF. MOVE SPACES TO REPORT-LINE. STRING 'Timestamp: ' WS-TIMESTAMP INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'Records read : ' WS-ED-TOTAL INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'Records passed : ' WS-ED-PASS INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'Records failed : ' WS-ED-FAIL INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'Records skipped : ' WS-ED-SKIP INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'Warnings issued : ' WS-ED-WARN INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'Errors detected : ' WS-ED-ERROR INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'Total chars : ' WS-TOTAL-CHARS INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'Total digits : ' WS-TOTAL-DIGITS INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'Hash total : ' WS-ED-HASH INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'R1: Half-width check (X''20''-X''7E'')' INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'R2: Character set (digits 0-9, leading +)' INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'R3: Length (mobile=11, landline=10-12)' INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING 'R4: Prefix lookup (China mobile/landline)' INTO REPORT-LINE. WRITE REPORT-REC. MOVE SPACES TO REPORT-LINE. STRING '=== END OF REPORT ===' INTO REPORT-LINE. WRITE REPORT-REC. DISPLAY 'ValidationHalfwidth: 4000-REPORT complete'. EXIT. *> *> ============================================================ *> 5000-AUDIT : Write audit summary with timestamps *> ============================================================ 5000-AUDIT SECTION. I5000-START. DISPLAY 'ValidationHalfwidth: 5000-AUDIT starting...'. MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-TIME. STRING WS-CURR-YEAR '-' WS-CURR-MONTH '-' WS-CURR-DAY ' ' WS-CURR-HOUR ':' WS-CURR-MIN ':' WS-CURR-SEC INTO WS-TIMESTAMP. MOVE SPACES TO AUDIT-LINE. STRING '=== AUDIT LOG ===' INTO AUDIT-LINE. WRITE AUDIT-REC. IF WS-FILE-AUDIT-STATUS NOT = '00' DISPLAY '5000-AUDIT: WRITE header failed, status=' WS-FILE-AUDIT-STATUS END-IF. MOVE SPACES TO AUDIT-LINE. STRING 'Program: ValidationHalfwidth' INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Timestamp: ' WS-TIMESTAMP INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Records read : ' WS-TOTAL-READ INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Records good : ' WS-GOOD-COUNT INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Records bad : ' WS-BAD-COUNT INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Records skip : ' WS-SKIP-COUNT INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Warnings : ' WS-WARN-COUNT INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Errors : ' WS-ERROR-COUNT INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Hash total : ' WS-HASH-TOTAL INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Rules: HALF-FORMAT-LENGTH-PREFIX' INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Severity: W=Warning, E=Error' INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Input : file-in.dat' INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Output: file-out-good.dat' INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Output: file-out-bad.dat' INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Output: file-out-report.dat' INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING 'Output: file-out-audit.dat' INTO AUDIT-LINE. WRITE AUDIT-REC. MOVE SPACES TO AUDIT-LINE. STRING '=== END AUDIT ===' INTO AUDIT-LINE. WRITE AUDIT-REC. DISPLAY 'ValidationHalfwidth: 5000-AUDIT complete'. EXIT. *> *> ============================================================ *> 6000-ERROR-HANDLE : Centralized error handler *> WARNING: display and continue *> ERROR: display, close files, stop run *> ============================================================ 6000-ERROR-HANDLE SECTION. I6000-START. MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-TIME. STRING WS-CURR-HOUR ':' WS-CURR-MIN ':' WS-CURR-SEC INTO WS-TRACE-TS. EVALUATE TRUE WHEN WS-SEVERITY-WARNING DISPLAY '6000-ERROR-HANDLE: [' WS-TRACE-TS '] WARNING code=' WS-ERROR-CODE ' ' WS-ERROR-DETAIL ADD 1 TO WS-WARN-COUNT WHEN WS-SEVERITY-ERROR DISPLAY '6000-ERROR-HANDLE: [' WS-TRACE-TS '] ** ERROR ** code=' WS-ERROR-CODE ' ' WS-ERROR-DETAIL ADD 1 TO WS-ERROR-COUNT ADD 1 TO WS-BAD-COUNT DISPLAY 'ValidationHalfwidth: ABORTING' PERFORM 9000-EXIT WHEN OTHER DISPLAY '6000-ERROR-HANDLE: [' WS-TRACE-TS '] UNKNOWN severity=' WS-ERROR-SEVERITY END-EVALUATE. EXIT. *> *> ============================================================ *> 9000-EXIT : Close files, display summary, stop run *> ============================================================ 9000-EXIT SECTION. I9000-START. DISPLAY 'ValidationHalfwidth: 9000-EXIT closing files...'. CLOSE FILE-IN. IF WS-FILE-IN-STATUS NOT = '00' DISPLAY 'CLOSE FILE-IN status=' WS-FILE-IN-STATUS END-IF. CLOSE FILE-OUT-GOOD. IF WS-FILE-GOOD-STATUS NOT = '00' DISPLAY 'CLOSE FILE-OUT-GOOD status=' WS-FILE-GOOD-STATUS END-IF. CLOSE FILE-OUT-BAD. IF WS-FILE-BAD-STATUS NOT = '00' DISPLAY 'CLOSE FILE-OUT-BAD status=' WS-FILE-BAD-STATUS END-IF. CLOSE FILE-OUT-REPORT. IF WS-FILE-REPORT-STATUS NOT = '00' DISPLAY 'CLOSE FILE-OUT-REPORT status=' WS-FILE-REPORT-STATUS END-IF. CLOSE FILE-OUT-AUDIT. IF WS-FILE-AUDIT-STATUS NOT = '00' DISPLAY 'CLOSE FILE-OUT-AUDIT status=' WS-FILE-AUDIT-STATUS END-IF. MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-TIME. STRING WS-CURR-YEAR '-' WS-CURR-MONTH '-' WS-CURR-DAY ' ' WS-CURR-HOUR ':' WS-CURR-MIN ':' WS-CURR-SEC INTO WS-TIMESTAMP. DISPLAY ' '. DISPLAY '========================================'. DISPLAY 'ValidationHalfwidth: FINAL SUMMARY'. DISPLAY 'Batch ended: ' WS-TIMESTAMP. DISPLAY 'Records read : ' WS-TOTAL-READ. DISPLAY 'Records passed : ' WS-GOOD-COUNT. DISPLAY 'Records failed : ' WS-BAD-COUNT. DISPLAY 'Records skipped : ' WS-SKIP-COUNT. DISPLAY 'Warnings issued : ' WS-WARN-COUNT. DISPLAY 'Errors detected : ' WS-ERROR-COUNT. DISPLAY 'Total chars : ' WS-TOTAL-CHARS. DISPLAY 'Total digits : ' WS-TOTAL-DIGITS. DISPLAY 'Hash total : ' WS-HASH-TOTAL. DISPLAY '========================================'. MOVE SPACES TO AUDIT-LINE. STRING 'Batch ended: ' WS-TIMESTAMP INTO AUDIT-LINE. WRITE AUDIT-REC. DISPLAY 'ValidationHalfwidth: Done.'. STOP RUN. *> *> ============================================================ END PROGRAM ValidationHalfwidth.