home *** CD-ROM | disk | FTP | other *** search
-
- (c)Copyright Sequiter Software Inc., 1987-1990. All rights reserved.
-
-
- Parsing and Evaluating Additional Functions
-
- The expression evaluation module of Code Base parses and evaluate
- dBASE expressions. It is not difficult to modify the expression
- evaluation module to support user defined functions or
- dBASE/Clipper/FoxPro functions not currently defined. Alternately,
- you can remove existing ones to make EXE files slightly smaller.
-
- In order to understand the following documentation, you need to understand
- dBASE expressions and the Code Base expression evaluation routines.
-
- To add a user defined function which is recognized by the Code Base
- expression evaluation routines, do the following:
-
- 1. Write the User Defined Function
- 2. Make an entry in the structure array 'v4functions'. This array
- is located in file 'e4functions.c'.
- 3. Rebuild the Code Base 4 library leaving out file 'e4functions.c'.
- Depending on your compiler, this step may not be necessary.
- For example, when using Turbo C you just need to add 'e4functions.c'
- to your project file.
- 4. Compile and Link your program explicitly compiling and linking
- in Code Base source file 'e4functions.c'.
- 5. Test the user defined function by calling 'e4parse' and 'e4exec.'.
-
- User Defined Functions return a void and have a structure array
- of type 'E4PARM' as a parameter.
-
- Example
-
- void e4upper( parms )
- E4PARM parms[1] ;
- {
- /* Call 'e4return_len' to make sure that there is enough
- space of the 'evaluation' stack to return the result. */
- if ( e4return_len( parms, parms[0].len+1 ) < 0 ) return ;
-
- parms[0].p.c[parms[0].len] = '\0' ;
- strupr( parms[0].p.c ) ;
- }
-
- The following 'v4functions' entry would be used to tell Code Base 4
- about the above user defined function:
-
- {280, 5,"UPPER", e4upper, 0, T_STR, 1, T_STR },
-
- As a result of this entry, the following Code Base
- call works:
-
- i4index( "I_NAME", "UPPER(CHAR_FLD)", 0, 0 ) ;
-
- or
-
- printf( "\n Result: %s", e4eval( "UPPER(CHAR_FLD)" ) ) ;
-
- dBASE Function 'UPPER' converts a character value to upper case.
-
- The purpose of the 'v4functions' entry is to tell routine 'e4parse'
- which dBASE function character sequence corresponds with which C function.
- Consequently, 'e4exec' calls the correct C routine. In addition, the entry
- specifies the dBASE function parameter and return information. This allows
- 'e4parse' to do most of the error checking. Consequently, the User Defined
- Functions can make assumptions about its parameters.
-
- dBASE field types are associated with the following integer constants
- defined in 'e4parse.h':
-
- dBASE Type Define Name Define Integer Value C Format
-
- CHAR T_STR (int) 'C' Characters
- DATE T_DATE_DOUB (int) 'd' Julian Double
- NUMERIC T_NUM_DOUB (int) 'N' Double
- FLOAT T_NUM_DOUB (int) 'N' Double
- LOGICAL T_LOG (int) 'L' Integer
-
- If you examine 'e4functions.c' or 'e4parse.h' you may notice that
- pre-defined Code Base user defined functions sometimes pass Numerics, Dates,
- and Floats as strings. Avoid this as it is slightly more complicated and is
- not formally documented.
-
- It is easy to add your own functions to be recognized by the expression
- evaluation routines. The source file to modify is 'e4functi.c'. You
- need to make an entry is the static array 'v4functions'. Each entry
- in 'v4functions' is a structure of type 'E4FUNCTIONS':
-
- typedef struct
- {
- int code ;
- int name_len ;
- char name[12] ;
- void (*function_ptr)( E4PARM *) ;
- int priority ;
- int return_type ;
- int num_parms ; /* 0 - No Return; -1 First Parm. Specifies # */
- int type[MAX_PARMS]; /* type[0] is the return type */
- } E4FUNCTIONS ;
-
-
- Following is a description of each member of structure 'E4FUNCTIONS':
-
- code
-
- The is a unique number corresponding to the function name. This unique,
- number should be different from the 'code' corresponding to other function
- names. For example, if the last
- function defined has a code value of '290', make the code value of the new
- function a number slightly bigger.
-
- name_len
-
- This is the number of characters in the function name. It should be
- less than twelve.
-
- name
-
- This is the name of the user defined function. The name must have
- be less than twelve characters long.
-
- function_ptr
-
- This is the corresponding C function. Refer to the above example
- for the syntax.
-
- priority
-
- This value is always zero for user defined functions.
-
- return_type
-
- This is the dBASE type of the return. Refer to the predefined
- constants specified above.
-
- num_parms
-
- This is the number of parameters for the user defined function. Routine
- 'e4parse' verifies that the actual number of parameters against
- this number. By default constant 'MAX_PARMS' is three. This
- There is a maximum of three parameters.
-
- type[MAX_PARMS]
-
- This is the dBASE type of each parameter. The
- integer constants corresponding to each dBASE type are specified
- above.
-
- The prototype for the C routines corresponding
- to the user defined function is as follows:
-
- void c_function_name( E4PARM *parms )
-
- This is the definition of structure E4PARM:
-
- typedef struct
- {
- union
- {
- void *v ;
- char *c ; /* For Character Parameters. */
- int *i ; /* For Logical Parameters. */
- long *l ;
- double *d ; /* For Numeric and Date parameters of Type Double. */
- } p ; /* Pointer to the parameter */
- int type ; /* The type of the parameter */
- int len ; /* The number of bytes in the parameter */
- } E4PARM ;
-
- There is an array element passed for each parameter. For example,
- if the type of the second User Defined Function parameter is T_NUM_DOUB,
- then '*parms[1].d' refereces the parameters 'double' value. The
- C function returns the User Defined Function result through the first
- parameter.
-
- Following is the definition of the C routine corresponding to
- dBASE function 'VAL'. 'VAL' takes a Character parameter and
- returns a Numeric result.
-
- /* C routine 'e4val' corresponds to the following 'e4functions' entry:
- {290, 3,"VAL", e4val, 0, T_NUM_DOUB, 1, T_STR },
- */
-
- void e4val( parms )
- E4PARM parms[1] ;
- {
- /* 'e4return_len' should be called to verify that there is enough
- space on the internal Code Base stack for the return value. */
- if ( e4return_len(parms, (int) sizeof(double)) < 0 ) return ;
-
- /* Since the parameter is specified as type 'T_STR', the parameter
- is formatted as ASCII characters. Consequently, it is
- conveniently accessed through 'parms[0].p.c'. The number
- of characters is specified by 'parms[0].len'. Since the result
- is specified as 'T_NUM_DOUB', it is formatted as a double.
- The length of the result is placed in 'parms[0].len' and the
- type of the result is placed in 'parms[0].type'. */
- *parms[0].p.d = c4atod( parms[0].p.c, (int) parms[0].len ) ;
- parms[0].len = sizeof(double) ;
- parms[0].type = T_NUM_DOUB ;
- }
-
- There is a Code Base defined integer variable named 'v4original_base_ref'.
- It contains the reference number of the database which was selected when
- the dBASE expression was originally parased. This variable is defined
- as an 'extern int' in file 'e4functions.c'.
-
- Notice that the same C function can correspond to more than one
- dBASE function. For example, under Code Base, "DTOS" and "DTOC"
- do exactly the same thing. Consequently, both 'v4functions' entries map to
- the same C function.
-
- {180, 4,"DTOS", e4dtoc, 0, T_STR, 1, T_DATE_STR },
- {185, 4,"DTOC", e4dtoc, 0, T_STR, 1, T_DATE_STR },
-
- Another different example is dBASE function "IIF". This function
- takes more than one possible parameter configuration. There
- is an entry in 'v4functions' for each of these possible configurations.
- Each of these entries must be adjacent to one another.
-
- {220, 3,"IIF", e4iif, 0, T_STR, 3, T_LOG, T_STR, T_STR },
- {220, 3,"IIF", e4iif, 0, T_NUM_DOUB, 3, T_LOG, T_NUM_DOUB, T_NUM_DOUB },
- {220, 3,"IIF", e4iif, 0, T_LOG, 3, T_LOG, T_LOG, T_LOG },
- {220, 3,"IIF", e4iif, 0, T_DATE_DOUB, 3, T_LOG, T_DATE_DOUB, T_DATE_DOUB },
-
- In the Code for 'e4iif', the values placed in 'parms[0].type'
- is dependent on the parameter type. Conseqently, the function is
- consistent with each parameter configuration:
-
- void e4iif( parms )
- E4PARM parms[3] ;
- {
- E4PARM *ptr ;
-
- if ( *parms[0].p.i )
- ptr = parms+1 ;
- else
- ptr = parms+2 ;
-
- memmove( parms[0].p.c, ptr->p.c, ptr->len ) ;
-
- parms[0].type = ptr->type ;
- parms[0].len = ptr->len ;
- }
-
- Note that instead of a single 'e4iif' C routine, there could have been
- a different C routine for each parameter configuration.