Your Browser is not longer supported

Please use Google Chrome, Mozilla Firefox or Microsoft Edge to view the page correctly
Loading...

{{viewport.spaceProperty.prod}}

Beispiel 3 - C-Anwenderroutine

&pagelevel(3)&pagelevel

Die folgende Anwenderroutine dient dazu, numerische Werte innerhalb eines Spaltenbereichs der aktuellen Arbeitsdatei zu addieren und das Ergebnis in die letzte Zeile einzufügen.

Es werden die EDT-Funktionen IEDTEXE, IEDTGET, IEDTPUT und IEDTPTM verwendet.

/********************************************************************/
/*                                                                  */
/* Beispiel 3                                                       */
/*                                                                  */
/* Dies ist ein Beispiel für eine Anwenderroutine. Sie wird mit     */
/* USE COM='*',ENTRY=*,MODLIB=EDT.BEISPIELE vereinbart.             */
/* Anschließend wird über *sum <col1>-<col2> die Funktion SUM       */
/* gerufen, wobei nur noch das Argument <col1>-<col2> übergeben     */
/* wird. Die Funktion SUM liest alle Zeilen der aktuellen Arbeits-  */
/* datei und extrahiert die im Spaltenbereich <col1>-<col2> ent-    */
/* haltenen Zahlenwerte. Zeilen mit ungültigen Werten werden mit    */
/* Markierung 14 versehen (werden dann überschreibbar gestellt).    */
/* Die letzte gelesene Zeile nimmt den Summenwert auf.              */
/*                                                                  */
/* Das Beispielprogramm fuehrt im Einzelnen folgende Aktionen       */
/* durch:                                                           */
/*                                                                  */
/* 1) Den gewünschten Spaltenbereich aus den Aufrufargumenten       */
/*    ermitteln.                                                    */
/* 2) In einer Schleife nacheinander alle Zeilen des aktuellen      */
/*    Arbeitsbereichs lesen und die im gewünschten Spaltenbereich   */
/*    enthaltene Zahl in eine Gleitpuktzahl umwandeln. Wenn dies    */
/*    gelingt, Gleitpunktzahl zum Summenwert addieren. Wenn dies    */
/*    nicht gelingt, Zeile mit Markierung 14 kennzeichnen (sie wird */
/*    dann überschreibbar gestellt).                                */
/* 4) Nach Beendigung der Schleife wird der Summenwert in die       */
/*    letzte Zeile eingefügt und zum Aufrufer zurückgekehrt.        */
/*                                                                  */
/********************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* Include-Dateien der EDT-Unterprogrammschnittstelle */
#define EDT_V17
#include <iedtgle.h>
/* Alternative zur fill_buff Funktion: Macro zum Füllen des Puffers */
                                       /* ---------------------------- (1) */
#define IEDBUFF_FILL(buf,s) \
    (buf)->length = (strlen(s) + 4); \
    strncpy((char *)(buf)->text,s,(size_t)((buf)->length - 4))
/********************************************************************/
/* Funktion: edtget                                                 */
/*                                                                  */
/* Aufgabe:                                                         */
/* Diese Funktion liest mit der Funktion IEDTGET der Unterprogramm- */
/* Schnittstelle eine Zeile aus der aktuellen Arbeitsdatei. Es wird */
/* immer relativ zum Satz mit Zeilennummer 0 gelesen.               */
/*                                                                  */
/* Parameter: glcb:    (IN)  Zeiger auf den von EDT mitgelieferten  */
/*                           glcb.                                  */
/*            rec:     (IN)  Zeiger auf einen Datenbereich, in dem  */
/*                           die von der Funktion GET gelesene      */
/*                           Zeile abgelegt wird.                   */
/*            disp:    (IN)  Gibt an, die wievielte Zeile ab der    */
/*                           Zeilennummer 0 gelesen werden soll.    */
/*            key      (OUT) Zeiger auf ein Feld, in dem der gele-  */
/*                           sene Schlüssel hinterlegt wird         */
/********************************************************************/
static void
edtget(iedglcb *glcb,char *rec,int disp,iedbyte *key)
{
    iedamcb amcb = IEDAMCB_INIT;
    iedbyte key1[8] = {0,0,0,0,0,0,0,0};
    /* Kontrollblock IEDAMCB versorgen */
    IEDAMCB_SET_NO_MARKS(amcb);
    amcb.length_key_outbuffer = 8;
    amcb.length_rec_outbuffer = 256;
    amcb.length_key1 = 8;
    amcb.displacement = disp;  /* lese <disp> Sätze nach Nr. 0 */
    /* Nimm aktuelle Arbeitsdatei (aus glcb) */
    strncpy((char *)amcb.filename,(char *)glcb->filename,8);
    IEDTGET(glcb,&amcb,key1,key,rec);
    rec[amcb.length_rec] = 0;  /* set C-string end */
}
/********************************************************************/
/* Funktion: edtput                                                 */
/*                                                                  */
/* Aufgabe:                                                         */
/* Diese Funktion schreibt mit der IEDTPUT-Funktion einen Satz an   */
/* die durch den Schlüssel key bezeichnete Stelle.                  */
/*                                                                  */
/* Parameter: glcb:    (IN)  Zeiger auf den von EDT mitgelieferten  */
/*                           glcb.                                  */
/*            rec:     (IN)  Zeiger auf einen Datenbereich, in dem  */
/*                           der zu schreibende Satz übergeben wird.*/
/*            key      (IN)  Zeiger auf ein Feld, in dem der zu     */
/*                           (über-)schreibende Schlüssel steht.    */
/* Rueckgabewert: keiner                                            */
/********************************************************************/
static void
edtput(iedglcb *glcb,char *rec,iedbyte *key)
{
    iedamcb amcb = IEDAMCB_INIT;
    amcb.length_key = 8;
    amcb.marks.mark_field = 0;
    amcb.length_rec = strlen(rec);
    /* Nimm aktuelle Arbeitsdatei (aus glcb) */
    strncpy((char *)amcb.filename,(char *)glcb->filename,8);
    IEDTPUT(glcb,&amcb,key,(unsigned char *)rec);
}
/********************************************************************/
/* Funktion: edtptm                                                 */
/*                                                                  */
/* Aufgabe:                                                         */
/* Diese Funktion schreibt mit der IEDTPTM-Funktion eine Markierung */
/* an die durch den Schlüssel key bezeichnete Stelle.               */
/*                                                                  */
/* Parameter: glcb:    (IN)  Zeiger auf den von EDT mitgelieferten  */
/*                           glcb.                                  */
/*            mark:    (IN)  Wert der zu schreibenden Markierung.   */
/*            key      (IN)  Zeiger auf ein Feld, in dem der zu     */
/*                           markierende Schlüssel steht.           */
/* Rueckgabewert: keiner                                            */
/********************************************************************/
static void
edtptm(iedglcb *glcb,int mark,iedbyte *key)
{
    iedamcb amcb = IEDAMCB_INIT;
    amcb.marks.mark_field = 0;
    amcb.length_key = 8;
    if (mark != 0)                 /* -------------------------------- (2) */
        amcb.marks.mark_field = (1 << mark);
    /* Nimm aktuelle Arbeitsdatei (aus glcb) */
    strncpy((char *)amcb.filename,(char *)glcb->filename,8);
    IEDTPTM(glcb,&amcb,key);
}
/********************************************************************/
/* Funktion: SUM                                                    */
/*                                                                  */
/* Aufgabe:                                                         */
/* Diese Funktion liest mit der Funktion edtget die gesamte         */
/* Arbeitsdatei, extrahiert für jede Zeile den Spaltenbereich,      */
/* der als Argument mitgeliefert wurde, und versucht, den dort      */
/* enthaltenen Text in eine Gleitkommazahl umzuwandeln.             */
/* Die ermittelten Zahlen werden addiert und der Summenwert wird    */
/* in die letzte Zeile ausgegeben (überschreibt dort den gegebenen  */
/* Spaltenbereich).                                                 */
/* Zeilen, die an der gegebenen Stelle keine gültige Gleitpunkt-    */
/* zahl enthalten, werden mittels Markierung 14 überschreibbar      */
/* gestellt.                                                        */
/*                                                                  */
/* Parameter: glcb:    (IN)  Zeiger auf einen glcb, der für Aufrufe */
/*                           von IEDTGET oder IEDTPUT verwendet     */
/*                           wird.                                  */
/*            cmd:     (IN)  Argumente, mit denen sum aufgerufen    */
/*                           wurde.                                 */
/* Rueckgabewert: keiner                                            */
/********************************************************************/
void
SUM(iedglcb *glcb,iedbuff *cmd)         /* --------------------------- (3) */
{
    char command[80];
    char line[256];
    char number[64];
    int len = cmd->length;
    size_t col1 = 0;
    size_t col2 = 0;
    iedbyte key[8];
    float fnum;
    float sum;
    int disp;
    /* Ermittle Spaltenbereich aus dem Aufrufargument */
    cmd->text[len] = '\0'; /* setze Endezeichen für C-String */
    if (sscanf((char *)cmd->text," %d - %d ",&col1,&col2) < 2)
    {
        glcb->IEDGLCB_RC_MAINCODE = IEDGLCBcmd_unrec_user_error;
        glcb->IEDGLCB_RC_SUBCODE1 = IEDGLCBparameter_error;
        return;                       /*------------------------------ (4) */
    }
    /* Anweisung @PAR PROT=ON, damit Markierung 14 wirkt */
    IEDBUFF_FILL((iedbuff *)command,"@PAR PROT=ON");
    IEDTEXE(glcb,(iedbuff *)command);
    sum = 0.0;
    /* Lese alle Zeilen der aktuellen Arbeitsdatei */
    for (disp = 1; disp < 99999999; disp++)  /*----------------------- (5) */
    {
        /* Naechste Zeile lesen */
        edtget(glcb,(char *)&line,disp,key);
        if (glcb->IEDGLCB_RC_MAINCODE != 0)
            return; /* MAINCODE unverändert durchreichen */
        /* Wenn jenseits der letzten Zeilennummer gelesen wird */
        /* gibt IEDTGET "last record" zurück */
        if (glcb->IEDGLCB_RC_SUBCODE1 == IEDGLCBlast_record)
            break; /* Schleife verlassen */
        /* extrahiere Zahlenwert */
        strncpy(number,&line[col1 - 1],col2 - col1 + 1);
        number[col2 - col1 + 1] = '\0';
        if (sscanf(number," %f ",&fnum) >= 1)
        {
            sum += fnum;
            edtptm(glcb,0,key); /* Setze evtl. Markierung zurück */
        }
        else /* keine gültige Gleitpunktzahl im Bereich */
        {
            /* Setze Markierung 14 - Zeile wird überschreibbar gestellt */
            edtptm(glcb,14,key);
        }
    }
    /* Setze Summenwert in die letzte Zeile ein und schreibe sie zurück */
    sprintf(number,"%6.2f      ",sum);
    strncpy(&line[col1 - 1],number,col2 - col1 + 1);
    edtput(glcb,(char *)line,key);
}
/********************************************************************/
/* Funktion: SUM@I                                                  */
/*                                                                  */
/* Aufgabe:                                                         */
/* Dies ist die Initialisierungsroutine zu SUM.                     */
/*                                                                  */
/* Parameter: glcb:    (IN)  Zeiger auf einen glcb in dem u.a. der  */
/*                           beim Aufruf von sum zu verwendende     */
/*                           Zeichensatz festgelegt werden kann.    */
/*                                                                  */
/* Rueckgabewert: keiner                                            */
/********************************************************************/
void SUM@I(iedglcb *glcb)                /* -------------------------- (6) */
{
    glcb->indicator.compatible_format = 1;
    memcpy(glcb->ccsn,"EDF04F    ",8); /* sum erwartet EDF04F */
    glcb->rc.rc_nbr = 0;
}

Erläuterungen

(1)Als Alternative zur Funktion fill_buff aus den Beispielen 1 und 2 wird hier ein mit #define vereinbartes Makro verwendet, um einen Anweisungspuffer zu versorgen.
(2)Die Funktion edtptm setzt jeweils nur eine Markierung. Zum Löschen einer Markierung muss sie mit dem Wert 0 aufgerufen werden.
(3)Der Funktionsname wird in Großbuchstaben definiert, da die Benutzeranwesung mit @USE COM='*',ENTRY=*,... vereinbart werden und mit *sum c1 - c2 aufgerufen werden soll. In diesem Fall setzt der EDT den ersten Teil der Benutzeranweisung (den Anweisungsnamen) in Großbuchstaben um (siehe Abschnitt „Aufruf einer benutzerdefinierten Anweisung“).
(4)Wenn sich das Aufrufargument nicht in zwei Ganzzahlen (Anfangs- und Endspalte) umwandeln lässt, wird die Anwenderroutine mit Returncode verlassen. Es erscheint dann die Meldung EDT5410. Hier sollte man natürlich noch weitere Überprüfungen
(z.B. col1 < col2) einfügen und entsprechende Meldungstexte aufbauen.
Im Interesse der Übersichtlichkeit wurde im Beispiel darauf verzichtet.
(5)Die hier implementierte Methode zum sequenziellen Lesen der Arbeitsdatei ist nicht sonderlich effektiv, da immer wieder von Beginn an gelesen wird. Man überlege sich, wie man unter Verwendung des in key zurück gelieferten Schlüssels mit konstantem amcb.displacement = +1 einen günstigeren Algorithmus implementieren kann.
(6)Es wird eine Initialisierungsroutine eingerichtet, damit der Aufruf der Anwenderroutine über die V17-Schnittstelle und im Zeichensatz EDF04F erfolgt.

Wenn die in Abschnitt „Produktion von Anwenderroutinen in C“ erklärte Prozedur im BS2000 in einer Datei namens CCMOD.DO und die Quelldatei als S-Element ANWEND1.C in der Bibliothek EDT.BEISPIELE abgelegt ist, kann das obige Programm mit

/CALL-PROC CCMOD.DO,(1)

übersetzt und das LLM ANWEND1 in der Bibliothek EDT.BEISPIELE abgelegt werden.

Wenn man die Benutzeranweisung mit

@USE COMMAND='*',ENTRY=*,MODLIB=EDT.BEISPIELE

vereinbart, kann man die Anweisung *SUM etwa benutzen, um Preise in einer Einkaufsliste addieren zu lassen:

Nach Eingabe von *sum 16-21 wird folgender Bildschirm angezeigt: