![]() | The COBOL Interfacing Environment | Header-to-COPY Utility | ![]() |
This chapter describes mixed-language programming; that is, the calling of C programs from COBOL programs, and the calling of COBOL programs and entry points from C functions. All references to C can also be taken to mean any other high-level languages that conform to C calling conventions, such as C++ code contained within the C++ syntax:
extern "C" { ... }.
This section describes how to call and cancel C programs from COBOL programs.
A COBOL program can call a C function using the COBOL CALL syntax. For example:
CALL "c_func" [USING ...] [RETURNING ...]
where c_func
is a C function. Any USING items are passed
as arguments to the C function. Any RETURNING item contains the return
code from the C function.
Refer to the chapter The COBOL Interfacing Environment for more details.
Canceling a COBOL program ensures that the next time it is referenced it is in its initial state. However, this does not necessarily happen when a non-COBOL program is canceled. Any tidying up of resources (memory, open files, and so on) used by the non-COBOL program depends on the language used to create the program and the various options associated with its compiler.
When you cancel a dynamically called COBOL or non-COBOL program, the memory used by the program is freed. Canceling programs that are statically linked into the executable does not free any memory.
The demonstration program cobmain1.cbl can be found using Infomgr. It demonstrates a COBOL program calling C and C++ functions. It shows how to:
A C function can call a COBOL entry point in the same way as it would
call another C function. For example, the following demonstrates C
code which calls a COBOL entry point, cobep
, using two
arguments:
cobep(arg1, arg2);
A C function can call, and cancel, COBOL programs and entry points using the cobcall(), cobcancel() and cobfunc() routines, as described in the sections below.
Before calling a COBOL program, you must call cobinit().
If your application has a C main() and the command line needs to be accessed from COBOL, then cobcommandline() must be called.
Before exiting a thread that has called a COBOL program, but which was not created via COBOL APIs, you must call cobthreadtidy(); also see the section Routines That Enable COBOL to be Called From C.
Before exiting an application that has called a COBOL program, you must call either cobtidy() or cobexit().
If the COBOL program and the C function that calls it are not contained in a callable shared object, nor linked together in a system executable file, then:
cob ... -d cobep
which searches for cobep
on disk (that is, for cobep.so,
cobep.gnt, and cobep.int).
The demonstration programs cmain1.c and cxxmain1.C can be found using Infomgr. They demonstrate a C and C++ program calling COBOL. They show how to:
Server Express provides a number of library routines that enable you to mix C and COBOL programs.
This section details the cob-prefix routines. These routines should only be called from C; they should not be called from COBOL. The routines are available on all platforms, except where stated otherwise.
The routines are prototyped in C header files, as indicated below, and are located in the $COBDIR/include directory.
The routines use portable data types, which have the naming convention cobtype_t. Definitions of these data types can be found in the cobtypes.h header file in $COBDIR/include.
This section describes the routines that enable COBOL programs to be called and canceled from C functions. See the sections Calling COBOL from C and Routines that Enable Use of a C main() for more details.
Before calling a COBOL program, you must call cobinit().
Before exiting a thread that has called a COBOL program, but was not created via the COBOL multi-threading syntax or library routines, you must call cobthreadtidy().
Before exiting an application that has called a COBOL program you must call either cobtidy() or cobexit()
Call a COBOL program, subprogram or entry point from C.
#include "cobcall.h" cobrtncode_t cobcall (const cobchar_t *name, int argc, cobchar_t **argv);
name |
A null-terminated string that specifies the name of the COBOL program to be called |
argc |
The number of arguments passed in argv |
argv |
Arguments to be passed to the COBOL program |
This routine is used to call the COBOL program of the specified name
using the arguments passed in argv
. Parameters
are passed BY REFERENCE.
The result of a cobcall() is a COBOL type call as defined in the ANSI '74 standard and behaves in the same way as if the COBOL entry point had been called from COBOL.
This is equivalent to calling a COBOL program directly from C code, using C syntax.
If the specified name is an entry point of an already loaded COBOL
program, that program is called. Alternatively, if the specified name
is a C function, then that is called. Otherwise, a program with a
basename of the specified name is searched for on disk using the standard
COBOL search order and paths. See the program_search_order
run-time tunable in the chapter Run-time Configuration in your
Server Express User's Guide for details on how to change
the program search order.
If no program of the specified name can be found a run-time error is produced. Also see the cobgetfuncaddr() function in this chapter.
If the COBOL entry point does not expect any arguments then argc
should be 0 and argv
should be NULL.
CALL "name" [USING ...] [RETURNING ...]
To call a COBOL entry point, cobep
, with two string
arguments from a C function use either:
cobchar_t *argv[2]; argv[0] = arg1; argv[1] = arg2; cobcall("cobep", 2, argv);
or:
cobep(arg1, arg2);
If cobep is not already loaded, it is searched for on disk using the standard COBOL search order and paths (that is, cobep.so, cobep.gnt, cobep.int).
Cancel a previously called COBOL program.
#include "cobcall.h" void cobcancel (const cobchar_t *name);
name |
A null terminated string that specifies the name of the COBOL program to be canceled. |
The COBOL program, specified by name
, is canceled
and the data contained in the program is returned to its initial state as
defined for the COBOL CANCEL verb (see your Language
Reference for details).
If name
is a C function then its data will be
unchanged. Also see Canceling C Functions.
If name
does not correspond to any loaded COBOL
entry point or C function no action occurs and this routine returns as
normal.
CANCEL "name"
To cancel the COBOL entry point cobep
:
cobcancel("cobep");
Call a COBOL program, subprogram or entry point and then cancel it
#include "cobcall.h" cobrtncode_t cobfunc (const cobchar_t *name, int argc, cobchar_t **argv);
name |
A null-terminated string that specifies the name of the COBOL program to be called |
argc |
The number of arguments passed in argv |
argv |
Arguments to be passed to the COBOL program |
This routine has the same effect as specifying cobcall() and then cobcancel(). That is, it calls the specified program and then cancels it, leaving the data contained in the program in its initial state.
See the descriptions of cobcall() and cobcancel() for more details.
This routine, unlike cobcall(), causes the program to behave as if it had been called using C function rules rather than COBOL call rules. cobfunc() returns the return code of the called program.
CALL "name" [USING ...] [RETURNING ...] CANCEL "name"
To call and then cancel a COBOL entry point cobep
, which
takes no arguments, use:
cobfunc("cobep", 0, NULL);
Return a function pointer to a COBOL program, subprogram or entry point.
#include "cobcall.h" PFR cobgetfuncaddr(int type, const cobchar_t *name);
type |
Indicates what is returned if the specified program is
not found.
|
|||||||||
name |
A null terminated string that specifies the name of the COBOL program to be found. |
This routine returns a function pointer to the COBOL program of the specified name.
If the specified name is an entry point of an already loaded COBOL
program, that program is called. Alternatively, if the specified name
is a C function, then that is called. Otherwise, a program with a
basename of the specified name is searched for on disk using the standard
COBOL search order and paths. See the program_search_order
run-time tunable in the chapter Run-time Configuration in your
Server Express User's Guide for details on how to change
the program search order.
If an error routine is returned (bit 0 set to 1) and it is subsequently called then a run-time error is produced, as for cobcall().
This routine only loads the program of the specified name; it does not call it. This enables programs to be preloaded. This is especially useful if you want to call an entry point within the program, but not the main entry point of the program.
SET procedure-pointer TO ENTRY "name"
The following C code calls a COBOL program cobprog
with
two arguments, coping with any error condition:
PFR cobprog; if ((cobprog = cobgetfuncaddr(0, "cobprog")) == NULL) { /* Error case */ } else { /* Loaded */ (*cobprog)(arg1, arg2); /* Call it! */ }
This section describes the routines required when the main entry point of an application is not a COBOL entry point; that is, when the main entry point is a C main() or provided by a third party.
Close down the global COBOL run environment.
#include "cobmain.h" void cobexit (cobrtncode_t exitstatus);
exitstatus |
The exit status returned to the calling process (for example, the shell). |
This routine terminates a running application in the same way as if a COBOL STOP RUN statement had been executed, emptying buffers, closing files and freeing any data areas allocated by the COBOL system.
You must use the cobexit() function to exit from non-COBOL applications rather than just using the C library routine exit().
This routine will ultimately call exit() and so will not return.
The specified exit status is returned to the calling process (for example, the shell). Standard UNIX practice is to use an exit status of 0 on success.
The COBOL run-time system returns values of -1 (255) and -2 (254) if it exits due to an error or signal. See the chapter Handling Protection Violation Errors for details.
STOP RUN
To exit an application that has used COBOL, returning an error value of +123 to the parent process, use:
cobexit(123);
Initialize the COBOL environment, so that a COBOL program can be called from a non-COBOL program.
#include "cobmain.h" int cobinit (void);
None.
If your program runs a mixture of non-COBOL and COBOL code, and the main program is not written in COBOL, you must call cobinit() before calling a COBOL program. If you do not, you might receive an initialization error when you enter your COBOL code.
On some platforms, the COBOL environment is initialized when the COBOL run-time system is loaded (for example, at process startup).
If the COBOL environment has already been initialised then cobinit() returns successfully.
This routine returns 0 on success.
None.
The following example shows how to initialize (and close down) the COBOL environment from a C main(), so that a COBOL program can be called:
main(int argv, char *argv) { cobinit(); /* Initialize COBOL environment */ cobcall("cobep", 0, NULL); /* Call a COBOL program */ cobtidy(); /* Close down COBOL environment */ return(0); }
Tidy up the global COBOL run environment.
#include "cobmain.h" int cobtidy (void);
None.
This routine deinitializes the COBOL environment, emptying buffers, closing files and freeing any data areas allocated by the COBOL system.
Use this routine if you want to close down the COBOL system, but are not yet ready to exit. It returns 0 on success.
This routine can only be called when all COBOL modules have been exited, and you do not intend to re-enter them. Do not call cobtidy() directly from a COBOL program.
Once cobtidy() has been called, no COBOL entry points or COBOL routines (such as cobinit()) should be called. Doing so results in undefined behaviour.
None.
The following example shows how to initialise and close down the COBOL environment from a C main(), so that a COBOL program can be called:
main(int argv, char *argv) { cobinit(); /* Initialize COBOL environment */ cobcall("cobep", 0, NULL); /* Call a COBOL program */ cobtidy(); /* Close down COBOL environment */ return(0); }
Set up the COBOL command line.
#include "cobmain.h" cobchar_t *cobcommandline(int flags, int *argcp, cobchar_t ***argvp, cobchar_t ***envpp, cobchar_t **namep);
flags |
Reserved for future use. Must be 0. |
argcp |
Address of the argc argument
passed to the C main(). |
argvp |
Address of the argv argument
passed to the C main(). |
envpp |
Address of the envp argument
passed to the C main(). |
namep |
Reserved for future use. Should be NULL. |
This routine sets up the COBOL run environment with the passed command line.
If your application has a C main() and the command line is accessed from COBOL, then this routine must be called.
This routine is only available in this form on UNIX platforms.
None.
The following example shows how to use this routine:
main(int argc, char **argv, char **envp) { cobinit(); cobcommandline(0, &argc, &argv, &envp, NULL); /* Rest of code here */ cobexit(0); }
This section describes the routines required when COBOL is called from threads created by non-COBOL APIs; that is, when a thread is created by C library, OS or third party threading APIs.
Before calling a COBOL program, you must call cobinit(). In a threaded environment where you don't know if you're the first thread or not, each thread should call cobinit().
Before exiting an application (and not just the current thread) that has called a COBOL program, you must call either cobtidy() or cobexit().
Tidy up the thread-local COBOL run environment.
#include "cobmain.h" int cobthreadtidy(void);
None.
This routine deinitializes the COBOL environment for the current thread, cleaning up any thread-state information and freeing any data allocated as thread-local. It returns 0 on success.
This routine can only be used when the current thread was created by non-COBOL APIs; that is, if the thread was created by C library, OS or third-party threading APIs. It must not be called if the thread was created by COBOL syntax or the CBL_THREAD_CREATE library routine. Do not call cobthreadtidy() directly from a COBOL program.
This routine must only be called when all COBOL modules have been exited in this thread and you do not intend to reenter them.
Once cobthreadtidy() has been called, no COBOL entry points or COBOL routines (such as cobinit()) should be called in this thread. Doing so results in undefined behaviour.
None.
When a C thread is created, you need to specify a C function that is the initial entry point for the thread. If this entry point is c_thread(), then the following shows how to:
cobep
, which takes no
arguments c_thread(void) { cobinit(); /* Only required if not */ /* already called in this */ /* process */ cobcall("cobep", 0, NULL); /* Call COBOL */ cobthreadtidy(); /* Tidy up COBOL in this */ /* thread */ return 0; /* Exit thread */ }
This section describes the routines that enable a C program to safely access data declared within COBOL programs.
A COBOL record layout is similar to a C structure containing arrays of characters. When the Compiler assigns a COBOL record layout, it does not take into account the alignment of binary or pointer data items, or byte ordering of binary (COMP-X) data items, required by any specific hardware platform; because of this, COBOL applications are extremely portable. However, this portability can cause problems in mixed-language applications. C structure layout is not as rigidly defined as COBOL record layout and varies quite widely from operating system to operating system. For example, in COBOL the structure:
01 mystruct is typedef. 05 mystruct-key-1 pic x occurs 2. 05 mystruct-bin-1 pic x(4) comp-5.
is six bytes long, no matter what platform it is compiled on. However, with the C compilers provided on most operating systems, a straightforward representation of this record layout in C would give different results. For example, :
struct mystruct { char mystruct_key_1[2]; long mystruct_bin_1; };
would result in a structure eight bytes long on most 32-bit operating
systems, and 16 bytes long on most 64-bit operating systems, due to
alignment padding. A better solution, because it is portable, is to
represent the COBOL record mystruct
using the C structure:
struct mystruct { char mystruct_key_1[2]; char mystruct_bin_1[4]; };
To enable conversion of COBOL data records into the C data types for a mixed-language application, your Server Express product contains a C include file $COBDIR/include/cbltypes.h which contains many of the basic types used in COBOL applications and in our CBL_ library routine interfaces. These types directly correspond to those types contained in the copyfile $COBDIR/cpylib/cbltypes.cpy.
Revisiting the example from section 11.3.4.1, the following COBOL record layout:
01 mystruct is typedef. 05 mystruct-key-1 cblt_x1 occurs 2. *> aka. "PIC X" 05 mystruct-bin-1 cblt_x4_comp5. *> aka. # "PIC X(4) COMP-5"
can be correctly represented in C, using $COBDIR/include/cbltypes.h, as:
#include "cbltypes.h" struct mystruct { cbl_x1_t mystruct_key_1[2]; cbl_x4_comp5_t mystruct_bin_1; };
The type name conventions used in cbltypes.h, are intended to naturally reflect the PICTURE strings of the corresponding COBOL type definition. The basic types provided in this include file are as follows:
cbl_x1_t cobol character position - basis for all types cbl_pointer_t Equivalent to: USAGE POINTER cbl_ppointer_t Equivalent to: USAGE PROCEDURE-POINTER cbl_sx1_comp5_t Equivalent to: PIC s9(n) COMP-5 where n=1 or 2 cbl_sx2_comp5_t Equivalent to: PIC s9(n) COMP-5 where n=3 or 4 cbl_sx4_comp5_t Equivalent to: PIC s9(n) COMP-5 where n=7 through 9 cbl_sx8_comp5_t Equivalent to: PIC s9(18) COMP-5 cbl_x1_comp5_t Equivalent to: PIC X(1) COMP-5 cbl_x2_comp5_t Equivalent to: PIC X(2) COMP-5 cbl_x4_comp5_t Equivalent to: PIC X(4) COMP-5 cbl_x8_comp5_t Equivalent to: PIC X(8) COMP-5 cbl_x1_compx_t Equivalent to: PIC X(1) COMP-X cbl_x2_compx_t Equivalent to: PIC X(2) COMP-X cbl_x4_compx_t Equivalent to: PIC X(4) COMP-X cbl_x8_compx_t Equivalent to: PIC X(8) COMP-X
Even though you can portably declare COBOL data in the C language, you still need to operate on that data in a C context. To enable you to do this, Server Express includes C library routines that enable many COBOL-based data types to be converted into a format suitable for use in the context of your C application component.
Convert COBOL-based data to/from native C language types.
#include "cbltypes.h" /* Includes cbltypes.h and cobgetput.h */ cobuns8_t cobget_x1_compx(const cbl_x1_compx_t *cbldata); cobuns16_t cobget_x2_compx(const cbl_x2_compx_t *cbldata); cobuns32_t cobget_x4_compx(const cbl_x4_compx_t *cbldata); cobuns64_t cobget_x8_compx(const cbl_x8_compx_t *cbldata); cobuns8_t cobget_x1_comp5(const cbl_x1_comp5_t *cbldata); cobuns16_t cobget_x2_comp5(const cbl_x2_comp5_t *cbldata); cobuns32_t cobget_x4_comp5(const cbl_x4_comp5_t *cbldata); cobuns64_t cobget_x8_comp5(const cbl_x8_comp5_t *cbldata); cobs8_t cobget_sx1_comp5(const cbl_sx1_comp5_t *cbldata); cobs16_t cobget_sx2_comp5(const cbl_sx2_comp5_t *cbldata); cobs32_t cobget_sx4_comp5(const cbl_sx4_comp5_t *cbldata); cobs64_t cobget_sx8_comp5(const cbl_sx8_comp5_t *cbldata); cobuns64_t cobget_xn_comp5(const cbl_x1_t *cbldata, cobuns8_t n); cobuns64_t cobget_xn_compx(const cbl_x1_t *cbldata, cobuns8_t n); cobs64_t cobget_sxn_comp5(const cbl_x1_t *cbldata, cobuns8_t n); void *cobget_pointer(const cbl_pointer_t *cbldata); PFR cobget_ppointer(const cbl_ppointer_t *cbldata); void cobput_x1_compx(cbl_x1_compx_t *cbldata, cobuns8_t val); void cobput_x2_compx(cbl_x2_compx_t *cbldata, cobuns16_t val); void cobput_x4_compx(cbl_x4_compx_t *cbldata, cobuns32_t val); void cobput_x8_compx(cbl_x8_compx_t *cbldata, cobuns64_t val); void cobput_x1_comp5(cbl_x1_comp5_t *cbldata, cobuns8_t val); void cobput_x2_comp5(cbl_x2_comp5_t *cbldata, cobuns16_t val); void cobput_x4_comp5(cbl_x4_comp5_t *cbldata, cobuns32_t val); void cobput_x8_comp5(cbl_x8_comp5_t *cbldata, cobuns64_t val); void cobput_sx1_comp5(cbl_sx1_comp5_t *cbldata, cobs8_t val); void cobput_sx2_comp5(cbl_sx2_comp5_t *cbldata, cobs16_t val); void cobput_sx4_comp5(cbl_sx4_comp5_t *cbldata, cobs32_t val); void cobput_sx8_comp5(cbl_sx8_comp5_t *cbldata, cobs64_t val); void cobput_xn_comp5(cbl_x1_t *cbldata, cobuns8_t n, cobuns64_t val); void cobput_xn_compx(cbl_x1_t *cbldata, cobuns8_t n, cobuns64_t val); void cobput_sxn_comp5(cbl_x1_t *cbldata, cobuns8_t n, cobs64_t val); void cobput_pointer(cbl_pointer_t *cbldata, void *val); void cobput_ppointer(cbl_ppointer_t *cbldata, PFR val);
cbldata |
Pointer to the COBOL data item and data description as indicated by the cobget or cobput routine name. |
n |
For cobget_xn_ or cobput_xn_
routines. Describes the number of COBOL character positions cbldata
occupies. |
val |
Value to be placed in the COBOL data item cbldata. |
The cobget_xn_compx and cobput_xn_compx routines enable you to extract
data from data descriptions such as PIC X(3)
.
mycblprog.cbl:
program-id. mycblprog. copy "cbltypes.cpy". 01 myrec. 05 myrec-key cblt-x4-compx value 10. procedure division. call 'mycprog' using myrec-key if myrec-key = 20 display "First call to 'mycblprog'" else display "Subsequent call to 'mycblprog'" end-if exit program end program mycblprog.
mycprog.cbl:
#include "cbltypes.h" void mycprog(cbl_x4_compx_t *cbldata) { cobput_x4_compx(cbldata, cobget_x4_compx(cbldata) + 10); }
This section describes the routines required so that the COBOL run-time system knows that the environment has changed.
Provide the same functionality as the C library call getenv().
#include "cobenv.h" cobchar_t *cobgetenv(const cobchar_t *name);
name |
A null-terminated string, specifying the environment variable name to be searched for. |
The specified environment variable is searched for and returned. If the environment variable does not exist then NULL is returned.
DISPLAY name UPON ENVIRONMENT-NAME ACCEPT ... FROM ENVIRONMENT-VALUE
The following code displays the value of $COBDIR:
cobchar_t *cobdir; if ((cobdir = cobgetenv("COBDIR")) == NULL) cobdir = "<unset>"; cobprinf("COBDIR=%s\n", cobdir);
Dynamically change the environment at run time.
#include cobenv.h" int cobputenv (const cobchar_t *envstr);
string |
The null terminated string to be placed into the environment. |
The environment string envstr is put into the environment. By convention, environment strings have the format:
NAME=VALUE
but the run-time system does not check that envstr
is in this format.
This routine ultimately passes envstr
into the C
library routine putenv(), which puts envstr
into the
OS environment. Hence, the value of envstr
cannot be modified or freed (if at all) until the environment variable has
been redefined using another cobputenv().
This routine returns a value of zero if the operation was successful; any other value indicates an unsuccessful operation. Illegal environment names lead to undefined results.
DISPLAY name UPON ENVIRONMENT-NAME DISPLAY value UPON ENVIRONMENT-VALUE
The following code shows how to set $ABC to XYZ:
cobputenv("ABC=XYZ");
Cause the run-time system to rescan the environment for COBOL environment strings.
#include "cobenv.h" int cobrescanenv(void);
None.
This routine rescans the environment for COBOL environment strings, such as file-name mapping entries (that is, dd_ entries). This can be useful if the environment has been changed without the knowledge of the run-time system.
A value of zero is returned on success; any other value indicates an unsuccessful call.
None.
The following code shows how to set a dd_ environment variable so that an open of file abc will instead open xyz:
cobputenv("dd_abc=xyz"); cobrescanenv();
For information on dd_ file mapping, see the section Filename Mapping in the chapter Filenames in your File Handling book.
Server Express supports a number of screen handling routines that you can use from C programs. These enable the run-time system and run-time support libraries to handle output from both C programs called from COBOL programs and from ACCEPT/DISPLAY operations performed by the calling COBOL programs. Normally if any screen handling is carried out outside the control of COBOL (for example, under the control of C) COBOL is not aware of the output from the screen handling operation when control returns to COBOL. The effect of subsequent screen handling operations could thus be undefined. The routines provided enable you to avoid this problem.
The routines in this section are not portable to non-UNIX environments.
When using these routines you must include the header file cobscreen.h, which is located in the directory $COBDIR/include. This file defines the attributes you can use, the type (cobchtype) and declares any external functions the routine needs. The type cobchtype defines a two-byte pair, with the first byte containing a character and the second the attribute for that character.
The attribute byte of cobchtype, as used in some of these routines, takes the same values as the user attribute byte. By default the UNIX user attribute byte is monochrome with the attributes listed below. These values can change when generic attributes are used (from COBOL). See the chapter Low-level Routines for Character Interfaces in your Programmer's Guide to Creating User Interfaces for details of the COBOL system library routines that can be used to set attributes.
The default monochrome attributes are bit settings and can be combined by ORing them together. The following attribute bit values are defined in cobscreen.h:
Attribute
|
Description
|
---|---|
A_NORMAL A_BOLD A_UNDER |
Normal, no attribute Bold or highlight Underline |
A_REVERSE A_BLINK A_DIM |
Reverse Blink Dim or lowlight |
These routines use their own "virtual cursor", set using cobmove(). The virtual cursor is thread-local; that is, each thread has its own virtual cursor.
Display the specified character on the screen at the virtual cursor's current position.
#include "cobscreen.h" void cobaddch (cobchtype ch);
ch |
The required character and any attributes. |
The specified character and attribute ch
are
displayed on the screen at the current position of the virtual cursor.
A character of \n
(new line) is a valid character, and
moves the virtual cursor to the beginning of the next line. No other
control characters are valid; their use causes undefined results.
None.
However, this routine is similar to the COBOL syntax:
CALL "CBL_WRITE_SCR_CHATTRS" USING ...
To display the character "X" in reverse-video, use:
cobaddch('X' | A_REVERSE);
Display the specified string on the screen starting at the virtual cursor's current position.
#include "cobscreen.h" int cobaddstr (const cobchtype *str);
str |
The required string and any attributes. |
The specified string of characters and attributes str
is displayed starting at the current position of the virtual cursor. If
the string is longer than the remaining width of the line, it will wrap
when it reaches the edge of the screen.
A character of \n
(new line) is a valid character, and
moves the virtual cursor to the beginning of the next line. The null
character \0
terminates the string. No other control
characters are valid; their use causes undefined results.
str
cannot contain more than 255 characters.
This routine returns 0 on success.
CALL "CBL_WRITE_SCR_CHATTRS" USING ...
To display the string "HUB" with highlighting, underline and blink attributes, use:
cobchtype s[4] = { 'H' | A_BOLD, 'U' | A_UNDER, 'B' | A_BLINK, 0 }; cobaddstr(s);
Display the specified string on the screen starting at the virtual cursor's current position.
#include "cobscreen.h" int cobaddstrc (const cobchar_t *cstr);
cstr |
The required string. |
The specified string of characters cstr
is
displayed with the default attribute (A_NORMAL), starting at the current
position of the virtual cursor. If the string is longer than the remaining
width of the line, it wraps when it reaches the edge of the screen.
A character of \n
(new line) is a valid character, and
moves the virtual cursor to the beginning of the next line. The null
character \0
terminates the string. No other control
characters are valid; their use causes undefined results.
cstr
cannot contain more than 255 characters.
CALL "CBL_WRITE_SCR_CHARS" USING ...
or:
DISPLAY cstr AT yyxx
To display the string "Hello World" followed by a newline, use:
cobaddstrc("Hello World\n");
Clear the screen and positions the cursor at line 0, column 0.
#include "cobscreen.h" void cobclear (void);
None.
This routine causes the screen to be cleared. The virtual cursor is reset to the home position, at line 0, column 0
CALL "CBL_CLEAR_SCREEN" USING ...
or:
DISPLAY SPACES UPON CRT
To clear the screen and display a message in the top left hand corner, use:
cobclear(); cobaddstrc("Cursor home occurs on cobclear\n");
Return the number of columns on the screen.
#include "cobscreen.h" int cobcols (void);
None.
This routine returns the width in columns of the screen.
CALL "CBL_GET_SCR_SIZE" USING ...
To find out and display the width of the screen use:
int width = cobcols(); cobprintf("Width of screen = %d\n", width);
Get a character from the keyboard.
#include "cobscreen.h" int cobgetch (void);
None.
Reads a character from the keyboard and returns it. If no character is pending this routine waits until a key is pressed.
A value of -1 is returned on error (for example, EOF).
CALL "CBL_READ_KBD_CHAR" USING ...
The following code asks for a Yes/No response:
int ch; cobaddstrc("Continue [y/n]? "); ch = cobgetch(); if (ch == 'Y' || ch == 'y') { /* Yes */ }
Return the number of lines on the screen.
#include "cobscreen.h" int coblines (void);
None.
This routine returns the depth in lines of the screen.
CALL "CBL_GET_SCR_SIZE" USING ...
To find out and display the depth of the screen use:
int depth = coblines(); cobprintf("Depth of screen = %d\n", depth);
Move the virtual cursor to the specified line and column on the screen.
#include "cobscreen.h" void cobmove (int y, int x);
y |
The line number to move the virtual cursor to |
x |
The column number to move the virtual cursor to |
The virtual cursor, as used by the routines in this section, is moved to the line and column values, as specified by the y and x parameters.
The virtual cursor home position, of the top left hand corner, is (0,0). That is, a y value of 0 and an x value of 0. The virtual cursor is thread-local. That is, each thread has its own virtual cursor.
CALL "CBL_PUT_SCR_POS" USING ...
The following displays a simple counter:
int secs = 10; char *message = "Time Left: "; cobmove(10, 10); cobprintf("%s%d", message, secs); while (secs--) { sleep(1); cobmove(10, 10 + strlen(message)); cobprintf("%2d", secs); }
Display the specified formatted string on the screen at the virtual cursor's current position.
#include "cobscreen.h" int cobprintf (const cobchar_t *fmt, ...);
fmt |
The formatted string to display. |
The formatted character string fmt
is displayed
with the default attribute (A_NORMAL), starting at the current position of
the virtual cursor. If the string is longer than the remaining width of
the line it wraps when it reaches the edge of the screen.
The fmt
paramter is formatted as it would be by
the C library routine, printf(). For example, any %s
in fmt
is substituted for the string in the subsequent arguments passed to
cobprintf().
The character \n
(new line) is a valid character and moves
the virtual cursor to the beginning of the next line. The null character
\0
terminates the string. No other control characters are
valid; their use causes undefined results.
The specified string must not be longer than 255 characters in length
when fmt
has been fully expanded.
This routine returns either the number of arguments output or -1 for an error condition.
None
The following displays a simple counter:
int secs = 10; char *message = "Time Left: "; cobmove(10, 10); cobprintf("%s%d", message, secs); while (secs--) { sleep(1); cobmove(10, 10 + strlen(message)); cobprintf("%2d", secs); }
Scroll the screen display, starting and finishing at the specified lines, up one line.
#include "cobscreen.h" void cobscroll (int top, int bot);
top |
The first line of the area of screen to be scrolled up one line. This must be two lines less than the physical screen size to prevent the top line from scrolling off the screen. |
bot |
The last line of the area of screen to be scrolled up one line |
None
The top line of the screen is 0. The bottom line of the screen can be found using coblines(). Hence, to scroll the entire screen use:
cobscroll(0, coblines() - 1);
This section details the routines to cope with terminal specific functionality. Also see the chapter Terminfo Database and Terminal Devices in your Server Express User's Guide.
The functions in this section are only available on UNIX environments.
Put the numeric keypad of the terminal keypad into local mode or transmit mode.
#include "cobscreen.h" void cobkeypad(int mode);
mode |
The keypad mode; either 0 or 1. |
This routine puts the numeric keypad of the terminal keypad (if there is one) into local mode or transmit mode. To function correctly, the smkx (transmit mode) and rmkx (local mode) entries must be present in the terminfo database for the terminal type you are using.
The mode
parameter should be 0 to put the keypad
into local mode or 1 to put the keypad into transmit mode. Any other value
is undefined.
By default, the run-time system puts the numeric keypad into transmit mode when smkx is present in your terminfo database.
None
Toggle the terminal screen between standard and wide modes.
#include "cobscreen.h" int cobtermmode(const cobuns8_t *mode)
mode |
The terminal mode; the address of a byte that is either 0 or 1. |
This routine toggles the terminal screen between default and wide modes, if this functionality is present in the terminfo database for the terminal type you are using.
To function correctly, the terminfo database must support a terminal
whose name is the current terminal type with a -w
suffix,
and the terminfo entries must also have appropriate initialization and/or
reset capabilities. For example, if the current terminal is vt100
then there also needs to be a vt100-w
in the terminfo
database and the vt100
and vt100-w
need
appropriate is1
, is2
, is3
,
rs1
, rs2
and/or rs3
entries.
The mode parameter should be 0 to put the terminal into standard (default) terminal mode or 1 to put the terminal into wide terminal mode. Any other value is undefined.
When the terminal mode is successfully toggled, the screen handling system is initialised (if it wasn't already), the screen is cleared and the cursor positioned in the home position.
This routine can be safely called from COBOL. See the section Wide Terminal Mode in the chapter Terminfo Database and Terminal Devices of your Server Express User's Guide for more details.
When using this routine, you must be aware of the following:
the normal mode uses the COBTERMINFO version and wide mode uses the system version. This can cause unexpected results where the two files differ in capabilities other than column size changes.
See the chapter Terminfo Database and Terminal Devices in your Server Express User's Guide for more details on the terminfo search order.
This routine returns 0 on success, non-zero on error. The following error values are currently returned:
1 | The terminfo file has not been found, is not readable, is corrupt or there is not enough memory. |
2 | The terminfo file does not contain one or more of the required capabilities. |
3 | The environment does not support the requested code. |
CALL "cobtermmode" using mode
The following code switches the terminal into wide mode, displays some text, waits for a keypress and restores the terminal back to normal mode:
cobuns8_t mode_on=1, mode_off=0; if (cobtermmode(&mode_on) == 0) { /* Display some text over beyond column 80 to demo */ /* wide mode */ cobmove(10, 100); cobprintf("Line 10, Column 100"); cobgetch(); /* Wait for a key press */ cobtermmode(&mode_off); /* Back into standard mode */ }
The COBOL run-time system sets the terminal to a mode suitable for COBOL. This means that any calls to the C library routine system() might fail because they do not reset the terminal settings before the call, or set them back after the call.
You should replace your calls to system() with calls to SYSTEM() as detailed below.
The function in this section is only available on UNIX environments.
Run an executable via a system shell.
#include <sys/wait.h> int SYSTEM (const unsigned char *cmd);
cmd |
A null-terminated system command line to be executed. |
The specified command line is passed to a shell and executed, as for the C library routine system().
The COBOL terminal state is reset to shell mode before the call and restored after the call.
As the COBOL environment is unaware of any output from another process, such as the shell or command executed during SYSTEM(), you must ensure that the screen is either not updated during the SYSTEM() call or is redisplayed after execution of the call.
The return value from this routine is the same format as that returned from the C library routine system(). There are macros in the C library include file <sys/wait.h> to manipulate this value and get the return code of the executed command. See your system documentation for more information.
CALL "CBL_EXEC_RUN_UNIT" USING ...
The example below copies one file to another, redirecting standard output and standard error to an error file (which could be subsequently opened and read to see if any output was generated by running the command) and displays the return code of the command:
int res; res = SYSTEM("cp f1 f2 > errfile 2>&1"); if (WIFEXITED(res)) cobprintf("Exit status: %d\n", WEXITSTATUS(res));
This section describes the cobsetjmp() and coblongjmp() routines that enable you to mix C and COBOL programs. They provide routines similar to the C library routines setjmp() and longjmp(); see your UNIX documentation for details of setjmp() and longjmp().
The purpose of the cobsetjmp() and coblongjmp() routines is to provide the capability of a non-local GO TO, for use in error or exception handling.
Provide the capability of a non-local GO TO, for use in error or exception handling.
#include "cobsetjmp.h" int cobsetjmp(struct cobjmp_buf *buf); void coblongjmp(struct cobjmp_buf *buf);
buf |
A buffer in which the current execution environment is saved. |
The cobsetjmp() routine saves the environment of the current COBOL
program and C function in the buffer pointed to by buf
.
It calls the C library routine setjmp(), which immediately returns a value
of 0.
A subsequent call to coblongjmp() either from elsewhere in the C function that called cobsetjmp(), or from one of its C or COBOL subprograms, causes execution to be resumed at the point immediately after the call to cobsetjmp().
After calling coblongjmp(), cobsetjmp() returns a non-zero value, thus enabling the value to be tested after the cobsetjmp() call.
The following restrictions apply when using these functions:
None.
The following shows how to use these routines:
void some_c_func(void) { struct cobjmp_buf buf; if (cobsetjmp(&buf) != 0) { cobprintf("Returned from coblongjmp\n"); return; } /* Valid code here - for example can call COBOL */ coblongjmp(&cobjmp_buf); }
This section describes the calls you need to make if you want to use signal handling in your application, especially if you are mixing COBOL and C in your application.
The run-time system sets up default signal handlers for all signals whose operating system default action is to cause termination. These default handlers make sure that the COBOL system is properly cleaned up before terminating. Hence, any open files are closed (to prevent file corruption), the terminal is reset to a sane state, user posted exit and error procedures are executed, and so on.
The run-time system also uses signal handling to provide various functionality. For example, interrupt key detection, Animator Zoom interrupt key, Job Control, and so on.
This COBOL system provides two routines that you can use to complement or override the signal handling used by the run-time system:
cobpostsighandler()
cobremovesighandler()
These routines allow multiple handlers for each signal and enable you to prioritize use of these handlers. You can use them from inside a C program only, not least because you need the C library include file <signal.h> for the signal values, which vary between platforms.
Use these routines instead of the operating system signal calls, (signal(), sigaction(), and so on) which provide only the ability to post a single signal handler for each call and so often prevent multiple applications being able to work together reliably.
For example, if you use one of the C library signal calls to post a signal handler before invoking a COBOL program, your signal handler might be overridden. Whereas, if you use one of the C library signal calls after invoking a COBOL program, the default run-time system handler, additional COBOL functionality and user posted signal handlers are all overridden, causing unexpected results.
Add the specified handler to the list of handlers for the specified signal, at the specified priority.
#include "cobsignal.h" cobsigtype_t cobpostsighandler (int signal, int priority, PFI_SIG handler);
signal |
Signal number, as defined in the <signal.h> include file. |
priority |
The priority of handler in the range 1 to 254. |
handler |
Address of your signal handler. |
This routine posts the specified handler to the list of handles for the specified signal at the specified priority. Also see the section Posting Signal Handlers below.
priority
is the priority of the handler in the
range 1 to 254, where 254 is the highest priority. Values 127 and 129
through 139 are reserved for use by MERANT.
handler
is the address of your signal handler.
This must be a C function returning an integer value.
This routine returns a pointer that you can use to remove your signal
handler later. If the return value is NULL, a signal handler was not
posted for this signal. This could be due to lack of memory or the signal
being disabled by the tunable signal_regime
.
None.
Remove a posted handler from the list of handlers for the appropriate signal.
#include "cobsignal.h" void cobremovesighandler (cobsigtype_t sighandler);
sighandler |
Pointer returned when posting your signal handler using a previous cobpostsighandler() call. |
This routine removes a previously posted signal handler.
sighandler
must have been previously returned when
posting a signal handler with the cobpostsighandler() routine. See the
section Posting Signal Handlers below.
There is no return value from this call.
None.
You use the cobpostsighandler() routine to post signal handlers.
The run-time system also uses the cobpostsighandler() routine to post all of its signal handling. Default handlers are posted for all signals whose operating system default action causes termination. The default handlers either make sure that the COBOL system has been cleaned up before terminating, or cause the signal to be ignored. These default handlers assume that the signals were generated by the operating system due to a serious error or that a signal has been unexpectedly raised. Hence, they usually produce a run-time system message, such as 114 or 115.
If the same handler is posted twice, and neither of them is removed using the cobremovesighandler() routine, the handler is executed twice (assuming the handler, and all handlers executed in between, do not return a value of zero).
If two handlers are posted with the same priority, the last one posted is executed first.
Once you have posted a handler, you do not need to repost it. The handler is called each time that signal is received (assuming that the first receipt of the signal does not cause termination). If you want to execute your handler only once, you must remove it, using the cobremovesighandler() routine, in your signal handler.
While processing signal handlers, the signal is blocked. This prevents recursion if the same signal is received in rapid succession.
A signal handler must return normally. That is, you must not use any other function that terminates a signal handler function, such as longjmp() or coblongjmp(), and you must use the C syntax to return a value:
return(num);
If you do use another function to return, the signal remains blocked, preventing any further signals from being processed.
When a signal is received, the handler posted with the highest priority for that signal is called. Your handler should take any appropriate action (such as setting a flag to be acted on later) and then return. If the handler returns a non-zero value, the handler with the next highest priority for that signal is called. If the signal handler returns zero, no further signal handlers are processed.
The run-time system posts its default signal handlers with priority 127. So, to override them, or to process your signal handler before them, post your handler with priority 128. Use a priority of 126 (or less) if you want to make sure that your handler is processed after the default run-time system handler (if the default run-time system handler does not exit).
The run-time system provides various functionality using signal handlers. These handlers are posted with a priority in the range of 129 to 139.
A signal handler should do very little. A signal can be generated at any time so the routine that was being executed could be in an "unsafe" state (eg. in the middle of modifying global variables) and so trying to execute it in your signal handler could cause problems. The routine being executed could be a C library routine such as malloc().
There are a small subset of C library routines that are safe to call from signal handlers. Do not try to call any other C library routines, or any COBOL routines, from your signal handler. See your system documentation for more information on the safe C library routines.
Some signals are generated by the operating system when a serious error has occurred. Catching these signals can cause unexpected and potentially dangerous results. You should not catch any of the following signals:
SIGBUS
SIGSEGV
SIGEMT
SIGILL
SIGIOT / SIGABRT
SIGSYS
SIGFPE
SIGTRAP
Preventing the run-time system from processing certain signals can break some run-time system functionality. If you catch any of these signals (with a priority of 140 or more), your signal handler must return a non-zero value so that the run-time system's handler is also executed. The signals concerned include:
SIGCHLD
SIGPIPE
SIGUSR1
SIGUSR2
SIGVTALRM
SIGWINCH
SIGCONT
SIGTSTP
SIGTTIN
SIGTTOU
Note: MERANT reserves the right to change their default signal handlers or use extra signals in the future.
The following example illustrates setting up a handler for the SIGALRM signal.
#include <stdio.h> #include <signal.h> #include "cobsignal.h" #include "cobmain.h" int mysigcatch(int sig) { cobprintf("In new signal handler\n"); return(0); /* Do not process any further handlers */ } void mysigexit(cobsigtype_t sighand) { cobprintf("Cancelling handler\n"); cobremovesighandler(sighand); /* Remove the handler */ } main(int argc, char *argv[]) { cobsigtype_t sighandle; cobinit(); sighandle = cobpostsighandler(SIGALRM, 128, mysigcatch); cobfunc("cobolprog", argc, argv); /* call a cobol program using cobfunc function */ alarm(1); /* raise the signal */ pause(); /* wait for the signal */ sleep(4); mysigexit(sighandle); cobexit(0); /* Cobexit - close down COBOL run-time environment */ }
The cobpostsighandler() routine enables two or more handlers to be posted for the same signal. When that signal is generated by the operating system (such as a SIGINT generated when the interrupt key is pressed), each handler can take appropriate action and then let other handlers be executed (by returning a non-zero value). Alternatively, they can decide to make the signal "ignored" by returning a value of zero to prevent other handlers from being executed. However, so that your handler can work with other handlers for the same signal, a handler of priority 140 (or more) should return non-zero to let other handlers have the opportunity to also be notified. A handler of priority 128 can return zero if you do not want the run-time system default action to be executed (which may cause termination).
When you raise a signal (such as by using alarm() to raise a SIGALRM signal, or when raising a signal to a different run-unit or application), then it is probable that only your signal handler wants to be called and other posted signal handlers are not expecting the signal. Hence, in this case, you should set a global resource before raising the signal and then check that resource in your signal handler. If the resource is set (as expected), then the signal was raised by you, so you can take the appropriate action and return zero to prevent other handlers from being unexpectedly called. If the resource is unset, then someone else (or something else, such as the operating system) raised the signal and so you can take no action and should let other handlers execute by returning a non-zero value.
Examples of global resources are global variables (if in the same run-unit), shared memory, pipes, files, and so on. Hence, in the above example, we could have set a global variable before raising the alarm() signal. We would then need to check the global variable in the signal handler, mysigcatch(). If it was set, we would carry out our action, reset the variable and return zero. However, if the global variable had not been set, then some other code is likely to have raised the signal. Hence, we would not want to carry out our action and would instead need to return a non-zero value immediately. This allows the appropriate action to be taken in some other handler.
If you have any signal handlers that are posted using a C library signal call, such as signal() or sigaction(), change them to use the cobpostsighandler() routine. This is so that your handler and any default run-time system handler, additional COBOL functionality and user posted signal handlers can all co-exist without one overriding the other, causing unexpected results.
The cobpostsighandler() routine interface is very similar to the signal() interface. The two parameters you pass to signal() are also passed to the cobpostsighandler() routine, plus a priority.
The differences between signal() and the cobpostsighandler() routine are:
The return value from cobpostsighandler() is either a pointer or NULL. You use this pointer to remove your handler later using cobremovesighandler(). If the return value is NULL, the handler was not posted for the signal.
You do not need to repost a handler that you posted using cobpostsighandler() routine; it stays posted. If you want your handler to be executed only once, remove it using the cobremovesighandler() routine.
If you are using third party software that posts a signal handler using a C library signal routine, such as signal() or sigaction(), unexpected results may occur. For example, if the third party software posts its handler before COBOL has been invoked, then when COBOL is invoked the third party's handler might be overridden by a run-time system/COBOL handler. If the third party subsequently raises a signal, then a 115 error may occur.
To overcome this, you can use the run-time tunable
signal_regime
.
This tunable prevents handlers from being posted for the specified signal
if a signal handler is posted before the first COBOL invocation.
If handlers are prevented from being posted for a signal, due to this tunable, the cobpostsighandler() routine returns NULL. Hence, the default run-time system handlers and any additional COBOL functionality achieved using the signal is not available. It also means that you should check the value returned from any cobpostsighandler() routine calls for NULL.
Use of the signal_regime
tunable is recommended only for use with third party software. You should
always use the cobpostsighandler() routine in your own code. See the
chapter Run-time
Configuration in your Server Express User's Guide
for details on how to set signal_regime
.
On some platforms, the C library routine sigaction() is available. It is more robust than signal() when signals are being received in rapid succession or when a machine is heavily loaded. The cobpostsighandler() routine uses sigaction() by default.
You can force the cobpostsighandler() routine to use signal() instead of
sigaction() by using the signal_interface
tunable. For more information on tunables see the chapter
Run-time
Configuration in the Server Express User's Guide.
Copyright © 2000 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names
used herein are protected by international law.
![]() | The COBOL Interfacing Environment | Header-to-COPY Utility | ![]() |