I am creating a COBOL application using the screen section (Library where you can lend books).
How I can create a scrollable list using Screen Section? Can it be implemented so that you can scroll through that list using certain keys?
In my application I have screens where lists are displayed but there I am displaying a limited number of items and then a key has to be pressed to see further items.
But now I have a more complex situation.
This is the code I would like to "convert" into the screen section mode:
IDENTIFICATION DIVISION.
PROGRAM-ID. RETBOOK.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
COPY "SLCUST.cbl".
COPY "SLBOOK.cbl".
COPY "SLLOAN.cbl".
DATA DIVISION.
FILE SECTION.
COPY "FDCUST.cbl".
COPY "FDBOOK.cbl".
COPY "FDLOAN.cbl".
WORKING-STORAGE SECTION.
COPY "WSALPHA".
77 A-PAUSE PIC X.
77 LOAN-FILE-AT-END PIC X.
77 THE-CUSTOMER-ID PIC 9(5).
77 THE-CUSTOMER-LAST-NAME PIC X(20).
77 THE-CUSTOMER-FIRST-NAME PIC X(20).
77 THE-BOOK-TO-RETURN-ID PIC 9(5).
77 LOAN-FOUND PIC X.
PROCEDURE DIVISION.
PROGRAM-BEGIN.
PERFORM DO-RETURN.
PROGRAM-EXIT.
EXIT PROGRAM.
PROGRAM-DONE.
STOP RUN.
OPEN-FILES.
OPEN I-O CUSTOMER-FILE.
OPEN I-O BOOK-FILE.
OPEN I-O LOAN-FILE.
CLOSE-FILES.
CLOSE CUSTOMER-FILE.
CLOSE BOOK-FILE.
CLOSE LOAN-FILE.
DO-RETURN.
PERFORM OPEN-FILES.
PERFORM FIND-CUSTOMER.
PERFORM DISPLAY-LOANED-BOOK-IDS.
IF LOAN-FOUND = "Y"
PERFORM RETURN-BOOK
ELSE
DISPLAY "No loans available".
PERFORM CLOSE-FILES.
FIND-CUSTOMER.
PERFORM ENTER-CUSTOMER-ID.
PERFORM GET-CUSTOMER-BY-ID.
ENTER-CUSTOMER-ID.
DISPLAY "Enter id of customer to find.".
ACCEPT THE-CUSTOMER-ID.
GET-CUSTOMER-BY-ID.
CALL "CUSTBYID" USING THE-CUSTOMER-ID.
DISPLAY "Press any key to continue.".
ACCEPT A-PAUSE.
DISPLAY-LOANED-BOOK-IDS.
PERFORM FIND-LENT-BOOKS-OF-CUSTOMER.
FIND-LENT-BOOKS-OF-CUSTOMER.
PERFORM READ-CUSTOMER-DATA.
PERFORM DISPLAY-CUSTOMER-DATA.
PERFORM INIT-DATA.
MOVE CUSTOMER-ID TO LOAN-CUSTOMER.
PERFORM READ-LOAN-DATA.
INIT-DATA.
MOVE SPACES TO LOAN-RECORD.
READ-CUSTOMER-DATA.
MOVE THE-CUSTOMER-ID TO CUSTOMER-ID.
READ CUSTOMER-FILE RECORD
INVALID KEY
DISPLAY "CUSTOMER NOT FOUND".
READ-LOAN-DATA.
MOVE "Y" TO LOAN-FOUND
START LOAN-FILE
KEY = LOAN-CUSTOMER
INVALID KEY
DISPLAY "No lent books."
MOVE "N" TO LOAN-FOUND
MOVE "Y" TO LOAN-FILE-AT-END
END-START.
PERFORM READ-NEXT-LOAN-DATA
UNTIL LOAN-FILE-AT-END = "Y".
READ-NEXT-LOAN-DATA.
IF LOAN-CUSTOMER = CUSTOMER-ID
READ LOAN-FILE NEXT RECORD
AT END
MOVE "Y" TO LOAN-FILE-AT-END
PERFORM DISPLAY-LOAN-DATA
ELSE
MOVE "Y" TO LOAN-FILE-AT-END.
DISPLAY-CUSTOMER-DATA.
DISPLAY "Lent books of".
DISPLAY CUSTOMER-FIRST-NAME.
DISPLAY CUSTOMER-LAST-NAME.
DISPLAY-LOAN-DATA.
DISPLAY "Loan id : " LOAN-ID.
DISPLAY "Loan Book : " LOAN-BOOK.
RETURN-BOOK.
CALL "LOANDEL".
Code of "LOANDEL"
IDENTIFICATION DIVISION.
PROGRAM-ID. LOANDEL.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
COPY "SLBOOK.cbl".
COPY "SLLOAN.cbl".
DATA DIVISION.
FILE SECTION.
COPY "FDBOOK.cbl".
COPY "FDLOAN.cbl".
WORKING-STORAGE SECTION.
77 THE-BOOK-ID PIC 9(5).
77 LOAN-FOUND PIC X.
77 BOOK-FOUND PIC X.
77 LOAN-KEY PIC 9(5).
PROCEDURE DIVISION.
PROGRAM-BEGIN.
OPEN I-O LOAN-FILE.
OPEN I-O BOOK-FILE.
PERFORM MAIN-PROCESS.
CLOSE LOAN-FILE.
CLOSE BOOK-FILE.
PROGRAM-EXIT.
EXIT PROGRAM.
PROGRAM-DONE.
STOP RUN.
MAIN-PROCESS.
PERFORM ENTER-BOOK-ID-TO-RETURN.
PERFORM DISPLAY-BOOK.
PERFORM FIND-LOAN.
IF LOAN-FOUND = "Y"
PERFORM DISPLAY-LOAN
PERFORM DELETE-LOAN
PERFORM MAKE-BOOK-AVAILABLE
ELSE
DISPLAY "Loan not found".
ENTER-BOOK-ID-TO-RETURN.
DISPLAY "Enter book id to return".
ACCEPT THE-BOOK-ID.
MOVE THE-BOOK-ID TO LOAN-BOOK.
MOVE THE-BOOK-ID TO BOOK-ID.
DISPLAY-BOOK.
CALL "BOOKBYID" USING THE-BOOK-ID.
FIND-LOAN.
MOVE "Y" TO LOAN-FOUND.
START LOAN-FILE
KEY = LOAN-BOOK
INVALID KEY
MOVE "N" TO LOAN-FOUND
DISPLAY "This book is not lent by the customer".
READ LOAN-FILE NEXT RECORD.
DELETE-LOAN.
DELETE LOAN-FILE RECORD
INVALID KEY
DISPLAY "Error deleting loan".
DISPLAY-LOAN.
DISPLAY "Loan to delete:".
DISPLAY "Loan id : " LOAN-ID.
DISPLAY "Loan customer : " LOAN-CUSTOMER.
DISPLAY "Loan book : " LOAN-BOOK.
DISPLAY "Loan date : " LOAN-DATE.
DISPLAY "Loan return date : " LOAN-RETURN-DATE.
MAKE-BOOK-AVAILABLE.
PERFORM FIND-BOOK.
MOVE "N" TO BOOK-LENT.
MOVE "N" TO BOOK-OVERDUE.
PERFORM SAVE-CHANGES.
FIND-BOOK.
MOVE "Y" TO BOOK-FOUND.
READ BOOK-FILE RECORD
INVALID KEY
MOVE "N" TO BOOK-FOUND.
SAVE-CHANGES.
REWRITE BOOK-RECORD
INVALID KEY
DISPLAY "Error rewriting book record".
Code of "BOOKBYID"
IDENTIFICATION DIVISION.
PROGRAM-ID. BOOKBYID.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
COPY "SLBOOK.cbl".
DATA DIVISION.
FILE SECTION.
COPY "FDBOOK.cbl".
WORKING-STORAGE SECTION.
77 BOOK-FOUND PIC X.
LINKAGE SECTION.
77 THE-BOOK-ID PIC 9(5).
PROCEDURE DIVISION
USING THE-BOOK-ID.
PROGRAM-BEGIN.
PERFORM OPEN-FILE.
PERFORM GET-BOOK-BY-ID.
PERFORM CLOSE-FILE.
PROGRAM-EXIT.
EXIT PROGRAM.
PROGRAM-DONE.
STOP RUN.
OPEN-FILE.
OPEN I-O BOOK-FILE.
CLOSE-FILE.
CLOSE BOOK-FILE.
GET-BOOK-BY-ID.
MOVE THE-BOOK-ID TO BOOK-ID.
PERFORM READ-BOOK.
IF BOOK-FOUND = "Y"
PERFORM DISPLAY-BOOK
ELSE
DISPLAY "Book not found".
READ-BOOK.
MOVE "Y" TO BOOK-FOUND.
READ BOOK-FILE RECORD
INVALID KEY
MOVE "N" TO BOOK-FOUND.
DISPLAY-BOOK.
DISPLAY "Title : " BOOK-TITLE.
DISPLAY "Author : " BOOK-AUTHOR.
I am using SCREEN SECTION in my other programs and DISPLAY/ACCEPT and DISPLAY BLANK SCREEN (wrapped in a paragraph) to clear the screen. Navigation using arrows, TAB and ENTER is not sufficient in this situation because I also would like to navigate through the scrollable list using other keys for example F3/F4.How can I achieve this here ?
Answer to the question "How to create a scrollable list of records in SCREEEN SECTION":
The most portable way is to define a CRT STATUS (goes to SPECIAL NAMES paragraph) which can be queried after each ACCEPT. The actual values you receive differ between implementations with the biggest difference you'll see is between X/Open COBOL definition (3-byte status, partial binary) and COBOL 2002+ (4byte status), some COBOL implementations may even accept and handle both (like GnuCOBOL 3.2+ ;-).
Implementations commonly ship a copybook with values you can test against, as there was no specification for the COBOL environment used: GnuCOBOL as an example would have copy screenio. with 4-byte definitions as constants (level 78 constants, not all COBOL implementations have those, the standard would use 01 ... CONSTANT) and an implied 4-byte status, allowing checks like IF COB-CRT-STATUS = COB-SCR-PAGE-DOWN and similar.
If you specify the CRT STATUS clause then query that, if it is a 3 byte one then you'd normally check the different parts.
Related
I'm entirely new to COBOL. I have a small COBOL program and a small C file. According to this article: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.ceea400/sdtpt.htm
the equivalent of a C signed integer in COBOL is
PIC S9(9) USAGE IS BINARY
I want to call the functions in the C file from COBOL, and display the result in COBOL. I am able to call the function, and it seems to behave as expected, data being passed as expected, but I'm not able to display the binary value with DISPLAY in COBOL.
My COBOL program:
IDENTIFICATION DIVISION.
PROGRAM-ID. MSQLTST5_COBHELPER.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 SQLCODE PIC S9(9) USAGE IS BINARY VALUE 100.
PROCEDURE DIVISION.
HEAD SECTION.
MAIN.
DISPLAY "COBOL, sqlcode is: " SQLCODE.
CALL "CONNECT_DEFAULT" USING SQLCODE.
DISPLAY "COBOL, sqlcode is: " SQLCODE.
STOP RUN.
END PROGRAM MSQLTST5_COBHELPER.
The C function I'm calling:
void connect_default(int* sqlcode)
{
printf("C, sqlcode is: %d\n", *sqlcode);
// internal code that places the expected error code -14006 in the variable sqlcode
printf("C, sqlcode is: %d\n", *sqlcode);
}
The output of running my COBOL program:
COBOL, sqlcode is: d
C, sqlcode is: 100
C, sqlcode is: -14006
COBOL, sqlcode is: J▒▒▒
It seems that the variable does indeed have the value 100 that I gave it, and then is passed correctly between C and COBOL, but when I ask COBOL to display the variable it seems to try to pick out the character that has the given ASCII code, rather than the numerical value, as the character 'd', which has the ASCII code 100, is displayed rather than the number 100.
How do I display this value as a numeric value in COBOL?
Why don't you transfer the contents of the SQLCODE field to a USAGE DISPLAY field using the MOVE instruction? It'll convert the binary number to a numeric one.
If the formatting is strange — here is why:
Signed numeric pictures without the SIGN SEPARATE clause must somehow include the sign without taking up space, so most compilers combine the last digit with the sign of the number. Most conventions use J for −1 till R for −9. They also pad the number with leading zeros. So -14006 will convert to 00001400O, because the last digit is a 6, and because it must be conbined with the minus sign, the last digit becomes -6, which is represented by an O. Roughly the same reasoning counts for 00000010{.
In order to reformat the number, you could actually use another picture, like
pic S9(9) sign leading separate
That will display -14006 as -000014006
This should achieve your intended results.
IDENTIFICATION DIVISION.
PROGRAM-ID. MSQLTST5_COBHELPER.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 SQLCODE PIC S9(9) USAGE IS BINARY VALUE 100.
01 SQLCODE-E PIC -9(9).
PROCEDURE DIVISION.
HEAD SECTION.
MAIN.
PERFORM DISPLAY-SQLCODE.
CALL "CONNECT_DEFAULT" USING SQLCODE.
PERFORM DISPLAY-SQLCODE.
STOP RUN.
DISPLAY-SQLCODE.
MOVE SQLCODE TO SQLCODE-E.
DISPLAY "COBOL, sqlcode is: " SQLCODE-E.
END PROGRAM MSQLTST5_COBHELPER.
The standard way to do this is to move the binary field to a "numeric edited" field:
01 DISPLAY-SQLCODE PIC -(9)9.
Then
MOVE SQLCODE TO DISPLAY-SQLCODE
Full example:
IDENTIFICATION DIVISION.
PROGRAM-ID. MSQLTST5_COBHELPER.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 SQLCODE PIC S9(9) USAGE IS BINARY VALUE 100.
01 DISPLAY-SQLCODE PIC -(9)9.
PROCEDURE DIVISION.
HEAD SECTION.
MAIN.
MOVE SQLCODE TO DISPLAY-SQLCODE
DISPLAY "COBOL, sqlcode is: " DISPLAY-SQLCODE
CALL "CONNECT_DEFAULT" USING SQLCODE
MOVE SQLCODE TO DISPLAY-SQLCODE
DISPLAY "COBOL, sqlcode is: " DISPLAY-SQLCODE
STOP RUN
.
END PROGRAM MSQLTST5_COBHELPER.
Move the variable to the display field and then just display the field
01 WS-FIELD-FOR-DISPLAY PIC -(9)9.
Reusing the file definition of file1 for another i.e file2 with out opening /closing file1.
I have a monthly file and my requirement is generate a daily file similar to monthly file.The record length and the File definition of both the files are same.
Can i make use of monthly file's FD to hold data and do some validation using monthly file data items for my Daily file and write my daily file later?
lot of validations are being done using monthly file's FD variables and I cannot do same validations using daily file's variables as i need to make changes/rewrite lot of code in many places in multiple programs.
Note: I am doing my daily file processing & generation after the monthly processing is over at the end .
Also ,we are using UNIX environment.
Please suggest me how can i achieve this if above mentioned method is not possible.
The record area for a file is not available until the file is opened. The SAME RECORD AREA clause may be used to provide an alias.
identification division.
program-id. srac.
environment division.
input-output section.
file-control.
select optional monthly-file assign "monthly.dat"
file status monthly-stat.
select daily-file assign "daily.dat"
file status daily-stat.
i-o-control.
same record area monthly-file daily-file.
data division.
file section.
fd monthly-file.
1 monthly-id pic 999.
fd daily-file.
1 daily-id pic 999.
working-storage section.
1 monthly-stat pic x(2).
1 daily-stat pic x(2).
procedure division.
open input monthly-file daily-file
display "monthly-stat:" space monthly-stat
display "daily-stat: " space daily-stat
read daily-file
display "monthly-id:" space monthly-id
if monthly-id < 10
add 100 to monthly-id
end-if
display "daily-id: " space daily-id
close monthly-file daily-file
stop run
.
monthly-stat: 05
daily-stat: 00
monthly-id: 001
daily-id: 101
In this example, the monthly and daily files have identical record description entries; but, the monthly file does not exist. Yet, one may use the data-names for the monthly file for validation, modification, or whatever.
Hi i am learning cobol from tutorialpoints and every program from there works as i've tested them in OpenCobolIDE(some needed a little editing). Then i came across the File Handling chapter and in there the program had a lot of errors. I did manage to rewrite the program until it didn't show me any errors but it doesn't do anything.
Here's my code:
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT STUDENT ASSIGN TO
'C:\Cobol\FIle Handling\input.txt'
ORGANIZATION IS INDEXED
ACCESS IS RANDOM
RECORD KEY IS STUDENT-ID
FILE STATUS IS FS.
DATA DIVISION.
FILE SECTION.
FD STUDENT.
01 STUDENT-FILE.
05 STUDENT-ID PIC 9(5).
05 NAME PIC A(25).
WORKING-STORAGE SECTION.
01 WS-STUDENT-FILE.
05 WS-STUDENT-ID PIC 9(5).
05 WS-NAME PIC A(25).
01 FS PIC 9(02).
PROCEDURE DIVISION.
OPEN I-O STUDENT.
MOVE 20005 TO STUDENT-ID.
READ STUDENT RECORD INTO WS-STUDENT-FILE
KEY IS STUDENT-ID
INVALID KEY DISPLAY 'Invalid Key'
NOT INVALID KEY DISPLAY WS-STUDENT-FILE
END-READ.
CLOSE STUDENT.
STOP RUN.
This is the text file:
20003 Mohtashim M.
20004 Nishant Malik
20005 Amitabh Bachhan
The result should be the text:
20005 Amitabh Bachhan
It's doing something: It's reading the file. But that's all; you didn't ask for it to display or do anything else beyond reading the record into memory. You might want to look at using the DISPLAY statement or maybe create another file to write the output to.
Might I make a couple of suggestions?
In modern COBOL, stylistically, you don't put a period after everything in the procedure division -- you only put it in where it is necessary. For example:
PROCEDURE DIVISION.
OPEN I-O STUDENT
MOVE 20005 TO STUDENT-ID
READ STUDENT RECORD INTO WS-STUDENT-FILE
KEY IS STUDENT-ID
INVALID KEY DISPLAY 'Invalid Key'
NOT INVALID KEY DISPLAY WS-STUDENT-FILE
END-READ
CLOSE STUDENT
STOP RUN
.
Although the compiler doesn't care about spaces and returns, if I were you, I'd try to indent my code a bit better (I like how I indented the above :-) ). It's up to you and a lot of people like to do it differently, but if you are consistent you can spot problems that might sneak through your code.
Edit: I didn't notice that you were reading with a key from a text file. So, either you need to:
read from a pre-built indexed file, or
read the file sequentially and search for what you want by comparing what you read for the student id you wanted.
I have an array of 5 elements and each of the elements holds a character. I want to accept user input in one line. For example: ABCDE. And I intend element 1 of the array to have A and element 2 of the array to have B and so on. Could someone help with this? I have attached the relevant portions of the code below:
environment division.
input-output section.
file-control.
select standard-input assign to keyboard.
select standard-output assign to display.
data division.
file section.
fd standard-input.
01 stdin-record pic x(80).
fd standard-output.
01 stdout-record pic x(80).
working-storage section.
01 input-area.
02 inputCharacters pic x(1) occurs 5 times.
01 print-line.
02 inputCharacters pic x(1) occurs 5 times.
procedure division.
open input standard-input, output standard-output.
read standard-input into input-area
at end
close standard-input, standard-output
end-read.
write
stdout-record from print-line after advancing 5 line
end-write
stop run.
MOVE input-area TO print-line
For the code you have, you could also do this:
write
stdout-record from input-area after advancing 5 line
end-write
If you don't need two copies of a table (COBOL doesn't really have "arrays" in the way you're probably used to) then don't have two copies.
If you do have two tables, I'd suggest making the item names different. If you don't, you're making things tougher by having to use "qualification" to make the references unique.
MOVE inputCharacters ( 1 ) OF input-area
TO inputCharacters ( 1 ) OF print-line
Instead of
MOVE inputCharacters ( 1 )
TO outputCharacters ( 1 )
If you don't mind qualification yourself, you may find that colleagues or future maintainers hate it.
I'm not quite sure what you want to happen with this:
read standard-input into input-area
at end
close standard-input, standard-output
end-read.
You only do one read, you you'll only get at end when there is no data (whatever that means with keyboard). In that case, you don't have data to do anything with.
You should look at how to use FILE STATUS for each file. Check the file-status field after each IO, and I'd also recommend using the file-status field for end-of-file checking, rather than the cumbersome AT END.
However, as I said, I don't know what that means with keyboard... so perhaps that won't work :-)
I'm coding routines like:
READ-A.
READ FILE-A
AT END
MOVE 1 TO EOF-A
NOT AT END
ADD 1 TO CN-READ-A
END-READ.
F-READ-A. EXIT.
to read several files and I was wondering if there's a way to code a routine that is able to read the filename from a variable so I don't have to code the same thing for each file. Thanks!
One solution as said above is to use multiple programs or nested program, for which
I have included an example below, which is solution 1.
Another solution is to COBOL classes, which might not be to your liking but I like them, so I've included an example, which is solution 2.
Solution 1:
program-id. TestProgram.
working-storage section.
01 file-name pic x(128).
01 file-lines pic 9(9).
procedure division.
move 0 to file-lines
move "d:\rts_win32.txt" to file-name
call "program1" using file-name file-lines
display file-lines
stop run
end program TestProgram.
program-id. Program1.
file-control.
select file-a assign to myfile
organization is line sequential.
data division.
fd file-a.
01 file-a-line pic x(80).
working-storage section.
01 EOF-A pic 9 value 0.
linkage section.
01 lk-filename pic x(128).
01 CN-READ-A pic 9(9).
procedure division using lk-filename
CN-READ-A.
move lk-filename to myfile
open input file-a
perform READ-A until EOF-A equals 1
close file-a
goback.
READ-A.
READ FILE-A
AT END
MOVE 1 TO EOF-A
NOT AT END
ADD 1 TO CN-READ-A
END-READ.
F-READ-A.
EXIT.
end program Program1.
Solution 2
program-id. TestProgram.:
working-storage section.
01 file-counter type FileLineCounter.
procedure division.
set file-counter to new type FileLineCounter("d:\rts_win32.txt")
display file-counter::LineCount
stop run
end program TestProgram.
class-id FileLineCounter.
file-control.
select file-a assign to myfile
organization is line sequential.
data division.
fd file-a.
01 file-a-line pic x(80).
working-storage section.
01 cn-read-a binary-long property as "LineCount".
method-id New.
01 EOF-A pic 9 value 0.
procedure division using by value filename as string.
set myfile to filename
open input file-a
perform READ-A until EOF-A equals 1
close file-a
goback.
READ-A.
READ FILE-A
AT END
MOVE 1 TO EOF-A
NOT AT END
ADD 1 TO CN-READ-A
END-READ.
F-READ-A.
EXIT.
end method.
end class.
May not be "in the wild" yet with compiler support, but the current ISO Draft 20xx standard includes FUNCTION-ID in place of PROGRAM-ID. It adds a parameter friendly function call computing paradigm to COBOL.
Might not help today, but maybe in the near future. If I'm not mistaken, User Defined Functions are actually from the COBOL 2002 spec, but it seems compiler vendors are hit or miss on support for the feature.
FUNCTION-ID support is in closed trials for OpenCOBOL 2.0, but the timeline for the 2.0 release is undetermined and could be another year or more before it's made public.
The proper Cobol way to parameterize routines is via the nested subprogram.
You can do what you want, but it is dependant upon your compiler and environment, you can pass a file, or a file name, or a DDname.
What platform are you on?
Edit: On z/OS, you can change what FILE-A points to at runtime using putenv() to adjust the dataset name associated with the DDNAME that FILE-A uses.
See:
http://ibmmainframes.com/post-57281.html
http://cicswiki.org/cicswiki1/index.php?title=How_do_I_allocate_a_file_dynamically_using_COBOL%3F
You will need a OPEN-A and CLOSE-A paragraph as well between switching files.
It isn't exactly passing parameters to your read statement, but it lets you reuse your OPEN/READ/WRITE/CLOSE statements for different files. But only serially.
There was a way, under VS COBOL II, where you could pass an FD to a subprogram, that would look something like:
CALL MYREADPGM USING FILE-A
CALL MYREADPGM USING FILE-B
This possible with Enterprise Cobol but IIRC VisualAge does not support that.
I realize this is an old thread, but hopefully someone might find this useful in the future: IBM's Enterprise COBOL on z/OS 6.4 compiler supports user-defined functions (released May 2022). User-defined functions could be a useful alternative to the other suggestion for internal programs. In contrast to program calls, there are compile time checks for parameters to user-defined function invocations. Also, you can invoke the function in a lot of places where you couldn't call a program, like within a
n expression.
Here's an example based on passing a file name to a function. It might be possible to combine this with the PUTENV() suggestion above.
IDENTIFICATION DIVISION.
FUNCTION-ID. READ-FILE.
DATA DIVISION.
LINKAGE SECTION.
1 FILE-NAME PIC X(50).
1 RET PIC 9(9).
PROCEDURE DIVISION USING FILE-NAME RETURNING RET.
* DO STUFF WITH FILE-NAME
* ...
GOBACK
.
END FUNCTION READ-FILE.
IDENTIFICATION DIVISION.
PROGRAM-ID. MAINPROG.
DATA DIVISION.
WORKING-STORAGE SECTION.
1 READ-RESULT PIC 9(9).
PROCEDURE DIVISION.
COMPUTE READ-RESULT = FUNCTION READ-FILE('MYINPUTFILE')
GOBACK
.
END PROGRAM MAINPROG.
More examples can be found in the Programming Guide Chapter 32 Using user-defined functions.
https://www.ibm.com/support/pages/enterprise-cobol-zos-documentation-library#Table642
You could create a data file of filenames, treat each one as an individual record, and then read each file. In the "SELECT ...ASSIGN" you would need to use a working-storage variable for the filename and move the value from the 'file of filenames' into it.
As you are using VisualAge, I assume in UNIX, you might also be able to run the program from the shell (sh,ksh), with the filename as a parameter, and repeatedly run the program from the shell for each file name.