Sie sind auf Seite 1von 57

Sequentially processing a file In WORKING-STORAGE you will need a field that will be used to indicate when the end

of file is reached. Trying to read beyond the end of a file is disastrous. Define a field similar to:
01 WS-END-OF-FILE-SW 88 WS-END-OF-FILE PIC X VALUE 'N'. VALUE 'Y'.

A skeleton of the PROCEDURE DIVISION will be similar to this:


PROCEDURE DIVISION. PERFORM 100-INITIALIZE. PERFORM 200-PROCESS-INPUT UNTIL WS-END-OF-FILE. PERFORM 900-TERMINATE. STOP RUN. * * * * * 100-INITIALIZE. THE FOLLOWING STATEMENT CAN BE USED TO OPEN ALL FILES OPEN INPUT INPUT-FILE. DO OTHER INITIALIZATION TASKS IN THIS PARAGRAPH, LIKE GETTING CURRENT DATE, INITIALIZING VARIABLES, ETC. THE PERFORM OF THE READ PARAGRAPH SHOULD BE THE LAST STATEMENT IN THIS PARAGRAPH. THIS IS THE PRIMING READ. PERFORM 110-READ-INPUT-FILE. 110-READ-INPUT-FILE. IF MULTIPLE INPUT FILES HAVE A SEPARATE READ PARAGRAPH FOR EACH. ALSO HAVE SEPARATE END-OF-FILE INDICATORS. READ INPUT-FILE AT END MOVE 'Y' TO WS-END-OF-FILE-SW END-READ. 200-PROCESS-INPUT. ENTER CODE HERE TO PROCESS THE INPUT DATA THE PERFORM OF THE READ PARAGRAPH SHOULD BE THE LAST STATEMENT IN THIS PARAGRAPH. PERFORM 110-READ-INPUT-FILE 900-TERMINATE. THE FOLLOWING STATEMENT CAN BE USED TO CLOSE ALL FILES CLOSE INPUT-FILE.

* *

* * *

Matching two files File matching is also known as co-sequential file processing, because multiple input files are being processed at once. All files must be sorted on the field(s) to be matched.

For example we have two input files, IN-ORDER and IN-CUSTOMER and we need to match them by customer number, a field appearing on both files. The basic logic will be similar to this:
PERFORM 200-READ-ORDER. PERFORM 210-READ-CUSTOMER. PERFORM 300-COMPARE UNTIL END-OF-CUSTOMER AND END-OF-ORDER. STOP RUN. 200-READ-ORDER. READ IN-ORDER AT END MOVE 'Y' TO END-OF-ORDER-SW MOVE HIGH-VALUES TO O-CUST-NBR END-READ. 210-READ-CUSTOMER. READ IN-ORDER AT END MOVE 'Y' TO END-OF-ORDER-SW MOVE HIGH-VALUES TO C-CUST-NBR END-READ. 300-COMPARE. IF O-CUST-NBR = C-CUST-NBR PERFORM P400-MATCH PERFORM P200-READ-ORDER PERFORM P210-READ-CUSTOMER ELSE IF O-CUST-NBR < C-CUST-NBR PERFORM P500-ORDER-W-NO-CUSTOMER PERFORM P200-READ-ORDER ELSE PERFORM P600-CUSTOMER-W-NO-ORDER PERFORM P210-READ-CUSTOMER END-IF END-IF.

Notes:

If one file can have multiple records matching a single record on the other file then that is the only file read after processing a match. In the above example if a customer can have multiple orders then after performing P400-MATCH do not perform P210-READ-CUSTOMER. Only read from the file that can contain multiple records with the same value for the field being matched. The purpose of setting the matched field to HIGH-VALUES upon end of file is prevent the other file from reaching a record with a higher value causing an attempted read beyond end-of-file. This algorithm can be extrapolated to allow for matching on multiple fields and for matching three or more files though it gets complicated quickly. Normally,

when matching more than two files multiple programs are used, each matching two files. Sorting a file Sorting a file requires defining two files in addition to the input (unsorted) file: the sorted file and a work file. Each requires a SELECT statement. The sorted file requires an FD and the work file requires an SD. SDs (Sort file Description) are just like FDs but cannot have a LABELS clause.
SELECT IN-FILE ASSIGN TO DISK. SELECT SORTED-FILE ASSIGN TO DISK. SELECT SORT-WORK ASSIGN TO DISK. FD 01 FD IN-FILE VALUE OF FILE-ID IS 'PAYROLL-FILE'. IN-RECORD PIC X(200).

SORTED-FILE VALUE OF FILE-ID IS 'SORTED-PAYROL-FILE'. 01 SORTED-RECORD PIC X(200). ONLY NEED TO DEFINE THE FIELDS THAT THE FILE WILL BE SORTED ON. BUT ACCOUNT FOR THE ENTIRE RECORD. SORT-WORK VALUE OF FILE-ID IS 'TEMP-1'. SORT-RECORD. 05 SR-EMPLOYEE PIC 9(09). 05 PIC X(21). 05 SR-REGION PIC X(03). 05 PIC X(87). 05 SR-DEPT PIC 9(02). 05 PIC X(78).

* * SD 01

The above SD has prepared us to sort on the employee number, region and department number. Let's sort on region first, then department and then employee. One COBOL statement will do the trick. The SORT statement will read the entire input file and sort it. You will use the sorted file as input to the rest of the program. Treat it as any other input file (read it, check for end of file, close it, etc.). Normally, the sort is done during program initialization but this depends on processing needs.
SORT SORT-WORK ON ASCENDING KEY SR-REGION ON ASCENDING KEY SR-DEPT ON ASCENDING KEY SR-EMPLOYEE USING IN-FILE GIVING SORTED-FILE. * SOME COMPILERS CLOSE THE FILE AFTER THE SORT, SOME DO NOT. * YOU MAY OR MAY NOT HAVE TO OPEN IT BEFORE CONTINUING.

OPEN INPUT SORTED-FILE. PERFORM UNTIL WS-EOF-SW = 'Y' READ SORTED-FILE AT END MOVE 'Y' TO WS-EOF-SW NOT AT END PERFORM 200-PROCESS END-READ END-PERFORM. CLOSE SORTED-FILE. STOP RUN.

As an alternative to specifying input and output files in the SORT you can instead specify an INPUT PROCEDURE or OUTPUT PROCEDURE, paragraphs to execute before and after the sort takes place.
SORT SORT-WORK ON ASCENDING KEY SR-REGION ON ASCENDING KEY SR-DEPT ON ASCENDING KEY SR-EMPLOYEE INPUT PROCEDURE 100-PRE-SORT OUTPUT PROCEDURE 200-POST-SORT. 100-PRE-SORT. OPEN INPUT IN-FILE. PERFORM UNTIL WS-EOF-SW = 'Y' READ IN-FILE AT END MOVE 'Y' TO WS-EOF-SW NOT AT END PERFORM 110-PROCESS END-READ END-PERFORM. CLOSE IN-FILE. 110-PROCESS. MOVE IN-RECORD TO SORT-RECORD. * ONLY SORT RECORDS WITH NON-ZERO DEPARTMENT NUMBER IF SR-DEPT NOT EQUAL ZEROES RELEASE SORT-RECORD END-IF. 200-POST-SORT. OPEN INPUT SORT-FILE. MOVE 'N' TO WS-EOF-SW. PERFORM UNTIL WS-EOF-SW = 'Y' RETURN SORT-FILE AT END MOVE 'Y' TO WS-EOF-SW NOT AT END PERFORM 300-PROCESS

END-READ END-PERFORM. CLOSE SORT-FILE.

Generating a report In WORKING-STORAGE define something similar to this (the lines per page will depend on the installation. Initialize the line number to the same value as lines per page to trigger the printing of headings for the first page):
01 WS-REPORT-VALUES. 05 WS-PAGE-NBR 05 WS-LINE-NBR 05 WS-LINES-PER-PAGE PIC 9(4). PIC 99 VALUE 66. PIC 99 VALUE 66.

Also in WORKING-STORAGE define separate records for each page heading line, each column heading line, each detail line and any total lines. The record layout in the FD for the report file should not contain any fields, only the record name and a PIC X big enough to hold any of the heading or detail records plus 1 character. If there are to be totals produced for the report then an accumulator field for each total must also be defined in WORKING-STORAGE (make sure it's big enough). Most reports contain the current date in one of the page headings. If so, get the current date in the program's initialization paragraph and store it on the page heading record. Do not get the current date every time the headings are printed. If your detail lines require special initializations before they are printed then call that paragraph during the program's initialization paragraph. While processing an input record you will be moving data to the detail line. At the end of the processing loop, but before reading the next input record, call the print detail line paragraph (the detail line now has all of the data that will be printed).
8000-PRINT-DETAIL. IF ANY OF THE FIELDS ON THE DETAIL LINE ARE TO BE TOTALLED THEN ADD ITS VALUE TO THE ACCUMULATING FIELD HERE, BEFORE ANYTHING IS PRINTED. ADD 1 TO WS-LINE-NBR. IF WS-LINE-NBR > WS-LINES-PER-PAGE PERFORM 8100-PRINT-HEADINGS END-IF. WRITE OT-REPORT-RECORD FROM WS-DETAIL-RECORD AFTER ADVANCING 1 LINE END-WRITE. * IF THE DETAIL LINES ARE NOT TO BE SINGLE SPACED THEN CHANGE * THE NUMBER OF LINES TO ADVANCE IN PREVIOUS WRITE AND ALSO THE * VALUE IN THE FOLLOWING ADD TO REFLECT DESIRED SPACING. ADD 1 TO WS-LINE-NBR. * IF YOUR DETAIL LINES REQUIRE SPECIAL INITIALIZATIONS THEN CALL * THAT PARAGRAPH AT THE END OF THIS PARAGRAPH * * *

8100-PRINT-HEADINGS. ADD 1 TO WS-PAGE-NBR * MOVE ANY FIELDS THAT ARE PART OF THE PAGE HEADINGS TO THE * PAGE HEADING RECORDS NOW (LIKE THE PAGE NUMBER). WRITE OT-REPORT-RECORD FROM WS-PAGE-HDR-1-RECORD AFTER PAGE END-WRITE. * INCLUDE SIMILAR WRITES FOR ALL REMAINING PAGE HEADING RECORDS AND * COLUMN HEADING RECORDS - EACH ADVANCING THE PROPER NUMBER OF LINES * TO REFLECT DESIRED SPACING (SINGLE, DOUBLE, ETC.). * * THE WS-LINE-NBR FIELD WILL NEED POPULATED WITH A VALUE INDICATING * HOW MANY LINES HAVE BEEN PRINTED ON THE PAGE DURING THIS PARAGRAPH, * INCLUDING SPACING. MOVE literal TO WS-LINE-NBR.

If any totals were accumulated during the generation of the report then call the paragraph to print the total line(s) from the program's termination paragraph (before you close the report file). Handling an empty report It is often valid for a report to have no data. Either the input file is empty (not necessarily a problem) or the input file has no records meeting whatever criteria is necessary in order to get printed on the report. The problem is that in such cases nothing comes out of the program, not even the headings (In the algorithm above the 1st headings aren't printed until the 1st detail line is built). How does the user know that the report is empty and there wasn't some problem that crashed the program? A common practice is to print a descriptive message on the report signifying that there was no data to print so that the end user knows that this was the case. Such a message needs defined in WORKING-STORAGE:
01 WS-DETAIL-0. 05 05 05 PIC X(54) VALUE SPACES. PIC X(24) VALUE '*** NO DATA TO PRINT ***'. PIC X(54) VALUE SPACES.

In the program's termination paragraph check the value of the page number field. If it is still zero then you haven't printed any detail records. Call the paragraph to print the page headings, then print the message to signify that there was no data print. If printing totals on the report then have the call to that paragraph as an 'ELSE' to the 'IF WS-PAGE-NBR = 0'.

Control Breaks on a report

In WORKING-STORAGE define fields to hold the current values of each field that is a control field. They must be defined exactly as the corresponding input fields are defined. Initialize them to ZEROS if numeric, LOW-VALUES if alphanumeric. Special processing is done whenever the value of a control field changes. Totals must be produced for the previous control group, fields must be initialized for the new control group and possibly some headings or a new page for the new control group. Checks for control break processing are done immediately after a record is read. Compare the value of the control field on the input record to the value in the hold field. If different then call the paragraph that handles control break processing. In WORKING-STORAGE:
01 WS-CONTROL-FIELDS. 05 WS-HOLD-DEPARTMENT 05 WS-FIRST-BREAK-SW 88 WS-FIRST-BREAK PIC X(03) VALUE LOW-VALUES. PIC X VALUE 'Y'. VALUE 'Y'.

In the PROCEDURE DIVISION:


2000-READ-INPUT-RECORD. READ INPUT-FILE AT END MOVE 'Y' TO WS-END-OF-FILE-SW NOT AT END PERFORM 2100-CHECK-FOR-BREAK END-READ. 2100-CHECK-FOR-BREAK. IF IN-DEPARTMENT NOT = WS-HOLD-DEPARTMENT * IF THERE WAS NO PREVIOUS CONTROL GROUP THEN DON'T TRY TO TOTAL * ANYTHING OR PRINT TOTAL LINE(S). IF WS-FIRST-BREAK MOVE 'N' TO WS-FIRST-BREAK-SW ELSE PERFORM 8100-TOTAL-PREVIOUS-GROUP END-IF * BOTH OF THE FOLLOWING PROCESSING MAY NOT BE NECESSARY PERFORM 8200-INITIALIZE-FOR-NEW-GROUP PERFORM 8300-HEADINGS-NEW-GROUP MOVE IN-DEPARTMENT TO WS-HOLD-DEPARTMENT END-IF.

The above code is for a single-level control break. Multiple-level control breaks take more care. The control fields will be ordered (i.e. break on salesperson within a region). Hold fields must be defined for each control fields. It may also be easier (and cleaner) to have separate paragraphs for totalling and headings for each control field. When checking for changes in the control fields start with the major field and then work your way to the most minor field (i.e. if the breaks were 'a' within 'b' within 'c' within 'd' within 'e' check field 'e' first, then 'd', etc.). A control break in a field implies a break in all fields minor to

the one with the break. Ensure all the control break processing that needs to be executed actually happens and happens in the correct order. Loading a table from a file We have a file containing part numbers and descriptions. Each record contains a 9-digit part number and a 41-byte description. This file is to be loaded into a table to be crossreferenced with a part number on another file. Since we want the entire table to be ready when we start processing our primary input file the table will be loaded, in its entirity, during program initialization.
FD 01 PART-MASTER. PART-MASTER-REC. 05 IN-PART-NBR 05 IN-PART-DESC

PIC 9(9). PIC X(41).

(In working storage) 01 FILLER. 05 PART-TABLE 10 PART-NBR 10 PART-DESC WS-EOF-SW 88 END-OF-FILE 88 TBL-OVERFLOW WS-SUB WS-TBL-MAX OCCURS 100 TIMES. PIC 9(9). PIC X(41). PIC X VALUE 'N'. VALUE 'Y'. VALUE 'F'.

01 01 01

PIC 999. PIC 999 VALUE 100.

(To load table from file) P100-LOAD-TABLE. OPEN INPUT PART-MASTER. MOVE 0 TO WS-SUB. PERFORM UNTIL END-OF-FILE OR TBL-OVERFLOW READ PART-MASTER AT END SET END-OF-FILE TO TRUE NOT AT END PERFORM P110-ADD-ENTRY END-READ END-PERFORM. CLOSE PART-MASTER. IF TBL-OVERFLOW DISPLAY 'ERROR: PART TABLE OVERFLOW!!!!' DISPLAY 'PROGRAM ENDING...' STOP RUN END-IF. P110-ADD-ENTRY. ADD 1 TO WS-SUB. IF WS-SUB > WS-TBL-MAX

SET TBL-OVERFLOW TO TRUE ELSE MOVE PART-MASTER-REC TO PART-TABLE (WS-SUB) END-IF.

Searching a table Now that the table has been populated with values using the previous algorithm let's try to use this table. The primary input file to this program (the sales file) contains, among other things, a part number. This is to be printed on a sales report along with the description of the part. The description is not kept on the sales file so the table is needed. A file matching algorithm is not used becuase that would require the sales file to be sorted by part number and it is doubtful that we would want it that way on the report. There are many ways to do this. If the table were indexed the SEARCH command could be used. The following is not using the SEARCH statement:
PERFORM P200-READ-SALES-FILE. MOVE '*** NO PART DESCRIPTION' TO RPT-DTL-PART-DESC. PERFORM VARYING WS-SUB FROM 1 BY 1 UNTIL (WS-SUB > WS-TBL-MAX) OR (IN-PRT-NBR = PART-NBR (WS-SUB)) IF IN-PRT-NBR = PART-NBR (WS-SUB) MOVE PART-DESC TO RPT-DTL-PART-DESC END-IF END-PERFORM. (if the table was defined as INDEXED BY WS-INDX) PERFORM P200-READ-SALES-FILE. SET WS-INDX TO 1. SEARCH PART-TABLE AT END MOVE '*** NO PART DESCRIPTION' TO RPT-DTL-PART-DESC WHEN IN-PRT-NBR = PART-NBR (WS-INDX) MOVE PART-DESC TO RPT-DTL-PART-DESC END-SEARCH.

Using relative files The SELECT for relative files requires the following clauses:
ORGANIZATION IS RELATIVE ACCESS IS DYNAMIC RELATIVE KEY IS working-storage-field-1 FILE STATUS IS working-storage-field-2.

working-storage-field-1 must be numeric, working-storage-field-2 is a PIC X(2).

Before a read or write the relative key must be populated with a value by the program. This is basically a record number. When a read is executed the value of the relative key directs the system to attempt a retrieval of that particular record (if relative key is 5 then the system will try to retrieve a record from the 5th slot in the file). If a write is executed then the system will attempt to place a record in that slot. The value of the file status after the statement is executed will indicate whether or not the statement successfully executed. If not, the value will also indicate what went wrong. This field can be interrogated with an IF or EVALUATE:
SELECT IN-MASTER ORGANIZATION IS RELATIVE ACCESS IS DYNAMIC RELATIVE KEY IS WS-RELATIVE-KEY FILE STATUS IS WS-FILE-STATUS. . . . . . . MOVE WS-REL-ADDR TO WS-RELATIVE-KEY. READ IN-MASTER. EVALUATE WS-FILE-STATUS WHEN '00' PERFORM 300-SUCCESSFUL-READ WHEN '23' PERFORM 400-RECORD-SLOT-IS-EMPTY WHEN '92' DISPLAY 'FILE NOT OPEN' WHEN OTHER DISPLAY 'UNEXPECTED FILE ERROR: ' WS-FILE-STATUS END-EVALUATE.

See the File Errors Page for a list of file status values and their meanings. As an alternative the INVALID KEY clause can be used:
MOVE WS-REL-ADDR TO WS-RELATIVE-KEY. READ IN-MASTER INVALID KEY PERFORM 400-RECORD-SLOT-IS-EMPTY NOT INVALID KEY PERFORM 300-SUCCESSFUL-READ END-READ.

This lumps all unsuccessful operations into one group so this may not be an appropriate method. Writes work similarly:
SELECT OT-MASTER ORGANIZATION IS RELATIVE ACCESS IS DYNAMIC

RELATIVE KEY IS WS-RELATIVE-KEY FILE STATUS IS WS-FILE-STATUS. . . . . . . MOVE WS-REL-ADDR TO WS-RELATIVE-KEY. WRITE OT-MASTER-RECORD. EVALUATE WS-FILE-STATUS WHEN '00' ADD +1 TO WS-NBR-RECORDS-WRITTEN WHEN '22' PERFORM 500-SLOT-ALREADY-USED WHEN '92' DISPLAY 'FILE NOT OPEN' WHEN OTHER DISPLAY 'UNEXPECTED FILE ERROR: ' WS-FILE-STATUS END-EVALUATE.

Writes also support INVALID KEY/NOT INVALID KEY. Relative files can be accessed as if they were sequential files. In the SELECT change the ACCESS IS DYNAMIC to ACCESS IS SEQUENTIAL. Can then use READs (include AT END) and WRITEs as if the file was sequential. Do not specify a RELATIVE KEY or a FILE STATUS. Relative files support two other type of operations, but these require the file to be opened for input and output at the same time. Access cannot be sequential. These operations are DELETE and REWRITE. The DELETE statement will delete the current record. This requires a successful READ before the DELETE.
OPEN I-O IN-MASTER. . . . . . . MOVE WS-REL-ADDR TO WS-RELATIVE-KEY. READ IN-MASTER. EVALUATE WS-FILE-STATUS . . . END-EVALUATE. DELETE IN-MASTER RECORD. EVALUATE WS-FILE-STATUS WHEN '00' PERFORM 200-SUCCESSFUL-DELETE WHEN '43' DISPLAY ' NO CURRENT RECORD. REL KEY = ' WS-RELATIVE-KEY . . . END-EVALUATE.

The REWRITE statement will update the current record. This requires a successful READ before the REWRITE.
OPEN I-O IN-MASTER. . . . . . . MOVE WS-REL-ADDR TO WS-RELATIVE-KEY. READ IN-MASTER. EVALUATE WS-FILE-STATUS . . . END-EVALUATE. * IF THE READ WAS SUCCESSFUL YOU WILL UPDATE WHATEVER FIELDS ON THE * RECORD WITH THEIR NEW VALUES AT THIS POINT REWRITE IN-MASTER-RECORD. EVALUATE WS-FILE-STATUS . . . END-EVALUATE.

Note that READ and DELETE use the file name; WRITE and REWRITE use the record name. DELETE uses the word 'RECORD' after the file name, do not connect it to the file name with a hyphen. REWRITE will not change the number of records in a file, it only alters the data in an existing record. All these statements support the INVALID KEY/NOT INVALID KEY clauses. Using indexed files The SELECT for indexed files requires the following clauses:
ORGANIZATION IS INDEXED ACCESS IS DYNAMIC RECORD KEY IS field-1 FILE STATUS IS working-storage-field-2.

With indexed files, the key is actually part of the record. No two records on the same file can have the same value for this key; the key must uniquely identify the record. workingstorage-field-2 is a PIC X(2). Before a read or write the record key must be populated with a value by the program. When a read is executed the index of the file is searched for the value of the record key. If the record is in the file then a matching entry will be in the index. If a write is executed then the system will ensure that the file doesn't already contain a record for that key. The value of the file status after the statement is executed will indicate whether or not the statement successfully executed. If not, the value will also indicate what went wrong. This field can be interrogated with an IF or EVALUATE:
SELECT IN-MASTER

ORGANIZATION IS INDEXED ACCESS IS DYNAMIC RECORD KEY IS IN-CUSTOMER-NBR FILE STATUS IS WS-FILE-STATUS. . . . . . . MOVE WS-CUST-NO TO IN-CUSTOMER-NBR. READ IN-MASTER. EVALUATE WS-FILE-STATUS WHEN '00' PERFORM 300-SUCCESSFUL-READ WHEN '23' PERFORM 400-RECORD-NOT-FOUND WHEN '92' DISPLAY 'FILE NOT OPEN' WHEN OTHER DISPLAY 'UNEXPECTED FILE ERROR: ' WS-FILE-STATUS END-EVALUATE.

See the File Errors Page for a list of file status values and their meanings. As an alternative the INVALID KEY clause can be used:
MOVE WS-CUST-NO TO IN-CUSTOMER-NBR. READ IN-MASTER INVALID KEY PERFORM 400-RECORD-NOT-FOUND NOT INVALID KEY PERFORM 300-SUCCESSFUL-READ END-READ.

This lumps all unsuccessful operations into one group so this may not be an appropriate method. Writes work similarly:
SELECT OT-MASTER ORGANIZATION IS INDEXED ACCESS IS DYNAMIC RECORD KEY IS OT-CUSTOMER-NBR FILE STATUS IS WS-FILE-STATUS. . . . . . . MOVE WS-CUST-NO TO OT-CUSTOMER-NBR. WRITE OT-MASTER-RECORD. EVALUATE WS-FILE-STATUS WHEN '00' ADD +1 TO WS-NBR-RECORDS-WRITTEN WHEN '22' PERFORM 500-RECORD-ALREADY-EXISTS

WHEN '92' DISPLAY 'FILE NOT OPEN' WHEN OTHER DISPLAY 'UNEXPECTED FILE ERROR: ' WS-FILE-STATUS END-EVALUATE.

Writes also support INVALID KEY/NOT INVALID KEY. Indexed files can be accessed as if they were sequential files. In the SELECT change the ACCESS IS DYNAMIC to ACCESS IS SEQUENTIAL. Can then use READs (include AT END) and WRITEs as if the file was sequential. Do not specify a RECORD KEY or a FILE STATUS. Indexed files support two other type of operations, but these require the file to be opened for input and output at the same time. Access cannot be sequential. These operations are DELETE and REWRITE. The DELETE statement will delete the current record. This requires a successful READ before the DELETE.
OPEN I-O IN-MASTER. . . . . . . MOVE WS-CUST-NO TO IN-CUSTOMER-NBR. READ IN-MASTER. EVALUATE WS-FILE-STATUS . . . END-EVALUATE. DELETE IN-MASTER RECORD. EVALUATE WS-FILE-STATUS WHEN '00' PERFORM 200-SUCCESSFUL-DELETE WHEN '43' DISPLAY ' NO CURRENT RECORD. REL KEY = ' WS-RELATIVE-KEY . . . END-EVALUATE.

The REWRITE statement will update the current record. This requires a successful READ before the REWRITE.
OPEN I-O IN-MASTER. . . . . . . MOVE WS-CUST-NO TO IN-CUSTOMER-NBR. READ IN-MASTER. EVALUATE WS-FILE-STATUS . . . END-EVALUATE.

* IF THE READ WAS SUCCESSFUL YOU WILL UPDATE WHATEVER FIELDS ON THE * RECORD WITH THEIR NEW VALUES AT THIS POINT REWRITE IN-MASTER-RECORD. EVALUATE WS-FILE-STATUS . . . END-EVALUATE.

Note that READ and DELETE use the file name; WRITE and REWRITE use the record name. DELETE uses the word 'RECORD' after the file name, do not connect it to the file name with a hyphen. REWRITE will not change the number of records in a file, it only alters the data in an existing record. All these statements support the INVALID KEY/NOT INVALID KEY clauses. Using indexed files with alternate keys An indexed file can have more than one key (a multi-key file). There will be one key designated as the primary key, all other keys are secondary, or alternate, keys. Alternate keys do not have to be unique within the file, primary keys do. The SELECT for such a file still requires the RECORD KEY clause (which identifies the primary key). Immediately following the RECORD KEY clause are any ALTERNATE KEY clauses. Any alternate keys that are used in the program are listed here. If an alternate key does not have to be unique specify it WITH DUPLICATES. All alternate keys must be part of the record.
SELECT IN-RENTAL-CAR-MASTER ORGANIZATION IS INDEXED ACCESS IS DYNAMIC RECORD KEY IS IN-LICENSE ALTERNATE KEY IS IN-VIN ALTERNATE KEY IS IN-STYLE WITH DUPLICATES ALTERNATE KEY IS IN-MFR WITH DUPLICATES FILE STATUS IS WS-FILE-STATUS.

When the file is opened the access path defaults to that of the primary key. To use an access path of one of the alternate keys, use the START command. You first prime the alternate key field with some value that you want to start with. You then execute a START with either 'EQUALS', 'NOT <' or '>'. For example:
MOVE 'HONDA' TO IN-MFR. START IN-RENTAL-CAR-MASTER KEY NOT < IN-MFR END-START.

This will change the access path to that of the alternate key IN-MFR and then position the file pointer so that it is at the first record whose key is equal to or greater than the specified value.

MOVE SPACES TO IN-VIN. START IN-RENTAL-CAR-MASTER KEY > IN-VIN END-START.

This one changes the access path to that of IN-VIN. The record pointer here is set to the first record in the file with an IN-VIN value higher than that of the specified value.
MOVE 'MIDSIZE' TO IN-STYLE. START IN-RENTAL-CAR-MASTER KEY EQUALS IN-STYLE END-START.

This one changes the access path to that of IN-STYLE. The record pointer here is set to the first record in the file with an IN-STYLE that matches that of the specified value. The file status needs to be checked after the START, or the INVALID KEY clause used. One cause of an unsuccessful START is if no such record can be found in the file. The START NOT < and START > do not actually read a record, even if the START was successful in postioning the file pointer. The READ NEXT statement can then be used to read records along the current access path. The file status must be checked after each READ NEXT or the INVALID KEY clause used. One common cause of an unsuccessful READ NEXT is reaching the end of the file. AT END can also be used.
* GET MANUFACTURER FROM KEYBOARD DISPLAY 'ENTER CAR MANUFACTURER: ' WITH NO ADVANCING. ACCEPT WS-MFR. MOVE WS-MFR TO IN-MFR. * ATTEMPT TO START FILE AT SPECIFIED MANUFACTURER START IN-RENTAL-CAR-MASTER KEY NOT < IN-MFR INVALID KEY DISPLAY 'NO RECORDS ON FILE FOR ' WS-MFR NOT INVALID KEY PERFORM 300-READ-NEXT-ON-MFR END-START. PERFORM 300-READ-NEXT-ON-MFR UNTIL WS-EOF-SW = 'Y'. . . . 300-READ-NEXT-ON-MFR. READ IN-RENTAL-CAR-MASTER NEXT RECORD AT END MOVE 'Y' TO WS-EOF-SW NOT AT END PERFORM 310-CHECK-MFR END-READ. 310-CHECK-MFR. IF IN-MFR = WS-MFR

DISPLAY 'CAR FOUND FOR MFR ' WS-MFR ' LICENSE ' IN-LICENSE ELSE MOVE 'Y' TO WS-EOF-SW END-IF.

Calling one program from another In these examples we will have PROGRAM1 call PROGRAM2. The first example shows a static call. PROGRAM2 is compiled into PROGRAM2.OBJ.
CALL 'PROGRAM2.OBJ'.

PROGRAM2 requires either a 'GOBACK' or 'EXIT PROGRAM' in order for control to return to PROGRAM1. A 'STOP RUN' will terminate all programs. When a program containing static calls is compiled the object code of all statically called programs is combined with the object code of the program with the calls into one package. The advantage is that the object code of called programs need not be present when the program is run, all object code is included in the one package. The disadvantage with this is that if one of the called programs is changed any program that statically calls it must be re-compiled so that the new version is included. The other type of call is a dynamic call. When a dynamic call is executed the object code for the called program is searched for on disk (it is not part of the calling program's object code) and then executed. The advantage is that the newest version of the called program is always executed - no need to re-compile the calling program. To change this to a dynamic call add the following to PROGRAM1's WORKINGSTORAGE SECTION. PROGRAM2.OBJ must exist when PROGRAM1 is run.
01 WS-CALLED-PGM PIC X(12) VALUE 'PROGRAM2.OBJ'.

The CALL now looks like:


CALL WS-CALLED-PGM.

Static calls have the called program as a literal in the call, dynamic calls have a field. The value of that field is the name of the called program. Passing some fields from PROGRAM1 to PROGRAM2 requires a little more work. First, only WORKING-STORAGE fields from PROGRAM1 can be passed to PROGRAM2. These fields are specfied in the CALL as follows:
CALL 'PROGRAM2.OBJ' USING WS-FIELD-1 WS-FIELD-2 WS-FIELD-3 WS-FIELD-4 WS-FIELD-5 END-CALL.

This can be done with either static or dynamic calls. Group-level fields can be passed so if all 5 of the above fields were under the same group-level field you could just specify it in the CALL. PROGRAM2 needs to know some fields are coming in. This is done on the PROCEDURE DIVISION statement of PROGRAM2:
PROCEDURE DIVISION USING LK-FIELD-A LK-FIELD-B LK-FIELD-C LK-FIELD-D LK-FIELD-E.

The fields can have the same name as they do in PROGRAM1. In PROGRAM2 these fields are defined in the LINKAGE SECTION, which is in the DATA DIVISION and follows the WORKING-STORAGE SECTION. The fields in the two USING clauses must appear in the same order. Remember that while the names don't have to match the data types and sizes do. All fields are passed by reference (meaning that pointers to the fields are passed and not copies of the data) so that PROGRAM2 can alter any of them. Receive data from the keyboard Say that a 3-digit number will be input into your program. Define:
01 01 WS-INPUT-FIELDS. 05 WS-INPUT-NUMBER WS-NUMERIC-FIELDS. 05 WS-NUMERIC-NUMBER PIC ZZ9. PIC 999.

In the PROCEDURE DIVISION:


DISPLAY 'Enter a number (0-999): ' WITH NO ADVANCING. ACCEPT WS-INPUT-NUMBER. MOVE WS-INPUT-NUMBER TO WS-NUMERIC-NUMBER. CALCULATIONS ARE TO BE DONE USING WS-NUMERIC-NUMBER

Conditions A condition is a special piece of code that allows you to instruct the computer to compare two pieces of data. Conditions are used in IF statements and in the While/Until clauses of the PERFORM statement Conditions have the syntax: data-1 operator data-2 where data-1 and data-2 can be a literal or a field. data-2 can also be a COBOL literal such as SPACES or ZEROS. Operator can be the traditional comparison symbols =, <, >, <=, >=. To check for inequality use 'NOT =' since not all compilers accept the symbol <>. Rarely, a compiler will not accept <= or >=. You can use 'NOT >' and 'NOT <' instead. To comply with older versions of COBOL English can be used (i.e. EQUALS, IS NOT EQUAL TO, etc.). Conditions can be combined into a compound condition by using AND and OR. Unless directed to do otherwise by grouping conditions with parenthesis COBOL will evaluate the ANDs first, then the ORs. If the conditions also contain NOTs then those are evaluated before the ANDs. Also see 88-level Fields. Continuation Statements can be continued over several lines without doing anything more than placing the code on separate lines. The compiler will figure it out. Very long alphanumeric literals can be continued on multiple lines by placing a hyphen in column 7 of the continuation lines and placing the remainder of the literal there. This continuation of the literal requires a beginning single quote. The literal on the previous line does not have an ending single quote but is considered to extend to column 72.
MOVE 'THIS IS ONE SERIOUSLY LONG ALPHANUME 'RIC LITERAL' TO WS-STRING.

The hyphen on the 2nd line is in column 7. The single quote on that line is in column 12 and the literal continues from there. The ending single quote on that line is required. Note that the portion of the literal that's on the first line does not have an ending quote. If the last 'E' is not in column 72 then it will be assumed that all characters between that 'E' and column 72 are spaces and will appear in the literal. Also valid with value clauses.

Control Breaks Control breaks are a feature of reports that allow for the grouping of and accumulating subtotals for data that belong together based on the value of a field (the control field). When the value for this field changes from one record to another the program "breaks" to do some special processing (like printing subtotals) before it goes on with the next record. The input file must be sorted on the control field(s). An example of a report with a single-level control break:
04/20/1999 Department: Janitorial Employee Nbr 123 45 6789 111 11 1111 Name Ray, Marcus Griese, Brian Hours 40.0 50.0 90.0 Rate 2.00 2.50 Pay 80.00 125.00 205.00 The ABC Company Payroll Register Page 1

Totals for department Janitorial: Department: Research and Development 456 78 9123 ... Grand Totals: Gates, Willy ...

12.0 ... 1,002.5

800.00 ...

9,600.00 ... 258,125.00

The control break is on department. Each control group (department) has it's own headings and footings (totals). Though it's not shown here in this example it's common for column headings to be repeated after each control heading. See the algorithms page for sample code. Data Types There are basically three types of data recognized by COBOL. Numeric data (both with or without decimal places: only 0-9, the decimal point and a sign allowed), alphabetic (only the characters A-Z) and alphanumeric (any characters). Alphabetic is rarely used. Math can only be performed on numeric fields. Dates Dates are common data for COBOL programs and must be manipulated often. Typically dates are stored in the Gregorian format, consisting of the familiar month, day and year. This is generally called the 'mmddyy' format, though the 'mmddyyyy' format is becoming the new standard (see the Y2K discussion page). While those formats are familiar to the

coders and users dates are more often stored in 'yymmdd' or 'yyyymmdd' format so that they can be sorted easily. So-called 'calendar math', where dates are used in calculations, can be a tedious process, unless your compiler supports the intrinsic date functions. If not, remember the following about the Gregorian calendar:

April, June, September and November only have 30 days February only has 28 days, 29 if a leap year All other months have 31 days The 'official' method of determining if a year is a leap year requires dividing the 4-digit year by 4, 100 and 400 and looking at the remainders of those three calculations. If the first remiander is 0 then the year is a leap year, but if the second remainder is also 0 then the year is not a leap year, but if the third remainder is also a 0 then the year is a leap year again. This is why 2000 is a leap year by 1900 and 2100 are not. These checks must be nested within each other, trying to put them in a single IF will not work.

Also see Julian Dates. Delimiters Delimiters are used as visual ends to a statement. They don't change processing but they do make code easier to read and maintain. An example of a delimiter is END-IF:
IF WS-OSU > WS-MICHIGAN statement(s) ELSE statement(s) END-IF

Verbs that have end-delimiters are the comparison verbs (IF, EVALUATE), input/output (READ, WRITE, DELETE, REWRITE, ACCEPT), math (ADD, SUBTRACT, MULTIPLY, DIVIDE, COMPUTE), processing transfer (PERFORM, CALL) and some other lesser used verbs. When the compiler encounters a period it takes that as the end of the statement. A delimiter that is found after a period is in error. Fields A field is what other languages call a variable. It's a place to store data. All fields must be declared in the DATA DIVISION. A field declaration has three parts: the level number, the field name and the PIC clause. VALUE clauses are optional.

A valid field name is from 1 to 30 characters in length; contains only the letters A-Z, the digits 0-9 and the hyphen; contains at least one letter; does not begin or end with a hyphen; and is not a COBOL reserved word. Also see Qualified Fields. HIGH-VALUES/LOW-VALUES These are special numeric literals inherent to COBOL. HIGH-VALUES is the COBOL equivalent to infinity - no number is greater than HIGH-VALUES. Conversely, no number is less than LOW-VALUES. They can be used in VALUE clauses, conditions and MOVE statements but math cannot be performed using these literals. Julian Dates Julian is a date format that's an alternative to Gregorian dates. It consists of a 3-digit day and a year; there are no months. The days range from 1 (Jan 1st) to either 365 or 366 (Dec 31), depending on if the year is a leap year or not. This is generally known as the 'dddyy' or 'dddyyyy' format, even though normally the date is stored as 'yyddd' or 'yyyyddd' to ease with sorting. Shops that make use of Julian dates will have callable routines that covert Julian to Gregorian and back again, because humans are comfortable with Gregorian dates. Intrinsic date functions available with newer COBOL compilers have these conversions built-in. Julian format has two advantages. First, it's smaller, so it takes up less space. Second, it eases with some calculations because it contains no months. For example, how many days are between Feb 5, 1997 and Nov 28, 1999? Convert to Julian (1997036 and 1999332) a quick subtraction gives 1026 days. Remember that 'borrowing' a year gives you 365 days. Getting a future date or past date can also be easier with Julian. What date is 45 days before Apr 15, 1999? Convert it to Julian (1999105), subtract 45 to get 1999060) and convert back to Gregorian (Mar 1, 1999). Level Numbers Level numbers are used to group fields in the Data Division. A field can then be defined as a collection of other fields. The higher the level number the lower in the heirarchy the field is. Normally, the field numbers 01, 05, 10, etc. are used. By spacing them out you leave yourself room in case a level needs to be added later. Valid level numbers are 0-49.

Each FD is required to have an 01-level field defined. This is the record definition. It can be broken down into smaller fields if desired. For example:
01 INPUT-RECORD. 05 IN-EMPLOYEE-NUMBER 05 IN-EMPLOYEE-NAME. 10 IN-EMP-LAST-NAME 10 IN-EMP-FIRST-NAME 10 IN-EMP-MIDDLE 05 IN-BIRTH-DATE. 10 IN-BIRTH-DD 10 IN-BIRTH-MM 10 IN-BIRTH-YEAR. 15 IN-BIRTH-CC 15 IN-BIRTH-YY 05 IN-DEPARTMENT PIC 9(09). PIC X(30). PIC X(15). PIC X. PIC 99. PIC 99. PIC 99. PIC 99. PIC X(05).

We have an 01-level field that is broken down into 4 fields (the 05-level fields). Two of the 05-level fields are also broken down. Employee number is an elementary field because it is not broken down into smaller fields. The employee name and birth date are group level fields because they are broken down into smaller fields. Only elementary fields have PIC clauses. The birth date is 8 characters long (the sum of the lengths of the elementary fields that compose it). All 8 characters can be accessed with one name (IN-BIRTH-DATE) or one of its pieces can be accessed by using that name instead (i.e. IN-BIRTH-MM). A group level item 'ends' when another field with the same level number, or one with a lower value, is encountered. For example, the list of fields within IN-BIRTH-YEAR ends when the 05-level IN-DEPARTMENT is encountered. A field of level 10 would also have ended it. All group level fields are considered to be alphanumeric. All of these level number concepts are valid for WORKING-STORAGE also. Also see 77-level Fields 88-level Fields. Literals Literals are specific values as opposed to fields. Alphanumeric literals are enclosed in single quotes. In the following statements:
MOVE 3.1415927 TO WS-PI. DISPLAY 'Enter a number: '.

3.1415927 is a numeric literal and 'Enter a number: ' is an alphanumeric literal. COBOL has some built-in literals like ZEROES and SPACES.

Also see Continuation HIGH-VALUES/LOW-VALUES. Paragraphs A paragraph is a section of COBOL code. Paragraph names start in the 'A' margin and follow the same naming rules that fields do. A paragraph ends when another paragraph name is encountered. Paragraphs can be executed with the PERFORM statement. You can think of a pargraph as the equivalent of a subroutine in other languages. There are no arguments, all fields are thought of as global. Also see Sections. PIC Clauses PIC (short for PICture) clauses describe the size and type of data for each field. Numeric data has a PIC character of 9, alphanumeric data uses X and alphabetic data an A. Each 9, X or A represents one character. Length can also be represented by a repetition factor. The PIC clauses 9999 and 9(04) both define 4-digit numbers. The PIC character V is used to mark where a decimal point is. If you had a 8-digit numeric field but 2 of the digits are after the decimal point, you would define it as PIC 9(06)V99. The decimal point is implied, it is not physically there in the data. It also takes up no space. To allow for a field to hold either positive or negative numbers precede the leftmost PIC character with an S (PIC S999V99). There are several output PIC characters which help with formatting data for display or print. Numeric fields are MOVEd to fields defined with these formatting PIC characters. Fields defined with these formatting PIC characters are considered alphanumeric. No calculations can be done with these fields. Newer versions of COBOL allow these fields to be MOVEd to straight numeric fields. To print a decimal point place a '.' in the desired place in the output PIC clause (i.e. PIC 999.99). You can place commas in output numbers also (i.e. PIC 999,999.99). In this manner the decimal point (and commas) do take up space. These are considered insertion characters - they insert themselves into the data. Other insertion characters are B (for a space), 0 (a zero) and / (useful in printing dates). There is Z, for suppressing leading zeroes. If the digit represented by a Z is a leading zero it will print as a blank. You normally have one 9 in the PIC clause, in the one's place. All other digits represented by Z's. Do not use Z's after the decimal point. If used with commas (i.e. PIC ZZZ,ZZ9.99) a comma will only print if the character to its left prints, else it prints as a blank. There are other zero suppression characters. A $ can be used just like the Z except that rightmost leading zero will print as a $ and all zeroes to the left of that will print as

spaces. So the value of 125.00 MOVEd to a PIC $$$,$$9.99 will print as ' $125.00'. This behavior of the $ is called 'floating'. An * will work the same way (for check protection) but all * print, not just the one to the left of the most significant digit. When either the floating $ or the * is used in conjunction with commas the comma will only print as a comma if the character to its left prints as a digit. Depending on the situation it will otherwise print as a blank, $ or *. For sign control you can use + or - as an output PIC character. A + will print + for positive numbers and - for negative numbers. A - will print a - for negative numbers and a blank for positive numbers. Either can be repeated to suppress leading zeroes (like the $) and can 'float' (also like the $). Alternatively, a + or - can be placed to the right of the number. For accounting purposes the PIC characters 'DB' and 'CR' can also be used (i.e. PIC $$$,$ $9.99DB). The DB or CR will only show if the value is negative. If positive they will print blanks. Also see Blank When Zero Truncation. Qualified Fields It is legal in COBOL for different fields to have the same name. These fields cannot be 01-level fields and cannot be part of the same group-level field. When referencing one of these fields the compiler requires the field to be qualified, meaning its group-level field must be specified. If both INPUT-RECORD and OUTPUTRECORD contained a field named PAY-RATE then in code you cannot simply reference PAY-RATE, it would have to either be PAY-RATE OF INPUT-RECORD or PAYRATE OF OUTPUT-RECORD. Reference Modification Reference modification allows for the referencing of a portion of a field without having to make it a group-level field and defining each portion of the field that will be accessed. If you wanted to check the value of the 4th through 6th characters of a field to see if they were equal to ABC you can code:
IF WS-FIELD (4:3) = 'ABC'

The first number in the parenthesis represents the start position in the field and the second number represents the length. Both values have to be specified. COBOL treats all such references as alphanumeric. Since this is not a self-documenting feature it should not be used carelessly.

Reports A report is simply a formatted representation of data, suitable for being printed on paper (hardcopy). Reports generically look like:
04/20/1999 Employee Nbr 123 45 6789 456 78 9123 ... Totals: The ABC Company Payroll Register Name Ray, Marcus Gates, Willy ... Hours 40.0 12.0 ... 1,002.5 Rate 2.00 800.00 ... Page 1 Pay 80.00 9,600.00 ... 258,125.00

The first two lines are page headings, which will appear on every page. The next printed line (following the blank line) is column headings. It's common for column heading lines to be printed on every page. Next come the detail lines - typically one per record. At the end of the report will be a total line (if you are totalling anything). Note that the first detail line is the 6th line printed on a page (must count the blank lines also). There are other types of lines that can appear on reports. Sometimes there are page footings (printed on the bottom of each page). There can also be report headings and report footings (only printed at the top and bottom of the report as opposed to each page). Note the formatting of the data. There are commas and leading zeroes are suppressed on page numbers and monetary figures. The date has slashes. Always make reports as easy to read as possible. See the algorithms page for sample code. Also see PIC clauses. Sections A section is a group of paragraphs. The section name must begin in the 'A' margin and be followed by the word 'SECTION'. Naming standards for sections are the same as those for paragraphs. A section ends when a new one begins. A section can be PERFORMed in the same manner a paragraph is PERFORMed. The PERFORM only uses the section name, there is no reference to it actually being a section instead of a paragraph. Subscripts and Indexes Subscripts and indexes are the two tools used to reference individual elements of a table. A subscript is a working-storage field defined separately from the table and is completely

available to the programmer. An index is created automatically by the system if it is directed to do so and only has limited availability to the programmer. An index cannot be part of a calculation, cannot be MOVEd to another field or cannot receive another field from a MOVE and it cannot be DISPLAYed. To manipulate an index the SET statement must be used. The major difference between a subscript and an index is that a subscript is a position in the table (first element, 20th element, etc.). An index is a byte offset of an element relative to the beginning of the table. Since the first element is 0 bytes away from the start of the table, it has an index of 0. The 20th element (say each element is a PIC X(5)) starts 95 bytes from the start of the table so its index is 95. When manipulating an index the programmer does not do so by this byte offset. It is done by position in the table and the translation to byte offset is done internally by COBOL. See the algorithms page for sample code on loading and searching tables. Also see OCCURS clause, Set. Tables Tables are the COBOL equivalent to arrays. It is a set of fields with the same name and the same data type. To reference an individual element of the table a subscript or index must be used. Tables are defined using the OCCURS clause. See the algorithms page for sample code on loading and searching tables. Truncation Truncation is a phenomenon that occurs when the receiving field of a MOVE or a math operation is not big enough to hold what it's getting. For alphanumeric fields truncation happens on the right (move 'COBOL' to a PIC X(4) and you get 'COBO') and numeric it happens on the left (move 1000005 to a PIC 9(06) and you get 5). No warnings, no messages. Just the loss of data. Also see On Size Error. 77-level Fields A working storage field can be declared with a level number of 77. The 77 must be in column 8, the field cannot be a group-level field and the field cannot be part of a grouplevel field.

88-level Fields A field declared with a level number of 88 is commonly known as a 'condition name'. This name can be used anywhere a condition can be used and is generally more readable. Condition names are declared immediately after the field they are associated with. They use no storage (they take up no room). For example your application contains a field named ACCT-TYPE which is PIC 999. One particular section of code determines if the account is a checking account (account type 100, 110, 210 or 300), a savings account (type 150 or 175) or a CD/IRA (type 400). An IF statement could look like:
IF WS-ACCT-TYPE = 100 OR 110 OR 210 OR 300 statement(s) ELSE IF WS-ACCT-TYPE = 150 OR 175 statement(s) ELSE IF WS-ACCT-TYPE = 400 statement(s) END-IF END-IF END-IF

Logically accurate but not entirely clear what account types are what. Comments would help, but condition names will help more. Define as:
01 WS-ACCT-TYPE 88 CHECKING-ACCT 88 SAVINGS-ACCT 88 CD-IRA-ACCT PIC 999. VALUE 100 110 210 300. VALUE 150 175. VALUE 400.

The same IF can now look like:


IF CHECKING-ACCT statement(s) ELSE IF SAVINGS-ACCT statement(s) ELSE IF CD-IRA-ACCT statement(s) END-IF END-IF END-IF

Now it's self-documenting. The added advantage is if another type of savings account is developed it only needs added at the condition name. The IF statement doesn't change. A specific value can appear in multiple condition names. Values associated with a condition name can be specified with THRU (i.e. VALUES 90 THRU 99). When

checking condition names 'NOT' can be used. If a condition name only has one value a statement such as 'SET CD-IRA-ACCT TO TRUE' is valid and is the equivalent to 'MOVE 400 TO WS-ACCT-TYPE'. Also see Set. Accept The ACCEPT statement is used to get information from a source other than a data file (like the keyboard or CPU clock). The statement:
ACCEPT field.

will cause the program to wait until the enter key is pressed. Any data typed in before the enter key is pressed will then be placed in field. See How do I ...? for issues with getting numeric data in this manner. See the algorithms page for sample code on receiving and processing data received interactively. The ACCEPT statement can also be used to get information from the system clock such as the current date and time:
ACCEPT ACCEPT ACCEPT ACCEPT field-1 field-2 field-3 field-4 FROM FROM FROM FROM DATE. TIME. DAY. DAY-OF-WEEK.

Where:

field-1 is PIC 9(6). The date will be in yymmdd format field-2 is PIC 9(8). The time will be in hhmmsscc format where cc is hundredths of a second. hh will be in military time (0-23) field-3 is PIC 9(3). The value will represent the current Julian date, which is a number from 1-366 representing the date as a number of days relative to the end of the previous year (Jan 1st = 1, Feb 1st = 32, etc.). field-4 is PIC 9. The values range from 1 (Monday) to 7 (Sunday).

Also see Delimiters. Add The basic form of the ADD statement is:
ADD value TO field-1.

which adds value (either a literal or a field) to field-1 and stores the result in field-1. A list of fields can follow the TO which will add the value to each of them. A list of values can be before the TO which would add all of them to field-1. It is possible to add two values (either literals or fields) and store the result in a separate field with the GIVING clause:
ADD value-1 TO value-2 GIVING field-1.

Also see Rounded, On Size Error, Truncation, Delimiters. Blank When Zero 'BLANK WHEN ZERO' can be specified with a PIC clause so that blanks are printed if the value of the field is zero. For example, 'PIC -,--9.99 BLANK WHEN ZERO'. Call The CALL statement is used to call another program. As long as the called program contains a GOBACK or EXIT PROGRAM then when the called program finishes control returns to the calling program. Fields can be passed from the calling program to the called program. These fields are in the calling program's WORKING-STORAGE SECTION and in the called program's LINKAGE SECTION. The USING clause on the CALL specifies the fields to pass. The called program lists these fields in the USING clause of the PROCEDURE DIVISION. These fields don't have to have the same name in both programs, but the definitions must match.
CALL 'PGM2.OBJ'. CALL 'PGM6F.OBJ' USING WS-FLD-1 WS-FLD-2 WS-FLD-3 WS-FLD-4 WS-FLD-5 END-CALL.

See the algorithms page for sample code on calling another program. Close The CLOSE statement will close an open file. Attempting to close a closed file will produce a run-time error. One CLOSE statement can close multiple files.
CLOSE file-name-1

file-name-2.

Also see Open. Compute COMPUTE allows you to combine several math operations in one statement, using familiar symbols instead of English-like sentances.
COMPUTE field-1 = expression.

Expression is any valid mathematical expression involving literals, fields and the following symbols: + (add), - (subtract), * (multiply), / (divide), ** (exponentiation). To code 2 to the 3rd power use '2 ** 3'. The order of operations is as follows: 1. Exponentiation, from right to left 2. Multiplication and division, from left to right 3. Addition and subtraction, from left to right Parenthesis can also be used to force the order in which the operations are carried out. Expressions inside parenthesis are computed first, from the innermost parenthesis to the outermost. COMPUTE comes with a warning. Some compilers will round/truncate each intermediate result as opposed to waiting until the end of all calculations. This can lead to erroneous results. Also see Rounded, On Size Error, Truncation, Delimiters. Copy COPY will insert the contents of the specified file into the program containing the COPY when the program is compiled. The file being copied is normally referred to as a copybook. COPYs can appear in any of the divisions. A period must terminate the COPY. Record layouts are commonly in copybooks. Every program that reads or writes the file can contain a COPY instead of having the same record definition repeated in several programs. If the record layout is changed the change needs to be in one place and the programs recompiled to grab the more recent version.
FD IN-CUSTOMER-MASTER RECORD CONTAINS 1200 CHARACTERS.

COPY CUSTMAST.

A specific location for the copybook can be specified on the COPY by using either 'OF' or 'IN', followed by the library name.
FD IN-CUSTOMER-MASTER RECORD CONTAINS 1200 CHARACTERS. COPY CUSTMAST OF CPYBOOKS.

COPY supports a REPLACING clause, where text in the copybook is altered once it is inserted in the program. The original copybook is unchanged. Literals and identifiers can be changed simply by specifying them in the command. Text can also be replaced, but requires the source and target text to be in between pairs of equal signs.
COPY CUSTMAST REPLACING CUST-NUMBER BY CUST-NBR. COPY CUSTMAST REPLACING ==CUST-== BY ==CUSTOMER-==, ==9(5)== BY ==X(5)==.

The first will change the name of a field, assuming it exists in the copybook. The second will change every occurrence of 'CUST-' to 'CUSTOMER-' and change all '9(5)' to 'X(5)'. Some record layout copybooks will have a dummy prefix on each field name and each time it is COPYed the prefix is changed by a REPLACING on the COPY. This allows for the copybook to used for multiple files in the same program - each COPY REPLACEs the dummy prefix with a different value avoiding having multiple fields with the same name. Corresponding MOVE CORRESPONDING (or just MOVE CORR) is used with group-level fields. Whenever the source and target group-level fields have elementary fields of exactly the same name then that field will be moved. Consider the following:
01 GROUP-1. 05 FIELD-A 05 FIELD-B. 10 FIELD-C 10 FIELD-D 05 FIELD-E 05 FIELD-F PIC 999. PIC PIC PIC PIC X(12). XXX. 99. X. 01 GROUP-2. 05 FIELD-E 05 FIELD-A 05 FIELD-BB. 10 FIELD-C 10 FIELD-D 05 FIELD-G PIC 99. PIC 9(4). PIC XXX. PIC X. PIC X(10).

The statement 'MOVE CORRESPONDING GROUP-1 TO GROUP-2' will cause both FIELD-A and FIELD-E to be moved. FIELD-C and FIELD-D have different group-level names so they don't correspond. This command is very useful when reformatting records. It can replace dozens, even hundreds, of moves.

Also see Move. Delete DELETE will delete the current record in a non-sequential file OPENed as 'I-O'. There must be a current record, so a successful READ or READ NEXT must precede the DELETE.
DELETE OT-FILE RECORD.

DELETE specifies the file name, followed by the word 'RECORD'. See the algorithms page for sample code on using non-sequential files. Also see Invalid Key. Display The DISPLAY statement is used to show information on the terminal screen. Any combination of literals and fields can be displayed. All of the following are valid:
DISPLAY field-name. DISPLAY 'Now performing paragraph 2000-READ'. DISPLAY 'Employee number = ' WS-EMPLOYEE-NBR.

Can use the clause 'WITH NO ADVANCING' after the value being displayed to prevent the cursor from dropping down a line on the screen. This can be useful for prompts for an ACCEPT statement:
DISPLAY 'Enter a number: ' WITH NO ADVANCING. ACCEPT WS-NBR.

Divide The basic form of the DIVIDE statement is:


DIVIDE value INTO field-1.

which divides value (either a literal or a field) into field-1 and stores the result in field-1. It is possible to store the result in a separate field with the GIVING clause. When using GIVING you can opt to divide BY instead of divide INTO. This changes the positions of the divisor and dividend:
DIVIDE value-1 INTO value-2 GIVING field-1. DIVIDE value-1 BY value-2 GIVING field-1.

You can also specify the remainder of the division to be stored in a separate field (only valid with GIVING):
DIVIDE value-1 INTO value-2 GIVING field-1 REMAINDER field-2.

While it is legal in COBOL to have REMAINDER when not working with integers it makes little sense to do so. Also see Rounded, On Size Error, Truncation, Delimiters. Evaluate The EVALUATE statement can be used to replace a nested- IF construct. It is the equivalent of a CASE or SWITCH statement of other languages.
EVALUATE WS-GRADE WHEN 100 DISPLAY 'PERFECT' WHEN 90 THRU 99 DISPLAY 'A' WHEN 80 THRU 89 DISPLAY 'B' WHEN 70 THRU 79 DISPLAY 'C' WHEN OTHER DISPLAY 'WOULD YOU LIKE FRIES WITH THAT?' END-EVALUATE.

Each 'WHEN' can only have one statement, though it can be a PERFORM. If multiple WHENs are true only the first one checked will execute. The 'WHEN OTHER' is like a 'none of the above'. If two WHENs are 'stacked' (no statement between them) they are treated like an 'OR'. For example:
EVALUATE WS-AGE WHEN 0 THRU 4 WHEN 70 THRU 99 DISPLAY 'TAKE A NAP' END-EVALUATE.

The display will execute if WS-AGE falls in either range. Instead of EVALUATEing a field you can use 'EVALUATE TRUE'. Each WHEN must then contain a condition. The first WHEN containing a true condition is executed. This method releases you from the restriction of checking the same field with each WHEN.

Also valid is 'EVALUATE FALSE' where the first WHEN containing a false condition is executed. Condition names cannot be used when EVALUATEing a field. Condition names can only be used with 'EVALUATE TRUE' or 'EVALUATE FALSE'. When EVALUATEing a field the WHENs contain values, not conditions. Use EVALUATE ALSO to evaluate multiple fields/conditions at the same time.
EVALUATE WS-SEX ALSO WS-MARITAL-STATUS WHEN 'F' ALSO 'S' MOVE 'MISS' TO WS-TITLE WHEN 'F' ALSO 'M' MOVE 'MRS.' TO WS-TITLE WHEN 'M' ALSO 'S' MOVE 'MR.' TO WS-TITLE WHEN 'M' ALSO 'M' MOVE 'POOR MR.' TO WS-TITLE WHEN OTHER DISPLAY 'CALL SECURITY' END-EVALUATE.

You can use EVALUTE TRUE and FALSE with ALSO. Each WHEN will then contain one condition for each TRUE or FALSE. Exit EXIT is used as the only statement in a paragraph that isn't supposed to do anything. This typically is used in conjunction with PERFORM THRUs. The paragraph being PERFORMed THRU is the one containing the EXIT.
PERFORM 300-READ-FILE THRU 300-EXIT. . . . . . . 300-READ-FILE. READ IN-FILE AT END MOVE 'Y' TO WS-EOF-SW GO TO 300-EXIT END-READ. . . . . (MUCH LOGIC) . . . . PERFORM 400-WRITE-RECORD THRU 400-EXIT. 300-EXIT. EXIT.

Exit Program EXIT PROGRAM is used in a called program instead of a STOP RUN. It will return execution to the calling program where a STOP RUN will terminate all currently running programs. Also see Goback. Go To GO TO is used to transfer control to another part of the program. The target of a GO TO is a paragraph name. Unlike a PERFORM a GO TO will not return when the paragraph finishes.
GO TO 300-EXIT.

Goback GOBACK is used in a called program instead of a STOP RUN. It will return execution to the calling program where a STOP RUN will terminate all currently running programs. Also see Exit Program. If The IF statement is used to limit the execution of code so that it only happens under certain conditions. The standard form is:
IF condition statement(s) END-IF.

The statement(s) are only executed if the condition is true. Each IF is allowed to have an ELSE. The statement(s) in the ELSE are only executed if the condition is false:
IF condition statement(s) ELSE statement(s) END-IF.

There must be at least one statement in either portion of the IF. If you do not want any processing done you can use the CONTINUE or NEXT SENTENCE statement:

IF condition CONTINUE ELSE statement(s) END-IF.

IFs can be nested (one IF inside another). COBOL will match an ELSE or an END-IF with the nearest IF that does not yet already have an ELSE or END-IF paired with it. IFs can also be used to check types. An field can be checked to see if it contains valid numerics with:
IF field IS NUMERIC

IS NOT NUMERIC is also valid. In the same manner a numeric field can be checked to see if IS POSITIVE, IS NEGATIVE or IS ZERO. The END-IF delimiter is not required. A period will end all IFs. Also see Evaluate. Initialize The INITIALIZE command is used to set all of the values for fields in the same grouplevel field to either 0 or spaces, depending on the field's definition. The statement:
INITIALIZE WS-GROUP.

where:
01 WS-GROUP. 05 WS-FIELD-1 05 WS-FIELD-2 05 WS-FIELD-3 05 WS-FIELD-4 PIC PIC PIC PIC X(05). 999. S9(04)V99. X(100).

is the equivalent to MOVEing SPACES to WS-FIELD-1 and WS-FIELD-4 and MOVEing ZEROS to WS-FIELD-2 and WS-FIELD-3. The nice thing is that as elementary fields are added to the group the INITIALIZE will automatically take care of them. INITIALIZE will not change the value of any FILLER items. If a non-FILLER item has a VALUE clause it will still get either ZEROS or SPACES with the INITIALIZE statement. The VALUE is ignored. Also see Move. Inspect

INSPECT has two purposes. It can count the number of times a particular character appears in an alphanumeric string, and it can change those characters to another.
INSPECT field-1 TALLYING field-2 FOR target.

Where field-1 is an alphanumeric field and field-2 is a numeric field that will hold the count. target has a few different possibilities. It can be the word CHARACTERS in which case field-2 holds the number of characters in the alphanumeric string. Or a specific character can INSPECTed for using either ALL or LEADING followed by the character. Finally, any of these forms can be ended with a BEFORE/AFTER INITIAL clause:
INSPECT INSPECT INSPECT INSPECT WS-A WS-A WS-A WS-A TALLYING TALLYING TALLYING TALLYING WS-N WS-N WS-N WS-N FOR FOR FOR FOR ALL '*' LEADING SPACES CHARACTERS AFTER INITIAL SPACE ',' BEFORE INITIAL '0'

To use INSPECT to change particular characters in an alphanumeric string, use REPLACING instead of TALLYING. The CHARACTERS, ALL and LEADING clauses are valid with REPLACING, as is FIRST. You can also use the BEFORE/AFTER INITIAL clause with REPLACING.
INSPECT WS-A REPLACING ALL SPACES BY ZEROES INSPECT WS-A REPLACING FIRST 'A' BY 'B' INSPECT WS-A REPLACING ALL ' ' BY '0' AFTER INITIAL ','

Invalid Key The INVALID KEY clause is used with any type of non-sequential I-O statement. It specifies a statement to be executed if the command fails. Any statement such as READ or WRITE with any relative or indexed file should include this clause. For example:
MOVE WS-KEY TO FILE-KEY. READ INDEX-FILE INVALID KEY PERFORM 300-RECORD-NOT-FOUND END-READ.

Upon an unsuccesful READ (for example, if no record in the file has that key) the specified statement is executed instead of the program crashing. There is an optional NOT INVALID KEY clause that can be included (must be after the INVALID KEY). It is best if only one statement is used in either the INVALID KEY or NOT INVALID KEY clause. See the algorithms page for sample code on using non-sequential files. Merge

The merge is used to sort multiple files into one. Each of these files requires its own FD in the FILE SECTION, as does the combined file. All of these files must obviously have the same record format. The merge requires another entry in the FILE SECTION, an SD instead of an FD.
MERGE sd-file-name ON ASCENDING KEY sd-field-name USING fd-input-file-name-1 fd-input-file-name-2 GIVING fd-output-file-name

To sort multiple fields list them in the desired order. DESCENDING KEYs can be mixed with ASCENDING KEYs in the same MERGE (but only use 'ON' once). List the input files in the desired order in the USING clause. Like the SORT an OUTPUT procedure can be specified (requiring a RETURN) instead of the GIVING, but the MERGE does not support the INPUT PROCEDURE option. Move The MOVE statement is used to place a value in a field. It is kind of like an assignment statement in other languages though it does not allow for computations. Even though the statement is a move, it is more like a copy. The data is still in its original place as well as the receiving field. The standard form of statement is:
MOVE value TO field.

where value can be a literal or a field. A list of fields can follow the TO causing the value to be MOVEd to each of the fields. With a numeric move the source and destination are checked for the location of the decimal place (if one is not explicitly defined it is assumed to be to the right of the rightmost digit) and the move is done based on that. For example, MOVEing the value 80.375 to a PIC 9(06)V99 will cause the receiving field to contain 80.37 and MOVEing the value 3.1415927 to a PIC 9(08) will cause the receiving field to contain 3. Alphanumeric and alphabetic moves first move the leftmost character of the sending field to the leftmost character of the receiving field, then the next character, and so on. All group-level MOVEs are considered alphanumeric. If the receiving field is larger than the data being MOVEd then the field will be padded. Alphanumeric fields are padded on the right with spaces, numerics are padded on the left with zeroes. If a numeric has more decimal places than the data being MOVEd then zeroes will be padded on the right in the decimal portion of the receiving field. Also see Truncation, Corresponding.

Mulitply The basic form of the multiply statement is:


MULTIPLY value BY field-1.

which multiplys value (either a literal or a field) by field-1 and stores the result in field-1. It is possible to store the result in a separate field with the GIVING clause:
MULTIPLY value-1 BY value-2 GIVING field-1.

Also see Rounded, On Size Error, Truncation, Delimiters. Occurs Occurs is used to define a table. It is followed by the number of elements in the table. COBOL does not support dynamic tables - the size must be specified.
01 WS-TABLE. 05 WS-ELEMENT OCCURS 100 TIMES PIC 9(5).

Defines a table with 100 elements. The allowable subscripts for this table are 1 through 100. To access a specific element of the table you would use something like WSELEMENT (27). A space is required before and after the parenthesis. The subscript can be a field but cannot be an expression. The subscript can be a separate working-storage numeric field or COBOL can told to create an index, like in the following:
01 WS-TABLE. 05 WS-ELEMENT OCCURS 100 TIMES INDEXED BY WS-INDX

PIC 9(5).

The field WS-INDX is automatically created by COBOL. The OCCURS can be on a group-level field which would then create a table containing multiple instances of each of the elementary fields. The OCCURS cannot appear on an 01-level field. It is also invalid on 77-level fields and 88-level fields.
01 WS-TABLE-AREA. 05 WS-TABLE 10 WS-KEY 10 WS-VALUE-1 10 WS-VALUE-2 OCCURS 100 TIMES. PIC XX. PIC 9(5). PIC 9(6)V99.

This would create 100 elements of each of the 3 elementary fields.


01 FILLER VALUE 'MONTUEWEDTHUFRISATSUN'.

05

WS-DAYS-OF-WEEK

OCCURS 7 TIMES.

Creates a table with 7 elements and also initializes them. This was not possible until a very recent version of COBOL. A redfines had to be used. See the algorithms page for sample code on loading and searching tables. On Size Error When used with one of the math verbs (ADD, SUBTRACT, MULTIPLY, DIVIDE, COMPUTE) it allows COBOL to detect truncation and divide-by-zero situations and execute a specified instruction instead of doing the calculation. The one statement can be a PERFORM. For example:
DIVIDE WS-TOTAL BY WS-COUNT GIVING WS-PCT ROUNDED ON SIZE ERROR MOVE 0 TO WS-PCT END-DIVIDE.

A statement can also be specified for 'NOT ON SIZE ERROR'. Open The open statement will open a file. Attempting to open an opened file will produce a run-time error. Accessing an unopened file will also produce a run-time error. You must specify whether the file is being opened as an input file or an output file. Opening an existing file as output will cause the contents of the file to lost immediately after it is opened. One read statement can open multiple files, even mixing input and output.
OPEN INPUT file-name-1 file-name-2. OPEN OUTPUT file-name-1 file-name-2. OPEN INPUT file-name-1 file-name-2 OUTPUT file-name-3 file-name-4.

Also see Close. Perform

The perform statement will execute the specified paragraph and then control will return to the statement following the perform. There are no restrictions as to the physical placement of a paragraph compared to the perform statement that executes it. There are several variations controlling the performing of paragraphs. A paragraph cannot perform itself; COBOL has no recursion.
PERFORM paragraph-name. PERFORM paragraph-name WHILE condition. PERFORM paragraph-name UNTIL condition. PERFORM paragraph-name VARYING field-1 FROM value-1 BY value-2 UNTIL condition. PERFORM paragraph-name value-1 TIMES.

Where any of the values can be literals or fields. Each of the examples can also be specified with a THRU option, allowing for a sequence of paragraphs to be executed.
PERFORM paragraph-name-1 THRU paragraph-name-2

Paragraph-name-2 will also be executed. There is also what's known as an in-line perform where a block of code appears between a PERFORM and END-PERFORM. No paragraph name is specified. For example:
PERFORM UNTIL WS-END-OF-FILE statement(s) READ IN-FILE AT END MOVE 'Y' TO WS-END-OF-FILE-SW END-READ END-PERFORM

When using the UNTIL option with a perform or in-line perform the 'UNTIL condition' clause can be preceded by 'WITH TEST AFTER' to have COBOL check the condition after the loop instead of before. This will cause the loop to always be executed at least once. This has the effect of a REPEAT-UNTIL loop of other languages. Also see Conditions Delimiters Sections.

Read The read statement will read the next record from the specified file and place the data in the record layout of that file's FD. The file must be already open as input. Reading an unopend file or attempting to read beyond the end of a file will produce a run-time error. The AT END clause is required.
READ file-name AT END statement END-READ.

Optional clauses are NOT AT END and INTO. NOT AT END specifies a statement to be executed if the read did not hit the end of the file. INTO specifies a working-storage field into which the system will place the input record.
READ file-name INTO working-storage field AT END statement NOT AT END statement END-READ.

Also see Delimiters. Read Next The READ NEXT is used after a successful START to read records along the established access path. The condition used by the START is not "remembered" by the READ NEXT so after each successful READ NEXT the record must be checked to see if it still matches whatever criteria the program is calling for. A successful read only means that a record was retrieved.
READ indexed-file-name NEXT RECORD AT END statement END-READ

Since this is still a "sequential" process the READ NEXT requires an AT END clause. The optional NOT AT END clause is supported. See the algortihms page for code examples.

Redefines The REDEFINES clause allows you to have multiple field definitions for the same piece of storage. The same data then can be referenced in multiple ways. Take a simple example, useful for data validation:
01 01 WS-NUMBER-X WS-NUMBER PIC X(8). REDEFINES WS-NUMBER-X PIC 9(6)V99.

This portion of the data division only consumes 8 bytes of storage, not 16. Each of the two PIC clauses is describing the same 8 bytes of data, just doing it differently. Once data is in WS-NUMBER-X it can be checked to see if it is numeric (IF WSNUMBER-X IS NUMERIC). If so, WS-NUMBER can then be used as part of a calculation. If the data happens to be non-numeric then this type of code will prevent the program from choking. We access the data as alphanumeric (any data allowed) to see if it is safe to access it as numeric before actually attempting to do so. Note that once the data was moved to WS-NUMBER-X it was also moved to WSNUMBER because they both describe the same portion of storage. There are a few rules with REDEFINES:

A redefinition must have the same level number as the field it is redefining The redefinition must immediately follow the field it is redefining (i.e. if an 05level field is being redefined then the redefinition must be the next 05-level field) Cannot have a REDEFINES of an 01-level field in an FD The redefinition should be the same size as the field it is redefining though not all compilers require this It is possible to redefine at the group level though each group-level field does not have to the same number of elementary fields Not all compilers allow VALUE with REDEFINES. It's a bad idea in any case Can have multiple REDEFINES of the same field

Release The RELEASE statment is required in an INPUT PROCEDURE of a SORT. It is used to specify that a record is to be included in the sort.
RELEASE sd-record-name RELEASE sd-record-name FROM working-storage-field

Only RELEASEd records will be sorted.

See the algorithms page for sample code on using the SORT statement. Also see Return. Return The RETURN statment is required in an OUTPUT PROCEDURE of a SORT. It is used to retrieve a record from the sort back into your program.
RETURN sd-file-name AT END statement END-RETURN

The records are RETURNed in the sorted order. Like the READ statement the RETURN supports the NOT AT END and INTO optional clauses. Also like the READ, it is best if only one statement is used in either the AT END or NOT AT END clauses. See the algorithms page for sample code on the SORT statement. Also see Release. Rewrite REWRITE will update the current record in a non-sequential file OPENed as 'I-O'. There must be a current record, so a successful READ or READ NEXT must precede the REWRITE. Following the READ/READ NEXT and before the REWRITE some information on the record will presumably be changed.
REWRITE IN-FILE-REC.

REWRITE specifies the record, not the file. See the algorithms page for sample code on using non-sequential files. Also see Invalid Key. Rounded Rounded is a clause valid with any of the math verbs (ADD, SUBTRACT, MULTIPLY, DIVIDE, COMPUTE). Place it in the command after the name of the field that will receive the result:
ADD IN-AMOUNT TO WS-BALANCE ROUNDED.

MULTIPLY IN-HOURS BY IN-RATE GIVING WS-PAY ROUNDED. COMPUTE WS-CUBE ROUNDED = WS-NBR ** WS-POWER.

Search The search command is used to search a table for a particular entry. The table must have an index (see OCCURS). The format is:
SEARCH field AT END statement-1 WHEN condition statement-2 END-SEARCH.

The field is the field with the OCCURS clause. WHEN specifies the condition on which to end the search (usually when some field equals a table entry) Only one statement can be specified in the WHEN but it can be a PERFORM. The AT END clause is optional, specifying one statement to be executed if the entire table is searched without satisfying the WHEN condition. It is recommended, however. For example:
* ALWAYS SET THE INDEX TO 1 BEFORE A SEARCH SET WS-INDX TO 1. SEARCH WS-TABLE AT END MOVE ZEROES TO SALES-TAX WHEN IN-STATE = WS-TABLE-STATE (WS-INDX) MOVE WS-TABLE-TAX TO SALES-TAX END-SEARCH.

There can be multiple WHENs but the search stops once the condition of a WHEN is satisfied. To allow for multiple search matches use a PERFORM VARYING, which can increment an index. If the table entries are sequenced by the field being searched then a binary search can be used instead. Use SEARCH ALL instead of SEARCH. It is more efficient than a regular search, especially with large tables. The SEARCH ALL has some limitations:

Only one WHEN is permitted The WHEN condition can only test equality The WHEN condition cannot contain an OR The table field must be to the left of the = in the condition

See the algorithms page for sample code on loading and searching tables.

Set Set can be used to manipulate an index:


SET WS-INDX TO WS-NUMBER. SET WS-INDX UP BY 1. SET WS-INDX DOWN BY 3.

Note that while an index is actually a byte offset within a table COBOL does not expect you to work on that level. Setting an index to 2 will cause it to point to the 2nd element in the table, regardless of its offset. Likewise, seting an index up one will move it to the next element in the table, regardless of the size of the element. COBOL will translate it to the proper offset for you. Set can also be used with condition names as an alternative to a MOVE. Consider the following:
01 WS-END-OF-FILE-SW 88 END-OF-FILE PIC X VALUE 'N'. VALUE 'Y'.

It is then permissible to code:


SET END-OF-FILE TO TRUE.

This is the equivalent to "MOVE 'Y' TO WS-END-OF-FILE-SW" but it is more readable. Most compilers will not allow a condition name with multiple values to be used in a SET. It is not a good idea in any case. Sort The sort statement is used to sort a file. It requires a work file area that is defined in the FILE SECTION, just like any other file, except it is an SD instead of an FD. The basic sort statement looks like:
SORT sd-file-name ON ASCENDING KEY sd-field-name USING fd-input-file-name GIVING fd-output-file-name

Multiple fields can be used in the sort, just list them in the desired order. DESCENDING KEY can be specified instead of ASCENDING KEY. DESCENDING KEY and ASCENDING KEY can be combined in the same statement. The SORT statement will open and close both the input and output files automatically. The field(s) to be sorted on must be defined in the SD of the sort file. An INPUT PROCEDURE can be specified instead of an input file. This allows the flexibility of selecting specific records to be sorted or to do other types of processing before the sort. Likewise, an OUTPUT PROCEDURE can be used instead of an output

file. An INPUT PROCEDURE requires a RELEASE statement and an OUTPUT PROCEDURE requires a RETURN statement. For example:
SORT sd-file-name ON ASCENDING KEY sd-field-name INPUT PROCEDURE IS paragraph-1 OUTPUT PROCEDURE IS paragraph-2

This statement will execute paragraph-1, perform the sort and then execute paragraph-2. An INPUT PROCEDURE can be used with GIVING and an OUTPUT PROCEDURE can be used with USING. Each of these options allows the THRU option (i.e. paragrapha THRU paragraph-b). The clause 'WITH DUPLICATES IN ORDER' can be included in the statement (after the last ASCENDING/DESCENDING KEY). This will cause any records with the same value(s) for the sort field(s) to be kept in their original order. Not specifying this will not necessarily change their original order, but there is no guarantee. See the algorithms page for sample code on using the SORT statement. Start The Start statement is used to establish an access path for an indexed file with alternate keys (see the algortihms page for code examples). Note that keys in alternate indexes are not necessarily unique and the START is used in conjunction with the READ NEXT statement to find and retrieve and these records.
START indexed-file-name KEY EQUALS alternate-key-field-in-FD END-START

The alternate key field must already be populated with a value. The first record in the file with that value for the alternate key is read. It is a good idea to include a INVALID KEY clause in any START to handle the case where there is no record in the file with the appropriate alternate key. Instead of 'EQUALS' the START also supports '>' and 'NOT <'. With some compilers a START with an EQUALS will read a record if an appropriate one exists, but a START with a '>' or 'NOT <' will not retrieve a record under any circumstances. Other compilers will never have a START actually read a record. See the algorithms page for sample code on using non-sequential files. Stop Run

The stop run statement will cause a normal termination to your program.
STOP RUN.

String The STRING is used to concatenate (join) multiple fields or literals into one field. It replaces a series of MOVEs. For example:
01 WS-DATE-FIELDS. 05 WS-YEAR 05 WS-MONTH 05 WS-DAY WS-DISPLAY-DATE PIC PIC PIC PIC X(4) VALUE '2000'. XX VALUE '12'. XX VALUE '24'. X(10).

01 .....

STRING WS-MONTH DELIMITED '/' DELIMITED WS-DAY DELIMITED '/' DELIMITED WS-YEAR DELIMITED INTO WS-DISPLAY-DATE.

BY BY BY BY BY

SPACE SIZE SPACE SIZE SPACE

After the above statement is executed WS-DISPLAY-DATE will contain '12/24/2000'. DELIMITED BY SPACE means to use as much of that field or literal that appears before the first space. If there are no spaces (like in the example) then the entire field or literal is used. Any character can be used in the DELIMITED BY clause. Literals are usually DELIMTED BY SIZE, meaning to use the whole thing. The DELIMITED BY character is never included in the combined field. Also see Unstring. Subtract The basic form of the subtract statement is:
SUBTRACT value FROM field-1.

which subtracts value (either a literal or a field) from field-1 and stores the result in field1. A list of fields can follow the FROM which will subtract the value from each of them. A list of values can be before the FROM which would subtract all of them from field-1. It is possible to store the result in a separate field with the GIVING clause:
SUBTRACT value-1 FROM value-2 GIVING field-1.

Also see Rounded, On Size Error, Truncation, Delimiters. Unstring The UNSTRING is used to split a field into multiple fields using a particular character to determine where to split the field. For example:
01 WS-NAME-FIELDS. 05 WS-FIRST 05 WS-MIDDLE 05 WS-LAST WS-WHOLE-NAME PIC PIC PIC PIC X(10). X. X(14). X(25) VALUE 'HOMER J SIMPSON'.

01 .....

UNSTRING WS-WHOLE-NAME DELIMITED BY SPACE INTO WS-FIRST, WS-MIDDLE, WS-LAST.

The above statement will take the all of WHOLE-NAME, up to but not including the 1st space, and place it into WS-FIRST. The the part that is between the 1st and 2nd spaces, not including either one, is placed in WS-MIDDLE, and so on. Also see String. Usage USAGE can be used in conjunction with the PIC clause to specify how numeric data is to be stored. The most common options are DISPLAY (the default), COMP and COMP-3. COMP is short for COMPUTATIONAL, which can also be used. The words 'USAGE IS' are optional. USAGE is only valid with numeric fields. It can be specified as follows:
01 WS-FIELDS. 05 WS-DISPLAY-1 05 WS-DISPLAY-2 05 WS-COMP-1 05 WS-COMP3-1 PIC PIC PIC PIC 9(4). 999 USAGE IS DISPLAY. S9999 USAGE IS COMPUTATIONAL. 9(5)V99 COMP-3.

A number stored as COMP is in binary format. A COMP-3 number is stored as packeddecimal. Using The USING clause is used to pass parameters from one program to another. It appears in the Call statement of the calling program to specify the parameter list. These parameters must be working storage fields. The called program must have a USING clause on its PROCEDURE DIVISION statement followed by the parameters the program is receiving. These fields are defined

in the LINKAGE SECTION of the DATA DIVISION, which follows the WORKINGSTORAGE SECTION. All of the received fields are updateable by the called program. The parameters do not have to have the same names in the calling and called programs but the sizes and data types have to match.
(In calling program) CALL 'PGM2.OBJ' USING WS-FIELD-1, WS-FIELD-2, WS-FIELD-3 END-CALL (In called program) PROCEDURE DIVISION USING LK-FIELD-A, LK-FIELD-B, LK-FIELD-C

See the algorithms page for sample code on calling one program from another. Value Value allows you to initialize a field at the same time it is defined. The VALUE clause follows the PIC clause and must be the proper type of data. The value can be changed in code at any time.
05 05 WS-NBR-LINES-PER-PAGE FILLER PIC 99 VALUE 60. PIC X(6) VALUE 'PAGE: '.

Some compilers will require the VALUE data to be the proper size also, others will truncate to fit. Most compilers will not allow VALUEs in input FDs - it is a bad idea in any case. Also see Continuation Initialize. Write The write statement will write data to the specified file. The file must be opened for output. Attempting to write to an unopened file or a file opened for input will produce a run-time error.
WRITE record-name.

Optional clauses are FROM, BEFORE and AFTER. FROM specifies a working-storage field from which the system will select the data that is to be written. FROM can appear with either BEFORE or AFTER. BEFORE and AFTER specify actions to be taken by the printer along with writing a record of data. You can either specify the number of lines that are to be advanced or you

can specify advancing to the top of the next page. BEFORE and AFTER cannot appear in the same write.
WRITE record-name FROM working-storage field END-WRITE. WRITE record-name AFTER ADVANCING value LINES END-WRITE. WRITE record-name AFTER PAGE END-WRITE.

Where value can be a literal or a field. Also see Delimiters.

File error codes:


Codes beginning with a '0' are considered successful, there just may be an FYI message. Codes beginning with a "1" are considered "at end" messages and those beginning with a "2" are considered "invalid key" messages.

00 Successful operation. (Any) 02 Key on record just read is duplicated on the next record (Read Next) Or key on record just added is duplicated in the file (Write, Rewrite) In either case the file allows duplicate keys. 05 Optional file is missing. If opened I-O the file was created. If this happened on a DELETE FILE then the file was not found. (Open, Delete File) 07 Attempted CLOSE REEL on a file that is not on tape. Close was successful. (Close) 0M Successful operation but some optional feature was not used or supported. (Any) 10 End of file. (Read Next) 14 Attempted sequential read on a relative file and relative key is too large. (Read Next) 21 Primary key written out of sequence or primary key on a rewrite does not match that of last record read. Only for indexed files opened sequentially. (Write, Rewrite) 22 Duplicate key found but not allowed. (Write, Rewrite) 23 Record not found. (Read) 24 Disk full. (Write, Rewrite)

24,01 Sequential write to a relative file and the relative key is too big. (Write) 30,nn Permanent error reported by the operating system. nn will be set to an operating system status value. (Any) 34 Disk full for sequential file or sort file. (Write, Sort) 35 File not found. (Open, Sort) 37,01 File being opened is not on the appropriate storage device for the mode it is being opened. (Open) 37,07 User does not authority to access the file. (Open) 37,08 Attempted open of print file for input. (Open) 37,09 Attempted open of a sequential file as I-O. (Open) 37,99 A Windows or NT run-time operation that is not network-enabled attempted to access a file on a remote machine. (Any) 38 File previously closed with LOCK. (Open) 39,nn File attributes do not match COBOL description. (Open) nn: o 01 - Mismatch detected but source unknown. o 02 - Mismatch with maximum record size. o 03 - Mismatch with minimum record size. o 04 - Mismatch with number of keys. o 05 - Mismatch with primary key description. o 06 - Mismatch with 1st alternate key description. o 07 - Mismatch with 2nd alternate key description. List continues with each alternate key.

41 File already open. (Open)

42 File not open. (Close, Unlock) 43 No current record. (Rewrite, Delete) 44 Record size changed and file does not allow it. (Rewrite) Also can happen if record does not conform to the RECORD CONTAINS clause in the program (Write, Rewrite). 46 No current record. Either did not issue a START or it failed. (Read Next) Note that is error code can be generated with sequential files if an item in the FD is accessed before the 1st record is read or after the end of file was reached.

47,01 File not open for input or I-O. (Read, Start) 47,02 File not open. (Read, Start) 48,01 File opened for input or sequential file opened as I-O. (Write) 48,02 File not open. (Write) 49,01 File not opened for I-O. (Rewrite, Delete) 49,02 File not open. (Rewrite, Delete) 90 Unusable file. Maybe empty file opened as I-O. (Open) 91 Password failure. (Open) 92 File already open. (Open) File not open. (Close, Start) File not open or already at end. (Read, Read Next) File not open or incorrect key. (Write) File not open or no previous read. (Rewrite, Delete)

93 File locked by another user. (Open) Also possible if there is not enough virtual storage. Could also happen if the program that created the file did not explicitly close the file - especially nonsequential files. The ACUCOBOL debugger will generate this error if it attempts to open a file as output and the file already exists.

94,10 Too many files open. (Open) 94,62 One of the LINAGE values for this file is illegal or out of range. (Open, Write) 94,63 Key not specified for a SORT or MERGE statement. 95 Conflicting file attributes. (Open) 96 No DD statement. (Open) 97 File not closed by previous job. (Open) 98,nn Index is corrupt. (Any) 99 Record locked by another user. (Read, Write, Rewrite, Delete) 9A Not enough memory for operation. (Any - usually Sort) 9B Requested operation not supported by the operating system. (Any) 9C,01 Operating system lock table is full 9C,02 Internal global lock table is full 9C,03 Internal per-file lock table is full

9D,nn Host file system error. nn is the host file system error code. (Any) 9E,nn Error in the transaction system. See section J.4, "Transaction Error Codes". 9Z This run-time has a limit on the number of records that can be processed and that limit has been exceeded. (Any)

Das könnte Ihnen auch gefallen