A String Data Structure for GnuCOBOL

When I started to learn COBOL in the late 70’s, HP BASIC was my primary language. BASIC is adept at handling strings. As I quickly found, COBOL (particularly the 1968 standard I was using), was not.

I know there are some string processing functions available in gnuCOBOL such as TRIM. For this post, I want to implement the string data structure I used for all of my string processing needs.

Simple Example of Lack of Strings

Here is a very rudimentary example of a problem that occurs by not having some type of string data structure. Say you define 2 variables:

01  buffer                     pic x(40).
01  formattedAmount            pic ---,--9.99.

Then initialize and output them:

move "JOHN SMITH"             to buffer.
move 1.98                     to formattedAmount.

display ">", buffer, "|", formattedAmount, "<".

The display would show:

>JOHN SMITH                              |      1.98<

Lining up data in columns might be suitable for a line printer but is ugly on a terminal. If you want to see the output as

>JOHN SMITH|1.98<

it really wasn’t doable.

A COBOL String Data Structure

At my first job, on a DEC-10, I stumbled upon a simple way to control how much of a string buffer could be displayed:

01 len                           pic s9(4), comp.
01 str.
   03  str-byte                  pic x,
         occurs                  0 to 80 times,
         depending on            len.

To display str without trailing spaces, I just needed to:

move 80                         to len.
move "JOHN SMITH"               to str.
move 10                         to len.
display ">", str, "<".

>JOHN SMITH<

Having to move 80 to len first was a bit clumsy. In more careful reading of the manual I found I could create the following data structure which became my standard COBOL string data structure:

01  cst-string.
    03  cst-max                            pic s9(4), comp, value 80.
    03  cst-len                            pic s9(4), comp.
    03  cst-in                             pic x(80).
    03  cst-out redefines                  cst-in.
        05  cst-byte                       pic x,
                occurs                     0 to 80 times,
                depending on               cst-len.

This worked like a charm. Now to setup a string it just required this:

move "JOHN SMITH"                         to str-in.
move 10                                   to str-len.
display ">", str-out, "<".

When I moved to a job programming HP3000’s in COBOL, I took this idea with me where I used it for several decades. More than likely some of that code is still running.

If you are a COBOL programmer, you may be saying “WHOA, you can’t do that!” Per the COBOL standards, you cannot redefine a variable length field!

That is true in gnuCOBOL and is true according to the ’74 and ’85 standard manuals I have. BUT it did work on the DEC10 and the HP3000 COBOL compilers.

Making the COBOL String Structure Work for gnuCOBOL

I screwed around with trying to get past that limitation for a while and finally gave up. Instead gnuCOBOL requires this data structure:

01  cst-string.
    03  cst-max                                   binary-short unsigned, value 256.
    03  cst-len                                   binary-short unsigned.
    03  cst-out.
        05 cst-byte                               pic x,
             occurs                               0 to 256 times,
             depending on                         cst-len.

The downside to this structure is you cannot move a string to it without first setting cst-len to cst-max before initializing cst-out. So to create a string you would do this:

move cst-max                                     to cst-len.
move "JOHN SMITH"                                to cst-out.
compute cst-len = 
    function length( 
        function trim( cst-out, trailing)).
if cst-len = 1 and cst-byte(1) = space then
    move zero                                    to cst-len.

Still kind of a lot of work to do, but one can create a copy book code fragment to do the work:

       >>source free
*>cfCstSet:
*>  01/31/12:   DWH.                 
*>              Created for openCOBOL.            
*>  08/15/20:   DWH.
*>              Updated for gnuCOBOL.
                                                                  
*>--------------------------------------------------------------   
*>    COPY cfstrset
*>    REPLACING cst-in BY <literal|word>].                           
*>--------------------------------------------------------------   
                                                                  
*>    openCOBOL doesn't allow my old STR string structure. The new
*>    structure requires the following code frag to move something
*>    into the structure and set the size.

*>    This code fragment can be copied anywhere such as:
*>        if 1=1 then
*>            copy cfCstSet replacing cst-in with "test";
*>        else,
*>            next sentence.
                             
    move cst-max                        to cst-len;
    move cst-in                         to cst-out;
    compute cst-len = 
        function length( 
            function trim( cst-out, trailing));
    if cst-len = 1 and cst-byte(1) = space then
        move zero                      to cst-len;
    end-if;

Now, to move create a string of “JOHN SMITH”, I just:

copy cfcstset,
    replacing cst-in by "JOHN SMITH".

Here is a listing of an example program (with expanded copy books) so you can see everything:

GnuCOBOL 3.1-rc1.0      cfcstsetEx.cbl       Sun Aug 16 15:21:34 2020  Page 0001
000011
LINE    PG/LN  A...B............................................................
000013
000001         >>SOURCE FREE
000002  identification division.                by "JOHN SMITH".
000003  program-id.urce free
000004      cfcstsetEx.
000005
000006  data division.  
000007
000008  working-storage section.
000009
000010  copy wscst.
000001C        >>SOURCE FREE
000002C *>wscst
000003C *>    AA0000: 01/08/88:    DWH.
000004C *>            STR COBOL string routine data names.
000005C *>    AA0001: 01/31/12:    DWH.
000006C *>            Converted to run in OpenCobol.                                   
000007C
000008C *>--------------------------------------------------------------
000009C *>    COPY wscst
000010C *>    [REPLACING 256 BY ].
000011C *>--------------------------------------------------------------ng
000012C *>    into the structure and set the size.
000013C *>    STANDARD COBOL STRING DATA STRUCTURE.
000014C *>    You can change the maximum string size by using the
000015C *>    REPLACING clause.
000016C *>            copy cfCstSet replacing cst-in with "test";
000017C 01  cst-string.
000018C     03  cst-max                         binary-short unsigned, value 256
000018+ .
000019C     03  cst-len                         binary-short unsigned.
000020C     03  cst-out.MITH" to cst-out;
000021C         05  cst-byte                    pic x,
000022C            occurs                       0 to 256 times,
000023C            depending on                 cst-len.
000024C
000011
000012  procedure division.
000013
000014      copy cfCstSet
000015          replacing cst-in                by "JOHN SMITH".
000001C        >>source free
000002C *>cfCstSet:
000003C *>  01/31/12:   DWH.
000004C *>              Created for openCOBOL.
000005C *>  08/15/20:   DWH.
000006C *>              Updated for gnuCOBOL.
000007C
000008C *>--------------------------------------------------------------
000009C *>    COPY cfstrset
000010C *>    REPLACING cst-in BY <literal|word>].
000011C *>--------------------------------------------------------------
000012C
GnuCOBOL 3.1-rc1.0      cfcstsetEx.cbl       Sun Aug 16 15:21:34 2020  Page 0002

LINE    PG/LN  A...B............................................................

000013C *>    openCOBOL doesn't allow my old STR string structure. The new
000014C *>    structure requires the following code frag to move something
000015C *>    into the structure and set the size.
000016C
000017C *>    This code fragment can be copied anywhere such as:
000018C *>        if 1=1 then
000019C *>            copy cfCstSet replacing cst-in with "test";
000020C *>        else,
000021C *>            next sentence.
000022C
000023C     move cst-max                        to cst-len;
000024C     move "JOHN SMITH" to cst-out;
000025C     compute cst-len =
000026C         function length(
000027C             function trim( cst-out, trailing));
000028C     if cst-len = 1 and cst-byte(1) = space then
000029C         move zero                      to cst-len;
000030C     end-if;
000031C
000032C
000016
000017      display ">", cst-out, "<".
000018
000019      stop run.


0 warnings in compilation group
0 errors in compilation group

And the resulting output:

>JOHN SMITH<

Next time, I will show how to pass the COBOL string data structure to Pascal and let it do some basic string processing functions.

This entry was posted in c-gnuCOBOL and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.