home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************
- ** ^FILE: strfuncs.c - Miscellaneous string functions for parseargs
- **
- ** ^DESCRIPTION:
- ** This file implements a wide variety of functions to manipulate
- ** strings in way way or another. Some of the functions may already
- ** be included in the standard library of some C compilers.
- **
- ** The following functions are implemented:
- **
- ** strucpy() -- copy a string and map to uppercase
- ** strlcpy() -- copy a string and map to lowercase
- ** strupr() -- convert a string to uppercase
- ** strlwr() -- convert a string to lowercase
- ** stricmp() -- case insensitive comparison of strings
- ** strnicmp() -- case insensitive length-limited comparison of strings
- ** strdup() -- return a (newly allocated) copy of a string
- ** strndup() -- return a (newly allocated) copy of a prefix of a string
- ** strpbrk() -- return first occurrence of character in a set
- ** strspn() -- return length of initial prefix of a character set
- ** strcspn() -- return length of initial prefix of a character set
- ** strltrim() -- trim leftmost (leading) characters in a string
- ** strrtrim() -- trim rightmost (trailing) characters in a string
- ** strtrim() -- trim leading and trailing characters in a string
- ** strsplit() -- split a string up into a vector of tokens
- ** strjoin() -- join a vector of tokens into a single string
- ** get_argpfx() -- return the length of the first part of the string
- ** get_argdesc() -- return the description (second part) of the string
- ** get_argname() -- return the aname (argument-name) of an argument
- ** get_kwdname() -- return the sname (keyword-name) of an argument
- ** match() -- match two keywords (case insensitive) upto a unique prefix
- ** basename() -- remove the leading directories (and disks) from a path
- ** indent_para() -- print an indented hanging paragraph
- **
- ** ^HISTORY:
- **
- ** 12/16/91 Brad Appleton <brad@ssd.csd.harris.com>
- ** - add strndup()
- **
- ** 11/26/91 Brad Appleton <brad@ssd.csd.harris.com>
- ** - added the following to indent_para(). If last arg is 0,
- ** then the whole length is used.
- **
- ** 08/27/91 Earl Chew <cechew@bruce.cs.monash.edu.au>
- ** - add extra length argument to indent_para().
- ** - add FORCE_KWDCASE() macro
- ** - add non-writable strings support to get_argname() and
- ** get_kwdname()
- ** - add get_argpfx() and get_argdesc() for non-writable strings
- ** support
- ** - allow zero length string for strsplit()
- **
- ** 01/02/91 Brad Appleton <brad@ssd.csd.harris.com> Created
- ** - changed from file misc.c to this name and added all of the strxxx
- ** functions (plus got rid of some unused functions).
- **
- ** --/--/-- Peter da Silva <peter@ferranti.com>
- **
- ** --/--/-- Eric P. Allman <eric@Berkeley.EDU> Created
- ***^^**********************************************************************/
-
- #include <stdio.h>
- #include <ctype.h>
- #include <useful.h>
-
- #ifdef vms
- # include <ssdef.h>
- #endif
-
- #include "strfuncs.h"
-
- EXTERN VOID syserr ARGS((const char *, ...));
-
- static CONST char WhiteSpace[] = " \t\n\r\v\f";
-
- #define c_ARG_SEP '='
- #if ( defined(unix_style) || defined(ibm_style) )
- # define FORCE_KWDCASE(s) strlwr(s)
- # define TO_KWDCASE(c) TOLOWER(c)
- # define KWDCASECOPY(dest,src) strlcpy(dest,src)
- #else
- # define FORCE_KWDCASE(s) strupr(s)
- # define TO_KWDCASE(c) TOUPPER(c)
- # define KWDCASECOPY(dest,src) strucpy(dest,src)
- #endif
-
-
- /***************************************************************************
- ** ^FUNCTION: strucpy, strlcpy - copy dest to src, mapping to upper/lower case
- **
- ** ^SYNOPSIS:
- **
- ** char *strucpy( dest, src )
- ** char *strlcpy( dest, src )
- **
- ** ^PARAMETERS:
- ** char *dest;
- ** -- the address to start copying to
- **
- ** char *src;
- ** -- the address to start copying from
- **
- ** ^DESCRIPTION:
- ** Strlcpy (strucpy) copies src into dest (upto and including the
- ** terminating NUL byte) and all uppercase (lowercase) characters in
- ** src are mapped to lowercase (uppercase) before being copied into dest.
- **
- ** ^REQUIREMENTS:
- ** Dest must be non-null, and large enough to hold the copied result.
- **
- ** ^SIDE-EFFECTS:
- ** Dest is (re)written
- **
- ** ^RETURN-VALUE:
- ** Address of dest.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- char *strucpy( char *dest, const char *src )
- #else
- char *strucpy( dest, src ) char *dest, *src;
- #endif
- {
- register char *s1 = dest;
- register CONST char *s2 = src;
-
- if ( !s2 ) return CHARNULL;
-
- for ( ; *s2 ; s1++, s2++ ) {
- *s1 = TOUPPER( *s2 );
- }
- *s1 = '\0';
-
- return s1;
- }
-
-
- #ifdef __ANSI_C__
- char *strlcpy( char *dest, const char *src )
- #else
- char *strlcpy( dest, src ) char *dest, *src;
- #endif
- {
- register char *s1 = dest;
- register CONST char *s2 = src;
-
- if ( !s2 ) return CHARNULL;
-
- for ( ; *s2 ; s1++, s2++ ) {
- *s1 = TOLOWER( *s2 );
- }
- *s1 = '\0';
-
- return s1;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: strupr, strlwr - convert a string to all upper/lower case
- **
- ** ^SYNOPSIS:
- ** char *strupr( str )
- ** char *strlwr( str )
- **
- ** ^PARAMETERS:
- ** char *str;
- ** -- the string to be converted
- **
- ** ^DESCRIPTION:
- ** Strupr (strlwr) converts all lowercase (uppercase) characters in <str>
- ** to uppercase (lowercase) and returns the address of <str>.
- **
- ** ^REQUIREMENTS:
- ** str should be non-null and non-empty.
- **
- ** ^SIDE-EFFECTS:
- ** str is overwritten with the uppercase (lowercase) result.
- **
- ** ^RETURN-VALUE:
- ** Address of str.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- char *strupr( char *str )
- #else
- char *strupr( str ) char *str;
- #endif
- {
- char *p = str;
-
- for ( ; p && *p ; p++ ) {
- if ( islower(*p) ) *p = toupper(*p);
- }
-
- return str;
- }
-
-
- #ifdef __ANSI_C__
- char *strlwr( char *str )
- #else
- char *strlwr( str ) char *str;
- #endif
- {
- char *p = str;
-
- for ( ; p && *p ; p++ ) {
- if ( isupper(*p) ) *p = tolower(*p);
- }
-
- return str;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: stricmp, strnicmp - case insensitive string comparison
- **
- ** ^SYNOPSIS:
- ** int stricmp( s1, s2 )
- ** int strnicmp( s1, s2, n )
- **
- ** ^PARAMETERS:
- ** char *s1;
- ** -- first string to compare
- **
- ** char *s2;
- ** -- second string to compare
- **
- ** size_t n;
- ** -- The number of characters to compare
- **
- ** ^DESCRIPTION:
- ** Stricmp (strnicmp) is identical to strcmp (strncmp) except that it
- ** it performs a case-insensitive comparison of characters.
- **
- ** ^REQUIREMENTS:
- ** Both s1 and s2 should be non-null and non-empty
- **
- ** ^SIDE-EFFECTS:
- ** None.
- **
- ** ^RETURN-VALUE:
- ** < 0 if s1 < s2
- ** = 0 if s1 matches s2
- ** > 0 if s1 > s2
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- int stricmp( const char *str1, const char *str2 )
- #else
- int stricmp( str1, str2 ) char *str1, *str2;
- #endif
- {
- register CONST char *s1 = str1, *s2 = str2;
- register char c1, c2;
-
- if ( s1 == s2 ) return 0;
- if ( !s1 ) return -1;
- if ( !s2 ) return 1;
-
- for ( ; *s1 && *s2 ; s1++ , s2++ ) {
- c1 = TOLOWER( *s1 );
- c2 = TOLOWER( *s2 );
-
- if (c1 != c2) return (int)(c1 -c2);
- }
- return (*s1 == *s2) ? 0 : (int)(*s1 - *s2);
- }
-
-
- #ifdef __ANSI_C__
- int strnicmp( const char *str1, const char *str2, size_t len )
- #else
- int strnicmp( str1, str2, len ) char *str1, *str2; size_t len;
- #endif
- {
- register CONST char *s1 = str1, *s2 = str2;
- register char c1, c2;
-
- if ( s1 == s2 ) return 0;
- if ( !s1 ) return -1;
- if ( !s2 ) return 1;
-
- for ( ; *s1 && *s2 && len ; s1++ , s2++ , len-- ) {
- c1 = TOLOWER( *s1 );
- c2 = TOLOWER( *s2 );
-
- if (c1 != c2) return (int)(c1 -c2);
- }
- return (!len || (*s1 == *s2)) ? 0 : (int)(*s1 - *s2);
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: strdup - copy a string
- **
- ** ^SYNOPSIS:
- */
- # ifndef __ANSI_C__
- char *strdup( str )
- /*
- ** ^PARAMETERS:
- */
- char *str;
- /* -- the string to replicate
- */
- # endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Strdup allocates storrage and copies the given string into the
- ** newly acquired space (returning its address). The returned result
- ** should be deallocated using free().
- **
- ** ^REQUIREMENTS:
- ** str should be non-null
- **
- ** ^SIDE-EFFECTS:
- ** None.
- **
- ** ^RETURN-VALUE:
- ** Address of the newly allocated string.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- # ifdef __ANSI_C__
- char *strdup( const char *str )
- # endif
- {
- unsigned len = strlen(str) + 1;
- char *p = (char *)malloc( len * sizeof(char) );
-
- if ( !p ) syserr( "malloc failed in strdup()" );
- strcpy(p, str);
-
- return p;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: strndup - copy a prefix of a string
- **
- ** ^SYNOPSIS:
- */
- # ifndef __ANSI_C__
- char *strndup( str, len )
- /*
- ** ^PARAMETERS:
- */
- char *str;
- /* -- the string to replicate
- */
- unsigned len;
- /* -- the number of characters to be replicated
- */
- # endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Strndup allocates storrage and copies the the first "len" characters
- ** of the given string into the newly acquired space (returning its
- ** address). The returned result should be deallocated using free().
- **
- ** ^REQUIREMENTS:
- ** str should be non-null
- **
- ** ^SIDE-EFFECTS:
- ** None.
- **
- ** ^RETURN-VALUE:
- ** Address of the newly allocated string.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- # ifdef __ANSI_C__
- char *strndup( const char *str, unsigned len )
- # endif
- {
- char *p = (char *)malloc( (len + 1) * sizeof(char) );
-
- if ( !p ) syserr( "malloc failed in strndup()" );
- strncpy(p, str, len);
-
- return p;
- }
-
-
- #ifdef BSD
-
- /***************************************************************************
- ** ^FUNCTION: strpbrk - return the first occurrence of characters in a string
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- char *strpbrk( str1, str2 )
- /*
- ** ^PARAMETERS:
- */
- char *str1;
- /* -- the string to be searched
- */
- char *str2;
- /* -- the set of characters to be located
- */
- #endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Strpbrk will attempt to locate the first occurence in str1 of any
- ** character from str2 and return the address of the first such
- ** occurrence. If str1 contains NO characters from str2, then NULL
- ** is returned.
- **
- ** ^REQUIREMENTS:
- ** Both str1 and str2 should be non-null and non-empty
- **
- ** ^SIDE-EFFECTS:
- ** None.
- **
- ** ^RETURN-VALUE:
- ** A pointer to the first occurence in str1 of any char from str2.
- **
- ** ^ALGORITHM:
- ** - foreach char in str1
- ** - if char is in str2, return the address of char
- ** end-for
- ** - if we have reached the end of str1, return NULL
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- char *strpbrk( const char *str1, const char *str2 )
- #endif
- {
- register CONST char *s1 = str1, *s2 = str2;
-
- if ( !s1 || !*s1 || !s2 || !*s2 ) return CHARNULL;
-
- for ( ; *s1 ; s1++ ) {
- if ( strchr(s2, *s1) ) return (char *)s1;
- }
-
- return CHARNULL;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: strspn, strcspn - identify leading runs of characters
- **
- ** ^SYNOPSIS:
- ** char *strspn( str1, str2 )
- ** char *strcspn( str1, str2 )
- **
- ** ^PARAMETERS:
- ** char *str1;
- ** -- the string to be searched
- **
- ** char *str2;
- ** -- the string to be searched
- **
- ** ^DESCRIPTION:
- ** Strspn (strcspn) attempts to determine the length of the longest
- ** leading prefix of str1 that consists entirely of character from
- ** (not from) str2.
- **
- ** ^REQUIREMENTS:
- ** Both str1 and str2 should be non-null and non-empty.
- **
- ** ^SIDE-EFFECTS:
- ** None.
- **
- ** ^RETURN-VALUE:
- ** The length of the initial prefix in str1 consisting entirely
- ** of characters from (not from) str2.
- **
- ** ^ALGORITHM:
- ** - length = 0
- ** - for each char in str1
- ** - if char is in str2 (for strcspn) or not in str2 (for strcspn)
- ** then return length
- ** - else
- ** add 1 to length
- ** end-if
- ** end-for
- ** - if end-of-string then return length
- **
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- int strspn( const char *str1, const char *str2 )
- #else
- int strspn( str1, str2 ) char *str1, *str2;
- #endif
- {
- register CONST char *s1 = str1, *s2 = str2;
- int len = 0;
-
- if ( !s1 || !*s1 || !s2 || !*s2 ) return 0;
- while ( *s1 && strchr(s2, *s1++) ) ++len;
- return len;
- }
-
-
- #ifdef __ANSI_C__
- int strcspn( const char *str1, const char *str2 )
- #else
- int strcspn( str1, str2 ) char *str1, *str2;
- #endif
- {
- register CONST char *s1 = str1, *s2 = str2;
- int len = 0;
-
- if ( !s1 || !*s1 || !s2 || !*s2 ) return 0;
- while ( *s1 && !strchr(s2, *s1++) ) ++len;
- return len;
- }
-
- #endif /* BSD */
-
-
- /***************************************************************************
- ** ^FUNCTION: strltrim, strrtrim, strtrim - trim leading/trailing characters
- **
- ** ^SYNOPSIS:
- ** char *strltrim( str, charset )
- ** char *strrtrim( str, charset )
- ** char *strtrim( str, charset )
- **
- ** ^PARAMETERS:
- ** char *str;
- ** -- the string to be trimmed
- **
- ** char *charset;
- ** -- the set of characters to be trimmed
- **
- ** ^DESCRIPTION:
- ** Strltrim removes from str, all leftmost (leading) characters occurring
- ** in charset.
- **
- ** Strrtrim removes from str, all rightmost (trailing) characters occurring
- ** in charset.
- **
- ** Strtrim removes from str, all leading and trailing characters occurring
- ** in charset.
- **
- ** For each of these functions, if charset is NULL or empty, then the set
- ** of whitespace characters (space, tab, newline, carriage-return, form-feed
- ** and vertical-tab) is assumed.
- **
- ** ^REQUIREMENTS:
- ** str should be non-null and non-empty.
- **
- ** ^SIDE-EFFECTS:
- ** characters may be removed from the beginning and/or end of str.
- **
- ** ^RETURN-VALUE:
- ** Address of str.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- char *strltrim( char *str, const char *charset )
- #else
- char *strltrim( str, charset ) char *str, *charset;
- #endif
- {
- register int i;
-
- if ( !str || !*str ) return str;
- /* if delim-string is NULL, whitespace is used */
- if ( !charset ) charset = WhiteSpace;
-
- i = strspn( str, charset );
- if ( i > 0 ) strcpy( str, &(str[i]) );
-
- return str;
- }
-
-
- #ifdef __ANSI_C__
- char *strrtrim( char *str, const char *charset )
- #else
- char *strrtrim( str, charset ) char *str, *charset;
- #endif
- {
- register int i;
-
- if ( !str || !*str ) return str;
- if ( !charset ) charset = WhiteSpace;
- for ( i = strlen(str) - 1 ;
- ( i >= 0 ) && (strchr( charset, str[i] )) ;
- i--
- ) ;
-
- str[i+1] = '\0';
-
- return str;
- }
-
-
- #ifdef __ANSI_C__
- char *strtrim( char *str, const char *charset )
- #else
- char *strtrim( str, charset ) char *str, *charset;
- #endif
- {
- register int i;
-
- if ( !str || !*str ) return str;
- if ( !charset ) charset = WhiteSpace;
- i = strspn( str, charset );
- if ( i > 0 ) strcpy( str, &(str[i]) );
-
- for ( i = strlen(str) - 1 ;
- ( i >= 0 ) && (strchr( charset, str[i] )) ;
- i--
- ) ;
-
- str[i+1] = '\0';
-
- return str;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: strsplit - split a string into tokens
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- int strsplit( vec, token_str, separators )
- /*
- ** ^PARAMETERS:
- */
- char **vec[];
- /* -- pointer to the string vector to be allocated
- */
- char token_str[];
- /* -- the string to be split up
- */
- char separators[];
- /* -- the delimiters that separate tokens
- */
- #endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Strsplit will split token_str up into a vector of tokens that are
- ** separated by one or more characters from <separators>. The number
- ** of tokens found is returned and storage is allocated for the given
- ** vector (which may later be deallocated using free()).
- **
- ** If <separators> is NULL or empty, then the set of whitespace characters
- ** is used as the token delimiters.
- **
- ** ^REQUIREMENTS:
- ** vec must be non-NULL (it must be a valid address).
- ** token_str should be non-null
- **
- ** ^SIDE-EFFECTS:
- ** All leading and trailing characters from <separators> are removed
- ** from token_str. Furthermore, all remaining sequences in token_str
- ** of characters from <separators> are replaced with a single NUL-byte.
- **
- ** Token_str holds the actual storage for all the strings in the newly
- ** created vector.
- **
- ** ^RETURN-VALUE:
- ** The number of tokens parsed.
- **
- ** ^ALGORITHM:
- ** - count the number of tokens present while at the same time removing
- ** all leading and trailing delimiters, and replacing all other sequences
- ** of delimiters with the NUL character.
- ** - allocate a vector large enough to point to all the token strings.
- ** - for i in 0 .. (numtokens - 1) do
- ** - vector[i] = token_str
- ** - advance token_str to point at the next character past the
- ** rightmost NUL-byte (which should be the start of the next token).
- ** end-for
- ** - vector[numtokens] = NUL
- ** - return the number of tokens parsed.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- int strsplit( char **vec[], char token_str[], const char separators[] )
- #endif
- {
- register char c, *pread, *pwrite;
- int i, count = 0;
-
- if ( !token_str ) token_str = "";
- /* if delim-string is NULL, whitespace is used */
- if ( !separators ) separators = WhiteSpace;
-
- /* trim leading separators */
- pread = token_str;
- while ( strchr(separators, *pread) ) ++pread;
- if ( ! *pread ) return 0;
- token_str = pwrite = pread;
-
- /*
- ** make first pass through string, counting # of tokens and
- ** separating all tokens by a single '\0'
- */
- for ( c = *pread++ ; c ; ) {
- if ( !strchr(separators, c) ) {
- do {
- *pwrite++ = c;
- } while ( (c = *pread++) && !strchr(separators, c) );
- *pwrite++ = '\0';
- ++count;
- }/*if*/
- while ( c && strchr(separators, c) ) c = *pread++;
- }/*for*/
-
- /* allocate space for the caller's vector (remember NULL at the end) */
- (*vec) = (char **)malloc( (1 + count) * sizeof( char * ) );
- if ( !*vec ) syserr( "malloc failed in strsplit()" );
-
- /* now go thru token-string again assigning pointers from vector */
- pread = token_str;
- for ( i = 0 ; i < count ; i++ ) {
- (*vec)[i] = pread; /* assign pointer */
- pread += strlen( pread ) + 1;
- }/* end-for */
-
- /* set up the trailing pointer to NULL at the end */
- (*vec)[ count ] = CHARNULL;
- return count;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: strjoin - join a vector of tokens together
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- char *strjoin( argv, separator )
- /*
- ** ^PARAMETERS:
- */
- char *argv[];
- /* -- pointer to the string vector to join together
- */
- char separator[];
- /* -- the the string to use to separate tokens (if NULL, " " is used)
- */
- #endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Strjoin will make a single string out of the given vector by copying
- ** all the tokens from the given vector (in order) to a newly allocated
- ** string. Tokens will be separated by a single occurence of <separator>.
- **
- ** If <separator> is NULL then a single space is used as the separator.
- ** If <separator> is empty, then no separator is used and the tokens are
- ** simply concatenated together.
- **
- ** ^REQUIREMENTS:
- ** argv must be non-NULL (it must be a valid address), and must be
- ** terminated by a pointer to NULL (argv[last+1] == NULL).
- **
- ** ^SIDE-EFFECTS:
- ** Storage is allocated.
- **
- ** ^RETURN-VALUE:
- ** The address of the newly-joined result (which should be deallocated
- ** using free()). Returns NULL if nothing was joined.
- **
- ** ^ALGORITHM:
- ** - count the number of characters to place in the joined-result.
- ** - allocate a string large-enough to copy the joined-result into.
- ** - copy each string into the string (with <separator> between tokens).
- ** - 0 return the result.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- char *strjoin( const char *argv[], const char separator[] )
- #endif
- {
- size_t sz = 0;
- register char *p;
- register CONST char *a, **av;
- register int seplen;
- char *result;
-
- /* if argv is NULL, nothing to do */
- if ( !argv ) return CHARNULL;
- if ( !separator ) separator = " ";
- seplen = strlen( separator );
-
- /* figure out how much space we need */
- for ( av = argv ; *av ; av++ ) {
- if ( !**av ) continue;
- sz += strlen( *av );
- if ( seplen && *(av + 1) ) sz += seplen;
- }
-
- /* allocate space */
- result = (char *)malloc( (sz + 1) * sizeof(char) );
- if ( !result ) syserr( "malloc failed in strjoin()" );
-
- /* join the strings together */
- *result = '\0';
- for ( av = argv, p = result ; (a = *av) ; av++ ) {
- if ( !*a ) continue;
- while ( (*p = *a++) ) ++p; /* copy token */
- if ( seplen && *(av + 1) ) {
- a = separator;
- while ( (*p = *a++) ) ++p; /* copy separator */
- }/*end-if*/
- }/*end-for*/
-
- return result;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: get_argpfx - get the prefix portion of a string
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- int get_argpfx( str )
- /*
- ** ^PARAMETERS:
- */
- char *str;
- /* -- the string to parse for a description
- */
- #endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Get_argdesc returns the length of the first portion of the string.
- **
- ** Two "portions" must be either separated by whitespace or the second
- ** portion may be within "(),{},[], or <>" delimiters. The second
- ** portion is assumed to begin with the first alphabetic following
- ** separator.
- **
- ** ^REQUIREMENTS:
- ** str should be non-null and non-empty
- **
- ** ^SIDE-EFFECTS:
- ** None.
- **
- ** ^RETURN-VALUE:
- ** The length of the first portion.
- **
- ** ^ALGORITHM:
- ** - locate the end of the first portion by scanning for whitespace or
- ** balanced delimiters.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- int get_argpfx( const char *str )
- #endif
- {
- register char *description;
- static CONST char whitespace[] = " \t\n\r\f\v";
- static CONST char beg_portion[] = "(<{[";
-
- description = strpbrk( str, whitespace );
- if ( !description ) {
- description = strpbrk( str, beg_portion );
- }
-
- return description ? description - str : strlen(str);
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: get_argdesc - get the description portion of a string
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- char *get_argdesc( str, len )
- /*
- ** ^PARAMETERS:
- */
- char *str;
- /* -- the string to parse for a description
- */
- int *len;
- /* -- the pointer to the length
- */
- #endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Get_argdesc returns a pointer to the second portion of the string
- ** and also indicates how long it is.
- **
- ** Two "portions" must be either separated by whitespace or the second
- ** portion may be within "(),{},[], or <>" delimiters. The second
- ** portion is assumed to begin with the first alphabetic following
- ** separator.
- **
- ** ^REQUIREMENTS:
- ** str should be non-null and non-empty
- **
- ** ^SIDE-EFFECTS:
- ** The length of the description is written to *len.
- **
- ** ^RETURN-VALUE:
- ** Address of the description (or NULL if the string has no description).
- **
- ** ^ALGORITHM:
- ** - locate the end of the first portion by scanning for whitespace or
- ** balanced delimiters.
- ** - locate the beginning of the second portion by scanning for the first
- ** alpha-numeric following the end of the first portion.
- ** - return the address of the description.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- char *get_argdesc( const char *str, int *len )
- #endif
- {
- register char *description = CHARNULL;
- BOOL is_end = FALSE, is_balanced = FALSE;
- char *p;
- static CONST char whitespace[] = " \t\n\r\f\v";
- static CONST char beg_portion[] = "(<{[";
- static CONST char end_portion[] = ")>}]";
-
- description = strpbrk( str, whitespace );
- if ( description ) {
- is_end = TRUE;
- while ( isspace(*++description) ) continue; /* trim leading ' ' */
- if ( strchr(beg_portion, *description) ) {
- is_balanced = TRUE;
- ++description;
- }
- }
- else {
- description = strpbrk( str, beg_portion );
- if ( description ) { /* skip leading '(' */
- is_end = is_balanced = TRUE;
- ++description;
- }
- }
-
- if ( !description ) {
- *len = 0;
- }
- else {
- if ( is_balanced ) { /* remove trailing ')' */
- p = description + (strlen( description ) - 1);
- if ( !strchr(end_portion, *p) ) ++p;
- *len = p - description;
- }
- else {
- while ( !isalnum(*description) ) ++description;
- *len = strlen( description );
- }
- }
-
- return description;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: get_argname - return the aname (argument-name) of an argument
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- char *get_argname( s, buf )
- /*
- ** ^PARAMETERS:
- */
- char *s;
- /* -- the ad_prompt field of an ARGDESC struct
- */
- char *buf;
- /* -- address to which the aname should be copied
- */
- #endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Get_argname will get the full argument name of the given argument
- ** (not just the keyword name) and copy it to buf.
- **
- ** ^REQUIREMENTS:
- ** Both s and buf must be non-null and non-empty.
- ** buf must be large enough to hold the result.
- **
- ** ^SIDE-EFFECTS:
- ** buf is overwritten.
- **
- ** ^RETURN-VALUE:
- ** Address of the buffer containing the name.
- **
- ** ^ALGORITHM:
- ** determine the name of an argument from its prompt
- ** and copy the result in the given buffer
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- char *get_argname( const char *s, char *buf )
- #endif
- {
- register CONST char *p2;
- int len;
-
- /* see if sname and aname are separated by c_ARG_SEP
- ** <buf> must be large enough to hold the result!
- */
- len = get_argpfx(s);
- p2 = strchr( s, c_ARG_SEP );
- if ( p2 && p2 < &s[len]) {
- ++p2;
- strncpy( buf, p2, len-(p2-s) );
- buf[len-(p2-s)] = 0;
- strlwr(buf);
- }
- else {
- strncpy( buf, s, len );
- buf[len] = 0;
- strlwr(buf);
- }
- return buf;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: get_kwdname - get the sname (keyword name) of an argument
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- char *get_kwdname( s, buf )
- /*
- ** ^PARAMETERS:
- */
- char *s;
- /* -- the ad_prompt field of an ARGDESC struct
- */
- char *buf;
- /* -- address to which the sname should be copied
- */
- #endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Get_kwdname will get the keyword name of the given argument
- ** (not the entire argument name) and copy it to buf.
- **
- ** The sname (keyword-name) consists only of all uppercase characters
- ** from the ad_prompt field (in the order they occur). If the ad_prompt
- ** field contains NO uppercase characters, than the aname and the sname
- ** are equivalent (the entire string).
- **
- ** ^REQUIREMENTS:
- ** Both s and buf must be non-null and non-empty.
- ** buf must be large enough to hold the result.
- **
- ** ^SIDE-EFFECTS:
- ** buf is overwritten.
- *
- ** ^RETURN-VALUE:
- ** Address of the buffer containing the keyword.
- **
- ** ^ALGORITHM:
- ** determine the keyword of an argument from its prompt
- ** and copy the result in the given buffer
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- char *get_kwdname( const char *s, char *buf )
- #endif
- {
- register char *p1 = (char *)s, *p2, ch;
- int len;
- BOOL caps = FALSE;
-
- if ( !p1 ) return CHARNULL;
-
- /* see if sname and aname are separated by c_ARG_SEP */
- len = get_argpfx( p1 );
- p2 = strchr( p1, c_ARG_SEP );
- if ( p2 && p2 < &p1[len]) {
- strncpy( buf, p1, p2-p1);
- buf[p2-p1] = 0;
- FORCE_KWDCASE(buf);
- return buf;
- }
-
- /* copy string into buffer and convert it to desired case */
- /* <buf> must be large enough to hold the result! */
- for ( p2 = buf; *p1 && len != 0; p1++, len-- ) {
- if ( isupper(*p1) ) {
- if ( !caps ) {
- caps = TRUE;
- p2 = buf;
- }
- *p2++ = TO_KWDCASE(*p1);
- }
- else if ( !caps ) {
- *p2++ = TO_KWDCASE(*p1);
- }
- }
- *p2 = '\0';
-
- return buf; /* return buffer address */
- }
-
- #ifndef amiga_style
-
- /***************************************************************************
- ** ^FUNCTION: match - match a keyword against a prospective argument
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- int match( candidate, target )
- /*
- ** ^PARAMETERS:
- */
- char *candidate;
- /* -- the possible keyword argument
- */
- char *target;
- /* -- the keyword to be matched
- */
- #endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Match will attempt to see if the candidate string matches the
- ** target string (case insensitive). First a match is tried on the
- ** sname of the keyword, then on the aname. Candidate may be only
- ** a partial leading portion of the target as long as it is at least
- ** two characters long (unless the keyword is 1 character long).
- **
- ** No "partial" matching is accepted for AmigaDOS command-lines.
- **
- ** ^REQUIREMENTS:
- ** Both candidate and target should be non-null and non-empty.
- ** target should be the ad_prompt field of an ARGDESC structure.
- **
- ** ^SIDE-EFFECTS:
- ** None.
- **
- ** ^RETURN-VALUE:
- * < 0 if candidate < target
- ** = 0 if candidate matches target
- ** > 0 if candidate > target
- **
- ** ^ALGORITHM:
- ** - attempt a partial match against the sname and return 0 if we succeed
- ** - attempt a partial match against the aname and return 0 if we succeed
- ** - if both the above fail return non-zero (no match).
- **
- ***^^**********************************************************************/
-
- /* rewritten 8/20/90 --BDA */
- #define MINLEN 2 /* minimum # of characters to match */
-
- #ifdef __ANSI_C__
- int match ( const char *candidate, const char *target )
- #endif
- {
- int i, clen, tlen, too_short=0;
- char arg_targ[ 256 ], kwd_targ[ 256 ];
-
-
- /* make kwd_targ the keyword portion of target */
- (VOID) get_kwdname( target, kwd_targ );
-
- /* match at least MINLEN characters if possible */
- tlen = strlen( kwd_targ );
- clen = strlen( candidate );
- if ( (tlen >= MINLEN) && (clen < MINLEN) ) {
- ++too_short; /* not long enough -- no match */
- }
-
- #ifdef vms_style
- /* if first two chars are NO then match at least MINLEN+2 chars */
- if ( !strnicmp(kwd_targ, "NO", 2) ) {
- if ( (tlen >= (MINLEN + 2)) && (clen < (MINLEN + 2)) ) {
- ++too_short; /* not long enough -- no match */
- }
- }
- #endif
-
- /* first try to match prefix of the keyword portion */
- i = (too_short) ? -1 : strnicmp(kwd_targ, candidate, clen);
-
- /* did we match? */
- if ( !i ) return 0; /* yes! */
-
- /* no! : compare the argument portion
- ** match at least MINLEN characters if possible
- */
- /* make arg_targ the argument portion of target */
- (VOID) get_argname( target, arg_targ );
-
- tlen = strlen(arg_targ);
- if ( (tlen >= MINLEN) && (clen < MINLEN) ) {
- return -1; /* not long enough -- no match */
- }
-
- #ifdef vms_style
- /* if first two chars are NO then match at least MINLEN+2 chars */
- if ( !strnicmp(arg_targ, "no", 2) ) {
- if ( (tlen >= (MINLEN + 2)) && (clen < (MINLEN + 2)) ) {
- return -1; /* not long enough -- no match */
- }
- }
- #endif
-
- return strnicmp(arg_targ, candidate, clen);
- }
-
-
- /* here is the AmigaDOS version of match() */
- #else
-
- # ifdef __ANSI_C__
- int match( const char *candidate, const char *target )
- # else
- int match( candidate, target) char *candidate, *target;
- # endif
- {
- char kwd_targ[ 256 ], arg_targ[ 256 ];
- int rc;
-
- (VOID) get_kwdname( target, kwd_targ );
- rc = stricmp( kwd_targ, candidate );
-
- if ( rc == 0 ) return 0;
-
- (VOID) get_argname( target, arg_targ );
- rc = stricmp( arg_targ, candidate );
-
- return rc;
- }
-
- #endif
-
-
- /***************************************************************************
- ** ^FUNCTION: basename - return the last component of a pathname
- **
- ** ^SYNOPSIS:
- ** char *basename( path )
- **
- ** ^PARAMETERS:
- ** path;
- ** -- the pathname to be truncated.
- **
- ** ^DESCRIPTION:
- ** Basename takes a pathname and strips of all leading components
- ** (except for the very last one) which refer to directories or
- ** disk-drives.
- **
- ** ^REQUIREMENTS:
- ** path should be non-null, non-empty, and should correspond to a valid
- ** pathname (absolute or relative).
- **
- ** ^SIDE-EFFECTS:
- ** None under Unix and AmigaDOS.
- **
- ** Under VMS, the file version is removed and any .COM or .EXE extension
- ** is also removed.
- **
- ** Under MS-DOS, any .EXE, .COM, or .BAT extension is removed.
- **
- ** Under OS/2, any .EXE, .COM, or .CMD extension is removed.
- **
- ** ^RETURN-VALUE:
- ** The address of the basename of the path.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- /* should use '\\' for MS-DOS & OS/2 and use ']' for VMS */
- #ifdef vms
- #define PATH_SEP ']'
-
- /* VAX/VMS version of basename */
- # ifdef __ANSI_C__
- char *basename( char path[] )
- # else
- char *basename( path ) char path[];
- # endif
- {
- char *base = strrchr( path, PATH_SEP );
- char *vers = strrchr( path, ';' );
- char *ext = strrchr( path, '.' );
-
- if ( !base ) {
- if ( !(base = strrchr( path, ':' )) ) {
- base = path;
- }
- else {
- ++base;
- }
- }
- else {
- ++base;
- }
-
- if ( vers ) *vers ='\0';
- if ( ext && (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
- *ext = '\0';
- }
-
- return base;
- }
-
- #else
- #ifdef AmigaDOS
- /* amiga version of basename() */
- # ifdef __ANSI_C__
- char *basename( char path[] )
- # else
- char *basename( path ) char path[];
- # endif
- {
- return path;
- }
- #else
- #define PATH_SEP '/' /* default path-separator character */
-
- /* default version of basename() */
- # ifdef __ANSI_C__
- char *basename( char path[] )
- # else
- char *basename( path ) char path[];
- # endif
- {
- char *base = strrchr( path, PATH_SEP );
-
- #if ( defined(MSDOS) || defined(OS2) )
- /* remove the extension from .EXE, .COM, .BAT, and .CMD files */
- # ifdef OS2
- if ( ext && (!stricmp(ext, ".CMD") ) *ext = '\0';
- # else
- if ( ext && (!stricmp(ext, ".BAT") ) *ext = '\0';
- # endif
-
- if ( ext && (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
- ext = '\0';
- }
- #endif
-
- if ( !base ) {
- #if ( defined(MSDOS) || defined(OS2) )
- base = strrchr( path, '\\' );
- if ( base ) return (base + 1);
- if ( path[ 1 ] == ':' ) return (path + 2); /* just remove drive */
- return (base + 1);
- #endif
- return path;
- }
- else {
- return (base + 1);
- }
- }
- #endif
- #endif
-
-
- /***************************************************************************
- ** ^FUNCTION: indent_para - print a hanging indented paragraph
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- VOID indent_para(fp, maxcols, margin, title, indent, text, textlen)
- /*
- ** ^PARAMETERS:
- */
- FILE *fp;
- /* -- the stream to which output is sent
- */
- int maxcols;
- /* -- the maximum width (in characters) of the output
- */
- int margin;
- /* -- the number of spaces to use as the left margin
- */
- char *title;
- /* -- the paragraph title
- */
- int indent;
- /* -- the distance between the title and the paragraph body
- */
- char *text;
- /* -- the body of the paragraph
- */
- int textlen;
- /* -- the length of the body of the paragraph
- */
- #endif /* !__ANSI_C__ */
-
- /* ^DESCRIPTION:
- ** Indent_para will print on fp, a titled, indented paragraph as follows:
- **
- ** <----------------------- maxcols --------------------------->
- ** <--- margin --> <-- indent -->
- ** title This is the first sentence
- ** of the paragraph. Etc ...
- **
- ** ^REQUIREMENTS:
- ** maxcols and indent must be positive numbers with maxcols > indent
- **
- ** ^SIDE-EFFECTS:
- ** Output is printed to fp.
- **
- ** ^RETURN-VALUE:
- ** None.
- **
- ** ^ALGORITHM:
- ** Print the paragraph title and then print the text.
- ** Lines are automatically adjusted so that each one starts in the
- ** appropriate column.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- void indent_para( FILE *fp, int maxcols, int margin,
- const char *title, int indent, const char *text,
- int textlen )
- #endif
- {
- register int idx = 0;
- BOOL first_line = TRUE;
- char ch;
-
- if ( ! textlen ) textlen = strlen( text );
-
- /* print the title */
- fprintf( fp, "%*s%-*s", margin, "", indent, title );
-
- idx = maxcols - margin - indent;
-
- if ( textlen <= idx )
- fprintf(fp, "%.*s\n", textlen, text);
- else
- do {
- /* backup to end of previous word */
- while (idx && !isspace(text[idx])) --idx;
- while (idx && isspace(text[idx])) --idx;
- idx++;
-
- /* print leading whitespace */
- if (!first_line)
- fprintf(fp, "%*s%-*s", margin, "", indent, "");
-
- fprintf(fp, "%.*s\n", idx, text);
-
- first_line = FALSE;
- text = &(text[idx+1]);
- textlen -= (idx+1);
-
- while (isspace(*text)) { /* goto next word */
- ++text;
- --textlen;
- }
-
- idx = maxcols - margin - indent;
-
- if ( textlen <= idx ) /* print-last line */
- fprintf(fp, "%*s%-*s%.*s\n", margin, "", indent, "", textlen, text);
- } while ( textlen > idx );
- }
-
-
- #ifdef STRTEST
-
- #define WS " \t\n\v\r\f\"'"
-
- static char string2[] = " oh what a beautiful - morning! ";
-
- static char string[] = "\n\
- \t' ', ARGREQ, argStr, Name, 'Name',\n\
- \t'n', ARGOPT|ARGLIST, listStr, Groups, 'newsGROUP (newsgroups test)',\n\
- \t'c', ARGOPT, argInt, RepCount, 'REPcount (number of reps)',\n\
- \t'd', ARGOPT, argStr, DirName, 'DIRname',\n\
- \t'x', ARGOPT, argBool, XFlag, 'Xflag (expand in X direction)',\n\
- \t' ', ARGOPT|ARGLIST, listStr, Argv, 'File',\n\
- \tENDOFARGS\n\
- ";
-
- static char word_str[] = "HELP (print help and quit)";
-
- main()
- #ifdef __ANSI_C__
- #endif
- {
- char **vector;
- unsigned i, numtoks;
-
- printf( "test of strtrim() and strsplit():\n\n" );
-
- printf( "unparsed string='%s'\n", string2 );
- printf( "ltrimmed string='%s'\n", strltrim( string2, WS ) );
- printf( "rtrimmed string='%s'\n", strrtrim( string2, WS ) );
-
- numtoks = strsplit( &vector, string, "," );
- printf( "number of tokens=%d\n", numtoks );
- for ( i = 0 ; i < numtoks ; i++ ) {
- printf( "trimmed token[%d] = '%s'\n", i, strtrim( vector[i], WS ) );
- }
-
- #ifdef vms
- exit( SS$_NORMAL );
- #else
- exit( 0 );
- #endif
-
- }
-
- #endif
-