Translating C Definitions [ Micro Focus COBOL for UNIX COBOL User Guide ] MPE/iX 5.0 Documentation
Micro Focus COBOL for UNIX COBOL User Guide
Translating C Definitions
The OSF/Motif Programmer's Reference Manual describes all the Motif API
functions in terms of the C programming language. For those programmers
unfamiliar with C, this section explains how to translate these
descriptions into COBOL.
Your Motif development system includes definitions of many of the Motif
function parameters in C header files that use a file extension of .h.
This COBOL system contains a utility, H2cpy
, to convert C header files into COBOL COPY-files. The utility converts
C header files including those supplied with the Motif development kit
into COBOL type definitions and COBOL CALL prototypes. It is especially
useful if you want to write Motif applications in COBOL using the System
Programming Extensions. See your COBOL System Reference chapter
Header-to-COPY Utility for details on converting C header files. See
your Language Reference for details on COBOL TYPEDEFs and CALL
prototypes.
Before you can compile any of the sample programs (or your own Motif
software), you must first run H2cpy to translate the C header files into
COBOL as described below.
Converting C Header Files
The Motif development system includes a variety of C header files in the
directory Xm in the standard header directory of /usr/include. Before
you can program to the Motif API you need to translate many of these into
COBOL using H2cpy. Generally, each Motif function has its own header
file; you can find out which this is from the OSF/Motif Programmer's
Reference Manual. For example, XmCreateMainWindow is associated with
/usr/include/Xm/MainW.h and XmMessageBoxGetChild is associated with
/usr/include/Xm/MessageB.h.
H2cpy must convert all C header files during one run to ensure that
declarations are not duplicated. For this reason, you might find that
the most convenient way to translate the header files is to convert them
indirectly by creating your own header file, which lists together all the
files you are interested in. For example create a file called motif.h
and add a line for each file header required:
#include <Xm/MainW.h>
#include <Xm/MessageB.h>
#include <Xm/PushB.h>
...
Then run H2cpy to convert them ensuring that the environment variable
INCLUDE is either not set or set to /usr/include:
h2cpy motif.h -v
Alternatively, where only a few header files are required, you can
specify all the individual files directly on the command line:
h2cpy /usr/include/Xm/MainW.h /usr/include/Xm/MessageB.h -v
This translates the MainW.h and MessageB.h files and all their included
files into the COBOL copyfile MainW.cpy. You can use the COPY statement
to include this file in your program. The compiler then validates any
function calls that you make to ensure that the parameters conform to the
COBOL CALL prototype in MainW.cpy. H2cpy will automatically generate
useful CALL prototypes from the C function prototypes. However, it might
be that you find the validation inappropriate in some cases. You have
the choice of either modifying MainW.cpy or of running H2cpy with the
option to suppress the generation of CALL prototypes.
Translating C Function Declarations
The C definition of the XmCreateMainWindow API function is taken
from/usr/include/Xm/MainW.h and is shown in the following example; the
rest of this section explains how to translate this C definition into
COBOL.
extern Widget XmCreateMainWindow
(Widget parent,
char *name,
ArgList args,
Cardinal argCount);
The following list defines each of the words in the example:
Word Meaning
extern Declares the function as external and not defined
in the current program
Widget Function returns data type of Widget
XmCreateMainWindow Function name
Widget Data type of the parameter parent
parent Possible name for the parameter (optional in the
declaration but required in any use of the
function)
char Data type of the parameter name; char is
equivalent to a COBOL alphanumeric data item. C
generally expects this to be terminated by a null
character.
*name The asterisk denotes that the routine expects the
address of the parameter to be passed rather than
the value. The "name" portion represents a
possible name for the parameter.
ArgList Data type of the parameter args
args Possible name for the parameter
Cardinal Data type of the parameter argCount
argCount Possible name for the parameter
); End of the function declaration
All Motif API function definitions appear in at least one of the Motif
header files. The names used for the parameters are not significant and
may differ between the documented function definition and the equivalent
definition in the header file.
You now need to find the definitions of the data types and other
constructs and decide how to code them in COBOL. This information is in
the files produced by H2cpy. Coding is fairly straightforward but
instead of passing fully typed pointer parameters by value, as described
in the C function definition, COBOL can often pass them more conveniently
using the BY REFERENCE clause as may be shown in the COBOL prototype.
The first thing you need to determine is the calling convention required
by the XmCreateMainWindow routine. Look this routine name up in
MainW.cpy and you will find a CALL prototype definition such as:
entry "XmCreateMainWindow" using
by value data-pointer
by reference any
by value data-pointer
by value uns-int
returning data-pointer
The parameters are specified in terms of COBOL type definitions
data-pointer, uns-int, et cetera which are defined at the beginning of
the MainW.cpy file. The parameter any signifies that any data type can
be used. All COBOL CALL statements referencing XmCreateMainWindow must
use parameters that conform with the corresponding data type otherwise
the compiler will give an error. Wherever possible it is preferable to
use the type definition when defining data items rather than the explicit
COBOL PICTURE so that your program will be more portable between
different Motif API environments.
The calling convention that the routine XmCreateMainWindow requires is
given in the SPECIAL-NAMES paragraph of the program in which it is
defined. Look in MainW.cpy for the program-id preceding the call
prototype and you will find a declaration such as:
program-id. "c_typedefs" is external.
01 XmScrolledWindowWidgetClass is typedef
...
There is no SPECIAL-NAMES paragraph after the PROGRAM-ID paragraph. This
tells you that the routine XmCreateMainWindow must be called with the
default COBOL calling convention of 0. This means that you do not need
to define a calling convention for calls to the Motif API routines. For
purposes of documentation you can add the following line to the
SPECIAL-NAMES paragraph if you wish:
call-convention 0 is motapi
Returning to the C definition of the XmCreateMainWindow example
above, the first data type you need to translate is Widget. Since
XmCreateMainWindow returns a value of type Widget, you need to define a
storage location for that value, say WidgetResult. Looking up Widget in
the file MainW.cpy, you find this definition:
01 Widget is typedef usage data-pointer.
The word TYPEDEF indicates that the data type Widget is a type definition
and so can be used to define the type (i.e., usage) of the variable
WidgetResult. Widget is defined as having the data type data-pointer,
which is defined at the beginning of the MainW.cpy file as:
77 data-pointer pointer is typedef.
The data types Widget and data-pointer are, therefore, both equivalent to
the COBOL type, POINTER and they can all be used interchangeably. From
the COBOL CALL prototype found earlier we see that the routine returns a
value of type data-pointer and so we can define WidgetResult in terms of
Widget. However, as a COBOL programmer you may find the definition more
convenient with the equivalent line:
01 WidgetResult usage data-pointer.
Next consider the parameters to the function call. The first parameter
has type Widget, which has already been determined as type data-pointer.
The CALL prototype says that the first parameter must be passed BY VALUE
and have a type data-pointer and so we can write the line:
01 parent usage data-pointer.
The CALL prototype says that the second parameter must be passed BY
REFERENCE but can be of any type. The BY REFERENCE clause is a
convenient COBOL way of avoiding direct use of parameter pointers and of
permitting type checking. It is otherwise equivalent to passing a
parameter as an untyped pointer BY VALUE.
The C header file declares the parameter name as a char pointer. In C, a
char pointer references a char datatype which represents both a one-byte
numeric item or the start of a multi-byte text string. In contrast,
COBOL recognises a one-byte numeric item and a multi-byte alphanumeric
item as distinct data types. For this reason, when H2cpy translates a C
function prototype parameter that is a char pointer it cannot specify a
specific data type and so generates any.
From the API function description we know that the parameter name is a
pointer to a C string which is a multi-byte text item that is terminated
by a C null character. The closest COBOL equivalent is either an
alphanumeric data item that includes a C null character within its value
or a concatenation of an alphanumeric data item with an explicit C null
character. (You can use the DELIMITED clause if you are prepared to
modify your CALL prototype; see your Language Reference for details.)
It is generally convenient to use the COBOL concatenation
operator. For example you can define the BY REFERENCE parameter for name
as:
01 MainWName pic x(10) value "My-Window" & x"00".
Where a literal such as x"00" is used many times, it is important that
the correct value is coded each time. This can be done in a simple way
by declaring the literal as a level 78 item and thereafter using the
level 78 name:
78 c-null value x"00".
01 MainWName pic x(10) value "My-Window" & c-null.
The third parameter is data type ArgList. From MainW.cpy you get:
01 ArgList is typedef usage data-pointer.
The CALL prototype says that the third parameter must be passed BY VALUE
and have a type data-pointer and so we can write the line:
01 MainWArgs usage data-pointer.
From the C definition we know that this pointer must reference an
argument structure of type Arg. We can define such a group item as:
01 MainWArg usage Arg occurs 100.
and in the procedure you can set the parameter with a statement such as:
set MainWArgs to address of MainWArg(1)
The next parameter is of data type Cardinal. From MainW.cpy you get:
01 Cardinal is typedef usage uns-int.
Cardinal is defined as having the data type uns-int, which is defined at
the beginning of the MainW.cpy file as:
77 uns-int pic 9(9) comp-5 is typedef.
The CALL prototype says that the fourth parameter must have a type
uns-int and so, for convenience, we can define the parameter as:
01 argCount usage uns-int.
After defining the complete list of parameters, you end up with the
following source lines:
copy "MainW.cpy".
program-id. motdemo.
special-names.
call-convention 0 is motapi.
working-storage section.
78 c-null value x"00".
01 WidgetResult usage data-pointer.
01 parent usage data-pointer.
01 MainWName pic x(10) value "My-Window" & c-null.
01 MainWArgs usage data-pointer.
01 argCount usage uns-int.
01 MainWArg usage Arg occurs 100.
procedure division.
set MainWArgs to address of MainWArg(1).
NOTE The names name and args are already used for a data type so we have
to choose other, unique names for these parameters. MainWName and
MainWArgs are used in the example above.
After you have performed all these conversions, the COBOL call to the API
function XmCreateMainWindow becomes:
call "XmCreateMainWindow" using
by value parent
by reference MainWName
by value MainWArgs
by value argCount
returning WidgetResult
If the values you pass to the function are constants, then you can use
the phrases:
by reference "literal"
for alphanumeric literals and:
by value literal size n
for numeric literals, as long as you use specify the size of the literal.
Therefore, you could replace two parameters with literals to give the
following call:
call "XmCreateMainWindow" using
by value parent
by reference "My-Window" & c-null
by value MainWArgs
by value 2 size 4
returning WidgetResult
Constants defined at level-78 do not have any size associated with them.
When they are used as parameters in a CALL statement, they default to a
size of four bytes. The SIZE phrase of the USING clause can be used
specifically to set the number of bytes passed as the parameter.
For example, the constant XmDIALOG_OK_BUTTON is defined in the C header
files as:
#define XmDIALOG_OK_BUTTON 4
and translated by H2cpy in motif.cpy as:
78 XmDIALOG-OK-BUTTON value 4.
NOTE C uses the underscore character ( _ ) to split long names or
prefixes. The underscore cannot be used in COBOL. Therefore, H2cpy
replaces all underscores in names with hyphens (-)
.
This constant can be used as a legal value for child parameter in the API
function XmMessageBoxGetChild which is defined in C as:
extern Widget XmMessageBoxGetChild(
Widget widget,
unsigned char child
) ;
and is translated by H2cpy into:
entry "XmMessageBoxGetChild" using
by value data-pointer
by value uns-char
returning data-pointer
However, the child parameter must be of type uns-char which is defined in
MainW.cpy as:
77 uns-char pic 9(2) comp-5 is typedef.
Which is one byte in size. If this is to be passed as a literal then you
would have to add a SIZE 1 clause to specify the correct size:
call "XmMessageBoxGetChild" using
by value parent
by value XmDIALOG-OK-BUTTON size 1
returning WidgetResult
For further examples of how to use the files created by H2cpy, see your
COBOL System Reference.
Macros.
H2cpy does not convert C macros defined in the header files because COBOL
has no equivalent feature. This should not be a problem with the Motif
API, but note that the COBOL REDEFINES statement can often be used to
achieve the same effect.
Compiling
Compiling a program for Motif is no different to compiling any other
program. For performance reasons you will probably want to produce
native code.
Linking
You can dynamically load a COBOL Motif application as an .int or a .gnt
file or you can build your Motif application as an executable file. To
dynamically load .int or .gnt files you first need to build a suitable
run-time system.
Building a Run-time System.
To run .int or .gnt files you need to produce an executable run-time that
has all the necessary Motif API support routines linked in. We recommend
that you specify just those routines that are required, either via the
cob -I flag, or by creating a dummy program. The dummy program just
needs a CALL literal statement for each routine that is required. For
example:
procedure division.
stop "Error - shouldn't get here in Dummy".
call "XtInitialize".
call "XmCreateMainWindow".
call "XtManageChild".
* et cetera ...
Compile and link this with the system libraries to produce a run-time
system. The exact list of system libraries to be used needs to be taken
from your Motif development system documentation. A typical cob command
is given below; your Motif system might include additional libraries that
need adding to the link list (for example +lPW +lsocket +lintl):
cob -xo mrts -e "" dummy.cbl +lXm +lXt +lX11
After compiling your Motif application then you can run it:
cob motdemo.cbl
./mrts motdemo.int
Building an Executable Application.
To build your application as an executable, just use the following cob
command (adding any additional libraries your Motif development system
might require):
cob -xF motdemo.cbl +lXm +lXt +lX11
Then run it by simply entering:
./motdemo
Debugging
You can use Animator to directly debug Motif applications on an X
terminal. You need to compile your application for animation, set COBSW
for animation and then run your application as .int code as discussed
above. For the Bourne shell use:
COBSW=+A
export COBSW
./mrts motdemo.int
MPE/iX 5.0 Documentation