lib/options.c

Go to the documentation of this file.
00001 /* Options.c - stuff to handle command line options.
00002  * This is smaller and more flexible than the cgiSpoof
00003  * routines we used to use - though cgiSpoof is still the
00004  * method of choice for actual CGI routines that want to
00005  * be tested from the command line. 
00006  *
00007  * This file is copyright 2002 Jim Kent, but license is hereby
00008  * granted for all use - public, private or commercial. */
00009 
00010 #include "common.h"
00011 #include "hash.h"
00012 #include "verbose.h"
00013 #include "options.h"
00014 
00015 static char const rcsid[] = "$Id: options.c,v 1.24 2005/12/12 04:03:40 kent Exp $";
00016 
00017 #ifdef MACHTYPE_alpha
00018     #define strtoll strtol
00019 #endif
00020 
00021 /* mask for type in optionSpec.flags */
00022 #define OPTION_TYPE_MASK (OPTION_BOOLEAN|OPTION_STRING|OPTION_INT|OPTION_FLOAT|OPTION_LONG_LONG|OPTION_DOUBLE)
00023 
00024 static struct optionSpec commonOptions[] = {
00025    {"verbose", OPTION_INT},
00026    {NULL, 0},
00027 };
00028 
00029 static struct optionSpec *matchingOption(char *name, struct optionSpec *optionSpecs)
00030 /* Go through spec table and return spec that matches name, or NULL
00031  * if none. */
00032 {
00033 while (optionSpecs->name != NULL)
00034     {
00035     if (sameString(optionSpecs->name, name))
00036         return optionSpecs;
00037     optionSpecs += 1;
00038     }
00039 return NULL;
00040 }
00041 
00042 static void validateOption(char *name, char *val, struct optionSpec *optionSpecs)
00043 /* validate an option against a list of values */
00044 {
00045 char *valEnd;
00046 struct optionSpec *optionSpec = matchingOption(name, optionSpecs);
00047 if (optionSpec == NULL)
00048     optionSpec = matchingOption(name, commonOptions);
00049 if (optionSpec == NULL)
00050     errAbort("-%s is not a valid option", name);
00051 
00052 switch (optionSpec->flags & OPTION_TYPE_MASK) {
00053 case OPTION_BOOLEAN:
00054     if (val != NULL)
00055         errAbort("boolean option -%s must not have value", name);
00056     break;
00057 case OPTION_STRING:
00058     if (val == NULL)
00059         errAbort("string option -%s must have a value", name);
00060     break;
00061 case OPTION_INT:
00062     if (val == NULL)
00063         errAbort("int option -%s must have a value", name);
00064     strtol(val, &valEnd, 10);
00065     if ((*val == '\0') || (*valEnd != '\0'))
00066         errAbort("value of -%s is not a valid integer: \"%s\"",
00067                  name, val);
00068     break;
00069 case OPTION_LONG_LONG:
00070     if (val == NULL)
00071         errAbort("int option -%s must have a value", name);
00072     strtoll(val, &valEnd, 10);
00073     if ((*val == '\0') || (*valEnd != '\0'))
00074         errAbort("value of -%s is not a valid long long: \"%s\"",
00075                  name, val);
00076     break;
00077 case OPTION_FLOAT:
00078     if (val == NULL)
00079         errAbort("float option -%s must have a value", name);
00080     strtod(val, &valEnd);
00081     if ((*val == '\0') || (*valEnd != '\0'))
00082         errAbort("value of -%s is not a valid float: \"%s\"",
00083                  name, val);
00084     break;
00085 case OPTION_DOUBLE:
00086     if (val == NULL)
00087         errAbort("double option -%s must have a value", name);
00088     strtod(val, &valEnd);
00089     if ((*val == '\0') || (*valEnd != '\0'))
00090         errAbort("value of -%s is not a valid double: \"%s\"",
00091                  name, val);
00092     break;
00093 default:
00094     errAbort("bug: invalid type in optionSpec for %s", optionSpec->name);
00095 }
00096 }
00097 
00098 static void parseMultiOption(struct hash *hash, char *name, char* val, struct optionSpec *spec)
00099 /* process multiple instances of an option, requres that the optionSpec of the option */
00100 {
00101 struct slName *valList;
00102 switch (spec->flags & OPTION_TYPE_MASK)
00103     {
00104     case OPTION_STRING:
00105         valList = hashFindVal(hash, name);
00106         if (valList == NULL)   /* first multi option */
00107             {
00108             valList = newSlName(val);
00109             hashAdd(hash, name, valList);
00110             }
00111         else
00112             {
00113             struct slName *el = newSlName(val);
00114             slAddTail(valList, el); /* added next multi option */
00115             }
00116         break;
00117     default:
00118         errAbort("UNIMPLEMENTED: multiple instances of a non-string option is not currently implemented");
00119     }
00120 }
00121 
00122 static boolean parseAnOption(struct hash *hash, char *arg, struct optionSpec *optionSpecs)
00123 /* Parse a single option argument and add to the hash, validating if
00124  * optionSpecs is not NULL.  Return TRUE if it's arg is an option argument
00125  * FALSE if it's not.
00126  */
00127 {
00128 char *name, *val;
00129 char *eqPtr = strchr(arg, '=');
00130 
00131 if (!((eqPtr != NULL) || (arg[0] == '-')))
00132     return FALSE;  /* not an option */
00133 
00134 /* A dash by itself is not an option.   It can mean
00135  * negative strand for some of the DNA oriented utilities. */
00136 if (arg[0] == '-' && (arg[1] == 0 || isspace(arg[1])))
00137     return FALSE;
00138 
00139 /* It's nice to be able to use url's in the command line, but they
00140  * may have = in them... */
00141 if (startsWith("http://", arg))
00142     return FALSE;
00143 
00144 name = arg;
00145 if (name[0] == '-')
00146     name++;
00147 if (eqPtr != NULL)
00148     {
00149     *eqPtr = '\0';
00150     val = eqPtr+1;
00151     }
00152 else
00153     val = NULL;
00154 
00155 if (optionSpecs != NULL)
00156     validateOption(name, val, optionSpecs);
00157 if (val == NULL)
00158     val = "on";
00159 if (optionSpecs == NULL)
00160     hashAdd(hash, name, val);
00161 else
00162     {
00163     struct optionSpec *spec = matchingOption(name, optionSpecs);
00164     if (spec != NULL && (spec->flags & OPTION_MULTI))    /* process multiple instances of option */
00165         parseMultiOption(hash, name, val, spec);
00166     else
00167         hashAdd(hash, name, val);
00168     }
00169 
00170 if (eqPtr != NULL)
00171     *eqPtr = '=';
00172 return TRUE;
00173 }
00174 
00175 
00176 static struct hash *parseOptions(int *pArgc, char *argv[], boolean justFirst,
00177                                  struct optionSpec *optionSpecs)
00178 /* Parse and optionally validate options */
00179 {
00180 int i, origArgc, newArgc = 1;
00181 char **rdPt = argv+1, **wrPt = argv+1;
00182 struct hash *hash = newHash(6);
00183 
00184 origArgc = *pArgc;
00185 
00186 /* parse arguments */
00187 for (i=1; i<origArgc; ++i)
00188     {
00189     if (sameString(*rdPt, "--"))
00190         {
00191         rdPt++;
00192         i++;
00193         break;
00194         }
00195     if (!parseAnOption(hash, *rdPt, optionSpecs))
00196         {
00197         /* not an option */
00198         if (justFirst)
00199             break;
00200         *wrPt++ = *rdPt;
00201         newArgc++;
00202         }
00203     rdPt++;
00204     }
00205 
00206 /* copy any remaining positional args */
00207 for (; i<origArgc; ++i)
00208     {
00209     *wrPt++ = *rdPt++;
00210     newArgc++;
00211     }
00212 
00213 *pArgc = newArgc;
00214 *wrPt = NULL; 
00215 return hash;
00216 }
00217 
00218 struct hash *optionParseIntoHash(int *pArgc, char *argv[], boolean justFirst)
00219 /* Read options in command line (only up to first real argument) into
00220  * options hash.   Options come in three forms:
00221  *      -option         words starting with dash
00222  *      option=val      words with = in the middle
00223  *      -option=val     combining the two.
00224  * The resulting hash will be keyed by the option name with the val
00225  * string for value.  For '-option' types the value is 'on'. */
00226 {
00227 return parseOptions(pArgc, argv, justFirst, NULL);
00228 }
00229 
00230 static struct hash *options = NULL;
00231 static struct optionSpec *optionSpecification = NULL;
00232 
00233 static void setOptions(struct hash *hash)
00234 /* Set global options hash to hash, and also do processing
00235  * of log file and other common options. */
00236 {
00237 options = hash;
00238 if (optionExists("verbose"))
00239     verboseSetLevel(optionInt("verbose", 0));
00240 }
00241 
00242 void optionHashSome(int *pArgc, char *argv[], boolean justFirst)
00243 /* Set up option hash from command line, optionally only adding
00244  * up to first non-optional word. */
00245 {
00246 if (options == NULL)
00247     {
00248     struct hash *hash = parseOptions(pArgc, argv, justFirst, NULL);
00249     setOptions(hash);
00250     }
00251 }
00252 
00253 void optionHash(int *pArgc, char *argv[])
00254 /* Read options in command line into options hash.   
00255  * Options come in three forms:
00256  *      -option         words starting with dash
00257  *      option=val      words with = in the middle
00258  *      -option=val     combining the two.
00259  * The resulting hash will be keyed by the option name with the val
00260  * string for value.  For '-option' types the value is 'on'. */
00261 {
00262 optionHashSome(pArgc, argv, FALSE);
00263 }
00264 
00265 void optionInit(int *pArgc, char *argv[], struct optionSpec *optionSpecs)
00266 /* Read options in command line into options hash.
00267  * Options come in three forms:
00268  *      -option         words starting with dash
00269  *      option=val      words with = in the middle
00270  *      -option=val     combining the two.
00271  * The resulting hash will be keyed by the option name with the val
00272  * string for value.  For '-option' types the value is 'on'.
00273  * The words in argv are parsed in assending order.  If a word of
00274  * "--" is encountered, argument parsing stops.
00275  * If optionSpecs is not NULL, it is an array of optionSpec that are
00276  * used to validate the options.  An option must exist in the array
00277  * and the value must be convertable to the type specified in flags.
00278  * Boolean options must no value, all other options must have one.
00279  * Array is terminated by a optionSpec with a NULL name.
00280  * If array NULL, no validation is done.
00281  */
00282 {
00283 if (options == NULL)
00284     {
00285     struct hash *hash = parseOptions(pArgc, argv, FALSE, optionSpecs);
00286     setOptions(hash);
00287     optionSpecification = optionSpecs;
00288     }
00289 }
00290 
00291 static char *optGet(char *name)
00292 /* Lookup option name.  Complain if options hash not set. */
00293 {
00294 if (options == NULL)
00295     errAbort("optGet called before optionHash");
00296 return hashFindVal(options, name);
00297 }
00298  
00299 char *optionVal(char *name, char *defaultVal)
00300 /* Return named option if in options hash, otherwise default. */
00301 {
00302 char *ret;
00303 /* if a optionSpec was used, make sure this option is not a multi option */
00304 if(optionSpecification != NULL) {
00305     struct optionSpec *spec = matchingOption(name, optionSpecification);
00306     if(spec != NULL && (spec->flags & OPTION_MULTI))    
00307         errAbort("ERROR: optionVal cannot be used to get the value of an OPTION_MULTI");
00308 }
00309 
00310 ret = optGet(name);
00311 if (ret == NULL)
00312      ret = defaultVal;
00313 return ret;
00314 }
00315 
00316 int optionInt(char *name, int defaultVal)
00317 /* Return integer value of named option, or default value
00318  * if not set. */
00319 {
00320 char *s = optGet(name);
00321 char *valEnd;
00322 int val;
00323 if (s == NULL)
00324     return defaultVal;
00325 if (sameString(s,"on"))
00326     return defaultVal;
00327 val = strtol(s, &valEnd, 10);
00328 if ((*s == '\0') || (*valEnd != '\0'))
00329     errAbort("value of -%s is not a valid integer: \"%s\"", name, s);
00330 return val;
00331 }
00332 
00333 long long optionLongLong(char *name, long long defaultVal)
00334 /* Return long long value of named option, or default value
00335  * if not set. */
00336 {
00337 char *s = optGet(name);
00338 char *valEnd;
00339 long long val;
00340 if (s == NULL)
00341     return defaultVal;
00342 if (sameString(s,"on"))
00343     return defaultVal;
00344 val = strtoll(s, &valEnd, 10);
00345 if ((*s == '\0') || (*valEnd != '\0'))
00346     errAbort("value of -%s is not a valid long long: \"%s\"", name, s);
00347 return val;
00348 }
00349 
00350 float optionFloat(char *name, float defaultVal)
00351 /* Return floating point value or default value if not set. */
00352 {
00353 char *s = optGet(name);
00354 char *valEnd;
00355 float val;
00356 if (s == NULL)
00357     return defaultVal;
00358 
00359 val = strtod(s, &valEnd);
00360 if ((*s == '\0') || (*valEnd != '\0'))
00361     errAbort("value of -%s is not a valid float: \"%s\"", name, s);
00362 return val;
00363 }
00364 
00365 struct slName *optionMultiVal(char *name, struct slName *defaultVal)
00366 /* Return named option if in options hash, otherwise default. */
00367 {
00368 struct slName *ret;
00369 if(optionSpecification == NULL)
00370     errAbort("ERROR: optionMultiVal can only be used after optionInit is called "
00371              "with a non-NULL optionSpecs");
00372 
00373 ret = hashFindVal(options, name);
00374 if (ret == NULL)
00375      ret = defaultVal;
00376 return ret;
00377 }
00378 
00379 double optionDouble(char *name, double defaultVal)
00380 /* Return double value or default value if not set */
00381 {
00382 char *s = optGet(name);
00383 char *valEnd;
00384 double val;
00385 if (s == NULL)
00386     return defaultVal;
00387 
00388 val = strtod(s, &valEnd);
00389 if ((*s == '\0') || (*valEnd != '\0'))
00390     errAbort("value of -%s is not a valid double: \"%s\"", name, s);
00391 return val;
00392 }
00393 
00394 boolean optionExists(char *name)
00395 /* Return TRUE if option has been set. */
00396 {
00397 return optGet(name) != NULL;
00398 }
00399 
00400 void optionMustExist(char *name)
00401 /* Abort if option has not been set. */
00402 {
00403 if (optGet(name) == NULL)
00404     errAbort("Missing required command line flag %s", name);
00405 }

Generated on Tue Dec 25 18:39:31 2007 for blat by  doxygen 1.5.2