|
From: <kin...@us...> - 2025-09-24 05:55:57
|
Revision: 7479
http://sourceforge.net/p/teem/code/7479
Author: kindlmann
Date: 2025-09-24 05:55:55 +0000 (Wed, 24 Sep 2025)
Log Message:
-----------
still debugging re-write in progress
Modified Paths:
--------------
teem/trunk/src/hest/README.md
teem/trunk/src/hest/argvHest.c
teem/trunk/src/hest/hest.h
teem/trunk/src/hest/methodsHest.c
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/test/tparse.c
Modified: teem/trunk/src/hest/README.md
===================================================================
--- teem/trunk/src/hest/README.md 2025-09-23 14:27:45 UTC (rev 7478)
+++ teem/trunk/src/hest/README.md 2025-09-24 05:55:55 UTC (rev 7479)
@@ -4,7 +4,7 @@
The purpose of `hest` is to bridge the `int argc`, `char *argv[]` command-line arguments and a set of C variables that need to be set for a C program to run. The variables can be of most any type (boolean, `int`, `float`, `char *` strings, or user-defined types), and the variables can hold single values (such as `float thresh`) or multiple values (such as `float RGBA[4]`).
-`hest` was created in 2002 out of frustration with how limiting other C command-line parsing libraries were, and has become essential for the utility of tools like `unu`. To the extent that `hest` bridges the interactive command-line with compiled C code, it has taken on some of the roles that in other contexts are served by scripting languages with C extensions. The `hest` code was revisited in 2023 to add long-overdue support for `--help`, and to add typed functions for specifying options like `hestOptAdd_4_Float`. Re-revisiting the code in 2025 finally fixed long-standing bugs with how quoted strings were handled and how response files were parsed, and to add `-{`, `}-` comments.
+`hest` was created in 2002 out of frustration with how limiting other C command-line parsing libraries were, and has become essential for the utility of tools like `unu`. To the extent that `hest` bridges the interactive command-line with compiled C code, it has taken on some of the roles that in other contexts are served by scripting languages with C extensions. The `hest` code was revisited in 2023 to add long-overdue support for `--help`, and to add typed functions for specifying options like `hestOptAdd_4_Float`. Re-writing the code in 2025 finally fixed long-standing bugs with how quoted strings were handled and how response files were parsed, and to add `-{`, `}-` comments.
## Terminology and concepts
@@ -17,7 +17,7 @@
- Separately, and possibly confusingly, `hest`'s behavior has many knobs and controls, stored in the `hestParm` struct. The pointer-to-struct is always named `hparm` in the code, to try to distinguish it from the parameters appearing on the command-line.
- An _option_ determines how to set one C variable. In the C code, one `hestOpt` struct stores everything about how to parse one option, _and_ the results of that parsing. An array of `hestOpt` structs (not pointers to structs) is how a `hest`-using program communicates what it wants to learn from the command-line. The `hestOpt` array is usually built up by calls to one of the `hestOptAdd` functions.
- On the command-line, the option may be defined by a flag and its associated parms; this is a _flagged_ option. Options may also be _unflagged_, or what others call "positional" arguments, because which C variable is set by parsing that option is disambiguated by the option's position on the command-line, and the corresponding ordering of `hestOpt` structs.
-- The typical way of using `hest` is to process *all* the args in the `argv` you give it. In this way `hest` is more like Python's `argparse` that tries to make sense of the entire command-line, rather than, say, POSIX `getopt` which sees some parts of `argv` as flag-prefixed options but the rest as "operands". `hest` doesn't know what an operand is, and tries to slot every `argv` element into an argument of some (possibly unflagged) option.
+- The typical way of using `hest` is to process _all_ the args in the `argv` you give it. In this way `hest` is more like Python's `argparse` that tries to make sense of the entire command-line, rather than, say, POSIX `getopt` which sees some parts of `argv` as flag-prefixed options but the rest as "operands". `hest` doesn't know what an operand is, and tries to slot every `argv` element into an argument of some (possibly unflagged) option.
- An option may have no parms, one parm, a fixed number of parms, or a variable number of parms. Unflagged options must have one or more parms. With `mv *.txt dir`, the `*.txt` filenames could be parsed as a variable number of parms for an unflagged option, and `dir` would be a fixed single parm for a second unflagged option. Flagged options can appear in any order on the command-line, and the same option can be repeated: later appearances over-ride earlier appearances.
- Sometimes multiple command-line options need to be saved and re-used together, over a time span longer than one shell or any variables set it. Command-line options can thus be stored in _response files_, and the contents of response files effecively expanded into the command-line. Response files can have comments, and response files can name other response files.
- The main `hest` function that does the parsing is `hestParse`. Its job is to set one variable (which may have multiple components) for every `hestOpt`. Information for setting each variable can come from the command-line, or from the default string set in the `hestOpt`, but it has to come from somewhere. Essentially, if no default string is given, then the option _must_ be set on the command-line (or a response file named there). In this sense, `hest`'s "options" are badly named, because they are not really optional.
@@ -26,15 +26,17 @@
## The different `kind`s of options, and how to `hestOptAdd` them.
-There are lot of moving pieces inside `hestParse`, and the description of how it works is complicated by how flexible a `hestOpt` can be. Two of the fields in the `hestOpt` are `min` and `max`: the min and max number of parameters that may be parsed for that option. All the different traditional uses of the command-line can be parameterized in terms of `min` and `max`, but the full range of possibilities of `min`,`max` (which `hest` supports) include some less conventional uses. The _`kind`_ is `hest`'s term for a numeric identifier for the kind of option that a `hestOpt` describes. The following ASCII-art illustrates how `min` and `max` determine:
+There are lot of moving pieces inside `hestParse`, and the description of how it works is complicated by how flexible a `hestOpt` can be. Two of the fields in the `hestOpt` are `min` and `max`: the min and max number of parameters that may be parsed for that option. All the different traditional uses of the command-line can be parameterized in terms of `min` and `max`, but the full range of possibilities of `min`,`max` (which `hest` supports) include some less conventional uses. Once the possibility of mapping out all possibilities for command-line options in terms of `min` and `max` was recognized, `hest` implementation was organized around that, even if typical uses of `hest` are not thought of that way. See also the **concrete examples** below.
+The _`kind`_ is `hest`'s term for a numeric identifier for the kind of option that a `hestOpt` describes. The following ASCII-art illustrates how `min` and `max` determine:
+
- numeric `kind`, shown as `(`_n_`)`; for _n_ = 1,2,3,4,5
- the prose name for that kind of option, which appears in the code and a description of its operation.
- Which `hestOptAdd_` function or family of functions is used to parse that kind of option. Here, `hestOptAdd_` is abbreviated `hOA_` and the final `_T` stands for the type (eg. `_Bool`, `_Int`, `_Float`, `_Enum`, `_Other`, etc).
```
- | . / . /
- | . / . /
+ | . / . /
+ | . / . /
| . / . /
| (5) multiple | (3) multiple
2--| variable | fixed
@@ -55,4 +57,29 @@
min > 0 1 2
```
-The `kind` of option is independent of whether it is flagged or unflagged, and independent of being optional (because the `hestOpt` has a default string) or required (because no default is given).
+The `kind` of option is independent of whether it is flagged or unflagged, and independent of being optional (due to the `hestOpt` having a default string) versus required (when no default is given). Note that users of `hest` may not ever need to worry about `kind`, and it certainly is not part of the API calls to create options and parse command-lines.
+
+Some **concrete examples** may be helpful for understanding `hest`'s utility ... (IN PROGRESS) ...
+... Give some specific examples, flagged and unflagged ...
+.. show a response file being used, show -{ }- commenting
+
+## Limits on what may be parsed, and the `--` flag
+
+If there are no variable parameter options (i.e. limiting oneself to kinds 1, 2, and 3), then there is no limit on options may be used, including the intermixing of flagged and unflagged options, because there is then zero ambiguity about how to attribute a given command-line argument to the parameters of some option.
+
+Things became more complicated with variable parameter options. ... two unflagged variable options wouldn't make sense ...
+
+In [POSIX command-lines](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_01), the elements of `argv` can be first "options" and then "operands", where "options" are
+indicated by something starting with `-`, and may have 0 or more "option-arguments" (what `hest` calls parameters). Then, according to Guideline 10:
+
+> The first -- argument that is not an option-argument should be accepted as a
+> delimiter indicating the end of options. Any following arguments should be treated
+> as operands, even if they begin with the `-` character.
+> So `--` marks the end of some "option-arguments".
+
+Even though, as noted above, `hest` itself does not traffic in "operands", and is _not_ currently compliant with the POSIX behavior just quoted, it does make _limited_ use of the `--` flag.
+
+The limits in using variable parameter options are:
+
+- There can be only one _unflagged_ multiple variable parameter option (kind 5). Having more than one creates ambiguity about which option consumes which arguments, and even though `--` could be used for demarcating them, this seems fragile and has not been implemented.
+- ... The `--` flag indicates the explicit end of a _flagged_ variable parameter options.
Modified: teem/trunk/src/hest/argvHest.c
===================================================================
--- teem/trunk/src/hest/argvHest.c 2025-09-23 14:27:45 UTC (rev 7478)
+++ teem/trunk/src/hest/argvHest.c 2025-09-24 05:55:55 UTC (rev 7479)
@@ -198,13 +198,15 @@
'r', // 2: hestSourceResponseFile
'd', // 3: hestSourceDefault
};
- printf("%s: %s hestArgVec %p has %u args:\n", caller, info, havec, havec->len);
+ printf("%s%s%s hestArgVec %p has %u args:\n ", airStrlen(caller) ? caller : "", //
+ airStrlen(caller) ? ": " : "", //
+ info, havec, havec->len);
for (uint idx = 0; idx < havec->hargArr->len; idx++) {
const hestArg *harg;
harg = havec->harg[idx];
// fprintf(stderr, "!%s harg@%p=%u:<%s>\n", "", AIR_VOIDP(harg), idx,
// harg->str ? harg->str : "NULL");
- printf(" %u%c:<%s>", idx, srcch[harg->source], harg->str ? harg->str : "NULL");
+ printf(" %u%c:<%s>", idx, srcch[harg->source], harg->str ? harg->str : "NULL");
}
printf("\n");
}
Modified: teem/trunk/src/hest/hest.h
===================================================================
--- teem/trunk/src/hest/hest.h 2025-09-23 14:27:45 UTC (rev 7478)
+++ teem/trunk/src/hest/hest.h 2025-09-24 05:55:55 UTC (rev 7479)
@@ -201,8 +201,8 @@
void *valueP; /* storage of parsed values */
char *dflt, /* default value(s) written out as string */
*info; /* description to be printed with "glossary" info */
- unsigned int *sawP; /* used ONLY for multiple variable parameter options
- (min < max >= 2): storage of # of parsed values */
+ unsigned int *sawP; /* really OUTPUT: used ONLY for multiple variable parameter
+ options (min < max >= 2): storage of # of parsed values */
const airEnum *enm; /* used ONLY for airTypeEnum options */
const hestCB *CB; /* used ONLY for airTypeOther options */
Modified: teem/trunk/src/hest/methodsHest.c
===================================================================
--- teem/trunk/src/hest/methodsHest.c 2025-09-23 14:27:45 UTC (rev 7478)
+++ teem/trunk/src/hest/methodsHest.c 2025-09-24 05:55:55 UTC (rev 7479)
@@ -586,12 +586,27 @@
}
}
if (opt[opi].flag) {
- char *tbuff = airStrdup(opt[opi].flag);
- if (!tbuff) {
- biffAddf(HEST, "%s: could not strdup() opi[%u].flag", __func__, opi);
+ const char *flag = opt[opi].flag;
+ uint fslen = AIR_UINT(strlen(flag));
+ if (fslen > AIR_STRLEN_SMALL / 2) {
+ biffAddf(HEST, "%s: strlen(opt[%u].flag) %u is too big", __func__, opi, fslen);
return 1;
}
- // no map, have to call free(tbuff) !
+ if (strchr(flag, '-')) {
+ biffAddf(HEST, "%s: opt[%u].flag \"%s\" contains '-', which will confuse things",
+ __func__, opi, flag);
+ return 1;
+ }
+ for (uint chi = 0; chi < fslen; chi++) {
+ if (!isprint(flag[chi])) {
+ biffAddf(HEST, "%s: opt[%u].flag \"%s\" char %u '%c' non-printing", __func__,
+ opi, flag, chi, flag[chi]);
+ return 1;
+ }
+ }
+ char *tbuff = airStrdup(flag);
+ assert(tbuff);
+ // no mop, have to call free(tbuff) !
char *sep;
if ((sep = strchr(tbuff, MULTI_FLAG_SEP))) {
*sep = '\0';
@@ -609,6 +624,13 @@
__func__, sep + 1, opi);
return (free(tbuff), 1);
}
+ if (strchr(sep + 1, MULTI_FLAG_SEP)) {
+ biffAddf(HEST,
+ "%s: opt[%u] flag string \"%s\" has more than one instance of "
+ "short/long separation character '%c'",
+ __func__, opi, flag, MULTI_FLAG_SEP);
+ return (free(tbuff), 1);
+ }
} else {
if (!strlen(opt[opi].flag)) {
biffAddf(HEST, "%s: opt[%u].flag is zero length", __func__, opi);
@@ -615,12 +637,11 @@
return (free(tbuff), 1);
}
}
- if (hparm->respectDashBraceComments
- && (strchr(opt[opi].flag, '{') || strchr(opt[opi].flag, '}'))) {
+ if (hparm->respectDashBraceComments && (strchr(flag, '{') || strchr(flag, '}'))) {
biffAddf(HEST,
"%s: requested hparm->respectDashBraceComments but opt[%u]'s flag "
"\"%s\" confusingly contains '{' or '}'",
- __func__, opi, opt[opi].flag);
+ __func__, opi, flag);
return (free(tbuff), 1);
}
if (4 == opt[opi].kind) {
@@ -669,8 +690,8 @@
__func__, opi);
return 1;
}
- varNum += ((int)opt[opi].min < _hestMax(opt[opi].max)
- && (NULL == opt[opi].flag)); /* HEY scrutinize casts */
+ // kind 4 = single variable parm; kind 5 = multiple variable parm
+ varNum += (opt[opi].kind > 3 && (NULL == opt[opi].flag));
}
if (varNum > 1) {
biffAddf(HEST, "%s: can't have %u unflagged min<max options, only one", __func__,
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-23 14:27:45 UTC (rev 7478)
+++ teem/trunk/src/hest/parsest.c 2025-09-24 05:55:55 UTC (rev 7479)
@@ -629,11 +629,11 @@
static uint
whichOptFlag(const hestOpt *opt, const char *flarg, const hestParm *hparm) {
uint optNum = opt->arrLen;
- if (hparm->verbosity)
+ if (hparm->verbosity > 3)
printf("%s: looking for maybe-is-flag |%s| in optNum=%u options\n", __func__, flarg,
optNum);
for (uint optIdx = 0; optIdx < optNum; optIdx++) {
- if (hparm->verbosity)
+ if (hparm->verbosity > 3)
printf("%s: optIdx %u |%s| ?\n", __func__, optIdx,
opt[optIdx].flag ? opt[optIdx].flag : "(nullflag)");
const char *optFlag = opt[optIdx].flag;
@@ -660,7 +660,7 @@
free(buff);
}
}
- if (hparm->verbosity) printf("%s: no match, returning UINT_MAX\n", __func__);
+ if (hparm->verbosity > 3) printf("%s: no match, returning UINT_MAX\n", __func__);
return UINT_MAX;
}
@@ -684,6 +684,51 @@
return ident;
}
+static int
+havecTransfer(hestArgVec *hvdst, hestArgVec *hvsrc, uint srcIdx, uint num) {
+ if (!(hvdst && hvsrc)) {
+ biffAddf(HEST, "%s: got NULL dst %p or src %p", __func__, AIR_VOIDP(hvdst),
+ AIR_VOIDP(hvsrc));
+ return 1;
+ }
+ if (num) {
+ if (!(srcIdx < hvsrc->len)) {
+ biffAddf(HEST, "%s: starting index %u in source beyond its length %u", __func__,
+ srcIdx, hvsrc->len);
+ return 1;
+ }
+ if (!(srcIdx + num < hvsrc->len)) {
+ biffAddf(HEST, "%s: %u args starting at index %u |%s| goes past length %u",
+ __func__, num, srcIdx, hvsrc->harg[srcIdx]->str, hvsrc->len);
+ return 1;
+ }
+ // okay now do the work, starting with empty destination
+ hestArgVecReset(hvdst);
+ for (uint ai = 0; ai < num; ai++) {
+ hestArgVecAppendArg(hvdst, hestArgVecRemove(hvsrc, srcIdx));
+ }
+ }
+ return 0;
+}
+
+void
+hestOptPrint(const char *fname, const char *ctx, const hestOpt *allopt) {
+ printf("%s: %s:\n", fname, ctx);
+ printf("%s: v.v.v.v.v.v.v.v.v hestOpt %p has %u options (allocated for %u):\n", fname,
+ AIR_VOIDP(allopt), allopt->arrLen, allopt->arrAlloc);
+ for (uint opi = 0; opi < allopt->arrLen; opi++) {
+ const hestOpt *opt = allopt + opi;
+ printf("--- opt %u:\tflag|%s|\tname|%s|\t k%d (%u)--(%d) \t%s \tdflt|%s|\n", opi,
+ opt->flag ? opt->flag : "(null)", opt->name ? opt->name : "(null)", opt->kind,
+ opt->min, opt->max, _hestTypeStr[opt->type],
+ opt->dflt ? opt->dflt : "(null)");
+ printf(" source %s\n", airEnumStr(hestSource, opt->source));
+ hestArgVecPrint("", " havec:", opt->havec);
+ }
+ printf("%s: ^'^'^'^'^'^'^'^'^\n", fname);
+ return;
+}
+
/*
havecExtractFlagged()
@@ -804,13 +849,10 @@
sprintf(info, "main havec after losing argIdx %u", argIdx);
hestArgVecPrint(__func__, info, havec);
}
- // empty any prior parm args learned for this option
- hestArgVecReset(theOpt->havec);
- for (uint pidx = 0; pidx < parmNum; pidx++) {
- if (hparm->verbosity) {
- printf("%s: moving |%s| to theOpt->havec\n", __func__, havec->harg[argIdx]->str);
- }
- hestArgVecAppendArg(theOpt->havec, hestArgVecRemove(havec, argIdx));
+ if (havecTransfer(theOpt->havec, havec, argIdx, parmNum)) {
+ biffAddf(HEST, "%s: trouble transferring %u args for %s", __func__, parmNum,
+ identStr(ident1, theOpt));
+ return 1;
}
if (hitVPS) {
// drop the variable-parameter-stop flag
@@ -841,16 +883,156 @@
}
// if needs to be set but hasn't been
if (needing && hestSourceUnknown == theOpt->source) {
- biffAddf(HEST, "%s: didn't get required %s\n", __func__,
- identStr(ident1, theOpt));
+ biffAddf(HEST, "%s: didn't get required %s", __func__, identStr(ident1, theOpt));
return 1;
}
}
}
+
+ if (hparm->verbosity) {
+ hestOptPrint(__func__, "end of havecExtractFlagged", opt);
+ hestArgVecPrint(__func__, "end of havecExtractFlagged", havec);
+ }
return 0;
}
+static uint
+nextUnflagged(uint opi, hestOpt *opt) {
+ uint optNum = opt->arrLen;
+ for (; opi < optNum; opi++) {
+ if (!opt[opi].flag) break;
+ }
+ return opi;
+}
+
/*
+havecExtractUnflagged()
+
+extracts the parameter args associated with all unflagged options (of `hestOpt *opt`)
+from the given `hestArgVec *havec` and (like havecExtractFlagged) extracts those args and
+saves them in the corresponding opt[].havec
+
+This is the function that has to handle the trickly logic of allowing there to be
+multiple unflagged options, only one of which may have a variable number of parms; that
+one has to be extracted last.
+*/
+static int
+havecExtractUnflagged(hestOpt *opt, hestArgVec *havec, const hestParm *hparm) {
+ char ident[AIR_STRLEN_HUGE + 1];
+ uint optNum = opt->arrLen;
+ uint unflagNum = 0;
+ for (uint opi = 0; opi < optNum; opi++) {
+ unflagNum += !opt[opi].flag;
+ }
+ if (!unflagNum) {
+ /* no unflagged options; we're done */
+ goto anythingleft;
+ }
+ uint unflag1st = nextUnflagged(0, opt);
+ if (hparm->verbosity) {
+ printf("%s: optNum %u != unflag1st %u: have %u (of %u) unflagged options\n",
+ __func__, optNum, unflag1st, unflagNum, optNum);
+ }
+ uint unflagVar; // the index of the unflagged variable parm option
+ for (unflagVar = unflag1st; //
+ unflagVar < optNum;
+ unflagVar = nextUnflagged(unflagVar + 1, opt)) {
+ if (opt[unflagVar].kind > 3) {
+ // kind 4 = single variable parm; kind 5 = multiple variable parm
+ break;
+ }
+ }
+ /* now, if there is a variable parameter unflagged opt (NOTE that _hestOPCheck()
+ ensured that there is at most one of these), then unflagVar is its index in opt[].
+ If there is no variable parameter unflagged opt, unflagVar is optNum. */
+ if (hparm->verbosity) {
+ printf("%s: unflagVar %d\n", __func__, unflagVar);
+ }
+
+ /* grab parameters for all unflagged opts before opt[unflagVar] */
+ for (uint opi = nextUnflagged(0, opt); opi < unflagVar;
+ opi = nextUnflagged(opi + 1, opt)) {
+ if (hparm->verbosity) {
+ printf("%s: looking at opi = %u (unflagVar = %u)\n", __func__, opi, unflagVar);
+ }
+ if (havecTransfer(opt[opi].havec, havec, 0, opt[opi].min /* min == max */)) {
+ biffAddf(HEST, "%s: trouble getting args for %s", __func__,
+ identStr(ident, opt + opi));
+ }
+ }
+ /* we skip over the variable parameter unflagged option, subtract from havec->len the
+ number of parameters in all the opts which follow it, in order to get the number of
+ parameters in the sole variable parameter option; store this in nvp */
+ int nvp = AIR_INT(havec->len);
+ for (uint opi = nextUnflagged(unflagVar + 1, opt); opi < optNum;
+ opi = nextUnflagged(opi + 1, opt)) {
+ nvp -= AIR_INT(opt[opi].min); // min == max
+ }
+ if (nvp < 0) {
+ uint opi = nextUnflagged(unflagVar + 1, opt);
+ uint np = opt[opi].min;
+ biffAddf(HEST,
+ "%s: remaining %u args not enough for the %u parameter%s "
+ "needed for %s or later options",
+ __func__, havec->len, np, np > 1 ? "s" : "", identStr(ident, opt + opi));
+ return 1;
+ }
+ /* else we had enough args for all the unflagged options following
+ the sole variable parameter unflagged option, so snarf them up */
+ for (uint opi = nextUnflagged(unflagVar + 1, opt); opi < optNum;
+ opi = nextUnflagged(opi + 1, opt)) {
+ // HEY check the nvp start
+ if (havecTransfer(opt[opi].havec, havec, nvp, opt[opi].min /* min == max */)) {
+ biffAddf(HEST, "%s: trouble getting args for %s", __func__,
+ identStr(ident, opt + opi));
+ }
+ }
+
+ /* now, finally, we grab the parameters of the sole variable parameter unflagged opt,
+ if it exists (unflagVar < optNum) */
+ if (hparm->verbosity) {
+ printf("%s: (still here) unflagVar %u vs optNum %u (nvp %d)\n", __func__, unflagVar,
+ optNum, nvp);
+ }
+ if (unflagVar < optNum) { // so there is a variable parameter unflagged opt
+ if (hparm->verbosity) {
+ printf("%s: unflagVar=%u: min, nvp, max = %u %d %d\n", __func__, unflagVar,
+ opt[unflagVar].min, nvp, _hestMax(opt[unflagVar].max));
+ }
+ /* we'll do error checking for unexpected args later */
+ if (nvp) {
+ /* pre-2023: this check used to be done regardless of nvp, but that incorrectly
+ triggered this error message when there were zero given parms, but the default
+ could have supplied them */
+ if (nvp < AIR_INT(opt[unflagVar].min)) {
+ biffAddf(HEST, "%s: didn't get minimum of %d arg%s for %s (got %d)", __func__,
+ opt[unflagVar].min, opt[unflagVar].min > 1 ? "s" : "",
+ identStr(ident, opt + unflagVar), nvp);
+ return 1;
+ }
+ if (havecTransfer(opt[unflagVar].havec, havec, 0, nvp)) {
+ biffAddf(HEST, "%s: trouble getting args for %s", __func__,
+ identStr(ident, opt + unflagVar));
+ }
+ }
+ } else {
+ hestArgVecReset(opt[unflagVar].havec);
+ }
+anythingleft:
+ if (hparm->verbosity) {
+ hestOptPrint(__func__, "end of havecExtractUnflagged", opt);
+ hestArgVecPrint(__func__, "end of havecExtractUnflagged", havec);
+ }
+ if (havec->len) {
+ biffAddf(HEST,
+ "%s: after handling %u unflagged opts, still have unexpected %u args "
+ "left in (starting with \"%s\")",
+ __func__, unflagNum, havec->len, havec->harg[0]->str);
+ }
+ return 0;
+}
+
+/*
hestParse(2): parse the `argc`,`argv` commandline according to the hestOpt array `opt`,
and as tweaked by settings in (if non-NULL) the given `hestParm *_hparm`. If there is
an error, an error message string describing it in detail is generated and
@@ -857,12 +1039,13 @@
- if errP: *errP is set to the newly allocated error message string
NOTE: it is the caller's responsibility to free() it later
- if !errP: the error message is fprintf'ed to stderr
+
The basic phases of parsing are:
0) Error checking on given `opt` array
1) Generate internal representation of command-line that includes expanding any response
- files; this is the `hestArgVec *havec`.
+ files; this all goes into the `hestArgVec *havec`.
2) From `havec`, extract the args that are attributable to flagged and unflagged options,
- moving each `hestArg` instead into per-hestOpt opt->havec
+ moving each `hestArg` out of main `havec` and into the per-hestOpt opt->havec
3) For options not user-supplied, process the opt's `dflt` string to set opt->havec
4) Now, every option should have a opt->havec set, regardless of where it came from.
So parse those per-opt args to set final values for the user to see
@@ -934,14 +1117,12 @@
}
// --2--2--2--2--2-- extract args associated with flagged and unflagged opt
- // HEY initialize internal working fields of each opt
- if (havecExtractFlagged(opt, havec, HPARM) /*
- || havecExtractUnflagged(opt, havec, HPARM) */) {
+ if (havecExtractFlagged(opt, havec, HPARM)
+ || havecExtractUnflagged(opt, havec, HPARM)) {
DO_ERR("problem extracting args for options");
airMopError(mop);
return 1;
}
- // HEY: verify that there were no errant extra args?
#if 0
/* --3--3--3--3--3-- process defaults strings for opts that weren't user-supplied
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-23 14:27:45 UTC (rev 7478)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-24 05:55:55 UTC (rev 7479)
@@ -34,7 +34,7 @@
hestParm *hparm = hestParmNew();
hparm->respectDashDashHelp = AIR_TRUE;
hparm->responseFileEnable = AIR_TRUE;
- hparm->verbosity = 10;
+ hparm->verbosity = 3;
int verb;
hestOptAdd_1_Int(&opt, "v", "verb", &verb, "0", "verbosity");
@@ -44,6 +44,8 @@
&slen);
int flag;
hestOptAdd_Flag(&opt, "b,bingo", &flag, "a flag");
+ int glaf;
+ hestOptAdd_Flag(&opt, "c,cingo", &glaf, "a flag");
char *err = NULL;
if (hestParse2(opt, argc - 1, argv + 1, &err, hparm)) {
fprintf(stderr, "%s: problem:\n%s\n", argv[0], err);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|