feat: add benchmark-programs — 58 telecom COBOL test programs

作为子目录纳入系统,与核心测试管道协同

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
NB-076
2026-06-25 09:53:21 +08:00
parent 50f9f0f52f
commit 94400d50d4
278 changed files with 44125 additions and 0 deletions
@@ -0,0 +1 @@
@@ -0,0 +1,75 @@
# 27-validation-halfwidth: Half-Width Character Validation
## 电信业务场景
电话号码格式校验。检查电话号码字段是否全为半角数字(0-9),检测全角字符混入和长度超出。
## Description
Reads FILE-IN and validates that each character in IN-TEXT is
half-width (ASCII printable: X'20'-X'7E'). Validates length
constraints: 20 or fewer half-width characters pass; more than 20
is an error. Full-width characters or control characters cause
rejection.
## Validation Rules
| Rule | Result | Error Code |
|-----------------------------------|--------------|------------|
| All characters X'20'-X'7E', <= 20 | PASS to GOOD | - |
| Contains non-half-width character | FAIL to BAD | 01 |
| All half-width but >20 chars | FAIL to BAD | 02 |
## Record Layout
### Input / Good Output (30 bytes)
| Field | Type | Length | Description |
|--------|----------|--------|-------------|
| TEXT | PIC X | 30 | Text to validate |
### Bad Output (32 bytes)
| Field | Type | Length | Description |
|----------|----------|--------|----------------|
| TEXT | PIC X | 30 | Original text |
| ERR-CODE | PIC X | 2 | Error code |
## Files
| File | Purpose |
|-------------------------------|--------------------------------|
| main-27-validation-halfwidth.cbl | Main COBOL program |
| data-gen.sh | Generate test data |
| run.sh | Compile, run, verify |
| README.md | This file |
## Tests
| Test Case | Expected |
|----------------------------------|-----------------------------|
| 4 half-width chars | PASS to GOOD |
| 10 half-width chars | PASS to GOOD |
| 20 half-width chars (boundary) | PASS to GOOD |
| 25 half-width chars (too long) | FAIL err 02 |
| Mixed with full-width | FAIL err 01 |
| Full-width only | FAIL err 01 |
| Half-width + control char | FAIL err 01 |
| All spaces (empty) | PASS to GOOD |
## Usage
```bash
cd 27-validation-halfwidth
bash data-gen.sh
bash run.sh
```
## Expected Behavior
- Half-width check uses byte comparison against X'20'-X'7E'.
- Full-width UTF-8 multi-byte characters have bytes > X'7E'
and are detected as non-half-width.
- Length is computed by trimming trailing spaces.
- Only records meeting both conditions (half-width + <= 20 chars)
are written to GOOD output.
@@ -0,0 +1 @@
=== AUDIT LOG === Program: ValidationHalfwidth Timestamp: 2026-06-22 16:35:27 Records read : 000000001 Records good : 000000001 Records bad : 000000000 Records skip : 000000000 Warnings : 000000001 Errors : 000000000 Hash total : 000000000000000 Rules: HALF-FORMAT-LENGTH-PREFIX Severity: W=Warning, E=Error Input : file-in.dat Output: file-out-good.dat Output: file-out-bad.dat Output: file-out-report.dat Output: file-out-audit.dat === END AUDIT ===
@@ -0,0 +1 @@
@@ -0,0 +1 @@
=== VALIDATION REPORT === Timestamp: 2026-06-22 16:35:27 Records read : 1 Records passed : 1 Records failed : 0 Records skipped : 0 Warnings issued : 1 Errors detected : 0 Total chars : 000000000000000 Total digits : 000000000000000 Hash total : 0 R1: Half-width check (X'20'-X'7E') R2: Character set (digits 0-9, leading +) R3: Length (mobile=11, landline=10-12) R4: Prefix lookup (China mobile/landline) === END OF REPORT ===
@@ -0,0 +1,841 @@
*> ============================================================
*> 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.
@@ -0,0 +1,157 @@
*> ============================================================
*> main-validation-halfwidth : 电话号码校验 (Phone Validation)
*> Input : FILE-IN (INPUT.DAT: 电话号码文字列)
*> Output: FILE-PASS (PASS.DAT: 校验通过)
*> Coverage: VF-N005, VF-N006, VF-A001, VF-A002, VF-R001
*> ============================================================
IDENTIFICATION DIVISION.
PROGRAM-ID. VALIDATE-HALF.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT FILE-IN ASSIGN TO "INPUT.DAT"
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-FS.
SELECT FILE-PASS ASSIGN TO "PASS.DAT"
ORGANIZATION IS SEQUENTIAL.
SELECT FILE-FAIL ASSIGN TO "FAIL.DAT"
ORGANIZATION IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD FILE-IN RECORD CONTAINS 60 CHARACTERS.
01 IN-RECORD.
05 IN-ID PIC X(10).
05 IN-HALF20 PIC X(20).
05 IN-HALF4 PIC X(4).
05 IN-CHECK-TYPE PIC X(1).
05 IN-FILLER PIC X(25).
FD FILE-PASS RECORD CONTAINS 60 CHARACTERS.
01 PASS-REC PIC X(60).
FD FILE-FAIL RECORD CONTAINS 80 CHARACTERS.
01 FAIL-REC.
05 FAIL-ID PIC X(10).
05 FAIL-REASON PIC X(30).
05 FAIL-DATA PIC X(40).
WORKING-STORAGE SECTION.
01 WS-FS PIC X(2).
01 WS-EOF PIC X(1) VALUE 'N'.
88 WS-EOF-Y VALUE 'Y' FALSE 'N'.
01 WS-READ-COUNT PIC 9(10).
01 WS-PASS-COUNT PIC 9(10).
01 WS-FAIL-COUNT PIC 9(10).
01 WS-I PIC 9(2).
01 WS-CHAR PIC X(1).
01 WS-IS-HALF PIC X(1) VALUE 'Y'.
88 WS-IS-HALF-Y VALUE 'Y' FALSE 'N'.
01 WS-CHECK-20 PIC X(20).
01 WS-CHECK-4 PIC X(4).
01 WS-HALF-LOWER PIC X(26) VALUE 'abcdefghijklmnopqrstuvwxyz'.
01 WS-HALF-UPPER PIC X(26) VALUE 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
01 WS-HALF-DIGIT PIC X(10) VALUE '0123456789'.
01 WS-HALF-SYMBOL PIC X(33) VALUE ' !"#$%&''()*+,-./:;<=>?@[\]^_`{|}~'.
01 WS-TELECOM-REC.
COPY "telecom/TEL-BILLING.cpy".
PROCEDURE DIVISION.
MAIN.
DISPLAY "VALIDATE-HALF: Starting halfwidth validation"
OPEN INPUT FILE-IN.
OPEN OUTPUT FILE-PASS FILE-FAIL.
PERFORM UNTIL WS-EOF-Y
READ FILE-IN INTO IN-RECORD
AT END
SET WS-EOF-Y TO TRUE
NOT AT END
ADD 1 TO WS-READ-COUNT
MOVE IN-HALF20 TO WS-CHECK-20
PERFORM CHECK-HALF20
IF WS-IS-HALF-Y
MOVE IN-HALF4 TO WS-CHECK-4
PERFORM CHECK-HALF4
END-IF
IF WS-IS-HALF-Y
ADD 1 TO WS-PASS-COUNT
MOVE IN-RECORD TO PASS-REC
WRITE PASS-REC
DISPLAY "PASS: " IN-ID " - halfwidth OK"
ELSE
ADD 1 TO WS-FAIL-COUNT
MOVE IN-ID TO FAIL-ID
STRING "HALFWIDTH CHECK FAILED - data contains "
"non-halfwidth characters"
DELIMITED BY SIZE INTO FAIL-REASON
END-STRING
MOVE IN-HALF20 TO FAIL-DATA
WRITE FAIL-REC
DISPLAY "FAIL: " IN-ID " - non-halfwidth detected"
END-IF
END-READ
END-PERFORM.
CLOSE FILE-IN FILE-PASS FILE-FAIL.
DISPLAY "VALIDATE-HALF: READ=" WS-READ-COUNT
" PASS=" WS-PASS-COUNT " FAIL=" WS-FAIL-COUNT
DISPLAY "VALIDATE-HALF: Total = READ (R001)"
IF WS-READ-COUNT = WS-PASS-COUNT + WS-FAIL-COUNT
DISPLAY "VALIDATE-HALF: PASS"
STOP RUN RETURNING 0
ELSE
DISPLAY "VALIDATE-HALF: FAIL - count mismatch"
STOP RUN RETURNING 1
END-IF
.
CHECK-HALF20.
SET WS-IS-HALF TO TRUE
PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 20
MOVE WS-CHECK-20(WS-I:1) TO WS-CHAR
IF WS-CHAR = SPACE
CONTINUE
ELSE
IF WS-CHAR >= 'a' AND <= 'z'
CONTINUE
ELSE IF WS-CHAR >= 'A' AND <= 'Z'
CONTINUE
ELSE IF WS-CHAR >= '0' AND <= '9'
CONTINUE
ELSE
MOVE 'N' TO WS-IS-HALF
EXIT PERFORM
END-IF
END-IF
END-PERFORM
.
CHECK-HALF4.
SET WS-IS-HALF TO TRUE
PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 4
MOVE WS-CHECK-4(WS-I:1) TO WS-CHAR
IF WS-CHAR = SPACE
CONTINUE
ELSE
IF WS-CHAR >= 'a' AND <= 'z'
CONTINUE
ELSE IF WS-CHAR >= 'A' AND <= 'Z'
CONTINUE
ELSE IF WS-CHAR >= '0' AND <= '9'
CONTINUE
ELSE
MOVE 'N' TO WS-IS-HALF
EXIT PERFORM
END-IF
END-IF
END-PERFORM
.
END PROGRAM VALIDATE-HALF.