00001
00002
00003
00004
00005
00006
00007
00008
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
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
00031
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
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
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)
00107 {
00108 valList = newSlName(val);
00109 hashAdd(hash, name, valList);
00110 }
00111 else
00112 {
00113 struct slName *el = newSlName(val);
00114 slAddTail(valList, el);
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
00124
00125
00126
00127 {
00128 char *name, *val;
00129 char *eqPtr = strchr(arg, '=');
00130
00131 if (!((eqPtr != NULL) || (arg[0] == '-')))
00132 return FALSE;
00133
00134
00135
00136 if (arg[0] == '-' && (arg[1] == 0 || isspace(arg[1])))
00137 return FALSE;
00138
00139
00140
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))
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
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
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
00198 if (justFirst)
00199 break;
00200 *wrPt++ = *rdPt;
00201 newArgc++;
00202 }
00203 rdPt++;
00204 }
00205
00206
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
00220
00221
00222
00223
00224
00225
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
00235
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
00244
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
00255
00256
00257
00258
00259
00260
00261 {
00262 optionHashSome(pArgc, argv, FALSE);
00263 }
00264
00265 void optionInit(int *pArgc, char *argv[], struct optionSpec *optionSpecs)
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
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
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
00301 {
00302 char *ret;
00303
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
00318
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
00335
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
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
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
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
00396 {
00397 return optGet(name) != NULL;
00398 }
00399
00400 void optionMustExist(char *name)
00401
00402 {
00403 if (optGet(name) == NULL)
00404 errAbort("Missing required command line flag %s", name);
00405 }