I am studying the Ada-> Cobol interface, and am wondering if there is any way to write the files to cobol default, without having to have a Cobol code written too, because I want to write a file using some rules of COBOL, but would to know how to do this directly in Ada.
For example, to read a file with cobol structure, I can use use that way:
with Interfaces.COBOL;
with COBOL_Sequential_IO; -- Assumed to be supplied by implementation
procedure Test_External_Formats is
112
-- Using data created by a COBOL program
-- Assume that a COBOL program has created a sequential file with
-- the following record structure, and that we need to
-- process the records in an Ada program
-- 01 EMPLOYEE-RECORD
-- 05 NAME PIC X(20).
-- 05 SSN PIC X(9).
-- 05 SALARY PIC 99999V99 USAGE COMP.
-- 05 ADJUST PIC S999V999 SIGN LEADING SEPARATE.
-- The COMP data is binary (32 bits), high-order byte first
113
package COBOL renames Interfaces.COBOL;
114
type Salary_Type is delta 0.01 digits 7;
type Adjustments_Type is delta 0.001 digits 6;
115
type COBOL_Employee_Record_Type is -- External representation
record
Name : COBOL.Alphanumeric(1..20);
SSN : COBOL.Alphanumeric(1..9);
Salary : COBOL.Byte_Array(1..4);
Adjust : COBOL.Numeric(1..7); -- Sign and 6 digits
end record;
pragma Convention (COBOL, COBOL_Employee_Record_Type);
116
package COBOL_Employee_IO is
new COBOL_Sequential_IO(COBOL_Employee_Record_Type);
use COBOL_Employee_IO;
117
COBOL_File : File_Type;
118
type Ada_Employee_Record_Type is -- Internal representation
record
Name : String(1..20);
SSN : String(1..9);
Salary : Salary_Type;
Adjust : Adjustments_Type;
end record;
119
COBOL_Record : COBOL_Employee_Record_Type;
Ada_Record : Ada_Employee_Record_Type;
120
package Salary_Conversions is
new COBOL.Decimal_Conversions(Salary_Type);
use Salary_Conversions;
121
package Adjustments_Conversions is
new COBOL.Decimal_Conversions(Adjustments_Type);
use Adjustments_Conversions;
122
begin
Open (COBOL_File, Name => "Some_File");
123
loop
Read (COBOL_File, COBOL_Record);
124
Ada_Record.Name := To_Ada(COBOL_Record.Name);
Ada_Record.SSN := To_Ada(COBOL_Record.SSN);
Ada_Record.Salary :=
To_Decimal(COBOL_Record.Salary, COBOL.High_Order_First);
Ada_Record.Adjust :=
To_Decimal(COBOL_Record.Adjust, COBOL.Leading_Separate);
... -- Process Ada_Record
end loop;
exception
when End_Error => ...
end Test_External_Formats;
Put, I don't know how to write a File with cobol structure, in the documentation, I not find a way; http://www-users.cs.york.ac.uk/~andy/lrm95/b_04.htm
For example, if I have that struct in Cobol ( based on this sample: http://www.csis.ul.ie/cobol/examples/Sort/MaleSort.htm ; http://www.csis.ul.ie/cobol/examples/SeqIns/STUDENTS.DAT )
FILE SECTION.
FD StudentFile.
01 StudentRec PIC X(30).
88 EndOfFile VALUE HIGH-VALUES.
FD MaleStudentFile.
01 MaleStudentRec PIC X(30).
SD WorkFile.
01 WorkRec.
02 FILLER PIC 9(7).
02 WStudentName PIC X(10).
02 FILLER PIC X(12).
02 WGender PIC X.
88 MaleStudent VALUE "M".
How I can make a program to write this struct, in Ada, using Cobol interfaces ?
Think physically. That is, what is the output file's format? Whether you create that file in Cobol or Ada is NOT an immediate issue when designing a file.
Let's assume that Cobol Workrec describes your file's format. Do you want to write an Ada program that calls a cobol subroutine to physically write the file? or do you want to use a Cobol program to write the file? Or do you want an Ada program that writes a file in the smae format as Workrec?? Your choice depends on your customer's requirements.
Related
I need a helping hand in order to understand the following assembly instruction. It seems to me that I am calling a address at someUnknownValue += 20994A?
E8 32F6FFFF - call std::_Init_locks::operator=+20994A
Whatever you're using to obtain the disassembly is trying to be helpful, by giving the target of the call as an offset from some symbol that it knows about -- but given that the offset is so large, it's probably confused.
The actual target of the call can be calculated as follows:
E8 is a call with a relative offset.
In a 32-bit code segment, the offset is specified as a signed 32-bit value.
This value is in little-endian byte order.
The offset is measured from the address of the following instruction.
e.g.
<some address> E8 32 F6 FF FF call <somewhere>
<some address>+5 (next instruction)
The offset is 0xFFFFF632.
Interpreted as a signed 32-bit value, this is -0x9CE.
The call instruction is at <some address> and is 5 bytes long; the next instruction is at <some address> + 5.
So the target address of the call is <some address> + 5 - 0x9CE.
If you are analyzing the PE file with a disassembler, the disassembler might had given you the wrong code. Most malware writer uses insertion of E8 as anti-disassembly technique. You can verify if the codes above E8 are jump instructions where the jump location is after E8.
I have a copybook with the folowing:
(...)
05 ESTGWABC-S-OUT.
10 ESTGWABC-S-COD-NUM PIC 9(003).
10 ESTGWABC-S-DESC-COD PIC X(020).
(...)
10 ESTGWABC-S-VAL-PAY PIC 9(015)V99.
10 ESTGWABC-S-QTD-REG PIC 9(002).
10 ESTGWABC-S-REG-PEOP OCCURS 0 TO 20 TIMES
DEPENDING ON ESTGWABC-S-QTD-REG.
15 ESTGWABC-S-CCONTR PIC 9(009).
15 ESTGWABC-S-VAL-PAY PIC 9(015)V99.
10 ESTGWABC-S-DEPEN PIC 9(005).
(...)
On my program, I'm wanting to initialize it before use it, so I'm doing the following:
INITIALIZE ESTGWABC-S-OUT
REPLACING ALPHANUMERIC BY SPACES
NUMERIC BY ZEROS
But I'm getting an compiling error:
"ESTGWABC-S-OUT" was found in an "INITIALIZE" statement but was variable-length or variably located. The operand was discarded from the "INITIALIZE" statement.
Can anybody give me a clue how can I solve it or what am I doing wrong? Thank you very much.
Can anybody give me a clue how can I solve it or what am I doing wrong?
Do not use INITIALIZE and you are doing nothing wrong.
Basically, standard COBOL sets rules for the organization of data records. It then defines the behavior of the INITIALIZE statement to properly operate on those data records.
The data items after the variable length table are 'variably located'. This does not conform to standard COBOL, which requires that any variable length data item, in this case, ESTGWABC-S-REG-PEOP, be located last in the record description entry. The location of ESTGWABC-S-DEPEN will change depending on the number of entries in the table, ESTGWABC-S-REG-PEOP. When the size of the table changes ESTGWABC-S-DEPEN will no longer be an initialized data item.
To allow the use of INITIALIZE, the 'copybook' must be changed.
Following is an example of how to use INITIALIZE with a standard-conforming variable length record. This was done with a Micro Focus compiler with flags to force COBOL 85 conformance.
$set ans85 flag"ans85" flagas"s"
identification division.
program-id. var-len.
data division.
working-storage section.
01 n pic 9(2).
01 a.
02 fixed-part.
03 b pic x(2).
03 c pic 9(2).
02 variable-part.
03 d occurs 0 to 10 depending c.
04 e pic x(2).
04 f pic 9(2).
procedure division.
begin.
initialize fixed-part
perform varying n from 1 by 1 until n > 10
initialize d (n)
end-perform
stop run
.
end program var-len.
i got a problem with simple cobol call - returning test program.
I am using micro focus cobol.
here are my 2 codes.
***************** CALLING PROGRAM
IDENTIFICATION DIVISION.
PROGRAM-ID. callreturning.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 VA PIC S9(8) USAGE DISPLAY.
01 VB PIC S9(8) USAGE DISPLAY.
01 VC PIC 9(4) USAGE DISPLAY value 0.
PROCEDURE DIVISION.
MOVE 1 TO VA.
MOVE 2 TO VB.
move 3 to VC.
CALL "add_two" USING VA VB returning VC.
* DISPLAY VA VB VC.
EXIT PROGRAM.
END PROGRAM callreturning.
*********CALLED PROGRAM
IDENTIFICATION DIVISION.
PROGRAM-ID. add_two.
ENVIRONMENT DIVISION.
DATA DIVISION.
LINKAGE SECTION.
01 PARM_A PIC S9(8) USAGE DISPLAY.
01 PARM_B PIC S9(8) USAGE DISPLAY.
01 PARM_C PIC 9(4) USAGE DISPLAY value 0.
PROCEDURE DIVISION USING PARM_A PARM_B returning PARM_C.
move 3 to PARM_C.
* ADD PARM_A TO PARM_B GIVING PARM_C.
goback.
END PROGRAM add_two.
CALLING program simply calls the second program with using returing value.
But when i compile both program and run, error happens.
error code: 114, pc=0, call=1, seg=0
114 Attempt to access item beyond bounds of memory (Signal 11)
Did i make a wrong code? or other problem? please help me :)
I am testing 'RETURNING' phrase
Your program compiles and works just fine if you get rid of the returning statement.
Background
01 levels defined in the linkage section are more like pointers in a C program. For normal parameters they are set by the calling program. But returning parameters will be unassigned.
The error is probably caused by trying to use an unallocated pointer.
Solution
Do not use returning as it is for working with languages like java.
Allocate storage to the return-value before using it.
See:
Microfocus Manual, Look at the returning example
IBM Manual Look at the Returning Phrase Section
Finally, returning is for working with java. Anything "type" defined on returning should be java compatible (i.e. binary-long and not 9(4)). I strongly suggest not using Returning in Cobol unless you are calling other languages.
Old Question, so i try a short Answer:
First, there is nothing wrong with using returning in MF-COBOL.
So, this is native COBOL (NetExpress as IDE, i assume). To correct ist just change the second Program:
Move PARM_C from the linkage to the working-storage section
The Procedure Division doesn't get the returning Phrase in its opening declaration. Move it instead to the goback phrase:
PROCEDURE DIVISION USING PARM_A PARM_B.
*>...
goback returning PARM_C.
I am opening a text file in Ada with the following code:
Open (File => out_parcial_variante1, Name => "c.txt", Mode => append_file);
put(File => out_parcial_variante1, Item=> "r");
close(out_parcial_variante1);
The file as a structure like this inside:
01 #510.00:1003.00,512.04:1110.00,515.00:998.00,-98.00,-100.00
<second empty line, this text is not in the file>
Note that besides the initial line the cursor is in a second line there with nothing written.
Whenever my code writes in the file, this happens:
01 #510.00:1003.00,512.04:1110.00,515.00:998.00,-98.00,-100.00
r
It creates another newline instead of appending on the 2nd line like this:
01 #510.00:1003.00,512.04:1110.00,515.00:998.00,-98.00,-100.00
r
How do I fix this?
EDIT: It's a pointer problem since I read the whole line before, but I try to close and open the file again and the pointer remains in the second line instead of going back to the beginning.
I threw together a quick test program with GNAT 2012 on Windows and it works as expected.
Code:
with Ada.Text_IO;
use Ada.Text_IO;
procedure Append_Test is
OPV: File_Type;
begin
Open (OPV, Append_File, "c.txt");
Put (OPV, "r");
Close (OPV);
end Append_Test;
I programmatically created the c.txt file, using Put_Line to output the text, this was the contents of the file:
01 #510.00:1003.00,512.04:1110.00,515.00:998.00,-98.00,-100.00
I used Cygwin's od -t x1 to dump the file, and saw that it terminated with a 0d 0a EOL sequence, i.e. CR/LF.
Running the above code resulted in a file containing the expected output:
01 #510.00:1003.00,512.04:1110.00,515.00:998.00,-98.00,-100.00
r
Again dumping with od showed the file ending with 0d 0a 72 0d 0a. That's the original EOL, to which is appended the 'r' and another EOL.
If this isn't happening for you, then it's not clear what you're actually doing. (Note that on Linux the 0d 0a sequences would instead be simply 0a.)
In standard Pascal (ISO7185), there was no procedure Assign that would've let a programmer to assign some kind of file name to a file variable. It only appeared in Turbo Pascal and other derivates.
So... how am I supposed to open a handle to a specific file if I comply with the standard?
Closest I've found is this Irie Pascal example:
program vowels(f, output);
var
f : file of char;
tot, vow : integer;
c : char;
begin
reset(f);
tot := 0;
vow := 0;
while not eof(f) do
begin
read(f, c);
case c of
'a', 'e', 'i', 'o', 'u',
'A', 'E', 'I', 'O', 'U'
: vow := vow + 1;
otherwise
end;
tot := tot + 1;
end;
writeln('Total characters read = ', tot);
writeln('Vowels read = ', vow)
end.
which suggests I might be able to give the file name as a startup parameter. This works using Irie Pascal. However, if I try to use that with P5, which should be closest to standard-compiliant Pascal compiler for modern computers I've found, I get (after replacing 'otherwise') **** Error: external file unknown 'f '. So, what'd be the standard way? Or is this actually the standard way and P5 is doing something wrong?
Edit: standard also gives a sample
program copy (f, g);
var f,g : file of real;
begin
reset(f) ; rewrite(g);
while not eof(f) do
begin
g^ := f^ ; get(f) ; put(g)
end
end.
but I haven't been able to get that to work with any compiler.
Edit2:
Doing it like this:
program copy (f, g);
var f,g : file of char;
begin
reset(f) ; rewrite(g);
while not eof(f) do
begin
g^ := f^ ; get(f) ; put(g)
end
end.
works just fine in Irie and is compliant with the standard. Using that, file name can be given as a startup parameter.
However, as explained by Marco van de Voort,
ISO 7185 does not have any standard way for a program to specify
file names at all, so any such way is already beyond 7185 (Bind
is ISO 10206, Assign is UCSD/BP, the 2nd parameter to Reset is
an extension of GPC and I think some other compilers).
(source)
IIRC this was for VMS support where the OS bound files before starting the program.
Unbound files were automatically tempfile iirc. Search the GNU Pascal maillists (old archives, say 2005 or so), they had quite some discussions about ISO file implementation.
It was Scope on the CDC 6000 series machines. However, the rest is correct. You basically assigned external files to logical header file names in the Scope command language.
Of course this seems very tedious now, but these were the days of the batch mode computer, where everything was submitted as a "deck" of cards to be run as input, then collected as a series of output "cards". Tape reels got rid of the actual cards, but tapes were treated as a collection of cards on a tape.
In normal use, Wirth's original compilers were actually limited to just an input and an output file. If you wanted more than one input file, you concatenated them. This was easier than it sounds, since most input and output files were text, and every file had distinct end tolkens in it.
This paradigm fit well with the idea that you mounted an input tape and an output tape for a job on a batch system. The job of the batch computer was to linearly process the input tape and produce the output tape. A large and fast machine would have several jobs concatenated onto a single tape and run sequentially.
The option of a high speed printer typically rounded out the system. Thus, a college kid in the 1960s learning computer science would punch a deck on what looked like a typewriter (or get it typed by a keypunch operator), then that deck would be collected and transcribed to a tape deck and scheduled to run. An hour or more later, you were handed a section of greenbar from the printer that represented the output from your program.
Anyways, its always a good debate question as to why Wirth put that limitation in the language. Probabaly it was for the simple reason that the CDC 6000 machines could not have dealt with a feature that randomly opened a file by name. Also remember that the predecessor to Pascal, Algol, had no I/O statements whatever! They considered I/O to be inherently machine specific.
Scott Moore