On 9/16/2010 11:38 AM, Scott Ford wrote:
I have seen several 'bit and piece' posts on LE Cobol calling C
All:

I have seen several 'bit and piece' posts on LE Cobol calling C. I have written
a sample C call and here is the source and have included the C source and JCL ,
Cobol source and JCL, I dont understand what I have missed, I have been through
the LE Books and C-C++ books and I am confused and the execution is receiving a
S0C7 :

JCL for 'C' compile:
----------------------

//ADCDMETA JOB SYSTEMS,MSGLEVEL=(1,1),MSGCLASS=X,CLASS=A,PRTY=8,
//     NOTIFY=&SYSUID,REGION=0M
//     EXEC EDCCL,
//   INFILE=SFORD.JCLLIB.CNTL(TESTC)',
//   OUTFILE='SFORD.CLINKLIB(TS04B),DISP=SHR'

'C'  Source:
-------------------

#include<stdio.h>
#include<string.h>
#pragma linkage(TS04B,COBOL)
void TS04B( char *pBuffer )
{
   strcpy( pBuffer, "OK       ");
   fprintf(stderr,"ok trans\n");
}

LE Cobol V4r1 JCL:
--------------------------

//ADCDTHRA JOB SYSTEMS,MSGLEVEL=(1,1),MSGCLASS=X,CLASS=A,PRTY=8,
//     NOTIFY=&SYSUID,REGION=4096K
//*----------------------------------------------------------------
//COB     EXEC PGM=IGYCRCTL,
//             PARM=('NOC(E)','FLAG(W)','DATA(31)',NODYN,RES,RENT,OPT,
//             MAP,NOSSR,NOZWB,NUM,NOTERM,NOVBREF,X,APOST,LIB,LIST),
//             REGION=1024K
//STEPLIB   DD DISP=SHR,DSN=IGY410.SIGYCOMP
//SYSLIB    DD DISP=SHR,DSN=CEE.ACEESRC1
//          DD DISP=SHR,DSN=SFORD.CLINKLIB
//SYSPRINT  DD SYSOUT=X
//SYSUT1    DD UNIT=VIO
//SYSUT2    DD UNIT=VIO
//SYSUT3    DD UNIT=VIO
//SYSUT4    DD UNIT=VIO
//SYSUT5    DD UNIT=VIO
//SYSUT6    DD UNIT=VIO
//SYSUT7    DD UNIT=VIO
//SYSLIN    DD DISP=(,PASS),DSN=&&LOADSET,
//             UNIT=VIO,
//             DCB=BLKSIZE=3200
//SYSIN     DD DISP=SHR,DSN=SFORD.COBOL.SOURCE(THRALLC)
//*
//LNK     EXEC PGM=IEWL,
//             COND=(4,LT,COB),
//             PARM='LIST,XREF',
//             REGION=4096K
//SYSLIB    DD DISP=SHR,DSN=SFORD.CLINKLIB
//          DD DISP=SHR,DSN=CEE.SCEELKED
//          DD DISP=SHR,DSN=SYS1.CSSLIB
//          DD DISP=SHR,DSN=TCPIP.SEZATCP
//SYSLMOD   DD DISP=SHR,DSN=SFORD.CLINKLIB
//SYSUT1    DD UNIT=SYSDA,
//             DCB=BLKSIZE=1024,
//             SPACE=(1024,(200,20))
//SYSPRINT  DD SYSOUT=X
//SYSLOUT   DD SYSOUT=X
//SYSLIN    DD DISP=(OLD,DELETE),DSN=&&LOADSET
//          DD DDNAME=SYSIN
//SYSIN     DD *
   MODE AMODE(31),RMODE(ANY)
   INCLUDE SYSLIB(EDCSTART)
   INCLUDE SYSLIB(CEEROOTB)
   INCLUDE SYSLIB(@@CBL2C)
   INCLUDE SYSLMOD(TS04B)
   ENTRY THRALLC
   NAME THRALLC(R)
/*
//

LE Cobol Source:
---------------------

        IDENTIFICATION DIVISION.
        PROGRAM-ID. THRALLC.
        ENVIRONMENT DIVISION.
        INPUT-OUTPUT SECTION.
        FILE-CONTROL.
        DATA DIVISION.
        FILE SECTION.
        WORKING-STORAGE SECTION.
        01 TS04B        PIC X(8) VALUE 'TS04B'.
        01 TESTIT       PIC X(10) VALUE 'SCOTT'.
        PROCEDURE DIVISION.
            DISPLAY 'START OF TS04A'.
            CALL TS04B USING TESTIT.
            DISPLAY TESTIT.
            GOBACK.

Sorry for the long post, but I think one has to see all the pieces.
Please tell me am I blind in my old age or what...
Thanks in advance.


Scott J Ford


I think there's a bunch of issues here, so I'll try and address
them all.

1. It seems to me you unnecessarily complicate things by
   calling your C source member TESTC and then binding it
   under the name TSO4B; why do that? life is simpler if
   you can use source member names the same as load module
   names; so I reverted to that

2. You don't really need the #pragma linkage(TS04B,COBOL)
   or, in my case, #pragma linkage(TESTC,COBOL) statement;
   (we'll see the tradeoffs shortly)

3. When you pass an array (in this case, a character string)
   to a C subroutine, C expects to be passed a pointer to
   the string; C also does not handle the end-of-list bit
   flag that COBOL generates; there are three ways (at least)
   to handle this:

   * code the #pragma linkage(TESTC,COBOL) statement
     - don't like to limit a subroutine to a single
       programming language

   * in your calling program, pass an extra parm, so that
     the first parm is the true string you want to pass
     and the second parm is just a place for COBOL to
     set on the end-of-list flag, which C will not even
     notice, since it is only expecting one parameter
     - a simple example, that works, is to name the
       parameter twice, such as:

          call testc using testit, testit
       (this works)

   * in your calling program, set up pointer to your
     last (and only, in this case) argument, and pass
     the pointer BY VALUE; for example:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. THRALLC.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 TS04B        PIC X(8) VALUE 'TESTC'.
       01 TESTIT       PIC X(10) VALUE 'SCOTT'.
       01 TESTIT-PTR   POINTER.
       PROCEDURE DIVISION.
           DISPLAY 'START OF THRALL.'
           SET TESTIT-PTR TO ADDRESS OF TESTIT
           CALL 'TESTC' USING BY VALUE TESTIT-PTR
           DISPLAY TESTIT
           GOBACK.

   (this, too, works)


3. I notice you compiled with NODYNAM, but you made
   a dynamic call (CALL data-item is _always_
   dynamic, since the compiler can't tell what will
   be in 'data-item' at run time, so it can't tell
   the binder to include the subroutine); in the
   spirit of your code, I coded CALL 'routine' but
   compiled with NODYNAM, which will create a static
   call

4. All was almost all well, until I kept getting a
   return code of 9; some investigation shows the
   return value of fprintf, printf, and sprintf is
   the number of characters printed; this value is
   sent back to the calling program; I fixed this
   by adding a return(0) in the subroutine; but
   the compiler was unhappy because the type of
   the function could not then be 'void'; so I
   changed it to 'int' and all was well

5. I did not need _ANY_ binder (linkage editor) control
   statements; the default processes work fine

So, compile member TESTC into load module member TESTC:

#include <stdio.h>
#include <string.h>
int  TESTC( char *pBuffer   )
{
   strcpy( pBuffer, "OK");
   fprintf(stderr,"ok trans\n");
   return(0);
}


[Not quite sure why you used fprintf instead of printf,
 but either works]


Then compile member THRALLC into load module THRALLC:

       PROCESS OFFSET  NODYNAM
       IDENTIFICATION DIVISION.
       PROGRAM-ID. THRALLC.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 TS04B        PIC X(8) VALUE 'TESTC'.
       01 TESTIT       PIC X(10) VALUE 'SCOTT'.
       01 TESTIT-PTR   POINTER.
       PROCEDURE DIVISION.
           DISPLAY 'START OF THRALL.'
           SET TESTIT-PTR TO ADDRESS OF TESTIT
           CALL 'TESTC' USING BY VALUE TESTIT-PTR
           DISPLAY TESTIT
           GOBACK.


the binder will automatically pick up TESTC; Then run
and the result was:

START OF THRALL.
ok trans
OK TT

Not sure what you were trying to do, but that's what
your code does.

<ad>
All this, and lots more, is covered in our 3 and a
half day course "Secrets of Inter-Language Communication
in z/OS". Details at:

  http://www.trainersfriend.com/Language_Environment_courses/m520descr.htm

</ad>



--

Kind regards,

-Steve Comstock
The Trainer's Friend, Inc.

303-393-8716
http://www.trainersfriend.com

* To get a good Return on your Investment, first make an investment!
  + Training your people is an excellent investment

----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: GET IBM-MAIN INFO
Search the archives at http://bama.ua.edu/archives/ibm-main.html

Reply via email to