The following user routine is used to add numerical values in a column range in the current work file and insert the result in the last line.
The EDT functions IEDTEXE
, IEDTGET
, IEDTPUT
and IEDTPTM
are used.
/********************************************************************/ /* */ /* Example 3 */ /* */ /* This is an example of a user routine. It is declared */ /* with USE COM='*',ENTRY=*,MODLIB=EDT.BEISPIELE . */ /* Next, *sum <col1>-<col2> is used to call the SUM function */ /* and the argument <col1>-<col2> is passed. */ /* The SUM function reads all the lines in the current work file */ /* and extracts the numerical values present in the <col1>-<col2> */ /* column range. Lines containing invalid values are flagged */ /* with mark 14 (i.e. they can be overwritten). */ /* The total value is entered in the last read line. */ /* */ /* The example program performs the following individual */ /* actions: */ /* */ /* 1) Determine the required column range from the call */ /* arguments. */ /* 2) Execute a loop in which all the lines in the current */ /* work area are read and the number present in the required */ /* column range is converted into a floating point value. If */ /* this is successful, add the floating point value to the total.*/ /* If this is not successful, flag the line with mark 14 */ /* (it can then be overwritten). */ /* 4) Once this loop has terminated, the total value is entered in */ /* the last line and control returns to the caller. */ /* */ /********************************************************************/ #include <string.h> #include <stdio.h> #include <stdlib.h> #include <ctype.h> /* Include files of the EDT subroutine interface */ #define EDT_V17 #include <iedtgle.h>
/* Alternative to the fill_buff function: Macro for filling the buffer */ /* ---------------------------- (1) */ #define IEDBUFF_FILL(buf,s) \ (buf)->length = (strlen(s) + 4); \ strncpy((char *)(buf)->text,s,(size_t)((buf)->length - 4)) /********************************************************************/ /* Function: edtget */ /* */ /* Task: */ /* This function uses the subroutine interface's IEDTGET function */ /* to read a line from the current work file. The read operation */ /* is always 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 = 256; 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); /* Get current work file (from glcb) */ strncpy((char *)amcb.filename,(char *)glcb->filename,8); IEDTPUT(glcb,&amcb,key,(unsigned char *)rec); } /********************************************************************/ /* Function: edtptm */ /* */ /* Task: */ /* This function uses the IEDTPTM function to write a mark */ /* at the location designated by key. */ /* */ /* Parameter: glcb: (IN) Pointer to the glcb supplied with */ /* EDT. */ /* mark: (IN) Value of the mark that is to be written*/ /* key (IN) Pointer to a field in which the key */ /* for marking is located. */ /* Return value: none */ /********************************************************************/ 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); /* Get current work file (from glcb) */ strncpy((char *)amcb.filename,(char *)glcb->filename,8);
IEDTPTM(glcb,&amcb,key); } /********************************************************************/ /* Function: SUM */ /* */ /* Task: */ /* This function uses the etdget function to read the entire */ /* work file, extracts – for every line – the column range */ /* that was passed as an argument and attempts to convert the */ /* text present there into a floating point value. */ /* The identified numbers are added and the total value is */ /* output in the last line (where it overwrites the specified */ /* column range). */ /* Lines which do not contain a valid floating point value at the */ /* specified location are made available for overwriting with */ /* mark 14. */ /* */ /* Parameter: glcb: (IN) Pointer to a glcb which is used for */ /* IEDTGET or IEDTPUT calls */ /* cmd: (IN) Arguments with which sum was */ /* called. */ /* Return value: none */ /********************************************************************/ 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; /* Determine column range from call argument */ cmd->text[len] = '\0'; /* Set end character for 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) */ } /* @PAR PROT=ON statement, therefore mark 14 effective */ IEDBUFF_FILL((iedbuff *)command,"@PAR PROT=ON");
IEDTEXE(glcb,(iedbuff *)command); sum = 0.0; /* Read all lines in current work file */ for (disp = 1; disp < 99999999; disp++) /*----------------------- (5) */ { /* Read next line */ edtget(glcb,(char *)&line,disp,key); if (glcb->IEDGLCB_RC_MAINCODE != 0) return; /* Pass on MAINCODE unchanged */ /* If reading goes beyond the last line number then */ /* IEDTGET returns "last record" */ if (glcb->IEDGLCB_RC_SUBCODE1 == IEDGLCBlast_record) break; /* Exit loop */ /* Extract numerical value */ 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); /* Reset mark if necessary */ } else /* No valid floating point number in range */ { /* Set mark 14 – line can be overwritten */ edtptm(glcb,14,key); } } /* Set total value in last line and write it back */ sprintf(number,"%6.2f ",sum); strncpy(&line[col1 - 1],number,col2 - col1 + 1); edtput(glcb,(char *)line,key); } /********************************************************************/ /* Function: SUM@I */ /* */ /* Task: */ /* This is the initialization routine for SUM. */ /* */ /* Parameter: glcb: (IN) Pointer to a glcb which is used, for */ /* example, to specify the character set */ /* to be used when sum is called. */ /* */ /* Return value: none */ /********************************************************************/
void SUM@I(iedglcb *glcb) /* -------------------------- (6) */ { glcb->indicator.compatible_format = 1; memcpy(glcb->ccsn,"EDF04F ",8); /* sum expects EDF04F */ glcb->rc.rc_nbr = 0; }
Explanations
(1) | As an alternative to the fill_buff function from examples 1 and 2, a macro declared with #define is used here to fill the statement buffer. |
(2) | The edtptm function sets only one mark in each case. To delete a mark, it must be called with the value 0 . |
(3) | The function name is defined in uppercase because the user statement is to be declared with @USE COM='*',ENTRY=*,... and called with *sum c1 - c2 . In this case, EDT converts the first part of the user statement (the statement name) into uppercase characters (see section “Calling a user-defined statement”). |
(4) | If the call argument cannot be converted into two integer values (start and end column) then the user routine is exited with a return code. The message EDT5410 is then displayed. Naturally, other checks should be incorporated here(e.g. col1 < col2 ) and the corresponding message texts should be written. For enhanced clarity, this has not been done in the example. |
(5) | 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. |
(6) | An initialization routine has been implemented so that the call of the user routine takes place via the V17 interface using the EDF04F character set. |
If the procedure explained in the section “Producing user routines in C” is stored in a file named CCMOD.DO
in BS2000 and the source file is stored as the S element ANWEND.C
in the library EDT.BEISPIELE
then the above program can be compiled with
/CALL-PROC CCMOD.DO,(1)
and LLM ANWEND1
can be stored in the library EDT.EXAMPLES
.
If the user statement is declared with
@USE COMMAND='*',ENTRY=*,MODLIB=EDT.BEISPIELE
then the *SUM
statement can be used, for example, to add prices in a purchasing list:
The following screen is displayed when *sum 16-21
is entered: