I'm learning COBOL and am attempting to read an unformatted file with C style file i/o (reading x bytes at a time). I've so far succeeded in reading the file one byte at a time and displaying the individual characters immediately, but I've been unable to store the contents of the file in a variable.
The code that I've tried is this:
IDENTIFICATION DIVISION.
PROGRAM-ID. FILEREADER.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT FILE-TO-READ
ASSIGN USING INPUT-FILE-NAME
ORGANIZATION IS SEQUENTIAL
ACCESS IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD FILE-TO-READ.
01 CHAR PIC X(1).
WORKING-STORAGE SECTION.
01 FILE-DATA-POINTER USAGE IS POINTER.
01 FILE-DATA-HOLDER PIC X BASED.
01 INPUT-DATA.
05 INPUT-FILE-NAME PIC X(100).
05 INPUT-FILE-CHARACTERS PIC 9(18).
01 MISC-DATA.
05 EOF PIC X(1).
05 STRING-INDEX PIC 9(18) USAGE IS COMP.
PROCEDURE DIVISION.
MAIN.
PERFORM GET-INPUT.
PERFORM ALLOCATE-STORAGE.
PERFORM READ-FILE.
PERFORM DISPLAY-FILE.
PERFORM CLEAN-UP.
STOP RUN.
GET-INPUT.
DISPLAY "Please enter the name of the file (maximum 100 char
- "acters)."
ACCEPT INPUT-FILE-NAME.
DISPLAY "Please enter the number of characters in your file
- "(the number of bytes)."
ACCEPT INPUT-FILE-CHARACTERS.
ALLOCATE-STORAGE.
ALLOCATE INPUT-FILE-CHARACTERS CHARACTERS RETURNING
FILE-DATA-POINTER SET ADDRESS OF FILE-DATA-HOLDER TO
FILE-DATA-POINTER.
IF ADDRESS OF FILE-DATA-POINTER = NULL
DISPLAY "System error when allocating RAM. Exiting..."
STOP RUN
END-IF.
READ-FILE.
INITIALIZE STRING-INDEX.
MOVE 'N' TO EOF.
MOVE 1 TO STRING-INDEX.
OPEN INPUT FILE-TO-READ.
PERFORM UNTIL EOF = 'Y'
READ FILE-TO-READ
AT END MOVE 'Y' TO EOF
NOT AT END MOVE CHAR TO FILE-DATA-HOLDER
(STRING-INDEX:1)
ADD 1 TO STRING-INDEX
END-READ
END-PERFORM.
CLOSE FILE-TO-READ.
DISPLAY-FILE.
DISPLAY FILE-DATA-HOLDER.
CLEAN-UP.
FREE FILE-DATA-POINTER.
When compiling this program I get the warning:
file_reader.cbl:64: warning: suspicious reference-modification: always using max. length [-Wothers]
62 | READ FILE-TO-READ
63 | AT END MOVE 'Y' TO EOF
64 > NOT AT END MOVE CHAR TO FILE-DATA-HOLDER
65 | (STRING-INDEX:1)
The program outputs the following:
Please enter the name of the file (maximum 100 characters).
test.txt <------ User input
Please enter the number of characters in your file (the number of bytes).
4 <------ Also user input
L
In this example, the text file contains the phrase "Lorem Ipsum" ASCII encoded.
After some research I figured out that this is because strings can't be subscripted/indexed like in C or Python. I then tried to use an array (table) of characters instead of a string, but this didn't work because you apparently can't dynamically allocate tables in COBOL, so now I'm back at square one.
To summarize, I need to find a way to store an entire file in a dynamically allocated variable in standard COBOL.
Any help is appreciated.
EDIT: I've figured out that the problem is not with the subscripting, but rather that the string only has a length of 1 character.
I've figured out what I was doing wrong. The picture for the variable FILE-DATA-HOLDER was limiting the number of characters that could be contained in the variable (obvious now that I think about it). All I had to do was change the picture of the aforementioned variable and slightly tweak the DISPLAY statement at the end.
Here is my updated code:
IDENTIFICATION DIVISION.
PROGRAM-ID. FILEREADER.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT FILE-TO-READ
ASSIGN USING INPUT-FILE-NAME
ORGANIZATION IS SEQUENTIAL
ACCESS IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD FILE-TO-READ.
01 CHAR PIC X(1).
WORKING-STORAGE SECTION.
01 FILE-DATA-POINTER USAGE IS POINTER.
01 FILE-DATA-HOLDER PIC X(2147483646) BASED.
01 INPUT-DATA.
05 INPUT-FILE-NAME PIC X(100).
05 INPUT-FILE-CHARACTERS PIC 9(10).
01 MISC-DATA.
05 EOF PIC X(1).
05 STRING-INDEX PIC 9(18) USAGE IS COMP.
PROCEDURE DIVISION.
MAIN.
PERFORM GET-INPUT.
PERFORM ALLOCATE-STORAGE.
PERFORM READ-FILE.
PERFORM DISPLAY-FILE.
PERFORM CLEAN-UP.
STOP RUN.
GET-INPUT.
DISPLAY "Please enter the name of the file (maximum 100 char
- "acters)."
ACCEPT INPUT-FILE-NAME.
DISPLAY "Please enter the number of characters in your file
- "(the number of bytes)."
ACCEPT INPUT-FILE-CHARACTERS.
ALLOCATE-STORAGE.
ALLOCATE INPUT-FILE-CHARACTERS CHARACTERS RETURNING
FILE-DATA-POINTER SET ADDRESS OF FILE-DATA-HOLDER TO
FILE-DATA-POINTER.
IF ADDRESS OF FILE-DATA-POINTER = NULL
DISPLAY "System error when allocating RAM. Exiting..."
STOP RUN
END-IF.
READ-FILE.
INITIALIZE STRING-INDEX.
MOVE 'N' TO EOF.
MOVE 1 TO STRING-INDEX.
OPEN INPUT FILE-TO-READ.
PERFORM UNTIL EOF = 'Y'
READ FILE-TO-READ
AT END MOVE 'Y' TO EOF
NOT AT END MOVE CHAR TO FILE-DATA-HOLDER
(STRING-INDEX:1)
ADD 1 TO STRING-INDEX
END-READ
END-PERFORM.
CLOSE FILE-TO-READ.
DISPLAY-FILE.
DISPLAY FILE-DATA-HOLDER (1:STRING-INDEX).
CLEAN-UP.
FREE FILE-DATA-POINTER.