Adding a User Function

This section provides an overview of the ufunc.c file and discusses how to:

  • Add a function prototype.

  • Add an entry to the USERFUNCS table.

  • Add implementation code.

  • Relink SQR.

The code examples in the following sections demonstrate how to extend SQR with an initcap function.

The key to this process is an SQR source file called ufunc.c. This file contains a list of user-defined functions. It also contains comments with a description of the process of adding a function to SQR. Ufunc.c is in the lib subdirectory (LIBW in Microsoft Windows).

To add initcap to SQR, you must add it to a global array called userfuncs in ufunc.c.

Begin by adding a function prototype to the function declaration list:

static void max CC_ARGS((int, double *[], double *));
static void split CC_ARGS((int, char *[], double *));
static void printarray CC_ARGS((int, char*[], double *));
static void initcap CC_ARGS((int, char *[], char *, int));

The preceding code segment is taken from the ufunc.c file. The first three lines are part of the original ufunc.c file. The line that adds the initcap function is shown like this. The modified version of ufunc.c is in the LIBW (Microsoft Windows) or LIB (UNIX) directory under <PS_HOME>\bin\sqr\<database_platform>.

This code defines a prototype for a C function called initcap. The prototype is required by the C compiler. The name of the C function does not have to be the same as the name of the SQR function. The SQR name for the function is defined in the next step.

The CC_ARGS macro makes the code portable between compilers that expect full prototyping and compilers in which the argument prototype is omitted. You could also write:

static void initcap();

Note also that the STATIC keyword means that the code for initcap will be added in the file ufunc.c. If you have the code in a separate file, remove the STATIC keyword.

The first argument of the C function is the argument count of the corresponding SQR function. In the case of initcap, this argument count should be 1 because initcap takes exactly one argument.

The second argument of the C function is an array of pointers. This array is the argument list. In this case, because initcap takes only one argument, only the first pointer is actually used.

The third argument of the C function is a pointer to the result buffer. Because initcap returns a string, it is defined as char*.

The last argument sets the maximum length of the result string. The length of this string is the size of the result buffer, which you must not overflow. You cannot return a value that is longer than the maximum length. The maximum length is typically around 2000 bytes, depending on the platform.

The next step is to define the initcap function to SQR. As stated before, this table exists in the ufunc.c file. Here is the modified code:

} userfuncs[] =
 {
 /* (2) Define functions in userfuncs table:
                           Number of 
 Name          Return_type Arguments Arg_Types Function
 ----          ----------- --------- --------- -------- */
 "max",        'n',        0,        "n",      PVR max,
 "split",      'n',        0,        "C",      PVR split,
 "printarray", 'n',        4,        "cnnc",   PVR printarray,
 "initcap",    'c',        1,        "c",      PVR initcap,
 /* Last entry must be NULL do not change */
 "", '\0', 0, "", 0
};

The userfuncs table is an array of structures. The added line is shown like this, and it initializes one structure in the array. The line contains five arguments, which correspond to the five fields of the structure.

The first argument is the name of the SQR function that is being added. This is the name that you will use in the LET, IF, and WHILE commands. The second argument is the return type, which 'c' (enclosed in single quotation marks) indicates is a character string. The third argument is the number of arguments that initcap will take. Set it to 1.

The fourth argument is a string representing the types of the arguments. Because initcap has only one argument, the string contains one character enclosed in double quotation marks, "c". This character indicates that the argument for initcap is a string. The last argument is a pointer to a C function that implements the SQR function that you are adding. This argument is the initcap function for which we have provided a prototype in the previous step. Note that the PVR macro provides proper cast for the pointer.

The next step is to add the implementation code for initcap. You can insert it into the ufunc.c file.

Note: To put the code in a separate file, you must remove the STATIC keyword from the prototype. You may also need to include standard C header files, such as CTYPE.H.

Here is the code that is inserted at the end of ufunc.c:

static void initcap CC_ARGL((argc,argv,result,maxlen))
CC_ARG(int, argc)       /* Number of actual arguments */
CC_ARG(char*, argv[])   /* Pointers to arguments: */
CC_ARG(char*, result)   /* Where to store result */
CC_LARG(int, maxlen)    /* Result's maximum length */
{
  int flag = 1;
  char *ptr;
  char *p;
  ptr = argv[0];
  p = result;
  while (*ptr) {
    if (ptr - argv[0] >= maxlen) break; /* don't exceed maxlen */
    if (isalnum(*ptr)) {
       if (flag) *p = islower(*ptr)?toupper(*ptr):*ptr;
       else *p = isupper(*ptr)?tolower(*ptr):*ptr;
       flag = 0;
    } else {
       flag = 1;
       *p = *ptr;
    }
     p++; ptr++;
  }
  *p = '\0';
  return;
}

Note the use of the CC_ARGL, CC_ARG, and CC_LARG macros. You can also write the code as follows (only the first five lines are shown):

static void initcap(argc,argv,result,maxlen)
int argc;       /* Number of actual arguments */
char* argv[];   /* Pointers to arguments: */
char* result;   /* Where to store result */
int maxlen;     /* Result's maximum length */

After you modify ask, you must relink SQR. Use the make file that is provided in the LIB (or LIBW) subdirectory of SQR. This step is specific to the operating system and database. SQR is linked with the database libraries, whose names and locations may vary. You may have to modify the make file for your system.

After SQR is relinked, you are ready to test. Try the following program:

begin-program
  let $a = initcap('MR. JOSEPH JEFFERSON')
  print $a ()
end-program

The result in the output file should be:

Mr. Joseph Jefferson

See the ufunc.c file for further information about argument types in user-defined functions.

See the product documentation for PeopleSoft 9.2 Application Installation.