Dieses Beispiel zeigt, wie man ein C-Hauptprogramm und eine C-Anwenderroutine in der gleichen Source compilieren kann.
Da der EDT bei der @USE-Anweisung zunächst den angegebenen Entry mit VSVI
sucht, findet er den Entry im Hauptprogramm und verwendet diesen.
Ein Nachladen findet dann nicht statt.
Im Beispiel wird die @USE-Anweisung auch gleich im Hauptprogramm gegeben, so dass der Anwender die Benutzeranweisung *rot
(o.ä.) gleich zur Verfügung hat.
Da die Anwenderroutine keinen speziellen Anweisungsstring erwartet, kann Beispiel 4 auch als Beispiel für eine Anwenderroutine dienen, die mit @RUN ENTRY=ROT13 aufgerufen werden kann.
/********************************************************************/ /* */ /* Beispiel 4 */ /* */ /* Dieses Beispiel zeigt die Kombination eines C-Hauptprogramms */ /* mit einer Anwenderroutine. Es gestattet die Übergabe eines */ /* Dateinamens als Argument. Diese Datei wird eingelesen, dann wird */ /* in den Bildschirmdialog gewechselt. Die Anwenderroutine im */ /* gleichen Programm ver- und etschlüsselt alle Sätze der aktuellen */ /* Arbeitsdatei nach dem (primitiven) ROT13 Verfahren. */ /* */ /* Das Hauptprogramm fuehrt folgende Aktionen durch: */ /* */ /* 1) Ermitteln des Dateinamens aus dem Aufrufargument. */ /* 2) Einlesen der Datei mittels @OPEN-Anweisung über IEDTCMD */ /* 3) Benutzeranweisung "*ROT13" mit @USE einrichten */ /* 3) Verzweigen in den Bildschirmdialog mit @DIALOG */ /* */ /* Die Anwenderroutine ROT13 fuehrt folgende Aktionen durch: */ /* */ /* 1) Lesen der aller Sätze der aktuellen Arbeitsdatei in Schleife. */ /* 2) Verschlüsseln jedes Satzes mit ROT13. */ /* 3) Rückschreiben des Satzes in die Arbeitsdatei mit IEDTPUT */ /* */ /********************************************************************/ #include <string.h> #include <stdlib.h> #include <stdio.h> #include <ctype.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 iedbuff *command = NULL; static iedbuff *message1 = NULL; static iedbuff *message2 = NULL; /********************************************************************/ /* 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.rc.structured_rc.mc.maincode != 0) && (glcb.return_message.structured_msg.rmsgl > 0)) { printf("%s\n",errmsg); /* Uebergebene Fehlermeldung ausgeben */ 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 liest mit der Funktion GET der Unterprogramm- */ /* Schnittstelle eine Zeile aus der aktuellen Arbeitsdatei. Es wird */ /* 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 = 2044; 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); strncpy((char *)amcb.filename,(char *)glcb->filename,8); IEDTPUT(glcb,&amcb,key,(unsigned char *)rec); } /* Statische Daten für die Verschlüsselung */ static char* lcc = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; static char* ucc = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"; /********************************************************************/ /* Funktion: ROT13 */ /* */ /* Aufgabe: */ /* Diese Funktion liest mit der Funktion EDTGET die gesamte */ /* Arbeitsdatei, und verschlüsselt jede Zeile nach dem ROT13 */ /* Verfahren (d.h. alle Buchstaben werden um 13 Zeichen verschoben */ /* Damit ergibt 2fache Verschlüsselung wieder das Original */ /* */ /* Parameter: glcb: (IN) Zeiger auf einen glcb, der für Aufrufe */ /* von IEDTGET oder IEDTPUT verwendet */ /* wird. */ /* cmd: (IN) Argumente, mit denen ROT13 aufgerufen */ /* wurde (nicht benutzt). */ /* Rueckgabewert: keiner */ /********************************************************************/
void ROT13(iedglcb *glcb,iedbuff *cmd) { char line[2048]; iedbyte key[8]; int disp; /* Lese alle Zeilen der aktuellen Arbeitsdatei */ for (disp = 1; disp < 99999999; disp++) /* -------------------- (1) */ { unsigned int j = 0; /* Naechste Zeile lesen */ edtget(glcb,(char *)&line,disp,key); if (glcb->IEDGLCB_RC_MAINCODE != 0) /* -------------------- (2) */ { glcb->IEDGLCB_RC_MAINCODE = IEDGLCBcmd_runtime_error; return; /* evtl. Meldung vom IEDTGET bleibt stehen */ } /* Wenn jenseits der letzten Zeilennummer gelesen wird */ /* gibt IEDTGET "last record" zurück */ if (glcb->IEDGLCB_RC_SUBCODE1 == IEDGLCBlast_record) break; /* Schleife verlassen */ /* Verschlüssele die Zeile */ for (j = 0; j < strlen((char *)&line); j++) { char* pos; char ch = line[j]; if (isalpha(ch)) { if (islower(ch)) pos = index(lcc,ch); else pos = index(ucc,ch); pos += 13; line[j] = *pos; } } /* Schreibe Zeile zurück */ edtput(glcb,(char *)&line,key); if (glcb->IEDGLCB_RC_MAINCODE != 0) { glcb->IEDGLCB_RC_MAINCODE = IEDGLCBcmd_runtime_error; return; /* evtl. Meldung vom IEDTPUT bleibt stehen */ } }
/* setze Subcode zurück, damit keine Meldung kommt */ glcb->IEDGLCB_RC_SUBCODE1 = 0; /* -------------------------- (3) */ } /********************************************************************/ /* Funktion: ROT13@I */ /* */ /* Aufgabe: */ /* Dies ist die Initialisierungsroutine zu ROT13. */ /* */ /* Parameter: glcb: (IN) Zeiger auf einen glcb in dem u.a. der */ /* beim Aufruf von ROT13 zu verwendende */ /* Zeichensatz festgelegt werden kann. */ /* */ /* Rueckgabewert: keiner */ /********************************************************************/ void ROT13@I(iedglcb *glcb) { glcb->indicator.compatible_format = 1; memcpy(glcb->ccsn,"EDF04F ",8); /* ROT13 erwartet EDF04F */ glcb->rc.rc_nbr = 0; } /********************************************************************/ /* Hauptprogramm */ /********************************************************************/ int main(int argc,char *argv[]) { char cmd[257]; /* Bereich zum Aufbau von EDT-Anweisungen */ int opt; extern int optind, opterr, optopt; extern char *optarg; /* Aufrufparameter auswerten */ while ((opt = getopt(argc,argv,"f:x:")) != -1) *------------- (4) */ { switch (opt) { case 'f': sprintf(cmd,"@OPEN FILE=%s",optarg); break; case 'x': sprintf(cmd,"@OPEN POSIX-FILE=%s",optarg); break; case ':': printf("Argument für -%c fehlt",optopt);
return 0; default: printf("Aufruf mit -f <file> oder -x <posix-file>"); return 0; } } /* buffer bereitstellen */ command = (iedbuff *)malloc(2048); message1 = (iedbuff *)malloc(2048); message2 = (iedbuff *)malloc(2048); edtcmd(&(cmd[0]),"",""); printrc("Fehler beim Einlesen der Datei."); /* Benutzeranweisung einrichten. MODLIB muss nicht gegeben werden.*/ edtcmd("USE COM='*',ENTRY=ROT13","",""); /* ----------------- (5) */ printrc("Fehler bei der @USE-Anweisung."); edtcmd("SETF(0);DIALOG","Beispiel 4 fuer die UP-Schnittstelle",""); printrc("Fehler bei der @SETF- oder der @DIALOG-Anweisung!"); edtcmd("HALT","",""); return 0; /* -------------- (6) */ }
Erläuterungen
(1) | 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. |
(2) | Die Fehlerbehandlung wurde aus Gründen der Übersichtlichkeit nur rudimentär implementiert. Man sollte hier zumindest noch überprüfen, ob der EDT eine Meldung zurückgegeben hat und ggf. selbst eine Meldung (mit dem Original-Returncode des EDT eintragen). |
(3) | Ein unerwarteter Returncode führt immer zur Ausgabe der Meldung EDT5410 nach Rückkehr aus der Anwenderroutine. |
(4) | Es werden die Aufrufparameter -f <dateiname> und -x <posix-dateiname> akzeptiert. |
(5) | Die Benutzeranweisung wird schon vor dem Wechsel in den Bildschirmdialog eingerichtet. Da der Entry im Programm selbst liegt, kann man auf Angabe einer Bibliothek verzichten. Da die Funktion ROT13 den übergebenen Anweisungsstring nicht auswertet, kann man sie beliebig, z.B. mit *rot oder auch nur mit * aufrufen. Ein Aufruf mit @RUN E=ROT13 ist daher ebenfalls möglich. |
(6) | Wenn das Programm "produktiv" verwendet werden soll, muss sich hier die Überprüfung auf evtl. noch geöffnete Dateien und ein entsprechender Beendigungsdialog anschließen. |
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 BEISPIEL4.C
in der Bibliothek EDT.BEISPIELE
abgelegt ist, kann das obige Programm mit
/CALL-PROC CC.DO,(4)
übersetzt und gebunden werden. Das erzeugte Progrann ist anschließend z.B. mit
/ST-EX-P (edt.beispiele,bsp4c),p-p='-f edt.test4'
ausführbar. Hier wurde bewusst extrem abgekürzt, um zu zeigen, dass mit einem solchen Starterprogramm auch im BS2000 relativ bequem der EDT direkt zum Editieren einer bestimmten Datei gestartet werden kann.
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: 1 WARNINGS: 0 ERRORS: 0 FATALS: 0 -------------- (1) % CDR9937 : MODULES GENERATED, CPU TIME USED = 3.3800 SEC % BND3102 SOME WEAK EXTERNS UNRESOLVED % BND1501 LLM FORMAT: '1' % BND1101 BINDER NORMALLY TERMINATED. SEVERITY CLASS: 'UNRESOLVED EXTERNAL' % CDR9936 : END; SUMMARY: NOTES: 1 WARNINGS: 0 ERRORS: 0 FATALS: 0 % CCM0998 CPU TIME USED: 4.6826 SECONDS
Erläuterungen
(1) Die "NOTE"
kommt zustande, weil der Aufrufparameter cmd
von ROT13
nicht angesprochen wird.
Die von diesem Beispielprogramm zu bearbeitende Datei EDT.TEST4
habe den CCS EDF04F
und sehe folgendermaßen aus:
Dies ist eine EDF04F Datei. Sie enthält alle möglichen Sonderzeichen: ÀÁ¿çÆ. Natürlich auch das € und das Å.
Dann erscheint nach Aufruf des Programms der folgende Bildschirm:
Nach Eingabe der Benutzeranweisung *rot
sieht die Ausgabe wie folgt aus: