This chapter deals with
UFORM specifications offer four places where you can call in functions of your own to customize the validation and default-value capability of mio. Three places are for validation functions, one for default functions:
Validation functions can be used to check the input in a
single field, to check values across fields, to change the
attributes of fields, or even to change the form that is
displayed on the terminal. This last operation would normally be
based on an evaluation performed in the function; if the
objective was only to change forms it would be simpler to use a
UFORM MENU or FORMEXIT statement.
The declaration of the firstval(), lastval() and field validation functions has the same format. It is:
int usrfunc(val, err, usrarg, flag, fldid, occno) char *val; /* pointer to value being validated */ char **err; /* pointer to error message or 0 */ char *usrarg; /* user argument passed to function */ int flag; /* identifies type of function */ FLDID *fldid; /* pointer to the buffer field id of this field */ int *occno; /* pointer to buffer occurrence number.*/
where:
usrfunc is the name of the function.
val points to the value of the field being validated. In calls to firstval() and lastval() functions val should be null (0), since no particular field is being validated.
err is a pointer to an error pointer. If an error is detected, err may be used to change the error pointer to point to an error message.
usrarg points to an argument string if one is needed. Its length can not exceed 11 characters.
flag is 2 for firstval(), 1 for lastval(), and 0 for field validation functions.
fldid and occno are pointers to the field id and
occurrence number of the field being validated.
firstval() is the generic name of a validation function called by the form handler program when the users exits the form, but before any other validation functions are called. It is often used to change field attributes or otherwise initialize the form. The nature and timing of the actions taken by mio depends on the value returned by the function.
lastval() is the generic name of a validation
function called after the user has left the form. It is useful
for checking for agreement among fields. For example, if a form
has a field for State and another for Zip_Code,
a user can enter values in each that would be accepted by field
validation functions, but that don't agree with each other. A State
of NY and Zip_Code of 94117 are
contradictory. Either State should be CA or
Zip_Code should start with digits in the 100-149
range.
firstval() should be written to return a 1, 2, 3 or 4 on success and a -1 on failure. The action taken by mio on receipt of the return code is shown in Table 1
if firstval returns | -1 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
then mio: | |||||
displays an error message | Y | - | - | - | - |
makes attribute changes immediately | - | Y | N | Y | N |
defers attribute changes to next form | - | N | Y | N | Y |
does field validations | - | Y | Y | N | N |
does lastval validations | - | Y | Y | N | N |
visits server before returning to user | - | Y | Y | N | N |
returns to user without visiting server | - | N | N | Y | Y |
Here is further explanation of the actions listed in Table 1:
If the validation criteria are not met, the function returns a -1. When a -1 is returned, no dynamic attribute changes are applied, no field validations are performed and lastval() is not called.
The firstval() function flag is always 2.
lastval() should be written to return a 1 or 2 on success and a -1 on failure. The action taken by mio is shown in Table 2.
if lastval returns | -1 | 1 | 2 |
then mio: | |||
displays an error message- | - | ||
makes attribute changes immediately | -N | ||
defers attribute changes to next form | - | N | Y |
The assumptions listed above following Table 1 are also in
effect for lastval().
The function must return a -1 if the field is in error and a 1 if the field is acceptable.
if the function returns | -1 | 1 |
then mio: | ||
displays an error message- | ||
allows user to go on to next field | N | Y |
If the field is found to be invalid, the function can set its err argument to point to an error message. If this is done, it overrides any value provided by the UFORM ERR specification (Error message: line on page 2 of the VARIABLE FIELD PARAMETERS form in vuform illustrated in Figure 3-12). Field validation functions are declared as shown above, except that flag is always 0.
val is a character pointer to the value in the field.
To access the values in other fields of the form the get_val()
routine can be called, or the external FML buffer pointer _gfbfr
can be referenced. These are described below.
In standard field validation functions val points to the value of the field. However for firstval() and lastval(), since no particular field is being validated, it would be inappropriate to make val point to the value in an arbitrary field. For these functions, val is always passed as null (0). Instead of accessing field values via a pointer, the firstval() and lastval() functions can call the get_val() routine, to find the value of any field on the screen. get_val() expects two arguments:
get_val() returns a read-only pointer to the field value or a (char *)0 if no value exists for the field. The pointer returned by get_val() is only valid until the next call of get_val().
In the TUXEDO System/T software get_val() is declared as follows:
char *get_val(fldid, occno) FLDID fldid; int occno;
In your firstval() or lastval() function it should be declared as:
extern char *get_val();
Another way to look at the data entered in the form is via the external variable _gfbfr. _gfbfr should be declared as follows:
#include "fml.h"; extern FBFR *_gfbfr;
_gfbfr can be read and modified with the standard FML buffer functions of the Field Manipulation Language (see the TUXEDO FML Guide). If necessary, _gfbfr can even be made larger by a call to tprealloc(). tprealloc() routine tprealloc() Modifications made to _gfbfr are reflected on the terminal on return from firstval() or lastval(). For read-only access, get_val() is preferred, since it is not FML specific.
By changing some system reserved fields in _gfbfr
it is possible to change forms and the destination service in
your firstval() or lastval() routine. (See
_gfbfr can be modified and attributes can be dynamically altered from firstval(), lastval() and standard field validation functions. However, there is some risk involved in changing system fields in the buffer in validation functions. It is easy to create confusion for the service that processes the data from the form.
There is another global variable called _gformnam, it should be declared as follows :
extern char _gformnam[];
It contains the name of the form currently shown on the screen. This global variable should be considered read-only; it should never be altered by the user program.
In the firstval() function flag is always 2,
in the lastval() function it is always 1, and in
standard field validation functions it is always 0. This
difference makes it possible to use the same function for all
three validations. You need only check flag. In all
validation functions fldid and occno are passed as
pointers. In standard field validation functions, changing their
values accomplishes nothing. However, if lastval()
returns failure, the cursor is positioned at the field designated
by *fldid and *occno. err keeps the same
meaning with all validations. That is, it should be set to point
to an error message, which is displayed if the function returns
failure. Before lastval() is called, mio
places the function key used to exit the form in the LEVKEY
system field.
The attributes associated with a field on a form can be dynamically altered by the firstval() function, the lastval() function, by a standard field validation function, or by a service. The alteration is made via a call to change_atts(). The format of the call is:
int change_atts(fbfr, fldid, occno, atts) FBFR *fbfr; /* FML buffer with screen representation*/ Fldid fldid; /* FML buffer field id */ int occno; /* occurrence number */ char *atts; /* attributes */
change_atts() adds a reserved field to the FML buffer for the screen. Depending on the return code of the function that calls change_atts(), the changes appear on the terminal immediately or are deferred to the next form.
Attributes that can be changed are shown in Table 4. The full table of attribute flag values is shown in Appendix A, Figure 4.
TYPE | Can be changed from U (unprotected) to P (protected), or vice versa. Changing the type of an L (literal) field is not allowed. |
CASE | Any of the legal flag values can be used. |
DISPLAY FEATURES | Any of the legal flag values can be used. A frequently used strategy is to highlight a field that is in error by changing the flag value to 2 (reverse video) |
Attributes other than those listed above may not be changed.
atts points to any of the FLAGS values to be changed.
For example, to change occurrence zero of LAST_NAME from an unprotected field accepting mixed case input displayed with normal intensity to unprotected, upper case, bold the function would be called as follows:
change_atts(fbfr,LAST_NAME,0,"Uu3")
atts can also point to the string "RESTORE". In this case the field will be restored to its initial attributes. Continuing with the above example, LAST_NAME could be restored to its initial attributes by:
change_atts(fbfr,LAST_NAME,0,"RESTORE")
The calls shown above also affect other occurrences of LAST_NAME on the same form that are tied to occurrence zero. change_atts() affects all fields on a form with the given fldid and occno. In the above example, if field LAST_NAME, occurrence number zero, appeared on two pages of a form, both fields would be affected by the change_atts() calls.
change_atts() has three return codes.
With the 0 return, the Ferror variable shows the cause of failure. Since change_atts() adds a field to the FML buffer, an out-of-space error is a possibility. In this case, tprealloc() should be called to enlarge the FML buffer.
If a firstval() function is changing the attributes of the form currently on the screen, then on success firstval() should return a 1 or a 3. If it is changing the attributes of a form it is about to display (by changing the FORMNAM system field), it should return a 2 or a 4.
If a lastval() function is changing the attributes
of the form currently on the screen, it should return a 1 on
success. If it is changing the attributes of a form it is about
to display (by changing the FORMNAM system field) it
should return a 2.
Default-value functions are named in a UFORM extended
descriptor statement for a variable field. Using a function to
furnish the default value for a field allows you to vary the
default value depending on a value entered by the user in some
other field. Once control has been passed to the function, the
techniques described above under
For default-value functions (specified in vuform under Default type: FUNC on page 2 of the VARIABLE FIELD PARAMETERS form illustrated in Figure 3-12), the declaration is as follows:
char *usrfunc(fldid, occno, usrarg) FLDID fldid; /* buffer field id of this field.*/ int occno; /* occurrence number of this field in buffer*/ char *usrarg; /* user argument passed to function */
The function must return a pointer to a string, which is taken
to be the default value.
User validation and default functions should be compiled with the -c option to suppress the link edit phase (see cc(1) in a UNIX programmer's reference manual). The resulting object files can then be stored in archive libraries. In general it is best to store validation functions and default-value functions in separate libraries, and to store no other external functions with them. If default functions and validation functions are stored together in one archive library or compiled together into one object file, the following naming convention must be followed:
This isn't such a bad idea even when the functions are stored in separate archive libraries; it makes them self-documenting.
The formerly-supported buildmio(1) was used to build a version of mio with user functions linked in. The -o option of buildmio can be used to assign a name to the executable file. The default name is a.out. The fact that your new version of mio has user functions linked in does not prevent you from naming it mio. However, if you do, it would be wise to save the original version under another name in case you have to backtrack.
In addition to linking user functions into mio, buildmio also gives you the capability of replacing all the literals (including error messages) output by mio, with literals of your own choosing.
You can run mio in test mode (-t option)
after you use buildmio if you want to check how the
compiled form looks and whether the validation functions perform
correctly. See
In addition to fields normally displayed on the user's screen,
there are two types of fields that are not displayed.
These are fields with a UFORM display flag of S, for secret. Secret fields are just like other fields as far as the application is concerned. Their distinguishing feature is that their contents are never displayed on the screen. Screen space is reserved for them, but characters entered into the field by the user are not echoed. If a value for a secret field is sent from the application service (presumably for use in some later validation function), the field is displayed as blank. In all other respects, the use of secret fields by an application service is just like non-secret fields.
It is worth remembering that the secret character of these
fields applies only to their display. When stored in a data base
a secret field is no more or less immune from unauthorized
viewing than an ordinary field. It is not encrypted unless your
application does it.
In addition to secret fields, the application service may send fields to the client process, mio, in the output buffer. Fields not mentioned in the UFORM definition of the form are not displayed on the screen. They are retained by mio in the screen buffer, and are subsequently input with the next mask. Such fields are commonly used to store information to be carried from one service request to another by re-entrant application functions. (The fields are, of course, defined in a field table file, as are all FML fields used in a TUXEDO System/T application.)
The use of such fields is totally application-specific, but the possible need for their existence is based on these characteristics of the TUXEDO System/T software:
This leads to a the need to be able to store information from
one visit and make it available on subsequent visits. In the
paragraphs that follow we will describe two ways of doing this.
This is the simpler of the two methods. Here is how you might go about it:
This method also assumes a field in the form buffer to carry information about a record key. Beyond that the strategy is to define a file of scratch pad records that can be created in one visit to the service and referenced in a subsequent visit.
An advantage of this method is that the amount of data stored could easily be more extensive than you might want to carry in a field in the buffer.
A disadvantage is that you need to include in the application
design some process for cleaning the file out as required.
It may be preferable to write conversational clients and
servers rather than using either of the above two methods for
carrying information from one request/response call to another.
In the conversational mode a connection between the client and
server is maintained until it is brought down, so the client can
be assured of working with a dedicated server until the task is
complete. Refer to Chapter 4
The TUXEDO System/T software includes a function called do_form(3c). do_form() acts like a simplified version of mio. The first of its two arguments is the name of a compiled form; the second is a pointer to a pointer to a fielded buffer. Use of the function is described in the BEA TUXEDO Reference Manual: Section 3c. The formal declaration is shown in Figure 1.
#include "fml.h" do_form(formname,fbfr) char *formname; FBFR *fbfr;
This section describes a variety of techniques you may need in order to write services that interface with DES. Refer to the BEA TUXEDO Programmer's Guide where the basic template of a service is described in detail.
The function declaration for service routines called by the standard main() is
usrfunc(svcinfo) TPSVCINFO *svcinfo;
where usrfunc is the name of the function and svcinfo points to the service information structure being passed to the function. This declaration should be used in all service functions. The service information structure, TPSVCINFO, is declared in atmi.h and includes the following members:
char name[32]; /* service name being invoked */ char *data; /* request data */ long len; /* request data length */ long flags; /* describes service attributes */ int cd; /* connection descriptor if (flags & TPCONV) true */ int appkey; /* application authentication client key */ CLIENTID cltid; /* client identifier for originating client */
The TPSVCINFO structure consists of a name
member that is populated with the name that the calling process
used to invoke the service, a data member that points
to a data buffer that was allocated by tpalloc(), a len
member that is set to the length of that buffer, a flags
member whose value indicates attributes that the service may want
to note, a cd member that contains a unique connection
descriptor for conversational connections, an appkey
member for authentication, and a cltid member that
identifies the originating client. The most important
characteristic of services coded to interface with the TUXEDO
System/T data entry system is that the data portion of
the message is an FML buffer. You must use FML functions in
dealing with the buffer and the fields it contains.
tprealloc() routine
The code shown in Figure 2 is an example of how you might deal with this situation.
static FBFR *fbfr . . . FBFR *newbuf = NULL /*Temporary buffer used to ensure there is enough data space left in the screen buffer*/ . . . fbfr = (FBFR *)svcinfo->data . . . /*At this point, assuming that at least 1000 bytes of unused data space is needed, allocate 1000 more bytes. Checking for that amount of unused space means having enough space in the buffer.*/ /*If the buffer has less than 1000 free bytes of data space left*/ if(Funused(fbfr) < 1000) { /*Allocate enough space for 50 additional fields and 1000 bytes of data space. */ newbuf = (FBFR*)tprealloc((char*)fbfr, svcinfo->len+1000) /* Check that return is not null. Code omitted. */ /*Copy the current data from the screen buffer to the temporary buffer. */ Fcpy(newbuf,fbfr); /* Check the return to make sure it is not < 0 */ /*Set the screen buffer to point to the temporary buffer*/ fbfr = newbuf; }
It may be useful for a TUXEDO System/T service to know which fields on a data entry form were modified by a user at a terminal. Four routines are provided for this purpose. The first, get_mods(), places in an array provided by the caller, the field ids and occurrence numbers of all modified fields in the specified buffer. Only fields that were changed through the standard input since the display of a new form are counted in the modified list. The format of the call to get_mods() is:
get_mods(fbfr,mod_array,size_mod_array) FBFR *fbfr; struct track_mods *mod_array; int size_mod_array;
fbfr points to an FML buffer that contains the data entered on the form by the user. This pointer to the FML buffer is the first argument in all four routines that provide information about modified fields. The reserved MODS field in the buffer carries the information about modified fields in an encoded format.
The second argument, mod_array, is a pointer to an array of track_mods structures. Space for this array must be allocated by the caller. The track_mods structure is defined in mods.h. Its format appears below:
#include "Fld.h" struct track_mods { FLDID fldid; /* field id of field */ int occno; /* occurrence number of field */ short flags; };
get_mods() places the field id of the modified field in fldid and the occurrence number in occno. The flags field does not contain any information of interest to the caller.
The third argument, size_mod_array, should contain
the number of track_mods structures that will fit into
mod_array. get_mods() will not place more
than size_mod_array entries in mod_array. get_mods()
returns a -1 on an error and the number of entries placed in mod_array
on success. On an error, Ferror should be checked for
the cause of the error. For this routine, a return code of zero
indicates that no fields were modified.
Before calling get_mods() you may want to find out the mod_array size needed to hold all the information that get_mods can return. For this purpose the mods_needed() routine is provided. Its format is shown below:
mods_needed(fbfr) FBFR *fbfr;
mods_needed() returns the number of entries needed
in mod_array to hold all modified field information
returned by get_mods(). It returns a -1 on an internal
failure, in which case Ferror contains the reason for
failure. The value returned by mods_needed() may be
passed directly to get_mods. If get_mods
finds a -1 in its size_mod_array parameter it will
return a 0.
While get_mods() returns all modified fields in an array, fld_mod() provides modification information about a specific field. It is called as follows:
fld_mod(fbfr, fldid, occno) FBFR *fbfr; FLDID fldid; int occno;
fld_mod returns a 1 if the field on the form
specified by fldid and occno was modified.
It returns a 0 if there was no modification and a -1 on an
internal error.
Another routine, set_mods(), enables you to force a field on the form to be considered as either modified or unmodified, regardless of its modification history. Its format is shown below:
set_mods(fbfr,fldid,occno,cmd) FBFR *fbfr; FLDID fldid; int occno; char *cmd;
set_mods() sets the modified status of all fields on a form with field identifier fldid and occurrence number occno based on cmd. cmd may be either of the strings MOD_SET or MOD_RESET. If cmd is MOD_RESET, the indicated fields will not be returned in the modified list until they are changed again. If cmd is MOD_SET, the indicated fields will always appear in the modified list until a new form is displayed or the modified field is reset with a call to set_mods(). If fldid is zero, cmd applies to all protected and unprotected fields on the form. set_mods() returns a 0 on an invalid cmd, a 1 on success and a -1 on an &F ;error (in which case the reason for the error is in Ferror). If the Ferror is FNOSPACE the caller should tprealloc() the FML buffer and try again. The FML function, Frealloc(), may be used to resize the buffer if the FML buffer is not being used as a message buffer in ATMI communication calls. tprealloc() tprealloc() routine Frealloc() (See tpalloc(3c) and Frealloc(3fml).)
A sample server that uses the above routines is in Figure 3. This server prints modified fields on the standard output, and resets all fields on the form to be unmodified.
#include <stdio.h> #include "fml.h" #include "atmi.h" #include "Usysflds.h" #include "mods.h" extern char *Fname(); extern char *malloc(); #define ERROR { sprintf(s,"FATAL ERROR");\ Fchgs(f,STATLIN, 0, s); \ tpreturn(TPFAIL,-1,NULL,0,0);\ } MOD(sinfo) TPSVCINFO *sinfo; { struct track_mods *mod_array; int i,cnt; FBFR *f; char s[100]; f = (FBFR *)sinfo->data; /* read in message from mio */ cnt=mods_needed(f); /* get the number of entries needed */ if (cnt < 0) ERROR; /* allocate space for the array */ mod_array=(struct track_mods *)malloc(cnt * sizeof(struct track_mods)); if (!mod_array) ERROR; if (get_mods(f,mod_array,cnt) < 0) ERROR; fprintf(stderr,"\n%d field(s) modified\n",cnt); for (i=0; i<cnt; i++) fprintf(stderr,"%s %d\n", Fname(mod_array[i].fldid),mod_array[i].occno); /* reset all the mods on the form */ if (set_mods(f,(FLDID)0,0,"MOD_RESET") < 1) { ERROR; } if (mod_array) free(mod_array); tpreturn(TPSUCCESS,1,f,0,0) }
The server can be built as follows:
$ buildserver -o MOD -s MOD -f MOD.c -f $TUXDIR/lib/formlib.a
As was described in Chapter 4, under
In addition to the fields explicitly described on a form, mio exchanges information with a service through system reserved fields. The list of fields is shown in Table 5.
#NAME | ID | TYPE | FLAG | COMMENT |
---|---|---|---|---|
CURSID | 2 | long | - | field id of cursor |
CURSOC | 3 | long | - | field occ no of cursor |
LEVKEY | 4 | string | - | function key used to leave form |
STATLIN | 5 | string | - | message for terminal status line |
FORMNAM | 6 | string | - | form that is (to be) displayed |
UPDTMOD | 7 | short | - | method of buffer refresh |
SRVCNM | 8 | string | - | destination service for input buffer |
NEWFORM | 9 | string | - | tells if FORMNAM is significant |
DESTSRVC | 17 | string | - | service to send the buffer to |
VALONENTRY | 19 | string | - | call validation functions when form is received |
Some of the system fields were described in Chapter 4. Those that have their greatest significance on output from a server are described here.
Like any fields used in the TUXEDO System/T software, system fields have identifying numbers. To prepare for possible expanded use of system fields in the future, the first 100 field numbers are reserved.
1. Replace the screen buffer entirely with the output buffer. 2. Modify the screen buffer using Fupdate(). 3. Modify the screen buffer using Fojoin(). mio holds the original screen buffer and sends a copy of it along to the server as the input buffer to the service function. When the service is ready to send out the results of its processing, it makes a call to Fchg() (see Fchg(3fml)) naming UPDTMOD as the field and specifying a 1, 2 or 3 for the val argument. UPDTMOD is a short, so the val argument needs to be a pointer to a short. The code might look like this:
short s; s = 1; Fchg(fbfr,UPDTMOD,0,&s,0);
The service then calls tpreturn() to send the output buffer back to mio. mio consults the val argument to determine whether the output buffer should replace the screen buffer, or update it with Fupdate() or Fojoin(). Replacing the buffer entirely (val = 1) can include changing to a different form. Fupdate() (val = 2) updates screen buffer fields with corresponding output buffer fields. Fields in the screen buffer that do not have counterparts in the output buffer are left alone. Fields in the output buffer that do not appear in the screen buffer are added. Fojoin() (val = 3) acts like Fupdate(), except that fields in the output buffer that are not in the screen buffer are discarded. Fupdate() and Fojoin() are FML functions. See Fupdate(3fml) and Fojoin(3fml) for details on how they operate.
In order for these changes to appear on the display, the validation function must return 1 (see the earlier description of firstval() and lastval()).
Since the system reserved fields reside in the FML buffer
portion of the message that mio sends to a service,
you use the same FML subroutines to access them as you would use
for the data fields in your application service routines, or in a
firstval() or lastval() function.
We have seen earlier in this chapter how you can use
#include "fml.h"; extern FBFR *_gfbfr;
to gain access to the FML buffer from a DES function. From a service, the way to get at the data that has been passed to a service as the data portion of the TPSVCINFO structure is illustrated in the following fragment.
TPSVCINFO *svcinfo; FBFR *fbfr; { . . . fbfr = (FBFR *)svcinfo->data; . . . }
The FML function to call to add a field is Fadd(). The code might look like this:
/* See if an occurrence zero of DESTSRVC exists */ if(Fpres(fbfr,DESTSRVC,0){ process the error; } /* No? Then okay to add one */ if(Fadd(fbfr,DESTSRVC,"OPEN_ACCT",0) == -1){ process the error; } . . .
Fpres() returns TRUE if the occurrence number of the Fpres() specified field exists in the buffer. Checking for the existence of an occurrence zero of DESTSRVC is one way to see if the field exists in the buffer at all. The arguments for the Fadd() call are as follows: Fadd()
fbfr | -the pointer to the buffer. |
DESTSRVC | -the FLDID of the field to be added (if an occurrence exists another is added. |
"OPEN_ACCT" | -a pointer to the value of the new field. (In this case, we're providing the literal value) |
0 | -the length because the field DESTSRVC is of type STRING. |
Fadd() returns a -1 on failure, so that is used as
a test for success in the example above.
The FML function you use to change a value in a system field is Fchg(). The code might look like this: Fchg()
if(Fchg(fbfr,DESTSRVC,0,"CLOSE_ACCT",0) == -1){ process the error; }
which says, ``In the FML buffer I'm pointing at, change
occurrence zero of the field called DESTSRVC to the
value CLOSE_ACCT.'' Again, where we used the literal CLOSE_ACCT,
we could have provided a pointer to a value. If the data type of
the value had been a CARRAY rather than a STRING,
the last argument would have given the actual length of the CARRAY.
The most frequently used function for checking the value of a system field is likely to be Fvals(), which returns Fvals() a character pointer to the string value of a field. (All the system fields except UPDTMOD, CURSID and CURSOC have a data type of string.)
Figure 4 shows how the code might look for checking what key was used to leave the form:
/*The system field LEVKEY always contains the value of the transmission key; that is, it records the value of the key sequence that was depressed when the form was completed and sent into the mio() process. The possible values of LEVKEY are <ESC> 0 (interpreted by the system as "F0") through <ESC> 9 (interpreted as "F9") and <CTRL> v (interpreted by the system as "F11"). With LEVKEY, meaning can be assigned to certain key sequences. */ char *levkval; /*Points to the value contained in the system field LEVKEY */ levkval = Fvals(fbfr,LEVKEY,0); /*In this example the possible values of LEVKEY are "F1" through "F3". Therefore, the switch can be done just on a value of 1, 2 or 3 in levkval[1] since levkval[0] == 'F' for each of the cases. */ switch(levkval[1]) { case '1': add(); break; case '2': display(); break; case '3': modify(); break; }