Corrected signed-to-unsigned comparisons
[gnutls.git] / src / libopts / find.c
blobf6510ee7454e8cd432443627afba2210f4956a59
1 /**
2 * @file check.c
4 * @brief Hunt for options in the option descriptor list
6 * Time-stamp: "2012-01-29 19:07:30 bkorb"
8 * This file contains the routines that deal with processing quoted strings
9 * into an internal format.
11 * This file is part of AutoOpts, a companion to AutoGen.
12 * AutoOpts is free software.
13 * AutoOpts is Copyright (c) 1992-2012 by Bruce Korb - all rights reserved
15 * AutoOpts is available under any one of two licenses. The license
16 * in use must be one of these two and the choice is under the control
17 * of the user of the license.
19 * The GNU Lesser General Public License, version 3 or later
20 * See the files "COPYING.lgplv3" and "COPYING.gplv3"
22 * The Modified Berkeley Software Distribution License
23 * See the file "COPYING.mbsd"
25 * These files have the following md5sums:
27 * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
28 * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
29 * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
32 /**
33 * find the name and name length we are looking for
35 static int
36 parse_opt(char const ** nm_pp, char ** arg_pp, char * buf, size_t bufsz)
38 int res = 0;
39 char const * p = *nm_pp;
40 *arg_pp = NULL;
42 for (;;) {
43 switch (*(p++)) {
44 case NUL: return res;
46 case '=':
47 if (res >= (int)bufsz)
48 return -1;
50 memcpy(buf, *nm_pp, res);
52 buf[res] = NUL;
53 *nm_pp = buf;
54 *arg_pp = (char *)p;
55 return res;
57 default:
58 res++;
63 /**
64 * print out the options that match the given name.
66 * @param pOpts option data
67 * @param opt_name name of option to look for
69 static void
70 opt_ambiguities(tOptions * opts, char const * name, int nm_len)
72 char const * const hyph =
73 NAMED_OPTS(opts) ? "" : LONG_OPT_MARKER;
75 tOptDesc * pOD = opts->pOptDesc;
76 int idx = 0;
78 fputs(zAmbigList, stderr);
79 do {
80 if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0)
81 fprintf(stderr, zAmbiguous, hyph, pOD->pz_Name);
83 else if ( (pOD->pz_DisableName != NULL)
84 && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0)
86 fprintf(stderr, zAmbiguous, hyph, pOD->pz_DisableName);
87 } while (pOD++, (++idx < opts->optCt));
90 /**
91 * Determine the number of options that match the name
93 * @param pOpts option data
94 * @param opt_name name of option to look for
95 * @param nm_len length of provided name
96 * @param index pointer to int for option index
97 * @param disable pointer to bool to mark disabled option
98 * @return count of options that match
100 static int
101 opt_match_ct(tOptions * opts, char const * name, int nm_len,
102 int * ixp, bool * disable)
104 int matchCt = 0;
105 int idx = 0;
106 int idxLim = opts->optCt;
107 tOptDesc * pOD = opts->pOptDesc;
109 do {
111 * If option disabled or a doc option, skip to next
113 if (pOD->pz_Name == NULL)
114 continue;
116 if ( SKIP_OPT(pOD)
117 && (pOD->fOptState != (OPTST_OMITTED | OPTST_NO_INIT)))
118 continue;
120 if (strneqvcmp(name, pOD->pz_Name, nm_len) == 0) {
122 * IF we have a complete match
123 * THEN it takes priority over any already located partial
125 if (pOD->pz_Name[ nm_len ] == NUL) {
126 *ixp = idx;
127 return 1;
132 * IF there is a disable name
133 * *AND* the option name matches the disable name
134 * THEN ...
136 else if ( (pOD->pz_DisableName != NULL)
137 && (strneqvcmp(name, pOD->pz_DisableName, nm_len) == 0)
139 *disable = true;
142 * IF we have a complete match
143 * THEN it takes priority over any already located partial
145 if (pOD->pz_DisableName[ nm_len ] == NUL) {
146 *ixp = idx;
147 return 1;
151 else
152 continue; /* does not match any option */
155 * We found a full or partial match, either regular or disabling.
156 * Remember the index for later.
158 *ixp = idx;
159 ++matchCt;
161 } while (pOD++, (++idx < idxLim));
163 return matchCt;
167 * Set the option to the indicated option number.
169 * @param opts option data
170 * @param arg option argument (if glued to name)
171 * @param idx option index
172 * @param disable mark disabled option
173 * @param st state about current option
175 static tSuccess
176 opt_set(tOptions * opts, char * arg, int idx, bool disable, tOptState * st)
178 tOptDesc * pOD = opts->pOptDesc + idx;
180 if (SKIP_OPT(pOD)) {
181 if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0)
182 return FAILURE;
184 fprintf(stderr, zDisabledErr, opts->pzProgName, pOD->pz_Name);
185 if (pOD->pzText != NULL)
186 fprintf(stderr, SET_OFF_FMT, pOD->pzText);
187 fputc(NL, stderr);
188 (*opts->pUsageProc)(opts, EXIT_FAILURE);
189 /* NOTREACHED */
190 _exit(EXIT_FAILURE); /* to be certain */
194 * IF we found a disablement name,
195 * THEN set the bit in the callers' flag word
197 if (disable)
198 st->flags |= OPTST_DISABLED;
200 st->pOD = pOD;
201 st->pzOptArg = arg;
202 st->optType = TOPT_LONG;
204 return SUCCESS;
208 * An option was not found. Check for default option and set it
209 * if there is one. Otherwise, handle the error.
211 * @param opts option data
212 * @param name name of option to look for
213 * @param arg option argument
214 * @param st state about current option
216 * @return success status
218 static tSuccess
219 opt_unknown(tOptions * opts, char const * name, char * arg, tOptState * st)
222 * IF there is no equal sign
223 * *AND* we are using named arguments
224 * *AND* there is a default named option,
225 * THEN return that option.
227 if ( (arg == NULL)
228 && NAMED_OPTS(opts)
229 && (opts->specOptIdx.default_opt != NO_EQUIVALENT)) {
231 st->pOD = opts->pOptDesc + opts->specOptIdx.default_opt;
232 st->pzOptArg = name;
233 st->optType = TOPT_DEFAULT;
234 return SUCCESS;
237 if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) {
238 fprintf(stderr, zIllOptStr, opts->pzProgPath, name);
239 (*opts->pUsageProc)(opts, EXIT_FAILURE);
240 /* NOTREACHED */
241 _exit(EXIT_FAILURE); /* to be certain */
244 return FAILURE;
248 * Several options match the provided name.
250 * @param opts option data
251 * @param name name of option to look for
252 * @param match_ct number of matching options
254 * @return success status (always FAILURE, if it returns)
256 static tSuccess
257 opt_ambiguous(tOptions * opts, char const * name, int match_ct)
259 if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) {
260 fprintf(stderr, zAmbigOptStr, opts->pzProgPath, name, match_ct);
261 if (match_ct <= 4)
262 opt_ambiguities(opts, name, strlen(name));
263 (*opts->pUsageProc)(opts, EXIT_FAILURE);
264 /* NOTREACHED */
265 _exit(EXIT_FAILURE); /* to be certain */
267 return FAILURE;
270 /*=export_func optionVendorOption
271 * private:
273 * what: Process a vendor option
274 * arg: + tOptions * + pOpts + program options descriptor +
275 * arg: + tOptDesc * + pOptDesc + the descriptor for this arg +
277 * doc:
278 * For POSIX specified utilities, the options are constrained to the options,
279 * @xref{config attributes, Program Configuration}. AutoOpts clients should
280 * never specify this directly. It gets referenced when the option
281 * definitions contain a "vendor-opt" attribute.
283 void
284 optionVendorOption(tOptions * pOpts, tOptDesc * pOD)
286 tOptState opt_st = OPTSTATE_INITIALIZER(PRESET);
287 char const * vopt_str = pOD->optArg.argString;
289 if ((pOD->fOptState & OPTPROC_IMMEDIATE) == 0)
290 opt_st.flags = OPTST_DEFINED;
292 if ( ((pOpts->fOptSet & OPTPROC_VENDOR_OPT) == 0)
293 || ! SUCCESSFUL(opt_find_long(pOpts, vopt_str, &opt_st))
294 || ! SUCCESSFUL(get_opt_arg(pOpts, &opt_st)) )
296 fprintf(stderr, zIllVendOptStr, vopt_str);
297 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
298 /* NOTREACHED */
302 * See if we are in immediate handling state.
304 if (pOpts->fOptSet & OPTPROC_IMMEDIATE) {
306 * See if the enclosed option is okay with that state.
308 if (DO_IMMEDIATELY(opt_st.flags))
309 (void)handle_opt(pOpts, &opt_st);
311 } else {
313 * non-immediate direction.
314 * See if the enclosed option is okay with that state.
316 if (DO_NORMALLY(opt_st.flags) || DO_SECOND_TIME(opt_st.flags))
317 (void)handle_opt(pOpts, &opt_st);
322 * Find the option descriptor by full name.
324 * @param pOpts option data
325 * @param opt_name name of option to look for
326 * @param pOptState state about current option
328 * @return success status
330 LOCAL tSuccess
331 opt_find_long(tOptions * pOpts, char const * opt_name, tOptState * pOptState)
333 char name_buf[128];
334 char * opt_arg;
335 int nm_len = parse_opt(&opt_name, &opt_arg, name_buf, sizeof(name_buf));
337 int matchIdx = 0;
338 bool disable = false;
339 int match_ct =
340 opt_match_ct(pOpts, opt_name, nm_len, &matchIdx, &disable);
343 * See if we found one match, no matches or multiple matches.
345 switch (match_ct) {
346 case 1: return opt_set(pOpts, opt_arg, matchIdx, disable, pOptState);
347 case 0: return opt_unknown(pOpts, opt_name, opt_arg, pOptState);
348 default: return opt_ambiguous(pOpts, opt_name, match_ct);
354 * Find the short option descriptor for the current option
356 * @param pOpts option data
357 * @param optValue option flag character
358 * @param pOptState state about current option
360 LOCAL tSuccess
361 opt_find_short(tOptions* pOpts, uint_t optValue, tOptState* pOptState)
363 tOptDesc* pRes = pOpts->pOptDesc;
364 int ct = pOpts->optCt;
367 * Search the option list
369 do {
370 if (optValue != pRes->optValue)
371 continue;
373 if (SKIP_OPT(pRes)) {
374 if ( (pRes->fOptState == (OPTST_OMITTED | OPTST_NO_INIT))
375 && (pRes->pz_Name != NULL)) {
376 fprintf(stderr, zDisabledErr, pOpts->pzProgPath, pRes->pz_Name);
377 if (pRes->pzText != NULL)
378 fprintf(stderr, SET_OFF_FMT, pRes->pzText);
379 fputc(NL, stderr);
380 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
381 /* NOTREACHED */
382 _exit(EXIT_FAILURE); /* to be certain */
384 goto short_opt_error;
387 pOptState->pOD = pRes;
388 pOptState->optType = TOPT_SHORT;
389 return SUCCESS;
391 } while (pRes++, --ct > 0);
394 * IF the character value is a digit
395 * AND there is a special number option ("-n")
396 * THEN the result is the "option" itself and the
397 * option is the specially marked "number" option.
399 if ( IS_DEC_DIGIT_CHAR(optValue)
400 && (pOpts->specOptIdx.number_option != NO_EQUIVALENT) ) {
401 pOptState->pOD = \
402 pRes = pOpts->pOptDesc + pOpts->specOptIdx.number_option;
403 (pOpts->pzCurOpt)--;
404 pOptState->optType = TOPT_SHORT;
405 return SUCCESS;
408 short_opt_error:
411 * IF we are to stop on errors (the default, actually)
412 * THEN call the usage procedure.
414 if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) {
415 fprintf(stderr, zIllOptChr, pOpts->pzProgPath, optValue);
416 (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE);
417 /* NOTREACHED */
418 _exit(EXIT_FAILURE); /* to be certain */
421 return FAILURE;
424 LOCAL tSuccess
425 get_opt_arg(tOptions * pOpts, tOptState * pOptState)
427 pOptState->flags |= (pOptState->pOD->fOptState & OPTST_PERSISTENT_MASK);
430 * Figure out what to do about option arguments. An argument may be
431 * required, not associated with the option, or be optional. We detect the
432 * latter by examining for an option marker on the next possible argument.
433 * Disabled mode option selection also disables option arguments.
436 enum { ARG_NONE, ARG_MAY, ARG_MUST } arg_type = ARG_NONE;
437 tSuccess res;
439 if ((pOptState->flags & OPTST_DISABLED) != 0)
440 arg_type = ARG_NONE;
442 else if (OPTST_GET_ARGTYPE(pOptState->flags) == OPARG_TYPE_NONE)
443 arg_type = ARG_NONE;
445 else if (pOptState->flags & OPTST_ARG_OPTIONAL)
446 arg_type = ARG_MAY;
448 else
449 arg_type = ARG_MUST;
451 switch (arg_type) {
452 case ARG_MUST: res = next_opt_arg_must(pOpts, pOptState); break;
453 case ARG_MAY: res = next_opt_arg_may( pOpts, pOptState); break;
454 case ARG_NONE: res = next_opt_arg_none(pOpts, pOptState); break;
457 return res;
462 * Find the option descriptor for the current option
464 LOCAL tSuccess
465 find_opt(tOptions * pOpts, tOptState * pOptState)
468 * IF we are continuing a short option list (e.g. -xyz...)
469 * THEN continue a single flag option.
470 * OTHERWISE see if there is room to advance and then do so.
472 if ((pOpts->pzCurOpt != NULL) && (*pOpts->pzCurOpt != NUL))
473 return opt_find_short(pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState);
475 if (pOpts->curOptIdx >= pOpts->origArgCt)
476 return PROBLEM; /* NORMAL COMPLETION */
478 pOpts->pzCurOpt = pOpts->origArgVect[ pOpts->curOptIdx ];
481 * IF all arguments must be named options, ...
483 if (NAMED_OPTS(pOpts)) {
484 char * pz = pOpts->pzCurOpt;
485 int def;
486 tSuccess res;
487 tAoUS * def_opt;
489 pOpts->curOptIdx++;
491 if (*pz != '-')
492 return opt_find_long(pOpts, pz, pOptState);
495 * The name is prefixed with one or more hyphens. Strip them off
496 * and disable the "default_opt" setting. Use heavy recasting to
497 * strip off the "const" quality of the "default_opt" field.
499 while (*(++pz) == '-') ;
500 def_opt = (void *)&(pOpts->specOptIdx.default_opt);
501 def = *def_opt;
502 *def_opt = NO_EQUIVALENT;
503 res = opt_find_long(pOpts, pz, pOptState);
504 *def_opt = def;
505 return res;
509 * Note the kind of flag/option marker
511 if (*((pOpts->pzCurOpt)++) != '-')
512 return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
515 * Special hack for a hyphen by itself
517 if (*(pOpts->pzCurOpt) == NUL)
518 return PROBLEM; /* NORMAL COMPLETION - this + rest are operands */
521 * The current argument is to be processed as an option argument
523 pOpts->curOptIdx++;
526 * We have an option marker.
527 * Test the next character for long option indication
529 if (pOpts->pzCurOpt[0] == '-') {
530 if (*++(pOpts->pzCurOpt) == NUL)
532 * NORMAL COMPLETION - NOT this arg, but rest are operands
534 return PROBLEM;
537 * We do not allow the hyphen to be used as a flag value.
538 * Therefore, if long options are not to be accepted, we punt.
540 if ((pOpts->fOptSet & OPTPROC_LONGOPT) == 0) {
541 fprintf(stderr, zIllOptStr, pOpts->pzProgPath,
542 pOpts->pzCurOpt-2);
543 return FAILURE;
546 return opt_find_long(pOpts, pOpts->pzCurOpt, pOptState);
550 * If short options are not allowed, then do long
551 * option processing. Otherwise the character must be a
552 * short (i.e. single character) option.
554 if ((pOpts->fOptSet & OPTPROC_SHORTOPT) != 0)
555 return opt_find_short(pOpts, (tAoUC)*(pOpts->pzCurOpt), pOptState);
557 return opt_find_long(pOpts, pOpts->pzCurOpt, pOptState);
561 * Local Variables:
562 * mode: C
563 * c-file-style: "stroustrup"
564 * indent-tabs-mode: nil
565 * End:
566 * end of autoopts/find.c */