Written my program but I cannot get the right output as needed Below is my code and my input with the output.
Also does my procedure program make sense or should I revise it, it seems it makes sense but after looking at different books I'm not sure anymore.
FD INPUT-FILE.
01 INPUT-RECORD.
05 EXCUSE-NUMBER PIC 9(02).
88 VALID-EXCUSE VALUE 1 THRU 10.
05 FILLER PIC X(03).
05 NUMBER-TIMES-USED PIC 9(02).
05 FILLER PIC X(73).
FD REPORT-FILE.
01 REPORT-RECORD PIC X(80).
FD ERROR-FILE.
01 ERROR-RECORD PIC X(80).
WORKING-STORAGE SECTION.
******************************************************************
* DEFINES PROCESSINGVARIABLES AND OUTPUT LINES *
******************************************************************
01 WS-AREA.
05 WS-IF-STATUS PIC X(02).
05 WS-OF-STATUS PIC X(02).
05 WS-EF-STATUS PIC X(02).
05 WS-END-OF-FILE PIC X(01) VALUE "N".
88 AT-WS-END-OF-FILE VALUE "Y".
05 WS-INVALID-RECORD PIC X(01) VALUE "N".
05 WS-LINE-NUMBER PIC 9(03) VALUE 0.
05 WS-MOST-USED-EXCUSE PIC 9(02) VALUE 0.
05 WS-EXCUSE PIC 9(02) VALUE 0.
05 WS-EXCUSE-TOTAL PIC 9(04).
01 BLANK-LINE.
05 PIC X(80).
******************************************************************
* (THIS IS WHERE THE HEADING ON THE PRINT OUT SHEET GOES) *
******************************************************************
01 HEADING-LINE-1.
05 FILLER PIC X(14) VALUE SPACES.
05 FILLER PIC X(37)
VALUE "TEN MOST OUTRAGEOUS HOME-WORK EXCUSES".
01 HEADING-LINE-2.
05 FILLER PIC X(11).
05 FILLER PIC X(06) VALUE "RECORD".
05 FILLER PIC X(08).
05 FILLER PIC X(05) VALUE "IMAGE".
******************************************************************
* DETAIL-LINE COMMENTS. *
* on the detail line we are writing out the Data information *
* in particular, when we write out the line-number, error *
* excuse number, excuses used, and how many times used *
* Detail summary will be reported out *
* Stars will be Display underneath bad data. *
*****************************************************************
01 DETAIL-LINE.
05 FILLER PIC X(03).
05 DL-EXCUSE-NUMBER PIC 9(02).
05 FILLER PIC X(03).
05 DL-EXCUSE-USED PIC X(51).
05 FILLER PIC X(03).
05 DL-AMOUNT-USED PIC ZZ9.
01 DETAIL-LINE-ERROR-1.
05 FILLER PIC X(08) VALUE SPACES.
05 DLE-LINE-NUMBER PIC ZZ9.
05 FILLER PIC X(09) VALUE SPACES.
05 DLE-ERROR PIC X(16).
01 DETAIL-LINE-ERROR-2.
05 FILLER PIC X(20) VALUE SPACES.
05 DLE-EXCUSE-NUMBER PIC X(02) VALUE SPACES.
05 FILLER PIC X(03) VALUE SPACES.
05 DLE-EXCUSE PIC X(02) VALUE SPACES.
01 DETAIL-TOTAL.
05 FILLER PIC X(41) VALUE SPACES.
05 FILLER PIC X(20)
VALUE "TOTAL EXCUSES USED =".
05 DT-TOTAL PIC ZZZ9 VALUE ZERO.
01 DETAIL-TOTAL-MOST-USED.
05 FILLER PIC X(34) VALUE SPACES.
05 FILLER PIC X(27)
VALUE "EXCUSE USE THE MOST TIMES =".
05 DTMU-HIGH PIC ZZZ9.
******************************************************************
* This is where we hard code the excuses used with the table *
* from the input file. *
******************************************************************
01 TABLE-EXCUSES-1.
05 PIC X(51)
VALUE "JOHN CONVINCE ME TO CONVERT TO LINUX".
05 PIC X(51)
VALUE "BEACUSE OF SECURITY REASON I CAN'T CONFIRM NOR DENY".
05 PIC X(51)
VALUE "BECAUSE THE HOSPITAL DOESN'T HAVE WIFI'".
05 PIC X(51)
VALUE "AFTER INSTALLING LINUX MY SYSTEM CRASHED".
05 PIC X(51)
VALUE "WHAT WAS THE QUESTION AGAIN".
05 PIC X(51)
VALUE "ARE YOU SURE, I REMEBER TURNING IT IN".
05 PIC X(51)
VALUE "I'M INVOKING MY 5TH AMENDMENT RIGHT".
05 PIC X(51)
VALUE "LINUX MADE ME CRAZY I THREW MY COMPUTER".
05 PIC X(51)
VALUE "SOMEONE STOLED MY BACKPACK".
05 PIC X(51)
VALUE "BEACUSE OF SECURITY REASON I CAN'T CONFIRM NOR DENY".
01 TABLE-EXCUSES-2 REDEFINES TABLE-EXCUSES-1.
05 TEN-EXCUSES OCCURS 10 TIMES PIC X(51).
01 TABLE-EXCUSES-COUNTER.
05 TABLE-EXCUSES-COUNT OCCURS 10 TIMES PIC 9(03).
PROCEDURE DIVISION.
******************************************************************
* Finally - where the real work gets done *
* it is divided into paragraphs (or modules) generally called *
* from the main controlling module (here 1000-MAIN-CONTROL). *
* 1000-Main be the control module, *
* 2000-Initialize *
* 3000-Process *
* 4000-Finish *
******************************************************************
1000-MAIN.
OPEN INPUT INPUT-FILE
OUTPUT REPORT-FILE, ERROR-FILE
PERFORM 2000-INITIALIZE
PERFORM UNTIL AT-WS-END-OF-FILE
READ INPUT-FILE
AT END MOVE "Y" TO WS-END-OF-FILE
NOT AT END PERFORM 3000-PROCESS
END-READ
END-PERFORM
PERFORM 4000-FINISH
VARYING WS-EXCUSE
FROM 1 BY 1
UNTIL WS-EXCUSE > 10
MOVE WS-MOST-USED-EXCUSE TO DTMU-HIGH
MOVE WS-EXCUSE-TOTAL TO DT-TOTAL
WRITE REPORT-RECORD FROM BLANK-LINE
WRITE REPORT-RECORD FROM DETAIL-TOTAL
WRITE REPORT-RECORD FROM BLANK-LINE
WRITE REPORT-RECORD FROM DETAIL-TOTAL-MOST-USED.
CLOSE INPUT-FILE REPORT-FILE ERROR-FILE
STOP RUN.
2000-INITIALIZE.
INITIALIZE WS-EXCUSE
INITIALIZE TABLE-EXCUSES-COUNTER
WRITE ERROR-RECORD FROM HEADING-LINE-2
WRITE ERROR-RECORD FROM BLANK-LINE
WRITE REPORT-RECORD FROM HEADING-LINE-1
WRITE REPORT-RECORD FROM BLANK-LINE.
3000-PROCESS.
MOVE "N" TO WS-INVALID-RECORD
ADD 1 TO WS-LINE-NUMBER
IF NOT VALID-EXCUSE
MOVE INPUT-RECORD TO DLE-ERROR
MOVE WS-LINE-NUMBER TO DLE-LINE-NUMBER
MOVE "Y" TO WS-INVALID-RECORD
MOVE ALL "*" TO DLE-EXCUSE-NUMBER
END-IF.
IF WS-INVALID-RECORD = "N"
INSPECT EXCUSE-NUMBER REPLACING LEADING SPACES BY ZERO
IF EXCUSE-NUMBER IS NUMERIC
ADD EXCUSE-NUMBER TO TABLE-EXCUSES-COUNT(EXCUSE-NUMBER)
IF TABLE-EXCUSES-COUNT(EXCUSE-NUMBER) >
WS-MOST-USED-EXCUSE
MOVE TABLE-EXCUSES-COUNT(EXCUSE-NUMBER)
TO WS-MOST-USED-EXCUSE
END-IF
ADD NUMBER-TIMES-USED TO WS-EXCUSE-TOTAL
ELSE
MOVE "Y" TO WS-INVALID-RECORD
MOVE WS-LINE-NUMBER TO DLE-LINE-NUMBER
MOVE INPUT-RECORD TO DLE-ERROR
MOVE ALL "*" TO DLE-EXCUSE
END-IF
END-IF.
IF WS-INVALID-RECORD = "Y"
WRITE ERROR-RECORD FROM DETAIL-LINE-ERROR-1
WRITE ERROR-RECORD FROM DETAIL-LINE-ERROR-2
MOVE SPACES TO DETAIL-LINE-ERROR-1
MOVE SPACES TO DETAIL-LINE-ERROR-2
END-IF.
4000-FINISH.
MOVE WS-EXCUSE TO DL-EXCUSE-NUMBER
MOVE TEN-EXCUSES(WS-EXCUSE) TO DL-EXCUSE-USED
MOVE TABLE-EXCUSES-COUNT(WS-EXCUSE) TO DL-AMOUNT-USED
WRITE REPORT-RECORD FROM DETAIL-LINE
WRITE REPORT-RECORD FROM BLANK-LINE
MOVE SPACES TO DETAIL-LINE.
My output is as follow then follow by what it should be.
RECORD IMAGE
3 0r4000700 03
**
12 125999999 12
**
21 125000899 21
**
23 A01001111 23
**
Should be:
RECORD IMAGE
3 0r4000700 03
**
6 074000Q00 06
**
12 125999999 12
**
21 125000899 21
**
23 A01001111 23
**
You have two problems which is causing record number three to not appear with the correct error and record number six not to appear as an error at all.
I've indented your code to allow you to better see what is going on.
As usual, the compiler doesn't care, doesn't take note of indentation, so it is for humans. So do it. Indent. Often you'll see some of your own errors just by doing that.
IF NOT VALID-EXCUSE
MOVE INPUT-RECORD TO DLE-ERROR
MOVE WS-LINE-NUMBER TO DLE-LINE-NUMBER
MOVE "Y" TO WS-INVALID-RECORD
MOVE ALL "*" TO DLE-EXCUSE-NUMBER
END-IF
IF WS-INVALID-RECORD = "N"
INSPECT EXCUSE-NUMBER REPLACING LEADING SPACES BY ZERO
IF EXCUSE-NUMBER IS NUMERIC
ADD EXCUSE-NUMBER TO TABLE-EXCUSES-COUNT(EXCUSE-NUMBER)
IF TABLE-EXCUSES-COUNT(EXCUSE-NUMBER) >
WS-MOST-USED-EXCUSE
MOVE TABLE-EXCUSES-COUNT(EXCUSE-NUMBER)
TO WS-MOST-USED-EXCUSE
END-IF
ADD NUMBER-TIMES-USED TO WS-EXCUSE-TOTAL
ELSE
MOVE "Y" TO WS-INVALID-RECORD
MOVE WS-LINE-NUMBER TO DLE-LINE-NUMBER
MOVE INPUT-RECORD TO DLE-ERROR
MOVE ALL "*" TO DLE-EXCUSE
END-IF
END-IF
If we take record three first.
Your range-test on the 88 (good to use 88s, do it more) is this, in hexadecimal:
X'3031' through X'3130'.
This will work if the field is already known to be NUMERIC, but otherwise, since numbers appear before letters in ASCII, a whole slew of stuff you don't want gets treated as "valid". The value of 12 are rejected because they are large than 10 (X'3130'). Any letter, preceded by a zero, will be treated as valid, as will any control-code or any remaining value that happens to fit in the huge range of non-numeric values.
As Bruce Martin indicated, you need to know that the field is NUMERIC before applying that test.
IF EXCUSE-NUMBER NUMERIC
AND NOT VALID-EXCUSE
MOVE INPUT-RECORD TO DLE-ERROR
MOVE WS-LINE-NUMBER TO DLE-LINE-NUMBER
MOVE "Y" TO WS-INVALID-RECORD
MOVE ALL "*" TO DLE-EXCUSE-NUMBER
END-IF
That's become a little difficult for humans to read (the compiler doesn't mind). Bruce's suggestion for simplification (positive checks and CONTINUE
with ELSE
to catch the bad data) is a good one:
IF ( EXCUSE-NUMBER NUMERIC )
AND ( VALID-EXCUSE )
[all the good data goes here]
CONTINUE
ELSE
[leaving all the bad data here, ie both not numeric and
numeric but not in range]
MOVE INPUT-RECORD TO DLE-ERROR
MOVE WS-LINE-NUMBER TO DLE-LINE-NUMBER
MOVE "Y" TO WS-INVALID-RECORD
MOVE ALL "*" TO DLE-EXCUSE-NUMBER
END-IF
Note: You need the NUMERIC-plus-range when you are validating data. Once good data is in your system, range-checks will work "as expected" as there will be no intervening non-numeric data to spoil the plot.
You also get to do both types errors for EXCUSE-NUMBER at once, simplifying the following IF.
If you can have a leading blank in either field, you need to deal with that before any checking. You don't need to use INSPECT
.
With a two-byte field just REDEFINES so you can give the entire field as alpha-numeric a name, and first byte a name. Put 88s on those with a value of space. If the 88 is true, set that to zero (whole field, or byte, two tests):
IF 88-level
MOVE ZERO TO name-you've-given
END-IF
So far, record three has been treated as valid. Now it gets into your nested-IF
. It EXCUSE-NUMBER is not NUMERIC, so hits the ELSE
, where you have coding for the second field, . Because you didn't indent, this was obscured.
Record three has been rejected "by accident".
In the nested-IF, you meant to check NUMBER-TIMES-USED
for NUMERIC.
Which explains why record six does not appear as an error, because it's only fault is NUMBER-TIMES-USED not being NUMERIC, which your program currently doesn't notice.
You've also erroneously added EXCUSE-NUMBER instead of NUMBER-TIMES-USED.
IF WS-INVALID-RECORD = "N"
[stuff for leading space]
IF NUMBER-TIMES-USED IS NUMERIC
ADD NUMBER-TIMES-USED TO TABLE-EXCUSES-COUNT(EXCUSE-NUMBER)
IF TABLE-EXCUSES-COUNT(EXCUSE-NUMBER) >
WS-MOST-USED-EXCUSE
MOVE TABLE-EXCUSES-COUNT(EXCUSE-NUMBER)
TO WS-MOST-USED-EXCUSE
END-IF
ADD NUMBER-TIMES-USED TO WS-EXCUSE-TOTAL
ELSE
MOVE "Y" TO WS-INVALID-RECORD
MOVE WS-LINE-NUMBER TO DLE-LINE-NUMBER
MOVE INPUT-RECORD TO DLE-ERROR
MOVE ALL "*" TO DLE-EXCUSE
END-IF
END-IF
Be aware that the size of TABLE-EXCUSES-COUNT
is greater than the size of WS-MOST-USED-EXCUSE
. If you keep it like that, you will get unexpected behaviour when you have more than 99 of the same type of excuse.
Your nested-IF is a bit tortuous, and you have some repetition. Here's some simplification:
IF ( EXCUSE-NUMBER NUMERIC )
AND ( VALID-EXCUSE )
PERFORM CHECK-NUMBER-TIMES-USED
ELSE
PERFORM SET-STANDARD-REJECTION
MOVE ALL "*" TO DLE-EXCUSE-NUMBER
END-IF
...
CHECK-NUMBER-TIMES-USED.
IF 88-level-first-byte-space
MOVE ZERO TO name-you've-given-the-first-byte
END-IF
IF 88-level-field-space
MOVE ZERO TO field
END-IF
IF NUMBER-TIMES-USED IS NUMERIC
ADD NUMBER-TIMES-USED TO TABLE-EXCUSES-COUNT ( EXCUSE-NUMBER )
WS-EXCUSE-TOTAL
PERFORM CHECK-HIGHEST-EXCUSE-COUNT
ELSE
PERFORM SET-STANDARD-REJECTION
MOVE ALL "*" TO DLE-EXCUSE
END-IF
SET-STANDARD-REJECTION.
MOVE INPUT-RECORD TO DLE-ERROR
MOVE WS-LINE-NUMBER TO DLE-LINE-NUMBER
MOVE "Y" TO WS-INVALID-RECORD
.
CHECK-HIGHEST-EXCUSE-COUNT.
IF TABLE-EXCUSES-COUNT ( EXCUSE-NUMBER )
GREATER THAN WS-COUNT-OF-MOST-USED
MOVE TABLE-EXCUSES-COUNT ( EXCUSE-NUMBER )
TO WS-COUNT-OF-MOST-USED
MOVE EXCUSE-NUMBER TO WS-EXCUSE
END-IF
.
There's at least one more simplification when you get to the totals, but see how that goes.