00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 #ifdef HAVE_CONFIG_H
00011 # include "config.h"
00012 #endif
00013 #include "clp.h"
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #include <stdio.h>
00017 #include <assert.h>
00018 #include <stdarg.h>
00019 #include <ctype.h>
00020 
00021 
00022 #if !defined(HAVE_STRTOUL) && !defined(HAVE_CONFIG_H)
00023 # define HAVE_STRTOUL 1
00024 #endif
00025 
00026 #ifdef __cplusplus
00027 extern "C" {
00028 #endif
00029 
00030 
00031 #define Clp_DoubledLong         (Clp_LongImplicit * 2)
00032 
00033 #define Clp_AnyArgument (Clp_Mandatory | Clp_Optional)
00034 
00035 #define MAX_AMBIGUOUS_VALUES    4
00036 
00037 typedef struct {
00038   
00039   Clp_ArgParseFunc func;
00040   int flags;
00041   void *thunk;
00042   
00043 } Clp_ArgType;
00044 
00045 
00046 typedef struct {
00047 
00048   int pos;
00049   int neg;
00050 
00051 } Clp_LongMinMatch;
00052 
00053 
00054 struct Clp_Internal {
00055 
00056   Clp_Option *opt;
00057   Clp_LongMinMatch *long_min_match;
00058   int nopt;
00059   
00060   Clp_ArgType *argtype;
00061   int nargtype;
00062   
00063   char * const *argv;
00064   int argc;
00065   
00066   unsigned char option_class[256];
00067   int both_short_and_long;
00068   
00069   char option_chars[3];
00070   char *text;
00071   
00072   char *program_name;
00073   void (*error_handler)(char *);
00074   
00075   int is_short;
00076   int whole_negated;            
00077   int could_be_short;
00078   
00079   int option_processing;
00080   
00081   int ambiguous;
00082   int ambiguous_values[MAX_AMBIGUOUS_VALUES];
00083   
00084   Clp_Option *current_option;
00085   int current_short;
00086   int negated_by_no;
00087   
00088 };
00089 
00090 
00091 struct Clp_ParserState {
00092   
00093   char * const *argv;
00094   int argc;
00095   char option_chars[3];
00096   char *text;
00097   int is_short;
00098   int whole_negated;
00099   
00100 };
00101 
00102 
00103 typedef struct Clp_StringList {
00104 
00105   Clp_Option *items;
00106   Clp_LongMinMatch *long_min_match;
00107   int nitems;
00108   
00109   int allow_int;
00110   int nitems_invalid_report;
00111   
00112 } Clp_StringList;
00113 
00114 
00115 #define TEST(o, f)              (((o)->flags & (f)) != 0)
00116 
00117 
00118 static int calculate_long_min_match(int, Clp_Option *, int, int, int);
00119 
00120 static int parse_string(Clp_Parser *, const char *, int, void *);
00121 static int parse_int(Clp_Parser *, const char *, int, void *);
00122 static int parse_bool(Clp_Parser *, const char *, int, void *);
00123 static int parse_double(Clp_Parser *, const char *, int, void *);
00124 static int parse_string_list(Clp_Parser *, const char *, int, void *);
00125 
00126 static int ambiguity_error(Clp_Parser *, int, int *, Clp_Option *,
00127                            const char *, const char *, ...);
00128 
00129 
00130 
00131 
00132 
00133 
00134 static void
00135 check_duplicated_short_options(int nopt, Clp_Option *opt, int negated)
00136 {
00137   int i;
00138   int check[256];
00139   
00140   for (i = 0; i < 256; i++)
00141     check[i] = -1;
00142   
00143   for (i = 0; i < nopt; i++)
00144     if (opt[i].short_name > 0 && opt[i].short_name < 256
00145         && (negated ? TEST(&opt[i], Clp_Negate)
00146             : !TEST(&opt[i], Clp_OnlyNegated))) {
00147       int sh = opt[i].short_name;
00148       if (check[sh] >= 0 && check[sh] != opt[i].option_id)
00149         fprintf(stderr, "CLP error: more than 1 option has short name `%c'\n",
00150                 sh);
00151       check[sh] = opt[i].option_id;
00152     }
00153 }
00154 
00155 Clp_Parser *
00156 Clp_NewParser(int argc, char * const argv[], int nopt, Clp_Option *opt)
00157      
00158 
00159 {
00160   int i;
00161   Clp_Parser *clp = (Clp_Parser *)malloc(sizeof(Clp_Parser));
00162   Clp_Internal *cli = (Clp_Internal *)malloc(sizeof(Clp_Internal));
00163   Clp_LongMinMatch *lmm = (Clp_LongMinMatch *)malloc(sizeof(Clp_LongMinMatch) * nopt);
00164   if (!clp || !cli || !lmm) goto failed;
00165   
00166   clp->internal = cli;
00167   cli->long_min_match = lmm;
00168   
00169   
00170   for (i = 0; i < nopt; i++)
00171     if (opt[i].option_id < 0) {
00172       fprintf(stderr, "CLP error: option %d has negative option_id\n", i);
00173       opt[i] = opt[nopt - 1];
00174       nopt--;
00175       i--;
00176     }
00177   
00178   
00179   for (i = 0; i < nopt; i++) {
00180     
00181     if (opt[i].arg_type <= 0)
00182       opt[i].flags &= ~Clp_AnyArgument;
00183     if (opt[i].arg_type > 0 && !TEST(&opt[i], Clp_Optional))
00184       opt[i].flags |= Clp_Mandatory;
00185     
00186     
00187 
00188     if (opt[i].short_name <= 0 || opt[i].short_name > 255)
00189       opt[i].short_name = 256;
00190     
00191     
00192     if (opt[i].long_name && strncmp(opt[i].long_name, "no-", 3) == 0) {
00193       opt[i].long_name += 3;
00194       opt[i].flags |= Clp_Negate | Clp_OnlyNegated;
00195     }
00196   }
00197   
00198   
00199   check_duplicated_short_options(nopt, opt, 0);
00200   check_duplicated_short_options(nopt, opt, 1);
00201   
00202   
00203   for (i = 0; i < nopt; i++)
00204     if (opt[i].long_name && !TEST(&opt[i], Clp_OnlyNegated))
00205       lmm[i].pos = calculate_long_min_match
00206         (nopt, opt, i, Clp_OnlyNegated, 0);
00207   for (i = 0; i < nopt; i++)
00208     if (opt[i].long_name && TEST(&opt[i], Clp_Negate))
00209       lmm[i].neg = calculate_long_min_match
00210         (nopt, opt, i, Clp_Negate, Clp_Negate);
00211   
00212   
00213   cli->opt = opt;
00214   cli->nopt = nopt;
00215   
00216   cli->argtype = (Clp_ArgType *)malloc(sizeof(Clp_ArgType) * 5);
00217   if (!cli->argtype) goto failed;
00218   cli->nargtype = 5;
00219   
00220   cli->argc = argc;
00221   cli->argv = argv;
00222   {
00223     char *slash = strrchr(argv[0], '/');
00224     cli->program_name = slash ? slash + 1 : argv[0];
00225   }
00226   cli->error_handler = 0;
00227   
00228   for (i = 0; i < 256; i++)
00229     cli->option_class[i] = 0;
00230   cli->option_class['-'] = Clp_Short;
00231   cli->both_short_and_long = 0;
00232   
00233   cli->is_short = 0;
00234   cli->whole_negated = 0;
00235   
00236   cli->option_processing = 1;
00237   cli->current_option = 0;
00238   
00239   
00240   Clp_AddType(clp, Clp_ArgString, 0, parse_string, 0);
00241   Clp_AddType(clp, Clp_ArgStringNotOption, Clp_DisallowOptions, parse_string, 0);
00242   Clp_AddType(clp, Clp_ArgInt, 0, parse_int, 0);
00243   Clp_AddType(clp, Clp_ArgUnsigned, 0, parse_int, (void *)cli);
00244   Clp_AddType(clp, Clp_ArgBool, 0, parse_bool, 0);
00245   Clp_AddType(clp, Clp_ArgDouble, 0, parse_double, 0);
00246   return clp;
00247   
00248  failed:
00249   if (cli && cli->argtype) free(cli->argtype);
00250   if (cli) free(cli);
00251   if (clp) free(clp);
00252   if (lmm) free(lmm);
00253   return 0;
00254 }
00255 
00256 void
00257 Clp_DeleteParser(Clp_Parser *clp)
00258      
00259 
00260 {
00261   int i;
00262   Clp_Internal *cli;
00263   if (!clp) return;
00264   
00265   cli = clp->internal;
00266   
00267   
00268   for (i = 0; i < cli->nargtype; i++)
00269     if (cli->argtype[i].func == parse_string_list) {
00270       Clp_StringList *clsl = (Clp_StringList *)cli->argtype[i].thunk;
00271       free(clsl->items);
00272       free(clsl->long_min_match);
00273       free(clsl);
00274     }
00275   
00276   free(cli->argtype);
00277   free(cli->long_min_match);
00278   free(cli);
00279   free(clp);
00280 }
00281 
00282 
00283 int
00284 Clp_SetOptionProcessing(Clp_Parser *clp, int option_processing)
00285      
00286 
00287 
00288 {
00289   Clp_Internal *cli = clp->internal;
00290   int old = cli->option_processing;
00291   cli->option_processing = option_processing;
00292   return old;
00293 }
00294 
00295 
00296 Clp_ErrorHandler
00297 Clp_SetErrorHandler(Clp_Parser *clp, void (*error_handler)(char *))
00298      
00299 
00300 {
00301   Clp_Internal *cli = clp->internal;
00302   Clp_ErrorHandler old = cli->error_handler;
00303   cli->error_handler = error_handler;
00304   return old;
00305 }
00306 
00307 
00308 int
00309 Clp_SetOptionChar(Clp_Parser *clp, int c, int option_type)
00310      
00311 
00312 
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 
00321 
00322 
00323 
00324 
00325 {
00326   int i;
00327   Clp_Internal *cli = clp->internal;
00328   
00329   if (option_type < 0 || option_type >= 2*Clp_LongImplicit
00330       || ((option_type & Clp_Short) && (option_type & Clp_ShortNegated))
00331       || ((option_type & Clp_Long) && (option_type & Clp_LongNegated))
00332       || ((option_type & Clp_LongImplicit) && (option_type & (Clp_Short | Clp_ShortNegated | Clp_Long | Clp_LongNegated))))
00333     return 0;
00334   
00335   if (c == 0)
00336     for (i = 1; i < 256; i++)
00337       cli->option_class[i] = option_type;
00338   else
00339     cli->option_class[c] = option_type;
00340 
00341   
00342 
00343 
00344 
00345 
00346 
00347   if (!cli->both_short_and_long) {
00348     int either_short = option_type & (Clp_Short | Clp_ShortNegated);
00349     int either_long = option_type & (Clp_Long | Clp_LongNegated);
00350     if (either_short && either_long) {
00351       unsigned char have_short[257];
00352       for (i = 0; i < 256; i++)
00353         have_short[i] = 0;
00354       for (i = 0; i < cli->nopt; i++)
00355         have_short[cli->opt[i].short_name] = 1;
00356       for (i = 0; i < cli->nopt; i++)
00357         if (cli->opt[i].long_name && cli->long_min_match[i].pos == 1) {
00358           
00359           unsigned char first = (unsigned char)cli->opt[i].long_name[0];
00360           if (have_short[first] && first != cli->opt[i].short_name)
00361             cli->long_min_match[i].pos++;
00362         }
00363       cli->both_short_and_long = 1;
00364     }
00365   }
00366   
00367   return 1;
00368 }
00369 
00370 
00371 
00372 
00373 
00374 
00375 static int
00376 min_different_chars(char *s, char *t)
00377      
00378 
00379 
00380 {
00381   char *sfirst = s;
00382   while (*s && *t && *s == *t)
00383     s++, t++;
00384   if (!*s)
00385     return s - sfirst;
00386   else
00387     return s - sfirst + 1;
00388 }
00389 
00390 static int
00391 calculate_long_min_match(int nopt, Clp_Option *opt, int which,
00392                          int flags, int flags_value)
00393 {
00394   int j, lmm = 1;
00395   
00396   for (j = 0; j < nopt; j++)
00397     if (opt[j].long_name
00398         && (opt[j].flags & flags) == flags_value
00399         && opt[which].option_id != opt[j].option_id
00400         && strncmp(opt[which].long_name, opt[j].long_name, lmm) == 0)
00401       lmm = min_different_chars(opt[which].long_name, opt[j].long_name);
00402   
00403   return lmm;
00404 }
00405 
00406 
00407 
00408 static int
00409 argcmp(const char *ref, const char *arg, int min_match)
00410      
00411 
00412 
00413 
00414 
00415 
00416 
00417 
00418 
00419 
00420 
00421 
00422 {
00423   const char *refstart = ref;
00424   while (*ref && *arg && *arg != '=' && *ref == *arg)
00425     ref++, arg++;
00426   if (*arg && *arg != '=')
00427     return 0;
00428   else if (ref - refstart < min_match)
00429     return -1;
00430   else
00431     return ref - refstart;
00432 }
00433 
00434 static int
00435 find_prefix_opt(const char *arg, int nopt, Clp_Option *opt,
00436                 Clp_LongMinMatch *lmmvec,
00437                 int *ambiguous, int *ambiguous_values, int negated)
00438      
00439 
00440 
00441 
00442 {
00443   int i;
00444   for (i = 0; i < nopt; i++) {
00445     int len, lmm;
00446     if (!opt[i].long_name
00447         || (negated && !TEST(&opt[i], Clp_Negate))
00448         || (!negated && TEST(&opt[i], Clp_OnlyNegated)))
00449       continue;
00450     
00451     lmm = (negated ? lmmvec[i].neg : lmmvec[i].pos);
00452     len = argcmp(opt[i].long_name, arg, lmm);
00453     if (len > 0)
00454       return i;
00455     else if (len < 0) {
00456       if (*ambiguous < MAX_AMBIGUOUS_VALUES)
00457         ambiguous_values[*ambiguous] = i;
00458       (*ambiguous)++;
00459     }
00460   }
00461   return -1;
00462 }
00463 
00464 
00465 
00466 
00467 
00468 
00469 int
00470 Clp_AddType(Clp_Parser *clp, int type_id, int flags,
00471             Clp_ArgParseFunc func, void *thunk)
00472      
00473 
00474 
00475 
00476 
00477 
00478 
00479 {
00480   int i;
00481   Clp_Internal *cli = clp->internal;
00482   Clp_ArgType *new_argtype;
00483   int nargtype = cli->nargtype;
00484   assert(nargtype);
00485   
00486   if (type_id <= 0 || !func) return 0;
00487   
00488   while (nargtype <= type_id)
00489     nargtype *= 2;
00490   new_argtype = (Clp_ArgType *)
00491     realloc(cli->argtype, sizeof(Clp_ArgType) * nargtype);
00492   if (!new_argtype) return 0;
00493   cli->argtype = new_argtype;
00494   
00495   for (i = cli->nargtype; i < nargtype; i++)
00496     cli->argtype[i].func = 0;
00497   cli->nargtype = nargtype;
00498   
00499   cli->argtype[type_id].func = func;
00500   cli->argtype[type_id].flags = flags;
00501   cli->argtype[type_id].thunk = thunk;
00502   return 1;
00503 }
00504 
00505 
00506 
00507 
00508 
00509 
00510 static int
00511 parse_string(Clp_Parser *clp, const char *arg, int complain, void *thunk)
00512 {
00513   clp->val.s = (char *)arg;
00514   return 1;
00515 }
00516 
00517 static int
00518 parse_int(Clp_Parser *clp, const char *arg, int complain, void *thunk)
00519 {
00520   char *val;
00521   int base = 10;
00522   if (arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) {
00523     base = 16;
00524     arg += 2;
00525   }
00526   
00527   if (thunk != 0) {             
00528 #if HAVE_STRTOUL
00529     clp->val.u = strtoul(arg, &val, base);
00530 #else
00531     
00532     clp->val.u = strtol(arg, &val, base);
00533 #endif
00534   } else
00535     clp->val.i = strtol(arg, &val, base);
00536   if (*arg != 0 && *val == 0)
00537     return 1;
00538   else if (complain) {
00539     const char *message = thunk != 0
00540       ? "`%O' expects a nonnegative integer, not `%s'"
00541       : "`%O' expects an integer, not `%s'";
00542     if (base == 16) arg -= 2;
00543     return Clp_OptionError(clp, message, arg);
00544   } else
00545     return 0;
00546 }
00547 
00548 static int
00549 parse_double(Clp_Parser *clp, const char *arg, int complain, void *thunk)
00550 {
00551   char *val;
00552   clp->val.d = strtod(arg, &val);
00553   if (*arg != 0 && *val == 0)
00554     return 1;
00555   else if (complain)
00556     return Clp_OptionError(clp, "`%O' expects a real number, not `%s'", arg);
00557   else
00558     return 0;
00559 }
00560 
00561 static int
00562 parse_bool(Clp_Parser *clp, const char *arg, int complain, void *thunk)
00563 {
00564   int i;
00565   char lcarg[6];
00566   if (strlen(arg) > 5 || strchr(arg, '=') != 0)
00567     goto error;
00568   
00569   for (i = 0; arg[i] != 0; i++)
00570     lcarg[i] = tolower(arg[i]);
00571   lcarg[i] = 0;
00572   
00573   if (argcmp("yes", lcarg, 1) > 0
00574       || argcmp("true", lcarg, 1) > 0
00575       || argcmp("1", lcarg, 1) > 0) {
00576     clp->val.i = 1;
00577     return 1;
00578   } else if (argcmp("no", lcarg, 1) > 0
00579              || argcmp("false", lcarg, 1) > 0
00580              || argcmp("1", lcarg, 1) > 0) {
00581     clp->val.i = 0;
00582     return 1;
00583   }
00584   
00585  error:
00586   if (complain)
00587     Clp_OptionError(clp, "`%O' expects a true-or-false value, not `%s'", arg);
00588   return 0;
00589 }
00590 
00591 
00592 
00593 
00594 
00595 
00596 static int
00597 parse_string_list(Clp_Parser *clp, const char *arg, int complain, void *thunk)
00598 {
00599   Clp_StringList *sl = (Clp_StringList *)thunk;
00600   int index, ambiguous = 0;
00601   int ambiguous_values[MAX_AMBIGUOUS_VALUES + 1];
00602   
00603   
00604   index = find_prefix_opt
00605     (arg, sl->nitems, sl->items, sl->long_min_match,
00606      &ambiguous, ambiguous_values, 0);
00607   if (index >= 0) {
00608     clp->val.i = sl->items[index].option_id;
00609     return 1;
00610   }
00611   
00612   if (sl->allow_int) {
00613     if (parse_int(clp, arg, 0, 0))
00614       return 1;
00615   }
00616   
00617   if (complain) {
00618     char *complaint = (ambiguous ? "an ambiguous" : "not a valid");
00619     if (!ambiguous) {
00620       ambiguous = sl->nitems_invalid_report;
00621       for (index = 0; index < ambiguous; index++)
00622         ambiguous_values[index] = index;
00623     }
00624     return ambiguity_error
00625       (clp, ambiguous, ambiguous_values, sl->items, "",
00626        "`%s' is %s argument to `%O'", arg, complaint);
00627   } else
00628     return 0;
00629 }
00630 
00631 
00632 int
00633 finish_string_list(Clp_Parser *clp, int type_id, int flags,
00634                    Clp_Option *items, int nitems, int itemscap)
00635 {
00636   int i;
00637   Clp_StringList *clsl = (Clp_StringList *)malloc(sizeof(Clp_StringList));
00638   Clp_LongMinMatch *lmm = (Clp_LongMinMatch *)malloc(sizeof(Clp_LongMinMatch) * nitems);
00639   if (!clsl || !lmm) goto error;
00640   
00641   clsl->items = items;
00642   clsl->long_min_match = lmm;
00643   clsl->nitems = nitems;
00644   clsl->allow_int = (flags & Clp_AllowNumbers) != 0;
00645   
00646   if (nitems < MAX_AMBIGUOUS_VALUES && nitems < itemscap && clsl->allow_int) {
00647     items[nitems].long_name = "any integer";
00648     clsl->nitems_invalid_report = nitems + 1;
00649   } else if (nitems > MAX_AMBIGUOUS_VALUES + 1)
00650     clsl->nitems_invalid_report = MAX_AMBIGUOUS_VALUES + 1;
00651   else
00652     clsl->nitems_invalid_report = nitems;
00653   
00654   for (i = 0; i < nitems; i++)
00655     lmm[i].pos = calculate_long_min_match(nitems, items, i, 0, 0);
00656   
00657   if (Clp_AddType(clp, type_id, 0, parse_string_list, clsl))
00658     return 1;
00659 
00660  error:
00661   if (clsl) free(clsl);
00662   if (lmm) free(lmm);
00663   return 0;
00664 }
00665 
00666 int
00667 Clp_AddStringListType(Clp_Parser *clp, int type_id, int flags, ...)
00668      
00669 
00670 
00671 
00672 
00673 
00674 
00675 
00676 
00677 
00678 
00679 
00680 
00681 
00682 {
00683   int nitems = 0;
00684   int itemscap = 5;
00685   Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap);
00686   
00687   va_list val;
00688   va_start(val, flags);
00689   
00690   if (!items) goto error;
00691   
00692   
00693   while (1) {
00694     int value;
00695     char *name = va_arg(val, char *);
00696     if (!name) break;
00697     value = va_arg(val, int);
00698     
00699     if (nitems >= itemscap) {
00700       Clp_Option *new_items;
00701       itemscap *= 2;
00702       new_items = (Clp_Option *)realloc(items, sizeof(Clp_Option) * itemscap);
00703       if (!new_items) goto error;
00704       items = new_items;
00705     }
00706     
00707     items[nitems].long_name = name;
00708     items[nitems].option_id = value;
00709     items[nitems].flags = 0;
00710     nitems++;
00711   }
00712 
00713   va_end(val);
00714   if (finish_string_list(clp, type_id, flags, items, nitems, itemscap))
00715     return 1;
00716   
00717  error:
00718   va_end(val);
00719   if (items) free(items);
00720   return 0;
00721 }
00722 
00723 
00724 int
00725 Clp_AddStringListTypeVec(Clp_Parser *clp, int type_id, int flags,
00726                          int nitems, char **strings, int *values)
00727      
00728 
00729 
00730 {
00731   int i;
00732   int itemscap = (nitems < 5 ? 5 : nitems);
00733   Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap);
00734   if (!items) return 0;
00735   
00736   
00737   for (i = 0; i < nitems; i++) {
00738     items[i].long_name = strings[i];
00739     items[i].option_id = values[i];
00740     items[i].flags = 0;
00741   }
00742   
00743   if (finish_string_list(clp, type_id, flags, items, nitems, itemscap))
00744     return 1;
00745   else {
00746     free(items);
00747     return 0;
00748   }
00749 }
00750 
00751 
00752 
00753 
00754 
00755 
00756 char *
00757 Clp_ProgramName(Clp_Parser *clp)
00758 {
00759   return clp->internal->program_name;
00760 }
00761 
00762 
00763 
00764 
00765 
00766 
00767 Clp_ParserState *
00768 Clp_NewParserState(void)
00769 {
00770   return (Clp_ParserState *)malloc(sizeof(Clp_ParserState));
00771 }
00772 
00773 void
00774 Clp_DeleteParserState(Clp_ParserState *save)
00775 {
00776   free(save);
00777 }
00778 
00779 
00780 void
00781 Clp_SaveParser(Clp_Parser *clp, Clp_ParserState *save)
00782      
00783 {
00784   Clp_Internal *cli = clp->internal;
00785   save->argv = cli->argv;
00786   save->argc = cli->argc;
00787   memcpy(save->option_chars, cli->option_chars, 3);
00788   save->text = cli->text;
00789   save->is_short = cli->is_short;
00790   save->whole_negated = cli->whole_negated;
00791 }
00792 
00793 
00794 void
00795 Clp_RestoreParser(Clp_Parser *clp, Clp_ParserState *save)
00796      
00797 {
00798   Clp_Internal *cli = clp->internal;
00799   cli->argv = save->argv;
00800   cli->argc = save->argc;
00801   memcpy(cli->option_chars, save->option_chars, 3);
00802   cli->text = save->text;
00803   cli->is_short = save->is_short;
00804   cli->whole_negated = save->whole_negated;
00805 }
00806 
00807 
00808 
00809 
00810 
00811 
00812 static void
00813 set_option_text(Clp_Internal *cli, char *text, int n_option_chars)
00814 {
00815   char *option_chars = cli->option_chars;
00816   assert(n_option_chars < 3);
00817   
00818   while (n_option_chars-- > 0)
00819     *option_chars++ = *text++;
00820   *option_chars = 0;
00821   
00822   cli->text = text;
00823 }
00824 
00825 
00826 static int
00827 next_argument(Clp_Parser *clp, int want_argument)
00828      
00829 
00830 
00831 
00832 
00833 
00834 
00835 
00836 
00837 
00838 
00839 
00840 
00841 
00842 
00843 
00844 
00845 {
00846   Clp_Internal *cli = clp->internal;
00847   char *text;
00848   int option_class;
00849 
00850   
00851   clp->have_arg = 0;
00852   clp->arg = 0;
00853   cli->could_be_short = 0;
00854   
00855   
00856   if (cli->is_short) {
00857     ++cli->text;
00858     if (cli->text[0] == 0)
00859       cli->is_short = 0;
00860     else if (want_argument > 0) {
00861       
00862       clp->have_arg = 1;
00863       if (cli->text[0] == '=')
00864         clp->arg = cli->text + 1;
00865       else
00866         clp->arg = cli->text;
00867       cli->is_short = 0;
00868       return 0;
00869     }
00870   }
00871   
00872   
00873   if (cli->is_short)
00874     return 1;
00875   
00876 
00877   cli->whole_negated = 0;
00878   cli->text = 0;
00879   
00880   if (cli->argc <= 1)
00881     return 0;
00882   
00883   cli->argc--;
00884   cli->argv++;
00885   text = cli->argv[0];
00886   
00887   if (want_argument > 1)
00888     goto not_option;
00889   
00890   option_class = cli->option_class[ (unsigned char)text[0] ];
00891   if (text[0] == '-' && text[1] == '-')
00892     option_class = Clp_DoubledLong;
00893   
00894   
00895 
00896 
00897   if ((option_class & (Clp_Short | Clp_ShortNegated))
00898       && (option_class & (Clp_Long | Clp_LongNegated))) {
00899     option_class &= ~(Clp_Short | Clp_ShortNegated);
00900     if (text[1] != 0) cli->could_be_short = 1;
00901   }
00902   
00903   switch (option_class) {
00904     
00905    case Clp_Short:
00906     cli->is_short = 1;
00907     goto check_singleton;
00908     
00909    case Clp_ShortNegated:
00910     cli->is_short = 1;
00911     cli->whole_negated = 1;
00912     goto check_singleton;
00913     
00914    case Clp_Long:
00915     goto check_singleton;
00916     
00917    case Clp_LongNegated:
00918     cli->whole_negated = 1;
00919     goto check_singleton;
00920     
00921    check_singleton:
00922     
00923 
00924     if (text[1] == 0)
00925       goto not_option;
00926     set_option_text(cli, text, 1);
00927     break;
00928     
00929    case Clp_LongImplicit:
00930     
00931 
00932     if (want_argument > 0)
00933       goto not_option;
00934     set_option_text(cli, text, 0);
00935     break;
00936     
00937    case Clp_DoubledLong:
00938     set_option_text(cli, text, 2);
00939     break;
00940     
00941    not_option: 
00942    case Clp_NotOption:
00943     cli->is_short = 0;
00944     clp->have_arg = 1;
00945     clp->arg = text;
00946     return 0;
00947     
00948    default:
00949     assert(0 && "misconfiguration");
00950     
00951   }
00952   
00953   return 1;
00954 }
00955 
00956 
00957 static void
00958 switch_to_short_argument(Clp_Parser *clp)
00959 {
00960   Clp_Internal *cli = clp->internal;
00961   const char *text = cli->argv[0];
00962   int option_class = cli->option_class[ (unsigned char)text[0] ];
00963   cli->is_short = 1;
00964   cli->whole_negated = (option_class & Clp_ShortNegated ? 1 : 0);
00965   set_option_text(cli, cli->argv[0], 1);
00966   assert(cli->could_be_short);
00967 }
00968 
00969 
00970 static Clp_Option *
00971 find_long(Clp_Parser *clp, char *arg)
00972      
00973 
00974 
00975 
00976 {
00977   Clp_Internal *cli = clp->internal;
00978   int value, len;
00979   Clp_Option *opt = cli->opt;
00980   int first_negative_ambiguous;
00981   
00982   
00983   value = find_prefix_opt
00984     (arg, cli->nopt, opt, cli->long_min_match,
00985      &cli->ambiguous, cli->ambiguous_values, clp->negated);
00986   if (value >= 0)
00987     goto worked;
00988   
00989   
00990   
00991 
00992   first_negative_ambiguous = cli->ambiguous;
00993   while (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-') {
00994     arg += 3;
00995     clp->negated = !clp->negated;
00996     value = find_prefix_opt
00997       (arg, cli->nopt, opt, cli->long_min_match,
00998        &cli->ambiguous, cli->ambiguous_values, clp->negated);
00999     if (value >= 0)
01000       goto worked;
01001   }
01002   
01003   
01004 
01005   {
01006     int i, max = cli->ambiguous;
01007     if (max > MAX_AMBIGUOUS_VALUES) max = MAX_AMBIGUOUS_VALUES;
01008     for (i = first_negative_ambiguous; i < max; i++)
01009       cli->ambiguous_values[i] = -cli->ambiguous_values[i] - 1;
01010     return 0;
01011   }
01012   
01013  worked:
01014   len = argcmp(opt[value].long_name, arg, cli->long_min_match[value].pos);
01015   if (arg[len] == '=') {
01016     clp->have_arg = 1;
01017     clp->arg = arg + len + 1;
01018   }
01019   return &opt[value];
01020 }
01021 
01022 
01023 static Clp_Option *
01024 find_short(Clp_Parser *clp, int short_name)
01025      
01026 {
01027   Clp_Internal *cli = clp->internal;
01028   Clp_Option *opt = cli->opt;
01029   int i;
01030   
01031   for (i = 0; i < cli->nopt; i++)
01032     if (opt[i].short_name == short_name
01033         && (clp->negated ? TEST(&opt[i], Clp_Negate)
01034             : !TEST(&opt[i], Clp_OnlyNegated)))
01035       return &opt[i];
01036   
01037   return 0;
01038 }
01039 
01040 
01041 int
01042 Clp_Next(Clp_Parser *clp)
01043      
01044 
01045 
01046 
01047 
01048 
01049 
01050 
01051 
01052 
01053 
01054 
01055 
01056 
01057 
01058 
01059 
01060 
01061 
01062 {
01063   Clp_Internal *cli = clp->internal;
01064   Clp_Option *opt;
01065   Clp_ParserState clpsave;
01066   int complain;
01067   
01068 
01069   cli->current_option = 0;
01070   cli->ambiguous = 0;
01071   
01072 
01073   if (!next_argument(clp, cli->option_processing ? 0 : 2))
01074     return clp->have_arg ? Clp_NotOption : Clp_Done;
01075   
01076   clp->negated = cli->whole_negated;
01077   if (cli->is_short)
01078     opt = find_short(clp, cli->text[0]);
01079   else
01080     opt = find_long(clp, cli->text);
01081   
01082 
01083 
01084   if (!opt && cli->could_be_short) {
01085     switch_to_short_argument(clp);
01086     opt = find_short(clp, cli->text[0]);
01087   }
01088   
01089 
01090   if (!opt || (clp->negated && !TEST(opt, Clp_Negate))) {
01091     
01092     
01093 
01094     if (strcmp(cli->argv[0], "--") == 0) {
01095       Clp_SetOptionProcessing(clp, 0);
01096       return Clp_Next(clp);
01097     }
01098     
01099     
01100     if (cli->ambiguous)
01101       ambiguity_error(clp, cli->ambiguous, cli->ambiguous_values,
01102                       cli->opt, cli->option_chars,
01103                       "option `%s%s' is ambiguous",
01104                       cli->option_chars, cli->text);
01105     else if (cli->is_short && !cli->could_be_short)
01106       Clp_OptionError(clp, "unrecognized option `%s%c'",
01107                       cli->option_chars, cli->text[0]);
01108     else
01109       Clp_OptionError(clp, "unrecognized option `%s%s'",
01110                       cli->option_chars, cli->text);
01111     return Clp_BadOption;
01112   }
01113   
01114 
01115   cli->current_option = opt;
01116   cli->current_short = cli->is_short;
01117   cli->negated_by_no = clp->negated && !cli->whole_negated;
01118   
01119 
01120   if (clp->negated || !TEST(opt, Clp_AnyArgument)) {
01121     if (clp->have_arg) {
01122       Clp_OptionError(clp, "`%O' can't take an argument");
01123       return Clp_BadOption;
01124     } else
01125       return opt->option_id;
01126   }
01127   
01128 
01129   
01130   if (opt->arg_type <= 0 || opt->arg_type >= cli->nargtype
01131       || cli->argtype[ opt->arg_type ].func == 0)
01132     return Clp_Error;
01133   
01134   
01135 
01136   complain = (clp->have_arg != 0) || TEST(opt, Clp_Mandatory);
01137   Clp_SaveParser(clp, &clpsave);
01138   
01139   if (TEST(opt, Clp_Mandatory) && !clp->have_arg) {
01140     
01141     
01142 
01143     int disallow = TEST(&cli->argtype[opt->arg_type], Clp_DisallowOptions);
01144     next_argument(clp, disallow ? 1 : 2);
01145     if (!clp->have_arg) {
01146       int got_option = cli->text != 0;
01147       Clp_RestoreParser(clp, &clpsave);
01148       if (got_option)
01149         Clp_OptionError(clp, "`%O' requires a non-option argument");
01150       else
01151         Clp_OptionError(clp, "`%O' requires an argument");
01152       return Clp_BadOption;
01153     }
01154     
01155   } else if (cli->is_short && !clp->have_arg && cli->text[1] != 0)
01156     
01157 
01158     next_argument(clp, 1);
01159   
01160 
01161   if (clp->have_arg) {
01162     Clp_ArgType *atr = &cli->argtype[ opt->arg_type ];
01163     if (atr->func(clp, clp->arg, complain, atr->thunk) <= 0) {
01164       
01165       clp->have_arg = 0;
01166       if (TEST(opt, Clp_Mandatory))
01167         return Clp_BadOption;
01168       else
01169         Clp_RestoreParser(clp, &clpsave);
01170     }
01171   }
01172   
01173   return opt->option_id;
01174 }
01175 
01176 
01177 char *
01178 Clp_Shift(Clp_Parser *clp, int allow_dashes)
01179      
01180 
01181 {
01182   Clp_ParserState clpsave;
01183   Clp_SaveParser(clp, &clpsave);
01184   next_argument(clp, allow_dashes ? 2 : 1);
01185   if (!clp->have_arg)
01186     Clp_RestoreParser(clp, &clpsave);
01187   return clp->arg;
01188 }
01189 
01190 
01191 
01192 
01193 
01194 
01195 typedef struct Clp_BuildString {
01196   char *text;
01197   char *pos;
01198   int capacity;
01199   int bad;
01200 } Clp_BuildString;
01201 
01202 static Clp_BuildString *
01203 new_build_string(void)
01204 {
01205   Clp_BuildString *bs = (Clp_BuildString *)malloc(sizeof(Clp_BuildString));
01206   if (!bs) goto bad;
01207   bs->text = (char *)malloc(256);
01208   if (!bs->text) goto bad;
01209   bs->pos = bs->text;
01210   bs->capacity = 256;
01211   bs->bad = 0;
01212   return bs;
01213   
01214  bad:
01215   if (bs) free(bs);
01216   return 0;
01217 }
01218 
01219 static void
01220 free_build_string(Clp_BuildString *bs)
01221 {
01222   if (bs) free(bs->text);
01223   free(bs);
01224 }
01225 
01226 static int
01227 grow_build_string(Clp_BuildString *bs, int want)
01228 {
01229   char *new_text;
01230   int ipos = bs->pos - bs->text;
01231   int new_capacity = bs->capacity;
01232   while (want >= new_capacity)
01233     new_capacity *= 2;
01234   new_text = (char *)realloc(bs->text, new_capacity);
01235   if (!new_text) {
01236     bs->bad = 1;
01237     return 0;
01238   } else {
01239     bs->text = new_text;
01240     bs->pos = bs->text + ipos;
01241     bs->capacity = new_capacity;
01242     return 1;
01243   }
01244 }
01245 
01246 #define ENSURE_BUILD_STRING(bs, space) \
01247   ((((bs)->pos - (bs)->text) + (space) >= (bs)->capacity)               \
01248    || grow_build_string((bs), ((bs)->pos - (bs)->text) + (space)))
01249 
01250 static void
01251 append_build_string(Clp_BuildString *bs, const char *s, int l)
01252 {
01253   if (l < 0) l = strlen(s);
01254   if (ENSURE_BUILD_STRING(bs, l)) {
01255     memcpy(bs->pos, s, l);
01256     bs->pos += l;
01257   }
01258 }
01259 
01260 
01261 static Clp_BuildString *
01262 Clp_VaOptionError(Clp_Parser *clp, Clp_BuildString *bs,
01263                   const char *fmt, va_list val)
01264      
01265 
01266 
01267 
01268 
01269 
01270 
01271 
01272 
01273 {
01274   Clp_Internal *cli = clp->internal;
01275   const char *percent;
01276   
01277   if (!bs) bs = new_build_string();
01278   if (!bs) return 0;
01279   append_build_string(bs, cli->program_name, -1);
01280   append_build_string(bs, ": ", 2);
01281   
01282   for (percent = strchr(fmt, '%'); percent; percent = strchr(fmt, '%')) {
01283     append_build_string(bs, fmt, percent - fmt);
01284     switch (*++percent) {
01285       
01286      case 's': {
01287        char *s = va_arg(val, char *);
01288        if (s) append_build_string(bs, s, -1);
01289        else append_build_string(bs, "(null)", 6);
01290        break;
01291      }
01292      
01293      case 'c': {
01294        int c = va_arg(val, int);
01295        if (ENSURE_BUILD_STRING(bs, 4)) {
01296          if (c >= 32 && c <= 126)
01297            *bs->pos++ = c;
01298          else if (c < 32) {
01299            *bs->pos++ = '^';
01300            *bs->pos++ = c + 64;
01301          } else {
01302            sprintf(bs->pos, "\\%03o", c);
01303            bs->pos += 4;
01304          }
01305        }
01306        break;
01307      }
01308      
01309      case 'd': {
01310        int d = va_arg(val, int);
01311        if (ENSURE_BUILD_STRING(bs, 32)) {
01312          sprintf(bs->pos, "%d", d);
01313          bs->pos = strchr(bs->pos, 0);
01314        }
01315        break;
01316      }
01317      
01318      case 'O': {
01319        Clp_Option *opt = cli->current_option;
01320        if (!opt)
01321          append_build_string(bs, "(no current option!)", -1);
01322        else if (cli->current_short) {
01323          append_build_string(bs, cli->option_chars, -1);
01324          if (ENSURE_BUILD_STRING(bs, 1))
01325            *bs->pos++ = opt->short_name;
01326        } else if (cli->negated_by_no) {
01327          append_build_string(bs, cli->option_chars, -1);
01328          append_build_string(bs, "no-", 3);
01329          append_build_string(bs, opt->long_name, -1);
01330        } else {
01331          append_build_string(bs, cli->option_chars, -1);
01332          append_build_string(bs, opt->long_name, -1);
01333        }
01334        break;
01335      }
01336      
01337      case '%':
01338       if (ENSURE_BUILD_STRING(bs, 1))
01339         *bs->pos++ = '%';
01340       break;
01341       
01342      default:
01343       if (ENSURE_BUILD_STRING(bs, 2)) {
01344         *bs->pos++ = '%';
01345         *bs->pos++ = *percent;
01346       }
01347       break;
01348       
01349     }
01350     fmt = ++percent;
01351   }
01352   
01353   append_build_string(bs, fmt, -1);
01354   append_build_string(bs, "\n", 1);
01355   
01356   return bs;
01357 }
01358 
01359 static void
01360 do_error(Clp_Parser *clp, Clp_BuildString *bs)
01361 {
01362   char *text;
01363   if (bs && !bs->bad) {
01364     *bs->pos = 0;
01365     text = bs->text;
01366   } else
01367     text = "out of memory\n";
01368   
01369   if (clp->internal->error_handler != 0)
01370     (*clp->internal->error_handler)(text);
01371   else
01372     fputs(text, stderr);
01373 }
01374 
01375 int
01376 Clp_OptionError(Clp_Parser *clp, const char *fmt, ...)
01377 {
01378   Clp_BuildString *bs;
01379   va_list val;
01380   va_start(val, fmt);
01381   bs = Clp_VaOptionError(clp, 0, fmt, val);
01382   va_end(val);
01383   do_error(clp, bs);
01384   free_build_string(bs);
01385   return 0;
01386 }
01387 
01388 static int
01389 ambiguity_error(Clp_Parser *clp, int ambiguous, int *ambiguous_values,
01390                 Clp_Option *opt, const char *prefix,
01391                 const char *fmt, ...)
01392 {
01393   Clp_BuildString *bs;
01394   int i;
01395   va_list val;
01396   va_start(val, fmt);
01397   bs = Clp_VaOptionError(clp, 0, fmt, val);
01398   if (!bs) goto done;
01399   
01400   append_build_string(bs, clp->internal->program_name, -1);
01401   append_build_string(bs, ": (Possibilities are", -1);
01402   
01403   for (i = 0; i < ambiguous && i < MAX_AMBIGUOUS_VALUES; i++) {
01404     int val = ambiguous_values[i];
01405     const char *no_dash = "";
01406     if (val < 0) val = -(val + 1), no_dash = "no-";
01407     if (i == 0)
01408       append_build_string(bs, " ", 1);
01409     else if (i == ambiguous - 1)
01410       append_build_string(bs, (i == 1 ? " and " : ", and "), -1);
01411     else
01412       append_build_string(bs, ", ", 2);
01413     append_build_string(bs, prefix, -1);
01414     append_build_string(bs, no_dash, -1);
01415     append_build_string(bs, opt[val].long_name, -1);
01416   }
01417   
01418   if (ambiguous > MAX_AMBIGUOUS_VALUES)
01419     append_build_string(bs, ", and others", -1);
01420   append_build_string(bs, ".)\n", -1);
01421   va_end(val);
01422   
01423  done:
01424   do_error(clp, bs);
01425   free_build_string(bs);
01426   return 0;
01427 }
01428 
01429 #ifdef __cplusplus
01430 }
01431 #endif