home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************
- ** ^FILE: argtype.c - argument type definitions for parseargs(3)
- **
- ** ^DESCRIPTION:
- ** This file implements the argument conversion functions for
- ** converting string, character, integer, floating-point,
- ** boolean, and pseudo-arguments, from command-line strings.
- **
- ** ^HISTORY:
- ** 01/03/91 Brad Appleton <brad@ssd.csd.harris.com>
- ** - Added structured block comments
- ** - Added argUsage & argDummy dummy-functions
- ** - Added argSBool, argTBool, and argUBool
- ** - Added ARGVEC handling to all necessary functions
- ** - Added argInput & argOutput for VMS
- ** - put floating-point routines (argFloat & argDouble) into
- ** this file (they may be excluded by #defining NOFLOAT)
- ** - changed routines to return negative values (where appropriate)
- **
- ** --/--/-- Peter da Silva <peter@ferranti.com>
- **
- ** --/--/-- Eric P. Allman <eric@Berkeley.EDU> Created
- ***^^**********************************************************************/
-
- #include <ctype.h>
- #include <useful.h>
- #include "strfuncs.h"
-
- #define PARSEARGS_NARGTYPES /* exclude arg-type externs */
- #include "parseargs.h"
-
- #ifdef __ANSI_C__
- # define PARMS(ad,vp,copyf) \
- ( register ARGDESC *ad, register char *vp, BOOL copyf )
- #else
- # define PARMS(ad,vp,copyf) \
- ( ad, vp, copyf ) register ARGDESC *ad; register char *vp; BOOL copyf;
- #endif
-
- #define REALLOC(ptr,size) (( ! ptr ) ? malloc(size) : realloc(ptr, size) )
- EXTERN VOID syserr ARGS((const char *, ...));
- EXTERN VOID usrerr ARGS((const char *, ...));
-
- #ifndef __ANSI_C__
- EXTERN long strtol ARGS((char *, char **, int));
- EXTERN double strtod ARGS((const char *, char **));
- #endif
-
- /***************************************************************************
- ** ^FUNCTION: argtype -- argument translation routines.
- **
- ** ^SYNOPSIS:
- ** BOOL argUsage( ad, vp, copyf )
- ** BOOL argEnd( ad, vp, copyf );
- ** BOOL argDummy( ad, vp, copyf );
- ** BOOL argBool( ad, vp, copyf );
- ** BOOL argSBool( ad, vp, copyf );
- ** BOOL argUBool( ad, vp, copyf );
- ** BOOL argTBool( ad, vp, copyf );
- ** BOOL argChar( ad, vp, copyf );
- ** BOOL argStr( ad, vp, copyf );
- ** BOOL argInt( ad, vp, copyf );
- ** BOOL argShort( ad, vp, copyf );
- ** BOOL argLong( ad, vp, copyf );
- ** BOOL argFloat( ad, vp, copyf );
- ** BOOL argDouble( ad, vp, copyf );
- ** BOOL argInput( ad, vp, copyf );
- ** BOOL argOutput( ad, vp, copyf );
- **
- ** ^PARAMETERS:
- ** ARGDESC *ad;
- ** -- the argument descriptor for this parameter.
- **
- ** char *vp;
- ** -- a pointer to the string input value.
- **
- ** BOOL copyf;
- ** -- if TRUE, the value will be destroyed later, and so should be copied
- ** if it will be retained (as for a string).
- **
- ** ^DESCRIPTION:
- ** Each of these converts a parameter value to the internal form, includ-
- ** ing validity checking. Their parameters and return values all behave
- ** similarly. One of these routines is called when an argument of that
- ** particular type is matched by one of the argument parsing function in
- ** parseargs(3). When such an argument is matched, its argument transla-
- ** tion routine is invoked and is passed (1) the address of the argument
- ** descriptor for the matched argument, (2) the possible argument string
- ** for that matched argument, and (3) a boolean field that is TRUE only
- ** if the second parameter points to temporary storage (indicating that
- ** some copying may need to be done instead of just pointing to the same
- ** object).
- **
- ** Once the argument translation routine is invoked, it is responsible
- ** for converting the argument string to the desired internal form
- ** (perhaps a number), and assigning the resultant value to the
- ** arg_valp(ad) field of the argument descriptor (this includes handling
- ** any necessary (re)allocation if the matched argument has the ARGVEC
- ** flag enabled). If the argument is an ARGVEC or ARGLIST then the rou-
- ** tine is responsible for allocating any space, copying the arg-flags to
- ** the value-specific flags, and setting the ARGCOPYF flag for the value
- ** if it needs to be allocated as well.
- **
- ** ^REQUIREMENTS:
- ** ARGKEYWORD should be set if the argument was matched via its
- ** string name (as opposed to by its character name).
- **
- ** ARGVALSEP should be set is the argument value was in a separate
- ** argv element from the argument string-name (or character name).
- **
- ** ^SIDE-EFFECTS:
- ** The value used should be stored in the location indicated by arg_valp(ad).
- **
- ** ^RETURN-VALUE:
- ** TRUE : if the conversion was successful and the entire value was used.
- **
- ** FALSE : if the conversion failed. The reason for failure should be
- ** diagnosed using usrerr().
- **
- ** -N : if the conversion was successful but only N characters of the value
- ** were used, the remaining characters may still match other arguments.
- **
- ** ^ALGORITHM:
- ** Function-specific, but the basic idea is as follows:
- **
- ** - convert the value-string into the desired type
- ** - if the value is invalid call usrerr and return FALSE
- ** end-if
- ** - if this ad is an ARGVEC
- ** - expand the vector and insert the new item at the end
- ** - update the item count
- ** - else
- ** - set *ad_valp to the converted value
- ** end-if
- ** - return TRUE if we used the whole arg, -N if we only used N-characters
- ***^^**********************************************************************/
-
- /* vector types and defines */
- #define BLOCKSIZE 5 /* number of items to allocate at once */
- #define VEC_SIZE(vec,el_typ) ( sizeof(el_typ *) * (BLOCKSIZE + vec->count) )
- typedef ARGVEC_T(char *) strvec_t;
- typedef ARGVEC_T(char) charvec_t;
- typedef ARGVEC_T(int) intvec_t;
- typedef ARGVEC_T(short) shortvec_t;
- typedef ARGVEC_T(long) longvec_t;
- typedef ARGVEC_T(float) floatvec_t;
- typedef ARGVEC_T(double) doublevec_t;
-
-
- /***************************************************************************
- ** ^SECTION: PSEUDO-TYPES -- argUsage, argEnd, argDummy
- ** ArgUsage is used to specify an argument that causes the command
- ** usage to be printed.
- **
- ** ArgDummy is used to force an item to show up in usage-messages but
- ** the item itself is never matched against any arguments from the
- ** command-line.
- **
- ** ArgEnd is used by amiga_args.c and vms_args.c to indicate an argument
- ** that forces all remaining arguments to be considered positional args.
- **
- ** These three are dummy functions. The routines themselves do nothing
- ** of importance, we just need to have their addresses available for
- ** identification in the corresponding <os>_args.c file.
- ***^^**********************************************************************/
-
- /*ARGSUSED*/
- BOOL argDummy PARMS(ad, vp, copyf)
- {
- return FALSE;
- }
-
-
- /*ARGSUSED*/
- BOOL argEnd PARMS(ad, vp, copyf)
- {
- return (FALSE);
- }
-
-
- /*ARGSUSED*/
- BOOL argUsage PARMS(ad, vp, copyf)
- {
- return FALSE;
- }
-
-
- /***************************************************************************
- ** ^SECTION: STRING-TYPES -- argStr
- ** ArgStr is one of the few argument translation routines that actually
- ** uses the <copyf> flag. If <copyf> is true then the string is duplicated.
- **
- ** ArgStr assigns the given string (or a copy of it) to the value referenced
- ** by arg_valp(unless the argument is a vector in which case the given string
- ** is appended to the end).
- **
- ** ArgStr ensures that the very last item in a vector of strings (the one
- ** accessed as vec.array[ vec.count ]) will always be NULL.
- ***^^**********************************************************************/
-
- /*ARGSUSED*/
- BOOL argStr PARMS(ad, vp, copyf)
- {
- char *cp;
- argName_t argname;
-
- (VOID) get_argname( arg_sname(ad), argname );
- if (copyf) {
- register int i;
-
- i = strlen(vp) + 1;
- cp = (char *) malloc(i * sizeof(char));
- if (!cp) {
- usrerr("out of memory parsing %s", argname);
- return FALSE;
- }
- memcpy(cp, vp, i);
- }
- else
- cp = vp;
-
- if ( ARG_isVEC(ad) ) {
- strvec_t *vec = (strvec_t *)arg_valp(ad);
-
- if ( (vec->count % BLOCKSIZE) == 0 ) {
- vec->array = (char **) REALLOC(vec->array, 1+VEC_SIZE(vec, char *));
- if ( !vec->array ) {
- if ( copyf ) free(cp);
- syserr("out of memory saving arg %s", argname);
- }
- vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t));
- if ( !vec->flags ) {
- syserr("out of memory saving arg %s", argname);
- }
- }
-
- vec->flags[ vec->count ] = arg_flags(ad);
- if ( copyf ) BSET( vec->flags[vec->count], ARGCOPYF );
- vec->array[ (vec->count)++ ] = cp;
- vec->array[ vec->count ] = (char *)NULL;
- }
- else
- *(char **) arg_valp(ad) = cp;
-
- return (TRUE);
- }
-
-
- /***************************************************************************
- ** ^SECTION: CHARACTER-TYPES -- argChar
- ** ArgChar assigns the given character to the value referenced by ad_valp
- ** (unless the argument is a vector in which case the given character
- ** is appended to the end).
- **
- ** If an argChar argument is matched as a single character option, then
- ** the immediately following character will be considered its argument
- ** (but the characters after it may still be processed as option-letters).
- **
- ** ArgChar ensures that the very last item in a vector of character (the
- ** one accessed as vec.array[ vec.count ]) will always be a NUL byte so
- ** that the resulting vector may also be used as a NULL terminated string.
- **
- ** Unlike argStr, argChar will translate character escape sequences such
- ** as '\n' and '\012'.
- ***^^**********************************************************************/
-
- /*ARGSUSED*/
- BOOL argChar PARMS(ad, vp, copyf)
- {
- auto char *vpp;
- argName_t argname;
- int status = FALSE;
- char c;
-
- (VOID) get_argname( arg_sname(ad), argname );
- if (!vp || !*vp) {
- status = FALSE;
- }
- if (strlen(vp) == 2 && vp[0]=='^') {
- c = vp[1] ^ '@';
- status = TRUE;
- }
- else if (strlen(vp) > 1 && vp[0]=='\\') {
- c = (int) strtol(&vp[1], &vpp, 8);
- if (*vpp == '\0')
- status = TRUE;
- }
- else if (strlen(vp) == 1) {
- c = *vp;
- status = TRUE;
- }
- else if ( !BTEST(arg_flags(ad), ARGVALSEP | ARGKEYWORD) ) {
- c = *vp;
- status = TRUE;
- }
-
- if ( status ) {
- if ( ARG_isVEC(ad) ) {
- charvec_t *vec = (charvec_t *)arg_valp(ad);
-
- if ( (vec->count % BLOCKSIZE) == 0 ) {
- vec->array = (char *) REALLOC(vec->array, 1+VEC_SIZE(vec, char));
- if (!vec->array) syserr("out of memory saving arg %s", argname);
- }
- vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t));
- if ( !vec->flags ) {
- syserr("out of memory saving arg %s", argname);
- }
-
- vec->flags[ vec->count ] = arg_flags(ad);
- vec->array[ (vec->count)++ ] = c;
- vec->array[ vec->count ] = '\0';
- }
- else
- *(char *) arg_valp(ad) = c;
- }
- else {
- usrerr("invalid character argument '%s' for %s",
- vp, argname);
- }
- return (status) ? (BOOL) -1 : FALSE;
- }
-
-
- /***************************************************************************
- ** ^SECTION: INTEGER-TYPES -- argInt, argShort, argLong
- ** Each of these functions converts the given string to the desired
- ** integral type. The value may be specified as an octal number by
- ** specifying the first digit to be 0. Similarly, If the first two
- ** characters are '0x' then the number is treated as hexadecimal.
- ***^^**********************************************************************/
-
- /*
- ** macro to define an integral argtype function
- **
- ** NOTE : do NOT use a terminating semicolon when invoking this macro!
- */
- #define INTEGRAL_ARGTYPE(name,num_t,ls_t) \
- BOOL name PARMS(ad, vp, copyf) \
- { \
- auto char *vpp; \
- argName_t argname; \
- num_t value; \
- \
- (VOID) get_argname( arg_sname(ad), argname ); \
- value = (num_t) strtol(vp, &vpp, 0); \
- if (*vpp != '\0') { \
- usrerr("invalid integer argument '%s' for %s", vp, argname); \
- return (FALSE); \
- } \
- else { \
- if ( ARG_isVEC(ad) ) { \
- ls_t *vec = (ls_t *)arg_valp(ad); \
- \
- if ( (vec->count % BLOCKSIZE) == 0 ) { \
- vec->array = (num_t *) REALLOC(vec->array, VEC_SIZE(vec, num_t)); \
- if ( !vec->array ) \
- syserr("out of memory saving arg %s", argname); \
- \
- vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t)); \
- if ( !vec->flags ) \
- syserr("out of memory saving arg %s", argname); \
- } \
- \
- vec->flags[ vec->count ] = arg_flags(ad); \
- vec->array[ (vec->count)++ ] = value; \
- } \
- else \
- *(num_t *) arg_valp(ad) = value; \
- \
- return (TRUE); \
- } \
- }
-
-
- /* define argInt() */
- INTEGRAL_ARGTYPE( argInt, int, intvec_t )
-
- /* define argShort() */
- INTEGRAL_ARGTYPE( argShort, short, shortvec_t )
-
- /* define argLong() */
- INTEGRAL_ARGTYPE( argLong, long, longvec_t )
-
-
- #ifndef NOFLOAT
-
- /***************************************************************************
- ** ^SECTION: FLOATING-POINT-TYPES -- argFloat, argDouble
- ** Each of these functions converts the given string to the desired
- ** floating-point type.
- ***^^**********************************************************************/
-
- /*
- ** macro to define a decimal argtype function
- **
- ** NOTE : do NOT use a terminating semicolon when invoking this macro!
- */
- #define DECIMAL_ARGTYPE(name,dec_t,ls_t) \
- BOOL name PARMS(ad, vp, copyf) \
- { \
- auto char *vpp; \
- argName_t argname; \
- dec_t value; \
- \
- (VOID) get_argname( arg_sname(ad), argname ); \
- value = (dec_t) strtod(vp, &vpp); \
- if (*vpp != '\0') { \
- usrerr("invalid decimal argument '%s' for %s", vp, argname); \
- return (FALSE); \
- } \
- else { \
- if ( ARG_isVEC(ad) ) { \
- ls_t *vec = (ls_t *)arg_valp(ad); \
- \
- if ( (vec->count % BLOCKSIZE) == 0 ) { \
- vec->array = (dec_t *) REALLOC(vec->array, VEC_SIZE(vec, dec_t)); \
- if (!vec->array) \
- syserr("out of memory saving arg %s", argname); \
- \
- vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t)); \
- if (!vec->flags) \
- syserr("out of memory saving arg %s", argname); \
- } \
- \
- vec->flags[ vec->count ] = arg_flags(ad); \
- vec->array[ (vec->count)++ ] = value; \
- } \
- else \
- *(dec_t *) arg_valp(ad) = value; \
- \
- return (TRUE); \
- } \
- }
-
- /* define argFloat */
- DECIMAL_ARGTYPE( argFloat, float, floatvec_t )
-
- /* define argLong */
- DECIMAL_ARGTYPE( argDouble, double, doublevec_t )
-
- #endif /* NOFLOAT */
-
-
- /*************************************************************************
- ** ^SECTION: BOOLEAN-TYPES -- argBool, argSBool, argUBool, argTBool
- ** ArgBool and argSBool set a boolean value (if no value is given).
- ** ArgUBool unsets a boolean value (if no value is given). ArgTBool
- ** toggles a boolean value (if no value is given). If a value is
- ** supplied to any of these routines, then the string is looked up
- ** in a table and assigned the corresponding value.
- **
- ** If a value is supplied for an argument that was matched via its
- ** single character name and is part of the same argv element as the
- ** argument-name (so that both ARGKEYWORD and ARGVALSEP are not set),
- ** then only the first character of the value is used (unless it is
- ** not found in our table, in which case the value is ignored and the
- ** default action is taken).
- **
- ** The only possible arguments for single-character options are the
- ** following:
- **
- ** 1, + set the flag
- ** 0, - unset the flag
- ** ^, ~ toggle the flag
- **
- ** The possible argument strings for long-options (keywords) are as
- ** follows (case-insensitive):
- */
-
- /* define a structure for an item in our boolean-lookup table */
- struct booltab {
- char *bname; /* string to match against */
- char bneedmatch; /* number of characters that must match */
- BOOL bval; /* value to use */
- };
-
- /* define the boolean-lookup table */
- STATIC struct booltab _BoolTab[] = {
- "1", 1, TRUE,
- "0", 1, FALSE,
- "+", 1, TRUE,
- "-", 1, FALSE,
- "yes", 1, TRUE,
- "no", 1, FALSE,
- "true", 1, TRUE,
- "false", 1, FALSE,
- "on", 2, TRUE,
- "off", 3, FALSE,
- CHARNULL
- };
-
- /**^^**********************************************************************/
-
-
- /*
- ** NOTE: Lists and vectors of Boolean types are not supported!!!
- ** (same goes for argEnd, argInput, & argOutput)
- */
-
- /*ARGSUSED*/
- BOOL argBool PARMS(ad, vp, copyf)
- {
- register struct booltab *b;
- register char *cp;
- argName_t argname;
- int len;
-
- (VOID) get_argname( arg_sname(ad), argname );
-
- /* ARGVECs are not supported for this Boolean arg-types */
- if ( ARG_isVEC(ad) )
- syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
- argname );
-
- /* if vp is NULL, just set to TRUE
- ** (needed for backward compatibility)
- */
- if ( !vp || !*vp ) {
- *(BOOL *) arg_valp(ad) = TRUE;
- return (TRUE);
- }
-
- /* allow single character arguments for non-keywords */
- if ( !BTEST(arg_flags(ad), ARGKEYWORD | ARGVALSEP) ) {
- if ( *vp == '+' || *vp == '1' ) {
- *(BOOL *) arg_valp(ad) = TRUE;
- return (BOOL) -1;
- }
- if ( *vp == '-' || *vp == '0' ) {
- *(BOOL *) arg_valp(ad) = FALSE;
- return (BOOL) -1;
- }
- if ( *vp == '~' || *vp == '^' ) {
- *(BOOL *) arg_valp(ad) = (*(BOOL *) arg_valp(ad)) ? FALSE : TRUE;
- return (BOOL) -1;
- }
-
- /* unmatched value, return FALSE for non-argBool (so the caller
- ** can use whatever default) and return TRUE for argBool.
- */
- if ( arg_type(ad) == argBool ) {
- *(BOOL *) arg_valp(ad) = TRUE;
- return TRUE;
- }
- return FALSE;
- }/* if single char option */
-
- /* copy input & convert to lower case */
- cp = strlwr( strdup(vp) );
- len = strlen( cp );
-
- /* search for a match in the table */
- for (b = _BoolTab; b->bname ; b++) {
- /* if too short, don't even bother trying */
- if (len < b->bneedmatch)
- continue;
-
- if ( memcmp(cp, b->bname, len) == 0) {
- /* got a match */
- *(BOOL *) arg_valp(ad) = b->bval;
- free( cp );
- return (TRUE);
- }
- }/*if match*/
-
- free( cp );
- usrerr("invalid Boolean argument '%s' for %s", vp, argname);
- return (FALSE);
- }
-
-
- /*ARGSUSED*/
- BOOL argSBool PARMS(ad, vp, copyf)
- {
- argName_t argname;
- BOOL retval;
-
- (VOID) get_argname( arg_sname(ad), argname );
-
- /* ARGVECs are not supported for this Boolean arg-types */
- if ( ARG_isVEC(ad) )
- syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
- argname );
-
- /* if vp is NULL, just set to TRUE */
- if ( !vp || !*vp || !(retval = argBool(ad, vp, copyf)) ) {
- *(BOOL *) arg_valp(ad) = TRUE;
- return (TRUE);
- }
- else
- return retval;
- }
-
- /*ARGSUSED*/
- BOOL argUBool PARMS(ad, vp, copyf)
- {
- argName_t argname;
- BOOL retval;
-
- (VOID) get_argname( arg_sname(ad), argname );
-
- /* ARGVECs are not supported for this Boolean arg-types */
- if ( ARG_isVEC(ad) )
- syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
- argname );
-
- /* if vp is NULL, just set to FALSE */
- if ( !vp || !*vp || !(retval = argBool(ad, vp, copyf)) ) {
- *(BOOL *) arg_valp(ad) = FALSE;
- return (TRUE);
- }
- else
- return retval;
- }
-
- /*ARGSUSED*/
- BOOL argTBool PARMS(ad, vp, copyf)
- {
- argName_t argname;
- BOOL retval;
-
- (VOID) get_argname( arg_sname(ad), argname );
-
- /* ARGVECs are not supported for this Boolean arg-types */
- if ( ARG_isVEC(ad) )
- syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
- argname );
-
- /* if vp is NULL, just toggle value */
- if ( !vp || !*vp || !(retval = argBool(ad, vp, copyf)) ) {
- *(BOOL *) arg_valp(ad) = (*(BOOL *) arg_valp(ad)) ? FALSE : TRUE ;
- return (TRUE);
- }
- else
- return retval;
- }
-
-
- #ifdef vms_style
-
- /***************************************************************************
- ** ^SECTION: I/O-REDIRECTION-TYPES -- argInput, argOutput
- ** ArgInput attempts to redirect the file-pointer addressed by ad_valp
- ** to the file named by the given value. The file is opened for reading.
- **
- ** ArgOutput attempts to redirect the file-pointer addressed by ad_valp
- ** to the file named by the given value. The file is opened for writing.
- **
- ** In either case, ad_valp should be of type (FILE **) (a pointer to a
- ** file pointer) and not a mere file pointer as in (FILE *)!!!
- **
- ** If the given files cannot be opened, then an error message is printed
- ** and the associated input/output streams are closed.
- ***^^**********************************************************************/
-
- /*
- ** slight problem here - on VMS, as_valp should be of type FILE **
- ** but on Unix (emulating VMS) it needs to be of type FILE *.
- ** we get around this using the following:
- */
- # ifdef vms
- # define FP *fp
- # else
- # define FP fp
- # endif
-
- /*ARGSUSED*/
- BOOL argInput PARMS(ad, vp, copyf)
- {
- #ifdef vms
- FILE **fp = (FILE **)arg_valp(ad);
- #else
- FILE *fp = (FILE *)arg_valp(ad);
- #endif
- BOOL error = FALSE;
-
- /* redirect file pointer to read from file */
- if ( !vp ) {
- usrerr( "Error: no file name given" );
- error = TRUE;
- }
-
- if ( !error && !FP )
- error = TRUE;
- else if ( !error && !freopen(vp, "r", FP) )
- error = TRUE;
-
- if ( error ) {
- usrerr( "Error: unable to redirect input to file \"%s.\"", vp );
- return (FALSE);
- }
- return (TRUE);
- }
-
-
- /*ARGSUSED*/
- BOOL argOutput PARMS(ad, vp, copyf)
- {
- #ifdef vms
- FILE **fp = (FILE **)arg_valp(ad);
- #else
- FILE *fp = (FILE *)arg_valp(ad);
- #endif
- BOOL error = FALSE;
-
- /* redirect file pointer to write to file */
- if ( !vp ) {
- usrerr( "Error: no file name given" );
- error = TRUE;
- }
-
- if ( !error && !FP )
- error = TRUE;
- else if ( !error && !freopen(vp, "a", FP) )
- error = TRUE;
-
- if ( error ) {
- usrerr( "Error: unable to redirect output to file \"%s.\"", vp );
- return (FALSE);
- }
- return (TRUE);
- }
-
- # undef FP
- #endif /* vms_style */
-