KICKS

A transaction processing system for CMS & TSO

KICKS KooKbooK recipe

Designing and implementing simple KICKS transactions using C

In KooKbooK recipe #1 you saw how to prepare, generate and use simple KICKS BMS maps, and in KooKbooK recipe #2 you saw how to use such maps in the design and implementation of a simple COBOL programs. In this recipe you will build on that to start designing, compiling and using similar KICKS transactions using C programs. This recipe will highlight differences, but won't go into the depth of explanation that recipe #1 and #2 did, so read those first!

KooKbooK recipe #1 discussed most of the relevant options for defining mapsets, maps, and fields. As you may imagine, binary maps are binary maps, makes no difference what programming language is being used to send them. However symbolic maps (aka dsects) are language specific - the need to generate them for the correct language is why there is a LANG= parameter for DFHMSD. The KICKS map generator proc/exec always generates both COBOL and C symbolic maps into the appropriate copy libraries.

When generating symbolic maps for C programs two additional parameters of DFHMSD become significant.

If a mapset contains several maps, the symbolic maps are defined so that they overlay one another. Thus you can't use them at the same time. This is often OK, especially if you will only use one of the set based on terminal type. But if you need to use them at the same time (for example based on the data) you can cause them to be allocated in separate space by specifying STORAGE=AUTO in the DFHMSD.

In COBOL most mapsets are defined without STORAGE=AUTO because doing so saves space. Our previous definition of TESTMAP in recipe #2 omitted STORAGE=AUTO for this reason.

In C, STORAGE=AUTO has the additional effect of defining the map as automatic storage (storage that KICKS allocates); the absence of STORAGE=AUTO causes the compiler to generate a (null) pointer (BMS assigns the name BMSMAPBR) instead of allocating the storage area. Most mapsets used with C programs are defined with STORAGE=AUTO because it simplifies map storage allocation Note this is not a problem when using the maps with COBOL, it just makes those COBOL programs somewhat bigger. The following C code in this recipe assumes STORAGE=AUTO has been added to the TESTMAP definition of recipe #2.

The other DFHMSD parameter of interest to C programmers is FOLD= (UPPER or LOWER, default=LOWER). The default, FOLD=LOWER, causes symbolic maps for C to be generated with lower case names. The following C code in this recipe assumes FOLD has been omitted, or specified as FOLD=LOWER

As in KooKbooK recipe #2, the program model is the KICKS startup transaction with the large color letters. You know how this works: press any key except clear and the colors of the letters change; but press clear and the transaction is gone and you are at a blank screen ready to enter your next transaction.

Let's start with a very simple program to send the map. On the Left is the COBOL program from the earlier recipe, on the Right the corresponding C program.

ID DIVISION.
PROGRAM-ID. TESTCOB.

DATA DIVISION.
WORKING-STORAGE SECTION.

COPY TESTMSD.

PROCEDURE DIVISION.

 EXEC CICS SEND
  MAP('TESTMAP') MAPSET('TESTMSD') ERASE
 END-EXEC.

 EXEC CICS RETURN END-EXEC.

 







#include "testmsd.h"

int main(KIKEIB *eib) {

 EXEC CICS SEND
  MAP("testmap") MAPSET("testmsd") ERASE
 ;

 EXEC CICS RETURN;

}

A few things to observe:

The JCL to compile the programs is also very similar; in TSO

//PROGRAM JOB
// EXEC K2KCOBCL (or KIKCB2CL)
//COPY.SYSUT1 DD *
** COBOL source as above **
/*
//LKED.SYSIN DD *
INCLUDE SKIKLOAD(KIKCOBGL)
ENTRY TESTCOB
NAME TESTCOB(R)
/*
 
//PROGRAM JOB REGION=5000K
// EXEC KIKGCCCL
//COPY.SYSUT1 DD *
** C source as above **
/*
//LKED.SYSIN DD *
INCLUDE SKIKLOAD(KIKGCCGL)
ENTRY @@KSTRT
NAME TESTCOB(R)
/*

or in CMS, compiling the above programs saved as TESTCOB COBOL & TESTCOB C

EXEC K2KCOBCL TESTCOB COBOL EXEC KIKGCCCL TESTCOB C

Where a large region is used for the GCCMVS compiler, the KIKGCCCL (instead of K2KCOBCL) proc/exec is used to compile, the KIKGCCGL glue routine (instead of KIKCOBGL) is included in the LKED step, and @@KSTRT is used instead of the PROGRAM-ID as the entry point.

When it comes to KICKS table entries you'll find the two programs are the same! In both cases the required PPT and PCT entries are

KIKPPT TYPE=ENTRY,PROGRAM=TESTMSD,USAGE=MAP
KIKPPT TYPE=ENTRY,PROGRAM=TESTCOB,PGMLANG=CMDLVL
and
KIKPCT TYPE=ENTRY,TRANSID=TCOB,PROGRAM=TESTCOB

Typing ‘TCOB’ to run this gives the expected result – the bare map is displayed with none of the fields filled and with the block letters in default color (same color as the rest of the text on the screen). And as before you get an APCT abend as soon as you press enter.

The earlier KooKbooK recipex showed how to 'fix' the APCT abend using a conversational approach, like this

ID DIVISION.
PROGRAM-ID. TESTCOB.

DATA DIVISION.
WORKING-STORAGE SECTION.
COPY TESTMSD.
COPY DFHAID.

PROCEDURE DIVISION.

RESEND-IT.

 EXEC CICS SEND
  MAP('TESTMAP') MAPSET('TESTMSD') ERASE
 END-EXEC.

 EXEC CICS RECEIVE
  MAP('TESTMAP') MAPSET('TESTMSD') NOHANDLE
 END-EXEC.

 IF EIBAID NOT = DFHCLEAR GO TO RESEND-IT.

 EXEC CICS RETURN END-EXEC.
 





#include "testmsd.h"
#include "dfhaid.h"

int main(KIKEIB *eib) {

do {

  EXEC CICS SEND
   MAP("testmap") MAPSET("testmsd") ERASE
  ;

  EXEC CICS RECEIVE
   MAP("testmap") MAPSET("testmsd") NOHANDLE
  ;
} while (eib->eibaid != DFHCLEAR);

 EXEC CICS RETURN;

}

and a pseudo-conversational approach, like this

...

PROCEDURE DIVISION.

 IF EIBCALEN NOT = 0
  EXEC CICS RECEIVE
   MAP('TESTMAP') MAPSET('TESTMSD') NOHANDLE
  END-EXEC
  IF EIBAID = DFHCLEAR
   EXEC CICS RETURN END-EXEC.

 EXEC CICS SEND
  MAP('TESTMAP') MAPSET('TESTMSD') ERASE
 END- EXEC.

 EXEC CICS RETURN
  TRANSID(EIBTRNID) COMMAREA(MAPA01O)
 END-EXEC.

...

int main(KIKEIB *eib) {
 
 if (eib->eibcalen != 0) {
  EXEC CICS RECEIVE
   MAP("testmap") MAPSET("testmsd") NOHANDLE
  ;
  if (eib->eibaid == DFHCLEAR)
   EXEC CICS RETURN ;
  }

 EXEC CICS SEND
  MAP("testmap") MAPSET("testmsd") ERASE
 ;

 EXEC CICS RETURN
  TRANSID(eib->eibtrnid) COMMAREA(testmap.mapa01o)
 ;
 

Recoding the whole KSGM transaction in C wouldn't show us much new, so that's left as an exercise!


Copyright © Mike Noel, 2015; last updated 2/3/2015 for KICKS 1.5.0