#include #include #include #include "options.h" /* Process one "normal" (i.e. integer, float, string, or boolean) option. */ int do_normal_option(option *opt, char *s) { switch (opt->type) { case OPT_INT: if (opt->otherptr) *opt->otherptr = 1; *(int *)opt->retptr = strtol(s, NULL, 0); break; case OPT_FLOAT: if (opt->otherptr) *opt->otherptr = 1; *(float *)opt->retptr = strtod(s, NULL); break; case OPT_STRING: if (opt->otherptr) *opt->otherptr = 1; *(char **)opt->retptr = s; break; case OPT_BOOL: if (opt->otherptr) *opt->otherptr = 1; if (*s == '0') *(int *)opt->retptr = 0; else *(int *)opt->retptr = 1; break; default: fprintf(stderr, "do_normal_option: unknown type %d", opt->type); return -1; } return 0; } /* Process one array-based option. */ int do_array_option(option *opt, char *str) { int *ints, *intbase; float *floats, *floatbase; int type = opt->type & 0xFF, num; char *s, *t; s = malloc(strlen(str)+2); if (!s) { fprintf(stderr, "out of memory\n"); return -1; } strcpy(s, str); num = 1; while (t = strchr(s, ',')) { strcpy(s, t+1); ++num; } strcat(strcpy(s, str), ","); switch (type) { case OPT_INT: if (opt->otherptr) *opt->otherptr = num; ints = intbase = malloc(sizeof(int) * num); while (*s) { t = strchr(s, ','); *t++ = 0; *ints++ = strtol(s, NULL, 0); strcpy(s, t); } *(int **)opt->retptr = intbase; break; case OPT_FLOAT: if (opt->otherptr) *opt->otherptr = num; floats = floatbase = malloc(sizeof(int) * num); while (*s) { t = strchr(s, ','); *t++ = 0; *floats++ = strtod(s, NULL); strcpy(s, t); } *(float **)opt->retptr = floatbase; break; case OPT_STRING: fprintf(stderr, "do_array_option: array of strings illegal\n"); return -1; case OPT_BOOL: if (opt->otherptr) *opt->otherptr = num; ints = intbase = malloc(sizeof(int) * num); while (*s) { t = strchr(s, ','); *t++ = 0; if (*s == '0') *ints++ = 0; else *ints++ = 1; strcpy(s, t); } *(int **)opt->retptr = intbase; break; default: fprintf(stderr, "do_array_option: unknown type %d", type); return -1; } return 0; } /* Read and process all '-' options; leave other arguments in argv, and return * new value of argc. Pointers returned are not modifiable. A return value * of -1 indicates that an error occurred while processing the options. */ int do_options(int argc, char **argv, option *options) { char *s; int arg = 1, i, n, nlen; option *opt; while (arg < argc) if (*(s = argv[arg]) == '-') { --argc; for (i = arg; i < argc; i++) argv[i] = argv[i+1]; s++; n = -1; nlen = 0; for (opt = options, i = 0; opt->name; opt++, i++) { if (!strncmp(s, opt->name, strlen(opt->name))) { /* Check for a perfect match... */ if (!isalpha( s[strlen(opt->name)] )) { n = i; break; } /* Else we might have a case like "-s" matching * "-ss300". Try to match the longest string * possible... */ if (strlen(opt->name) > nlen) { n = i; nlen = strlen(opt->name); } } } /* Did we find a match? */ if (n >= 0) { opt = &options[n]; s += strlen(opt->name); if (!*s && opt->type != OPT_BOOL) { s = argv[arg]; --argc; for (i = arg; i < argc; i++) argv[i] = argv[i+1]; } switch (opt->type & ~0xFF) { case 0: if (n = do_normal_option(opt, s)) return n; break; case OPT_ARRAY: if (n = do_array_option(opt, s)) return n; break; default: fprintf(stderr, "do_options: unknown type %d", opt->type); return -1; } } else { fprintf(stderr, "Unknown option -%s\n", s); } } else arg++; return argc; }