This example illustrates the combination of a C main program and a C user routine in the same source.
Because when the @USE statement is run, EDT first searches for the specified entry with VSVI
, it finds the entry in the main program and uses this.
No dynamic loading is therefore performed.
In the example, the @USE statement is issued directly in the main program, with the result that the user statement *rot
(or similar.) is immediately available to the user.
Since the user routine does not expect any special statement string, example 4 can also act as an example of a user routine that can be called with @RUN ENTRY=ROT13.
/********************************************************************/ /* */ /* Example 4 */ /* */ /* This example illustrates the combination of a C main program */ /* with a user routine. It makes it possible to pass a */ /* file name as an argument. This file is read in before switching */ /* to the screen dialog. The user routine in the */ /* same program encrypts / decrypts all the records in the current */ /* work file using the (primitive) ROT13 procedure. */ /* */ /* The main program performs the following actions: */ /* */ /* 1) Determine the file name from the call argument. */ /* 2) Read the file using an @OPEN statement via IEDTCMD */ /* 3) Set up the user statement "*ROT13" with @USE */ /* 4) Branch to the screen dialog with @DIALOG */ /* */ /* The user routine ROT13 performs the following actions: */ /* */ /* 1) Read all the records in the current work file in a loop. */ /* 2) Encrypt each record with ROT13. */ /* 3) Write the record back to the work file with IEDTPUT */ /* */ /********************************************************************/ #include <string.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h>
/* Include files of the EDT subroutine interface */ #define EDT_V17 #include <iedtgle.h> /* Create and initialize the EDT subroutine interface data */ /* structures required for this example. */ static iedglcb glcb = IEDGLCB_INIT; static iedupcb upcb = IEDUPCB_INIT; static iedbuff *command = NULL; static iedbuff *message1 = NULL; static iedbuff *message2 = NULL; /********************************************************************/ /* Function: printrc */ /* */ /* Task: */ /* If EDT has returned an error message, then the error message */ /* is output by this function. */ /* */ /* Parameter: errmsg (IN) Pointer to the additional error */ /* message to be output if an error occurs*/ /* */ /* Return value: none */ /********************************************************************/ 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); /* Output the passed error message */ 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); /* Output EDT message */ exit(1); } }
/********************************************************************/ /* Function: fill_buff */ /* */ /* Task: */ /* This function enters content and the record length field in a */ /* record of variable length. */ /* */ /* Parameter: p: (IN) Pointer to a structure of type */ /* iedbuff, which contains the variable */ /* length record to be set. */ /* textp: (IN) Points to a string which contains the */ /* text to be entered. The length */ /* of the string implicitly defines the */ /* record length (length of string + 4). */ /* */ /* Return value: none */ /********************************************************************/ static void fill_buff(iedbuff *p,char *textp) { size_t l_text; /* Length of string */ if ((l_text = strlen(textp)) > 2044) l_text = 2044; /* Restrict length to 2044 characters */ strncpy((char *)p->text,textp,l_text); /* Enter text */ p->length = l_text + 4; /* Enter record length */ } /********************************************************************/ /* Function: edtcmd */ /* */ /* Task: */ /* This function enters the passed strings in records of */ /* variable lengths (DMS format) and then calls the EDT's */ /* CMD interface. */ /* */ /* Parameter: cmd: (IN) Pointer to a string which contains */ /* the EDT statement(s) that are to be */ /* executed. The length of the string */ /* implicitly defines the record length */ /* (String length + 4). */ /* msg1: (IN) Pointer to a string which contains the */ /* text to be entered. The length */ /* of the string implicitly defines the */ /* record length (length of string + 4). */ /* msg2: (IN) Pointer to a string which contains the */ /* text to be entered. The length */ /* of the string implicitly defines the */
/* record length (length of string + 4). */ /* */ /* Return value: none */ /********************************************************************/ 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); } /********************************************************************/ /* Function: edtget */ /* */ /* Task: */ /* This function uses the subroutine interface's GET function */ /* to read a line from the current work file. The read operation */ /* is performed relative to the record with line number 0. */ /* */ /* Parameter: glcb: (IN) Pointer to the glcb supplied with */ /* EDT. */ /* rec: (IN) Pointer to a data area in which */ /* the line read by the GET function */ /* is stored. */ /* disp: (IN) Specifies the displacement of the */ /* line to be read from line number 0. */ /* key (OUT) Pointer to a field in which the read */ /* key is stored */ /********************************************************************/ 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}; /* Enter values in IEDAMCB control block */ IEDAMCB_SET_NO_MARKS(amcb); amcb.length_key_outbuffer = 8; amcb.length_rec_outbuffer = 2044; amcb.length_key1 = 8; amcb.displacement = disp; /* read <disp> records after 0 */ /* Get current work file (from glcb) */ strncpy((char *)amcb.filename,(char *)glcb->filename,8); IEDTGET(glcb,&amcb,key1,key,rec); rec[amcb.length_rec] = 0; /* set C-string end */ }
/********************************************************************/ /* Function: edtput */ /* */ /* Task: */ /* This function uses the IEDTPUT function to write a record to */ /* the location designated by key. */ /* */ /* Parameter: glcb: (IN) Pointer to the glcb supplied with */ /* EDT. */ /* rec: (IN) Pointer to a data area in which */ /* the record to be written is passed. */ /* key (IN) Pointer to a field in which the key */ /* to be (over)written is located. */ /* Return value: none */ /********************************************************************/ 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); } /* Static data for encryption */ static char* lcc = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; static char* ucc = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"; /********************************************************************/ /* Function: ROT13 */ /* */ /* Task: */ /* This function uses the EDTGET function to read the entire */ /* work file and encrypts every line using the ROT13 encryption */ /* procedure (i.e. all the letters are moved 13 characters) */ /* As a result, performing encryption twice restores the original */ /* */ /* Parameter: glcb: (IN) Pointer to a glcb which is used for */ /* IEDTGET or IEDTPUT */ /* cmd: (IN) Arguments with which ROT13 was */ /* called (not used). */ /* Return value: none */ /********************************************************************/
void ROT13(iedglcb *glcb,iedbuff *cmd) { char line[2048]; iedbyte key[8]; int disp; /* Read all lines in current work file */ for (disp = 1; disp < 99999999; disp++) /*-------------------- (1) */ { unsigned int j = 0; /* Read next line */ edtget(glcb,(char *)&line,disp,key); if (glcb->IEDGLCB_RC_MAINCODE != 0) /* -------------------- (2) */ { glcb->IEDGLCB_RC_MAINCODE = IEDGLCBcmd_runtime_error; return; /* Any message from IEDTGET remains in place */ } /* If reading goes beyond the last line number then */ /* IEDTGET returns "last record" */ if (glcb->IEDGLCB_RC_SUBCODE1 == IEDGLCBlast_record) break; /* Exit loop */ /* Encrypt the line */ 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; } } /* Write the line back */ edtput(glcb,(char *)&line,key); if (glcb->IEDGLCB_RC_MAINCODE != 0) { glcb->IEDGLCB_RC_MAINCODE = IEDGLCBcmd_runtime_error; return; /* Any message from IEDTPUT remains in place */ } }
/* Reset subcode so that no message is issued */ glcb->IEDGLCB_RC_SUBCODE1 = 0; /* -------------------------- (3) */ } /********************************************************************/ /* Function: ROT13@I */ /* */ /* Task: */ /* This is the initialization routine for ROT13. */ /* */ /* Parameter: glcb: (IN) Pointer to a glcb which is used, for */ /* example, to specify the character set */ /* to be used when ROT13 is called. */ /* */ /* Return value: none */ /********************************************************************/ void ROT13@I(iedglcb *glcb) { glcb->indicator.compatible_format = 1; memcpy(glcb->ccsn,"EDF04F ",8); /* ROT13 expects EDF04F */ glcb->rc.rc_nbr = 0; } /********************************************************************/ /* Main program */ /********************************************************************/ int main(int argc,char *argv[]) { char cmd[257]; /* Area for the construction of EDT statements */ int opt; extern int optind, opterr, optopt; extern char *optarg; /* Evaluate call parameters */ 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; } } /* Provide buffer */ command = (iedbuff *)malloc(2048); message1 = (iedbuff *)malloc(2048); message2 = (iedbuff *)malloc(2048); edtcmd(&(cmd[0]),"",""); printrc("Fehler beim Einlesen der Datei."); /* Set up user statement. MODLIB does not have to be specified.*/ 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) */ }
Explanations:
(1) | The method for the sequential reading of the work file implemented here is not particularly effective since it is always necessary to restart the read operation from the beginning again. Readers should consider how it might be possible to develop a more effective algorithm by using the key returned in key with a constant amcb.displacement = +1. |
(2) | For reasons of clarity, there is only a rudimentary implementation of the error handling mechanisms. At this point, a check should at least be performed to determine whether EDT has returned a message and, if necessary, issue a message yourself (enter with the original EDT return code). |
(3) | An unexpected return code always results in the output of the message EDT5410 following return from the user routine. |
(4) | The call parameters -f <filename> and -x <posix-filename> are accepted. |
(5) | The user statement is set up before the switchover to the screen dialog. Since the entry is located in the program itself, it is not necessary to specify a library. Since the ROT13 function does not evaluate the passed statement string, it can be called in any desired way, for example with *rot or even just with * . A call with @RUN E=ROT13 is therefore also possible. |
(6) | If the program is to be used “productively”, a check for any files that are still open and a corresponding close dialog must be added here. |
If the procedure explained in the section “Producing main programs in C” is stored in a file named CC.DO
in BS2000 and the source file is stored as the S element BEISPIEL4.C
in the library EDT.BEISPIELE
then the above program can be compiled and linked with
/CALL-PROC CC.DO,(4).
The generated program can then be executed, for example, using
/ST-EX-P (edt.beispiele,bsp4c),p-p='-f edt.test4'
This representation is deliberately highly abbreviated in order to demonstrate that this type of starter program can also be used in BS2000 to start EDT relatively easily in order to edit a given file.
When CC.DO
runs, the following or similar output is generated by the system or the compiler:
% 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
Explanations
(1) The “NOTE”
occurs because the call parameter cmd
is not addressed by ROT13
.
Let us assume that the file to be processed by this example program EDT.TEST4
has the CCS EDF04F
and resembles the following:
Dies ist eine EDF04F Datei. Sie enthält alle möglichen Sonderzeichen: ÀÁ¿çÆ. Natürlich auch das € und das Å.
When the program is called, the following screen is displayed:
After entry of the *rot
user statement, the output is as follows: