Operation (cont.) [ COBOL/HP-UX Operating Guide for the Series 700 and 800 ] MPE/iX 5.0 Documentation
COBOL/HP-UX Operating Guide for the Series 700 and 800
Operation (cont.)
Call Requirements
Having decided to use the call mechanism for your application, the
following sections look at some of the practical aspects of creating such
applications.
The total number of programs which can be loaded in memory as the result
of a call is not constant. The number depends on the amount of available
memory in your computer and the size of the program being called.
One consideration regarding dynamically called programs is the amount of
memory fragmentation at the time of the
call. By calling and
canceling
dynamically linked subprograms, it is possible to have free areas of
memory scattered among blocks of memory allocated to active subprograms.
With free memory fragmented into several small blocks, there may not be
enough contiguous free memory to load a dynamically linked subprogram.
When a program is dynamically called, the following conditions affect its
loading:
* There must be enough contiguous memory free to load the program.
Note that overlaid programs allocate enough memory to hold the
root and the largest overlay.
* The run time system must be able to open the executable file.
This may not be possible if the operating system's limit on the
number of open files has been reached.
* On UNIX, canceling a COBOL program actually frees memory only if
the -l run-time switch is set to 0. If this switch is not set,
the program is merely marked as being canceled. Subsequent calls
to the program will then need only initialize the data division
and mark the program active once more. With -l0 set, the program
must again be searched for on disk and loaded. If the limit set
by the -l switch is exceeded, programs marked as canceled will be
canceled properly in order to free memory resource. For full
details on -l, see Appendix E , Descriptions of Run-Time
Switches.
Dynamically called programs have an advantage over programs that have
been linked into a single executable file in that dynamically called
programs have their memory freed when they are canceled while the latter
do not.
Public Symbols and Your Program-ID
Every program must have an entry point and a public symbol associated
with that entry point. If your program includes a Program-ID paragraph,
the compiler uses that name as the name of your subprogram. If no
Program-ID paragraph exists, then the compiler uses the file-name of the
.o file from the command line as the name of the program. This is
important to remember because programs which are linked together are
called by the public symbol the compiler created in the .o file. In
contrast, dynamically called subprograms can only be called by their
file-names since the run time system must perform disk searches to load
them.
You can avoid many "program not found" errors by always using the
file-name without extensions in the Program-ID paragraph. This allows
flexibility in constructing your executable programs with statically or
dynamically called programs. For details on the Program-ID paragraph,
see your Language Reference.
Calling Subprograms
This section looks in more detail at how to call subprograms. It
provides information on writing subprograms and passing parameters
between them.
You may write subprograms or your main programs in the COBOL language or
in some other language, such as C. You may mix these subprograms freely
in an application. However, before you call a non-COBOL subprogram from
a COBOL program, you must link it to either the dynamic loader run-time
support module or to your statically or dynamically linked COBOL
application.
Calling COBOL Subprograms.
A COBOL subprogram can be:
* statically or dynamically linked using the cob command
* dynamically loaded at run-time
A statically linked program is an executable object module, while a
dynamically loadable module is either a COBOL intermediate code (.int)
file or a COBOL native code (.gnt) file.
You can call a COBOL subprogram by using one of the following formats of
the call statement:
CALL "literal" USING ...
or:
CALL data-name USING ...
For any COBOL programs, the literal string or the contents of the
alphanumeric data item must represent the Program-ID, the entry point
name, or the base-name of the source file (that is, the file-name without
any extension). The path and file-name for a module may also be
specified when referencing a COBOL program, but we do not recommend you
do this, as unexpected results can occur where the referenced module
exists in more than one file, or type of format, or if the application is
ported to other environments. For statically linked modules the native
code generator converts calls with literal strings to subroutine calls
which refer to external symbols. If the symbol has not been defined when
linking is performed, it is assumed to be the name of a file to be
dynamically loaded, provided you specify the -d flag on the cob command
line (see Appendix D Descriptions of cob Flags for details). The
Micro Focus COBOL system automatically creates a routine to define the
symbol and to load the associated file if it is entered at run-time.
Note: Programs that are called at link time must have names that the
system assembler and linker can accept; that is, they must not
contain character other than 0-9, A-Z, a-z, underscore (_), or
hyphen (-). You must correct any entry point names that use
character other than these so that they are acceptable to the
system assembler and linker.
Calling Statically or Dynamically Linked Programs
Use a CALL literal statement to call a statically or dynamically linked
program directly.
Calling Dynamically Loadable Programs
Use a CALL literal statement to a dynamically loadable program, or a CALL
data-name statement, to make the dynamic loader run-time support module
to search for the called program. The dynamic loader run-time support
module follows this search order to find the named file:
1. the entry points of all loaded programs
2. the disk in order to find a suitable file from which the program
could be loaded.
If the COBOL program is referenced as a file-name, then before starting
this search operation, the dynamic loader run-time support module splits
the required program name into its component parts, that is directory,
base-name, and extension. The dynamic loader run-time support module
does not use the directory portion of the program name in its search of
loaded programs. It compares the base-name with the entry point names of
all loaded programs. If you specify no extension, then the first
matching name that the dynamic loader run-time support module finds is
assumed to be the program which you want to call. If you do specify an
extension, then the extension of the loaded program must be the same if a
match is to be made. Alternate entry points to programs are treated as
if they had the extension of the file from which they were loaded.
If the dynamic loader run-time support module has to search for a file on
disk, it searches for it directory by directory, then extension by
extension in each directory. If you specify a directory path, the
dynamic loader run-time support module searches for the file only in the
named directory.
When call specifies a file with no path name, then the search order
followed is:
1. the directory from which the calling program was loaded for the
named file
2. the directories specified by the COBPATH environment variable.
You can set COBPATH to a value of the form:
[:] path-name [:path-name] ...
For example:
COBPATH=/u:/v:/cdw/srclib:/cdw/otherlib
If you include the optional colon (:) at the beginning of the
string, the dynamic loader run-time support module assumes the
current directory is the first one to be searched
3. the directory specified by the COBDIR environment variable.
See Appendix I Environment Variables for further details on COBPATH
and COBDIR.
If you specify a file extension, the dynamic loader run-time support
module will search only for a file with a matching extension. However,
you are not recommended to include the extensions .int and .gnt in the
file-names you specify to the CALL statement. If you specify a file
without an extension, the dynamic loader run-time support module uses the
following algorithm to search for it:
1. If the file is not linked with the COBOL libraries, the dynamic
loader run-time support module adds the extension .gnt to the
base-name of the file and tries to find the corresponding native
code file on disk.
2. If it cannot find the native code file on disk, it adds the
extension .int to the base-name of the file, and searches the disk
for the corresponding intermediate code file.
The dynamic loader run-time support module always assumes that the first
matching program name which it finds is the program you require to CALL.
If no matching program is found a run-time error occurs.
Note that if the first character of a file-name which is to be
dynamically loaded at run-time is the dollar sign ($), the first element
of the file-name is checked for file-name mapping. The first element of
the file-name consists of all the characters before the first forward
slash character (/). See Chapter 12 , COBOL File Handling for
details. For example, if the statement:
CALL "$MYLIB/A"
is found in the source program, the file A is loaded from the path as
defined by the MYLIB environment variable at run-time.
Calling Dynamically Loadable COBOL Programs Via Entry Points
Micro Focus COBOL allows you to define multiple entry points to a
dynamically loaded program using the ENTRY statement. You can CALL a
program either via the main entry point (at the start of the Procedure
Division) or via one of the points in the program marked by an ENTRY
statement. See your Language Reference for a description of the ENTRY
statement. This facility is designed primarily for compatibility with
other COBOL environments; we do not recommend you use it for other
purposes because of the special considerations listed in the remainder of
this section.
Command Line Syntax
You can CALL a dynamically loadable program via an entry point in the
same way that you would call it via its main entry point; that is:
CALL name USING parameters
where:
name is the name defined in the ENTRY statement that
defines the entry point you are using
parameters is a list of parameters within the range 0 to 127.
You can specify different parameters at different
entry points within the same program.
There are certain features that you need to be aware of when calling
dynamically loadable programs via entry points. To illustrate these
features we will use as an example a program structured as follows:
procedure division using param-1,param-2.
first-para.
. . .
. . .
. . .
entry "other" using param-3,param-4,param-5.
. . .
. . .
via main entry point
If you compile this program into an intermediate code file mainprog.int
using the cob command (see Chapter 2 , COBOL System Interface for
details), and CALL it via its main entry point, as follows:
CALL "mainprog" USING PAR-1,PAR-2.
and at some later point CALL the same program via its other entry point,
as follows:
CALL "other" USING PAR-3,PAR-4,PAR-5.
the dynamic loader run-time support module loads the program called via
its main entry point and notes the names of any other entry points within
the program. When you subsequently call the same program via its other
entry point, the dynamic loader run-time support module can detect that
the program containing this entry point is already loaded, provided that
you have not used the CANCEL statement to release the memory occupied by
the program after the first call.
via "other" entry point
If, on the other hand, your first entry to a program is via the entry
point "other" rather than by the main entry point, the dynamic loader
run-time support module is not able to associate the entry point "other"
with the program "mainprog.int", so it is unable to load the program.
You can solve this problem by creating a link between mainprog.int and
the entry point "other", using the UNIX command ln, as follows:
ln mainprog.int other.int
via entry point in a segment
If you are calling via an entry point in an overlay segment, you must
also establish a link between the intermediate code overlay file and the
entry point. For example, if you are calling via an entry point "other"
in mainprog.int, that is located in a section with segment number 52, you
would have to create a link as follows:
ln mainprog.i52 other.i52
Similarly, if you have code-generated "mainprog" you can link this
version of the program with the entry point "other", as follows:
ln mainprog.gnt other.gnt
If you are calling via an entry point in an overlay segment, you must
also establish a link between the generated code overlay file and the
entry point. For example:
ln mainprog.g52 other.g52
If you are animating a program that is being entered initially by an
entry point other than the main entry point, you must establish a link
between the .idy file used by ANIMATOR and the entry point. For example:
ln mainprog.idy other.idy
avoiding duplicate copies
However, you may still experience problems if you want to CALL the
program again later using the main entry point rather than "other". When
you call a program via any of its entry points, the dynamic loader
run-time support module picks up the references to all its other entry
points. Unless your program has a program name assigned to it in the
Program-ID paragraph, the main entry point will not have a name
associated with it. The consequence is that if you call the above
program by:
CALL "other" USING...
and later call the same program again by:
CALL "mainprog" USING...
the dynamic loader run-time support module, not being aware of a "main"
entry point, does not detect that the program is already loaded and loads
a duplicate copy. This wastes memory unnecessarily. However, the
dynamic loader run-time support module does detect that the program it
has just loaded duplicates the names of some entry points of which it was
already aware, and so outputs error 119 "symbol redefined". See your
Error Messages manual for details of this message.
Although loading duplicate copies of programs wastes memory, it also
causes you another problem. When the dynamic loader run-time support
module loads a program, it initializes the area of memory holding the
program's data so that the data is initially either undefined or has the
initial values assigned to it by the VALUE clauses in the Data Division.
If you exit from the program without canceling the memory it occupies,
when you reenter the program, its data will be in the state in which the
program left it.
You can make the dynamic loader run-time support module aware of the main
entry point of a program that you enter via another entry point
by including a program name in the Program-ID paragraph in the
Identification Division of your program. For example:
identification division.
program-id. mainprog.
Now when you CALL the program, the dynamic loader run-time support module
will be aware of the entry point mainprog. Consequently, to reenter the
program successfully via the main entry point after having entered it
first via the "other" entry point, you would have to use:
CALL "mainprog" using...
via the Program-ID entry point
Note that if you call a program via the Program-ID entry point, then this
is case sensitive. By default, you must specify the program name in
lower case in the Program-ID paragraph as shown in the above example; you
could not call this program with:
CALL "MAINPROG" USING...
You can alter this default, thus allowing you to specify the program name
in upper case by setting the FOLDPROGID compiler directive.
Following the IBM conventions and in order to ensure complete portability
of your applications, you are recommended to use only digits and
upper-case letters in your Program-ID and entry point names. If the
first character of a program name (that is the file-name of the source
code, the Program-ID name and any ENTRY ""USING name) is not
alphabetical, it is mapped to an alphabetical character as follows, so
that it can be referenced either by its original name or by the name
resulting from this conversion:
0 converts to J
1-9 converts to A-I
This applies only if the digit is in the first character position of the
program-name. If your program-name contains a hyphen, this is mapped to
zero such that it may be referenced with either a hyphen or a zero,
regardless of it position in the name.
The dynamic loader run-time support module converts the names of all
calls before searching for the program in memory. If the program is not
found in memory, an attempt is made to load it from disk using the
unmapped name. Hence, the first time a program is called, you must use
the program file-name; that is, the Program-ID. A hyphen, therefore, may
be accepted. After loading, however, the program name and entry point
names are held by the dynamic loader run time support module in their
unmapped format.
You must not use entirely numeric call names as COBOL Program-IDs as
these are reserved by the COBOL system. This is for compatibility with
the way in which non-COBOL programs were called in previous Micro Focus
COBOL products. See Appendix B , Compatibility Issues for full
details.
You should be aware when using multiple entry points in programs that
this is regarded in many circles as bad programming practice. We
recommend that if you do use multiple entry points, you avoid entering a
program for the first time via an entry point other than the main entry
point.
Passing the Command Line
This section describes the various ways in which you can call a program
and pass the command line to the main program as a parameter. The main
program in a run-unit is the first program within it; that is, the
program which is called directly by the COBOL system. The COBOL system
treats the main program in a run-unit as a special case. It can be
regarded as being called by the system shell, with the command line
representing the one parameter to the call.
As the maximum size, form and contents of the command line vary between
operating systems, these issues need to be considered if you wish to port
your application between environments. For example, to ensure
portability, a maximum command line size of 128 characters may be
appropriate rather than the system shell limit. Similarly, only
alphabetic and numeric characters together with the equals sign (=) and
space characters should be used for entering the command line for a
program if you wish to guarantee portability.
The UNIX system may modify the user entered command line whenever
metacharacters such as the asterisk (*), question mark (?), parentheses (
), backslash (\) or quotation marks (") are entered on the command line.
The parentheses are often used in command lines in non-UNIX environments,
so the COBOL system allows the equals sign (=) to be used to represent
parentheses. For example, if you enter a command line in the following
format:
prog param1 param2=param3 param4= param5
the command is actually passed to the COBOL program in the following
format:
param1 param2(param3) param4( ) param5
The command line can accessed from COBOL in one of the following ways:
* ACCEPT ... FROM COMMAND-LINE
* ACCEPT ... FROM ARGUMENT-NUMBER/ARGUMENT-VALUE
* Linkage Section
* ACCEPT ... FROM CONSOLE
* READ from stdin
Each of these methods is discussed in the following sections.
ACCEPT ... FROM COMMAND-LINE
The ACCEPTdata-name FROM COMMAND-LINE statement causes the complete
contents of the command line to be moved to data-name. See your Language
Reference for complete details.
ACCEPT ... FROM ARGUMENT NUMBER/ARGUMENT-VALUE
This statement processes the command line as a series of space delimited
parameters. See your Language Reference for details.
Linkage Section
You can pass a command line parameter, in the format shown below, to the
Linkage Section of the main program:
01 cmd-line.
05 argc pic 9(4) comp.
05 arg.
10 args pic x occurs 0 to 65535 depending on arg c.
In order to be able to access this example parameter, the main program
must declare the above area in its Linkage Section and must have the
following Procedure Division header:
procedure division using cmd-line.
This causes the main program to be invoked as though the system program
which had invoked it were a COBOL program calling it with a CALL
statement of the form:
CALL "program-name" using cmd-line.
You can substitute your own names for the items shown in the above
example, but you must use a format similar to that shown here.
Note that ARGC contains a count of the actual number of occurrences of
ARGS, that is, the number of characters on the command line, and you must
not access data beyond this. You are recommended to test that the length
field contains a non-zero value which does not exceed the maximum limit
of the occurs. You should take care not to access data beyond the end of
the command line (for example, by defining a fixed length field and then
MOVEing it) as this would be an illegal reference and could give you a
hardware error on some systems.
Consider the following example:
working-storage section.
01 argv pic x(20).
01 argv-length pic 9(4) comp.
01 argv-max-length pic 9(4) comp value 20.
01 next-argv pic 9(4) comp value 1.
linkage section.
01 cmd-param.
03 cmd-length pic 9(4) comp-x.
03 cmd-line.
05 cmd-char pic x occurs 1 to 999 depending on cmd-length.
procedure division using cmd-param.
a000 section.
if cmd-length = 0
display "No command line "
end-if
if cmd-length 999
display "Command line too long" stop run
end-if
perform until next-argv cmd-length
unstring cmd-line delimited by all " " into argv
count in argv-length with pointer next-argv
if argv-length argv-max-length
display "Argument too long"
else
perform process-argv
end-if
end-perform.
...
process-argv.
...
In order to ensure that your program is portable, you must use the OCCURS
DEPENDING clause. If you do not use this clause, characters after the
end of the specified command line length may be accessed, thereby giving
a memory validation error on some systems.
The length of the command line is held as a two-byte integer which can
hold values larger than the COBOL picture.
ACCEPT ... FROM CONSOLE and READ from stdin
The following formats are provided for compatibility with earlier COBOL
versions and can be enabled by setting the appropriate cobconfig value
(see Chapter 31 , Run-Time Configuration for details).
The first ACCEPT data-name[FROM CONSOLE] executed in a program behaves in
the same way as ACCEPT data-name FROM COMMAND-LINE. Subsequent ACCEPT ...
FROM CONSOLE statements read the standard input.
A LINE SEQUENTIAL file named :CI: or stdin will read standard input,
except for the first read, which will return the command line into the
input buffer.
Calling Non-COBOL Subprograms.
You can access non-COBOL subprograms using the standard COBOL CALL ...
USING statement. The address of each USING parameter is passed to the
argument in the non-COBOL subprogram which has the same ordinal position
in the formal parameter declarations. You must thus ensure all formal
parameter declarations are pointers.
Note that, if you use the CALL...USING BY VALUE form of the CALL...USING
statement, the USING parameter is not passed BY VALUE if it is larger
than four bytes long. If it is larger than this, it may be passed BY
REFERENCE, but no warning is output to inform you of this. If you
specify a numeric literal with a CALL...USING BY VALUE statement, it is
passed BY VALUE as though it were a four-byte COMP-5 item; that is, it
appears in machine-order as a data item and not as a pointer to that data
item. If you specify a data item with a CALL...USING BY VALUE statement
it must be defined as COMP-5.
If you call a C routine by number, the parameter must be a number in the
range 0 to 127.
The following example shows how C functions can be accessed from a COBOL
program:
$set rtncode-size(4)
working-storage section.
01 str.
03 str-text pic x(10).
03 filler pic x value x"00".
* Null terminate string for C function
01 counter pic 9(8) comp-5 value zero.
procedure division.
call-c section.
call "cfunc" using str, counter
if return-code not = zero
* RETURN-CODE set from return () in C
display "ERROR"
else
display "OK"
end-if
stop run.
------------------------------------------------
cfunc (st, c)
char *st;
int *c;
{
.
.
.
return(0);
}
All of the non-COBOL subprograms which you want to call from COBOL must
be statically linked to the dynamic loader run-time support module, or to
your executable COBOL application, using the cob command. The format of
the cob command you use determines whether you are creating a new RTS, or
a fully linked executable application program with the non-COBOL programs
linked to it.
cob -xe "" cprog.c -o rts
creates a new RTS called "rts" and allows all COBOL programs invoked with
rts to access the C functions linked to rts, as the entry point is null,
and can be supplied at run-time, while:
cob -x cobprog.cbl cprog.c -o cobprog
creates a fully executable COBOL application called "cobprog" and allows
only the specified COBOL program (cobprog.cbl) and any of its called
subprograms, to access the C functions linked to it. See Chapter 2 ,
COBOL System Interface for full details on the use of the cob command.
When you use the CALL statement from within a COBOL program to access a
non-COBOL module as described above, you must ensure that the COBOL run
environment is not accidentally damaged. This means, you must ensure
that:
* The called module preserves the local COBOL run environment (that
is, the registers) according to 'C' calling conventions. Refer to
the documentation supplied with your UNIX system for allocation of
registers over calls, and a definition of which registers should
be preserved, and which can be used as work registers.
* The global COBOL run environment (that is, data areas allocated by
the COBOL system, open file, buffers, environment variables, and
so on) should be destroyed or altered only under the direct
control of the COBOL system. See Appendix A , Advanced
Programming Features for details.
The CANCEL statement has no effect when it references a non-COBOL
program.
The Micro Focus COBOL system supports functions to allow C programs
to call COBOL programs. Full details on these functions are given in
Appendix A , Advanced Programming Features.
Run-Time Errors 114 and 115
The Micro Focus COBOL system traps unexpected signals and returns
run-time errors:
114 Attempt to access item beyond bounds of memory
115 unexpected signal
Where C and COBOL modules are linked together, these error messages are
usually due to an error in the C code which causes a hardware interrupt
for such conditions as segmentation violation. If you do receive these
run-time errors, carefully check the C source routines using the system
debugger, paying particular attention to the format and byte ordering of
parameters passed between the COBOL and C modules.
Calling Operating System Functions.
The COBOL Run-Time system sets the terminal to a mode suitable for COBOL.
Calls to "system" will fail because they do not affect the mode, as
terminal settings are not modified before or after the call.
You should replace your calls to "system" with calls to "SYSTEM": this
is a subroutine provided with this COBOL system so that your operating
system can perform the same operations as system( ), but return the
terminal to shell mode before executing the command. The format of this
command is:
CALL "SYSTEM" using cmd-line
where:
cmd-line is a null-terminated command line
Upon completion of the call"SYSTEM" command, the terminal is reset to the
mode suitable for COBOL. For example:
01 cmd-line
03 c-1 pic xx value "sh".
03 c-2 pic x value x"00".
procedure division.
000-control.
display "test" at 0101
call "SYSTEM" using cmd-line
display "back in program" at 0201
stop run.
As COBOL is unaware of any output from either call "system" or call
"SYSTEM", you must ensure that your screen is either not updated by a
call or is redisplayed after execution of the call.
We recommend that you use the dd_ interface method to interface with your
operating system (see Chapter 12 , COBOL File Handling for details).
For example, if you want to move one file to another file, running
/bin/sh you should set your dd_ environment variable to:
"mv [file1] [file2]2 &1"
All output can be read via the file and displayed in COBOL. You can
change the dd_ mapping by using cobputenv, if you want to access
different operating system commands (see Appendix A , Advanced
Programming Features).
Recursion
This section shows you how you can create recursive programs with this
COBOL system.
In this COBOL system, a program can be recursive provided it is not
nested inside another program and it has a Local-Storage Section. A
program can call itself via either its program-ID or an entry point. The
example below illustrates recursion in COBOL. It reads a table of a
person's descendants and displays the names of those who have no
children.
Each call of a recursive routine is called an
instance. Each instance needs a different set of the data items used by
the routine. For this reason this COBOL system allows you to have a
Local-Storage Section. Every time a new instance of the routine starts,
a new, initialized copy of this section is created in memory; this is
deleted when the instance finishes. You get a run-time error message if
you try to use recursion in a program that does not contain a
Local-Storage Section.
Example
In the following example, the table in the item family-tree contains an
entry for each of Fred Smith's descendants. Assume the data has been put
in the table by an earlier program. The first entry is Fred Smith's own.
Each entry contains, as well as the person's name, a data item called
eldest-pointer containing the position in the table of the entry for that
person's eldest child. Someone with no children has 99 in this item.
Similarly each entry has a data item sibling-pointer pointing to the
entry for the person's next younger sibling. Someone with no younger
siblings has 99 in this item.
identification division.
program-id. family.
. . .
working-storage section.
01 family-tree.
03 individualoccurs 50.
05 ind-name pic x(30).
05 eldest-pointer pic 9(2).
05 sibling-pointer pic 9(2).
local-storage section.
01 tree-pointer pic 9(2).
linkage section.
01 parent-pointer pic 9(2).
procedure division.
move 1 to tree-pointer
call "children" using tree-pointer
stop run.
* If this person has no eldest child, routine "children"
* displays the person's name and does nothing more. Otherwise,
* this routine starts with the person's eldest child and calls
* itself for each sibling in turn.
entry "children" using parent-pointer
move eldest-pointer(parent-pointer) to tree-pointer
if tree-pointer = 99
display ind-name(parent-pointer)
else
perform until tree-pointer = 99
call "children" using tree-pointer
move sibling-pointer(tree-pointer)to tree-pointer
end-perform
end-if.
MPE/iX 5.0 Documentation