How to do balance line in Cobol using 3 input files? - cobol

my challenge on class is code a program which read 3 input txt files and generate 1 txt output file. All input files must be preferentially line sequential mode and no one indexed (this are rules for breaking our minds).
File 1 has field ID-USER (ordered by it) and others;
File 2 has fiels ID-USER (ordered by it), ID-JOB and others;
File 3 has field ID-JOB (ordered by it) and others.
Output file will join data from 3 files.
Balance line in cobol with 2 files is a hard work but I can do it. But using 3 input files, when ID-USER is corresponding in files 1 and 2, I must advance read on file 3 to record corresponding ID-JOB on files 2 and 3, and my balance line is doesn't more work because I don't know if is possible "restart" read on file 3.
Resuming: how to restart a read using sequential mode on specific input file (file 3)? Or reverse search direction on same cobol program.

Two possible processes
2 sort merge programs one on Job-Id, one on ID-USER
Load File-3 into a indexed file (VSAM file on the mainframe) or a data base. The key for the Index-File/Db would be Job-Id. Then you can do a indexed read
Two Programs
The exact sequence would depend on the file output order. You could
Sort File-2 and File-3 on Job-id and create an output file-4 with the required data from both files
Sort file-1 and file-4 on ID-USER and merge the 2 files
Alternatively you could
Sort Merge file-1 and file-2 on ID-USER and create file-4
Sort Merge file-1 and file-4 on Job-id
Index file solution
Load file-3 into an index file (say file-3i) (could use an array if small) either before your program starts or as part of the initialization.
Sort Merge file-1 and file-2 on ID-USER and do an index-lookup on File-3i

I'm never quite sure on Stack Overflow and home work when it comes to referring to online resources, but the GnuCOBOL FAQ has a sample of merging line sequential files.
Hopefully the little sample still leaves you with a chance to learn about MERGE and not rob you of any opportunity.
https://open-cobol.sourceforge.io/faq/index.html#merge
Note in the syntax rail diagram how ON ... KEY phrases can be repeated per file, with multiple files.
To avoid link rot; here is the code, but this should always be findable by web searching for "GnuCOBOL FAQ" in the MERGE reserved word entry.
GCobol >>SOURCE FORMAT IS FIXED
*> ***************************************************************
*> Author: Brian Tiffin
*> Date: 20140610
*> Purpose: Demonstrate a merge pass
*> Tectonics: cobc -x gnucobol-merge-sample.cob
*> ***************************************************************
identification division.
program-id. gnucobol-merge-sample.
environment division.
configuration section.
repository.
function all intrinsic.
io input-output section.
file-control.
select master-file
assign to "master-sample.dat"
organization is line sequential.
select eastern-transaction-file
assign to "east-transact-sample.dat"
organization is line sequential.
select western-transaction-file
assign to "west-transact-sample.dat"
organization is line sequential.
select merged-transactions
assign to "merged-transactions.dat"
organization is line sequential.
select working-merge
assign to "merge.tmp".
data data division.
file section.
fd master-file.
01 master-record pic x(64).
fd eastern-transaction-file.
01 transact-rec pic x(64).
fd western-transaction-file.
01 transact-rec pic x(64).
fd merged-transactions.
01 new-rec pic x(64).
sd working-merge.
01 merge-rec.
02 master-key pic 9(8).
02 filler pic x.
02 action pic xxx.
02 filler PIC x(52).
code *> ***************************************************************
*> not much code
*> trick. DEP, CHQ, BAL are action keywords. They sort
*> descending as DEP, CHQ, BAL, so do all deposits, then
*> all withdrawals, then balance reports.
*> ***************************************************************
procedure division.
merge working-merge
on ascending key master-key
descending key action
using eastern-transaction-file, western-transaction-file,
master-file
giving merged-transactions
done goback.
end program gnucobol-merge-sample.
Data samples look like
11111111 CHQ 0001111.11 withdrawal from account one
33333333 DEP 0333333.33 third of a million in, pocket change
33333333 CHQ 0000333.33 payroll
33333333 CHQ 0000333.33 payroll
33333333 CHQ 0000333.33 payroll
55555555 DEP 0000555.55 deposit to new record five
55555555 CHQ 0000055.55 withdrawal from account five
East
11111111 CHQ 0001111.11 withdrawal from account one
44444444 DEP 0000044.44 deposit to account four
66666666 BAL balance request for account six
West, etc.
GnuCOBOL makes it pretty easy to deal with the LINE SEQUENTIAL part.
There are more questions in your question, not mentioned here, as this listing is just to demonstrate MERGE with LINE SEQUENTIAL, and to not worry about head explosions.

How to restart a read using sequential mode on specific input file (file 3)?
To restart the reading of a file from the beginning, use CLOSE then OPEN INPUT.
Or reverse search direction on same cobol program.
There are no COBOL statements to read a line sequential file in reverse. It is possible by calling a C program to scan File 3 in reverse by treating it as a "binary" file.
It is not clear to me the term, balance line, should apply in this case. This is because the third file does not share the same sequence as the second file.
Bruce Martin has provided some suggestions for accomplishing the task.
This being a "challenge [in] class", it may be a case where you cannot use those suggestions.
However, if you want to proceed as you have outlined, then you need to be aware that if you "restart" when ID-JOB of File 2 is less than ID-JOB of File 3, you need to treat that as a potential edge case. Specifically, when ID-JOB of File 2 is less than the minimum value of ID-JOB of File 3, an infinite loop is possible.

Related

What is the logic to write a COBOL program to reverse records and move from 1 file to another?

For example:
File1
AAA
BBB
CCC
DDD
File2
DDD
CCC
BBB
AAA
What is the logic to write a COBOL program to reverse records and move from 1 file to another?
Addressing a COBOL-only solution, the method for reversing the sequence of records in a file changed between COBOL 85 and COBOL 2002. Specifically, the REVERSED phrase was made obsolete in COBOL 85 and removed in COBOL 2002.
COBOL 85
The following requires the input be fixed-length records with ORGANIZATION SEQUENTIAL.
Code:
environment division.
input-output section.
file-control.
select file1 assign "file1.dat"
organization sequential
.
select file2 assign "file2.dat"
organization sequential
.
data division.
file section.
fd file1.
01 file1-rec pic x(4).
fd file2.
01 file2-rec pic x(4).
working-storage section.
01 eof-flag pic 9 value 0.
88 eof-file1 value 1.
procedure division.
begin.
open input file1 reversed
output file2
perform read-file1
perform until eof-file1
write file2-rec from file1-rec
perform read-file1
end-perform
close file1 file2
stop run
.
read-file1.
read file1
at end
set eof-file1 to true
end-read
.
Input:
AAAABBBBCCCCDDDD
Output:
DDDDCCCCBBBBAAAA
[Note that because these are fixed-length, four-character records, there are no separators and, therefore, the records are not shown on separate lines.]
For RELATIVE or INDEXED files, it is necessary to, first, copy the records to a fixed-length sequential file, then use the above logic to create the "reversed" sequential file. For variable-length records, it is also necessary to save the record length as part of the fixed-length record before using the above reversing. Then, rather than writing fixed-length records, write variable-length records.
COBOL 2002 (untested)
Code:
environment division.
input-output section.
file-control.
select file1 assign "file1.dat"
organization sequential
.
select file2 assign "file2.dat"
organization sequential
.
data division.
file section.
fd file1.
01 file1-rec pic x(4).
fd file2.
01 file2-rec pic x(4).
working-storage section.
01 eof-flag pic 9 value 0.
88 eof-file1 value 1.
procedure division.
begin.
open input file1
output file2
start file1 last
invalid key
set eof-file1 to true
not invalid key
perform read-file1
end-start
perform until eof-file1
write file2-rec from file1-rec
perform read-file1
end-perform
close file1 file2
stop run
.
read-file1.
read file1 previous
at end
set eof-file1 to true
end-read
.
The input file may be SEQUENTIAL, RELATIVE, or INDEXED. If INDEXED, the primary key will be used. ACCESS must be either SEQUENTIAL or DYNAMIC. The records may be either fixed- or variable-length.
COBOL 2002 standard
START statement 14.8.37.3 General rules
SEQUENTIAL FILES
21) If LAST is specified, the file position indicator is set to the record number of the last existing logical record in the physical file. If no records exist in the file, or the physical file does not support the ability to position at the last record, the I-O status value in the file connector referenced by file-name-1 is set to '23', the invalid key condition exists, and the execution of the START statement is unsuccessful.
The above code, will treat the invalid key condition the same as end of file.
You should read the File1, storing the information into a Local Table. When you have all the records read, then you start writing the Local Table in the File 2, in the reverse order.

How to remove end-of-proof symbol?

Every time I'm writing to an output file, there will always be an end-of-proof symbol (□).
Consider the program below:
IDENTIFICATION DIVISION.
PROGRAM-ID. HEY.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT OUTFILE ASSIGN TO "alpha.txt".
DATA DIVISION.
FILE SECTION.
FD OUTFILE.
01 OUTREC PIC X(10).
PROCEDURE DIVISION.
OPEN OUTPUT OUTFILE
MOVE "ABCDEFGHIJ" TO OUTREC
WRITE OUTREC
CLOSE OUTFILE
STOP RUN.
The contents of alpha.txt is
ABCDEFJHIJ
□
I'm using Realia because that is what our school requires us to use. I'm also aware that if I run the same code above using some other compiler such as OpenCobol, the output is just fine, i.e., without the the end-of-proof symbol.
So, how do I remove the end-of-proof symbol?
There is likely no end-of-proof symbol in the file, instead the symbol you see is used for the non-printable character which is in there (or a character without a symbol in the used font; or, as Rick pointed out the end-of-file marker).
From the "txt" extension it looks like you want a text file but as you did not specify anything you end up with a sequential file.
I'm not 100% sure about the support for the (up to COBOL 202x non-standard) ORGANIZATION IS LINE SEQUENTIAL in Realia COBOL, but I suggest to give it a try:
SELECT OUTFILE ASSIGN TO "alpha.txt"
ORGANIZATION IS LINE SEQUENTIAL.
It is almost certainly an end-of-file mark (Cntl-Z or 0x1A). On my system (Win 10) the symbol is displayed as elongated (tall) rather than square. Pasted to this post it is square.
ABCDEFJHIJ
[The square shows in preview and edit; but later disappears.]
See also this answer and this Wikipedia article, End-of-file, for more information.
How to remove end-of-proof symbol?
Reading files in Realia COBOL is not a problem. It may not be a problem with GNUCobol. However, a character by character copy of the file, stopping at the eof-of-file mark, can be done in COBOL or any other language.

Reading cobol file line by line seperated by new line character

I'm having trouble reading a file line-by-line. This is a current snippet of the code:
file-control.
select input-file
assign input-file-name
organization is sequential
file section.
fd input-file.
01 input-file-record picturex(25)
working-storage section.
01 ws-eof picture a(1).
and here's where I actually read in the file:
perform until ws-eof = 'Y'
read input-file into input-file-record
at end move 'Y' to ws-eof
not at end
display input-file-record
end-read
end-perform
close input-file
The problem is, i'm trying to read the file line by line, but it seems like it's just filling up 25 characters, then reading again instead of looping by the return character in the text file.
The text file would look something like this:
AAAA
BBBB
CCCC
DDDD
The problem is, i'm trying to read the file line by line, but it seems like it's just filling up 25 characters, then reading again instead of looping by the return character in the text file.
The system is exactly doing what you tell it to do:
organization is sequential *> sequential, fixed length
01 input-file-record picture x(25) *> the fixed length is 25 bytes
Depending on the compiler you use (it is always a good idea to specify this if there isn't a specific tag for it already that you can use, and even in this case the version number never harms) you can either use the common extension (which may even get standard with COBOL 202x):
organization is line sequential *> sequential, read until line break found
or have to read it sequential (in this case likely with a bigger size) and
inspect file-rec converting all x'0d' by x'0a' *> if you expect windows or mac line breaks
move 1 to strpoint
unstring file-rec
delimited by all x'0a'
into real-rec
with pointer strpoint
end-unstring

Reusing the file definition of one file for another with out opening /closing it

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.

How to write a cobol code to do the below logic?

1) Read a line of 2000 characters and replace all SPACES with a single "+" plus character. i.e. Convert "A B" to "A+B" or "A B" to "A+B"
2)Read a line of 2000 characters, then search for a specific patterns like "PWD" or "INI" or etc and finally store next 6 characters into a variable.
3) Read a line of 2000 characters and store the last word in the string to a variable.
Edit:
I use Micro Focus COBOL.
This is a screenshot of my piece of code so far.
My code is below. It removes a few spaces but not all. Try writing any sentence with random numbers of spaces in between words in and input file for test-data.
IDENTIFICATION DIVISION.
PROGRAM-ID. SALAUT.
ENVIRONMENT DIVISION.
FILE-CONTROL.
SELECT IN-FILE ASSIGN TO "INFILE"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-IN-FILE-STATUS.
SELECT OUT-FILE ASSIGN TO "OUTFILE"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-OUT-FILE-STATUS.
DATA DIVISION.
FILE SECTION.
FD IN-FILE.
01 FS-IN-FILE PIC X(200).
FD OUT-FILE.
01 FS-OUT-FILE PIC X(200).
WORKING-STORAGE SECTION.
01 WS-ATMA-C.
03 WS-OUT-FILE-STATUS PIC X(02).
03 WS-IN-FILE-STATUS PIC X(02).
03 WS-LOOP-COUNTER PIC 9(03) VALUE 1.
03 WS-IN-EOF PIC X value 'N'.
03 WS-IN-FILE-LEN PIC 9(03).
03 WS-IN-SPACE-CNT PIC 9(03) VALUE 1.
03 FS-IN-FILE-2 PIC X(200).
03 WS-TRIL-SPACE-CNT PIC 9(03).
03 WS-TOT-SPACE-CNT PIC 9(03).
PROCEDURE DIVISION.
MAIN-PARA.
OPEN INPUT IN-FILE.
IF WS-IN-FILE-STATUS <> '00'
EXHIBIT 'IN-FILE-OPEN-ERROR : STOP-RUN'
EXHIBIT NAMED WS-IN-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF.
OPEN OUTPUT OUT-FILE.
IF WS-OUT-FILE-STATUS <> '00'
EXHIBIT 'OUT-FILE-OPEN-ERROR : STOP-RUN'
EXHIBIT NAMED WS-OUT-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF.
PERFORM SPACE-REMOVER-PARA THRU SPACE-REMOVER-PARA-EXIT.
CLOSE IN-FILE.
IF WS-IN-FILE-STATUS <> '00'
EXHIBIT 'IN-FILE-CLOSE-ERROR : STOP-RUN'
EXHIBIT NAMED WS-IN-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF.
CLOSE OUT-FILE.
IF WS-OUT-FILE-STATUS <> '00'
EXHIBIT 'IN-FILE-CLOSE-ERROR : STOP-RUN'
EXHIBIT NAMED WS-OUT-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF.
MAIN-PARA-EXIT.
STOP RUN.
SPACE-REMOVER-PARA.
PERFORM UNTIL WS-IN-EOF = 'Y'
INITIALIZE FS-IN-FILE FS-OUT-FILE WS-IN-FILE-LEN FS-IN-FILE-2
READ IN-FILE
AT END
MOVE 'Y' TO WS-IN-EOF
NOT AT END
INSPECT FS-IN-FILE TALLYING WS-IN-FILE-LEN FOR CHARACTERS
EXHIBIT NAMED WS-IN-FILE-LEN
MOVE 1 TO WS-LOOP-COUNTER
IF WS-IN-FILE-LEN <> 0
PERFORM UNTIL WS-IN-SPACE-CNT <= ZEROS
INSPECT FS-IN-FILE TALLYING WS-TOT-SPACE-CNT FOR ALL " "
INSPECT FUNCTION REVERSE (FS-IN-FILE) TALLYING
WS-TRIL-SPACE-CNT FOR LEADING " "
INITIALIZE WS-IN-SPACE-CNT
COMPUTE WS-IN-SPACE-CNT =
WS-TOT-SPACE-CNT - WS-TRIL-SPACE-CNT
PERFORM VARYING WS-LOOP-COUNTER FROM 1 BY 1
UNTIL WS-LOOP-COUNTER >=
WS-IN-FILE-LEN - (2 * WS-TRIL-SPACE-CNT)
IF FS-IN-FILE(WS-LOOP-COUNTER:2) = " "
STRING FS-IN-FILE(1:WS-LOOP-COUNTER - 1) DELIMITED BY SIZE
FS-IN-FILE(WS-LOOP-COUNTER + 2
: WS-IN-FILE-LEN - WS-LOOP-COUNTER - 2)
DELIMITED BY SIZE
INTO FS-IN-FILE-2
END-STRING
INITIALIZE FS-IN-FILE
MOVE FS-IN-FILE-2 TO FS-IN-FILE
INITIALIZE FS-IN-FILE-2
END-IF
END-PERFORM
INITIALIZE WS-LOOP-COUNTER WS-TRIL-SPACE-CNT WS-TOT-SPACE-CNT
END-PERFORM
WRITE FS-OUT-FILE FROM FS-IN-FILE
IF WS-OUT-FILE-STATUS <> '00'
EXHIBIT 'OUT-FILE-WRITE-ERROR : STOP-RUN'
EXHIBIT NAMED WS-OUT-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF
END-IF
END-READ
END-PERFORM.
SPACE-REMOVER-PARA-EXIT.
EXIT.
As INSPECT REPLACING only allows to replace the same number of bytes you can not use it. As Brian pointed out your COBOL runtime may comes with options like GnuCOBOL's FUNCTION SUBSTITUTE. In any case the question "Which COBOL" is still useful to be answered.
To do Thraydor's approach use UNSTRING to a table using a string pointer. Something along
MOVE 1 TO strpoint
PERFORM VARYING table-idx FROM 1 BY 1
UNTIL table-idx = table-max
UNSTRING your2000line DELIMITED BY ALL SPACES
INTO tmp-table (table-idx)
WITH POINTER strpoint
NOT ON OVERFLOW
EXIT PERFORM
END-UNSTRING
END-PERFORM
Another approach which always work is a simple PERFORM over the 2000 bytes with a bunch of IF your2000line (pos:1) statements (if possible: combine it to a single EVALUATE) checking byte by byte (comparing the last byte for removing the duplicate bytes) transferring the source with replacements to a temporary field and MOVE it back once you're finished
Please edit your question to show what exactly you've tried and you can get much better answers.
Firstly, bear in mind that COBOL is a language of dialects. There are also active commercial compilers which target the 1974, 1985, 2002 (now obsolete, incorporated in 2014) and 2014 Standards. All with their own Language Extensions, which may or many not be honoured in a different COBOL compiler.
If you are targeting your learning to a particular environment (IBM Mainframe COBOL you have said) then use that dialect as a subset of what is available to you in the actual COBOL you are using. Which means using the IBM Manuals.
Don't pick and chose stuff from places and use it just because it somehow seemed like a good idea at the time.
I have to admit that EXHIBIT was great fun to use, but it was only ever a Language Extension, and IBM dropped it by at least the later releases of OS/VS COBOL. It, like ON, was a "debugging" statement, although that didn't prevent their being used "normally". There's additional overhead to using EXHIBIT over a simple DISPLAY. IBM Enterprise COBOL only has a simple DISPLAY.
Whilst you may think it fun to use pictograms (the "oh my goodness, what symbol should I use for this" of a figure attempting to pull his own hair out) be aware that that particular symbol was a latecomer to the 2014 Standard, and if it appears in Enterprise COBOL within the next 20 to 50 years I'd be surprised (very low of the list of things to do, another cute way to write "not equal to" when many already exist, and COBOL even has an ELSE).
Some pointers. Don't have a procedure called "remove-all-the-spaces" if what it does is itself is "everything-including-install-a-new-kitchen-sink". Is it any wonder you can't find why it doesn't work?
Many, many, many COBOL programs have the task of reading a file, until the end, and processing the records in the file. Get yourself one of those working well first. Is that relevant to the "business process" the program is addressing? No, it's just technical stuff, which you can't do without so hide it somewhere. Where? in PERFORMed procedures (paragraphs or SECTIONS). Don't expect someone who quickly wants to know what your program is doing to want to read the stuff which every program does. Hide it.
You can find quite a bit of general advice here about writing COBOL programs. Pay attention to those which advise of the use of full-stops/periods, priming reads, and the general structure of COBOL programs.
It is very important to describe things accurately. Work on good, descriptive, accurate names for data-names and procedures. A file is a collection of records.
You have cut down the size of your data to make testing easier, without realising that you have a problem with your data-definitions when you go back to full-length data. Your "counters" can only hold three digits, when they need to be able to cope with the numbers up to 2000.
There is no point in doing something to a piece of data, and then immediately squishing that something with something else which is not related in any way to the original something.
MOVE SPACE TO B
MOVE A TO B
The first MOVE is redundant, superflous, and does nothing but suck up CPU time and confuse the next reader of your program. "Is there some code missing, because otherwise that's just plain dumb".
This is a variant of that example with the MOVE, and you are doing this all over the place:
INITIALIZE WS-IN-SPACE-CNT
COMPUTE WS-IN-SPACE-CNT =
WS-TOT-SPACE-CNT - WS-TRIL-SPACE-CNT
The INITIALIZE is a waste of space, resources, and an introducer of confusion, and extra lines of code to make your program more difficult to understand.
Also, don't "reset" things after they are used, so that they are "ready for next time". That creates dependencies which a future amender of your program will not expect. Even when expected/noticed, they make the code harder to follow.
Exactly what is wrong with your code is impossible to say without knowing what you think is wrong with it. For instance, there is not even a sign of a "+" replacing any spaces, so if you feel that is what it wrong, you simply haven't coded for it.
You've also only attempted one of the three tasks. If once of those not working is what you think is wrong...
Knowing what you think is wrong is one thing, but there are a lot of other problems. If you sit down and sort those out, methodically, then you'll come up with a "structurally" COBOL program which you'll find its easier to understand what your own code does, and where problems lie.
A B C D E
A+B+C+D+E
To get from the first to the second using STRING, look into Simon's suggestion to use WITH POINTER.
Another approach you could take would be using reference-modification.
Either way, you'd be build your result field a piece at a time
This field intentionally blank
A
A+B
A+B+C
A+B+C+D
A+B+C+D+E
Rather than tossing all the data around each time. There are also other ways to code it, but that can be for later.

Resources