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 2 - C-Hauptprogramm

&pagelevel(3)&pagelevel

Dieses Beispiel nutzt die IEDTCMD-Schnittstelle und die IEDTGET-Schnittstelle, um Sätze einer Datei zu lesen und zu verarbeiten:

/********************************************************************/
/*                                                                  */
/* Beispiel 2                                                       */
/*                                                                  */
/* Dieses Beispiel verwendet die IEDTCMD-Schnittstelle zur          */
/* Ausfuehrung von EDT-Anweisungen sowie die IEDGET-               */
/* Schnittstelle zum Lesen von Zeilen. Es werden aus einer          */
/* Datei, die Rechnungsdaten enthaelt, alle Datensaetze             */
/* ausgegeben, deren Rechnungsdatum mehr als eine fest              */
/* vorgegebene Anzahl von Tagen vor dem aktuellen Datum             */
/* liegen.                                                          */
/*                                                                  */
/* Das Beispielprogramm fuehrt im Einzelnen folgende Aktionen       */
/* durch:                                                           */
/*                                                                  */
/* 1) Aktuelles Datum ermitteln.                                    */
/* 2) Alle Zeilen der Datei mit den Rechnungsdaten mittels der      */
/*    @COPY-Anweisung (Format 1) in den Arbeitsbereich $0 einlesen. */
/* 3) In einer Schleife nacheinander alle Zeilen des Arbeits-       */
/*    bereichs $0 lesen und die Zeitdifferenz zwischen dem          */
/*    aktuellen Datum und dem Rechnungsdatum berechnen. Ist         */
/*    diese Zeitdifferenz groesser, als ein fest vorgegebenes       */
/*    Limit, wird von dieser Zeile Kundennummer, Rechnungsnummer    */
/*    und Rechnungsbetrag ausgegeben.                               */
/* 4) Nach Beendigung der Schleife wird der EDT mit der Anweisung   */
/*    @HALT und anschliessend dieses Beispielprogramm beendet.      */
/*                                                                  */
/********************************************************************/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
/* Include-Dateien der EDT-Unterprogrammschnittstelle */
#define EDT_V17
#include <iedtgle.h>
/* Anlegen und Initialisieren der fuer dieses Beispiel benoetigten */
/* Datenstrukturen der EDT-Unterprogrammschnittstelle.             */
static iedglcb glcb = IEDGLCB_INIT;
static iedupcb upcb = IEDUPCB_INIT;
static iedamcb amcb = IEDAMCB_INIT;
static iedbuff *command = NULL;
static iedbuff *message1 = NULL;
static iedbuff *message2 = NULL;
/* Definition einer Ausgabezeile */
typedef struct line
{
    char kdnr[8];         /* Kundennummer */
    char free1[2];
    char renr[8];         /* Rechnungsnummer */
    char free2[2];
    char betr[10];        /* Rechnungsbetrag */
    char free3[2];
    char day[2];          /* Tag der Rechnungsstellung */
    char trenn1[1];
    char mon[2];          /* Monat der Rechnungsstellung */
    char trenn2[1];
    char year[4];         /* Jahr der Rechnungsstellung */
    char rest[215];
} LINE;
/********************************************************************/
/* Funktion: printrc                                                */
/*                                                                  */
/* Aufgabe:                                                         */
/* Falls der EDT eine Fehlermeldung zurueckgegeben hat, wird die    */
/* Fehlermeldung durch diese Funktion ausgegeben.                   */
/*                                                                  */
/* Parameter: errmsg   (IN)  Zeiger auf die im Fehlerfall           */
/*                           zusaetzlich auszugebende Fehlermeldung */
/*                                                                  */
/* Rueckgabewert: keiner                                            */
/********************************************************************/
static void
printrc(char *errmsg)
{
    char message[81];
    if (glcb.IEDGLCB_RC_MAINCODE != 0)
    {
        printf("%s: %08x\n",errmsg,
         glcb.IEDGLCB_RC_NBR);/* Uebergebene Fehlermeldung + code ausgeben */
        if (glcb.return_message.structured_msg.rmsgl > 0)
        {
            strncpy(message,(char*)glcb.return_message.structured_msg.rmsgf,
                glcb.return_message.structured_msg.rmsgl);
            message[glcb.return_message.structured_msg.rmsgl] = 0x00;
            printf("Meldungstext: %s\n",message);  /* EDT-Meldung ausgeben */
        }
        exit(1);
    }
}
/********************************************************************/
/* Funktion: fill_buff                                              */
/*                                                                  */
/* Aufgabe:                                                         */
/* Diese Funktion versorgt einen Satz variabler Laenge (DVS-Format) */
/* mit einem Inhalt sowie das Satzlaengenfeld.                      */
/*                                                                  */
/* Parameter: p:       (IN)  Zeiger auf eine Struktur vom Typ       */
/*                           iedbuff, die den zu versorgenden Satz  */
/*                           variabler Laenge enthaelt.             */
/*            textp:   (IN)  Zeiger auf einen String, der den ein-  */
/*                           zutragenden Text enthaelt. Die Laenge  */
/*                           des Strings legt implizit die Laenge   */
/*                           des Satzes fest (Laenge String + 4).   */
/*                                                                  */
/* Rueckgabewert: keiner                                            */
/********************************************************************/
static void
fill_buff(iedbuff *p,char *textp)
{
    size_t l_text;                          /* Laenge des String */
    if ((l_text = strlen(textp)) > 2044)
        l_text = 2044;      /* Laenge auf 2044 Zeichen begrenzen */
    strncpy((char *)p->text,textp,l_text);  /* Text eintragen */
    p->length = l_text + 4;                 /* Satzlaenge versorgen */
}
/********************************************************************/
/* Funktion: edtcmd                                                 */
/*                                                                  */
/* Aufgabe:                                                         */
/* Diese Funktion traegt die uebergegebenen Strings in Saetze       */
/* variabler Laenge ein (DVS-Format) und ruft anschliessend die     */
/* CMD-Schnittstelle des EDT auf.                                   */
/*                                                                  */
/* Parameter: cmd:     (IN)  Zeiger auf einen String, der die       */
/*                           auszufuehrenden EDT-Anweisung(en)      */
/*                           enthaelt. Die Laenge des Strings legt  */
/*                           implizit die Laenge des Satze fest     */
/*                           (Laenge String + 4).                   */
/*            msg1:    (IN)  Zeiger auf einen String, der den ein-  */
/*                           zutragenden Text enthaelt. Die Laenge  */
/*                           des Strings legt implizit die Laenge   */
/*                           des Satzes fest (Laenge String + 4).   */
/*            msg2:    (IN)  Zeiger auf einen String, der den ein-  */
/*                           zutragenden Text enthaelt. Die Laenge  */
/*                           des Strings legt implizit die Laenge   */
/*                           des Satzes fest (Laenge String + 4).   */
/*                                                                  */
/* Rueckgabewert: keiner                                            */
/********************************************************************/
static void
edtcmd(char *cmd,char *msg1,char *msg2)
{
    fill_buff(command,cmd);
    fill_buff(message1,msg1);
    fill_buff(message2,msg2);
    IEDTCMD(&glcb,&upcb,command,message1,message2);
}
/********************************************************************/
/* Funktion: edtget                                                 */
/*                                                                  */
/* Aufgabe:                                                         */
/* Diese Funktion liesst mit der Funktion GET der Unterprogramm-    */
/* Schnittstelle eine Zeile aus der Arbeitsdatei $0. Es wird immer  */
/* relativ zum Satz mit Zeilennummer 0 gelesen.                     */
/*                                                                  */
/* Parameter: 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.    */
/* Rueckgabewert: keiner                                            */
/********************************************************************/
static void
edtget(char *rec,int disp)
{
    char localfile[9] = "$0      ";
    iedbyte key1[8] = {0,0,0,0,0,0,0,0};
    iedbyte key[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;              /* -------------------------- (1) */
    amcb.displacement = disp;  /* lese <disp> Sätze nach Nr. 0 */
    strncpy((char *)amcb.filename,localfile,8); /* Arbeitsdatei $0 */
    IEDTGET(&glcb,&amcb,key1,key,rec);
}
/********************************************************************/
/* Hauptprogramm                                                    */
/********************************************************************/
int
main(void)
{
    char filename[] = "edt.rechnung2";
    char cmd[257];
    LINE zeile;
    int  disp;
    int  days = 20;
    int  time_diff;
    time_t zeit1;
    time_t zeit2;
    struct tm t;
    printf("\nStart Beispiel2\n\n");
    /* buffer bereitstellen */
    command = (iedbuff *)malloc(2048);
    message1 = (iedbuff *)malloc(2048);
    message2 = (iedbuff *)malloc(2048);
    /* Heutiges Datum ermitteln */
    zeit1 = time((time_t *) 0);
    /* Fuer die Umwandlung des Datums in der Zeile */
    /* wird die Uhrzeit auf 0 Uhr gesetzt          */
    t.tm_sec = 0;
    t.tm_min = 0;
    t.tm_hour = 0;
    /* Die zu bearbeitende Datei mit der   */
    /* Anweisung @COPY (Format 1) einlesen */
    sprintf(cmd,"COPY FILE=%s",filename);
    edtcmd(cmd,"","");
    printrc("Fehler bei der @COPY-Anweisung!");
    /* In der folgenden Schleife werden alle Zeilen */
    /* der Arbeitsdatei $0 bearbeitet.              */
    for (disp = 1; disp < 99999999; disp++)   /*-------------------- (2) */
    {
        /* Naechste Zeile lesen */
        edtget((char *)&zeile,disp);
        printrc("Fehler bei der Funktion GET!");
        /* Wenn jenseits der letzten Zeilennummer gelesen wird */
        /* gibt IEDTGET "last record" zurück */
        if (glcb.IEDGLCB_RC_SUBCODE1 == IEDGLCBlast_record)
            break; /* Schleife verlassen */
        t.tm_mday = atoi(zeile.day);          /* Datum aus der  */
        t.tm_mon = atoi(zeile.mon) - 1;       /* eingelesenen   */
        t.tm_year = atoi(zeile.year) - 1900;  /* Zeile holen    */
        zeit2 = mktime(&t);                   /* Datum in einen */
                                              /* Zeitwert konv. */
        /* Zeitdifferenz in Tagen bestimmen */
        time_diff = difftime(zeit1,zeit2)/86400;
        /* Falls die vorgegebene Zeitspanne vorbei ist, fuer die */
        /* aktuelle Zeile Kundennummer, Rechnungsnummer und      */
        /* Rechnungsbetrag ausgeben.                             */
        if (time_diff > days)
        {
            zeile.free1[0] = '\0';   /* ---------------------------- (3) */
            zeile.free2[0] = '\0';
            zeile.free3[0] = '\0';
            printf("Kdnr.: %s, Rechn.nr.: %s, Betrag: %s Euro\n",
                 zeile.kdnr,zeile.renr,zeile.betr);
        }
    }
    /* EDT und Programm beenden */
    edtcmd("HALT","","");
    printrc("Fehler bei der @HALT-Anweisung!");
    printf("\n\nEnde Beispiel2\n\n");
    return 0;
}

Erläuterungen

(1)Bei der IEDTGET-Funktion müssen nur length_key1 und length_key_outbuffer versorgt sein.
(2)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.
(3)Hier wird das Endezeichen für C-Strings eingesetzt, um eine direkte Ausgabe ohne Umwandlung zu ermöglichen.

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

/CALL-PROC CC.DO,(2)

übersetzt und gebunden werden. Das erzeugte Programm ist anschließend mit

/START-EXECUTABLE-PROGRAM (E=BSP2C,L=EDT.BEISPIELE)

ausführbar. Bei Ablauf von CC.DO werden etwa folgende Ausgaben vom System bzw. vom Compiler erzeugt:

%  BLS0524 LLM 'SDFCC', VERSION '03.1A40' OF '2005-02-03 16:16:36' LOADED
%  BLS0551 COPYRIGHT (C) Fujitsu Siemens Computers GmbH 2005. ALL RIGHTS 
RESERVED
%  CDR9992 : BEGIN C/C++(BS2000/OSD) VERSION 03.1A40
%  CDR9907 : NOTES: 0  WARNINGS: 0  ERRORS: 0  FATALS: 0
%  CDR9937 : MODULES GENERATED, CPU TIME USED = 2.6000 SEC
%  BND3102 SOME WEAK EXTERNS UNRESOLVED
%  BND1501 LLM FORMAT: '1'
%  BND1101 BINDER NORMALLY TERMINATED. SEVERITY CLASS: 'UNRESOLVED EXTERNAL'
%  CDR9936 : END; SUMMARY: NOTES: 0  WARNINGS: 0  ERRORS: 0  FATALS: 0
%  CCM0998 CPU TIME USED: 3.6403 SECONDS

Die von diesem Beispielprogramm zu bearbeitende Datei EDT.RECHNUNG2 sehe folgendermaßen aus:

00347563  00028654     1378.89  21.05.2007
00345781  00027349    21500.00  07.04.2007
00375863  00028937      248.23  19.05.2007
00242365  00012358     4577.54  23.03.2007
00416467  00046687     6776.31  10.05.2007
00576373  00015463      578.00  19.04.2007
00785214  00053417    65465.00  13.12.2006
00265432  00065743     6534.67  16.05.2007
00546315  00035476      656.34  29.05.2007
00675436  00015334     7878.45  04.05.2007
00353466  00087227      654.24  11.11.2006
00534267  00067854    52346.00  15.05.2007
00243535  00078921     4532.54  22.04.2007
00783432  00063223      548.19  17.05.2007
00623556  00054342     5346.32  17.03.2007
00234354  00065233     4534.65  08.05.2007

Nach Aufruf von /START-EXECUTABLE-PROGRAM (E=BSP2C,L=EDT.BEISPIELE) wird dann (am 4.5.2007) in etwa folgende Ausgabe zu sehen sein:

%  BLS0523 ELEMENT 'BSP2C', VERSION '@', TYPE 'L' FROM LIBRARY ':A:$USER.EDT
.BEISPIELE' IN PROCESS
%  BLS0524 LLM '$LIB-ELEM$EDT$BEISPIELE$$BSP2C$$', VERSION ' ' OF '2007-05-04 
12
:22:24' LOADED
Start Beispiel2
Kdnr.: 00345781, Rechn.nr.: 00027349, Betrag:   21500.00 Euro
Kdnr.: 00242365, Rechn.nr.: 00012358, Betrag:    4577.54 Euro
Kdnr.: 00785214, Rechn.nr.: 00053417, Betrag:   65465.00 Euro
Kdnr.: 00353466, Rechn.nr.: 00087227, Betrag:     654.24 Euro
Kdnr.: 00623556, Rechn.nr.: 00054342, Betrag:    5346.32 Euro
Ende Beispiel  2
%  CCM0998 CPU TIME USED: 0.3276 SECONDS