Skip to content

Instantly share code, notes, and snippets.

@mainframed
Last active May 3, 2024 13:38
Show Gist options
  • Save mainframed/a8e94ec1e2d791eaf96d9aac981e2c10 to your computer and use it in GitHub Desktop.
Save mainframed/a8e94ec1e2d791eaf96d9aac981e2c10 to your computer and use it in GitHub Desktop.

Simple (LOL) CICS DOGE "Good Morning" screen (i.e. overly complicated hello world)

CICS is like this mystery wrapped in an enigma wrapped in a riddle. Sure you've heard about it, your company might even rely on it day to day for some really important transactions. But if you wanted to quickly learn how to write and deploy a CICS transaction (or application) its basically impossible. Sure you could grab the Murach book, which is great, but its not a 101 level tutorial, they don't even comment about how to use CEDA to install your cics program and mention compiling COBOL and assembling maps in passing.

Throughout this writeup I'm going to refer to CICS like a web server. Yes, i know its the proto-webserver. I don't care, its the roaring 20's. With that in mind, some quick terminology:

  • Transaction: 4 characters long, think of this like a URL. We'll use DOGE as our transaction.
  • Region: This is like "servers". Imagine you had 3 tomcat servers running on different ports, same deal here, except we call them regions and they have different application IDs (yay SNA).

So we'll start real simple, you need a few things:

  1. Resource Pool - You know how when you define webservers you tell it paths it can use for root. This is essentially the same thing. This is probably the thing I struggled with the most. You'll see later how to define a a program to CICS and I always wondered "hey, why arent we defining actual datasets here? All we specify are members, what is going on?" Well, wonder no more, CICS, like almost everything on a mainframe is started with a job. In the job is the "option" DFHRPL. This option specifies all the datasets CICS will look in for programs (this, bee tee dubs is called 'dataset concatenation'). Think of it like a $PATH for CICS. I've modified my startup JCL and added USER.CICSLOAD to DFHRPL, you can find the job in SDSF typically. IMPORTANT When you create your 'load library' make sure you define it as a LIBRARY not a PDS or CICS won't be able to load it.

  2. A Map - Sometimes referred to BMS or Mapset. This is assembler using a bunch of macros to make a nice looking screen in TN3270. Trust me its super fun and way better than manually writting TN3270 in hlasm. The code below is our DOGE ascii art example map (thanks /u/cmang on reddit https://www.reddit.com/r/doge/comments/21viok/such_textmode_very_ascii/):

* HLASM BMS Map
CHKACCSS TITLE 'Dogecoin BMS'
         PRINT NOGEN
DOGECN   DFHMSD TYPE=&SYSPARM,  * Either DESCT or MAP                  X
               MODE=OUT,       * One of IN/OUT/INOUT                   X
               LANG=COBOL,                                             X
               MAPATTS=(COLOR,HILIGHT),                                X
               TIOAPFX=YES,                                            X
               CTRL=FREEKB     * Free the keyboard
* Below is the MAP name, you use this in COBOL to reference the MAP
* You could have more than one map, hence size/line/column
DOGECN1  DFHMDI SIZE=(24,80),   * How big is the screen                X
               LINE=1,         * Where do we start this map            X
               COLUMN=1
*.~'~.~'~.~'~.~'~.~'~.~'~.~'~.~'~.~'~.~'~.
* Good resource
* https://www.ibm.com/support/knowledgecenter/SSGMCP_5.2.0/com.ibm.cics
*   .ts.applicationprogramming.doc/topics/dfhp473.html
* Colors: [DEFAULT], BLUE, RED, PINK, GREEN,
*         TURQUOISE, YELLOW, NEUTRAL (white)
* DOGECICS
*                               Y.                      _
*                               YiL                   .```.
*                               Yii;      WOW       .; .;;`.
*                 MUCH COIN     YY;ii._           .;`.;;;; :
*                               iiYYYYYYiiiii;;;;i` ;;::;;;;
*                           _.;YYYYYYiiiiiiYYYii  .;;.   ;;;
*                        .YYYYYYYYYYiiYYYYYYYYYYYYii;`  ;;;;
*                      .YYYYYYY$$YYiiYY$$$$iiiYYYYYY;.ii;`..
*                     :YYY$!.  TYiiYY$$$$$YYYYYYYiiYYYYiYYii.
*                     Y$MM$:   :YYYYYY$!"``"4YYYYYiiiYYYYiiYY.
*                  `. :MM$$b.,dYY$$Yii" :`   :YYYYllYiiYYYiYY
*               _.._ :`4MM$!YYYYYYYYYii,.__.diii$$YYYYYYYYYYY
*               .,._ $b`P`     "4$$$$$iiiiiiii$$$$YY$$$$$$YiY;
*                  `,.`$:       :$$$$$$$$$YYYYY$$$$$$$$$YYiiYYL
*                   "`:$$.    .;PPb$~.,.``T$$YY$$$$YYYYYYiiiYYU:
*                 ` ;$P$;;: ;;;;i$y$"!Y$$$b;$$$Y$YY$$YYYiiiYYiYY
*                   $Fi$$ .. ``:iii.`-";YYYYY$$YY$$$$$YYYiiYiYYY
*                   :Y$$rb ````  `_..;;i;YYY$YY$$$$$$$YYYYYYYiYY:
*                    :$$$$$i;;iiiiidYYYYYYYYYY$$$$$$YYYYYYYiiYYYY.
*                     `$$$$$$$YYYYYYYYYYYYY$$$$$$YYYYYYYYiiiYYYYYY
*                     .i!$$$$$$YYYYYYYYY$$$$$$YYY$$YYiiiiiiYYYYYYY
*                    :YYiii$$$$$$$YYYYYYY$$$$YY$$$$YYiiiiiYYYYYYi`
         DFHMDF POS=(1,1),      * Where to put the text                X
               LENGTH=8,                                               X
               COLOR=BLUE,                                             X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='DOGECICS'
*
         DFHMDF POS=(2,31),      * Where to put the text               X
               LENGTH=25,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='Y.                      _'
*
         DFHMDF POS=(3,31),      * Where to put the text               X
               LENGTH=27,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='YiL                   .```.'
*
         DFHMDF POS=(4,31),      * Where to put the text               X
               LENGTH=28,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='Yii;      WOW       .; .;;`.'
*
         DFHMDF POS=(5,17),      * Where to put the text               X
               LENGTH=42,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='MUCH COIN     YY;ii._           .;`.;;;; :'
*
         DFHMDF POS=(6,31),      * Where to put the text               X
               LENGTH=28,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='iiYYYYYYiiiii;;;;i` ;;::;;;;'
*
         DFHMDF POS=(7,27),      * Where to put the text               X
               LENGTH=32,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='_.;YYYYYYiiiiiiYYYii  .;;.   ;;;'
*
         DFHMDF POS=(8,24),      * Where to put the text               X
               LENGTH=35,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='.YYYYYYYYYYiiYYYYYYYYYYYYii;`  ;;;;'
*
         DFHMDF POS=(9,22),      * Where to put the text               X
               LENGTH=37,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='.YYYYYYY$$YYiiYY$$$$iiiYYYYYY;.ii;`..'
*
         DFHMDF POS=(10,21),      * Where to put the text              X
               LENGTH=39,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL=':YYY$!.  TYiiYY$$$$$YYYYYYYiiYYYYiYYii.'
*
         DFHMDF POS=(11,21),      * Where to put the text              X
               LENGTH=40,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='Y$MM$:   :YYYYYY$!"``"4YYYYYiiiYYYYiiYY.'
*
         DFHMDF POS=(12,18),      * Where to put the text              X
               LENGTH=42,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='`. :MM$$b.,dYY$$Yii" :`   :YYYYllYiiYYYiYY'
*
         DFHMDF POS=(13,15),      * Where to put the text              X
               LENGTH=45,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='_.._ :`4MM$!YYYYYYYYYii,.__.diii$$YYYYYYYYYYY'
*
         DFHMDF POS=(14,15),      * Where to put the text              X
               LENGTH=46,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='.,._ $b`P`     "4$$$$$iiiiiiii$$$$YY$$$$$$YiY;'
*
         DFHMDF POS=(15,18),      * Where to put the text              X
               LENGTH=44,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='`,.`$:       :$$$$$$$$$YYYYY$$$$$$$$$YYiiYYL'
*
         DFHMDF POS=(16,19),      * Where to put the text              X
               LENGTH=44,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='"`:$$.    .;PPb$~.,.``T$$YY$$$$YYYYYYiiiYYU:'
*
         DFHMDF POS=(17,17),      * Where to put the text              X
               LENGTH=46,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='` ;$P$;;: ;;;;i$y$"!Y$$$b;$$$Y$YY$$YYYiiiYYiYY'
*
         DFHMDF POS=(18,19),      * Where to put the text              X
               LENGTH=44,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='$Fi$$ .. ``:iii.`-";YYYYY$$YY$$$$$YYYiiYiYYY'
*
         DFHMDF POS=(19,19),      * Where to put the text              X
               LENGTH=45,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL=':Y$$rb ````  `_..;;i;YYY$YY$$$$$$$YYYYYYYiYY:'
*
         DFHMDF POS=(20,20),      * Where to put the text              X
               LENGTH=45,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL=':$$$$$i;;iiiiidYYYYYYYYYY$$$$$$YYYYYYYiiYYYY.'
*
         DFHMDF POS=(21,21),      * Where to put the text              X
               LENGTH=44,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='`$$$$$$$YYYYYYYYYYYYY$$$$$$YYYYYYYYiiiYYYYYY'
*
         DFHMDF POS=(22,21),      * Where to put the text              X
               LENGTH=44,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL='.i!$$$$$$YYYYYYYYY$$$$$$YYY$$YYiiiiiiYYYYYYY'
*
         DFHMDF POS=(23,20),      * Where to put the text              X
               LENGTH=45,                                              X
               COLOR=YELLOW,                                           X
               ATTRB=(NORM,PROT),                                      X
               INITIAL=':YYiii$$$$$$$YYYYYYY$$$$YY$$$$YYiiiiiYYYYYYi`'
*
         DFHMSD TYPE=FINAL
         END

Imagine having to make that yourself, there's some dirty python to make the DFHMDF macro calls with a given ascii art in the bonus section below.

To assemble this HLASM we need JCL. Thankfully CICS comes with a procedure called DFHMAPS. On ADCD (zPDT) systems this is typically in DFH###.CICS.SDFHPROC(DFHMAPS) where ### is your CICS version (for example 5.2 would be DFH520.CICS.SDFHPROC).

//COBCOMP  JOB 'Compile COBOL',NOTIFY=&SYSUID
//IBMLIB   JCLLIB ORDER=DFH520.CICS.SDFHPROC
//* make sure that the MAPLIB is pointed
//* to your CICS loadlib. If you are not sure about this
//* you can go to The JESJCL of the job for your CICS
//* region in Spool and check for DFHRPL dd statement.
//CPLSTP   EXEC DFHMAPS,MAPLIB='USER.CICSLOAD',
//         INDEX='DFH520.CICS',
//         DSCTLIB='DOGE.CICS',
//         MAPNAME='DOGEGM'
//* MAPLIB is where the compiled CICS BMS MAP is stored!
//* The DD below is the source of the program to assemble!
//COPY.SYSUT1  DD DSN=DOGE.CICS(DOGEGMSC),DISP=SHR

Some quick explanation here:

  • JCLLIB: Thats the PDS where DFHMAPS is stored, this tells JES where to look
  • MAPLIB: Where we want our compiled code to go
  • INDEX: Where CICS libraries and stuff can be found
  • DSCTLIB: Where to put the data definitions we'll use in COBOL to refer to the map (e.g. COPY)
  • MAPNAME: The filename of both the DSECT and assembled binary
  1. COBOL - Your actual COBOL program that does something (doesn't need to be COBOL, could be C, JAVA, PL/I, HLASM). Here's a quick example that loads our map:
       IDENTIFICATION DIVISION.
       PROGRAM-ID.   DOGE01.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       COPY DOGEGM.

       PROCEDURE DIVISION.
       00000-MAIN.

           EXEC CICS
                SEND MAP('DOGECN1')
                     MAPSET('DOGEGM')
                     ERASE
           END-EXEC.

           EXEC CICS RETURN END-EXEC.

       00000-EXIT.
           GOBACK.

Of note, MAPSET must match what you set MAPNAME to when you assembled the map.

And of course you know you'll need JCL, same as above we use DFHYITVL instead of DFHMAPS.

//COBCOMP  JOB 'Compile COBOL',NOTIFY=&SYSUID
//IBMLIB   JCLLIB ORDER=DFH520.CICS.SDFHPROC
//* make sure that the PROGLIB in the DFHYITVL is pointed
//* to your CICS loadlib. If you are not sure about this
//* you can go to The JESJCL of the job for your CICS
//* region in Spool and check for DFHRPL dd statement.
//CPLSTP   EXEC DFHYITVL,PROGLIB='USER.CICSLOAD',
//         INDEX='DFH520.CICS',
//         DSCTLIB='USER.CICSLOAD',
//         AD370HLQ='IGY520',
//         LE370HLQ='CEE'
//* PROGLIB is where the compiled CICS program is stored!
//* The DD below is the source of the program to compile!
//TRN.SYSIN  DD DSN=DOGE.CICS(HLWRLDMP),DISP=SHR
//* The DD below is where COBOL COPY files are stored
//* COPY in COBOL is like IMPORT in python
//* So this tells the compiler where to find them
//COB.SYSLIB DD
//           DD DSN=DOGE.CICS,DISP=SHR
//* In PROGLIB there could be a member called DOGE
//* The (R) means 'replace' if the member already exists
//LKED.SYSIN DD *
   NAME DOGE(R)
//

Some quick explanation here:

  • JCLLIB: Thats the PDS where DFHYITVL is stored, this tells JES where to look
  • PROGLIB: Where we want our compiled code to go
  • INDEX: Where CICS libraries and stuff can be found
  • AD370HLQ: The HLQ to find your COBOL compiler
  • LE370HLQ: The HLQ to find the common environment libraries

Installing our code in CICS

With that all done you now need to install it in CICS.

To "install" a cics program think of again it like a web server.

We need a transaction (like a url) to connect the terminal to. That transaction needs to have some kind of program behind it (think like php). We also need a map file (this would be like an html template).

Now, cics isn't as smart as a modern webserver and doesn't know about files or things like that. It keeps everything in 'tables'. So we DEFINE a program using CEDA. We add it to a group. A group is like a folder for this application, so everything we want should go in one group.

CEDA DEFINE PROG(DOGE) GROUP(DOGECOIN)

Next, we need to link the transaction to the program, CICS now knows there's a compiled exec called 'DOGE' in a dataset defined by DFHRPL (this is a section in the CICS job that is running, you can look it up in SDSF under JESJCL for that CICS regions job). In our example we've added USER.CICSLOAD to DFHRPL. Which means there's a file called 'DOGE' in USER.CICSLOAD: USER.CICSLOAD(DOGE) is the program we just defined. Think of DFHRPL like the path in a web server setup.

Next we need to tell CICS how to find our 3270 template. This is the assembled HLASM program from above. It's the same command as above:

CEDA DEFINE MAPSET(DOGEGM) GROUP(DOGECOIN)

You just need to make sure that the MAPSET, the file and the COPY in your COBOL is the same. So here we have a cobol program with a copy statement that says COPY DOGEGM., this copies the data definitions for our map in COBOL, we also have the statement MAPSET(DOGEGM) in COBOL which means 'there's a mapset in CICS defined with a name of DOGEGM use that', we have a file USER.CICSLOAD(DOGEGM) and we have the CEDA above with MAPSET(DOGEGM). Easy peasy.

With those defined we now need to define a transaction that will use the program USER.CICSLOAD(DOGE) when we call it in CICS.

CEDA DEFINE TRANSACTION(DOGE) GROUP(DOGECOIN) PROGRAM(DOGE)

I like to think of groups like folders. In the DOGECOIN group we have the following:

Group: DOGECOIN:  
    Transaction: DOGE  
        Program: DOGE
        Mapset: DOGEGM

If this were a web server I would break it down like:

/DOGEGOIN/DOGE <---- redirects to DOGE.php  
/DOGECOIN/DOGE.php  
/DOGECOIN/DOGEGM.html  

Except, this is all just setup, like staging. We have a group with a program, transaction and map, but we haven't enabled them. Do do that we can install the whole group:

CEDA INSTALL GROUP(DOGECOIN)

At this point you can hit F3 and type DOGE to access your transaction!

Making Changes

All of this only works for the first time you compile a program and install it. What if, after CICS is booted you need to incorporate your changes after recompiling the map or COBOL? Why you can use CEMT:

CEMT SET PROGRAM(DOGE) NEWCOPY

Long story short, CICS keeps a copy of the program in memory, so you need to tell it to reload the code from disc, which is what the CEMT command is telling CICS to do. It's sorta like clearing the server cache and forcing it to get a new copy from disk.

But what if you change the mapset? You'd think CEMT would have a command like SET MAPSET(DOGEGM) NEWCOPY but lol nope, it treats your MAPSET like a program, so if you make changes to a mapset all you need to do is:

CEMT SET PROGRAM(DOGEGM) NEWCOPY

There's a lot more to writting CICS programs but this should be enough to get you started!

BONUS

Python code to convert ascii art to CICS macro calls:

#!/usr/bin/env python3

# -------1---------2---------3---------4---------5---------6---------7---------8

doge = '''DOGECICS
                              Y.                      _
                              YiL                   .```.
                              Yii;      WOW       .; .;;`.
                MUCH COIN     YY;ii._           .;`.;;;; :
                              iiYYYYYYiiiii;;;;i` ;;::;;;;
                          _.;YYYYYYiiiiiiYYYii  .;;.   ;;;
                       .YYYYYYYYYYiiYYYYYYYYYYYYii;`  ;;;;
                     .YYYYYYY$$YYiiYY$$$$iiiYYYYYY;.ii;`..
                    :YYY$!.  TYiiYY$$$$$YYYYYYYiiYYYYiYYii.
                    Y$MM$:   :YYYYYY$!"``"4YYYYYiiiYYYYiiYY.
                 `. :MM$$b.,dYY$$Yii" :`   :YYYYllYiiYYYiYY
              _.._ :`4MM$!YYYYYYYYYii,.__.diii$$YYYYYYYYYYY
              .,._ $b`P`     "4$$$$$iiiiiiii$$$$YY$$$$$$YiY;
                 `,.`$:       :$$$$$$$$$YYYYY$$$$$$$$$YYiiYYL
                  "`:$$.    .;PPb$~.,.``T$$YY$$$$YYYYYYiiiYYU:
                ` ;$P$;;: ;;;;i$y$"!Y$$$b;$$$Y$YY$$YYYiiiYYiYY
                  $Fi$$ .. ``:iii.`-";YYYYY$$YY$$$$$YYYiiYiYYY
                  :Y$$rb ````  `_..;;i;YYY$YY$$$$$$$YYYYYYYiYY:
                   :$$$$$i;;iiiiidYYYYYYYYYY$$$$$$YYYYYYYiiYYYY.
                    `$$$$$$$YYYYYYYYYYYYY$$$$$$YYYYYYYYiiiYYYYYY
                    .i!$$$$$$YYYYYYYYY$$$$$$YYY$$YYiiiiiiYYYYYYY
                   :YYiii$$$$$$$YYYYYYY$$$$YY$$$$YYiiiiiYYYYYYi`
'''


hlasm = '''
         DFHMDF POS=({row},{column}),      * Where to put the text             X
               LENGTH={len},                                             X
               COLOR=YELLOW,                                          X
               ATTRB=(NORM,PROT),                                     X
               INITIAL='{text}'
*'''


for i in doge.splitlines():
    print("* {}".format(i))

row = 1
max_len = 46
for line in doge.splitlines():
    column1 = len(line) - len(line.lstrip()) + 1
    f_row = format(row, '02d')
    f_col = format(column1, '02d')
    text = line[column1-1:]
    f_len = format(len(text), '02d')
    if len(text) > 46:
        print("RUH ROH")
        print("MANUAL INTERVENTION REQUIRED FOR ROW {} COLUMN {}".format(f_row, f_col))
        print(text)
    else:
        temp = list(hlasm.format(row=f_row,column=f_col,len=f_len,text=text))
        new_hlasm = "".join(temp)
        print(new_hlasm)
    row = row + 1
@DougieLawson
Copy link

I've made the continuation char in col 71 code work better. The CICS macros allow for leading zeros.

--- cicsdoge.py~        2020-06-27 19:51:22.952883000 +0000
+++ cicsdoge.py 2020-06-27 19:53:36.462883000 +0000
@@ -28,10 +28,11 @@
 '''


-hlasm = '''         DFHMDF POS=({row},{column}),      * Where to put the text
-               LENGTH={len},
-               COLOR=YELLOW,                                           X
-               ATTRB=(NORM,PROT),                                      X
+hlasm = '''
+         DFHMDF POS=({row},{column}),      * Where to put the text             X
+               LENGTH={len},                                             X
+               COLOR=YELLOW,                                          X
+               ATTRB=(NORM,PROT),                                     X
                INITIAL='{text}'
 *'''

@@ -43,18 +44,16 @@
 max_len = 46
 for line in doge.splitlines():
     column1 = len(line) - len(line.lstrip()) + 1
+    f_row = format(row, '02d')
+    f_col = format(column1, '02d')
     text = line[column1-1:]
+    f_len = format(len(text), '02d')
     if len(text) > 46:
         print("RUH ROH")
-        print("MANUAL INTERVENTION REQUIRED FOR ROW {} COLUMN {}".format(row, column1))
+        print("MANUAL INTERVENTION REQUIRED FOR ROW {} COLUMN {}".format(f_row, f_col))
         print(text)
     else:
-        temp = list(hlasm.format(row=row,column=column1,len=len(text),text=text))
-        temp[71] = "X"
-        if row > 9:
-            temp[146] = "X"
-        else:
-            temp[145] = "X"
+        temp = list(hlasm.format(row=f_row,column=f_col,len=f_len,text=text))
         new_hlasm = "".join(temp)
         print(new_hlasm)
     row = row + 1

I'll fire up an IMS system and make you an IMS MFS version when I get a chance. You must know that IMS is that better transaction manager that's not CICS. It the one that comes with the happy friendly DL/I database.

@mainframed
Copy link
Author

mainframed commented Jun 27, 2020

Hell yeah I'll take a similar IMS writeup!

Also, I didn't know you could use leading zeros thanks for the patch! I've applied it to the above.

@DougieLawson
Copy link

Here's v0.0.1 of the IMS MFS generator (not tested on a real IMS system yet).

#!/usr/bin/python3

doge = '''                              Y.                      _
                              YiL                   .```.
                              Yii;      WOW       .; .;;`.
                MUCH COIN     YY;ii._           .;`.;;;; :
                              iiYYYYYYiiiii;;;;i` ;;::;;;;
                          _.;YYYYYYiiiiiiYYYii  .;;.   ;;;
                       .YYYYYYYYYYiiYYYYYYYYYYYYii;`  ;;;;
                     .YYYYYYY$$YYiiYY$$$$iiiYYYYYY;.ii;`..
                    :YYY$!.  TYiiYY$$$$$YYYYYYYiiYYYYiYYii.
                    Y$MM$:   :YYYYYY$!"``"4YYYYYiiiYYYYiiYY.
                 `. :MM$$b.,dYY$$Yii" :`   :YYYYllYiiYYYiYY
              _.._ :`4MM$!YYYYYYYYYii,.__.diii$$YYYYYYYYYYY
              .,._ $b`P`     "4$$$$$iiiiiiii$$$$YY$$$$$$YiY;
                 `,.`$:       :$$$$$$$$$YYYYY$$$$$$$$$YYiiYYL
                  "`:$$.    .;PPb$~.,.``T$$YY$$$$YYYYYYiiiYYU:
                ` ;$P$;;: ;;;;i$y$"!Y$$$b;$$$Y$YY$$YYYiiiYYiYY
                  $Fi$$ .. ``:iii.`-";YYYYY$$YY$$$$$YYYiiYiYYY
                  :Y$$rb ````  `_..;;i;YYY$YY$$$$$$$YYYYYYYiYY:
                   :$$$$$i;;iiiiidYYYYYYYYYY$$$$$$YYYYYYYiiYYYY.
                    `$$$$$$$YYYYYYYYYYYYY$$$$$$YYYYYYYYiiiYYYYYY
                    .i!$$$$$$YYYYYYYYY$$$$$$YYY$$YYiiiiiiYYYYYYY
                   :YYiii$$$$$$$YYYYYYY$$$$YY$$$$YYiiiiiYYYYYYi`
'''
imsFMT1 = '''         ALPHA 'abcdefghijklmnopqrstuvwxyz`\_'
DOGE     FMT
         DEV TYPE=3270-A02,FEAT=IGNORE,SYSMSG=SYSMSG
         STACK ON
         DIV TYPE=INOUT
'''
imsFMT2 = '''SYSMSG   DFLD  LTH=79,POS=(24,2)
         STACK OFF
         DEV TYPE=3270-A03,FEAT=IGNORE,SYSMSG=SYSMSG
         UNSTACK ,KEEP
         DEV TYPE=3270-A04,FEAT=IGNORE,SYSMSG=SYSMSG
         UNSTACK ,KEEP
         DEV TYPE=3270-A05,FEAT=IGNORE,SYSMSG=SYSMSG
         UNSTACK ,KEEP
         DEV TYPE=(3270,2),FEAT=IGNORE,SYSMSG=SYSMSG
         UNSTACK ,KEEP
         DEV TYPE=3270-A03,FEAT=(PFK,CARD,PEN),SYSMSG=SYSMSG
         UNSTACK ,KEEP
         DEV TYPE=3270-A04,FEAT=(PFK,CARD,PEN),SYSMSG=SYSMSG
         UNSTACK ,KEEP
         DEV TYPE=3270-A05,FEAT=(PFK,CARD,PEN),SYSMSG=SYSMSG
         UNSTACK ,KEEP
         DEV TYPE=(3270,2),FEAT=(PFK,CARD,PEN),SYSMSG=SYSMSG
         UNSTACK ,DELETE
         FMTEND
DOGEMSI  MSG   TYPE=INPUT,SOR=DOGE,NXT=DOGEMSO
         SEG
         MFLD  'DOGE '
         MFLD SYSMSG,LTH=79
         MSGEND
DOGEMSO  MSG   TYPE=OUTPUT,SOR=DOGE,NXT=DOGEMSI
         SEG
         MFLD SYSMSG,LTH=79
         MSGEND
         END
'''
DFLD = "DFLD"
QUOTE = "'"
POS  = "POS=({},{}),"
CONT = "X"
LTH  = "LTH={}"

for line in imsFMT1.splitlines():
    print (line)

row = 1
column = 1

for line in doge.splitlines():
    length = len(line)
    row += 1
    f_row = format(row, '02d')
    f_column = format(column, '02d')
    rc_POS = POS.format(f_row, f_column)
    len_LTH = LTH.format(length)
    outLine = DFLD.rjust(13, ' ')+" "+QUOTE+line+QUOTE+","+rc_POS+len_LTH
    if len(outLine) > 71:
        print (outLine[:71]+CONT)
        contLine = outLine[71:]
        contLen = len(contLine)
        print (contLine.rjust(15+contLen, ' '))
    else:
        print (outLine)

for line in imsFMT2.splitlines():
    print (line)

And a COBOL IMS transaction program (we're talking extremely ugly code here)

000100 CBL QUOTE NUMPROC(NOPFD)
000200 TITLE "DOGE MESSAGE PROCESSING PROGRAM"
000300 IDENTIFICATION DIVISION.
000400   PROGRAM-ID. DOGEPGM.
000500 ENVIRONMENT DIVISION.
000600 DATA DIVISION.
000700 WORKING-STORAGE SECTION.
000800   01 AIB.
000900      05 AIBID PIC X(8) VALUE "DFSAIB  ".
001000      05 LEN PIC S9(8) COMP VALUE +128.
001100      05 SUB-FUNCTION PIC X(8).
001200      05 PCB-NAME PIC X(8).
001300      05 FILLER PIC X(8).
001400      05 FILLER PIC X(8).
001500      05 IOAREA-LENGTH PIC S9(8) COMP VALUE +160.
001600      05 IOAREA-USED PIC 9(9) COMP.
001700      05 FILLER PIC X(8).
001800      05 FILLER PIC X(2).
001900      05 FILLER PIC X(2).
002000      05 CALL-RETURN-CODE PIC 9(9) COMP.
002100      05 REASON-CODE PIC 9(9) COMP.
002200      05 FILLER PIC X(4).
002300      05 RSA1-PTR POINTER.
002400      05 RSA2-PTR POINTER.
002500      05 RSA3-PTR POINTER.
002600      05 FILLER PIC X(40).
002700   77 GU   PIC X(4) VALUE "GU  ".
002800   77 ISRT PIC X(4) VALUE "ISRT".
002900   77 FORMAT-OUT PIC X(8) VALUE SPACES.
003000   01 SWITCHES.
003100      02 END-SWITCH PIC X.
003200      88 DO-MORE VALUE "0".
003300      88 NO-MORE VALUE "1".
003400   01 MESSAGE-1.
003500      05 LL     PIC S9(3) COMP VALUE +79 .
003600      05 ZZ     PIC S9(3) COMP VALUE +0.
003700      05 I-MSG  PIC X(22).
003800   01 INPUT-MSG.
003900      05 IN-LL PIC S9(3) COMP.
004000      05 IN-ZZ PIC S9(3) COMP.
004050      05 IN-TRAN PIC X(5).
004100      05 IN-TEXT PIC X(22).
004200      05 FILLER PIC X(85).
004300 LINKAGE SECTION.
004400   01 IO-PCB.
004500      05 IO-PCB-LTERM PIC X(8).
004600      05 FILLER PIC X(2).
004700      05 IO-PCB-STATUS PIC X(2).
004800      05 IO-PCB-DATE PIC S9(7) COMP-3.
004900      05 IO-PCB-TIME PIC S9(7) COMP-3.
005000      05 IO-PCB-SEQ PIC X(4).
005100      05 IO-PCB-MODNAME PIC X(8).
005200      05 IO-PCB-USERID PIC X(8).
005300      05 IO-PCB-GROUP PIC X(8).
005400      05 IO-PCB-TSTAMP.
005500        10 IO-PCB-TS-DATE PIC S9(7) COMP-3.
005600        10 IO-PCB-TS-TIME PIC X(6).
005700        10 IO-PCB-TS-OFFSET PIC S9(3) COMP-3.
005800      05 IO-PCB-IND PIC X(1).
005900 PROCEDURE DIVISION.
006000 MAIN-LINE.
006100      MOVE "DOGEMSO" TO FORMAT-OUT
006200      PERFORM WITH TEST AFTER UNTIL NO-MORE
006300        MOVE "IOPCB" TO PCB-NAME
006400        CALL "AIBTDLI" USING GU,
006500                             AIB,
006600                             INPUT-MSG
006700        SET ADDRESS OF IO-PCB TO RSA1-PTR
006800        DISPLAY "---------"
006900        DISPLAY IO-PCB-STATUS
007000        DISPLAY IO-PCB-MODNAME
007100        IF CALL-RETURN-CODE > 0 THEN
007200          SET NO-MORE TO TRUE
007300        ELSE
007400          MOVE IN-TEXT TO I-MSG
007500          MOVE "IOPCB" TO PCB-NAME
007600          CALL "AIBTDLI" USING ISRT,
007700                               AIB,
007800                               MESSAGE-1,
007900                               FORMAT-OUT
008000          DISPLAY MESSAGE-1
008100          DISPLAY FORMAT-OUT
008200        END-IF
008300      END-PERFORM
008400      GOBACK.

@massimo79m
Copy link

Very useful!
Do you have a similar thing for a cics+db2?
thank you

@DougieLawson
Copy link

Do you have a similar thing for a cics+db2?

There's nothing to do with Db2, so the CICS one will just work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment