/** ** $Header: /roq/libsdsc/arg.c 1 11/02/99 4:38p Zaphod $ ** Copyright (c) 1989-1995 San Diego Supercomputer Center (SDSC) ** a division of General Atomics, San Diego, California, USA ** ** Users and possessors of this source code are hereby granted a ** nonexclusive, royalty-free copyright and design patent license to ** use this code in individual software. License is not granted for ** commercial resale, in whole or in part, without prior written ** permission from SDSC. This source is provided "AS IS" without express ** or implied warranty of any kind. ** ** For further information contact: ** E-Mail: info@sds.sdsc.edu ** ** Surface Mail: Information Center ** San Diego Supercomputer Center ** P.O. Box 85608 ** San Diego, CA 92138-5608 ** (619) 534-5000 **/ #define HEADER " $Header: /roq/libsdsc/arg.c 1 11/02/99 4:38p Zaphod $" /** ** FILE ** arg.c - Argument Parsing Package ** ** PROJECT ** libsdsc - SDSC Utility Library ** ** DESCRIPTION ** This file contains source for the argument parsing package. ** These functions simplify the parsing of complex command line ** argument groupings and partially enforce the SDSC tool conventions. ** ** PUBLIC CONTENTS ** d =defined constant ** f =function ** m =defined macro ** t =typedef/struct/union ** v =variable ** ? =other ** ** ArgErrNo v error number ** ArgNNrr v number of error messages ** ArgErrList v error messages ** ArgPError f Print error message ** ArgQError f Query error message ** ** ArgHelp f print a short help message ** ArgFullHelp f print a full-length help message ** ArgFeedback f dump a feedback from to a file ** ArgRegister f dump a user-registration form to a file ** ArgVersion f print version number info to stderr ** ** ArgParse f Parse command line arguments ** ** ArgQNOpt f Query # of Options on Command-Line ** ArgQOpt f Query Option on Command-Line ** ** ArgQNOccur f query # of occurrences of an option ** ArgQNValue f query # of values for an occurrence of an option ** ArgQOccurOpt f query which command-line option this occurrence is ** ArgQValue f query value for an occurrence of an option ** ** PRIVATE CONTENTS ** ** argValue t info on one value of an occurrence of an option ** argOccur t info on one occurrence of an option ** argInfo t info on an option and all its occurrences ** argKeyword t info on a keyword in the hash table ** ** ARGNSTANDARD d # of standard options ** argStandard v standard options ** argStandardRegister v standard -register option ** argStandardFeedback v standard -feedback option ** ** argKeywordTable v Keyword hash table ** argKeywordTableLength v Length of the hash table ** ** argHelpOption t alphabetical option list entry ** argHelpCommandName v name of the command (argv[0]) ** argHelpCommand v command struct for help ** argHelpNOptionList v # of options in list ** argHelpOptionList v options list for help ** ** argOptionOrder v Options in command-line order ** argNOpt v Number of options on command-line ** ** argPrintForm f print a form to a file ** argHash f hash a keyword to get its hash table index ** argFind f find a keyword's entry in the hash table ** argAdd f add an entry to the hash table ** argGetValue f parse a value out of an argument ** argSortCompare f Comparison function for qsort ** ** argCacheKeyword v keyword of last option queried ** argCacheInfo v info for last option queried ** argCacheNOccur v # of last occurrence queried ** argCacheOccur v occurrence for last occurrence queried ** argCacheNValue v # of last value queried ** argCacheValue v value for last value queried ** ** HISTORY ** $Log: /roq/libsdsc/arg.c $ * * 1 11/02/99 4:38p Zaphod ** Revision 1.18 1995/06/29 00:17:39 bduggan ** updated copyright ** ** Revision 1.17 1995/06/29 00:15:29 bduggan ** added prototype for argPrintForm, added include file for sun ** ** Revision 1.16 1995/05/18 18:41:30 bduggan ** Fixed bug w/ gcc on sun's (Can't change char*'s in ** protected memory) ** ** Revision 1.15 1995/04/21 17:55:23 bduggan ** Added command-specific help capability. ** Removed protoypes for standard ansi functions. ** Added include files. ** ** Revision 1.15 1995/04/21 17:55:23 bduggan ** Added command-specific help capability. ** Removed protoypes for standard ansi functions. ** Added include files. ** ** Revision 1.14 94/10/03 16:09:41 nadeau ** Updated to ANSI C and C++ compatibility. ** Removed all use of register keyword. ** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char) ** Added forward declarations. ** Added misc. casts to passify SGI and DEC compilers. ** Updated comments. ** Updated indenting on some code. ** Updated copyright message. ** ** Revision 1.13 93/07/26 09:24:46 allans ** fixed bug in ArgParse initialization loop. Now all NEXT pointers ** are set to NIL. ** ** Revision 1.12 92/09/10 16:05:51 vle ** Added extern declaration of argPrintForm() to make SGI ** compiler happy. ** ** Revision 1.11 92/09/02 13:54:41 vle ** Updated copyright notice. ** ** Revision 1.10 91/10/03 13:11:55 nadeau ** Comment updates. ** ** Revision 1.9 91/09/17 20:04:12 nadeau ** Added support for arg_fullusage field of ArgCommand struct. ** ** Revision 1.8 91/09/17 19:32:46 nadeau ** Fixed a few minor bugs relating to splitting off -register ** and -feedback into their own standard option tables and ** adding -fullhelp. Added hash table debug print routine. ** Added code to copy the help text to a tmp buffer before ** modifying it prior to printing. This was necessary for ** the NeXT, which defaults to putting initialized strings ** into read-only segments. When we tried to modify the help ** text, we died. ** ** Revision 1.7 91/09/01 17:12:08 nadeau ** Changed help support. Added support for -fullhelp. Changed ** ArgHelp to display user's usage line and copyright message.` ** Added ArgFullHelp. Changed ArgVersion to display user's ** version and copyright messages. Changed ArgRegister and ** ArgFeedback to use the user's form strings. ** ** Revision 1.6 91/08/25 13:56:38 nadeau ** Added support for ArgQOccurOpt. ** ** Revision 1.5 91/03/11 12:58:56 nadeau ** Updated feedback and registration forms. ** ** Revision 1.4 91/01/11 11:34:16 nadeau ** Added #ifndef's around INDEX and RINDEX macros. ** ** Revision 1.3 91/01/09 16:34:23 nadeau ** Added ArgQError() and enhanced handling of multiple occurrence ** implied keywords. ** ** Revision 1.2 90/05/16 12:19:09 nadeau ** Removed bogus extra check on keywords before adding them. It caused ** later equivs that were the same as earlier abreviations of equivs to ** bomb out with a duplicate keyword message when it should have just ** removed the extra colliding earlier abreviations. ** ** Revision 1.1 90/05/16 11:53:54 nadeau ** Initial revision ** **/ /*LINTLIBRARY*/ #include "sdsccopyright.h" #include #include #include #include #include #include #ifdef sun #include /* for strtod() */ #endif #include "sdsc.h" #ifdef __STDC__ static int argPrintForm( char *, char *, char *, int ); #else static int argPrintForm( ); #endif #ifndef NULL #define NULL 0 #endif #ifndef MAXINT #define MAXINT (((unsigned long)(~((unsigned long)0)))>>1) #endif #ifndef W_OK #define W_OK 0x02 #define F_OK 0x00 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif /* * FUNCTION PROTOTYPES */ #ifdef __STDC__ static int argPrintForm( char *, char *, char *, int ); static void argPrintWithNames(char *, char *); #else static int argPrintForm( ); static void argPrintWithNames(); #endif /* * GLOBAL VARIABLE * ArgErrNo - error number * ArgNErr - number of error messages * ArgErrList - error messages * * DESCRIPTION * On an error, the argument parsing package routines return -1 and set * ArgErrNo to an error code. The programmer may call ArgPError * to print the associated error message to stderr, or may do the * message lookup in ArgErrList themselves. */ int ArgErrNo = -1; /* Arg package error number */ char *ArgErrList[] = /* Error message list */ { /* ARGESYS */ "System error: see errno", /* ARGEUNKKEYWORD */ "Unknown keyword", /* ARGENOPT */ "Bad option number", /* ARGENOCCUR */ "Bad occurrence number", /* ARGENVALUE */ "Bad value number", /* ARGENOVALUE */ "Option has no values", /* ARGEREG */ "Cannot create registration form file", /* ARGEFBK */ "Cannot create feedback form file", }; int ArgNErr = 8; /* Number of error messages */ /* * TYPEDEF & STRUCTURE * argValue - info on one value of an occurrence of an option * argOccur - info on one occurrence of an option * argInfo - info on an option and all its occurrences * argKeyword - info on a keyword in the hash table * * DESCRIPTION * From top down, the keyword hash table is constructed of argKeyword * structs, each one containing the keyword hashed, and a pointer to * an argInfo struct for it. Hash collisions are handled by constructing * a linked list of argKeyword structs hanging off the initial argKeyword * struct in the table. * * An argInfo struct contains a pointer to the caller's original * ArgOption description, a count of the number of occurrences of * the option on the parsed command line (initially zero), and a pointer * to a linked list of such occurrences (initially NULL). * * An argOccur struct contains info on a single occurrence of an option * and its values on the command line. It contains a count of the * number of values and a linked list of that many argValue structs. * argOccur struct's are also linked together into a linked list in the * order in which options occur on the command-line. arg_next points to * the next in this list, while arg_option is a back-pointer to the * ArgOption struct for the option. * * An argValue struct is just an ArgValue struct with a linked list pointer * to point to the next value in the list. */ typedef struct argValue { ArgValue arg_value; /* Value information */ struct argValue *arg_next; /* Next in value list */ } argValue; typedef struct argOccur { int arg_nvalue; /* Number of values in occurrence*/ argValue *arg_value; /* List of values for option */ struct argOccur *arg_next; /* Next in occurrence list */ struct ArgOption *arg_option; /* Option owning this data */ struct argOccur *arg_clnext; /* Next in command line order */ int arg_noption; /* Option # in command line order*/ } argOccur; typedef struct argInfo { ArgOption *arg_option; /* Option for argument */ int arg_noccur; /* Number of occurrences of option*/ argOccur *arg_occur; /* List of occurrences */ } argInfo; typedef struct argKeyword { char arg_keyword[ARGKMAXLEN];/* Keyword name */ argInfo *arg_info; /* Information on option */ struct argKeyword *arg_next; /* Next in collision list */ } argKeyword; /* * GLOBAL * argStandard - standard options * argStandardRegister - standard -register option * argStandardFeedback - standard -feedback option * * DESCRIPTION * argStandard provides information on the standard options -help, * -feedback, -register, and -version. The hash table is primed with * these options before parsing the command-line. */ #define ARGNSTANDARD 3 static ArgOption argStandard[ARGNSTANDARD] = { { "help", NULL, "Give help about specific options", ARGFNONE, 0, 0, ARGTNONE }, { "fullhelp", NULL, "Display a full-length help message", ARGFNONE, 0, 0, ARGTNONE }, { "version", NULL, "Display the command's version numbers", ARGFFULLHELP, 0, 0, ARGTNONE } }; static ArgOption argStandardRegister[1] = { { "register", NULL, "Generate a user registration form%end\ Create a software user registration form in the file %command.reg.0", ARGFFULLHELP, 0, 0, ARGTNONE }, }; static ArgOption argStandardFeedback[1] = { { "feedback", NULL, "Generate a feedback form (bug report)%end\ Create a software feedback (bug report) form in the file %command.fbk.0", ARGFFULLHELP, 0, 0, ARGTNONE }, }; #define ARGNSTANDARDOPT (ARGNSTANDARD + 2) /* * GLOBALS * argKeywordTable - Keyword hash table * argKeywordTableLength - Length of the hash table * * DESCRIPTION * The keyword hash table is the primary data structure for referencing * parsed command-line information. All keywords, equivalent keywords, * and their truncation abbreviations are entered into the hash table. * Keywords, equivalent keywords and abbreviations that all refer to * the same option, all point to the same argInfo structure. * * The size of the hash table is determined and the space dynamically * allocated by ArgParse(). */ static int argKeywordTableLength = 0;/* Size of hash table */ static argKeyword *argKeywordTable = NULL;/* Hash table of keywords */ /* * MACROS * EndOfLineString * EndOfLineStringLength * * DESCRIPTION * This symbol in the help string seperates the one line help string * from the detailed help string. i.e. The detailed help string is only * printed when -help -option is specified. The one line help string * is printed when the options are listed. * * EndOfLineStringLength is the length of the complete string. */ #define EndOfLineString "%end" #define EndOfLineStringLength 4 /* * TYPEDEF & STRUCTURE * argHelpOption - alphabetical option list entry * * DESCRIPTION * For the printing of the option list information in a help message, * ArgParse() creates alphabetically sorted lists of the option * structures. Each entry in the list is an argHelpOption struct. * Each struct gives the keyword or equivalent keyword and a pointer * to the option information. Note that abbreviated keywords and * equivalent keywords are not entered in this list. */ typedef struct argHelpOption { char *arg_keyword; ArgOption *arg_option; } argHelpOption; #ifdef __STDC__ static int argSortCompare( argHelpOption *, argHelpOption * ); static char* argPrintOneLineHelp( argHelpOption *); #else static int argSortCompare( ); static char* argPrintOneLineHelp( ); #endif /* * GLOBALS * argHelpCommandName - name of the command (argv[0]) * argHelpCommand - command struct for -help and -fullhelp * argHelpNOptionList - # of options in argHelpOptionList * argHelpOptionList - options list for -help * argFullHelpNOptionList - # of options in argFullHelpOptionList * argFullHelpOptionList - options list for -fullhelp * * DESCRIPTION * These globals provide information needed by ArgHelp() in printing * a help message. * * argHelpCommandName is the name of the command, as invoked. This * is simply argv[0]. * * argHelpCommand is a pointer to the user's ArgCommand struct. * * ArgHelpNOptionList and ArgFullHelpNOptionList are the lengths of the * alphabetical option lists, and ArgHelpOptionList and ArgFullHelpOption- * List are pointers to the heads of these lists. The alphabetical * option lists are used in printing the list of options in help messages. */ static char *argHelpCommandName; /* argv[0] */ static ArgCommand *argHelpCommand; /* Command info */ static int argHelpNOptionList; /* Length of list */ static argHelpOption *argHelpOptionList; /* Sorted option list */ static int argFullHelpNOptionList; /* Length of list */ static argHelpOption *argFullHelpOptionList; /* Sorted option list */ /* * GLOBALS * argOptionOrder - Options in command-line order * argNOpt - Number of options on command-line * * DESCRIPTION * During the parsing of the command-line, the options are linked * in to a command-line order list of occurrences and the number of * options counted. */ static int argNOpt = 0; /* # of options */ static argOccur *argOptionOrder = NULL; /* Command-line order list*/ /* * FUNCTION * ArgPError - Print error message * * DESCRIPTION * The error text associated with the current ArgErrNo is printed * to stderr, preceded by the given leader string. */ void /* Returns nothing */ #ifdef __STDC__ ArgPError( char *s ) #else ArgPError( s ) char *s; /* Leader string */ #endif { if ( ArgErrNo == ARGESYS ) perror( s ); else if ( ArgErrNo < 0 || ArgErrNo >= ArgNErr ) (void)fprintf( stderr, "Unknown error\n" ); else if ( s && *s ) (void)fprintf( stderr, "%s: %s\n", s, ArgErrList[ArgErrNo] ); else (void)fprintf( stderr, "%s\n", ArgErrList[ArgErrNo] ); } /* * FUNCTION * ArgQError - Query error message * * DESCRIPTION * The error text associated with the current ArgErrNo is returned. */ extern int errno; /* System call error code */ extern int sys_nerr; /* # of system call error codes */ extern char *sys_errlist[]; /* Error code message strings */ char * /* Returns error text */ #ifdef __STDC__ ArgQError( void ) #else ArgQError( ) #endif { if ( ArgErrNo == ARGESYS ) { if ( errno < 0 || errno >= sys_nerr ) return ( "Unknown error" ); return ( sys_errlist[errno] ); } if ( ArgErrNo < 0 || ArgErrNo >= ArgNErr ) return ( "Unknown error" ); return ( ArgErrList[ArgErrNo] ); } /* * FUNCTION * argHash - hash a keyword to get its hash table index * * DESCRIPTION * The keyword's ASCII characters are added together and the result * modulo the hash table size returned as the hash table index. */ static int /* Returns hash index */ #ifdef __STDC__ argHash( char *keyword ) #else argHash( keyword ) char *keyword; /* Keyword to hash */ #endif { int i = 0; /* Hash index */ while ( *keyword ) i += *keyword++; return ( i % argKeywordTableLength ); } #ifdef DEBUG /* * FUNCTION * argPrint - print the hash table for debugging * * DESCRIPTION * The hash table is walked and each entry, and its collision chain * printed to stderr. */ static void /* Returns nothing */ #ifdef __STDC__ argPrint( void ) #else argPrint( ) #endif { int i = 0; /* Hash table index */ argKeyword *ak; /* Hash table pointer */ (void)fprintf( stderr, "Hash table dump (%d entries):\n", argKeywordTableLength ); for ( i = 0; i < argKeywordTableLength; i++ ) { (void)fprintf( stderr, "[%2d] ", i ); ak = &argKeywordTable[i]; if ( ak->arg_info == NULL ) { (void)fprintf( stderr, "empty\n" ); continue; } (void)fprintf( stderr, "%s (%s)\n", ak->arg_keyword, ak->arg_info->arg_option->arg_keyword ); for ( ak = ak->arg_next; ak; ak = ak->arg_next ) (void)fprintf( stderr, " %s (%s)\n", ak->arg_keyword, ak->arg_info->arg_option->arg_keyword ); } } #endif /* DEBUG */ /* * FUNCTION * argFind - find a keyword's entry in the hash table * * DESCRIPTION * The keyword is hashed and looked up in the hash table. The table's * first entry, and its collision list, are searched until an entry * is found that matches the keyword. A pointer to the entry found, * or NULL if none is found, is returned. */ static argInfo * /* Returns table entry */ #ifdef __STDC__ argFind( char *keyword ) #else argFind( keyword ) char *keyword; /* Keyword to find in table */ #endif { argKeyword *ak; /* Keyword entry found */ ak = &argKeywordTable[argHash( keyword )]; while ( ak && strcmp( ak->arg_keyword, keyword ) != 0 ) ak = ak->arg_next; if ( !ak ) return ( NULL ); return ( ak->arg_info ); } /* * FUNCTION * argAdd - add an entry to the hash table * * DESCRIPTION * The keyword, and all its truncation abbreviations, are added to * the hash table. For each one of these, the name is hashed and * looked up in the hash table. The table entry, and each entry in * its collision list is searched to see if the name is already in * the table. If it is, then either we have an error (if both * that in the table, and the one we are adding are not abbreviations), * or we have two keywords with a common set of abbreviations. * In the later case we search for those abbreviations and remove them. */ static int /* Returns status */ #ifdef __STDC__ argAdd( char *keyword, argInfo *info ) #else argAdd( keyword, info ) char *keyword; /* Keyword to add to hash table */ argInfo *info; /* Options occurrence info */ #endif { char *s; /* String pointer */ argKeyword *ak; /* Hash table entry */ char str[ARGKMAXLEN]; /* Temporary keyword holder */ argKeyword *aktmp; /* Temp hash table entry */ argKeyword *akfirst; /* First Hash table entry */ int len; /* Length of temp keyword holder*/ argInfo *oldinfo; /* Old option's info */ /* * For every abbreviation of the keyword, add the option and its * info structure to the hash table. */ s = str; (void)strcpy( s, keyword ); for ( len = strlen( s ); *s; s[--len] = '\0' ) { akfirst = ak = &argKeywordTable[argHash( s )]; if ( ak->arg_info == NULL ) { /* * Use this entry for the new keyword and option info. */ (void)strcpy( ak->arg_keyword, s ); ak->arg_info = info; continue; } /* * Hash table entry already in use. For this entry, * and each entry in the collision chain, check to * see if we have the same keyword. */ do { if ( strcmp( ak->arg_keyword, s ) != 0 ) continue; /* Not the same */ /* * Keyword's are the same. One of four situations * has occurred: * * 1. Keyword in table is unabbreviated, and our * new keyword is unabbreviated: * The programmer goofed. Issue an * error and exit. * * 2. Keyword in table is unabbreviated, and our * new keyword is abbreviated: * We can't use this abbreviation, or * any further ones for our new keyword. * Remove all abbreviations of table * keyword. * * 3. Keyword in table is abbreviated, and our * new keyword is unabbreviated: * We can't use any of our new keyword's * abbreviations and all shorter * abbreviations of the table keyword must * be removed from the table. * * 4. Keyword in table is abbreviated, and our new * keyword is abbreviated: * This and all further abbreviations of * our new keyword and the table keyword * are non-unique and must be removed * from the table. */ oldinfo = ak->arg_info; if ( strcmp( oldinfo->arg_option->arg_keyword, ak->arg_keyword ) == 0 ) { /* * The keyword in the table already is not * an abbreviation. */ if ( strcmp( s, keyword ) == 0 ) { /* * Neither is this an abbreviation. * So, we have two keywords that are * identical. Programmer error. */ return ( -2 ); } /* * All abbreviations of the keyword already * in the table will collide with those of * the new keyword. Fall through and delete * those entries from the table. */ s[--len] = '\0'; } else { /* * The keyword in the table already is * an abbreviation. */ if ( strcmp( s, keyword ) == 0 ) { /* * Our new keyword isn't yet an * abbreviation. Take over the * table entry that used to be for * some other keyword's abbreviation. */ ak->arg_info = info; s[--len] = '\0'; } /* * All abbreviations of the keyword already * in the table will collide with those of * the new keyword. Fall through and delete * those entries from the table. */ } /* * Remove non-unique abbreviations. */ for ( ; *s ; s[--len] = '\0' ) { ak = &argKeywordTable[argHash( s )]; if ( ak->arg_info == NULL ) continue; /* Nothing there */ if ( ak->arg_info == oldinfo && strcmp( ak->arg_keyword, s ) == 0 ) { /* * Remove entry from table and move * 1st collision list entry up. */ if ( ak->arg_next == NULL ) { ak->arg_info = NULL; continue; } aktmp = ak->arg_next; (void)strcpy( ak->arg_keyword, aktmp->arg_keyword ); ak->arg_info = aktmp->arg_info; ak->arg_next = aktmp->arg_next; free( aktmp ); /* fall thru to check collisions too */ } /* * Walk the collision list and unlink the * abbreviation's entry (if found). */ if ( ak->arg_next == NULL ) continue; for ( aktmp = ak, ak = ak->arg_next; ak; aktmp = ak, ak = ak->arg_next ) { if ( ak->arg_info != oldinfo ) continue; if ( strcmp( ak->arg_keyword, s ) != 0 ) continue; aktmp->arg_next = ak->arg_next; free( ak ); break; } } return ( 0 ); } while ( (ak = ak->arg_next) ); /* * None of the collision entries were for this keyword. * Add us to the front of the collision chain. */ if ( (ak = (argKeyword *)malloc( (unsigned int )sizeof( argKeyword ))) == NULL ) return ( -1 ); (void)strcpy( ak->arg_keyword, s ); ak->arg_info = info; ak->arg_next = akfirst->arg_next; akfirst->arg_next = ak; } return ( 0 ); } /* * FUNCTION * ArgHelp - print a -help message * ArgFullHelp - print a -fullhelp message * * DESCRIPTION * A help message containing a usage line, the first part of the help * text, a list of options, and the second part of the help text is * printed to stderr. */ int /* Returns status */ #ifdef __STDC__ ArgHelp( void ) #else ArgHelp( ) #endif { char line[81]; /* Output line buffer */ char tmp[81]; /* Temporary line buffer */ char *help1tmp; /* Temporary help string holder */ char *help2tmp; /* Temporary help string holder */ int i, j; /* Counter */ int len; /* Current line length */ argHelpOption *ah; /* Help option list pointer */ int nOpt; /* Number of options */ int specificHelp = 0; /* Flag: Are we doing help for specific options? */ char *optionName; /* Name of one option */ int nOccur; /* number of occurences of an option */ char message[80]; /* Brief message */ char* tmpStr; /* temporary char * */ /* Give help for specific options, if any are given */ if ( (nOpt = ArgQNOpt()) > 1) specificHelp = 1; /* * Print a usage line of the form: * * Usage: name options... * * 'name' is argv[0]. * * 'options' is either the arg_usage text given in the caller's * ArgCommand structure, or it is generated automatically as a * list of the option keywords and their valuenames strings with * square brackets around optional options and implied keywords. * Hidden and FullHelp options are omitted. */ if ( argHelpCommand->arg_usage ) (void)fprintf( stderr, "Usage : %s %s\n", argHelpCommandName, argHelpCommand->arg_usage ); else { (void)sprintf( line, "Usage : %s ", argHelpCommandName ); len = strlen( line ); for ( i=0, ah=argHelpOptionList; iarg_option->arg_flags & ARGFHIDDEN) || (ah->arg_option->arg_flags & ARGFFULLHELP) ) continue; if ( ah->arg_option->arg_valuenames && ah->arg_option->arg_valuenames[0] != '\0' ) { if ( ah->arg_option->arg_flags & ARGFREQUIRED ) { if ( ah->arg_option->arg_flags & ARGFIMPKEYWORD) (void)sprintf( tmp, "[-%s] %s ", ah->arg_keyword, ah->arg_option->arg_valuenames); else (void)sprintf( tmp, "-%s %s ", ah->arg_keyword, ah->arg_option->arg_valuenames); } else { if ( ah->arg_option->arg_flags & ARGFIMPKEYWORD) (void)sprintf( tmp, "[[-%s] %s] ", ah->arg_keyword, ah->arg_option->arg_valuenames); else (void)sprintf( tmp, "[-%s %s] ", ah->arg_keyword, ah->arg_option->arg_valuenames); } } else { if ( ah->arg_option->arg_flags & ARGFREQUIRED ) { if ( ah->arg_option->arg_flags & ARGFIMPKEYWORD) (void)sprintf( tmp, "[-%s] ", ah->arg_keyword ); else (void)sprintf( tmp, "-%s ", ah->arg_keyword ); } else (void)sprintf( tmp, "[-%s] ", ah->arg_keyword ); } if ( strlen( tmp ) + len > 80 ) { (void)fprintf( stderr, "%s\n", line ); (void)sprintf( line, " " ); len = strlen( line ); } (void)strcat( line, tmp ); len += strlen( tmp ); } (void)fprintf( stderr, "%s\n", line ); } /* * Print a copyright message, if any. */ if ( argHelpCommand->arg_copyright && specificHelp==0) (void)fprintf( stderr, "\n%s\n\n", argHelpCommand->arg_copyright ); /* * Make a temporary private copy of the help text before we scan, * potentially modify, and print it. * * This may seem like a dumb, inefficient, and unneccesary thing * to do, and it is. However, it really is necessary for portability. * A command's help text is typically assigned to the ArgCommand * structure by a compile-time initialization. On some hosts (such * as the NeXT and its MACH Gnu C compiler) such compile-time * initialized data is placed into a write-protected data segment * that cannot be changed at run-time without causing a memory error. * Since we do need to make minor changes at run-time, we are forced * to make a private copy in an unprotected segment and change the * copy instead of the original. */ if ( argHelpCommand->arg_help1 && specificHelp==0) { if ( (help1tmp = (char *)malloc( (unsigned int )(strlen( argHelpCommand->arg_help1 ) + 1) )) == NULL ) { (void)fprintf( stderr, "%s: Out of memory in argument parsing!\n", argHelpCommandName ); exit( 1 ); /*NOTREACHED*/ } (void)strcpy( help1tmp, argHelpCommand->arg_help1 ); } else help1tmp = NULL; if ( argHelpCommand->arg_help2 && specificHelp==0) { if ( (help2tmp = (char *)malloc( (unsigned int)(strlen( argHelpCommand->arg_help2 ) + 1) )) == NULL ) { (void)fprintf( stderr, "%s: Out of memory in argument parsing!\n", argHelpCommandName ); exit( 1 ); /*NOTREACHED*/ } (void)strcpy( help2tmp, argHelpCommand->arg_help2 ); } else help2tmp = NULL; /* * If there are options beyond the help option, then * for each option, print the help text accompanying * this option (if any). * * If there are no options beyond the help option, then * print the command help text. */ if ( specificHelp==1 ) { /* Print help for each command that was given. */ for (i=1; i < nOpt; i++) { /* * Copy the help string into a buffer (for the same * reasons given above). Then search for the * string EndOfLineString in the line. If it's there * then give specific help about this option. * If it's not there, explain that there is no * specific help for this option. * * You may be wondering why there is simply not * another element of the structure containing * extra help for an option. * * There should be. However, this package was * not designed with this function in mind, so * to preserve backwards compatibility, we're * doing it this way. */ /* Get the name of option number i */ optionName = ArgQOpt (i, &nOccur); for ( j=0, ah=argFullHelpOptionList; jarg_keyword, optionName)==0) break; } if (j