Inside COBOL #37
by
Shawn Gordon
As promised, I am finally getting around to talking about doing mapped file access from COBOL. First let’s talk about why you may want to do mapped file access. The idea behind mapped file access is that a file is treated as an array in memory by your program, you don’t have to deal with it in terms of records, this is really convenient for certain things like EDI. Beyond some of the convenience is the fact that if the file is in memory it is blazingly fast to access. Here is an extreme example of mapped access.
There was a program that Gavin Scott at Denkart wrote years ago to do really really fast file reads called FOXVIEW. This program is extreme because I think Gavin wrote it in Assembler, but it is doing mapped file access at some level. Now I just tried it out on a 959-200 with 512 meg of memory. When I scan a file that isn’t in memory I can see the program be as slow as 5,000 lines a second, but running it a second time after the file is in memory I have seen 500,000 lines per second. That’s right, half a million lines a second. Obviously this is an amazing use of technology.
At this point you are probably coming to the same conclusion that I came to when I first started looking at mapped file access years ago. Basically, how do you know if a file is in memory, and if it’s not, what’s the quickest way to get it there so that you can take full advantage of the mapped access. What I found out is that there is no good way. There are some utility programs out there that I think address some of the issues, but it’s not that straight forward.
Mapped file access comes in two flavors, short and long. Short mapped access uses a short pointer, so is more limited in the amount of data that can be represented in memory. Long mapped is the way that most people go. The
fundamental problem with both for COBOL programmers is that COBOL doesn’t directly support pointers, let alone long pointers. The following code shows how you can make use of a small C sub-routine to handle the actual file i/o, while we use COBOL as the driving routine. Since we just spent five months comparing the two languages, you shouldn’t have much trouble understanding what is going on.
These examples come from the HP support web page, and I am going to print them in their entirity. They are pretty well documented, and shouldn’t be to hard to tweak to your own needs.
Description: How to read files mapped with long a pointer in COBOL
PROBLEM TEXT
I would like to access a file through long pointers in COBOL.
Is this possible?
RESOLUTION TEXT
Not directly, since COBOL doesn’t support a long pointer type. It is possible to access files with long pointers as long as it is done with C/XL or Pascal/XL subroutines. The following two programs, one in COBOL/XL, and the other in
C/XL, demonstrate how to open, then read a file using long pointers.
$CONTROL USLINIT,SOURCE,MAP
IDENTIFICATION DIVISION.
PROGRAM-ID. COBMAP.
INSTALLATION. ATLANTA RESPONSE CENTER.
DATE-WRITTEN.
DATE-COMPILED.
REMARKS.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. HP-3000.
OBJECT-COMPUTER. HP-3000.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
77 NUMCHAR PIC S9(9) COMP VALUE 0.
77 MAP-ADDRESS PIC S9(18) COMP VALUE 0.
77 RECNUM PIC S9(9) COMP VALUE 0.
77 BUFREC PIC X(80) VALUE SPACES.
77 RECLEN PIC S9(9) COMP VALUE 80.
PROCEDURE DIVISION.
******************************************************
* 25 HOUSE KEEPING *
******************************************************
MY-START SECTION.
25-HOUSE-KEEPING.
* How to construct the final program:
* 1) Compile the C program: CSUBMAP. Don’t link.
* 2) Compile this program.
* 3) Link the COBOL program and the C subroutines together.
*
* Call the subroutine to open the file ‘temp’ as a mapped
* file using long pointers. The pointer is returned in the
* MAP-ADDRESS variable. Note that we do not actually
* manipulate the MAP-ADDRESS variable in the COBOL program,
* but let the subroutines do the work.
CALL “\mopen” USING MAP-ADDRESS.
DISPLAY “Enter record number to display “.
ACCEPT RECNUM FREE.
* Now, we call the routine to access the requested record.
* Notice that the variable MAP-ADDRESS is being passed
* BY VALUE, not by reference. This is because the subroutine
* expects a 64-bit address, which COBOL has no knowledge of.
* By passing the value only, the subroutine is fooled into
* thinking that the value being passed is an address, which it
* actually is. In the first routine, we pass the address of the
* variable that is to hold the actual 64-bit address.
CALL “\mystrncpyl” USING \RECLEN\, \RECNUM\,
BUFREC, \MAP-ADDRESS\.
DISPLAY “Record number ” RECNUM “: ” BUFREC.
STOP RUN.
————————————————————
#pragma list off
#pragma HP_ALIGN MPE_16
#include
#include
#pragma list on
#pragma intrinsic HPFOPEN
/* This contains two subroutines, mopen, and mystrncpyl,
which can be used by other languages, such as COBOL,
to open, then read a mapped file using long pointers.
NOTE: No error checking is done!
*/
/* int filenum, domain = 3, i,j; */
char fname[] = “temp”; /* This name could be anything */
struct { short info;
short subsys;
} status;
char ^data;
char buf[80];
main(){
int rnum,rpos;
mopen(&data);
/* Now, calculate the line number to display */
rnum=5; /* We selected line 5 for our example */
rpos=(80*rnum);
mystrncpyl(80,rnum, buf, data);
printf(“Record number %d:”,rnum);
printf(“%80s”,buf);
printf(“;\n”);
return;
}
/* The two subroutines are the ones actually used by the COBOL program.
*/
mopen(char ^*dpointer)
{
HPFOPEN(&filenum, &status, 2, fname, 3, &domain,
21, dpointer);
if (status.info | status.subsys) {
printf(“;%s%hd,%hd”,”HPFOPEN status = “,status.info,
status.subsys);
exit(2);
}
}
/* This routine is required to move a string referenced by a
long pointer because strncpy and strcpy can’t handle long
pointers.
*/
mystrncpyl(int n, int rnum, char *to, char ^from)
{
from=from+(n*rnum); /* Calculate desired record number */
while(n–)
{
*to++ = *from++;
}
return;
}