1

I have C program that calls COBOL. I want to set the switches before the COBOL program is called. This is normally done using the COBSW environment variable.

When I set COBSW in the C program, it is as tho it is ignored. When I set COBSW before the program is called, it is detected fine.

How can I get the COBSW set in C and have COBOL recognize it?

Here are somethings I tried:

  1. I removed cobinit() and the program still runs. This indicates to me that the cobinit is somehow automatic when the C program starts and it will only pickup COBSW set in sh.

  2. I added cobrescanenv() to the program.

  3. Moved cobinit() before the cobputenv().

Here is the sh script that runs the test:

export C_INCLUDE_PATH=$COBDIR/include

PATH=$COBDIR/bin:$PATH

gcc -o callcobol.o -c -g -Wall -Wno-unused-variable -fPIC -Ibuild -Isrc callcobol.c

/opt/microfocus/VisualCOBOL/bin/cob -o callcobol -g callcobol.o -L/usr/local/lib -ldl -lrt -lpthread

cob -z cobsw.cbl -o TESTSW.so

unset COBSW
echo "Test ONE, COBSW not set:"
echo "We want the output to be:"
echo "SW0=ON  sw1=ON  sw2=ON  sw3=ON  sw4=ON  sw5=ON  sw6=OFF sw7=ON "
echo "Getting:"
./callcobol

#                Output:
#                        value of COBSW is: +0+1+2+3+4+5-6+7
echo ""
echo ""

export COBSW=+1+2   # This should be ignore because we are setting COBSW in the c program.
echo "Test TWO, COBSW set to ${COBSW}, but should be overlaid by putenv() in C:"
echo "We want the output to be:"
echo "SW0=ON  sw1=ON  sw2=ON  sw3=ON  sw4=ON  sw5=ON  sw6=OFF sw7=ON "
echo "Getting:"
./callcobol

Here is callcobol.c:

#include <stdlib.h>
#include <stdio.h>
#include "cobcall.h"
#include "cobmain.h"
#include "cobenv.h"
PFR cobgetfuncaddr(int type, const cobchar_t *name);
int cobinit (void);

int main(int argc, char *argv[])
{
    cobchar_t *prog = (cobchar_t *) "TESTSW";
    //char *cobswval;
    const char *cobswname = "COBSW";

    cobputenv( (cobchar_t *) "COBSW=+0+1+2+3+4+5-6+7");    // out dummy computed SWITCH values for the program
    //cobswval = getenv( cobswname);
    //fprintf(stdout,"value of COBSW is: %s\n", cobswval);
    cobinit();             /* Initialize COBOL environment */
    cobrescanenv();

    PFR cobprog;

    if ((cobprog = cobgetfuncaddr(0, prog)) == NULL)
    {
        fprintf(stderr,"ERROR: could not find cobol module %s\n", (char *) prog);
    }
    else
    {
        /* Loaded */
        (*cobprog)();    /* Call it! */
    }

    cobtidy();             /* Close down COBOL environment */

    return(0);   // return a return code of zero
}

Here is cobsw.cbl:

  $SET CONFIRM
  $SET IBMCOMP
  $SET CHARSET"EBCDIC"
   IDENTIFICATION DIVISION.
   PROGRAM-ID. TESTSW.
   ENVIRONMENT DIVISION.
   CONFIGURATION SECTION.
   SPECIAL-NAMES.
     SWITCH-0 IS SW0 ON IS SW_0_ON
     SWITCH-1 IS SW1 ON IS SW_1_ON
     UPSI-2 ON IS SW_2_ON
     UPSI-3 ON IS SW_3_ON
     UPSI-4 ON IS SW_4_ON
     UPSI-5 ON IS SW_5_ON
     UPSI-6 ON IS SW_6_ON
     UPSI-7 ON IS SW_7_ON.
   INPUT-OUTPUT SECTION.
   FILE-CONTROL.
   DATA DIVISION.
   FILE SECTION.
   WORKING-STORAGE SECTION.
   01  rec-cnt pic 9(11) value zero.
   01  sw-out.
        02 filler     pic x(4) value "SW0=".
        02 SW0-status pic x(3).
        02 filler     pic x(5) value " sw1=".
        02 SW1-status pic x(3).
        02 filler     pic x(5) value " sw2=".
        02 SW2-status pic x(3).
        02 filler     pic x(5) value " sw3=".
        02 SW3-status pic x(3).
        02 filler     pic x(5) value " sw4=".
        02 SW4-status pic x(3).
        02 filler     pic x(5) value " sw5=".
        02 SW5-status pic x(3).
        02 filler     pic x(5) value " sw6=".
        02 SW6-status pic x(3).
        02 filler     pic x(5) value " sw7=".
        02 SW7-status pic x(3).
   01 acc-data pic x(80) value spaces.
   LINKAGE SECTION.
   PROCEDURE DIVISION.
   MAIN-PARAGRAPH.
       move "OFF" to SW0-status SW1-status SW2-status
                     SW3-status SW4-status SW5-status
                     SW6-status  SW7-status.

       IF SW_0_ON move "ON " to  SW0-status.
       IF SW_1_ON move "ON " to  SW1-status.
       IF SW_2_ON move "ON " to  SW2-status.
       IF SW_3_ON move "ON " to  SW3-status.
       IF SW_4_ON move "ON " to  SW4-status.
       IF SW_5_ON move "ON " to  SW5-status.
       IF SW_6_ON move "ON " to  SW6-status.
       IF SW_7_ON move "ON " to  SW7-status.
       display sw-out.
       EXIT PROGRAM.
   END PROGRAM TESTSW.

Here is the script output:

Test ONE, COBSW not set:
We want the output to be:
SW0=ON  sw1=ON  sw2=ON  sw3=ON  sw4=ON  sw5=ON  sw6=OFF sw7=ON
Getting:
SW0=OFF sw1=OFF sw2=OFF sw3=OFF sw4=OFF sw5=OFF sw6=OFF sw7=OFF


Test TWO, COBSW set to +1+2, but should be overlaid by putenv() in C:
We want the output to be:
SW0=ON  sw1=ON  sw2=ON  sw3=ON  sw4=ON  sw5=ON  sw6=OFF sw7=ON
Getting:
SW0=OFF sw1=ON  sw2=ON  sw3=OFF sw4=OFF sw5=OFF sw6=OFF sw7=OFF
Be Kind To New Users
  • 9,672
  • 13
  • 78
  • 125
  • In general terms, you're setting switches just in the environment loaded to run the first program. You need to find a way to export them, from C, to the master environment so that the COBOL program will have access. – Brian Knoblauch Aug 20 '15 at 17:25
  • The COBOL program is running in the process and same environment as the C program. In this case the COBOL program is like a function rather than a stand alone program. With that new information, could you elaborate on your statement. Perhaps tell us what a "Master environment" is. – Be Kind To New Users Aug 20 '15 at 19:01
  • 1
    From the way I read your script, C is not actually calling COBOL, the shell is. In a typical OS, the shell holds the environment. A fresh shell is spawned (with copied environment) to run the C application. The C application updates that environment. When it ends that environment is discarded, so the shell that starts COBOL has the original (unmodified) environment. Either C has to directly spawn COBOL with it's copy of the environment or you need to export the C version of the shell back to the parent shell. – Brian Knoblauch Aug 20 '15 at 19:04
  • Brian, Please look at the C code rather than the shell script and you will see where the COBOL is being called as a function from the C code. – Be Kind To New Users Aug 20 '15 at 20:05
  • Can you show callcobol, please? Also exactly version and name of Micro Focus COBOL you are using. – Bill Woodger Aug 22 '15 at 09:20
  • The C code in the example is callcobol.c. I will have to ask the developer what the exact version is, but name of the COBOL is VisualCOBOL. – Be Kind To New Users Aug 22 '15 at 11:31
  • From some Micro Focus docs. You need to check this for your exact product: "If a COBOL entry point is referenced by a direct C function call, and not using cobcall(), the reference to the COBOL program needs to be resolved using the cob -d flag; for example: cob ... -d cobep which searches for cobep on disk (that is, for cobep.so, cobep.gnt, and cobep.int)." – Bill Woodger Aug 24 '15 at 09:57
  • The environment-variables that tell COBOL something aren't like those you set-up for yourself, in that the COBOL runtime has to connect the value of the envrionment-variable to the UPSI switches (in this case). In Micro Focus COBOL generally (let alone your specific) I don't know where there happens, but *suspect* it is "outside" of the program, thus without the reference to cobep at compile-time. there will be no run-time intervention to make the connection. – Bill Woodger Aug 24 '15 at 10:08
  • You can demonstrate that by adding a CALL in the COBOL program to show the value of the COBSW environment-variable. If it is as I posit, then the UPSI switches will be saying one thing (which they are) and the COBSW telling you another (which your printf when uncommented does). – Bill Woodger Aug 24 '15 at 10:09

1 Answers1

1

The COBOL runtime switches are read once from the environment variable COBSW or the command line during process initialization.

So unfortunately setting COBSW will not work because the runtime has already read COBSW.

All is not lost because you can use the X"91" function 11 API from COBOL to set the switches.

Stephen Gennard
  • 1,910
  • 16
  • 21
  • 1
    So what's the point in Micro Focus supplying `cobrescanenv()`? – Bill Woodger Sep 02 '15 at 08:14
  • 1
    cobrescanenv picks up changes of DD_ environment variables, user set environment variables and entry-point mapping environment but not unfortunately COBSW. I would imagine it could but it doesn't. – Stephen Gennard Sep 02 '15 at 09:10
  • OK. In the example, the cobputenv is before the coboinit. According to the OP, cobgetenv shows the set/put with the expected value. OP did say the COBOL program still runs if cobinit is omitted. Any idea how the run-time environment is established? – Bill Woodger Sep 02 '15 at 09:37
  • 1
    The program is compiled with "cob" which ensures the Micro Focus COBOL runtime's environment is setup, so cobinit() in this case will do very little as the environment has already been setup. The cobputenv() is being honour but the runtime is not noticing that COBSW has changed to re-parse it to set the COBOL switches. Hence I mention the x"91" fn 11 API. – Stephen Gennard Sep 02 '15 at 09:59
  • Thanks. There must be some point in cobinit though. The init is presumably only for the "main" program. So, I assume the compile could be done as a dynamically-loadable subprogram, so the cobiinit would be needed? – Bill Woodger Sep 02 '15 at 10:35
  • 1
    cobinit() is useful in a statically linked environment. Micro Focus provides a "self-contained" shared object that initialised the runtime when the shared object itself is loaded, this does not require cobinit(). – Stephen Gennard Sep 02 '15 at 12:08
  • 1
    Thanks. Satisfies me. Can you update your answer with these things, please? So it was an application of "things" from various Micro Focus documentation which just aren't going to cooperate with each other, I guess :-) – Bill Woodger Sep 02 '15 at 12:21