Het gebruik van C functies in COBOL

De tijd dat applicaties volledig op zichzelf staan, is al lang verleden tijd. De nieuwste generatie COBOL-compilers houdt met dit gegeven al lang rekening. De mogelijkheden om COBOL applicaties te integreren met applicaties die in andere programmeertalen zijn ontwikkeld worden jaarlijks groter. Hierdoor is het mogelijk om componten over applicaties heen te hergebruiken en daarmee ontwikkeltijd te besparen. Bovendien wordt het mogelijk om de kracht van de ene programmeertaal in te zetten in een andere omgeving. Dit artikel beschrijft hoe binnen COBOL (Enterprise COBOL) gebruikt gemaakt kan worden van C-functies.

Datatypen

Veel programmeertalen kennen datatypen die sterke overeenkomsten vertonen. Zo ondersteunen de meeste talen wel de typen integer, string en float, in welke vorm dan ook. COBOL kent in principe geen datatypen, maar variabelen worden in de working-storage gedefinieerd. De picture clause bepaalt of een variabele numeriek danwel alfanumeriek is. Met behulp van de clauses BINARY, PACKED-DECIMAL etc kan wrden gespecificieerd hoe de inhoud van de variabele intern in het geheugen wordt opgeslagen.
 
COBOL ondersteunt de meeste binnen C gebruikte elementaire datatypen
 
Om met C-componenten te kunnen werken, moeten de binnen C bekende datatypen ook in COBOL gebruikt kunnen worden.
 
        WORKING-STORAGE SECTION.
        01 DATA-ITEMS.
            03 boolean         PIC X.
                88 B-FALSE     VALUE X’00’.
                88 B-TRUE      VALUES X’01’ THROUGH X’FF’.
            03 single          COMP-1.
            03 double          COMP-2.
            03 byte            PIC A.
            03 short           PIC S9(4) COMP-5.
            03 int             PIC S9(9) COMP-5.
            03 long            PIC S9(18) COMP-5.
            03 char            PIC N.
            03 string          PIC X(30).
Listing 1 – definitie van C-datatypen in COBOL working-storage.
 
In Listing 1 zijn de meest voorkomende datatypen in C en Java gedefinieerd in een COBOL WORKING-STORAGE SECTION. Data-items van het type COMP-1 en COMP-2 zijn floating point data-items, waarbij COMP-1 vier bytes groot is(single precision) en COMP-2 acht bytes (double precision). Door deze definitie is de PICTURE clause voor deze data-items verboden. Voor alfanumerieke velden kan zowel PIC X als PIC A worden gebruikt. Dit zijn synoniemen van elkaar.
Data-items van het type COMP-5 worden intern gerepresenteerd als binaire data. Het verschil met het type BINARY of COMP is echter, dat de maximale waarde van het data-item wordt bepaald door het aantal benodigde bytes en niet door de PIC S9… clause. Data-items gedefinieerd als PIC S9(5) COMP-5 en PIC S9(9) COMP-5 nemen beide vier bytes in beslag en zijn daardoor beide van het type integer.
 

Strings

De interne representatie van strings verschilt enorm tussen C en COBOL. Binnen COBOL is de lengte van een string altijd gelijk aan de lengte van de definitie in de WORKING-STORAGE. Een string gedefinieerd met een lengte 10 die de waarde “ABC” bevat, is in feite de string “ABC” gevolgd door zeven spaties. C kent de zogenaamde null-terminated string, waarbij de string van wordt afgesloten door een hexadecimale nul.
 
        WORKING-STORAGE SECTION.
        01 S        PIC X(31) VALUE Z’ABC’.
        PROCEDURE DIVISION.
        …
             MOVE Z’My string for C’ TO S.
             STRING “My string for C”
                    X’00’
                    DELIMITED BY SIZE
                    INTO S
             END-STRING.
 
Listing 2 – gebruik van null-terminated strings
 
Enterprise COBOL ondersteunt ten dele het gebruik van de null-terminated string (zie Listing 2). Door bij een MOVE-statement of een VALUE-clause de toe te wijzen string te voorzien van de prefix Z, wordt de string als een null-terminated string in het data-item geplaatst. Wat hierbij in feite gebeurd, is dat ná de string een karakter van het type LOW-VALUE oftewel de hexadecimale nul wordt toegevoegd. Bij de definitie van het data-item moet dus wel rekening gehouden worden met de bepaling van de maximale lengte dat er één extra byte wordt gereserveerd voor de null-terminator.
 
Null-terminated strings zijn slechts beperkt bruikbaar binnen COBOL
 
Verder zijn de mogelijkheden voor het gebruik van de null-terminated strings beperkt binnen COBOL. Voor het verwijderen van de null-terminator of het bepalen van de lengte van een null-terminated string moet eigen code worden geschreven.
 
        WORKING-STORAGE SECTION.
        01 S        PIC X(31) VALUE Z’ABC’.
        01 S2       PIC X(30).
        01 S-LEN    PIC S9(3) COMP-5.

        PROCEDURE DIVISION.
       …
       ****
       **** Bepalen van de lengte van de 0X-string
       ****
            Inspect S tallying S-LEN for characters before initial X’00’.
       ****
       **** Verwijderen van de null-terminator
       ****
            Unstring S delimited by X’00’ into S2.
Listing 3 – null-terminated string operaties in COBOL
 
Aangezien de mogelijkheden bestaan voor het gebruik van C-functies in COBOL, is het raadzaam om eerst te bepalen of er een C-functie voorhanden is. In C kennen we strlen() voor het bepalen van de stringlengte. Deze functie kan ook in COBOL worden gebruikt. Verderop in dit artikel wordt daar verder op ingegaan.
 
Parameters
In native COBOL kennen we slechts één manier om parameters door te geven aan een subprogramma en dat is door middel van het meegegeven van het adres van het betreffende data-item. Om componenten van andere programmeertalen te kunnen aanroepen, zijn ook andere mechanismen noodzakelijk. Bovendien kennen andere programmeeromgevingen functies die een waarde als resultaat teruggeven, een mechanisme die we in COBOL in feite ook niet kennen.
 
        …
        PROCEDURE DIVISION.
        …
       ****
       **** Aanroepen van een subprogramma
       ****
            CALL “SUBPROG” USING BY REFERENCE <var-1>
                                 BY VALUE <var-2>
                                 BY CONTENT <var-3>
                                 RETURNING <var-4>.
      
Listing 4 – Aanroep van subprogramma met diverse parameter mechanismen
 
In Listing 4 zijn alle mogelijke varianten van het doorgeven van parameters weergegeven. Met behulp van BY REFERENCE wordt het adres van het data-item meegegeven, zoals we dat normaliter in COBOL ook doen. BY REFERENCE is de default. Met behulp van BY VALUE wordt de waarde van het data-item aan het subprogramma meegegeven. Evenals bij BY REFERENCE wordt bij BY CONTENT een adres meegegeven, maar in de laatste geval is dit een kopie van het data-item. Met behulp van RETURNING wordt het data-item geïdentificeerd die het resultaat van het subprogramma zal bevatten. Dit data-item is voor het subprogramma write-only.
 
Aanroepen C-functies
Het aanroepen van een C-functie is niets anders dan het aanroepen van een subprogramma, zoals weergegeven in Listing 4. Enterprise COBOL levert een complete library met C-functies die binnen een COBOL-programma als subprogramma kunnen worden aangeroepen. Maar, er bestaat nog een andere manier en dat is door het gebruik van een FUNCTION-POINTER (zie Listing 5).
 
        CBL PGMNAME(LONGMIXED)        IDENTIFICATION DIVISION.        PROGRAM-ID. “TESTC”.        DATA DIVISION.
        WORKING-STORAGE SECTION.

        77 FP                  USAGE FUNCTION-POINTER.        77 MELDING-TEMPLATE    PIC X(80) VALUE            Z”Fout bij het openen van MQ Object %s, met code %s”.        01 PARM-1              PIC X(20) VALUE 
            Z”Queue manager”.
        01 PARM-2              PIC X(20) VALUE Z“2085”.        01 FOUTMELDING         PIC X(133).        01 STR-LEN             PIC S9(4) COMP-5.
        PROCEDURE DIVISION.

            CALL "SPRINTF"      RETURNING FP.
            CALL FP USING MELDING-TEMPLATE
                          PARM-1
                          PARM-2
                      RETURNING FOUTMElDING.              CALL "STRLEN" USING                        BY VALYE ADDRESS OF FOUTMELDIN                     RETURNING STR-LEN.                    DISPLAY FOUTMELDING (1:STR-LEN).            GO BACK.















 
Listing 5 – Aanroep C-functie mbv een FUNCTION-POINTER
 
Het eerste CALL-statement haalt het adres op van de functie “SPRINTF” en plaatst deze in het data-item FP die als FUNCTION-POINTER is gedefinieerd.
 
C-functies zijn aan te roepen als subprogramma of met behulp van een FUNCTION-POINTER
 
Het tweede CALL-statement gebruikt de FUNCTION-POINTER om de C-functie aan te roepen.
Het derde CALL-statement roept de C-functie strlen aan om de lengte van de met sprintf geformeerde foutmelding te bepalen. Met behulp van reference modification wordt bij het weergeven van de foutmelding de null-terminator verwijderd.
 
De nut en noodzaak van voor het aanroepen van een C-functie met behulp van een FUNCTION-POINTER laat ik aan ieders eigen fantasie over. Mijn voorkeur gaat uit naar de aanroep zoals die gebruikt is naar de C-functie strlen.
Voorbeeld
Hoewel COBOL een zeer krachtige programmeertaal is, ontbreken er in mijn ogen een aantal belangrijke zaken. Een daarvan zijn string-manipulatie functies, zoals het zoekenen vervangen van strings binnen een string. Een XML-verwerkend programma moest een aantal XML-strings samenvoegen tot één string en bepaalde voorkomens uit de XML-string verwijderen. Om dit te kunnen doen, heb je een functie nodig waarmee de inhoud van een geheugengebied verplaatst kunnen worden naar een andere geheugenlokatie, waarbij de bron en het doel elkaar moeten kunnen overlappen. COBOL kent niet een dergelijke functie, maar C wel, te weten memmove (zie Listing 6).
 
void * memmove ( void * destination, 
                 const void * source, 
                 size_t num );
 
 
Listing 6 – Declaratie C-functie memmove
 
Deze functie wordt ook door Enterprise COBOL meegeleverd in de library met C-functies. De parameters van deze functie zijn:
1.    Het adres van het geheugen van de bestemming (BY REFERENCE);
2.    Het adres van het geheugen van de bron (BY VALUE);
3.    Het aantal te verplaatsen bytes (BY VALUE)
 
In COBOL kan de aanroep naar deze functie er als volgt uitzien (Listing 7):
 
           CALL 'MEMMOVE' USING
                   BY REFERENCE STR-XML(X-NAAR:1)
                       BY VALUE ADDRESS OF STR-XML(X-VAN:1)
                       BY VALUE STR-XML-COUNT.
Listing 7 – Aanroep memmove in COBOL
 
De te bewerken XML is als string gedefinieerd als STR-XML. De subscript X-NAAR en X-VAN definiëren de positie binnen STR-XML waar naartoe en van waar data verplaatst moet worden en STR-XML-COUNT bevat het aantal te verplaatsen bytes. Met behulp van BY VALUE ADRRESS OF STR-XML(X-VAN:1) wordt eerst het adres bepaalt van STR-XML(X-VAN:1) en dit adres wordt vervolgens als een waarde meegegeven aan memmove. Bij de eerste parameter ontbreekt de ADDRESS OF omdat BY REFERENCE al expliciet aangeeft dat het adres moet worden meegegeven.
 
Integratie van COBOL met C-componeten is een krachtige troef voor hergebruik
 
Overige toepassingen
Het hergebruiken van C-functies binnen COBOL applicaties betekent dat er veel extra mogelijkheden ontstaan voor deze applicaties. Naast string- en geheugenmanipulaties, ontstaan er bijvoorbeeld ook mogelijkheden voor dynamische geheugenallocaties (malloc). Een aantal tekortkomingen van COBOL kunnen hiermee het hoofd worden geboden.
Maar naast bestaande C-functies, kunnen ook eigen functies die geschreven zijn in C worden gebruikt. Hierdoor is de weg open om bijvoorbeeld binnen de gehele organisatie gebruik te maken van één en dezelfde renteberekeningsmodule. Het is hierdoor niet een leuk speeltje voor de ontwikkelaar, maar een serieuze methode om in te zetten voor het hergebruiken van componenten.

 

Geef feedback:

CAPTCHA image
Vul de bovenstaande code hieronder in
Verzend Commentaar