You can subscribe to this list here.
| 2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(19) |
Nov
(45) |
Dec
(80) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2004 |
Jan
(58) |
Feb
(127) |
Mar
(74) |
Apr
(34) |
May
(117) |
Jun
(14) |
Jul
(26) |
Aug
(13) |
Sep
(1) |
Oct
(38) |
Nov
(13) |
Dec
(5) |
| 2005 |
Jan
(108) |
Feb
(134) |
Mar
(54) |
Apr
(133) |
May
(16) |
Jun
(54) |
Jul
(128) |
Aug
(99) |
Sep
(157) |
Oct
(182) |
Nov
(236) |
Dec
(212) |
| 2006 |
Jan
(86) |
Feb
(76) |
Mar
(121) |
Apr
(27) |
May
(7) |
Jun
(1) |
Jul
(6) |
Aug
(28) |
Sep
(1) |
Oct
(27) |
Nov
(5) |
Dec
|
| 2007 |
Jan
(32) |
Feb
(22) |
Mar
(22) |
Apr
(11) |
May
(3) |
Jun
(12) |
Jul
(11) |
Aug
(9) |
Sep
(37) |
Oct
(4) |
Nov
(9) |
Dec
(51) |
| 2008 |
Jan
(7) |
Feb
(31) |
Mar
(46) |
Apr
(31) |
May
(5) |
Jun
(27) |
Jul
(12) |
Aug
(5) |
Sep
(13) |
Oct
(24) |
Nov
(112) |
Dec
(15) |
| 2009 |
Jan
(6) |
Feb
(103) |
Mar
(66) |
Apr
(9) |
May
(8) |
Jun
(1) |
Jul
(20) |
Aug
(9) |
Sep
(2) |
Oct
(81) |
Nov
(88) |
Dec
(30) |
| 2010 |
Jan
(65) |
Feb
(57) |
Mar
(22) |
Apr
(12) |
May
(4) |
Jun
(12) |
Jul
(43) |
Aug
(6) |
Sep
(6) |
Oct
(4) |
Nov
(6) |
Dec
(3) |
| 2011 |
Jan
(10) |
Feb
(27) |
Mar
(11) |
Apr
(9) |
May
(69) |
Jun
(73) |
Jul
(67) |
Aug
(116) |
Sep
(40) |
Oct
(11) |
Nov
(34) |
Dec
(19) |
| 2012 |
Jan
|
Feb
(4) |
Mar
(28) |
Apr
(18) |
May
(9) |
Jun
(7) |
Jul
(4) |
Aug
(155) |
Sep
(264) |
Oct
(172) |
Nov
(15) |
Dec
(40) |
| 2013 |
Jan
(1) |
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
(20) |
Jul
(76) |
Aug
(67) |
Sep
(49) |
Oct
(27) |
Nov
(3) |
Dec
(3) |
| 2014 |
Jan
(7) |
Feb
(7) |
Mar
(16) |
Apr
|
May
(4) |
Jun
(1) |
Jul
(18) |
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
| 2015 |
Jan
(6) |
Feb
(5) |
Mar
(3) |
Apr
(23) |
May
(5) |
Jun
|
Jul
(2) |
Aug
(4) |
Sep
|
Oct
|
Nov
(2) |
Dec
(4) |
| 2016 |
Jan
(2) |
Feb
(7) |
Mar
(2) |
Apr
(1) |
May
(14) |
Jun
(3) |
Jul
|
Aug
(3) |
Sep
|
Oct
|
Nov
(1) |
Dec
(3) |
| 2017 |
Jan
(6) |
Feb
|
Mar
(3) |
Apr
|
May
|
Jun
|
Jul
|
Aug
(12) |
Sep
(6) |
Oct
|
Nov
(3) |
Dec
|
| 2018 |
Jan
(4) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(8) |
Sep
|
Oct
|
Nov
|
Dec
(1) |
| 2019 |
Jan
|
Feb
|
Mar
(4) |
Apr
|
May
|
Jun
|
Jul
|
Aug
(3) |
Sep
(8) |
Oct
|
Nov
(2) |
Dec
(25) |
| 2020 |
Jan
|
Feb
(3) |
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
(3) |
Oct
(53) |
Nov
(33) |
Dec
|
| 2021 |
Jan
(2) |
Feb
|
Mar
|
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(4) |
Dec
(5) |
| 2022 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
(5) |
Jul
(93) |
Aug
(206) |
Sep
(39) |
Oct
(19) |
Nov
(11) |
Dec
|
| 2023 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(2) |
Jun
(150) |
Jul
(124) |
Aug
(14) |
Sep
(5) |
Oct
|
Nov
(1) |
Dec
|
| 2024 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(12) |
Jul
(62) |
Aug
|
Sep
(7) |
Oct
|
Nov
(7) |
Dec
|
| 2025 |
Jan
|
Feb
|
Mar
|
Apr
(14) |
May
(3) |
Jun
|
Jul
|
Aug
(76) |
Sep
(214) |
Oct
(6) |
Nov
|
Dec
|
|
From: <kin...@us...> - 2025-09-25 08:56:51
|
Revision: 7486
http://sourceforge.net/p/teem/code/7486
Author: kindlmann
Date: 2025-09-25 08:56:49 +0000 (Thu, 25 Sep 2025)
Log Message:
-----------
still debugging stack, dammit
Modified Paths:
--------------
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/test/tparse.c
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-25 07:47:57 UTC (rev 7485)
+++ teem/trunk/src/hest/parsest.c 2025-09-25 08:56:49 UTC (rev 7486)
@@ -310,8 +310,7 @@
}
*nastP = nastTryAgain;
}
- } else {
- // hin->source is hestSourceResponseFile or hestSourceDefault
+ } else if (hestSourceResponseFile == hin->source || hestSourceDefault == hin->source) {
int icc; // the next character we read as int
int state = argstStart;
do {
@@ -354,6 +353,9 @@
}
}
} while (nastUnknown == *nastP);
+ } else {
+ biffAddf(HEST, "%s%sconfused about hin->source %d", _ME_, hin->source);
+ return 1;
}
return 0;
}
@@ -514,10 +516,13 @@
static int
histProcess(hestArgVec *havec, int *helpWantedP, hestArg *tharg, hestInputStack *hist,
const hestParm *hparm) {
+ if (!hist->len) {
+ biffAddf(HEST, "%s%scannot process zero-height stack", _ME_);
+ return 1;
+ }
if (helpWantedP) *helpWantedP = AIR_FALSE;
int nast = nastUnknown;
uint iters = 0;
- hestInput *topHin;
// printf("!%s: hello hist->len %u\n", __func__, hist->len);
// initialize destination havec
airArrayLenSet(havec->hargArr, 0);
@@ -526,12 +531,10 @@
Otherwise, we loop again. */
while (1) {
iters += 1;
- /* if this loop just pushed a response file, the top hestInput is different
- from what it was when this function started, so re-learn it. */
- topHin = hist->hin + hist->len - 1;
- /* printf("!%s: (iters %u) topHin(%p)->rfname = |%s|\n", __func__, iters,
- AIR_VOIDP(topHin), topHin->rfname); */
- const char *srcstr = airEnumStr(hestSource, topHin->source);
+ // learn ways to describe current input source
+ hestInput *topHin = hist->hin + hist->len - 1;
+ int srcval = topHin->source;
+ const char *srcstr = airEnumStr(hestSource, srcval);
// read next arg into tharg
if (histProcNextArg(&nast, tharg, hist, hparm)) {
biffAddf(HEST, "%s%s(iter %u, on %s) unable to get next arg", _ME_, iters, srcstr);
@@ -544,8 +547,18 @@
}
break;
}
+ // annoyingly, we may get here with an empty stack (HEY fix this?)
+ topHin = (hist->len //
+ ? hist->hin + hist->len - 1
+ : NULL);
+ printf("!%s: nast = %s, |stack| = %u, topHin = %p\n", __func__, airEnumStr(nast_ae, nast),
+ hist->len, AIR_VOIDP(topHin));
// we have a token, is it turning off commenting?
if (hparm->respectDashBraceComments && !strcmp("}-", tharg->str)) {
+ if (!topHin) {
+ biffAddf(HEST, "%s%s(iter %u, on %s) unexpected empty stack (0)", _ME_, iters, srcstr);
+ return 1;
+ }
if (topHin->dashBraceComment) {
topHin->dashBraceComment -= 1;
if (hparm->verbosity) {
@@ -563,6 +576,10 @@
}
// not ending comment, are we starting (or deepening) one?
if (hparm->respectDashBraceComments && !strcmp("-{", tharg->str)) {
+ if (!topHin) {
+ biffAddf(HEST, "%s%s(iter %u, on %s) unexpected empty stack (1)", _ME_, iters, srcstr);
+ return 1;
+ }
topHin->dashBraceComment += 1;
if (hparm->verbosity) {
printf("%s: topHin->dashBraceComment now %u\n", __func__,
@@ -571,7 +588,7 @@
continue;
}
// if in comment, move along
- if (topHin->dashBraceComment) {
+ if (topHin && topHin->dashBraceComment) {
if (hparm->verbosity > 1) {
printf("%s: (iter %u, on %s) skipping commented-out |%s|\n", __func__, iters,
srcstr, tharg->str);
@@ -580,6 +597,10 @@
}
// else this arg is not in a comment and is not related to commenting
if (hparm->respectDashDashHelp && !strcmp("--help", tharg->str)) {
+ if (!topHin) {
+ biffAddf(HEST, "%s%s(iter %u, on %s) unexpected empty stack (2)", _ME_, iters, srcstr);
+ return 1;
+ }
if (hestSourceCommandLine == topHin->source) {
/* user asking for help halts further parsing work: user is not looking
for parsing results nor error messages about that process */
@@ -601,6 +622,10 @@
srcstr, tharg->str);
}
if (hparm->responseFileEnable && tharg->str[0] == RESPONSE_FILE_FLAG) {
+ if (!topHin) {
+ biffAddf(HEST, "%s%s(iter %u, on %s) unexpected empty stack (3)", _ME_, iters, srcstr);
+ return 1;
+ }
if (hestSourceDefault == topHin->source) {
biffAddf(HEST,
"%s%s(iter %u, on %s) %s response files not handled in this source",
@@ -624,7 +649,11 @@
srcstr, tharg->str, havec->len);
}
// set source in the hestArg we just appended
- havec->harg[havec->len - 1]->source = topHin->source;
+ havec->harg[havec->len - 1]->source = srcval;
+ // bail if stack is empty
+ if (!topHin) {
+ break;
+ }
}
if (hist->len && nast == nastEmpty) {
biffAddf(HEST, "%s%snon-empty stack (depth %u) can't generate args???", _ME_,
@@ -1010,7 +1039,7 @@
uint np = opt[opi].min;
biffAddf(HEST,
"%s%sremaining %u args not enough for the %u parameter%s "
- "needed for %s or later options",
+ "needed for unflagged %s or later options",
_ME_, havec->len, np, np > 1 ? "s" : "", identStr(ident, opt + opi));
return 1;
}
@@ -1097,7 +1126,7 @@
uint optNum = opt->arrLen;
for (uint opi = 0; opi < optNum; opi++) {
if (hparm->verbosity) {
- printf("%s: INCOMING", __func__);
+ printf(" -> %s incoming", __func__);
optPrint(opt + opi, opi);
}
if (opt[opi].source) {
@@ -1111,7 +1140,7 @@
opt[opi].dflt is enforced to be NULL) so there is no default string to tokenize,
but we above set source to default for sake of completeness, and to signal that
the flag was not given by user */
- continue;
+ goto nextopt;
}
char ident[AIR_STRLEN_HUGE + 1];
identStr(ident, opt + opi);
@@ -1149,8 +1178,9 @@
_ME_, opi, ident, opt[opi].havec->len, opt[opi].min);
return 1;
}
+ nextopt:
if (hparm->verbosity) {
- printf("%s: OUTGOING", __func__);
+ printf("<- %s: outgoing", __func__);
optPrint(opt + opi, opi);
}
}
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-25 07:47:57 UTC (rev 7485)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-25 08:56:49 UTC (rev 7486)
@@ -54,7 +54,7 @@
int glaf;
hestOptAdd_Flag(&opt, "c,cingo", &glaf, "a flag");
int unpC[2];
- hestOptAdd_2_Int(&opt, NULL, "C C", unpC, NULL, "unflagged C");
+ hestOptAdd_2_Int(&opt, NULL, "C C", unpC, "dfltC0", "unflagged C");
/*
int *unpC;
unsigned int sawC;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-25 07:47:59
|
Revision: 7485
http://sourceforge.net/p/teem/code/7485
Author: kindlmann
Date: 2025-09-25 07:47:57 +0000 (Thu, 25 Sep 2025)
Log Message:
-----------
still hacking, and changed terminology of variable number of parameters from variable to variadic
Modified Paths:
--------------
teem/trunk/src/hest/README.md
teem/trunk/src/hest/adders.c
teem/trunk/src/hest/hest.h
teem/trunk/src/hest/methodsHest.c
teem/trunk/src/hest/parseHest.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-24 21:20:39 UTC (rev 7484)
+++ teem/trunk/src/hest/README.md 2025-09-25 07:47:57 UTC (rev 7485)
@@ -4,8 +4,10 @@
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-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.
+`hest` was created in 2002 out of frustration with how limited 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 approaches 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.
+`hest` is powerful and not simple. This note attempts to give a technical description useful for someone thinking about using `hest`, as well as anyone trying wrap their head around the `hest` source code, including its author.
+
## Terminology and concepts
`hest` has possibly non-standard terminology for the elements of command-line parsing. Here is a bottom-up description of the command-line and what `hest` can do with it:
@@ -17,12 +19,11 @@
- 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 specified 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 in the `hestOpt` array.
-- `hest`'s goal 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 leaves the rest as "operands" for something else downstream to interpret. `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.
+- An option may have no parms, one parm, a fixed number of parms, or a variable number of parms; `hest` calls these _variadic_ options to separate the description of the options from the information (the C _variable_) that the option describes. Unflagged options must have one or more parms. With `mv *.txt dir`, the `*.txt` filenames could be parsed as a variadic parm list for an unflagged option, and `dir` would be a fixed single parm for a second unflagged option.
+- Sometimes multiple command-line options need to be saved and re-used together, over a time span longer than any one shell. 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 (from `#` to end of line, just like shell scripts), and response files can in turn 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.
-Note that `hest` does not attempt to follow POSIX conventions (or terminology) for command-line descriptions, because those conventions don't empower the kind of expressivity and flexibility that motivated `hest`'s creation. POSIX does not encompass the scientific computing and visualization contexts that Teem was built for.
+Pre-dating `hest` are the [POSIX conventions for command-line arguments](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_01), wherein the elements of `argv` can be first "options" and then "operands", where "options" are indicated by an initial `-` character, and may have zero or more "option-arguments" (what `hest` calls "parameters"). However, `hest` does not attempt to follow POSIX conventions (or terminology) for command-line usage. In particular, `hest` has no idea of an "operand" while it tries to interpret _every_ the `argv` args as some argument of some (possibly unflagged) option. Disregard for POSIX has not limited `hest`'s expressivity and flexibility, or its utility for the scientific computing and visualization contexts that it was built for.
## The different `kind`s of options, and how to `hestOptAdd` them.
@@ -39,12 +40,12 @@
| . / . /
| . / . /
| (5) multiple | (3) multiple
- 2--| variable | fixed
+ 2--| variadic | fixed
| parms | parms
| hOA_Nv_T | hOA_{2,3,4,N}_T
|.............................../
| (4) single | (2) single
- 1--| variable | fixed
+ 1--| variadic | fixed
| parm | parm
| hOA_1v_T | hOA_1_T
|...............|/
@@ -57,29 +58,36 @@
min > 0 1 2
```
-The `kind` of option is mostly 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). The one wrinkle is that unflagged options must have at least one parameter (i.e. `min` > 0), either by the command-line or via a default string. An unflagged option allowed to have zero parameters has no textual existence and so is unactionable. Thus for unflagged options, `kind`s 1 and 4 are ruled out; kind 5 is possible with `min` >= 1. This is likely already too much low-level information: users of `hest` will likely not ever need to worry about `kind`, and certainly `kind` is not part of the API calls to create options and parse command-lines.
+The `kind` of option is mostly 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). The one wrinkle is that unflagged options must have at least one parameter (i.e. `min` > 0), either by the command-line or via a default string. An unflagged option allowed to have zero parameters has no explicit textual existence, which seems out-of-bounds for a command-line parser. Thus for unflagged options, `kind`s 1 and 4 are ruled out, and kind 5 is possible with `min` >= 1. This is likely already too much low-level information: users of `hest` will probably never need to worry about `kind`, and certainly `kind` 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
+## The over-all process `hestParse`, its limits, 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.
+Given an `argc`,`argv` command-line and a `hestOpt` array describing the options to parse, `hestParse` must first answer: **which elements of `argv` are associated with which options?** If there are no variadic options (i.e. limiting oneself to kinds 1, 2, and 3), then the answer is straight-forward, even flagged options being able to appear on the command-line in any order. The option set has some fixed number of slots. The flag arguments for the flagged options, and the position of arguments of unflagged options, implies how to put each `argv` element into each slot.
-Things became more complicated with variable parameter options. ... two unflagged variable options wouldn't make sense ...
+Things became more complicated with variadic options. Suppose ... two unflagged variadic 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:
+Understanding how `hest` attributes arguments to options starts with knowing the main phases of `hestParse`:
-> 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".
+0. Validate the given `hestOpt` array
+1. Convert given `argc`,`argv`, to an internal (`hestArgVec`) representation of the argument vector (called `havec` in the code). This is the phase in which response files are expanded and `-{`,`}-` comments are interpreted.
+1. 1. Extract from `havec` all the arguments associated with flagged options: the flag args, any immediately subsequent associated parm args.
+ 1. What remains in `havec` are the concatenation of args associated with the unflagged (positional) options. As long as there is at most one unflagged variadic option, there is an unambigious assignment of arguments to options.
+1. For any options not yet processed, tokenize into arguments the option's default string, and save these per-option.
+1. Finally, parse the per-option arguments to set the value(s) of C variable pointed to by each `hestOpt`. Each `hestOpt` also remembers the source of information for setting the variable (e.g. command-line vs default string).
-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.
+Fans of [POSIX Guidelines](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02) may know that Guideline 10 describes the role of `--`:
-The limits in using variable parameter options are:
+> 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".
-- 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.
+Even though, as noted above, `hest` itself does not traffic in "operands" or follow POSIX, it does borrow `--` in a limited way to help with step 2.1 above: `--` marks the end of arguments for a _flagged_ variadic option, to demarcate them from any arguments intended for _unflagged_ options (variadic or not). In this sense, the `--` mark is more about seperating steps 2.1 and 2.2 above, than it is about separating options from operands.
+
+`hest`'s limitations in option variety and processing are:
+
+- There can be only one _unflagged_ multiple variadic option (kind 5). Having more than one creates ambiguity about which option consumes which arguments, and `hest` currently attempts nothing (not even `--`) to resolve this. There can be, however, more than one _flagged_ multiple variadic options.
+- The `--` flag indicates the explicit end of arguments for a _flagged_ variadic option.
+- `hest` strives to interpret the entire `argv` argument vector; there is currently no way to tell `hest` (via `--` or otherwise): "stop processing `argv` here, and leave the as operands for something else to interpret".
+- Flagged options can appear in any order on the command-line, and the same option can be repeated: the last appearances over-rides all earlier appearances. `hest` currently cannot remember a list of occurance of repeated options (unlike, say, `sed -e ... -e ... `. )
Modified: teem/trunk/src/hest/adders.c
===================================================================
--- teem/trunk/src/hest/adders.c 2025-09-24 21:20:39 UTC (rev 7484)
+++ teem/trunk/src/hest/adders.c 2025-09-25 07:47:57 UTC (rev 7485)
@@ -104,11 +104,11 @@
_T_ = simple scalar types
_E_ = airEnum
_O_ = Other (needs hestCB)
-_1 = single parameter, either fixed (kind 2) or variable (kind 4)
+_1 = single parameter, either fixed (kind 2) or variadic (kind 4)
_M = 2, 3, or 4 = COMPILE-TIME fixed # of parameters (kind 3)
(these exist as a convenience, covering many common hest uses)
_N = RUN_TIME user-given fixed # of parameters (still kind 3)
-_V = RUN_TIME variable # of parameters (kind 5)
+_V = RUN_TIME variadic # of parameters (kind 5)
*/
@@ -122,7 +122,7 @@
_1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1 _1
*/
-/* "_1v_" functions (declared via _DCL_T_0) are for a single variable parm opt (kind 4),
+/* "_1v_" functions (declared via _DCL_T_0) are for a single variadic parm opt (kind 4),
"_1_" functions (declared via _DCL_T_1) are for a single fixed parm opt (kind 2)
*/
#define _DCL_T_0(ATYP, CTYP) \
Modified: teem/trunk/src/hest/hest.h
===================================================================
--- teem/trunk/src/hest/hest.h 2025-09-24 21:20:39 UTC (rev 7484)
+++ teem/trunk/src/hest/hest.h 2025-09-25 07:47:57 UTC (rev 7485)
@@ -164,7 +164,7 @@
** for when the thing you want to parse from the command-line is airTypeOther: not a
** simple boolean, number, string, or airEnum. hestParse() will not allocate anything to
** store individual things, though it may allocate an array in the case of a multiple
-** variable parameter option. If your things are actually pointers to things, then you
+** variadic parameter option. If your things are actually pointers to things, then you
** do the allocation in the parse() callback. In this case, you set destroy() to be
** your "destructor", and it will be called on the result of derefencing the argument
** to parse().
@@ -201,7 +201,7 @@
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; /* really OUTPUT: used ONLY for multiple variable parameter
+ unsigned int *sawP; /* really OUTPUT: used ONLY for multiple variadic 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 */
@@ -217,8 +217,8 @@
1: min == max == 0 stand-alone flag; no parameters
2: min == max == 1 single fixed parameter
3: min == max >= 2 multiple fixed parameters
- 4: min == 0; max == 1; single variable parameter
- 5: min < max; max >= 2 multiple variable parameters
+ 4: min == 0; max == 1; single variadic parameter
+ 5: min < max; max >= 2 multiple variadic parameters
This is set by hest functions as part of building up an array of hestOpt,
and informs the later action of hestOptFree */
alloc; /* Information (set by hestParse) about whether flag is non-NULL, and what
@@ -258,7 +258,7 @@
string (storing zero or many parameters), from which hestParse ultimately parsed
whatever values were set in *valueP above. Internally, hest maintains an argc,argv-like
representation of the info to parse, but here it is joined back together into a
- space-delimited single string. Note that in the case of single variable parameter
+ space-delimited single string. Note that in the case of single variadic parameter
options used without a parameter, the value stored will be "inverted" from the string
here. */
char *parmStr;
@@ -418,8 +418,8 @@
1 min == max == 0 hestOptAdd_Flag (stand-alone flag; no parameters)
2 min == max == 1 hestOptAdd_1_T single fixed parameter
3 min == max >= 2 hestOptAdd_{2,3,4,N}_T multiple fixed parameters
- 4 min == 0; max == 1 hestOptAdd_1v_T single variable parameter
- 5 min < max; max >= 2 hestOptAdd_Nv_T multiple variable parameters
+ 4 min == 0; max == 1 hestOptAdd_1v_T single variadic parameter
+ 5 min < max; max >= 2 hestOptAdd_Nv_T multiple variadic parameters
The type T can be (one for each airType enum value): Bool, Short, UShort, Int, UInt,
Long, ULong, Size_t, Float, Double, Char, String, Enum, or Other. An `airEnum *enm` is
Modified: teem/trunk/src/hest/methodsHest.c
===================================================================
--- teem/trunk/src/hest/methodsHest.c 2025-09-24 21:20:39 UTC (rev 7484)
+++ teem/trunk/src/hest/methodsHest.c 2025-09-25 07:47:57 UTC (rev 7485)
@@ -261,7 +261,7 @@
return 4;
}
- /* else multiple variable parameters */
+ /* else multiple variadic parameters */
return 5;
}
@@ -398,7 +398,7 @@
Like hestOptAdd has done since 2013: returns UINT_MAX in case of error.
NOTE that we do NOT do here ANY error checking on the validity of the arguments passed,
-e.g. enforcing that we have a non-NULL sawP if min != max (a variable parameter option),
+e.g. enforcing that we have a non-NULL sawP if min != max (a variadic parameter option),
or that without a flag (`flag` is NULL) we must have min > 0. All of that is done later,
in _hestOPCheck.
*/
@@ -526,7 +526,7 @@
return 1;
}
uint optNum = opt->arrLen;
- uint varNum = 0; // number of variable-parameter options
+ uint varNum = 0; // number of variadic-parameter options
for (uint opi = 0; opi < optNum; opi++) {
if (!(AIR_IN_OP(airTypeUnknown, opt[opi].type, airTypeLast))) {
biffAddf(HEST, "%s%sopt[%u].type (%d) not in valid range [%d,%d]", _ME_, opi,
@@ -545,7 +545,7 @@
}
if (5 == opt[opi].kind && !(opt[opi].sawP)) {
biffAddf(HEST,
- "%s%sopt[%u] has multiple variable parameters (min=%u,max=%d), "
+ "%s%sopt[%u] has multiple variadic parameters (min=%u,max=%d), "
"but sawP is NULL",
_ME_, opi, opt[opi].min, opt[opi].max);
return 1;
@@ -607,6 +607,15 @@
return 1;
}
}
+ if (1 == opt[opi].kind) {
+ if (opt[opi].dflt) {
+ biffAddf(HEST,
+ "%s%sstand-alone flag (opt[%u] %s) should not give a default; will "
+ "be ignored",
+ _ME_, opi, opt[opi].flag);
+ return 1;
+ }
+ }
char *tbuff = airStrdup(flag);
assert(tbuff);
// no mop, have to call free(tbuff) !
@@ -650,7 +659,7 @@
if (4 == opt[opi].kind) {
if (!opt[opi].dflt) {
biffAddf(HEST,
- "%s%sflagged single variable parameter must "
+ "%s%sflagged single variadic parameter must "
"specify a default",
_ME_);
return (free(tbuff), 1);
@@ -657,7 +666,7 @@
}
if (!strlen(opt[opi].dflt)) {
biffAddf(HEST,
- "%s%sflagged single variable parameter default "
+ "%s%sflagged single variadic parameter default "
"must be non-zero length",
_ME_);
return (free(tbuff), 1);
@@ -694,12 +703,12 @@
}
if (4 == opt[opi].kind && !opt[opi].dflt) {
biffAddf(HEST,
- "%s%sopt[%u] is single variable parameter, but "
+ "%s%sopt[%u] is single variadic parameter, but "
"no default set",
_ME_, opi);
return 1;
}
- // kind 4 = single variable parm; kind 5 = multiple variable parm
+ // kind 4 = single variadic parm; kind 5 = multiple variadic parm
varNum += (opt[opi].kind > 3 && (NULL == opt[opi].flag));
}
if (varNum > 1) {
Modified: teem/trunk/src/hest/parseHest.c
===================================================================
--- teem/trunk/src/hest/parseHest.c 2025-09-24 21:20:39 UTC (rev 7484)
+++ teem/trunk/src/hest/parseHest.c 2025-09-25 07:47:57 UTC (rev 7485)
@@ -137,7 +137,7 @@
But hestParse does not know or care about "operands": *every* element of the given argv
will be interpreted as the argument to some option, including an unflagged option (a
-variable unflagged option is how hest would support something like "cksum *.txt"). For
+variadic unflagged option is how hest would support something like "cksum *.txt"). For
hest to implement the expected behavior for "--", hest has to care about "--" only in the
context of collecting parameters to *flagged* options. But copyArgv() is upstream of that
awareness (of flagged vs unflagged), so we do not act on "--" here.
@@ -392,7 +392,7 @@
happens after defaults are enstated.
This is where, thanks to the action of whichOptFlag(), "--" (and only "--" due to
-VAR_PARM_STOP_FLAG) is used as a marker for the end of a *flagged* variable parameter
+VAR_PARM_STOP_FLAG) is used as a marker for the end of a *flagged* variadic parameter
option. AND, the "--" marker is removed from the argv.
*/
static int
@@ -528,7 +528,7 @@
recording the number of parameters in optParmNum[].
This is the function that has to handle the trickly logic of allowing there to be
-multiple unflagged options, one of which may have a variable number of parms; that
+multiple unflagged options, one of which may have a variadic number of parms; that
one has to be extracted last.
*/
static int
@@ -556,7 +556,7 @@
break;
}
}
- /* now, if there is a variable parameter unflagged opt, unflagVar is its
+ /* now, if there is a variadic parameter unflagged opt, unflagVar is its
index in opt[], or else unflagVar is optNum */
if (hparm->verbosity) {
printf("%sunflagVar %d\n", me, unflagVar);
@@ -579,9 +579,9 @@
airMopAdd(pmop, optParms[op], airFree, airMopAlways);
optParmNum[op] = np;
}
- /* we skip over the variable parameter unflagged option,
+ /* we skip over the variadic parameter unflagged option,
subtract from *argcP 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,
+ in order to get the number of parameters in the sole variadic parameter option,
store this in nvp */
nvp = *argcP;
for (op = nextUnflagged(unflagVar + 1, opt, optNum); op < optNum;
@@ -596,7 +596,7 @@
return 1;
}
/* else we had enough args for all the unflagged options following
- the sole variable parameter unflagged option, so snarf them up */
+ the sole variadic parameter unflagged option, so snarf them up */
for (op = nextUnflagged(unflagVar + 1, opt, optNum); op < optNum;
op = nextUnflagged(op + 1, opt, optNum)) {
np = opt[op].min;
@@ -605,7 +605,7 @@
optParmNum[op] = np;
}
- /* now we grab the parameters of the sole variable parameter unflagged opt,
+ /* now we grab the parameters of the sole variadic parameter unflagged opt,
if it exists (unflagVar < optNum) */
if (hparm->verbosity) {
printf("%s (still here) unflagVar %d vs optNum %d (nvp %d)\n", me, unflagVar, optNum,
@@ -675,7 +675,7 @@
optDfltd[optIdx] = opt[optIdx].flag && !optAprd[optIdx];
break;
case 4:
- /* -------- optional single variables -------- */
+ /* -------- optional single variadics -------- */
/* if the flag appeared (if there is a flag) but the parameter didn't, we'll
"invert" the default; if the flag didn't appear (or if there isn't a flag) and
the parameter also didn't appear, we'll use the default. In either case,
@@ -1036,7 +1036,7 @@
}
break;
case 4:
- /* -------- optional single variables -------- */
+ /* -------- optional single variadics -------- */
if (optParms[op] && vP) {
int pret;
switch (type) {
@@ -1087,8 +1087,8 @@
break;
case airTypeOther:
/* we're parsing an single "other". We will not perform the special flagged
- single variable parameter games as done above, so whether this option is
- flagged or unflagged, we're going to treat it like an unflagged single variable
+ single variadic parameter games as done above, so whether this option is
+ flagged or unflagged, we're going to treat it like an unflagged single variadic
parameter option: if the parameter didn't appear, we'll parse it from the
default, if it did appear, we'll parse it from the command line. Setting up
optParms[op] thusly has already been done by _hestDefaults() */
@@ -1130,7 +1130,7 @@
}
break;
case 5:
- /* -------- multiple variable parameters -------- */
+ /* -------- multiple variadic parameters -------- */
if (optParms[op] && vP) {
if (1 == whichCase(opt, optDfltd, optParmNum, appr, op)) {
*((void **)vP) = NULL;
@@ -1385,7 +1385,7 @@
} else {
fprintf(stderr,
"%sunexpected end-of-parameters flag \"%s\": "
- "not ending a flagged variable-parameter option\n",
+ "not ending a flagged variadic-parameter option\n",
ME, stops);
}
airMopError(mop);
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-24 21:20:39 UTC (rev 7484)
+++ teem/trunk/src/hest/parsest.c 2025-09-25 07:47:57 UTC (rev 7485)
@@ -469,7 +469,6 @@
return 0;
}
-#if 0
static int
histPushDefault(hestInputStack *hist, const char *dflt, const hestParm *hparm) {
if (!(hist && dflt && hparm)) {
@@ -494,7 +493,6 @@
hist->hin[idx].carIdx = 0;
return 0;
}
-#endif
/* histProcess
Consumes args (tokens) from the stack `hist`, mostly just copying them into `havec`,
@@ -516,7 +514,7 @@
static int
histProcess(hestArgVec *havec, int *helpWantedP, hestArg *tharg, hestInputStack *hist,
const hestParm *hparm) {
- *helpWantedP = AIR_FALSE;
+ if (helpWantedP) *helpWantedP = AIR_FALSE;
int nast = nastUnknown;
uint iters = 0;
hestInput *topHin;
@@ -583,9 +581,14 @@
// else this arg is not in a comment and is not related to commenting
if (hparm->respectDashDashHelp && !strcmp("--help", tharg->str)) {
if (hestSourceCommandLine == topHin->source) {
- *helpWantedP = AIR_TRUE;
/* user asking for help halts further parsing work: user is not looking
for parsing results nor error messages about that process */
+ if (!helpWantedP) {
+ biffAddf(HEST, "%s%s(iter %u, on %s) saw \"--help\" but have NULL helpWantedP",
+ _ME_, iters, srcstr);
+ return 1;
+ }
+ *helpWantedP = AIR_TRUE;
return 0;
} else {
biffAddf(HEST, "%s%s(iter %u, on %s) \"--help\" not handled in this source",
@@ -760,14 +763,13 @@
}
/* havecExtractFlagged
-
-extracts the parameter args associated with all flagged options from the given
+Extracts the parameter args associated with all flagged options from the given
`hestArgVec *havec` (as generated by histProc()) and stores them the corresponding
opt->havec. Also sets opt->source according to where that flag arg appeared (we don't
notice if the parameters were weirdly split between the comamnd-line and a response file;
only the source of the flag arg is recorded).
-In the case of variable parameter options, this does the work of figuring out which args
+In the case of variadic parameter options, this does the work of figuring out which args
belong with the option. In any case, this only extracts and preserves (in opt->havec) the
parameter args, not the flag arg that identified which option was being set.
@@ -774,11 +776,11 @@
As a result of this work, the passed `havec` is shortened: all args associated with
flagged opts are removed, so that later work can extract args for unflagged opts.
-For variable parameter options, the sawP information is not set here, since it is better
+For variadic parameter options, the sawP information is not set here, since it is better
set at the final value parsing time, which happens after defaults are enstated.
This is where, thanks to the action of whichOptFlag(), "--" (and only "--" due to
-VAR_PARM_STOP_FLAG) is used as a marker for the end of a flagged variable parameter
+VAR_PARM_STOP_FLAG) is used as a marker for the end of a flagged variadic parameter
option. AND, the "--" marker is removed from `havec`.
*/
static int
@@ -819,7 +821,7 @@
AIR_INT(parmNum) < _hestMax(theOpt->max)
// and looking ahead by parmNum still gives us a valid index pai
&& !(hitEnd = !((pai = argIdx + 1 + parmNum) < havec->len))
- // and either this isn't a variable parm opt
+ // and either this isn't a variadic parm opt
&& (!varParm || // or, it is a varparm opt, and we aren't looking at "--"
!(hitVPS = !strcmp(VPS, havec->harg[pai]->str)))
&& UINT_MAX // and we aren't looking at start of another flagged option
@@ -846,7 +848,7 @@
parmNum);
} else if (hitVPS) {
biffAddf(HEST,
- "%s%shit \"-%c\" (variable-parameter-stop flag) before getting %u "
+ "%s%shit \"-%c\" (variadic-parameter-stop flag) before getting %u "
"parameter%s for %s (got %u)",
_ME_, VAR_PARM_STOP_FLAG, theOpt->min, theOpt->min > 1 ? "s" : "",
identStr(ident1, theOpt), parmNum);
@@ -880,7 +882,7 @@
return 1;
}
if (hitVPS) {
- // drop the variable-parameter-stop flag
+ // drop the variadic-parameter-stop flag
hestArgNix(hestArgVecRemove(havec, argIdx));
}
if (hparm->verbosity) {
@@ -937,7 +939,7 @@
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
+multiple unflagged options, only one of which may have a variadic number of parms; that
one has to be extracted last.
*/
static int
@@ -957,7 +959,7 @@
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
+ uint unflagVar; // the index of the unflagged variadic parm option
for (unflagVar = unflag1st; //
unflagVar < optNum;
unflagVar = nextUnflagged(unflagVar + 1, opt)) {
@@ -968,14 +970,14 @@
_ME_, unflagVar);
return 1;
} else {
- // kind 5 = multiple variable parm; we allow one of these
+ // kind 5 = multiple variadic parm; we allow one of these
break;
}
}
}
- /* now, if there is a variable parameter unflagged opt (NOTE that _hestOPCheck()
+ /* now, if there is a variadic 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 there is no variadic parameter unflagged opt, unflagVar is optNum. */
if (hparm->verbosity) {
printf("%s: unflagVar %u %s\n", __func__, unflagVar,
(unflagVar == optNum ? "==> there is no unflagged var parm opt"
@@ -995,9 +997,9 @@
return 1;
}
}
- /* we skip over the variable parameter unflagged option, subtract from havec->len the
+ /* we skip over the variadic 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 */
+ parameters in the sole variadic 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)) {
@@ -1013,7 +1015,7 @@
return 1;
}
/* else we had enough args for all the unflagged options following
- the sole variable parameter unflagged option, so snarf them up */
+ the sole variadic parameter unflagged option, so snarf them up */
for (uint opi = nextUnflagged(unflagVar + 1, opt); opi < optNum;
opi = nextUnflagged(opi + 1, opt)) {
if (havecTransfer(opt + opi, havec, nvp, opt[opi].min /* min == max */, hparm)) {
@@ -1023,13 +1025,13 @@
}
}
- /* now, finally, we grab the parameters of the sole variable parameter unflagged opt,
+ /* now, finally, we grab the parameters of the sole variadic 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 (unflagVar < optNum) { // so there is a variadic 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));
@@ -1081,7 +1083,6 @@
return 0;
}
-// char **optParms, int *optDfltd, unsigned int *optParmNum, const int *optAprd
/* optProcessDefaults
All the command-line arguments (and any response files invoked therein) should now be
processed (by transferring the arguments to per-option opt->havec arrays), but we need to
@@ -1088,102 +1089,70 @@
ensure that every option has information from which to set values. The per-option
opt->dflt string is what we look to now, to finish setting per-option opt->havec arrays
for all the options for which opt->havec have not already been set. We use
-`hestSourceUknown == opt->source` as the indicator of not already being set.
+`!opt->source` (aka hestSourceUnknown) as the indicator of not already being set.
*/
static int
-optProcessDefaults(hestOpt *opt, const hestParm *hparm) {
- // char *tmpS, ident[AIR_STRLEN_HUGE + 1];
- uint optNum = hestOptNum(opt);
- for (uint optIdx = 0; optIdx < optNum; optIdx++) {
+optProcessDefaults(hestOpt *opt, hestArg *tharg, hestInputStack *hist,
+ const hestParm *hparm) {
+ uint optNum = opt->arrLen;
+ for (uint opi = 0; opi < optNum; opi++) {
if (hparm->verbosity) {
- printf("%s: ", __func__);
- optPrint(opt + optIdx, optIdx);
+ printf("%s: INCOMING", __func__);
+ optPrint(opt + opi, opi);
}
-#if 0
- switch (opt[optIdx].kind) {
- case 1:
- /* -------- (no-parameter) boolean flags -------- */
- /* default is indeed always ignored for the sake of setting the option's value, but
- optDfltd is used downstream to set the option's source. The info came from
- the user if the flag appears, otherwise it is from the default. */
- optDfltd[optIdx] = !optAprd[optIdx];
- break;
- case 2:
- /* -------- one required parameter -------- */
- case 3:
- /* -------- multiple required parameters -------- */
- /* we'll used defaults if the flag didn't appear */
- optDfltd[optIdx] = opt[optIdx].flag && !optAprd[optIdx];
- break;
- case 4:
- /* -------- optional single variables -------- */
- /* if the flag appeared (if there is a flag) but the parameter didn't, we'll
- "invert" the default; if the flag didn't appear (or if there isn't a flag) and
- the parameter also didn't appear, we'll use the default. In either case,
- optParmNum[op] will be zero, and in both cases, we need to use the default
- information. */
- optDfltd[optIdx] = (0 == optParmNum[optIdx]);
- /* fprintf(stderr, "%s optParmNum[%d] = %u --> optDfltd[%d] = %d\n", me,
- * op, optParmNum[op], op, optDfltd[op]); */
- break;
- case 5:
- /* -------- multiple optional parameters -------- */
- /* we'll use the default if there is a flag and it didn't appear. Otherwise (with a
- flagged option), if optParmNum[op] is zero, we'll use the default if user has
- given zero parameters, yet the the option requires at least one. If an unflagged
- option can have zero parms, and user has given zero parms, then we don't use the
- default */
- optDfltd[optIdx]
- = (opt[optIdx].flag
- ? !optAprd[optIdx] /* option is flagged and flag didn't appear */
- /* else: option is unflagged, and there were no given parms,
- and yet the option requires at least one parm */
- : !optParmNum[optIdx] && opt[optIdx].min >= 1);
- /* fprintf(stderr,
- * "!%s: opt[%d].flag = %d; optAprd[op] = %d; optParmNum[op] = %d;
- * opt[op].min = %d "
- * "--> optDfltd[op] = %d\n",
- * me, op, !!opt[op].flag, optAprd[op], optParmNum[op], opt[op].min,
- * optDfltd[op]);
- */
- break;
+ if (opt[opi].source) {
+ /* the source is already set (to something other than hestSourceUnknown),
+ so there's no need for using the default */
+ continue;
}
- /* if not using the default, we're done with this option; continue to next one */
- if (!optDfltd[optIdx]) continue;
- optParms[optIdx] = airStrdup(opt[optIdx].dflt);
+ opt[opi].source = hestSourceDefault;
+ if (1 == opt[opi].kind) {
+ /* There is no meaningful "default" for stand-alone flags (and in fact
+ opt[opi].dflt is enforced to be NULL) so there is no default string to tokenize,
+ but we above set source to default for sake of completeness, and to signal that
+ the flag was not given by user */
+ continue;
+ }
+ char ident[AIR_STRLEN_HUGE + 1];
+ identStr(ident, opt + opi);
+ // should have already checked for this but just to make sure
+ if (!opt[opi].dflt) {
+ biffAddf(HEST, "%s%sopt[%u] %s needs default string but it is NULL", _ME_, opi,
+ ident);
+ return 1;
+ }
+ /* in some circumstances the default may be empty "", even if non-NULL, which means
+ that no args will be put into opt[opi].havec, and that's okay, but that's part of why
+ we set the source above to hestSourceDefault, so that we'd know the source even if it
+ isn't apparent in any of the (non-existant) args. */
if (hparm->verbosity) {
- printf("%soptParms[%d] = |%s|\n", me, optIdx, optParms[optIdx]);
+ printf("%s: looking at opt[%u] %s default string |%s|\n", __func__, opi, ident,
+ opt[opi].dflt);
}
- if (optParms[optIdx]) {
- airMopAdd(mop, optParms[optIdx], airFree, airMopAlways);
- airOneLinify(optParms[optIdx]);
- tmpS = airStrdup(optParms[optIdx]);
- optParmNum[optIdx] = airStrntok(tmpS, " ");
- airFree(tmpS);
+ if (histPushDefault(hist, opt[opi].dflt, hparm)
+ || histProcess(opt[opi].havec, NULL, tharg, hist, hparm)) {
+ biffAddf(HEST, "%s%sproblem tokenizing opt[%u] %s default string", _ME_, opi,
+ ident);
+ return 1;
}
- /* fprintf(stderr,
- * "!%s: after default; optParmNum[%d] = %u; varparm = %d (min %d vs max
- * %d)\n", me, op, optParmNum[op], AIR_INT(opt[op].min) < _hestMax(opt[op].max),
- * ((int)opt[op].min), _hestMax(opt[op].max)); */
- if (AIR_INT(opt[optIdx].min) < _hestMax(opt[optIdx].max)) {
- if (!AIR_IN_CL(AIR_INT(opt[optIdx].min), AIR_INT(optParmNum[optIdx]),
- _hestMax(opt[optIdx].max))) {
- if (-1 == opt[optIdx].max) {
- fprintf(stderr,
- "%s# parameters (in default) for %s is %d, but need %d or more\n", ME,
- identStr(ident, opt + optIdx, hparm, AIR_TRUE), optParmNum[optIdx],
- opt[optIdx].min);
- } else {
- fprintf(
- stderr,
- "%s# parameters (in default) for %s is %d, but need between %d and %d\n", ME,
- identStr(ident, opt + optIdx, hparm, AIR_TRUE), optParmNum[optIdx],
- opt[optIdx].min, _hestMax(opt[optIdx].max));
- }
- return 1;
- }
+ if (hparm->verbosity) {
+ printf("%s: DONE looking at opt[%u] %s default string |%s|\n", __func__, opi,
+ ident, opt[opi].dflt);
}
-#endif
+ /* havecExtractFlagged and havecExtractUnflagged have done the work of ensuring that
+ the minimum number of parm args have been extracted for each option. We have to do
+ something analogous for args tokenized from the default strings. */
+ if (opt[opi].havec->len < opt[opi].min) {
+ biffAddf(
+ HEST,
+ "%s%sopt[%u] %s default string supplied %u args but option wants at least %u",
+ _ME_, opi, ident, opt[opi].havec->len, opt[opi].min);
+ return 1;
+ }
+ if (hparm->verbosity) {
+ printf("%s: OUTGOING", __func__);
+ optPrint(opt + opi, opi);
+ }
}
return 0;
}
@@ -1197,15 +1166,20 @@
- 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 all goes into the `hestArgVec *havec`. 2) From `havec`, extract
-the args that are attributable to flagged and unflagged options, 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
+1) Generate internal representation of command-line that includes expanding any response
+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` 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
+
What is allocated as result of work here should be freed by hestParseFree
*/
int
@@ -1286,7 +1260,7 @@
/* --3--3--3--3--3-- process defaults strings for opts that weren't user-supplied
Like havecExtract{,Un}Flagged, this builds up opt->havec, but does not parse it */
- if (optProcessDefaults(opt, HPARM)) {
+ if (optProcessDefaults(opt, tharg, hist, HPARM)) {
DO_ERR("problem with processing defaults");
airMopError(mop);
return 1;
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-24 21:20:39 UTC (rev 7484)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-25 07:47:57 UTC (rev 7485)
@@ -34,7 +34,7 @@
hestParm *hparm = hestParmNew();
hparm->respectDashDashHelp = AIR_TRUE;
hparm->responseFileEnable = AIR_TRUE;
- hparm->verbosity = 1;
+ hparm->verbosity = 10;
int verb;
hestOptAdd_1_Int(&opt, "v", "verb", &verb, "0", "verbosity");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-24 21:20:44
|
Revision: 7484
http://sourceforge.net/p/teem/code/7484
Author: kindlmann
Date: 2025-09-24 21:20:39 +0000 (Wed, 24 Sep 2025)
Log Message:
-----------
still hacking, and may have fixed longstanding bugs: never enforced that unflagged variable parameter options had min > 0, and, may not have checked that unflagged options without defaults were satisfied by command-line
Modified Paths:
--------------
teem/trunk/src/hest/README.md
teem/trunk/src/hest/adders.c
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-24 18:49:34 UTC (rev 7483)
+++ teem/trunk/src/hest/README.md 2025-09-24 21:20:39 UTC (rev 7484)
@@ -16,8 +16,8 @@
- The set of arguments that logically belong together (often following a flag) in the service of setting a variable are called _parameters_ (or _parms_). There is some slippage of terminology between the `char *` string that communicates the parameter, and the value (such an `int`) parsed from the parameter string.
- 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.
+- On the command-line, the option may be specified 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 in the `hestOpt` array.
+- `hest`'s goal 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 leaves the rest as "operands" for something else downstream to interpret. `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.
@@ -57,7 +57,7 @@
min > 0 1 2
```
-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.
+The `kind` of option is mostly 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). The one wrinkle is that unflagged options must have at least one parameter (i.e. `min` > 0), either by the command-line or via a default string. An unflagged option allowed to have zero parameters has no textual existence and so is unactionable. Thus for unflagged options, `kind`s 1 and 4 are ruled out; kind 5 is possible with `min` >= 1. This is likely already too much low-level information: users of `hest` will likely not ever need to worry about `kind`, and certainly `kind` 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 ...
Modified: teem/trunk/src/hest/adders.c
===================================================================
--- teem/trunk/src/hest/adders.c 2025-09-24 18:49:34 UTC (rev 7483)
+++ teem/trunk/src/hest/adders.c 2025-09-24 21:20:39 UTC (rev 7484)
@@ -22,21 +22,19 @@
/*
Since r6184 2014-03-17, GLK has noted (in ../TODO.txt):
- (from tendGlyph.c): there needs to be an alternative API for hest
- that is not var-args based (as is hestOptAdd). You can't tell when
- you've passed multiple strings for the detailed usage information by
- accident. GLK had accidentally inserted a comma into my multi-line
- string for the "info" arg, relying on the automatic string
- concatenation, and ended up passing total garbage to hestOptAdd for
- the airEnum pointer, causing him to think that the tenGlyphType airEnum
- was malformed, when it was in fact fine ...
+ (from tendGlyph.c): there needs to be an alternative API for hest that is not var-args
+ based (as is hestOptAdd). You can't tell when you've passed multiple strings for the
+ detailed usage information by accident. GLK had accidentally inserted a comma into my
+ multi-line string for the "info" arg, relying on the automatic string concatenation,
+ and ended up passing total garbage to hestOptAdd for the airEnum pointer, causing him
+ to think that the tenGlyphType airEnum was malformed, when it was in fact fine ...
This motivated the r7026 2023-07-06 addition of non-var-args hestOptAdd_nva, which
would have caught the above error.
-The underlying issue there, though, is the total lack of type-checking associated with
-the var-args functions. Even without var-args, the "void*" type of the value storage
-pointer is still a problem. Therefore, the functions in this file help do as much
-type-checking as possible with hest. These functions cover nearly all uses of hest
+The underlying issue there, though, is MORE than the total lack of type-checking
+associated with the var-args functions. Even without var-args, the "void*" type of the
+value storage pointer is still a problem. Therefore, the functions in this file help do
+as much type-checking as possible with hest. These functions cover all uses of hest
within Teem (and in GLK's SciVis class), in a way that is specific to the type of the
value storage pointer valueP, which is still a void* even in hestOptAdd_nva. Many of the
possibilities here are unlikely to be needed (an option for 4 booleans?), but are
@@ -52,14 +50,14 @@
type (like void* is the generic pointer type), and, we're not doing compile-time checks
on the non-NULL-ity of hestCB->destroy. So it all devolves back to plain void*. Still,
the hestOptAdd_*_Other function are generated here to slightly simplify the hestOptAdd
-call, since there is no more NULL and NULL for sawP and enum. The only way around this
-particular type-checking black hole is still extreme attentiveness.
+call, since there is no more NULL and NULL for sawP and enum, respectively. The only way
+around this particular type-checking black hole is still extreme attentiveness.
Two other design points of note:
(1) If we're moving to more type checking, why not make the default values be something
other than a mere string? Why isn't the default typed in a way analogous to the newly
-typed valueP? This is a great idea, and it was actually briefly tried, but then
+typed valueP? This is a great idea, and it was actually briefly tried in 2023, but then
abandoned. One of the original good ideas that made hest work (when it was created) was
the recognition that if the point is to get values out of argv strings collected from the
command-line, then you are absolutely unavoidably in the business of parsing values from
Modified: teem/trunk/src/hest/methodsHest.c
===================================================================
--- teem/trunk/src/hest/methodsHest.c 2025-09-24 18:49:34 UTC (rev 7483)
+++ teem/trunk/src/hest/methodsHest.c 2025-09-24 21:20:39 UTC (rev 7484)
@@ -396,6 +396,11 @@
and the 99 non-var-args hestOptAdd_* functions also all call this.
Like hestOptAdd has done since 2013: returns UINT_MAX in case of error.
+
+NOTE that we do NOT do here ANY error checking on the validity of the arguments passed,
+e.g. enforcing that we have a non-NULL sawP if min != max (a variable parameter option),
+or that without a flag (`flag` is NULL) we must have min > 0. All of that is done later,
+in _hestOPCheck.
*/
unsigned int
hestOptAdd_nva(hestOpt **optP, const char *flag, const char *name, int type,
@@ -491,30 +496,28 @@
return NULL;
}
-/*
- * _hestOPCheck
- *
- * new biff-based container for all logic that used to be in _hestOptCheck (which is
- * the 2025 rename of _hestPanic): the validation of the given hestOpt array `opt` itself
- * (but *not* anything about the command-line or its parsing), relative to the given
- * (non-NULL) hestParm `hparm`.
- *
- * Pre-2025, hest did not depend on biff, and this instead took a 'char *err' that
- * somehow magically had to be allocated for the size of any possible error message
- * generated here. The 2025 re-write recognized that biff is the right way to accumulate
- * error messages, but the use of biff is internal to biff, and not (unusually for Teem)
- * part of the the expected use of biff's API. Thus, public functions hestOptCheck() and
- * hestOptParmCheck(), which are the expected way to access the functionality herein,
- * take a `char **errP` arg into which a message is sprintf'ed, after allocation.
- *
- * The shift to using biff removed how this function used to fprintf(stderr) some
- * messages like "panic 0.5" which were totally uninformative. Now, hestOptCheck() and
- * hestOptParmCheck(), which both call _hestOPCheck, will fprintf(stderr) the informative
- * biff message.
- *
- * Prior to 2023 code revisit: this used to set the "kind" in all the opts, but now that
- * is more appropriately done at the time the option is added.
- */
+/* _hestOPCheck
+New biff-based container for all logic that originated in _hestOptCheck (which is the
+2025 rename of _hestPanic): the validation of the given hestOpt array `opt` itself (but
+*not* anything about the command-line or its parsing), relative to the given (non-NULL)
+hestParm `hparm`.
+
+Pre-2025, hest did not depend on biff, and this instead took a 'char *err' that somehow
+magically had to be allocated for the size of any possible error message generated here.
+The 2025 re-write recognized that biff is the right way to accumulate error messages, but
+the use of biff is internal to biff, and not (unusually for Teem) part of the the
+expected use of biff's API. Thus, public functions hestOptCheck() and hestOptParmCheck(),
+which are the expected way to access the functionality herein, take a `char **errP` arg
+into which a message is sprintf'ed, after allocation.
+
+The shift to using biff removed how this function used to fprintf(stderr) some messages
+like "panic 0.5" which were totally uninformative. Now, hestOptCheck() and
+hestOptParmCheck(), which both call _hestOPCheck, will fprintf(stderr) the informative
+biff message.
+
+Prior to 2023 code revisit: this used to set the "kind" in all the opts, but now that is
+more appropriately done at the time the option is added.
+*/
int
_hestOPCheck(const hestOpt *opt, const hestParm *hparm) {
if (!(opt && hparm)) {
@@ -552,7 +555,7 @@
biffAddf(HEST,
"%s%sopt[%u] (%s) is type \"enum\", but no "
"airEnum pointer given",
- _ME_, opi, opt[opi].flag ? opt[opi].flag : "?");
+ _ME_, opi, opt[opi].flag ? opt[opi].flag : "unflagged");
return 1;
}
}
@@ -561,7 +564,7 @@
biffAddf(HEST,
"%s%sopt[%u] (%s) is type \"other\", but no "
"callbacks given",
- _ME_, opi, opt[opi].flag ? opt[opi].flag : "?");
+ _ME_, opi, opt[opi].flag ? opt[opi].flag : "unflagged");
return 1;
}
if (!(opt[opi].CB->size > 0)) {
@@ -670,8 +673,14 @@
}
*/
free(tbuff);
+ } else { // ------ end of if (opt[opi].flag)
+ // opt[opi] is unflagged
+ if (!opt[opi].min) {
+ biffAddf(HEST, "%s%sunflagged opt[%u] (name %s) must have min >= 1, not 0", _ME_,
+ opi, opt[opi].name ? opt[opi].name : "not set");
+ return 1;
+ }
}
- // ------ end of if (opt[opi].flag)
if (1 == opt[opi].kind) {
if (!opt[opi].flag) {
biffAddf(HEST, "%s%sopt[%u] flag must have a flag", _ME_, opi);
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-24 18:49:34 UTC (rev 7483)
+++ teem/trunk/src/hest/parsest.c 2025-09-24 21:20:39 UTC (rev 7484)
@@ -600,7 +600,7 @@
if (hparm->responseFileEnable && tharg->str[0] == RESPONSE_FILE_FLAG) {
if (hestSourceDefault == topHin->source) {
biffAddf(HEST,
- "%s%s(iter %u, on %s) %s response file not handled in this source",
+ "%s%s(iter %u, on %s) %s response files not handled in this source",
_ME_, iters, srcstr, tharg->str);
return 1;
} else {
@@ -697,12 +697,19 @@
return ident;
}
-// havecTransfer moves `num` args from `hvsrc` (starting at `srcIdx`) to `hvdest`
+/* havecTransfer
+(if `num`) moves `num` args from `hvsrc` (starting at `srcIdx`) to `opt->havec`
+This takes `hestOpt *opt` instead of `opt->havec` so that we can also take this
+time to set `opt->source` according to the incoming `hvsrc->harg[]->source`. To
+minimize cleverness, we set `opt->source` with every transferred argument, which
+means that the per-option source remembered is the source of the *last* argument of the
+option.
+*/
static int
-havecTransfer(hestArgVec *hvdst, hestArgVec *hvsrc, uint srcIdx, uint num,
+havecTransfer(hestOpt *opt, hestArgVec *hvsrc, uint srcIdx, uint num,
const hestParm *hparm) {
- if (!(hvdst && hvsrc)) {
- biffAddf(HEST, "%s%sgot NULL dst %p or src %p", _ME_, AIR_VOIDP(hvdst),
+ if (!(opt && hvsrc)) {
+ biffAddf(HEST, "%s%sgot NULL opt %p or hvsrc %p", _ME_, AIR_VOIDP(opt),
AIR_VOIDP(hvsrc));
return 1;
}
@@ -717,10 +724,12 @@
hvsrc->len, num, srcIdx);
return 1;
}
- // okay now do the work, starting with empty destination
- hestArgVecReset(hvdst);
+ // okay now do the work, starting with empty destination havec
+ hestArgVecReset(opt->havec);
for (uint ai = 0; ai < num; ai++) {
- hestArgVecAppendArg(hvdst, hestArgVecRemove(hvsrc, srcIdx));
+ hestArg *harg = hestArgVecRemove(hvsrc, srcIdx);
+ hestArgVecAppendArg(opt->havec, harg);
+ opt->source = harg->source;
}
}
return 0;
@@ -765,8 +774,8 @@
As a result of this work, the passed `havec` is shortened: all args associated with
flagged opts are removed, so that later work can extract args for unflagged opts.
-The sawP information is not set here, since it is better set at the final value parsing
-time, which happens after defaults are enstated.
+For variable parameter options, the sawP information is not set here, since it is better
+set at the final value parsing time, which happens after defaults are enstated.
This is where, thanks to the action of whichOptFlag(), "--" (and only "--" due to
VAR_PARM_STOP_FLAG) is used as a marker for the end of a flagged variable parameter
@@ -858,19 +867,14 @@
printf("%s: ________ argv[%d]=|%s|: optIdx %u |%s| followed by %u parms\n",
__func__, argIdx, havec->harg[argIdx]->str, optIdx, theOpt->flag, parmNum);
}
- // remember from whence this option came
- theOpt->source = havec->harg[argIdx]->source;
- // lose the flag argument
if (hparm->verbosity > 1) {
hestArgVecPrint(__func__, "main havec as it came", havec);
}
+ // remember from whence this flagged option came
+ theOpt->source = havec->harg[argIdx]->source;
+ // lose the flag argument
hestArgNix(hestArgVecRemove(havec, argIdx));
- if (hparm->verbosity > 1) {
- char info[AIR_STRLEN_HUGE + 1];
- sprintf(info, "main havec after losing argIdx %u", argIdx);
- hestArgVecPrint(__func__, info, havec);
- }
- if (havecTransfer(theOpt->havec, havec, argIdx, parmNum, hparm)) {
+ if (havecTransfer(theOpt, havec, argIdx, parmNum, hparm)) {
biffAddf(HEST, "%s%strouble transferring %u args for %s", _ME_, parmNum,
identStr(ident1, theOpt));
return 1;
@@ -904,7 +908,7 @@
}
// if needs to be set but hasn't been
if (needing && hestSourceUnknown == theOpt->source) {
- biffAddf(HEST, "%s%sdidn't get required %s", _ME_, identStr(ident1, theOpt));
+ biffAddf(HEST, "%s%sdidn't see required %s", _ME_, identStr(ident1, theOpt));
return 1;
}
}
@@ -946,7 +950,7 @@
}
if (!unflagNum) {
/* no unflagged options; we're ~done */
- goto anythingleft;
+ goto finishingup;
}
uint unflag1st = nextUnflagged(0, opt);
if (hparm->verbosity) {
@@ -958,8 +962,15 @@
unflagVar < optNum;
unflagVar = nextUnflagged(unflagVar + 1, opt)) {
if (opt[unflagVar].kind > 3) {
- // kind 4 = single variable parm; kind 5 = multiple variable parm
- break;
+ if (4 == opt[unflagVar].kind) {
+ // (should have been enforced by _hestOPCheck)
+ biffAddf(HEST, "%s%sopt[%u] is (disallowed) unflagged single var parm (kind 4)",
+ _ME_, unflagVar);
+ return 1;
+ } else {
+ // kind 5 = multiple variable parm; we allow one of these
+ break;
+ }
}
}
/* now, if there is a variable parameter unflagged opt (NOTE that _hestOPCheck()
@@ -972,14 +983,14 @@
}
/* grab parameters for all unflagged opts before opt[unflagVar] */
- for (uint opi = nextUnflagged(0, opt); opi < unflagVar;
+ for (uint opi = nextUnflagged(0, opt); //
+ opi < unflagVar;
opi = nextUnflagged(opi + 1, opt)) {
if (hparm->verbosity) {
printf("%s: looking at opi = %u kind %d\n", __func__, opi, opt[opi].kind);
}
- opt[opi].source = havec->harg[0]->source;
- if (havecTransfer(opt[opi].havec, havec, 0, opt[opi].min /* min == max */, hparm)) {
- biffAddf(HEST, "%s%strouble getting args for %s", _ME_,
+ if (havecTransfer(opt + opi, havec, 0, opt[opi].min /* min == max */, hparm)) {
+ biffAddf(HEST, "%s%strouble getting args for unflagged %s", _ME_,
identStr(ident, opt + opi));
return 1;
}
@@ -1005,10 +1016,8 @@
the sole variable parameter unflagged option, so snarf them up */
for (uint opi = nextUnflagged(unflagVar + 1, opt); opi < optNum;
opi = nextUnflagged(opi + 1, opt)) {
- opt[opi].source = havec->harg[nvp]->source;
- if (havecTransfer(opt[opi].havec, havec, nvp, opt[opi].min /* min == max */,
- hparm)) {
- biffAddf(HEST, "%s%strouble getting args for %s", _ME_,
+ if (havecTransfer(opt + opi, havec, nvp, opt[opi].min /* min == max */, hparm)) {
+ biffAddf(HEST, "%s%strouble getting args for unflagged %s", _ME_,
identStr(ident, opt + opi));
return 1;
}
@@ -1025,7 +1034,7 @@
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 */
+ /* we'll do error checking for unexpected args next */
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
@@ -1036,17 +1045,27 @@
identStr(ident, opt + unflagVar), nvp);
return 1;
}
- opt[unflagVar].source = havec->harg[0]->source;
- if (havecTransfer(opt[unflagVar].havec, havec, 0, nvp, hparm)) {
- biffAddf(HEST, "%s%strouble getting args for %s", _ME_,
+ if (havecTransfer(opt + unflagVar, havec, 0, nvp, hparm)) {
+ biffAddf(HEST, "%s%strouble getting args for unflagged %s", _ME_,
identStr(ident, opt + unflagVar));
return 1;
}
}
- } else {
- hestArgVecReset(opt[unflagVar].havec);
}
-anythingleft:
+
+ /* make sure that unflagged options without default were given */
+ for (uint opi = nextUnflagged(0, opt); //
+ opi < optNum;
+ opi = nextUnflagged(opi + 1, opt)) {
+ if (!(opt[opi].dflt) && hestSourceUnknown == opt[opi].source) {
+ char ident1[AIR_STRLEN_HUGE + 1];
+ biffAddf(HEST, "%s%sdidn't see required (unflagged) %s", _ME_,
+ identStr(ident1, opt + opi));
+ return 1;
+ }
+ }
+
+finishingup:
if (hparm->verbosity) {
optAllPrint(__func__, "end of havecExtractUnflagged", opt);
hestArgVecPrint(__func__, "end of havecExtractUnflagged", havec);
@@ -1053,9 +1072,10 @@
}
if (havec->len) {
biffAddf(HEST,
- "%s%safter handling %u unflagged opts, have %u unexpected args "
- "(starting with \"%s\")",
- _ME_, unflagNum, havec->len, havec->harg[0]->str);
+ "%s%safter getting %u unflagged opts, have %u unexpected arg%s "
+ "%s\"%s\"",
+ _ME_, unflagNum, havec->len, havec->len > 1 ? "s," : "",
+ havec->len > 1 ? "starting with " : "", havec->harg[0]->str);
return 1;
}
return 0;
@@ -1067,7 +1087,8 @@
processed (by transferring the arguments to per-option opt->havec arrays), but we need to
ensure that every option has information from which to set values. The per-option
opt->dflt string is what we look to now, to finish setting per-option opt->havec arrays
-for all the options for which opt->havec have not already been set.
+for all the options for which opt->havec have not already been set. We use
+`hestSourceUknown == opt->source` as the indicator of not already being set.
*/
static int
optProcessDefaults(hestOpt *opt, const hestParm *hparm) {
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-24 18:49:34 UTC (rev 7483)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-24 21:20:39 UTC (rev 7484)
@@ -46,7 +46,9 @@
&slen);
int *unpB;
unsigned int sawB;
- hestOptAdd_Nv_Int(&opt, NULL, "B B", 1, -1, &unpB, NULL, "unflagged B", &sawB);
+ hestOptAdd_Nv_Int(&opt, NULL, "B B", 1, -1, &unpB, "BBBB", "unflagged B", &sawB);
+ /* int unpB[2];
+ hestOptAdd_2_Int(&opt, NULL, "B B", unpB, NULL, "unflagged B"); */
int flag;
hestOptAdd_Flag(&opt, "b,bingo", &flag, "a flag");
int glaf;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-24 18:49:38
|
Revision: 7483
http://sourceforge.net/p/teem/code/7483
Author: kindlmann
Date: 2025-09-24 18:49:34 +0000 (Wed, 24 Sep 2025)
Log Message:
-----------
still debugging
Modified Paths:
--------------
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/privateHest.h
teem/trunk/src/hest/test/tparse.c
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-24 08:24:08 UTC (rev 7482)
+++ teem/trunk/src/hest/parsest.c 2025-09-24 18:49:34 UTC (rev 7483)
@@ -29,6 +29,7 @@
hist = hestInputStack
*/
+// histPopt pops one hestInput from the `hist` stack
static int
histPop(hestInputStack *hist, const hestParm *hparm) {
if (!(hist && hparm)) {
@@ -56,7 +57,7 @@
return 0;
}
-// possible *nastP values to indicate histProc_N_ext_A_rg _st_atus
+// possible *nastP values to indicate histProcNextArg status
enum {
nastUnknown, // 0: don't know
nastEmpty, // 1: we have no arg to give and we have given it
@@ -76,11 +77,11 @@
.sense = AIR_FALSE};
static const airEnum *const nast_ae = &_nast_ae;
-/*
+/* argst* enum values
Properly parsing a character sequence into "arguments", like the shell does to convert
the typed command-line into the argv[] array, is more than just calling strtok(), but the
-old hest code only did that, which is why it had to be re-written. Instead, handling "
-vs ' quotes, character escaping, and the implicit concatenation of adjacent args,
+old hest code only did that, which is why it had to be re-written. Instead, handling
+" vs ' quotes, character escaping, and the implicit concatenation of adjacent args,
requires a little deterministic finite automaton (DFA) to be done correctly. Here is the
POSIX info about tokenizing:
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_03
@@ -87,8 +88,8 @@
(although hest does not do rule 5 about parameter expansion, command substitution,
or arithmetic expansion), and here are the details about quoting:
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02
-Here is instructive example code https://github.com/nyuichi/dash.git ; in src/parser.c
-see the readtoken1() function.
+Here is instructive example code https://github.com/nyuichi/dash.git
+ in src/parser.c see the readtoken1() function and the DFA there.
*/
/* the DFA states of our arg tokenizer */
enum {
@@ -119,7 +120,12 @@
.sense = AIR_FALSE};
static const airEnum *const argst_ae = &_argst_ae;
-/* parse an arg argument and save into `tharg`, one character `cc` at a time */
+/* argstGo
+Implements the DFA that tokenizes a character sequence into arguments: the thing that the
+shell does for you to convert the command-line you type into an array argv[] of args.
+This gets one character `icc` at a time, and a pointer to the current DFA state
+`*stateP`, and builds up the output token in `tharg`.
+The Next Arg STatus pointer `nastP` is used to signal when a token is finished. */
static int
argstGo(int *nastP, hestArg *tharg, int *stateP, int icc, int vrbo) {
char cc = (char)icc;
@@ -254,16 +260,15 @@
return 0;
}
-/*
-histProcNextArgTry draws on whatever the top input source is, to (try to) produce
-another arg. It sets in *nastP the status of the next arg production process. Allowing
-nastTryAgain is a way to acknowledge that we are called iteratively by a loop we
-don't control, and managing the machinery of arg production is itself a multi-step
-process that doesn't always produce an arg. We should NOT need to do look-ahead to
-make progress, even if we don't produce an arg: when we see that the input source at
-the top of the stack is exhausted, then we pop that source, but we shouldn't have to
-then immediately test if the next input source is also exhausted (instead we say "try
-again").
+/* histProcNextArgTry
+Draws on whatever the top input source is, to (try to) produce another arg. It sets in
+*nastP the status of the next arg production process. Allowing nastTryAgain is a way to
+acknowledge that we are called iteratively by a loop we don't control, and managing the
+machinery of arg production is itself a multi-step process that doesn't always produce an
+arg. We should NOT need to do look-ahead to make progress, even if we don't produce an
+arg: when we see that the input source at the top of the stack is exhausted, then we pop
+that source, but we shouldn't have to then immediately test if the next input source is
+also exhausted (instead we say "try again").
*/
static int
histProcNextArgTry(int *nastP, hestArg *tharg, hestInputStack *hist,
@@ -317,8 +322,11 @@
} else {
icc = EOF;
}
+ } else if (hestSourceResponseFile == hin->source) {
+ icc = fgetc(hin->rfile); // may be EOF
} else {
- icc = fgetc(hin->rfile); // may be EOF
+ biffAddf(HEST, "%s%sconfused by input source %d", _ME_, hin->source);
+ return 1;
}
if (argstGo(nastP, tharg, &state, icc, hparm->verbosity > 3)) {
if (hestSourceResponseFile == hin->source) {
@@ -350,6 +358,7 @@
return 0;
}
+// histProcNextArg wraps around histProcNextArgTry, hiding occurances of nastTryAgain
static int
histProcNextArg(int *nastP, hestArg *tharg, hestInputStack *hist,
const hestParm *hparm) {
@@ -367,34 +376,7 @@
return 0;
}
-#if 0
static int
-histPushDefault(hestInputStack *hist, const char *dflt, const hestParm *hparm) {
- if (!(hist && dflt && hparm)) {
- biffAddf(HEST, "%s%sgot NULL pointer (hist %p, dflt %p, hparm %p)", _ME_,
- AIR_VOIDP(hist), AIR_VOIDP(dflt), AIR_VOIDP(hparm));
- return 1;
- }
- if (HIST_DEPTH_MAX == hist->len) {
- biffAddf(HEST, "%s%sinput stack depth already at max %u", _ME_, HIST_DEPTH_MAX);
- return 1;
- }
- if (hparm->verbosity) {
- printf("%s: changing stack height: %u --> %u with dflt=|%s|; "
- "dfltLen %u, dfltIdx 0\n",
- __func__, hist->hinArr->len, hist->hinArr->len + 1, dflt,
- AIR_UINT(strlen(dflt)));
- }
- uint idx = airArrayLenIncr(hist->hinArr, 1);
- hist->hin[idx].source = hestSourceDefault;
- hist->hin[idx].dfltStr = dflt;
- hist->hin[idx].dfltLen = strlen(dflt);
- hist->hin[idx].carIdx = 0;
- return 0;
-}
-#endif
-
-static int
histPushCommandLine(hestInputStack *hist, int argc, const char **argv,
const hestParm *hparm) {
if (!(hist && argv && hparm)) {
@@ -487,13 +469,40 @@
return 0;
}
-/*
-histProcess consumes args (tokens) from the stack `hist`, mostly just copying
-them into `havec`, but this does interpret the tokens just enough to implement:
+#if 0
+static int
+histPushDefault(hestInputStack *hist, const char *dflt, const hestParm *hparm) {
+ if (!(hist && dflt && hparm)) {
+ biffAddf(HEST, "%s%sgot NULL pointer (hist %p, dflt %p, hparm %p)", _ME_,
+ AIR_VOIDP(hist), AIR_VOIDP(dflt), AIR_VOIDP(hparm));
+ return 1;
+ }
+ if (HIST_DEPTH_MAX == hist->len) {
+ biffAddf(HEST, "%s%sinput stack depth already at max %u", _ME_, HIST_DEPTH_MAX);
+ return 1;
+ }
+ if (hparm->verbosity) {
+ printf("%s: changing stack height: %u --> %u with dflt=|%s|; "
+ "dfltLen %u, dfltIdx 0\n",
+ __func__, hist->hinArr->len, hist->hinArr->len + 1, dflt,
+ AIR_UINT(strlen(dflt)));
+ }
+ uint idx = airArrayLenIncr(hist->hinArr, 1);
+ hist->hin[idx].source = hestSourceDefault;
+ hist->hin[idx].dfltStr = dflt;
+ hist->hin[idx].dfltLen = strlen(dflt);
+ hist->hin[idx].carIdx = 0;
+ return 0;
+}
+#endif
+
+/* histProcess
+Consumes args (tokens) from the stack `hist`, mostly just copying them into `havec`,
+but this does interpret the tokens just enough to implement:
(what) (allowed sources)
- commenting with -{ , }- all (even a default string, may regret this)
- ask for --help command-line
- - response files command-line, response file
+ - response files command-line, response file (not default string)
since these are the things that histProcNextArg does not understand (it just produces
finished tokens). On the other hand, we do NOT know anything about individual hestOpts
and their flags, which is why they weren't passed to us (--help is special).
@@ -579,8 +588,8 @@
for parsing results nor error messages about that process */
return 0;
} else {
- biffAddf(HEST, "%s%s(iter %u, on %s) \"--help\" not expected here", _ME_, iters,
- srcstr);
+ biffAddf(HEST, "%s%s(iter %u, on %s) \"--help\" not handled in this source",
+ _ME_, iters, srcstr);
return 1;
}
}
@@ -589,14 +598,21 @@
srcstr, tharg->str);
}
if (hparm->responseFileEnable && tharg->str[0] == RESPONSE_FILE_FLAG) {
- // tharg->str is asking to open a response file; try pushing it
- if (histPushResponseFile(hist, tharg->str + 1, hparm)) {
- biffAddf(HEST, "%s%s(iter %u, on %s) unable to process response file %s", _ME_,
- iters, srcstr, tharg->str);
+ if (hestSourceDefault == topHin->source) {
+ biffAddf(HEST,
+ "%s%s(iter %u, on %s) %s response file not handled in this source",
+ _ME_, iters, srcstr, tharg->str);
return 1;
+ } else {
+ // tharg->str is asking to open a response file; try pushing it
+ if (histPushResponseFile(hist, tharg->str + 1, hparm)) {
+ biffAddf(HEST, "%s%s(iter %u, on %s) unable to process response file %s", _ME_,
+ iters, srcstr, tharg->str);
+ return 1;
+ }
+ // have just added response file to stack, next iter will start reading from it
+ continue;
}
- // have just added response file to stack, next iter will start reading from it
- continue;
}
// this arg is not specially handled by us; add it to the arg vec
hestArgVecAppendString(havec, tharg->str);
@@ -615,8 +631,7 @@
return 0;
}
-/*
-whichOptFlag(): for which option (by index) is this the flag?
+/* whichOptFlag(): for which option (by index) is this the flag?
Given an arg string `flarg` (which may be an flag arg like "-size" or parm arg like
"512"), this finds which one, of the options in the given hestOpt array `opt` is
@@ -682,6 +697,7 @@
return ident;
}
+// havecTransfer moves `num` args from `hvsrc` (starting at `srcIdx`) to `hvdest`
static int
havecTransfer(hestArgVec *hvdst, hestArgVec *hvsrc, uint srcIdx, uint num,
const hestParm *hparm) {
@@ -710,26 +726,31 @@
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);
+static void
+optPrint(const hestOpt *opt, uint opi) {
+ printf("--- opt %u:", opi);
+ printf("\t%s%s", opt->flag ? "flag-" : "", opt->flag ? opt->flag : "UNflag");
+ printf("\tname|%s|\t k%d (%u)--(%d) \t%s \tdflt|%s|\n",
+ 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);
+ return;
+}
+
+static void
+optAllPrint(const char *func, const char *ctx, const hestOpt *optall) {
+ printf("%s: %s:\n", func, ctx);
+ printf("%s: v.v.v.v.v.v.v.v.v hestOpt %p has %u options (allocated for %u):\n", func,
+ AIR_VOIDP(optall), optall->arrLen, optall->arrAlloc);
+ for (uint opi = 0; opi < optall->arrLen; opi++) {
+ optPrint(optall + opi, opi);
}
- printf("%s: ^'^'^'^'^'^'^'^'^\n", fname);
+ printf("%s: ^'^'^'^'^'^'^'^'^\n", func);
return;
}
-/*
-havecExtractFlagged()
+/* havecExtractFlagged
extracts the parameter args associated with all flagged options from the given
`hestArgVec *havec` (as generated by histProc()) and stores them the corresponding
@@ -890,7 +911,7 @@
}
if (hparm->verbosity) {
- hestOptPrint(__func__, "end of havecExtractFlagged", opt);
+ optAllPrint(__func__, "end of havecExtractFlagged", opt);
hestArgVecPrint(__func__, "end of havecExtractFlagged", havec);
}
return 0;
@@ -905,8 +926,7 @@
return opi;
}
-/*
-havecExtractUnflagged()
+/* 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
@@ -925,7 +945,7 @@
unflagNum += !opt[opi].flag;
}
if (!unflagNum) {
- /* no unflagged options; we're done */
+ /* no unflagged options; we're ~done */
goto anythingleft;
}
uint unflag1st = nextUnflagged(0, opt);
@@ -985,7 +1005,7 @@
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
+ opt[opi].source = havec->harg[nvp]->source;
if (havecTransfer(opt[opi].havec, havec, nvp, opt[opi].min /* min == max */,
hparm)) {
biffAddf(HEST, "%s%strouble getting args for %s", _ME_,
@@ -1016,6 +1036,7 @@
identStr(ident, opt + unflagVar), nvp);
return 1;
}
+ opt[unflagVar].source = havec->harg[0]->source;
if (havecTransfer(opt[unflagVar].havec, havec, 0, nvp, hparm)) {
biffAddf(HEST, "%s%strouble getting args for %s", _ME_,
identStr(ident, opt + unflagVar));
@@ -1027,13 +1048,13 @@
}
anythingleft:
if (hparm->verbosity) {
- hestOptPrint(__func__, "end of havecExtractUnflagged", opt);
+ optAllPrint(__func__, "end of havecExtractUnflagged", opt);
hestArgVecPrint(__func__, "end of havecExtractUnflagged", havec);
}
if (havec->len) {
biffAddf(HEST,
- "%s%safter handling %u unflagged opts, still have unexpected %u args "
- "left in (starting with \"%s\")",
+ "%s%safter handling %u unflagged opts, have %u unexpected args "
+ "(starting with \"%s\")",
_ME_, unflagNum, havec->len, havec->harg[0]->str);
return 1;
}
@@ -1040,10 +1061,116 @@
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
+// char **optParms, int *optDfltd, unsigned int *optParmNum, const int *optAprd
+/* optProcessDefaults
+All the command-line arguments (and any response files invoked therein) should now be
+processed (by transferring the arguments to per-option opt->havec arrays), but we need to
+ensure that every option has information from which to set values. The per-option
+opt->dflt string is what we look to now, to finish setting per-option opt->havec arrays
+for all the options for which opt->havec have not already been set.
+*/
+static int
+optProcessDefaults(hestOpt *opt, const hestParm *hparm) {
+ // char *tmpS, ident[AIR_STRLEN_HUGE + 1];
+ uint optNum = hestOptNum(opt);
+ for (uint optIdx = 0; optIdx < optNum; optIdx++) {
+ if (hparm->verbosity) {
+ printf("%s: ", __func__);
+ optPrint(opt + optIdx, optIdx);
+ }
+#if 0
+ switch (opt[optIdx].kind) {
+ case 1:
+ /* -------- (no-parameter) boolean flags -------- */
+ /* default is indeed always ignored for the sake of setting the option's value, but
+ optDfltd is used downstream to set the option's source. The info came from
+ the user if the flag appears, otherwise it is from the default. */
+ optDfltd[optIdx] = !optAprd[optIdx];
+ break;
+ case 2:
+ /* -------- one required parameter -------- */
+ case 3:
+ /* -------- multiple required parameters -------- */
+ /* we'll used defaults if the flag didn't appear */
+ optDfltd[optIdx] = opt[optIdx].flag && !optAprd[optIdx];
+ break;
+ case 4:
+ /* -------- optional single variables -------- */
+ /* if the flag appeared (if there is a flag) but the parameter didn't, we'll
+ "invert" the default; if the flag didn't appear (or if there isn't a flag) and
+ the parameter also didn't appear, we'll use the default. In either case,
+ optParmNum[op] will be zero, and in both cases, we need to use the default
+ information. */
+ optDfltd[optIdx] = (0 == optParmNum[optIdx]);
+ /* fprintf(stderr, "%s optParmNum[%d] = %u --> optDfltd[%d] = %d\n", me,
+ * op, optParmNum[op], op, optDfltd[op]); */
+ break;
+ case 5:
+ /* -------- multiple optional parameters -------- */
+ /* we'll use the default if there is a flag and it didn't appear. Otherwise (with a
+ flagged option), if optParmNum[op] is zero, we'll use the default if user has
+ given zero parameters, yet the the option requires at least one. If an unflagged
+ option can have zero parms, and user has given zero parms, then we don't use the
+ default */
+ optDfltd[optIdx]
+ = (opt[optIdx].flag
+ ? !optAprd[optIdx] /* option is flagged and flag didn't appear */
+ /* else: option is unflagged, and there were no given parms,
+ and yet the option requires at least one parm */
+ : !optParmNum[optIdx] && opt[optIdx].min >= 1);
+ /* fprintf(stderr,
+ * "!%s: opt[%d].flag = %d; optAprd[op] = %d; optParmNum[op] = %d;
+ * opt[op].min = %d "
+ * "--> optDfltd[op] = %d\n",
+ * me, op, !!opt[op].flag, optAprd[op], optParmNum[op], opt[op].min,
+ * optDfltd[op]);
+ */
+ break;
+ }
+ /* if not using the default, we're done with this option; continue to next one */
+ if (!optDfltd[optIdx]) continue;
+ optParms[optIdx] = airStrdup(opt[optIdx].dflt);
+ if (hparm->verbosity) {
+ printf("%soptParms[%d] = |%s|\n", me, optIdx, optParms[optIdx]);
+ }
+ if (optParms[optIdx]) {
+ airMopAdd(mop, optParms[optIdx], airFree, airMopAlways);
+ airOneLinify(optParms[optIdx]);
+ tmpS = airStrdup(optParms[optIdx]);
+ optParmNum[optIdx] = airStrntok(tmpS, " ");
+ airFree(tmpS);
+ }
+ /* fprintf(stderr,
+ * "!%s: after default; optParmNum[%d] = %u; varparm = %d (min %d vs max
+ * %d)\n", me, op, optParmNum[op], AIR_INT(opt[op].min) < _hestMax(opt[op].max),
+ * ((int)opt[op].min), _hestMax(opt[op].max)); */
+ if (AIR_INT(opt[optIdx].min) < _hestMax(opt[optIdx].max)) {
+ if (!AIR_IN_CL(AIR_INT(opt[optIdx].min), AIR_INT(optParmNum[optIdx]),
+ _hestMax(opt[optIdx].max))) {
+ if (-1 == opt[optIdx].max) {
+ fprintf(stderr,
+ "%s# parameters (in default) for %s is %d, but need %d or more\n", ME,
+ identStr(ident, opt + optIdx, hparm, AIR_TRUE), optParmNum[optIdx],
+ opt[optIdx].min);
+ } else {
+ fprintf(
+ stderr,
+ "%s# parameters (in default) for %s is %d, but need between %d and %d\n", ME,
+ identStr(ident, opt + optIdx, hparm, AIR_TRUE), optParmNum[optIdx],
+ opt[optIdx].min, _hestMax(opt[optIdx].max));
+ }
+ return 1;
+ }
+ }
+#endif
+ }
+ return 0;
+}
+
+/* hestParse2
+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
- 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
@@ -1050,13 +1177,15 @@
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 all goes into the `hestArgVec *havec`.
-2) From `havec`, extract the args that are attributable to flagged and unflagged options,
- 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
+1) Generate internal representation of command-line that includes expanding any
+response 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`
+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
+
+What is allocated as result of work here should be freed by hestParseFree
*/
int
hestParse2(hestOpt *opt, int argc, const char **argv, char **errP,
@@ -1127,7 +1256,7 @@
// --2--2--2--2--2-- extract args associated with flagged and unflagged opt
if (havecExtractFlagged(opt, havec, HPARM)
- // this will detect extraneous args after unflaggeds are extracted
+ // this will detect extraneous args after unflagged opts are extracted
|| havecExtractUnflagged(opt, havec, HPARM)) {
DO_ERR("problem extracting args for options");
airMopError(mop);
@@ -1134,15 +1263,15 @@
return 1;
}
-#if 0
/* --3--3--3--3--3-- process defaults strings for opts that weren't user-supplied
Like havecExtract{,Un}Flagged, this builds up opt->havec, but does not parse it */
- if (optProcessDefaults) {
+ if (optProcessDefaults(opt, HPARM)) {
DO_ERR("problem with processing defaults");
airMopError(mop);
return 1;
}
+#if 0
// --4--4--4--4--4-- Finally, parse the args and set values
if (optSetValues) {
DO_ERR("problem with setting values");
Modified: teem/trunk/src/hest/privateHest.h
===================================================================
--- teem/trunk/src/hest/privateHest.h 2025-09-24 08:24:08 UTC (rev 7482)
+++ teem/trunk/src/hest/privateHest.h 2025-09-24 18:49:34 UTC (rev 7483)
@@ -83,7 +83,7 @@
cranked up hestParm->verbosity to debug hest itself and don't want error messages
prefixed by a lot of weird hest function names:
In a function where hestParm *hparm is defined, the biff call should look like:
- biffAddf(HEST, "%s%sthis is the error", _ME_, ... )
+ biffAddf(HEST, "%s%shit a problem", _ME_, ... )
Note the "%s%s" start, with NO following space.
Or if its not hparm but some other source `verb` of a verbosity level
biffAddf(HEST, "%s%sthis is the error", _MEV_(verb), ... )
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-24 08:24:08 UTC (rev 7482)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-24 18:49:34 UTC (rev 7483)
@@ -42,8 +42,8 @@
int unpA[2];
hestOptAdd_2_Int(&opt, NULL, "A A", unpA, NULL, "unflagged A");
unsigned int slen;
- hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 2, -1, &res, "640 480",
- "image resolutions", &slen);
+ hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 0, -1, &res, NULL, "image resolutions",
+ &slen);
int *unpB;
unsigned int sawB;
hestOptAdd_Nv_Int(&opt, NULL, "B B", 1, -1, &unpB, NULL, "unflagged B", &sawB);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-24 08:24:12
|
Revision: 7482
http://sourceforge.net/p/teem/code/7482
Author: kindlmann
Date: 2025-09-24 08:24:08 +0000 (Wed, 24 Sep 2025)
Log Message:
-----------
slightly better handling of function self-identification with error reporting
Modified Paths:
--------------
teem/trunk/src/hest/methodsHest.c
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/privateHest.h
teem/trunk/src/hest/test/tparse.c
Modified: teem/trunk/src/hest/methodsHest.c
===================================================================
--- teem/trunk/src/hest/methodsHest.c 2025-09-24 06:38:03 UTC (rev 7481)
+++ teem/trunk/src/hest/methodsHest.c 2025-09-24 08:24:08 UTC (rev 7482)
@@ -518,7 +518,7 @@
int
_hestOPCheck(const hestOpt *opt, const hestParm *hparm) {
if (!(opt && hparm)) {
- biffAddf(HEST, "%s: got NULL opt (%p) or hparm (%p)", __func__, AIR_VOIDP(opt),
+ biffAddf(HEST, "%s%sgot NULL opt (%p) or hparm (%p)", _ME_, AIR_VOIDP(opt),
AIR_VOIDP(hparm));
return 1;
}
@@ -526,33 +526,33 @@
uint varNum = 0; // number of variable-parameter options
for (uint opi = 0; opi < optNum; opi++) {
if (!(AIR_IN_OP(airTypeUnknown, opt[opi].type, airTypeLast))) {
- biffAddf(HEST, "%s: opt[%u].type (%d) not in valid range [%d,%d]", __func__, opi,
+ biffAddf(HEST, "%s%sopt[%u].type (%d) not in valid range [%d,%d]", _ME_, opi,
opt[opi].type, airTypeUnknown + 1, airTypeLast - 1);
return 1;
}
if (!(opt[opi].valueP)) {
- biffAddf(HEST, "%s: opt[%u]'s valueP is NULL!", __func__, opi);
+ biffAddf(HEST, "%s%sopt[%u]'s valueP is NULL!", _ME_, opi);
return 1;
}
// `kind` set by hestOptSingleSet
if (-1 == opt[opi].kind) {
- biffAddf(HEST, "%s: opt[%u]'s min (%d) and max (%d) incompatible", __func__, opi,
+ biffAddf(HEST, "%s%sopt[%u]'s min (%d) and max (%d) incompatible", _ME_, opi,
opt[opi].min, opt[opi].max);
return 1;
}
if (5 == opt[opi].kind && !(opt[opi].sawP)) {
biffAddf(HEST,
- "%s: opt[%u] has multiple variable parameters (min=%u,max=%d), "
+ "%s%sopt[%u] has multiple variable parameters (min=%u,max=%d), "
"but sawP is NULL",
- __func__, opi, opt[opi].min, opt[opi].max);
+ _ME_, opi, opt[opi].min, opt[opi].max);
return 1;
}
if (airTypeEnum == opt[opi].type) {
if (!(opt[opi].enm)) {
biffAddf(HEST,
- "%s: opt[%u] (%s) is type \"enum\", but no "
+ "%s%sopt[%u] (%s) is type \"enum\", but no "
"airEnum pointer given",
- __func__, opi, opt[opi].flag ? opt[opi].flag : "?");
+ _ME_, opi, opt[opi].flag ? opt[opi].flag : "?");
return 1;
}
}
@@ -559,29 +559,29 @@
if (airTypeOther == opt[opi].type) {
if (!(opt[opi].CB)) {
biffAddf(HEST,
- "%s: opt[%u] (%s) is type \"other\", but no "
+ "%s%sopt[%u] (%s) is type \"other\", but no "
"callbacks given",
- __func__, opi, opt[opi].flag ? opt[opi].flag : "?");
+ _ME_, opi, opt[opi].flag ? opt[opi].flag : "?");
return 1;
}
if (!(opt[opi].CB->size > 0)) {
- biffAddf(HEST, "%s: opt[%u]'s \"size\" (%u) invalid", __func__, opi,
+ biffAddf(HEST, "%s%sopt[%u]'s \"size\" (%u) invalid", _ME_, opi,
(uint)(opt[opi].CB->size));
return 1;
}
if (!(opt[opi].CB->type)) {
- biffAddf(HEST, "%s: opt[%u]'s \"type\" is NULL", __func__, opi);
+ biffAddf(HEST, "%s%sopt[%u]'s \"type\" is NULL", _ME_, opi);
return 1;
}
if (!(opt[opi].CB->parse)) {
- biffAddf(HEST, "%s: opt[%u]'s \"parse\" callback NULL", __func__, opi);
+ biffAddf(HEST, "%s%sopt[%u]'s \"parse\" callback NULL", _ME_, opi);
return 1;
}
if (opt[opi].CB->destroy && (sizeof(void *) != opt[opi].CB->size)) {
biffAddf(HEST,
- "%sopt[%u] has a \"destroy\", but size %lu isn't "
+ "%s%sopt[%u] has a \"destroy\", but size %lu isn't "
"sizeof(void*)",
- __func__, opi, (unsigned long)(opt[opi].CB->size));
+ _ME_, opi, (unsigned long)(opt[opi].CB->size));
return 1;
}
}
@@ -589,18 +589,18 @@
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);
+ biffAddf(HEST, "%s%sstrlen(opt[%u].flag) %u is too big", _ME_, opi, fslen);
return 1;
}
if (strchr(flag, '-')) {
- biffAddf(HEST, "%s: opt[%u].flag \"%s\" contains '-', which will confuse things",
- __func__, opi, flag);
+ biffAddf(HEST, "%s%sopt[%u].flag \"%s\" contains '-', which will confuse things",
+ _ME_, 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]);
+ biffAddf(HEST, "%s%sopt[%u].flag \"%s\" char %u '%c' non-printing", _ME_, opi,
+ flag, chi, flag[chi]);
return 1;
}
}
@@ -612,51 +612,51 @@
*sep = '\0';
if (!(strlen(tbuff) && strlen(sep + 1))) {
biffAddf(HEST,
- "%s: either short (\"%s\") or long (\"%s\") flag"
+ "%s%seither short (\"%s\") or long (\"%s\") flag"
" of opt[%u] is zero length",
- __func__, tbuff, sep + 1, opi);
+ _ME_, tbuff, sep + 1, opi);
return (free(tbuff), 1);
}
if (hparm->respectDashDashHelp && !strcmp("help", sep + 1)) {
biffAddf(HEST,
- "%s: long \"--%s\" flag of opt[%u] is same as \"--help\" "
+ "%s%slong \"--%s\" flag of opt[%u] is same as \"--help\" "
"that requested hparm->respectDashDashHelp handles separately",
- __func__, sep + 1, opi);
+ _ME_, 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 "
+ "%s%sopt[%u] flag string \"%s\" has more than one instance of "
"short/long separation character '%c'",
- __func__, opi, flag, MULTI_FLAG_SEP);
+ _ME_, 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);
+ biffAddf(HEST, "%s%sopt[%u].flag is zero length", _ME_, opi);
return (free(tbuff), 1);
}
}
if (hparm->respectDashBraceComments && (strchr(flag, '{') || strchr(flag, '}'))) {
biffAddf(HEST,
- "%s: requested hparm->respectDashBraceComments but opt[%u]'s flag "
+ "%s%srequested hparm->respectDashBraceComments but opt[%u]'s flag "
"\"%s\" confusingly contains '{' or '}'",
- __func__, opi, flag);
+ _ME_, opi, flag);
return (free(tbuff), 1);
}
if (4 == opt[opi].kind) {
if (!opt[opi].dflt) {
biffAddf(HEST,
- "%s: flagged single variable parameter must "
+ "%s%sflagged single variable parameter must "
"specify a default",
- __func__);
+ _ME_);
return (free(tbuff), 1);
}
if (!strlen(opt[opi].dflt)) {
biffAddf(HEST,
- "%s: flagged single variable parameter default "
+ "%s%sflagged single variable parameter default "
"must be non-zero length",
- __func__);
+ _ME_);
return (free(tbuff), 1);
}
}
@@ -674,20 +674,20 @@
// ------ end of if (opt[opi].flag)
if (1 == opt[opi].kind) {
if (!opt[opi].flag) {
- biffAddf(HEST, "%s: opt[%u] flag must have a flag", __func__, opi);
+ biffAddf(HEST, "%s%sopt[%u] flag must have a flag", _ME_, opi);
return 1;
}
} else {
if (!opt[opi].name) {
- biffAddf(HEST, "%s: opt[%u] isn't a flag: must have \"name\"", __func__, opi);
+ biffAddf(HEST, "%s%sopt[%u] isn't a flag: must have \"name\"", _ME_, opi);
return 1;
}
}
if (4 == opt[opi].kind && !opt[opi].dflt) {
biffAddf(HEST,
- "%s: opt[%u] is single variable parameter, but "
+ "%s%sopt[%u] is single variable parameter, but "
"no default set",
- __func__, opi);
+ _ME_, opi);
return 1;
}
// kind 4 = single variable parm; kind 5 = multiple variable parm
@@ -694,7 +694,7 @@
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__,
+ biffAddf(HEST, "%s%scan't have %u unflagged min<max options, only one", _ME_,
varNum);
return 1;
}
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-24 06:38:03 UTC (rev 7481)
+++ teem/trunk/src/hest/parsest.c 2025-09-24 08:24:08 UTC (rev 7482)
@@ -32,20 +32,19 @@
static int
histPop(hestInputStack *hist, const hestParm *hparm) {
if (!(hist && hparm)) {
- biffAddf(HEST, "%s: got NULL pointer (hist %p hparm %p)", __func__, AIR_VOIDP(hist),
+ biffAddf(HEST, "%s%sgot NULL pointer (hist %p hparm %p)", _ME_, AIR_VOIDP(hist),
AIR_VOIDP(hparm));
return 1;
}
if (!(hist->len)) {
- biffAddf(HEST, "%s: cannot pop from input stack height 0", __func__);
+ biffAddf(HEST, "%s%scannot pop from input stack height 0", _ME_);
return 1;
}
hestInput *topHin = hist->hin + hist->len - 1;
if (topHin->dashBraceComment) {
biffAddf(HEST,
- "%s: %u start comment marker%s \"-{\" not balanced by equal later \"}-\"",
- __func__, topHin->dashBraceComment,
- topHin->dashBraceComment > 1 ? "s" : "");
+ "%s%s%u start comment marker%s \"-{\" not balanced by equal later \"}-\"",
+ _ME_, topHin->dashBraceComment, topHin->dashBraceComment > 1 ? "s" : "");
return 1;
}
if (hparm->verbosity) {
@@ -144,24 +143,24 @@
ret = 0;
break;
case argstSingleQ:
- biffAddf(HEST, "%s: hit input end inside single-quoted string", __func__);
+ biffAddf(HEST, "%s%shit input end inside single-quoted string", _MEV_(vrbo));
ret = 1;
break;
case argstDoubleQ:
- biffAddf(HEST, "%s: hit input end inside double-quoted string", __func__);
+ biffAddf(HEST, "%s%shit input end inside double-quoted string", _MEV_(vrbo));
ret = 1;
break;
case argstEscapeIn:
- biffAddf(HEST, "%s: hit input end after \\ escape from arg", __func__);
+ biffAddf(HEST, "%s%shit input end after \\ escape from arg", _MEV_(vrbo));
ret = 1;
break;
case argstEscapeDQ:
- biffAddf(HEST, "%s: hit input end after \\ escape from double-quoted string",
- __func__);
+ biffAddf(HEST, "%s%shit input end after \\ escape from double-quoted string",
+ _MEV_(vrbo));
ret = 1;
break;
default:
- biffAddf(HEST, "%s: hit input end in unknown state %d", __func__, *stateP);
+ biffAddf(HEST, "%s%shit input end in unknown state %d", _MEV_(vrbo), *stateP);
ret = 1;
}
return ret;
@@ -270,7 +269,7 @@
histProcNextArgTry(int *nastP, hestArg *tharg, hestInputStack *hist,
const hestParm *hparm) {
if (!(nastP && tharg && hist && hparm)) {
- biffAddf(HEST, "%s: got NULL pointer (nastP %p tharg %p hist %p hparm %p)", __func__,
+ biffAddf(HEST, "%s%sgot NULL pointer (nastP %p tharg %p hist %p hparm %p)", _ME_,
AIR_VOIDP(nastP), AIR_VOIDP(tharg), AIR_VOIDP(hist), AIR_VOIDP(hparm));
return 1;
}
@@ -300,7 +299,7 @@
} else {
// we have gotten to the end of the given argv array, pop it as input source */
if (histPop(hist, hparm)) {
- biffAddf(HEST, "%s: trouble popping %s", __func__,
+ biffAddf(HEST, "%s%strouble popping %s", _ME_,
airEnumStr(hestSource, hestSourceCommandLine));
return 1;
}
@@ -321,12 +320,12 @@
} else {
icc = fgetc(hin->rfile); // may be EOF
}
- if (argstGo(nastP, tharg, &state, icc, hparm->verbosity > 1)) {
+ if (argstGo(nastP, tharg, &state, icc, hparm->verbosity > 3)) {
if (hestSourceResponseFile == hin->source) {
- biffAddf(HEST, "%s: trouble at character %u of %s \"%s\"", __func__,
- hin->carIdx, airEnumStr(hestSource, hin->source), hin->rfname);
+ biffAddf(HEST, "%s%strouble at character %u of %s \"%s\"", _ME_, hin->carIdx,
+ airEnumStr(hestSource, hin->source), hin->rfname);
} else {
- biffAddf(HEST, "%s: trouble at character %u of %s |%s|", __func__, hin->carIdx,
+ biffAddf(HEST, "%s%strouble at character %u of %s |%s|", _ME_, hin->carIdx,
airEnumStr(hestSource, hin->source), hin->dfltStr);
}
return 1;
@@ -337,10 +336,10 @@
// we're at end; pop input; *nastP already set to nastTryAgain by argstGo()
if (histPop(hist, hparm)) {
if (hestSourceResponseFile == hin->source) {
- biffAddf(HEST, "%s: trouble popping %s \"%s\"", __func__,
+ biffAddf(HEST, "%s%strouble popping %s \"%s\"", _ME_,
airEnumStr(hestSource, hin->source), hin->rfname);
} else {
- biffAddf(HEST, "%s: trouble popping %s |%s|", __func__,
+ biffAddf(HEST, "%s%strouble popping %s |%s|", _ME_,
airEnumStr(hestSource, hin->source), hin->dfltStr);
}
return 1;
@@ -357,7 +356,7 @@
// printf("!%s: hello hist->len %u\n", __func__, hist->len);
do {
if (histProcNextArgTry(nastP, tharg, hist, hparm)) {
- biffAddf(HEST, "%s: trouble getting next arg", __func__);
+ biffAddf(HEST, "%s%strouble getting next arg", _ME_);
return 1;
}
if (hparm->verbosity > 1) {
@@ -368,16 +367,16 @@
return 0;
}
-#if 0 // not used yet
+#if 0
static int
histPushDefault(hestInputStack *hist, const char *dflt, const hestParm *hparm) {
if (!(hist && dflt && hparm)) {
- biffAddf(HEST, "%s: got NULL pointer (hist %p, dflt %p, hparm %p)", __func__,
+ biffAddf(HEST, "%s%sgot NULL pointer (hist %p, dflt %p, hparm %p)", _ME_,
AIR_VOIDP(hist), AIR_VOIDP(dflt), AIR_VOIDP(hparm));
return 1;
}
if (HIST_DEPTH_MAX == hist->len) {
- biffAddf(HEST, "%s: input stack depth already at max %u", __func__, HIST_DEPTH_MAX);
+ biffAddf(HEST, "%s%sinput stack depth already at max %u", _ME_, HIST_DEPTH_MAX);
return 1;
}
if (hparm->verbosity) {
@@ -399,12 +398,12 @@
histPushCommandLine(hestInputStack *hist, int argc, const char **argv,
const hestParm *hparm) {
if (!(hist && argv && hparm)) {
- biffAddf(HEST, "%s: got NULL pointer (hist %p, argv %p, hparm %p)", __func__,
+ biffAddf(HEST, "%s%sgot NULL pointer (hist %p, argv %p, hparm %p)", _ME_,
AIR_VOIDP(hist), AIR_VOIDP(argv), AIR_VOIDP(hparm));
return 1;
}
if (HIST_DEPTH_MAX == hist->len) {
- biffAddf(HEST, "%s: input stack depth already at max %u", __func__, HIST_DEPTH_MAX);
+ biffAddf(HEST, "%s%sinput stack depth already at max %u", _ME_, HIST_DEPTH_MAX);
return 1;
}
if (hparm->verbosity) {
@@ -426,21 +425,21 @@
static int
histPushResponseFile(hestInputStack *hist, const char *rfname, const hestParm *hparm) {
if (!(hist && rfname && hparm)) {
- biffAddf(HEST, "%s: got NULL pointer (hist %p, rfname %p, hparm %p)", __func__,
+ biffAddf(HEST, "%s%sgot NULL pointer (hist %p, rfname %p, hparm %p)", _ME_,
AIR_VOIDP(hist), AIR_VOIDP(rfname), AIR_VOIDP(hparm));
return 1;
}
if (HIST_DEPTH_MAX == hist->len) {
// HEY test this error
- biffAddf(HEST, "%s: input stack depth already at max %u", __func__, HIST_DEPTH_MAX);
+ biffAddf(HEST, "%s%sinput stack depth already at max %u", _ME_, HIST_DEPTH_MAX);
return 1;
}
if (!strlen(rfname)) {
// HEY test this error
biffAddf(HEST,
- "%s: saw arg start with response file flag \"%c\" "
+ "%s%ssaw arg start with response file flag \"%c\" "
"but no filename followed",
- __func__, RESPONSE_FILE_FLAG);
+ _ME_, RESPONSE_FILE_FLAG);
return 1;
}
// have we seen rfname before?
@@ -452,9 +451,9 @@
&& !strcmp(oldHin->rfname, rfname)) {
// HEY test this error
biffAddf(HEST,
- "%s: already reading \"%s\" as response file; "
+ "%s%salready reading \"%s\" as response file; "
"cannot recursively read it again",
- __func__, rfname);
+ _ME_, rfname);
return 1;
}
}
@@ -462,7 +461,7 @@
// are we trying to read stdin twice?
if (!strcmp("-", rfname) && hist->stdinRead) {
// HEY test this error
- biffAddf(HEST, "%s: response filename \"%s\" but previously read stdin", __func__,
+ biffAddf(HEST, "%s%sresponse filename \"%s\" but previously read stdin", _ME_,
rfname);
return 1;
}
@@ -469,7 +468,7 @@
// try to open response file
FILE *rfile = airFopen(rfname, stdin, "r");
if (!(rfile)) {
- biffAddf(HEST, "%s: couldn't fopen(\"%s\",\"r\"): %s", __func__, rfname,
+ biffAddf(HEST, "%s%scouldn't fopen(\"%s\",\"r\"): %s", _ME_, rfname,
strerror(errno));
return 1;
}
@@ -528,8 +527,7 @@
const char *srcstr = airEnumStr(hestSource, topHin->source);
// read next arg into tharg
if (histProcNextArg(&nast, tharg, hist, hparm)) {
- biffAddf(HEST, "%s: (iter %u, on %s) unable to get next arg", __func__, iters,
- srcstr);
+ biffAddf(HEST, "%s%s(iter %u, on %s) unable to get next arg", _ME_, iters, srcstr);
return 1;
}
if (nastEmpty == nast) {
@@ -550,9 +548,9 @@
continue; // since }- does not belong in havec
} else {
biffAddf(HEST,
- "%s: (iter %u, on %s) end comment marker \"}-\" not "
+ "%s%s(iter %u, on %s) end comment marker \"}-\" not "
"balanced by prior \"-{\"",
- __func__, iters, srcstr);
+ _ME_, iters, srcstr);
return 1;
}
}
@@ -581,12 +579,12 @@
for parsing results nor error messages about that process */
return 0;
} else {
- biffAddf(HEST, "%s: (iter %u, on %s) \"--help\" not expected here", __func__,
- iters, srcstr);
+ biffAddf(HEST, "%s%s(iter %u, on %s) \"--help\" not expected here", _ME_, iters,
+ srcstr);
return 1;
}
}
- if (hparm->verbosity > 1) {
+ if (hparm->verbosity > 2) {
printf("%s: (iter %u, on %s) looking at latest tharg |%s|\n", __func__, iters,
srcstr, tharg->str);
}
@@ -593,8 +591,8 @@
if (hparm->responseFileEnable && tharg->str[0] == RESPONSE_FILE_FLAG) {
// tharg->str is asking to open a response file; try pushing it
if (histPushResponseFile(hist, tharg->str + 1, hparm)) {
- biffAddf(HEST, "%s: (iter %u, on %s) unable to process response file %s",
- __func__, iters, srcstr, tharg->str);
+ biffAddf(HEST, "%s%s(iter %u, on %s) unable to process response file %s", _ME_,
+ iters, srcstr, tharg->str);
return 1;
}
// have just added response file to stack, next iter will start reading from it
@@ -610,7 +608,7 @@
havec->harg[havec->len - 1]->source = topHin->source;
}
if (hist->len && nast == nastEmpty) {
- biffAddf(HEST, "%s: non-empty stack (depth %u) can't generate args???", __func__,
+ biffAddf(HEST, "%s%snon-empty stack (depth %u) can't generate args???", _ME_,
hist->len);
return 1;
}
@@ -685,20 +683,21 @@
}
static int
-havecTransfer(hestArgVec *hvdst, hestArgVec *hvsrc, uint srcIdx, uint num) {
+havecTransfer(hestArgVec *hvdst, hestArgVec *hvsrc, uint srcIdx, uint num,
+ const hestParm *hparm) {
if (!(hvdst && hvsrc)) {
- biffAddf(HEST, "%s: got NULL dst %p or src %p", __func__, AIR_VOIDP(hvdst),
+ biffAddf(HEST, "%s%sgot NULL dst %p or src %p", _ME_, 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__,
+ biffAddf(HEST, "%s%sstarting index %u in source beyond its length %u", _ME_,
srcIdx, hvsrc->len);
return 1;
}
if (!(srcIdx + num <= hvsrc->len)) {
- biffAddf(HEST, "%s: have only %u args but want %u starting at %u", __func__,
+ biffAddf(HEST, "%s%shave only %u args but want %u starting at %u", _ME_,
hvsrc->len, num, srcIdx);
return 1;
}
@@ -758,7 +757,7 @@
uint argIdx = 0;
hestOpt *theOpt = NULL;
while (argIdx < havec->len) { // NOTE: havec->len may decrease within an interation!
- if (hparm->verbosity) {
+ if (hparm->verbosity > 1) {
printf("%s: ------------- argIdx = %u (of %u) -> argv[argIdx] = |%s|\n", __func__,
argIdx, havec->len, havec->harg[argIdx]->str);
}
@@ -765,7 +764,7 @@
uint optIdx = whichOptFlag(opt, havec->harg[argIdx]->str, hparm);
if (UINT_MAX == optIdx) {
// havec->harg[argIdx]->str is not a flag for any option, move on to next arg
- if (hparm->verbosity) {
+ if (hparm->verbosity > 2) {
printf("%s: |%s| not a flag arg, continue\n", __func__,
havec->harg[argIdx]->str);
}
@@ -811,26 +810,26 @@
if (parmNum < theOpt->min) { // didn't get required min # parameters
if (hitEnd) {
biffAddf(HEST,
- "%s: hit end of args before getting %u parameter%s "
+ "%s%shit end of args before getting %u parameter%s "
"for %s (got %u)",
- __func__, theOpt->min, theOpt->min > 1 ? "s" : "",
- identStr(ident1, theOpt), parmNum);
+ _ME_, theOpt->min, theOpt->min > 1 ? "s" : "", identStr(ident1, theOpt),
+ parmNum);
} else if (hitVPS) {
biffAddf(HEST,
- "%s: hit \"-%c\" (variable-parameter-stop flag) before getting %u "
+ "%s%shit \"-%c\" (variable-parameter-stop flag) before getting %u "
"parameter%s for %s (got %u)",
- __func__, VAR_PARM_STOP_FLAG, theOpt->min, theOpt->min > 1 ? "s" : "",
+ _ME_, VAR_PARM_STOP_FLAG, theOpt->min, theOpt->min > 1 ? "s" : "",
identStr(ident1, theOpt), parmNum);
} else if (UINT_MAX != nextOptIdx) {
- biffAddf(HEST, "%s: saw %s before getting %u parameter%s for %s (got %d)",
- __func__, identStr(ident2, opt + nextOptIdx), theOpt->min,
+ biffAddf(HEST, "%s%ssaw %s before getting %u parameter%s for %s (got %d)", _ME_,
+ identStr(ident2, opt + nextOptIdx), theOpt->min,
theOpt->min > 1 ? "s" : "", identStr(ident1, theOpt), parmNum);
} else {
biffAddf(HEST,
- "%s: sorry, confused about not getting %u "
+ "%s%ssorry, confused about not getting %u "
"parameter%s for %s (got %d)",
- __func__, theOpt->min, theOpt->min > 1 ? "s" : "",
- identStr(ident1, theOpt), parmNum);
+ _ME_, theOpt->min, theOpt->min > 1 ? "s" : "", identStr(ident1, theOpt),
+ parmNum);
}
return 1;
}
@@ -850,8 +849,8 @@
sprintf(info, "main havec after losing argIdx %u", argIdx);
hestArgVecPrint(__func__, info, havec);
}
- if (havecTransfer(theOpt->havec, havec, argIdx, parmNum)) {
- biffAddf(HEST, "%s: trouble transferring %u args for %s", __func__, parmNum,
+ if (havecTransfer(theOpt->havec, havec, argIdx, parmNum, hparm)) {
+ biffAddf(HEST, "%s%strouble transferring %u args for %s", _ME_, parmNum,
identStr(ident1, theOpt));
return 1;
}
@@ -884,7 +883,7 @@
}
// if needs to be set but hasn't been
if (needing && hestSourceUnknown == theOpt->source) {
- biffAddf(HEST, "%s: didn't get required %s", __func__, identStr(ident1, theOpt));
+ biffAddf(HEST, "%s%sdidn't get required %s", _ME_, identStr(ident1, theOpt));
return 1;
}
}
@@ -958,8 +957,9 @@
if (hparm->verbosity) {
printf("%s: looking at opi = %u kind %d\n", __func__, opi, opt[opi].kind);
}
- if (havecTransfer(opt[opi].havec, havec, 0, opt[opi].min /* min == max */)) {
- biffAddf(HEST, "%s: trouble getting args for %s", __func__,
+ opt[opi].source = havec->harg[0]->source;
+ if (havecTransfer(opt[opi].havec, havec, 0, opt[opi].min /* min == max */, hparm)) {
+ biffAddf(HEST, "%s%strouble getting args for %s", _ME_,
identStr(ident, opt + opi));
return 1;
}
@@ -976,9 +976,9 @@
uint opi = nextUnflagged(unflagVar + 1, opt);
uint np = opt[opi].min;
biffAddf(HEST,
- "%s: remaining %u args not enough for the %u parameter%s "
+ "%s%sremaining %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));
+ _ME_, havec->len, np, np > 1 ? "s" : "", identStr(ident, opt + opi));
return 1;
}
/* else we had enough args for all the unflagged options following
@@ -986,8 +986,9 @@
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__,
+ if (havecTransfer(opt[opi].havec, havec, nvp, opt[opi].min /* min == max */,
+ hparm)) {
+ biffAddf(HEST, "%s%strouble getting args for %s", _ME_,
identStr(ident, opt + opi));
return 1;
}
@@ -1010,13 +1011,13 @@
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__,
+ biffAddf(HEST, "%s%sdidn't get minimum of %d arg%s for %s (got %d)", _ME_,
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__,
+ if (havecTransfer(opt[unflagVar].havec, havec, 0, nvp, hparm)) {
+ biffAddf(HEST, "%s%strouble getting args for %s", _ME_,
identStr(ident, opt + unflagVar));
return 1;
}
@@ -1031,9 +1032,9 @@
}
if (havec->len) {
biffAddf(HEST,
- "%s: after handling %u unflagged opts, still have unexpected %u args "
+ "%s%safter handling %u unflagged opts, still have unexpected %u args "
"left in (starting with \"%s\")",
- __func__, unflagNum, havec->len, havec->harg[0]->str);
+ _ME_, unflagNum, havec->len, havec->harg[0]->str);
return 1;
}
return 0;
@@ -1077,11 +1078,12 @@
// error string song and dance
#define DO_ERR(WUT) \
+ biffAddf(HEST, "%s%s" WUT, _MEV_(HPARM->verbosity)); \
char *err = biffGetDone(HEST); \
if (errP) { \
*errP = err; \
} else { \
- fprintf(stderr, "%s: " WUT ":\n%s", __func__, err); \
+ fprintf(stderr, "%s: problem:\n%s", __func__, err); \
free(err); \
}
@@ -1125,6 +1127,7 @@
// --2--2--2--2--2-- extract args associated with flagged and unflagged opt
if (havecExtractFlagged(opt, havec, HPARM)
+ // this will detect extraneous args after unflaggeds are extracted
|| havecExtractUnflagged(opt, havec, HPARM)) {
DO_ERR("problem extracting args for options");
airMopError(mop);
Modified: teem/trunk/src/hest/privateHest.h
===================================================================
--- teem/trunk/src/hest/privateHest.h 2025-09-24 06:38:03 UTC (rev 7481)
+++ teem/trunk/src/hest/privateHest.h 2025-09-24 08:24:08 UTC (rev 7482)
@@ -79,6 +79,20 @@
extern int _hestMax(int max);
extern int _hestOPCheck(const hestOpt *opt, const hestParm *parm);
+/* wacky hack to use with biffAddf(HEST), so that normal hest users, who haven't
+ cranked up hestParm->verbosity to debug hest itself and don't want error messages
+ prefixed by a lot of weird hest function names:
+ In a function where hestParm *hparm is defined, the biff call should look like:
+ biffAddf(HEST, "%s%sthis is the error", _ME_, ... )
+ Note the "%s%s" start, with NO following space.
+ Or if its not hparm but some other source `verb` of a verbosity level
+ biffAddf(HEST, "%s%sthis is the error", _MEV_(verb), ... )
+ */
+#define _ME_ \
+ ((hparm) && (hparm)->verbosity ? __func__ : ""), \
+ ((hparm) && (hparm)->verbosity ? ": " : "")
+#define _MEV_(V) ((V) ? __func__ : ""), ((V) ? ": " : "")
+
#ifdef __cplusplus
}
#endif
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-24 06:38:03 UTC (rev 7481)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-24 08:24:08 UTC (rev 7482)
@@ -34,7 +34,7 @@
hestParm *hparm = hestParmNew();
hparm->respectDashDashHelp = AIR_TRUE;
hparm->responseFileEnable = AIR_TRUE;
- hparm->verbosity = 3;
+ hparm->verbosity = 1;
int verb;
hestOptAdd_1_Int(&opt, "v", "verb", &verb, "0", "verbosity");
@@ -44,8 +44,9 @@
unsigned int slen;
hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 2, -1, &res, "640 480",
"image resolutions", &slen);
- int unpB[2];
- hestOptAdd_2_Int(&opt, NULL, "B B", unpB, NULL, "unflagged B");
+ int *unpB;
+ unsigned int sawB;
+ hestOptAdd_Nv_Int(&opt, NULL, "B B", 1, -1, &unpB, NULL, "unflagged B", &sawB);
int flag;
hestOptAdd_Flag(&opt, "b,bingo", &flag, "a flag");
int glaf;
@@ -52,6 +53,11 @@
hestOptAdd_Flag(&opt, "c,cingo", &glaf, "a flag");
int unpC[2];
hestOptAdd_2_Int(&opt, NULL, "C C", unpC, NULL, "unflagged C");
+ /*
+ int *unpC;
+ unsigned int sawC;
+ hestOptAdd_Nv_Int(&opt, NULL, "C C", 1, 2, &unpC, NULL, "unflagged C", &sawC);
+ */
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.
|
|
From: <kin...@us...> - 2025-09-24 06:38:05
|
Revision: 7481
http://sourceforge.net/p/teem/code/7481
Author: kindlmann
Date: 2025-09-24 06:38:03 +0000 (Wed, 24 Sep 2025)
Log Message:
-----------
fewer bugs
Modified Paths:
--------------
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/test/tparse.c
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-24 06:06:44 UTC (rev 7480)
+++ teem/trunk/src/hest/parsest.c 2025-09-24 06:38:03 UTC (rev 7481)
@@ -697,9 +697,9 @@
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);
+ if (!(srcIdx + num <= hvsrc->len)) {
+ biffAddf(HEST, "%s: have only %u args but want %u starting at %u", __func__,
+ hvsrc->len, num, srcIdx);
return 1;
}
// okay now do the work, starting with empty destination
@@ -947,7 +947,9 @@
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);
+ printf("%s: unflagVar %u %s\n", __func__, unflagVar,
+ (unflagVar == optNum ? "==> there is no unflagged var parm opt"
+ : "is index of single unflagged var parm opt"));
}
/* grab parameters for all unflagged opts before opt[unflagVar] */
@@ -954,11 +956,12 @@
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);
+ printf("%s: looking at opi = %u kind %d\n", __func__, opi, opt[opi].kind);
}
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));
+ return 1;
}
}
/* we skip over the variable parameter unflagged option, subtract from havec->len the
@@ -986,6 +989,7 @@
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));
+ return 1;
}
}
@@ -1014,6 +1018,7 @@
if (havecTransfer(opt[unflagVar].havec, havec, 0, nvp)) {
biffAddf(HEST, "%s: trouble getting args for %s", __func__,
identStr(ident, opt + unflagVar));
+ return 1;
}
}
} else {
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-24 06:06:44 UTC (rev 7480)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-24 06:38:03 UTC (rev 7481)
@@ -39,13 +39,19 @@
int verb;
hestOptAdd_1_Int(&opt, "v", "verb", &verb, "0", "verbosity");
int *res;
+ int unpA[2];
+ hestOptAdd_2_Int(&opt, NULL, "A A", unpA, NULL, "unflagged A");
unsigned int slen;
- hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 2, -1, &res, NULL, "image resolutions",
- &slen);
+ hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 2, -1, &res, "640 480",
+ "image resolutions", &slen);
+ int unpB[2];
+ hestOptAdd_2_Int(&opt, NULL, "B B", unpB, NULL, "unflagged B");
int flag;
hestOptAdd_Flag(&opt, "b,bingo", &flag, "a flag");
int glaf;
hestOptAdd_Flag(&opt, "c,cingo", &glaf, "a flag");
+ int unpC[2];
+ hestOptAdd_2_Int(&opt, NULL, "C C", unpC, NULL, "unflagged C");
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.
|
|
From: <kin...@us...> - 2025-09-24 06:06:47
|
Revision: 7480
http://sourceforge.net/p/teem/code/7480
Author: kindlmann
Date: 2025-09-24 06:06:44 +0000 (Wed, 24 Sep 2025)
Log Message:
-----------
bug fix
Modified Paths:
--------------
teem/trunk/src/hest/parsest.c
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-24 05:55:55 UTC (rev 7479)
+++ teem/trunk/src/hest/parsest.c 2025-09-24 06:06:44 UTC (rev 7480)
@@ -765,10 +765,11 @@
uint optIdx = whichOptFlag(opt, havec->harg[argIdx]->str, hparm);
if (UINT_MAX == optIdx) {
// havec->harg[argIdx]->str is not a flag for any option, move on to next arg
- argIdx++;
- if (hparm->verbosity)
+ if (hparm->verbosity) {
printf("%s: |%s| not a flag arg, continue\n", __func__,
havec->harg[argIdx]->str);
+ }
+ argIdx++;
continue;
}
// else havec->harg[argIdx]->str is a flag for option with index optIdx aka theOpt
@@ -1028,6 +1029,7 @@
"%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 1;
}
return 0;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
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.
|
|
From: <kin...@us...> - 2025-09-23 14:27:48
|
Revision: 7478
http://sourceforge.net/p/teem/code/7478
Author: kindlmann
Date: 2025-09-23 14:27:45 +0000 (Tue, 23 Sep 2025)
Log Message:
-----------
removing bad idea
Modified Paths:
--------------
teem/trunk/src/hest/parsest.c
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-23 14:21:24 UTC (rev 7477)
+++ teem/trunk/src/hest/parsest.c 2025-09-23 14:27:45 UTC (rev 7478)
@@ -735,7 +735,7 @@
if (hparm->verbosity) printf("%s: any associated parms?\n", __func__);
int hitEnd = AIR_FALSE;
int varParm = (5 == opt[optIdx].kind);
- const char *pas, VPS[3] = {'-', VAR_PARM_STOP_FLAG, '\0'};
+ const char VPS[3] = {'-', VAR_PARM_STOP_FLAG, '\0'};
int hitVPS = AIR_FALSE;
uint nextOptIdx = 0, // what is index of option who's flag we hit next
parmNum = 0, // how many parm args have we counted up
@@ -746,12 +746,12 @@
&& !(hitEnd = !((pai = argIdx + 1 + parmNum) < havec->len))
// and either this isn't a variable parm opt
&& (!varParm || // or, it is a varparm opt, and we aren't looking at "--"
- !(hitVPS = !strcmp(VPS, (pas = havec->harg[pai]->str))))
+ !(hitVPS = !strcmp(VPS, havec->harg[pai]->str)))
&& UINT_MAX // and we aren't looking at start of another flagged option
- == (nextOptIdx = whichOptFlag(opt, pas, hparm))) {
+ == (nextOptIdx = whichOptFlag(opt, havec->harg[pai]->str, hparm))) {
if (hparm->verbosity)
printf("%s: optIdx %d |%s|; argIdx %u < %u |%s| --> parmNum --> %d\n", __func__,
- optIdx, theOpt->flag, argIdx, pai, pas, parmNum + 1);
+ optIdx, theOpt->flag, argIdx, pai, havec->harg[pai]->str, parmNum + 1);
parmNum++;
}
/* we stopped because we got the max number of parameters, or
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-23 14:21:28
|
Revision: 7477
http://sourceforge.net/p/teem/code/7477
Author: kindlmann
Date: 2025-09-23 14:21:24 +0000 (Tue, 23 Sep 2025)
Log Message:
-----------
changing hestArgVec from array of hestArg structs to array of pointers to hestArg structs
Modified Paths:
--------------
teem/trunk/src/hest/argvHest.c
teem/trunk/src/hest/hest.h
teem/trunk/src/hest/parsest.c
Modified: teem/trunk/src/hest/argvHest.c
===================================================================
--- teem/trunk/src/hest/argvHest.c 2025-09-23 11:04:43 UTC (rev 7476)
+++ teem/trunk/src/hest/argvHest.c 2025-09-23 14:21:24 UTC (rev 7477)
@@ -22,14 +22,6 @@
#define INCR 32
-/* to avoid strict aliasing warnings */
-typedef union {
- hestArg **harg;
- hestArgVec **havec;
- hestInput **hin;
- void **v;
-} hestPtrPtrUnion;
-
/* -------------------------- hestArg = harg = hestArg = harg ---------------------- */
/* dereferences as char *, sets to '\0' */
@@ -40,46 +32,45 @@
return;
}
-static void
-hargInit(void *_harg) {
- hestArg *harg = (hestArg *)_harg;
+hestArg *
+hestArgNew(void) {
+ hestArg *harg = AIR_CALLOC(1, hestArg);
+ assert(harg);
harg->str = NULL;
harg->len = 0;
airPtrPtrUnion appu;
appu.c = &(harg->str);
harg->strArr = airArrayNew(appu.v, &(harg->len), sizeof(char), INCR);
+ // underlying array harg->str will not be reallocated if shrunk
+ harg->strArr->noReallocWhenSmaller = AIR_TRUE;
airArrayStructCB(harg->strArr, setNul, NULL);
harg->source = hestSourceUnknown;
/* initialize with \0 so that harg->str is "" */
airArrayLenIncr(harg->strArr, 1);
/* now harg->str = {0:'\0'} and harg->len = 1; */
- return;
-}
-
-hestArg *
-hestArgNew(void) {
- hestArg *harg = AIR_CALLOC(1, hestArg);
- assert(harg);
- hargInit(harg);
return harg;
}
-static void
-hargDone(void *_harg) {
- hestArg *harg = (hestArg *)_harg;
- airArrayNuke(harg->strArr);
- return;
+static void *
+_hestArgNew_vp(void) {
+ return AIR_VOIDP(hestArgNew());
}
hestArg *
hestArgNix(hestArg *harg) {
if (harg) {
- hargDone(harg);
+ airArrayNuke(harg->strArr);
free(harg);
}
return NULL;
}
+static void *
+_hestArgNix_vp(void *_harg) {
+ hestArg *harg = (hestArg *)_harg;
+ return AIR_VOIDP(hestArgNix(harg));
+}
+
void
hestArgReset(hestArg *harg) {
assert(harg);
@@ -112,6 +103,15 @@
/* ---------------------- hestArgVec = havec = hestArgVec = havec ------------------ */
+/* to avoid strict aliasing warnings */
+typedef union {
+ hestArg **harg;
+ hestArg ***hargP;
+ hestArgVec **havec;
+ hestInput **hin;
+ void **v;
+} hestPtrPtrUnion;
+
hestArgVec *
hestArgVecNew() {
hestArgVec *havec = AIR_CALLOC(1, hestArgVec);
@@ -119,11 +119,12 @@
havec->harg = NULL;
havec->len = 0;
hestPtrPtrUnion hppu;
- hppu.harg = &(havec->harg);
- havec->hargArr = airArrayNew(hppu.v, &(havec->len), sizeof(hestArg), INCR);
+ hppu.hargP = &(havec->harg);
+ havec->hargArr = airArrayNew(hppu.v, &(havec->len), sizeof(hestArg *), INCR);
// underlying array havec->harg will not be reallocated if shrunk
havec->hargArr->noReallocWhenSmaller = AIR_TRUE;
- airArrayStructCB(havec->hargArr, hargInit, hargDone);
+ // airArrayStructCB(havec->hargArr, hargInit, hargDone);
+ airArrayPointerCB(havec->hargArr, _hestArgNew_vp, _hestArgNix_vp);
return havec;
}
@@ -144,17 +145,17 @@
return NULL;
}
-void
+hestArg *
hestArgVecRemove(hestArgVec *havec, uint popIdx) {
- // (experimented with allocating something to hold what was lost)
- // hestArg *ret = NULL;
+ hestArg *ret = NULL;
if (havec && popIdx < havec->len) { // note: this implies that havec->len >= 1
- // ret = AIR_CALLOC(1, hestArg); // (we don't have a constructor?)
- // memcpy(ret, havec->harg + popIdx);
- for (uint ai = popIdx; ai < havec->len - 1; ai++) {
+ ret = havec->harg[popIdx];
+ uint ai;
+ for (ai = popIdx; ai < havec->len - 1; ai++) {
// shuffle down info inside the hestArg elements of havec->harg
- hestArgSetString(havec->harg + ai, (havec->harg + ai + 1)->str);
- (havec->harg + ai)->source = (havec->harg + ai + 1)->source;
+ havec->harg[ai] = havec->harg[ai + 1];
+ // hestArgSetString(havec->harg + ai, (havec->harg + ai + 1)->str);
+ // (havec->harg + ai)->source = (havec->harg + ai + 1)->source;
/* why cannot just memcpy:
because then the last hestArg element of havec->harg
(the one that is being forgotten)
@@ -164,29 +165,46 @@
as the callack from airArrayLenIncr(), then it will also
free the str inside the second-to-last element; oops */
}
+ // NULL out final out, using final value of ai
+ havec->harg[ai] = NULL;
// decrement the nominal length of havec->harg
airArrayLenIncr(havec->hargArr, -1);
}
- return;
+ return ret;
}
void
hestArgVecAppendString(hestArgVec *havec, const char *str) {
uint idx = airArrayLenIncr(havec->hargArr, 1);
- hestArgSetString(havec->harg + idx, str);
+ hestArgSetString(havec->harg[idx], str);
}
void
+hestArgVecAppendArg(hestArgVec *havec, hestArg *harg) {
+ uint idx = airArrayLenIncr(havec->hargArr, 1);
+ // oops, delete the hestArg just created via callback
+ hestArgNix(havec->harg[idx]);
+ havec->harg[idx] = harg;
+}
+
+void
hestArgVecPrint(const char *caller, const char *info, const hestArgVec *havec) {
// fprintf(stderr, "!%s: %s hestArgVec %p has %u args:\n", caller, info, havec,
// havec->len);
+ char srcch[] = {
+ // quick way of identifying source
+ '?', // 0: hestSourceUnknown
+ 'c', // 1: hestSourceCommandLine
+ 'r', // 2: hestSourceResponseFile
+ 'd', // 3: hestSourceDefault
+ };
printf("%s: %s hestArgVec %p has %u args:\n", caller, info, havec, havec->len);
for (uint idx = 0; idx < havec->hargArr->len; idx++) {
const hestArg *harg;
- harg = havec->harg + idx;
+ harg = havec->harg[idx];
// fprintf(stderr, "!%s harg@%p=%u:<%s>\n", "", AIR_VOIDP(harg), idx,
// harg->str ? harg->str : "NULL");
- printf(" %u:<%s>", idx, 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 11:04:43 UTC (rev 7476)
+++ teem/trunk/src/hest/hest.h 2025-09-23 14:21:24 UTC (rev 7477)
@@ -121,7 +121,7 @@
// hestArgVec: for building up a "vector" of arguments
typedef struct {
- hestArg *harg; // array of hestArg structs (not pointers to them)
+ hestArg **harg; // array of pointers to hestArg structs
unsigned int len; // number of arguments in this vector
airArray *hargArr; // (manages harg and len)
} hestArgVec;
@@ -231,7 +231,7 @@
array of strings
3: free((*valueP)[i]) and free(*valueP), because it is a dynamically
allocated array of strings */
- hestArgVec *havec; // the args attributed to this option
+ hestArgVec *havec; // the (non-flag) parm args attributed to this option
/* Since hest's beginning in 2002, the basic container for a set of options was an
array of hestOpt structs (not pointers to them, which rules out argv-style
NULL-termination of the array), also unfortunately with no other top-level container
@@ -343,8 +343,9 @@
HEST_EXPORT hestArgVec *hestArgVecNew(void);
HEST_EXPORT void hestArgVecReset(hestArgVec *havec);
HEST_EXPORT hestArgVec *hestArgVecNix(hestArgVec *havec);
-HEST_EXPORT void hestArgVecRemove(hestArgVec *havec, unsigned int popIdx);
+HEST_EXPORT hestArg *hestArgVecRemove(hestArgVec *havec, unsigned int popIdx);
HEST_EXPORT void hestArgVecAppendString(hestArgVec *havec, const char *str);
+HEST_EXPORT void hestArgVecAppendArg(hestArgVec *havec, hestArg *harg);
HEST_EXPORT void hestArgVecPrint(const char *caller, const char *info,
const hestArgVec *havec);
HEST_EXPORT hestInput *hestInputNew(void);
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-23 11:04:43 UTC (rev 7476)
+++ teem/trunk/src/hest/parsest.c 2025-09-23 14:21:24 UTC (rev 7477)
@@ -607,7 +607,7 @@
srcstr, tharg->str, havec->len);
}
// set source in the hestArg we just appended
- (havec->harg + havec->len - 1)->source = topHin->source;
+ havec->harg[havec->len - 1]->source = topHin->source;
}
if (hist->len && nast == nastEmpty) {
biffAddf(HEST, "%s: non-empty stack (depth %u) can't generate args???", __func__,
@@ -713,44 +713,46 @@
uint argIdx = 0;
hestOpt *theOpt = NULL;
while (argIdx < havec->len) { // NOTE: havec->len may decrease within an interation!
- hestArg *theArg = havec->harg + argIdx;
if (hparm->verbosity) {
printf("%s: ------------- argIdx = %u (of %u) -> argv[argIdx] = |%s|\n", __func__,
- argIdx, havec->len, theArg->str);
+ argIdx, havec->len, havec->harg[argIdx]->str);
}
- uint optIdx = whichOptFlag(opt, theArg->str, hparm);
+ uint optIdx = whichOptFlag(opt, havec->harg[argIdx]->str, hparm);
if (UINT_MAX == optIdx) {
- // theArg->str is not a flag for any option, move on to next arg
+ // havec->harg[argIdx]->str is not a flag for any option, move on to next arg
argIdx++;
if (hparm->verbosity)
- printf("%s: |%s| not a flag arg, continue\n", __func__, theArg->str);
+ printf("%s: |%s| not a flag arg, continue\n", __func__,
+ havec->harg[argIdx]->str);
continue;
}
- // else theArg->str is a flag for option with index optIdx aka theOpt
+ // else havec->harg[argIdx]->str is a flag for option with index optIdx aka theOpt
theOpt = opt + optIdx;
if (hparm->verbosity)
printf("%s: argv[%u]=|%s| is flag of opt %u \"%s\"\n", __func__, argIdx,
- theArg->str, optIdx, theOpt->flag);
+ havec->harg[argIdx]->str, optIdx, theOpt->flag);
/* see if we can associate some parameters with the flag */
if (hparm->verbosity) printf("%s: any associated parms?\n", __func__);
- uint parmNum = 0;
int hitEnd = AIR_FALSE;
int varParm = (5 == opt[optIdx].kind);
- char VPS[3] = {'-', VAR_PARM_STOP_FLAG, '\0'};
+ const char *pas, VPS[3] = {'-', VAR_PARM_STOP_FLAG, '\0'};
int hitVPS = AIR_FALSE;
- uint nextOptIdx = 0; // what is index of option who's flag we see next
- while (AIR_INT(parmNum) < _hestMax(theOpt->max) // parmNum is plausible # parms
- && !(hitEnd = !(argIdx + 1 + parmNum < havec->len)) // and have valid index
- && (!varParm // and either this isn't a variable parm opt
- || // or, it is a varparm opt and we aren't looking at "--"
- !(hitVPS = !strcmp(VPS, (theArg + 1 + parmNum)->str)))
- && UINT_MAX // and we aren't looking at start of another flagged option
- == (nextOptIdx = whichOptFlag(opt, (theArg + 1 + parmNum)->str,
- hparm))) {
+ uint nextOptIdx = 0, // what is index of option who's flag we hit next
+ parmNum = 0, // how many parm args have we counted up
+ pai; // tmp parm arg index
+ while ( // parmNum is plausible # parms
+ AIR_INT(parmNum) < _hestMax(theOpt->max)
+ // and looking ahead by parmNum still gives us a valid index pai
+ && !(hitEnd = !((pai = argIdx + 1 + parmNum) < havec->len))
+ // and either this isn't a variable parm opt
+ && (!varParm || // or, it is a varparm opt, and we aren't looking at "--"
+ !(hitVPS = !strcmp(VPS, (pas = havec->harg[pai]->str))))
+ && UINT_MAX // and we aren't looking at start of another flagged option
+ == (nextOptIdx = whichOptFlag(opt, pas, hparm))) {
+ if (hparm->verbosity)
+ printf("%s: optIdx %d |%s|; argIdx %u < %u |%s| --> parmNum --> %d\n", __func__,
+ optIdx, theOpt->flag, argIdx, pai, pas, parmNum + 1);
parmNum++;
- if (hparm->verbosity)
- printf("%s: optIdx %d |%s|: |%s| --> parmNum --> %d\n", __func__, optIdx,
- theOpt->flag, (theArg + 1 + parmNum - 1)->str, parmNum);
}
/* we stopped because we got the max number of parameters, or
we hitEnd, or
@@ -788,15 +790,15 @@
}
if (hparm->verbosity) {
printf("%s: ________ argv[%d]=|%s|: optIdx %u |%s| followed by %u parms\n",
- __func__, argIdx, theArg->str, optIdx, theOpt->flag, parmNum);
+ __func__, argIdx, havec->harg[argIdx]->str, optIdx, theOpt->flag, parmNum);
}
// remember from whence this option came
- theOpt->source = theArg->source;
+ theOpt->source = havec->harg[argIdx]->source;
// lose the flag argument
if (hparm->verbosity > 1) {
hestArgVecPrint(__func__, "main havec as it came", havec);
}
- hestArgVecRemove(havec, argIdx);
+ hestArgNix(hestArgVecRemove(havec, argIdx));
if (hparm->verbosity > 1) {
char info[AIR_STRLEN_HUGE + 1];
sprintf(info, "main havec after losing argIdx %u", argIdx);
@@ -805,16 +807,14 @@
// empty any prior parm args learned for this option
hestArgVecReset(theOpt->havec);
for (uint pidx = 0; pidx < parmNum; pidx++) {
- // theArg still points to the next arg (at index argIdx) for this option
if (hparm->verbosity) {
- printf("%s: moving |%s| to theOpt->havec\n", __func__, theArg->str);
+ printf("%s: moving |%s| to theOpt->havec\n", __func__, havec->harg[argIdx]->str);
}
- hestArgVecAppendString(theOpt->havec, theArg->str);
- hestArgVecRemove(havec, argIdx);
+ hestArgVecAppendArg(theOpt->havec, hestArgVecRemove(havec, argIdx));
}
if (hitVPS) {
// drop the variable-parameter-stop flag
- hestArgVecRemove(havec, argIdx);
+ hestArgNix(hestArgVecRemove(havec, argIdx));
}
if (hparm->verbosity) {
char info[AIR_STRLEN_HUGE + 1];
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-23 11:04:46
|
Revision: 7476
http://sourceforge.net/p/teem/code/7476
Author: kindlmann
Date: 2025-09-23 11:04:43 +0000 (Tue, 23 Sep 2025)
Log Message:
-----------
better comments
Modified Paths:
--------------
teem/trunk/src/hest/privateHest.h
Modified: teem/trunk/src/hest/privateHest.h
===================================================================
--- teem/trunk/src/hest/privateHest.h 2025-09-23 10:59:06 UTC (rev 7475)
+++ teem/trunk/src/hest/privateHest.h 2025-09-23 11:04:43 UTC (rev 7476)
@@ -51,8 +51,8 @@
// multiFlagSep; /* character in flag which signifies that there is a long and
// short version, and which separates the two. Or, can be set
// to '\0' to disable this behavior entirely. */
-// However, there is more confusion than utility created by allowing these
-// change. The actual value in giving these things names was in code legibility by
+// However, there is more confusion than utility created by allowing these to be
+// changed. The actual value in giving these things names was in code legibility by
// removing magic constants, so that's the role of these #define's now.
#define RESPONSE_FILE_FLAG '@'
#define RESPONSE_FILE_COMMENT '#'
@@ -65,8 +65,8 @@
/* methodsHest.c */
/*
- * These were moved not just from air.h but also from public hest.h, with a
- * air --> _hest renaming, since these are only used to implement hest functions.
+ * These were moved not just from air.h (see note there) but also from public hest.h,
+ * with a air --> _hest renaming, since these are only used to implement hest functions.
*/
#define _HEST_TYPE_MAX 14
HEST_EXPORT const char _hestTypeStr[_HEST_TYPE_MAX + 1][AIR_STRLEN_SMALL + 1];
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-23 10:59:10
|
Revision: 7475
http://sourceforge.net/p/teem/code/7475
Author: kindlmann
Date: 2025-09-23 10:59:06 +0000 (Tue, 23 Sep 2025)
Log Message:
-----------
more consistent use of newline
Modified Paths:
--------------
teem/trunk/src/hest/parseHest.c
Modified: teem/trunk/src/hest/parseHest.c
===================================================================
--- teem/trunk/src/hest/parseHest.c 2025-09-23 10:49:03 UTC (rev 7474)
+++ teem/trunk/src/hest/parseHest.c 2025-09-23 10:59:06 UTC (rev 7475)
@@ -69,7 +69,7 @@
again by copyArgv */
if (!(file = fopen(argv[argIdx] + 1, "rb"))) {
/* can't open the indicated response file for reading */
- fprintf(stderr, "%scouldn't open \"%s\" for reading as response file", ME,
+ fprintf(stderr, "%scouldn't open \"%s\" for reading as response file\n", ME,
argv[argIdx] + 1);
*argsNumP = 0;
*respFileNumP = 0;
@@ -226,8 +226,7 @@
}
/* uint _hestErrStrlen(const hestOpt *opt, int argc, const char **argv) ...
- * This was a bad idea, so has been removed for TeemV2. Now hest internally uses biff
- */
+ * This was a bad idea; removed for TeemV2. Now hest internally uses biff */
/*
identStr()
@@ -1353,7 +1352,7 @@
}
/* else !sawHelp; do sanity check on argc_used vs argc */
if (argc_used < argc) {
- fprintf(stderr, "%sargc_used %d < argc %d; sorry, confused", ME, argc_used, argc);
+ fprintf(stderr, "%sargc_used %d < argc %d; sorry, confused\n", ME, argc_used, argc);
airMopError(mop);
return 1;
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-23 10:49:07
|
Revision: 7474
http://sourceforge.net/p/teem/code/7474
Author: kindlmann
Date: 2025-09-23 10:49:03 +0000 (Tue, 23 Sep 2025)
Log Message:
-----------
now with clang-format
Modified Paths:
--------------
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/test/tparse.c
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-23 10:48:04 UTC (rev 7473)
+++ teem/trunk/src/hest/parsest.c 2025-09-23 10:49:03 UTC (rev 7474)
@@ -831,12 +831,12 @@
uint optNum = opt->arrLen;
for (uint opi = 0; opi < optNum; opi++) {
theOpt = opt + opi;
- if (theOpt->flag) { // this is a flagged option we should have handled above
- int needing = (1 != theOpt->kind // this kind of option can take a parm
+ if (theOpt->flag) { // this is a flagged option we should have handled above
+ int needing = (1 != theOpt->kind // this kind of option can take a parm
&& !(theOpt->dflt)); // and this option has no default
if (hparm->verbosity > 1) {
- printf("%s: flagged opt %u |%s| source = %s%s\n",
- __func__, opi, theOpt->flag, airEnumStr(hestSource, theOpt->source),
+ printf("%s: flagged opt %u |%s| source = %s%s\n", __func__, opi, theOpt->flag,
+ airEnumStr(hestSource, theOpt->source),
needing ? " <-- w/ parm but w/out default" : "");
}
// if needs to be set but hasn't been
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-23 10:48:04 UTC (rev 7473)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-23 10:49:03 UTC (rev 7474)
@@ -38,8 +38,10 @@
int verb;
hestOptAdd_1_Int(&opt, "v", "verb", &verb, "0", "verbosity");
- int *res; unsigned int slen;
- hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 2, -1, &res, NULL, "image resolutions", &slen);
+ int *res;
+ unsigned int slen;
+ hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 2, -1, &res, NULL, "image resolutions",
+ &slen);
int flag;
hestOptAdd_Flag(&opt, "b,bingo", &flag, "a flag");
char *err = NULL;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-23 10:48:07
|
Revision: 7473
http://sourceforge.net/p/teem/code/7473
Author: kindlmann
Date: 2025-09-23 10:48:04 +0000 (Tue, 23 Sep 2025)
Log Message:
-----------
fewer bugs
Modified Paths:
--------------
teem/trunk/src/hest/methodsHest.c
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/test/tparse.c
Modified: teem/trunk/src/hest/methodsHest.c
===================================================================
--- teem/trunk/src/hest/methodsHest.c 2025-09-23 10:27:36 UTC (rev 7472)
+++ teem/trunk/src/hest/methodsHest.c 2025-09-23 10:48:04 UTC (rev 7473)
@@ -367,7 +367,9 @@
opt->valueP = valueP;
opt->dflt = airStrdup(dflt);
opt->info = airStrdup(info);
- /* deal with (what used to be) var args */
+ // need to set kind now so can be used in later conditionals
+ opt->kind = opt_kind(min, max);
+ // deal with (what used to be) var args
opt->sawP = (5 == opt->kind /* */
? sawP
: NULL);
@@ -377,11 +379,10 @@
opt->CB = (airTypeOther == type /* */
? CB
: NULL);
- opt->kind = opt_kind(min, max);
- /* alloc set by hestParse */
+ // alloc set by hestParse
opt->havec = hestArgVecNew();
- /* leave arrAlloc, arrLen untouched: managed by caller */
- /* yes, redundant with opt_init() */
+ // leave arrAlloc, arrLen untouched: managed by caller
+ // yes, redundant with opt_init()
opt->source = hestSourceUnknown;
opt->parmStr = NULL;
opt->helpWanted = AIR_FALSE;
@@ -541,9 +542,9 @@
}
if (5 == opt[opi].kind && !(opt[opi].sawP)) {
biffAddf(HEST,
- "%s: have multiple variable parameters, "
+ "%s: opt[%u] has multiple variable parameters (min=%u,max=%d), "
"but sawP is NULL",
- __func__);
+ __func__, opi, opt[opi].min, opt[opi].max);
return 1;
}
if (airTypeEnum == opt[opi].type) {
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-23 10:27:36 UTC (rev 7472)
+++ teem/trunk/src/hest/parsest.c 2025-09-23 10:48:04 UTC (rev 7473)
@@ -831,14 +831,16 @@
uint optNum = opt->arrLen;
for (uint opi = 0; opi < optNum; opi++) {
theOpt = opt + opi;
- if (1 != theOpt->kind // this kind of option can take a parm
- && theOpt->flag // and this is a flagged option we should have handled above
- && !(theOpt->dflt)) { // and this option has no default
+ if (theOpt->flag) { // this is a flagged option we should have handled above
+ int needing = (1 != theOpt->kind // this kind of option can take a parm
+ && !(theOpt->dflt)); // and this option has no default
if (hparm->verbosity > 1) {
- printf("%s: opt %u |%s| (flagged opt w/ parm but no default) source = %s\n",
- __func__, opi, theOpt->flag, airEnumStr(hestSource, theOpt->source));
+ printf("%s: flagged opt %u |%s| source = %s%s\n",
+ __func__, opi, theOpt->flag, airEnumStr(hestSource, theOpt->source),
+ needing ? " <-- w/ parm but w/out default" : "");
}
- if (hestSourceUnknown == theOpt->source) { // but this option hasn't been set
+ // 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));
return 1;
@@ -845,7 +847,6 @@
}
}
}
-
return 0;
}
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-23 10:27:36 UTC (rev 7472)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-23 10:48:04 UTC (rev 7473)
@@ -38,8 +38,8 @@
int verb;
hestOptAdd_1_Int(&opt, "v", "verb", &verb, "0", "verbosity");
- int res[2];
- hestOptAdd_2_Int(&opt, "s,size", "sx sy", res, NULL, "image resolution");
+ int *res; unsigned int slen;
+ hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 2, -1, &res, NULL, "image resolutions", &slen);
int flag;
hestOptAdd_Flag(&opt, "b,bingo", &flag, "a flag");
char *err = NULL;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-23 10:27:39
|
Revision: 7472
http://sourceforge.net/p/teem/code/7472
Author: kindlmann
Date: 2025-09-23 10:27:36 +0000 (Tue, 23 Sep 2025)
Log Message:
-----------
now with clang-format
Modified Paths:
--------------
teem/trunk/src/hest/argvHest.c
teem/trunk/src/hest/parsest.c
Modified: teem/trunk/src/hest/argvHest.c
===================================================================
--- teem/trunk/src/hest/argvHest.c 2025-09-23 10:26:02 UTC (rev 7471)
+++ teem/trunk/src/hest/argvHest.c 2025-09-23 10:27:36 UTC (rev 7472)
@@ -178,7 +178,8 @@
void
hestArgVecPrint(const char *caller, const char *info, const hestArgVec *havec) {
- // fprintf(stderr, "!%s: %s hestArgVec %p has %u args:\n", caller, info, havec, havec->len);
+ // fprintf(stderr, "!%s: %s hestArgVec %p has %u args:\n", caller, info, havec,
+ // havec->len);
printf("%s: %s hestArgVec %p has %u args:\n", caller, info, havec, havec->len);
for (uint idx = 0; idx < havec->hargArr->len; idx++) {
const hestArg *harg;
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-23 10:26:02 UTC (rev 7471)
+++ teem/trunk/src/hest/parsest.c 2025-09-23 10:27:36 UTC (rev 7472)
@@ -833,15 +833,16 @@
theOpt = opt + opi;
if (1 != theOpt->kind // this kind of option can take a parm
&& theOpt->flag // and this is a flagged option we should have handled above
- && !(theOpt->dflt)) { // and this option has no default
- if (hparm->verbosity > 1) {
- printf("%s: opt %u |%s| (flagged opt w/ parm but no default) source = %s\n",
- __func__, opi, theOpt->flag, airEnumStr(hestSource, theOpt->source));
- }
- if (hestSourceUnknown == theOpt->source) { // but this option hasn't been set
- biffAddf(HEST, "%s: didn't get required %s\n", __func__, identStr(ident1, theOpt));
- return 1;
- }
+ && !(theOpt->dflt)) { // and this option has no default
+ if (hparm->verbosity > 1) {
+ printf("%s: opt %u |%s| (flagged opt w/ parm but no default) source = %s\n",
+ __func__, opi, theOpt->flag, airEnumStr(hestSource, theOpt->source));
+ }
+ if (hestSourceUnknown == theOpt->source) { // but this option hasn't been set
+ biffAddf(HEST, "%s: didn't get required %s\n", __func__,
+ identStr(ident1, theOpt));
+ return 1;
+ }
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-23 10:26:08
|
Revision: 7471
http://sourceforge.net/p/teem/code/7471
Author: kindlmann
Date: 2025-09-23 10:26:02 +0000 (Tue, 23 Sep 2025)
Log Message:
-----------
fewer memory errors
Modified Paths:
--------------
teem/trunk/src/hest/argvHest.c
teem/trunk/src/hest/methodsHest.c
teem/trunk/src/hest/parsest.c
Modified: teem/trunk/src/hest/argvHest.c
===================================================================
--- teem/trunk/src/hest/argvHest.c 2025-09-23 08:36:57 UTC (rev 7470)
+++ teem/trunk/src/hest/argvHest.c 2025-09-23 10:26:02 UTC (rev 7471)
@@ -67,12 +67,7 @@
static void
hargDone(void *_harg) {
hestArg *harg = (hestArg *)_harg;
- if (harg->str) {
- /* If caller wants to keep harg->str around,
- they need to have copied it (the pointer) and set harg->str to NULL */
- free(harg->str);
- }
- airArrayNix(harg->strArr); /* leave the underlying str alone */
+ airArrayNuke(harg->strArr);
return;
}
@@ -157,8 +152,17 @@
// ret = AIR_CALLOC(1, hestArg); // (we don't have a constructor?)
// memcpy(ret, havec->harg + popIdx);
for (uint ai = popIdx; ai < havec->len - 1; ai++) {
- // shuffle down the hestArg elements (not pointers to them) of havec->harg
- memcpy(havec->harg + ai, havec->harg + ai + 1, sizeof(hestArg));
+ // shuffle down info inside the hestArg elements of havec->harg
+ hestArgSetString(havec->harg + ai, (havec->harg + ai + 1)->str);
+ (havec->harg + ai)->source = (havec->harg + ai + 1)->source;
+ /* why cannot just memcpy:
+ because then the last hestArg element of havec->harg
+ (the one that is being forgotten)
+ and the second-to-last element (the last one being kept)
+ will share ->str pointers.
+ When hargDone is called on the last hestArg's address
+ as the callack from airArrayLenIncr(), then it will also
+ free the str inside the second-to-last element; oops */
}
// decrement the nominal length of havec->harg
airArrayLenIncr(havec->hargArr, -1);
@@ -174,11 +178,14 @@
void
hestArgVecPrint(const char *caller, const char *info, const hestArgVec *havec) {
+ // fprintf(stderr, "!%s: %s hestArgVec %p has %u args:\n", caller, info, havec, havec->len);
printf("%s: %s hestArgVec %p has %u args:\n", caller, info, havec, havec->len);
for (uint idx = 0; idx < havec->hargArr->len; idx++) {
const hestArg *harg;
harg = havec->harg + idx;
- printf(" %u:<%s>", idx, harg->str);
+ // fprintf(stderr, "!%s harg@%p=%u:<%s>\n", "", AIR_VOIDP(harg), idx,
+ // harg->str ? harg->str : "NULL");
+ printf(" %u:<%s>", idx, harg->str ? harg->str : "NULL");
}
printf("\n");
}
Modified: teem/trunk/src/hest/methodsHest.c
===================================================================
--- teem/trunk/src/hest/methodsHest.c 2025-09-23 08:36:57 UTC (rev 7470)
+++ teem/trunk/src/hest/methodsHest.c 2025-09-23 10:26:02 UTC (rev 7471)
@@ -647,6 +647,7 @@
return 1;
}
*/
+ free(tbuff);
}
// ------ end of if (opt[opi].flag)
if (1 == opt[opi].kind) {
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-23 08:36:57 UTC (rev 7470)
+++ teem/trunk/src/hest/parsest.c 2025-09-23 10:26:02 UTC (rev 7471)
@@ -650,11 +650,14 @@
/* else try the long version */
sprintf(buff, "--%s", sep + 1);
if (!strcmp(flarg, buff)) return (free(buff), free(ofboth), optIdx);
+ free(buff);
+ free(ofboth);
} else {
/* flag only comes in short version */
char *buff = AIR_CALLOC(strlen("-") + strlen(optFlag) + 1, char);
sprintf(buff, "-%s", optFlag);
if (!strcmp(flarg, buff)) return (free(buff), optIdx);
+ free(buff);
}
}
if (hparm->verbosity) printf("%s: no match, returning UINT_MAX\n", __func__);
@@ -790,11 +793,22 @@
// remember from whence this option came
theOpt->source = theArg->source;
// lose the flag argument
+ if (hparm->verbosity > 1) {
+ hestArgVecPrint(__func__, "main havec as it came", havec);
+ }
hestArgVecRemove(havec, argIdx);
- // empty any pior parm args learned for this option
+ if (hparm->verbosity > 1) {
+ char info[AIR_STRLEN_HUGE + 1];
+ 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++) {
// theArg still points to the next arg (at index argIdx) for this option
+ if (hparm->verbosity) {
+ printf("%s: moving |%s| to theOpt->havec\n", __func__, theArg->str);
+ }
hestArgVecAppendString(theOpt->havec, theArg->str);
hestArgVecRemove(havec, argIdx);
}
@@ -819,10 +833,15 @@
theOpt = opt + opi;
if (1 != theOpt->kind // this kind of option can take a parm
&& theOpt->flag // and this is a flagged option we should have handled above
- && theOpt->dflt // and this option has no default
- && (hestSourceUnknown == theOpt->source)) { // but this option hasn't been set
+ && !(theOpt->dflt)) { // and this option has no default
+ if (hparm->verbosity > 1) {
+ printf("%s: opt %u |%s| (flagged opt w/ parm but no default) source = %s\n",
+ __func__, opi, theOpt->flag, airEnumStr(hestSource, theOpt->source));
+ }
+ if (hestSourceUnknown == theOpt->source) { // but this option hasn't been set
biffAddf(HEST, "%s: didn't get required %s\n", __func__, identStr(ident1, theOpt));
return 1;
+ }
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-23 08:36:59
|
Revision: 7470
http://sourceforge.net/p/teem/code/7470
Author: kindlmann
Date: 2025-09-23 08:36:57 +0000 (Tue, 23 Sep 2025)
Log Message:
-----------
still working on hestParse rewrite
Modified Paths:
--------------
teem/trunk/src/hest/argvHest.c
teem/trunk/src/hest/hest.h
teem/trunk/src/hest/methodsHest.c
teem/trunk/src/hest/parseHest.c
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/privateHest.h
teem/trunk/src/hest/test/argv.c
teem/trunk/src/hest/test/tparse.c
Modified: teem/trunk/src/hest/argvHest.c
===================================================================
--- teem/trunk/src/hest/argvHest.c 2025-09-22 20:54:48 UTC (rev 7469)
+++ teem/trunk/src/hest/argvHest.c 2025-09-23 08:36:57 UTC (rev 7470)
@@ -20,9 +20,6 @@
#include "hest.h"
#include "privateHest.h"
-#include <assert.h>
-#include <sys/errno.h>
-
#define INCR 32
/* to avoid strict aliasing warnings */
@@ -52,6 +49,7 @@
appu.c = &(harg->str);
harg->strArr = airArrayNew(appu.v, &(harg->len), sizeof(char), INCR);
airArrayStructCB(harg->strArr, setNul, NULL);
+ harg->source = hestSourceUnknown;
/* initialize with \0 so that harg->str is "" */
airArrayLenIncr(harg->strArr, 1);
/* now harg->str = {0:'\0'} and harg->len = 1; */
@@ -107,8 +105,9 @@
}
void
-hestArgAddString(hestArg *harg, const char *str) {
+hestArgSetString(hestArg *harg, const char *str) {
assert(harg && str);
+ hestArgReset(harg);
uint len = AIR_UINT(strlen(str));
for (uint si = 0; si < len; si++) {
hestArgAddChar(harg, str[si]);
@@ -127,27 +126,55 @@
hestPtrPtrUnion hppu;
hppu.harg = &(havec->harg);
havec->hargArr = airArrayNew(hppu.v, &(havec->len), sizeof(hestArg), INCR);
+ // underlying array havec->harg will not be reallocated if shrunk
+ havec->hargArr->noReallocWhenSmaller = AIR_TRUE;
airArrayStructCB(havec->hargArr, hargInit, hargDone);
return havec;
}
+void
+hestArgVecReset(hestArgVec *havec) {
+ if (havec) {
+ airArrayLenSet(havec->hargArr, 0);
+ }
+ return;
+}
+
hestArgVec *
hestArgVecNix(hestArgVec *havec) {
- assert(havec);
- airArrayNuke(havec->hargArr);
- free(havec);
+ if (havec) {
+ airArrayNuke(havec->hargArr);
+ free(havec);
+ }
return NULL;
}
void
+hestArgVecRemove(hestArgVec *havec, uint popIdx) {
+ // (experimented with allocating something to hold what was lost)
+ // hestArg *ret = NULL;
+ if (havec && popIdx < havec->len) { // note: this implies that havec->len >= 1
+ // ret = AIR_CALLOC(1, hestArg); // (we don't have a constructor?)
+ // memcpy(ret, havec->harg + popIdx);
+ for (uint ai = popIdx; ai < havec->len - 1; ai++) {
+ // shuffle down the hestArg elements (not pointers to them) of havec->harg
+ memcpy(havec->harg + ai, havec->harg + ai + 1, sizeof(hestArg));
+ }
+ // decrement the nominal length of havec->harg
+ airArrayLenIncr(havec->hargArr, -1);
+ }
+ return;
+}
+
+void
hestArgVecAppendString(hestArgVec *havec, const char *str) {
uint idx = airArrayLenIncr(havec->hargArr, 1);
- hestArgAddString(havec->harg + idx, str);
+ hestArgSetString(havec->harg + idx, str);
}
void
-hestArgVecPrint(const char *caller, const hestArgVec *havec) {
- printf("%s: hestArgVec %p has %u args:\n", caller, havec, havec->len);
+hestArgVecPrint(const char *caller, const char *info, const hestArgVec *havec) {
+ printf("%s: %s hestArgVec %p has %u args:\n", caller, info, havec, havec->len);
for (uint idx = 0; idx < havec->hargArr->len; idx++) {
const hestArg *harg;
harg = havec->harg + idx;
Modified: teem/trunk/src/hest/hest.h
===================================================================
--- teem/trunk/src/hest/hest.h 2025-09-22 20:54:48 UTC (rev 7469)
+++ teem/trunk/src/hest/hest.h 2025-09-23 08:36:57 UTC (rev 7470)
@@ -49,9 +49,9 @@
*
* The blissfully-type-unaware hestOptAdd() has always relied on the airTypeT enum values
* below. Since that function is not being removed, to avoid needless code breakage with
- * TeemV2, these values now live in this hest header. hest users should instead be using
- * one of the 99 properly typed hestOptAdd_X_T functions, which have no need for airType
- * pseudo-types.
+ * TeemV2, these values now live in this hest header. However, hest users should instead
+ * be using one of the 99 properly typed hestOptAdd_X_T functions from adder.c (see
+ * below), which have no need for airType pseudo-types.
*
* Other things that used to be in air, but which really only mattered to implement hest
* functions have been moved into privateHest.h, but with air --> _hest renaming:
@@ -94,6 +94,71 @@
};
/*
+The hestArg, hestArgVec, hestInput, and hestInputStack were all created for the 2025
+TeemV2 rewrite of hestParse, to fix bugs and limits on how the code previously worked:
+- Command-line arguments containing spaces were fully never correctly handled: the
+ internal representation of one argument, as one space-delineated substring of all
+ the arguments concatenated back into a single string (a bad idea), was never correctly
+ implemented. Now the internal representation of argv is with an array data structure,
+ not a single string that has to be retokenized. The old code was wary of dynamic
+ reallocation as part of the parsing process, the new code embraces it (note the many
+ airArray).
+- When parsing response files, ""-quoted strings were not correctly handled (nor was "#"
+ appearing within a string), and response files could not invoke other response files.
+- Can now support long-wanted feature: commenting out of some span of arguments, with
+ new hest-specific "-{" "}-" delimiters. As long as these are space-separated from
+ other args, these are left intact by sh, bash, and zsh (csh and tcsh get confused).
+ They must be kept as separate args to avoid brace expansion.
+*/
+
+// hestArg: for building up and representing one argument string
+typedef struct {
+ char *str; // the argument string
+ unsigned int len; // NOT strlen(); this includes '\0'-termination
+ airArray *strArr; // (manages str and len)
+ int source; // from hestSource* enum
+} hestArg;
+
+// hestArgVec: for building up a "vector" of arguments
+typedef struct {
+ hestArg *harg; // array of hestArg structs (not pointers to them)
+ unsigned int len; // number of arguments in this vector
+ airArray *hargArr; // (manages harg and len)
+} hestArgVec;
+
+// hestInput: what is the thing we're processing now to build up a hestArgVec
+typedef struct {
+ int source; // from the hestSource* enum
+ // ------ if source == hestSourceCommandLine ------
+ unsigned int argc;
+ const char **argv; // we do NOT own
+ unsigned int argIdx;
+ // ------ if source == hestSourceResponseFile ------
+ char *rfname; // we DO own
+ FILE *rfile; // user opens and closes this
+ // ------ if source == hestSourceDefault ------
+ const char *dfltStr; // we do NOT own
+ unsigned int dfltLen; // strlen(dfltStr)
+ // for both hestSourceResponseFile and hestSourceDefault
+ unsigned int carIdx; // which character are we on
+ // ------ general for all inputs ------
+ unsigned int dashBraceComment; /* not a boolean: how many -{ }- comment levels
+ deep are we currently; tracked this way to
+ permit nested commenting */
+} hestInput;
+
+/* hestInputStack: a way of remembering what more needs to be processed to build
+ up a hestArgVec. This full stack may be overkill, but is is the right tool for
+ handling the expansion of a @opts.txt response file, especially with the possibility
+ that response files can be expanded inside of other response files */
+typedef struct {
+ hestInput *hin; // array of hestInputs
+ unsigned int len; // size of stack of hestInputs
+ airArray *hinArr; // (manages hin and len)
+ int stdinRead; // while processing this stack we have read in "-" aka stdin
+} hestInputStack;
+
+/*
******** hestCB struct
**
** for when the thing you want to parse from the command-line is airTypeOther: not a
@@ -143,9 +208,10 @@
/* --------------------- end of user-defined fields
These are set by hest functions to remember state for the sake of other hest functions.
- It is probably a drawback of the simple design of hest that this internal state ends
- up in the same struct as the input parameters above, because it blocks some
- const-correctness opportunities that would otherwise make sense. */
+ It may be a drawback of the simple design of hest that this internal state ends
+ up in the same struct as the input parameters above, but it also makes sense to keep
+ all per-opt state in one place. The const-correctness we might want of hestParse is
+ thwarted by this internal state, but also by the important output fields, below. */
int kind, /* What kind of option is this, based on min and max:
0: (invalid; unset)
1: min == max == 0 stand-alone flag; no parameters
@@ -165,6 +231,7 @@
array of strings
3: free((*valueP)[i]) and free(*valueP), because it is a dynamically
allocated array of strings */
+ hestArgVec *havec; // the args attributed to this option
/* Since hest's beginning in 2002, the basic container for a set of options was an
array of hestOpt structs (not pointers to them, which rules out argv-style
NULL-termination of the array), also unfortunately with no other top-level container
@@ -253,64 +320,6 @@
unsigned int columns; /* number of printable columns in output */
} hestParm;
-/*
-The hestArg, hestArgVec, hestInput, and hestInputStack were all created for the TeemV2
-rewrite of hestParse, to fix bugs and limits on how the code previously worked:
-- Command-line arguments containing spaces were fully never correctly handled: the
- internal representation of one argument, amidst a space-seperated string of all
- arguments (why?!?) put back in ""-quoting, but it was never correctly implemented.
- Now the internal representation of argv is with an array data structure, not a single
- string that has to be retokenized.
-- When parsing response files, ""-quoted strings were never handled at all (nor was "#"
- appearing within a string), and response files could not invoke other response files.
-- Can now support long-wanted feature: commenting out of some span of arguments, with
- new hest-specific "-{" "}-" delimiters. As long as these are space-separated from
- other args, these are left intact by sh, bash, and zsh (csh and tcsh get confused).
- They must be kept as separate args to avoid brace expansion.
-*/
-
-// hestArg: for building up and representing one argument
-typedef struct {
- char *str;
- unsigned int len; // NOT strlen; this includes '\0'-termination
- airArray *strArr;
-} hestArg;
-
-// hestArgVec: for building up a "vector" of arguments
-typedef struct {
- hestArg *harg; /* array of hestArgs */
- unsigned int len;
- airArray *hargArr;
-} hestArgVec;
-
-// hestInput: what is the thing we're processing now to build up an arg vec
-typedef struct {
- int source; // from the hestSource* enum
- // ------ if source == hestSourceCommandLine ------
- unsigned int argc;
- const char **argv; // we do NOT own
- unsigned int argIdx;
- // ------ if source == hestSourceResponseFile ------
- char *rfname; // we DO own
- FILE *rfile; // user opens and closes this
- // ------ if source == hestSourceDefault ------
- const char *dfltStr; // we do NOT own
- unsigned int dfltLen; // strlen(dfltStr)
- // for both hestSourceResponseFile and hestSourceDefault
- unsigned int carIdx; // which character are we on
- // ------ general for all inputs ------
- unsigned int dashBraceComment; /* not a boolean: how many -{ }- comment levels
- deep are we currently; tracked this way to
- permit nested commenting */
-} hestInput;
-
-typedef struct {
- hestInput *hin; // array of hestInputs
- unsigned int len;
- airArray *hinArr;
- int stdinRead; // while processing this stack we have read in "-" aka stdin
-} hestInputStack;
-
// defaultsHest.c
HEST_EXPORT int hestDefaultVerbosity;
HEST_EXPORT int hestDefaultResponseFileEnable;
@@ -330,20 +339,19 @@
HEST_EXPORT hestArg *hestArgNix(hestArg *harg);
HEST_EXPORT void hestArgReset(hestArg *harg);
HEST_EXPORT void hestArgAddChar(hestArg *harg, char cc);
-HEST_EXPORT void hestArgAddString(hestArg *harg, const char *str);
+HEST_EXPORT void hestArgSetString(hestArg *harg, const char *str);
HEST_EXPORT hestArgVec *hestArgVecNew(void);
+HEST_EXPORT void hestArgVecReset(hestArgVec *havec);
HEST_EXPORT hestArgVec *hestArgVecNix(hestArgVec *havec);
+HEST_EXPORT void hestArgVecRemove(hestArgVec *havec, unsigned int popIdx);
HEST_EXPORT void hestArgVecAppendString(hestArgVec *havec, const char *str);
-HEST_EXPORT void hestArgVecPrint(const char *caller, const hestArgVec *havec);
+HEST_EXPORT void hestArgVecPrint(const char *caller, const char *info,
+ const hestArgVec *havec);
HEST_EXPORT hestInput *hestInputNew(void);
HEST_EXPORT hestInput *hestInputNix(hestInput *hin);
HEST_EXPORT hestInputStack *hestInputStackNew(void);
HEST_EXPORT hestInputStack *hestInputStackNix(hestInputStack *hist);
-// parsest.c
-HEST_EXPORT int hestParse2(hestOpt *opt, int argc, const char **argv, char **errP,
- const hestParm *hparm);
-
// methodsHest.c
HEST_EXPORT const int hestPresent;
HEST_EXPORT const airEnum *const hestSource;
@@ -361,6 +369,7 @@
int max, void *valueP, const char *dflt,
const char *info, unsigned int *sawP,
const airEnum *enm, const hestCB *CB);
+// Instead of hestOptAdd, use one of the 99 type-checked functions (from adders.c), below
HEST_EXPORT unsigned int hestOptAdd(hestOpt **optP,
const char *flag, const char *name,
int type, unsigned int min, int max,
@@ -369,7 +378,6 @@
... /* unsigned int *sawP,
const airEnum *enm,
const hestCB *CB */);
-// SEE ALSO (from adders.c) all the 99 type-checked versions of hestOptAdd_, below!
HEST_EXPORT unsigned int hestOptNum(const hestOpt *opt);
HEST_EXPORT hestOpt *hestOptFree(hestOpt *opt);
HEST_EXPORT void *hestOptFree_vp(void *opt);
@@ -384,6 +392,10 @@
hestParm *hparm, const char *me, const char *info,
int doInfo, int doUsage, int doGlossary);
+// parsest.c
+HEST_EXPORT int hestParse2(hestOpt *opt, int argc, const char **argv, char **errP,
+ const hestParm *hparm);
+
// usage.c
HEST_EXPORT void _hestPrintStr(FILE *f, unsigned int indent, unsigned int already,
unsigned int width, const char *_str, int bslash);
@@ -395,23 +407,29 @@
// adders.c
HEST_EXPORT void hestOptAddDeclsPrint(FILE *f);
-/* The 99 (!) non-var-args alternatives to hestOptAdd, also usefully type-specific for
-the type of value to be parsed in a way that hestOptAdd_nva cannot match. These capture
-all the common uses (and then some) of hest within Teem. They are named according to
-kind, and according to the type T of the parms to be parsed for each option:
+/* The 99 (!) non-var-args alternatives to hestOptAdd, enable more type checking because
+they non-var-args, but are also usefully type-specific for each possible type of value to
+be parsed in a way that hestOptAdd_nva cannot match. In fact, *all* possible ways of
+using hest are covered here, due to the enumeration over "kind" and over type T, which
+determines the function name as follows:
-min, max function family kind description
-min == max == 0 hestOptAdd_Flag 1 (stand-alone flag; no parameters)
-min == max == 1 hestOptAdd_1_T 2 single fixed parameter
-min == max >= 2 hestOptAdd_{2,3,4,N}_T 3 multiple fixed parameters
-min == 0; max == 1 hestOptAdd_1v_T 4 single variable parameter
-min < max; max >= 2 hestOptAdd_Nv_T 5 multiple variable parameters
+kind min, max function family description
+ 1 min == max == 0 hestOptAdd_Flag (stand-alone flag; no parameters)
+ 2 min == max == 1 hestOptAdd_1_T single fixed parameter
+ 3 min == max >= 2 hestOptAdd_{2,3,4,N}_T multiple fixed parameters
+ 4 min == 0; max == 1 hestOptAdd_1v_T single variable parameter
+ 5 min < max; max >= 2 hestOptAdd_Nv_T multiple variable parameters
-The type T can be: Bool, Short, UShort, Int, UInt, Long, ULong, Size_t, Float, Double,
-Char, String, Enum, or Other. An airEnum* is passed with the T=Enum functions, or a
-hestCB* is passed for the T=Other functions. The number of parameters *sawP that hestParm
-saw on the command-line is passed for the _Nv_ options.
+The type T can be (one for each airType enum value): Bool, Short, UShort, Int, UInt,
+Long, ULong, Size_t, Float, Double, Char, String, Enum, or Other. An `airEnum *enm` is
+passed with the T=Enum functions. A `hestCB *CB` is passed for the T=Other functions. The
+number of parms `int *sawP` that hestParm saw on the command-line is passed for the _Nv_
+options.
+For each of the 14 different `_T` types, there are 7 different families for `_1`
+(kind=2), `_2`,`_3`,`_4`,`_N` (kind=3),`_1v` (kind=4), and `_Nv` (kind=5).
+14 * 7 = 98, plus hestOptAdd_Flag makes 99 functions.
+
All declarations below were automatically generated via hest/test/decls (which calls
hestOptAddDeclsPrint), followed by clang-format. */
HEST_EXPORT unsigned int hestOptAdd_Flag(hestOpt **optP, const char *flag, int *valueP,
Modified: teem/trunk/src/hest/methodsHest.c
===================================================================
--- teem/trunk/src/hest/methodsHest.c 2025-09-22 20:54:48 UTC (rev 7469)
+++ teem/trunk/src/hest/methodsHest.c 2025-09-23 08:36:57 UTC (rev 7470)
@@ -19,8 +19,6 @@
#include "hest.h"
#include "privateHest.h"
-#include <limits.h>
-#include <assert.h>
#include <sys/ioctl.h> // for ioctl(), TIOCGWINSZ, struct winsize
#include <unistd.h> // for STDOUT_FILENO and friends
@@ -221,7 +219,7 @@
return ret;
}
-/* _hestMax(-1) == INT_MAX, otherwise _hestMax(m) == m */
+// _hestMax(-1) == INT_MAX, otherwise _hestMax(m) == m
int
_hestMax(int max) {
@@ -290,6 +288,7 @@
opt->sawP = NULL;
opt->kind = 0; /* means that this hestOpt has not been set */
opt->alloc = 0;
+ opt->havec = NULL;
opt->arrAlloc = opt->arrLen = 0;
opt->source = hestSourceUnknown;
opt->parmStr = NULL;
@@ -368,7 +367,6 @@
opt->valueP = valueP;
opt->dflt = airStrdup(dflt);
opt->info = airStrdup(info);
- opt->kind = opt_kind(min, max);
/* deal with (what used to be) var args */
opt->sawP = (5 == opt->kind /* */
? sawP
@@ -379,7 +377,9 @@
opt->CB = (airTypeOther == type /* */
? CB
: NULL);
+ opt->kind = opt_kind(min, max);
/* alloc set by hestParse */
+ opt->havec = hestArgVecNew();
/* leave arrAlloc, arrLen untouched: managed by caller */
/* yes, redundant with opt_init() */
opt->source = hestSourceUnknown;
@@ -475,17 +475,15 @@
opt->name = (char *)airFree(opt->name);
opt->dflt = (char *)airFree(opt->dflt);
opt->info = (char *)airFree(opt->info);
+ opt->havec = hestArgVecNix(opt->havec);
return;
}
hestOpt *
hestOptFree(hestOpt *opt) {
- int opi, num;
-
if (!opt) return NULL;
-
- num = opt->arrLen;
- for (opi = 0; opi < num; opi++) {
+ uint num = opt->arrLen;
+ for (uint opi = 0; opi < num; opi++) {
_hestOptFree(opt + opi);
}
free(opt);
@@ -503,14 +501,15 @@
* Pre-2025, hest did not depend on biff, and this instead took a 'char *err' that
* somehow magically had to be allocated for the size of any possible error message
* generated here. The 2025 re-write recognized that biff is the right way to accumulate
- * error messages, but the use of biff is internal to biff, but not (unusually for Teem)
+ * error messages, but the use of biff is internal to biff, and not (unusually for Teem)
* part of the the expected use of biff's API. Thus, public functions hestOptCheck() and
* hestOptParmCheck(), which are the expected way to access the functionality herein,
* take a `char **errP` arg into which a message is sprintf'ed, after allocation.
*
- * The shift to using biff removed how this function used to fprintf(stderr) some message
- * like "panic 0.5" which as completely uninformative. Now, hestOptCheck() and
- * hestOptParmCheck() fprintf(stderr) the biff message.
+ * The shift to using biff removed how this function used to fprintf(stderr) some
+ * messages like "panic 0.5" which were totally uninformative. Now, hestOptCheck() and
+ * hestOptParmCheck(), which both call _hestOPCheck, will fprintf(stderr) the informative
+ * biff message.
*
* Prior to 2023 code revisit: this used to set the "kind" in all the opts, but now that
* is more appropriately done at the time the option is added.
Modified: teem/trunk/src/hest/parseHest.c
===================================================================
--- teem/trunk/src/hest/parseHest.c 2025-09-22 20:54:48 UTC (rev 7469)
+++ teem/trunk/src/hest/parseHest.c 2025-09-23 08:36:57 UTC (rev 7470)
@@ -1450,29 +1450,22 @@
**
** free()s whatever was allocated by hestParse()
**
-** returns NULL only to facilitate use with the airMop functions.
-** You should probably just ignore this quirk.
+** ignore-able quirk: returns NULL, to facilitate use with the airMop functions
*/
void *
hestParseFree(hestOpt *opt) {
- int op, i, optNum;
- unsigned int ui;
- void **vP;
- void ***vAP;
- char **str;
- char ***strP;
-
- optNum = hestOptNum(opt);
- for (op = 0; op < optNum; op++) {
+ uint optNum = opt->arrLen;
+ for (uint op = 0; op < optNum; op++) {
+ hestArgVecNix(opt[op].havec);
opt[op].parmStr = airFree(opt[op].parmStr);
/*
printf("!hestParseFree: op = %d/%d -> kind = %d; type = %d; alloc = %d\n",
op, optNum-1, opt[op].kind, opt[op].type, opt[op].alloc);
*/
- vP = (void **)opt[op].valueP;
- vAP = (void ***)opt[op].valueP;
- str = (char **)opt[op].valueP;
- strP = (char ***)opt[op].valueP;
+ void **vP = (void **)opt[op].valueP;
+ void ***vAP = (void ***)opt[op].valueP;
+ char **str = (char **)opt[op].valueP;
+ char ***strP = (char ***)opt[op].valueP;
switch (opt[op].alloc) {
case 0:
/* nothing was allocated */
@@ -1493,11 +1486,11 @@
break;
case 2:
if (airTypeString == opt[op].type) {
- for (i = 0; i < (int)opt[op].min; i++) { /* HEY scrutinize casts */
+ for (int i = 0; i < (int)opt[op].min; i++) { /* HEY scrutinize casts */
str[i] = (char *)airFree(str[i]);
}
} else {
- for (i = 0; i < (int)opt[op].min; i++) { /* HEY scrutinize casts */
+ for (int i = 0; i < (int)opt[op].min; i++) { /* HEY scrutinize casts */
vP[i] = opt[op].CB->destroy(vP[i]);
}
}
@@ -1504,12 +1497,12 @@
break;
case 3:
if (airTypeString == opt[op].type) {
- for (ui = 0; ui < *(opt[op].sawP); ui++) {
+ for (uint ui = 0; ui < *(opt[op].sawP); ui++) {
(*strP)[ui] = (char *)airFree((*strP)[ui]);
}
*strP = (char **)airFree(*strP);
} else {
- for (ui = 0; ui < *(opt[op].sawP); ui++) {
+ for (uint ui = 0; ui < *(opt[op].sawP); ui++) {
(*vAP)[ui] = opt[op].CB->destroy((*vAP)[ui]);
}
*vAP = (void **)airFree(*vAP);
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-22 20:54:48 UTC (rev 7469)
+++ teem/trunk/src/hest/parsest.c 2025-09-23 08:36:57 UTC (rev 7470)
@@ -22,9 +22,6 @@
/* parse, Parser, PARSEST: please let this be the final implementation of hestParse */
-#include <assert.h>
-#include <sys/errno.h>
-
/* variable name conventions:
harg = hestArg
havec = hestArgVec
@@ -296,7 +293,7 @@
// printf("!%s: argi %u vs argc %u\n", __func__, argi, hin->argc);
if (argi < hin->argc) {
// there are args left to parse
- hestArgAddString(tharg, hin->argv[argi]);
+ hestArgSetString(tharg, hin->argv[argi]);
// printf("!%s: now tharg->str=|%s|\n", __func__, tharg->str);
*nastP = nastBehold;
hin->argIdx++;
@@ -516,6 +513,8 @@
uint iters = 0;
hestInput *topHin;
// printf("!%s: hello hist->len %u\n", __func__, hist->len);
+ // initialize destination havec
+ airArrayLenSet(havec->hargArr, 0);
/* We `return` directly from this loop ONLY when we MUST stop processing the stack,
because of an error, or because of user asking for help.
Otherwise, we loop again. */
@@ -534,7 +533,7 @@
return 1;
}
if (nastEmpty == nast) {
- // the stack has no more tokens to give, stop looped requests for mre
+ // the stack has no more tokens to give, stop looped requests for more
if (hparm->verbosity) {
printf("%s: (iter %u, on %s) empty!\n", __func__, iters, srcstr);
}
@@ -598,7 +597,7 @@
__func__, iters, srcstr, tharg->str);
return 1;
}
- // have just added response file to stack, next iter will read from it
+ // have just added response file to stack, next iter will start reading from it
continue;
}
// this arg is not specially handled by us; add it to the arg vec
@@ -607,6 +606,8 @@
printf("%s: (iter %u, on %s) added |%s| to havec, now len %u\n", __func__, iters,
srcstr, tharg->str, havec->len);
}
+ // set source in the hestArg we just appended
+ (havec->harg + havec->len - 1)->source = topHin->source;
}
if (hist->len && nast == nastEmpty) {
biffAddf(HEST, "%s: non-empty stack (depth %u) can't generate args???", __func__,
@@ -617,18 +618,240 @@
}
/*
-hestParse(2): parse the `argc`,`argv` commandline according to the hestOpt array `opt`.
+whichOptFlag(): for which option (by index) is this the flag?
+
+Given an arg string `flarg` (which may be an flag arg like "-size" or parm arg like
+"512"), this finds which one, of the options in the given hestOpt array `opt` is
+identified by `flarg`. Returns the index of the matching option, if there is a match.
+
+If there is no match, returns UINT_MAX.
+*/
+static uint
+whichOptFlag(const hestOpt *opt, const char *flarg, const hestParm *hparm) {
+ uint optNum = opt->arrLen;
+ if (hparm->verbosity)
+ 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)
+ printf("%s: optIdx %u |%s| ?\n", __func__, optIdx,
+ opt[optIdx].flag ? opt[optIdx].flag : "(nullflag)");
+ const char *optFlag = opt[optIdx].flag;
+ if (!optFlag) continue; // it can't be for this unflagged option
+ if (strchr(optFlag, MULTI_FLAG_SEP)) {
+ // look for both long and short versions
+ char *buff = AIR_CALLOC(strlen("--") + strlen(flarg) + strlen(optFlag) + 1, char);
+ char *ofboth = airStrdup(optFlag);
+ char *sep = strchr(ofboth, MULTI_FLAG_SEP);
+ *sep = '\0'; // break short and long into separate strings
+ /* first try the short version */
+ sprintf(buff, "-%s", ofboth);
+ if (!strcmp(flarg, buff)) return (free(buff), free(ofboth), optIdx);
+ /* else try the long version */
+ sprintf(buff, "--%s", sep + 1);
+ if (!strcmp(flarg, buff)) return (free(buff), free(ofboth), optIdx);
+ } else {
+ /* flag only comes in short version */
+ char *buff = AIR_CALLOC(strlen("-") + strlen(optFlag) + 1, char);
+ sprintf(buff, "-%s", optFlag);
+ if (!strcmp(flarg, buff)) return (free(buff), optIdx);
+ }
+ }
+ if (hparm->verbosity) printf("%s: no match, returning UINT_MAX\n", __func__);
+ return UINT_MAX;
+}
+
+/* identStr sprints into `ident` (and returns same `ident`)
+ a way to identify `opt` in error and usage messages */
+static char *
+identStr(char *ident, const hestOpt *opt) {
+ if (opt->flag) {
+ if (strchr(opt->flag, MULTI_FLAG_SEP)) {
+ char *fcopy = airStrdup(opt->flag);
+ char *sep = strchr(fcopy, MULTI_FLAG_SEP);
+ *sep = '\0';
+ sprintf(ident, "\"-%s%c--%s\" option", fcopy, MULTI_FLAG_SEP, sep + 1);
+ free(fcopy);
+ } else {
+ sprintf(ident, "\"-%s\" option", opt->flag);
+ }
+ } else {
+ sprintf(ident, "\"<%s>\" option", opt->name);
+ }
+ return ident;
+}
+
+/*
+havecExtractFlagged()
+
+extracts the parameter args associated with all flagged options from the given
+`hestArgVec *havec` (as generated by histProc()) and stores them the corresponding
+opt->havec. Also sets opt->source according to where that flag arg appeared (we don't
+notice if the parameters were weirdly split between the comamnd-line and a response file;
+only the source of the flag arg is recorded).
+
+In the case of variable parameter options, this does the work of figuring out which args
+belong with the option. In any case, this only extracts and preserves (in opt->havec) the
+parameter args, not the flag arg that identified which option was being set.
+
+As a result of this work, the passed `havec` is shortened: all args associated with
+flagged opts are removed, so that later work can extract args for unflagged opts.
+
+The sawP information is not set here, since it is better set at the final value parsing
+time, which happens after defaults are enstated.
+
+This is where, thanks to the action of whichOptFlag(), "--" (and only "--" due to
+VAR_PARM_STOP_FLAG) is used as a marker for the end of a flagged variable parameter
+option. AND, the "--" marker is removed from `havec`.
+*/
+static int
+havecExtractFlagged(hestOpt *opt, hestArgVec *havec, const hestParm *hparm) {
+ char ident1[AIR_STRLEN_HUGE + 1], ident2[AIR_STRLEN_HUGE + 1];
+ uint argIdx = 0;
+ hestOpt *theOpt = NULL;
+ while (argIdx < havec->len) { // NOTE: havec->len may decrease within an interation!
+ hestArg *theArg = havec->harg + argIdx;
+ if (hparm->verbosity) {
+ printf("%s: ------------- argIdx = %u (of %u) -> argv[argIdx] = |%s|\n", __func__,
+ argIdx, havec->len, theArg->str);
+ }
+ uint optIdx = whichOptFlag(opt, theArg->str, hparm);
+ if (UINT_MAX == optIdx) {
+ // theArg->str is not a flag for any option, move on to next arg
+ argIdx++;
+ if (hparm->verbosity)
+ printf("%s: |%s| not a flag arg, continue\n", __func__, theArg->str);
+ continue;
+ }
+ // else theArg->str is a flag for option with index optIdx aka theOpt
+ theOpt = opt + optIdx;
+ if (hparm->verbosity)
+ printf("%s: argv[%u]=|%s| is flag of opt %u \"%s\"\n", __func__, argIdx,
+ theArg->str, optIdx, theOpt->flag);
+ /* see if we can associate some parameters with the flag */
+ if (hparm->verbosity) printf("%s: any associated parms?\n", __func__);
+ uint parmNum = 0;
+ int hitEnd = AIR_FALSE;
+ int varParm = (5 == opt[optIdx].kind);
+ char VPS[3] = {'-', VAR_PARM_STOP_FLAG, '\0'};
+ int hitVPS = AIR_FALSE;
+ uint nextOptIdx = 0; // what is index of option who's flag we see next
+ while (AIR_INT(parmNum) < _hestMax(theOpt->max) // parmNum is plausible # parms
+ && !(hitEnd = !(argIdx + 1 + parmNum < havec->len)) // and have valid index
+ && (!varParm // and either this isn't a variable parm opt
+ || // or, it is a varparm opt and we aren't looking at "--"
+ !(hitVPS = !strcmp(VPS, (theArg + 1 + parmNum)->str)))
+ && UINT_MAX // and we aren't looking at start of another flagged option
+ == (nextOptIdx = whichOptFlag(opt, (theArg + 1 + parmNum)->str,
+ hparm))) {
+ parmNum++;
+ if (hparm->verbosity)
+ printf("%s: optIdx %d |%s|: |%s| --> parmNum --> %d\n", __func__, optIdx,
+ theOpt->flag, (theArg + 1 + parmNum - 1)->str, parmNum);
+ }
+ /* we stopped because we got the max number of parameters, or
+ we hitEnd, or
+ varParm and we hitVPS, or
+ we hit the start of another flagged option (indicated by nextOptIdx) */
+ if (hparm->verbosity)
+ printf("%s: optIdx %d |%s|: stopped w/ "
+ "parmNum=%u hitEnd=%d hitVPS=%d nextOptIdx=%u\n",
+ __func__, optIdx, theOpt->flag, parmNum, hitEnd, hitVPS, nextOptIdx);
+ if (parmNum < theOpt->min) { // didn't get required min # parameters
+ if (hitEnd) {
+ biffAddf(HEST,
+ "%s: hit end of args before getting %u parameter%s "
+ "for %s (got %u)",
+ __func__, theOpt->min, theOpt->min > 1 ? "s" : "",
+ identStr(ident1, theOpt), parmNum);
+ } else if (hitVPS) {
+ biffAddf(HEST,
+ "%s: hit \"-%c\" (variable-parameter-stop flag) before getting %u "
+ "parameter%s for %s (got %u)",
+ __func__, VAR_PARM_STOP_FLAG, theOpt->min, theOpt->min > 1 ? "s" : "",
+ identStr(ident1, theOpt), parmNum);
+ } else if (UINT_MAX != nextOptIdx) {
+ biffAddf(HEST, "%s: saw %s before getting %u parameter%s for %s (got %d)",
+ __func__, identStr(ident2, opt + nextOptIdx), theOpt->min,
+ theOpt->min > 1 ? "s" : "", identStr(ident1, theOpt), parmNum);
+ } else {
+ biffAddf(HEST,
+ "%s: sorry, confused about not getting %u "
+ "parameter%s for %s (got %d)",
+ __func__, theOpt->min, theOpt->min > 1 ? "s" : "",
+ identStr(ident1, theOpt), parmNum);
+ }
+ return 1;
+ }
+ if (hparm->verbosity) {
+ printf("%s: ________ argv[%d]=|%s|: optIdx %u |%s| followed by %u parms\n",
+ __func__, argIdx, theArg->str, optIdx, theOpt->flag, parmNum);
+ }
+ // remember from whence this option came
+ theOpt->source = theArg->source;
+ // lose the flag argument
+ hestArgVecRemove(havec, argIdx);
+ // empty any pior parm args learned for this option
+ hestArgVecReset(theOpt->havec);
+ for (uint pidx = 0; pidx < parmNum; pidx++) {
+ // theArg still points to the next arg (at index argIdx) for this option
+ hestArgVecAppendString(theOpt->havec, theArg->str);
+ hestArgVecRemove(havec, argIdx);
+ }
+ if (hitVPS) {
+ // drop the variable-parameter-stop flag
+ hestArgVecRemove(havec, argIdx);
+ }
+ if (hparm->verbosity) {
+ char info[AIR_STRLEN_HUGE + 1];
+ sprintf(info, "main havec after extracting optIdx %u |%s| and %u parms", optIdx,
+ theOpt->flag, parmNum);
+ hestArgVecPrint(__func__, info, havec);
+ sprintf(info, "optIdx %u |%s|'s own havec", optIdx, theOpt->flag);
+ hestArgVecPrint(__func__, info, theOpt->havec);
+ }
+ // do NOT increment argIdx
+ }
+
+ /* make sure that flagged options without default were given */
+ uint optNum = opt->arrLen;
+ for (uint opi = 0; opi < optNum; opi++) {
+ theOpt = opt + opi;
+ if (1 != theOpt->kind // this kind of option can take a parm
+ && theOpt->flag // and this is a flagged option we should have handled above
+ && theOpt->dflt // and this option has no default
+ && (hestSourceUnknown == theOpt->source)) { // but this option hasn't been set
+ biffAddf(HEST, "%s: didn't get required %s\n", __func__, identStr(ident1, theOpt));
+ return 1;
+ }
+ }
+
+ 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
+ - 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`.
+2) From `havec`, extract the args that are attributable to flagged and unflagged options,
+ moving each `hestArg` instead into 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
*/
int
hestParse2(hestOpt *opt, int argc, const char **argv, char **errP,
const hestParm *_hparm) {
+ airArray *mop = airMopNew(); // initialize the mop
- // -------- initialize the mop
- airArray *mop = airMopNew();
-
- // -------- make exactly one of (given) _hparm and (our) hparm non-NULL
+ // make exactly one of (given) _hparm and (our) hparm non-NULL
hestParm *hparm = NULL;
if (!_hparm) {
hparm = hestParmNew();
@@ -661,7 +884,7 @@
printf("%s: _hestOPCheck passed\n", __func__);
}
- // -------- allocate the state we use during parsing
+ // allocate the state we use during parsing
hestInputStack *hist = hestInputStackNew();
airMopAdd(mop, hist, (airMopper)hestInputStackNix, airMopAlways);
hestArgVec *havec = hestArgVecNew();
@@ -672,7 +895,7 @@
printf("%s: parsing state allocated\n", __func__);
}
- // -------- initialize input stack w/ given argc,argv, then process it
+ // --1--1--1--1--1-- initialize input stack w/ given argc,argv, process it
if (histPushCommandLine(hist, argc, argv, HPARM)
|| histProcess(havec, &(opt->helpWanted), tharg, hist, HPARM)) {
DO_ERR("problem with initial processing of command-line");
@@ -681,7 +904,7 @@
}
if (HPARM->verbosity > 1) {
// have finished input stack, what argvec did it leave us with?
- hestArgVecPrint(__func__, havec);
+ hestArgVecPrint(__func__, "after histProcess", havec);
}
if (opt->helpWanted) {
// once the call for help is made, we respect it: clean up and return
@@ -689,12 +912,32 @@
return 0;
}
- // ( extract, process: make little argvec for each opt )
- // extract given flagged options
- // extract given unflagged options
- // process default strings of not-given options
- // set value(s) from per-opt argvec
+ // --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) */) {
+ 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
+ Like havecExtract{,Un}Flagged, this builds up opt->havec, but does not parse it */
+ if (optProcessDefaults) {
+ DO_ERR("problem with processing defaults");
+ airMopError(mop);
+ return 1;
+ }
+
+ // --4--4--4--4--4-- Finally, parse the args and set values
+ if (optSetValues) {
+ DO_ERR("problem with setting values");
+ airMopError(mop);
+ return 1;
+ }
+#endif
airMopOkay(mop);
return 0;
}
Modified: teem/trunk/src/hest/privateHest.h
===================================================================
--- teem/trunk/src/hest/privateHest.h 2025-09-22 20:54:48 UTC (rev 7469)
+++ teem/trunk/src/hest/privateHest.h 2025-09-23 08:36:57 UTC (rev 7470)
@@ -27,6 +27,10 @@
It is still the case, however, the hest users do not need to call into biff */
#include <teem/biff.h>
+#include <limits.h> // for UINT_MAX
+#include <assert.h>
+#include <sys/errno.h>
+
typedef unsigned int uint;
// pre-TeemV2, these used to be change-able defaults in defaultsHest.c:
Modified: teem/trunk/src/hest/test/argv.c
===================================================================
--- teem/trunk/src/hest/test/argv.c 2025-09-22 20:54:48 UTC (rev 7469)
+++ teem/trunk/src/hest/test/argv.c 2025-09-23 08:36:57 UTC (rev 7470)
@@ -51,22 +51,16 @@
printf("%s: |%s|\n", argv[0], harg->str);
hestArgAddChar(harg, '!');
printf("%s: |%s|\n", argv[0], harg->str);
- hestArgAddString(harg, "bingo bob lives\n");
+ hestArgSetString(harg, "bingo bob lives\n");
printf("%s: |%s|\n", argv[0], harg->str);
hestArgNix(harg);
hestArgVec *havec = hestArgVecNew();
- hestArgVecPrint(argv[0], havec);
- hestArgVecAppendString(havec, "this");
- hestArgVecPrint(argv[0], havec);
- hestArgVecAppendString(havec, "is");
- hestArgVecPrint(argv[0], havec);
- hestArgVecAppendString(havec, "totally");
- hestArgVecPrint(argv[0], havec);
- hestArgVecAppendString(havec, "");
- hestArgVecPrint(argv[0], havec);
+ hestArgVecPrint(argv[0], "step 0", havec);
+ hestArgVecAppendString(havec, "banana");
+ hestArgVecPrint(argv[0], "step 1", havec);
hestArgVecAppendString(havec, "bonkers");
- hestArgVecPrint(argv[0], havec);
+ hestArgVecPrint(argv[0], "step 2", havec);
hestArgVecNix(havec);
exit(0);
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-22 20:54:48 UTC (rev 7469)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-23 08:36:57 UTC (rev 7470)
@@ -36,8 +36,10 @@
hparm->responseFileEnable = AIR_TRUE;
hparm->verbosity = 10;
+ int verb;
+ hestOptAdd_1_Int(&opt, "v", "verb", &verb, "0", "verbosity");
int res[2];
- hestOptAdd_2_Int(&opt, "res", "sx sy", res, NULL, "image resolution");
+ hestOptAdd_2_Int(&opt, "s,size", "sx sy", res, NULL, "image resolution");
int flag;
hestOptAdd_Flag(&opt, "b,bingo", &flag, "a flag");
char *err = NULL;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-22 20:54:50
|
Revision: 7469
http://sourceforge.net/p/teem/code/7469
Author: kindlmann
Date: 2025-09-22 20:54:48 +0000 (Mon, 22 Sep 2025)
Log Message:
-----------
less confusion diagnostic message
Modified Paths:
--------------
teem/trunk/src/hest/parsest.c
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-22 20:40:04 UTC (rev 7468)
+++ teem/trunk/src/hest/parsest.c 2025-09-22 20:54:48 UTC (rev 7469)
@@ -529,7 +529,7 @@
const char *srcstr = airEnumStr(hestSource, topHin->source);
// read next arg into tharg
if (histProcNextArg(&nast, tharg, hist, hparm)) {
- biffAddf(HEST, "%s: (arg %u of %s) unable to get next arg", __func__, iters,
+ biffAddf(HEST, "%s: (iter %u, on %s) unable to get next arg", __func__, iters,
srcstr);
return 1;
}
@@ -536,7 +536,7 @@
if (nastEmpty == nast) {
// the stack has no more tokens to give, stop looped requests for mre
if (hparm->verbosity) {
- printf("%s: (arg %u of %s) empty!\n", __func__, iters, srcstr);
+ printf("%s: (iter %u, on %s) empty!\n", __func__, iters, srcstr);
}
break;
}
@@ -551,7 +551,7 @@
continue; // since }- does not belong in havec
} else {
biffAddf(HEST,
- "%s: (arg %u of %s) end comment marker \"}-\" not "
+ "%s: (iter %u, on %s) end comment marker \"}-\" not "
"balanced by prior \"-{\"",
__func__, iters, srcstr);
return 1;
@@ -569,7 +569,7 @@
// if in comment, move along
if (topHin->dashBraceComment) {
if (hparm->verbosity > 1) {
- printf("%s: (arg %u of %s) skipping commented-out |%s|\n", __func__, iters,
+ printf("%s: (iter %u, on %s) skipping commented-out |%s|\n", __func__, iters,
srcstr, tharg->str);
}
continue;
@@ -582,20 +582,20 @@
for parsing results nor error messages about that process */
return 0;
} else {
- biffAddf(HEST, "%s: (arg %u of %s) \"--help\" not expected here", __func__,
+ biffAddf(HEST, "%s: (iter %u, on %s) \"--help\" not expected here", __func__,
iters, srcstr);
return 1;
}
}
if (hparm->verbosity > 1) {
- printf("%s: (arg %u of %s) looking at latest tharg |%s|\n", __func__, iters,
+ printf("%s: (iter %u, on %s) looking at latest tharg |%s|\n", __func__, iters,
srcstr, tharg->str);
}
if (hparm->responseFileEnable && tharg->str[0] == RESPONSE_FILE_FLAG) {
// tharg->str is asking to open a response file; try pushing it
if (histPushResponseFile(hist, tharg->str + 1, hparm)) {
- biffAddf(HEST, "%s: (arg %u of %s) unable to process response file %s", __func__,
- iters, srcstr, tharg->str);
+ biffAddf(HEST, "%s: (iter %u, on %s) unable to process response file %s",
+ __func__, iters, srcstr, tharg->str);
return 1;
}
// have just added response file to stack, next iter will read from it
@@ -604,7 +604,7 @@
// this arg is not specially handled by us; add it to the arg vec
hestArgVecAppendString(havec, tharg->str);
if (hparm->verbosity > 1) {
- printf("%s: (arg %u of %s) added |%s| to havec, now len %u\n", __func__, iters,
+ printf("%s: (iter %u, on %s) added |%s| to havec, now len %u\n", __func__, iters,
srcstr, tharg->str, havec->len);
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-22 20:40:07
|
Revision: 7468
http://sourceforge.net/p/teem/code/7468
Author: kindlmann
Date: 2025-09-22 20:40:04 +0000 (Mon, 22 Sep 2025)
Log Message:
-----------
comment tweaks
Modified Paths:
--------------
teem/trunk/src/air/air.h
teem/trunk/src/hest/hest.h
Modified: teem/trunk/src/air/air.h
===================================================================
--- teem/trunk/src/air/air.h 2025-09-22 20:35:11 UTC (rev 7467)
+++ teem/trunk/src/air/air.h 2025-09-22 20:40:04 UTC (rev 7468)
@@ -454,7 +454,7 @@
/* changes for for TeemV2:
*** airParseStrT() are no longer var-args; it was a mistaken way to enforce uniformity
- * across parsers for different types, and it was really only airParseStrE (for
+ * across parsers for different types, but it was really only airParseStrE (for
* parsing airEnum values) that needed it. Then airParseStrS sneakily used it for
* its final "greedy" argument, which was also a bad idea to overcome bad ideas in
* hestParse(), which have since been fixed with its 2025 re-write.
@@ -475,8 +475,8 @@
* const char airTypeStr[HEST_TYPE_MAX + 1][AIR_STRLEN_SMALL + 1] --> _hestTypeStr
* const size_t airTypeSize[HEST_TYPE_MAX + 1] --> _hestTypeSize
* unsigned int (*const airParseStr[AIR_TYPE_MAX + 1])(void *,
- const char *, *const char *,
- *unsigned int);
+ * const char *, *const char *,
+ * *unsigned int);
* --> _hestParseStr
*/
/* parseAir.c */
Modified: teem/trunk/src/hest/hest.h
===================================================================
--- teem/trunk/src/hest/hest.h 2025-09-22 20:35:11 UTC (rev 7467)
+++ teem/trunk/src/hest/hest.h 2025-09-22 20:40:04 UTC (rev 7468)
@@ -50,11 +50,11 @@
* The blissfully-type-unaware hestOptAdd() has always relied on the airTypeT enum values
* below. Since that function is not being removed, to avoid needless code breakage with
* TeemV2, these values now live in this hest header. hest users should instead be using
- * the properly typed hestOptAdd_X_T functions, which have no need for airType
+ * one of the 99 properly typed hestOptAdd_X_T functions, which have no need for airType
* pseudo-types.
*
* Other things that used to be in air, but which really only mattered to implement hest
- * functions have been moved into privateHest.h, but with air --> hest renaming.
+ * functions have been moved into privateHest.h, but with air --> _hest renaming:
* #define AIR_TYPE_MAX
* const char airTypeStr[AIR_TYPE_MAX + 1][AIR_STRLEN_SMALL + 1];
* const size_t airTypeSize[AIR_TYPE_MAX + 1];
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-22 20:35:14
|
Revision: 7467
http://sourceforge.net/p/teem/code/7467
Author: kindlmann
Date: 2025-09-22 20:35:11 +0000 (Mon, 22 Sep 2025)
Log Message:
-----------
API CHANGE: removed: int hestMinNumArgs(const hestOpt *opt);
because it was not being used anywhere else in Teem
Also belatedly add `const` to: hestOptCheck(const hestOpt *opt, char **errP);
API NEW: added "int hestOptParmCheck(const hestOpt *opt, const hestParm *hparm, char **errP);
for checking a hestOpt and a non-NULL hestParm together
2025 rewrite continues, and now a lot more of hest uses biff internally
Modified Paths:
--------------
teem/trunk/src/hest/hest.h
teem/trunk/src/hest/methodsHest.c
teem/trunk/src/hest/parseHest.c
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/privateHest.h
teem/trunk/src/hest/test/tparse.c
teem/trunk/src/hest/usage.c
Modified: teem/trunk/src/hest/hest.h
===================================================================
--- teem/trunk/src/hest/hest.h 2025-09-22 20:29:18 UTC (rev 7466)
+++ teem/trunk/src/hest/hest.h 2025-09-22 20:35:11 UTC (rev 7467)
@@ -183,7 +183,9 @@
/* --------------------- Output
Things set/allocated by hestParse. */
- /* from the hestSource* enum; from whence was this information learned */
+ /* from the hestSource* enum; from whence was this information learned. Can use
+ hestSourceUser(opt->source) to test for the sources associated with the user:
+ hestSourceCommandLine or hestSourceResponseFile */
int source;
/* if parseStr is non-NULL: a string (freed by hestParseFree) that is a lot like the
string (storing zero or many parameters), from which hestParse ultimately parsed
@@ -367,11 +369,12 @@
... /* unsigned int *sawP,
const airEnum *enm,
const hestCB *CB */);
-// SEE ALSO all the special-purpose and type-checked versions in adders.c, below
+// SEE ALSO (from adders.c) all the 99 type-checked versions of hestOptAdd_, below!
HEST_EXPORT unsigned int hestOptNum(const hestOpt *opt);
HEST_EXPORT hestOpt *hestOptFree(hestOpt *opt);
HEST_EXPORT void *hestOptFree_vp(void *opt);
-HEST_EXPORT int hestOptCheck(hestOpt *opt, char **errP);
+HEST_EXPORT int hestOptCheck(const hestOpt *opt, char **errP);
+HEST_EXPORT int hestOptParmCheck(const hestOpt *opt, const hestParm *hparm, char **errP);
// parseHest.c
HEST_EXPORT int hestParse(hestOpt *opt, int argc, const char **argv, char **errP,
@@ -384,7 +387,6 @@
// usage.c
HEST_EXPORT void _hestPrintStr(FILE *f, unsigned int indent, unsigned int already,
unsigned int width, const char *_str, int bslash);
-HEST_EXPORT int hestMinNumArgs(const hestOpt *opt);
HEST_EXPORT void hestUsage(FILE *file, const hestOpt *opt, const char *argv0,
const hestParm *hparm);
HEST_EXPORT void hestGlossary(FILE *file, const hestOpt *opt, const hestParm *hparm);
@@ -406,7 +408,7 @@
min < max; max >= 2 hestOptAdd_Nv_T 5 multiple variable parameters
The type T can be: Bool, Short, UShort, Int, UInt, Long, ULong, Size_t, Float, Double,
-Char, String, Enum, and Other. An airEnum* is passed with the T=Enum functions, or a
+Char, String, Enum, or Other. An airEnum* is passed with the T=Enum functions, or a
hestCB* is passed for the T=Other functions. The number of parameters *sawP that hestParm
saw on the command-line is passed for the _Nv_ options.
Modified: teem/trunk/src/hest/methodsHest.c
===================================================================
--- teem/trunk/src/hest/methodsHest.c 2025-09-22 20:29:18 UTC (rev 7466)
+++ teem/trunk/src/hest/methodsHest.c 2025-09-22 20:35:11 UTC (rev 7467)
@@ -113,9 +113,6 @@
.sense = AIR_FALSE};
const airEnum *const hestSource = &_hestSource;
-// see documentation in parseHest.c
-#define ME ((hparm && hparm->verbosity) ? me : "")
-
int
hestSourceUser(int src) {
return (hestSourceCommandLine == src || hestSourceResponseFile == src);
@@ -353,7 +350,8 @@
/*
hestOptSingleSet: a completely generic setter for a single hestOpt
-Note that this makes no attempt at error-checking; that is all in hestOptCheck
+Note that this makes no attempt at error-checking; that is all in _hestOPCheck.
+*THIS* is the function that sets opt->kind.
*/
void
hestOptSingleSet(hestOpt *opt, const char *flag, const char *name, int type,
@@ -392,15 +390,11 @@
/*
hestOptAdd_nva: A new (as of 2023) non-var-args ("_nva") version of hestOptAdd;
-now hestOptAdd is a wrapper around this. And, the per-hestOpt logic has now
-been moved to hestOptSingleSet.
+The per-hestOpt logic (including setting opt->kind) has now been moved to
+hestOptSingleSet. The venerable var-args hestOptAdd is now a wrapper around this.
+and the 99 non-var-args hestOptAdd_* functions also all call this.
Like hestOptAdd has done since 2013: returns UINT_MAX in case of error.
-
-Note: (as of 2023) you probably shouldn't use this function; instead use
-one of hestOptAdd_Flag, hestOptAdd_1_T, hestOptAdd_{2,3,4,N}_T, hestOptAdd_1v_T,
-or hestOptAdd_Nv_T for T=Bool, Int, UInt, LongInt, ULongInt, Size_t, Float, Double,
-Char, String, Enum, Other
*/
unsigned int
hestOptAdd_nva(hestOpt **optP, const char *flag, const char *name, int type,
@@ -425,9 +419,21 @@
}
/*
-** as of Sept 2013 this returns information: the index of the
-** option just added. Returns UINT_MAX in case of error.
-*/
+ * hestOptAdd
+ *
+ * Until 2023, this was the main way of using hest: a var-args function that could do no
+ * useful type-checking, and was very easy to call incorrectly, leading to inscrutable
+ * errors.
+ *
+ * Now, thankfully, you have 99 better hestOptAdd_ functions to use instead:
+ * hestOptAdd_Flag, hestOptAdd_1_T, hestOptAdd_{2,3,4,N}_T, hestOptAdd_1v_T, or
+ * hestOptAdd_Nv_T for T=Bool, Short, UShort, Int, UInt, LongInt, ULongInt, Size_t,
+ * Float, Double, Char, String, Enum, or Other.
+ *
+ * This returns the index of the option just added, to so the caller can remember it and
+ * this speed up later checking the `hestOpt->source` to learn where how the option was
+ * parsed. Returns UINT_MAX in case of error.
+ */
unsigned int
hestOptAdd(hestOpt **optP, const char *flag, const char *name, int type,
unsigned int min, int max, void *valueP, const char *dflt, const char *info,
@@ -487,181 +493,150 @@
}
/*
-_hestOptCheck() (formerly _hestPanic, in parseHest.c)
-
-This performs the validation of the given hestOpt array itself (not the command line to
-be parsed), with descriptive error messages sprintf'ed into err, if given. hestOptCheck()
-is the expected way for users to access this.
-
-Prior to 2023 code revisit; this used to set the "kind" in all the opts but now that is
-more appropriately done at the time the option is added (by hestOptAdd, hestOptAdd_nva,
-hestOptSingleSet, or hestOptAdd_*_*)
-*/
+ * _hestOPCheck
+ *
+ * new biff-based container for all logic that used to be in _hestOptCheck (which is
+ * the 2025 rename of _hestPanic): the validation of the given hestOpt array `opt` itself
+ * (but *not* anything about the command-line or its parsing), relative to the given
+ * (non-NULL) hestParm `hparm`.
+ *
+ * Pre-2025, hest did not depend on biff, and this instead took a 'char *err' that
+ * somehow magically had to be allocated for the size of any possible error message
+ * generated here. The 2025 re-write recognized that biff is the right way to accumulate
+ * error messages, but the use of biff is internal to biff, but not (unusually for Teem)
+ * part of the the expected use of biff's API. Thus, public functions hestOptCheck() and
+ * hestOptParmCheck(), which are the expected way to access the functionality herein,
+ * take a `char **errP` arg into which a message is sprintf'ed, after allocation.
+ *
+ * The shift to using biff removed how this function used to fprintf(stderr) some message
+ * like "panic 0.5" which as completely uninformative. Now, hestOptCheck() and
+ * hestOptParmCheck() fprintf(stderr) the biff message.
+ *
+ * Prior to 2023 code revisit: this used to set the "kind" in all the opts, but now that
+ * is more appropriately done at the time the option is added.
+ */
int
-_hestOptCheck(const hestOpt *opt, char *err, const hestParm *hparm) {
- /* see note on ME (at top) for why me[] ends with ": " */
- static const char me[] = "_hestOptCheck: ";
- char tbuff[AIR_STRLEN_HUGE + 1], *sep;
- int numvar, opi, optNum;
-
- optNum = hestOptNum(opt);
- numvar = 0;
- for (opi = 0; opi < optNum; opi++) {
+_hestOPCheck(const hestOpt *opt, const hestParm *hparm) {
+ if (!(opt && hparm)) {
+ biffAddf(HEST, "%s: got NULL opt (%p) or hparm (%p)", __func__, AIR_VOIDP(opt),
+ AIR_VOIDP(hparm));
+ return 1;
+ }
+ uint optNum = opt->arrLen;
+ uint varNum = 0; // number of variable-parameter options
+ for (uint opi = 0; opi < optNum; opi++) {
if (!(AIR_IN_OP(airTypeUnknown, opt[opi].type, airTypeLast))) {
- if (err)
- sprintf(err, "%sopt[%d].type (%d) not in valid range [%d,%d]", ME, opi,
- opt[opi].type, airTypeUnknown + 1, airTypeLast - 1);
- else
- fprintf(stderr, "%s: panic 0\n", me);
+ biffAddf(HEST, "%s: opt[%u].type (%d) not in valid range [%d,%d]", __func__, opi,
+ opt[opi].type, airTypeUnknown + 1, airTypeLast - 1);
return 1;
}
if (!(opt[opi].valueP)) {
- if (err)
- sprintf(err, "%sopt[%d]'s valueP is NULL!", ME, opi);
- else
- fprintf(stderr, "%s: panic 0.5\n", me);
+ biffAddf(HEST, "%s: opt[%u]'s valueP is NULL!", __func__, opi);
return 1;
}
+ // `kind` set by hestOptSingleSet
if (-1 == opt[opi].kind) {
- if (err)
- sprintf(err, "%sopt[%d]'s min (%d) and max (%d) incompatible", ME, opi,
- opt[opi].min, opt[opi].max);
- else
- fprintf(stderr, "%s: panic 1\n", me);
+ biffAddf(HEST, "%s: opt[%u]'s min (%d) and max (%d) incompatible", __func__, opi,
+ opt[opi].min, opt[opi].max);
return 1;
}
if (5 == opt[opi].kind && !(opt[opi].sawP)) {
- if (err)
- sprintf(err,
- "%shave multiple variable parameters, "
- "but sawP is NULL",
- ME);
- else
- fprintf(stderr, "%s: panic 2\n", me);
+ biffAddf(HEST,
+ "%s: have multiple variable parameters, "
+ "but sawP is NULL",
+ __func__);
return 1;
}
if (airTypeEnum == opt[opi].type) {
if (!(opt[opi].enm)) {
- if (err) {
- sprintf(err,
- "%sopt[%d] (%s) is type \"enum\", but no "
- "airEnum pointer given",
- ME, opi, opt[opi].flag ? opt[opi].flag : "?");
- } else {
- fprintf(stderr, "%s: panic 3\n", me);
- }
+ biffAddf(HEST,
+ "%s: opt[%u] (%s) is type \"enum\", but no "
+ "airEnum pointer given",
+ __func__, opi, opt[opi].flag ? opt[opi].flag : "?");
return 1;
}
}
if (airTypeOther == opt[opi].type) {
if (!(opt[opi].CB)) {
- if (err) {
- sprintf(err,
- "%sopt[%d] (%s) is type \"other\", but no "
- "callbacks given",
- ME, opi, opt[opi].flag ? opt[opi].flag : "?");
- } else {
- fprintf(stderr, "%s: panic 4\n", me);
- }
+ biffAddf(HEST,
+ "%s: opt[%u] (%s) is type \"other\", but no "
+ "callbacks given",
+ __func__, opi, opt[opi].flag ? opt[opi].flag : "?");
return 1;
}
if (!(opt[opi].CB->size > 0)) {
- if (err)
- sprintf(err, "%sopt[%d]'s \"size\" (%d) invalid", ME, opi,
- (int)(opt[opi].CB->size));
- else
- fprintf(stderr, "%s: panic 5\n", me);
+ biffAddf(HEST, "%s: opt[%u]'s \"size\" (%u) invalid", __func__, opi,
+ (uint)(opt[opi].CB->size));
return 1;
}
if (!(opt[opi].CB->type)) {
- if (err)
- sprintf(err, "%sopt[%d]'s \"type\" is NULL", ME, opi);
- else
- fprintf(stderr, "%s: panic 6\n", me);
+ biffAddf(HEST, "%s: opt[%u]'s \"type\" is NULL", __func__, opi);
return 1;
}
if (!(opt[opi].CB->parse)) {
- if (err)
- sprintf(err, "%sopt[%d]'s \"parse\" callback NULL", ME, opi);
- else
- fprintf(stderr, "%s: panic 7\n", me);
+ biffAddf(HEST, "%s: opt[%u]'s \"parse\" callback NULL", __func__, opi);
return 1;
}
if (opt[opi].CB->destroy && (sizeof(void *) != opt[opi].CB->size)) {
- if (err)
- sprintf(err,
- "%sopt[%d] has a \"destroy\", but size %lu isn't "
- "sizeof(void*)",
- ME, opi, (unsigned long)(opt[opi].CB->size));
- else
- fprintf(stderr, "%s: panic 8\n", me);
+ biffAddf(HEST,
+ "%sopt[%u] has a \"destroy\", but size %lu isn't "
+ "sizeof(void*)",
+ __func__, opi, (unsigned long)(opt[opi].CB->size));
return 1;
}
}
if (opt[opi].flag) {
- strcpy(tbuff, opt[opi].flag);
+ char *tbuff = airStrdup(opt[opi].flag);
+ if (!tbuff) {
+ biffAddf(HEST, "%s: could not strdup() opi[%u].flag", __func__, opi);
+ return 1;
+ }
+ // no map, have to call free(tbuff) !
+ char *sep;
if ((sep = strchr(tbuff, MULTI_FLAG_SEP))) {
*sep = '\0';
if (!(strlen(tbuff) && strlen(sep + 1))) {
- if (err)
- sprintf(err,
- "%seither short (\"%s\") or long (\"%s\") flag"
- " of opt[%d] is zero length",
- ME, tbuff, sep + 1, opi);
- else
- fprintf(stderr, "%s: panic 9\n", me);
- return 1;
+ biffAddf(HEST,
+ "%s: either short (\"%s\") or long (\"%s\") flag"
+ " of opt[%u] is zero length",
+ __func__, tbuff, sep + 1, opi);
+ return (free(tbuff), 1);
}
if (hparm->respectDashDashHelp && !strcmp("help", sep + 1)) {
- if (err)
- sprintf(err,
- "%slong \"--%s\" flag of opt[%d] is same as \"--help\" "
- "that requested hparm->respectDashDashHelp handles separately",
- ME, sep + 1, opi);
- else
- fprintf(stderr, "%s: panic 9.5\n", me);
- return 1;
+ biffAddf(HEST,
+ "%s: long \"--%s\" flag of opt[%u] is same as \"--help\" "
+ "that requested hparm->respectDashDashHelp handles separately",
+ __func__, sep + 1, opi);
+ return (free(tbuff), 1);
}
} else {
if (!strlen(opt[opi].flag)) {
- if (err)
- sprintf(err, "%sopt[%d].flag is zero length", ME, opi);
- else
- fprintf(stderr, "%s: panic 10\n", me);
- return 1;
+ biffAddf(HEST, "%s: opt[%u].flag is zero length", __func__, opi);
+ return (free(tbuff), 1);
}
}
if (hparm->respectDashBraceComments
&& (strchr(opt[opi].flag, '{') || strchr(opt[opi].flag, '}'))) {
- if (err)
- sprintf(err,
- "%srequested hparm->respectDashBraceComments but opt[%d]'s flag "
- "\"%s\" confusingly contains '{' or '}'",
- ME, opi, opt[opi].flag);
- else
- fprintf(stderr, "%s: panic 10.5\n", me);
- return 1;
+ biffAddf(HEST,
+ "%s: requested hparm->respectDashBraceComments but opt[%u]'s flag "
+ "\"%s\" confusingly contains '{' or '}'",
+ __func__, opi, opt[opi].flag);
+ return (free(tbuff), 1);
}
if (4 == opt[opi].kind) {
if (!opt[opi].dflt) {
- if (err)
- sprintf(err,
- "%sflagged single variable parameter must "
- "specify a default",
- ME);
- else
- fprintf(stderr, "%s: panic 11\n", me);
- return 1;
+ biffAddf(HEST,
+ "%s: flagged single variable parameter must "
+ "specify a default",
+ __func__);
+ return (free(tbuff), 1);
}
if (!strlen(opt[opi].dflt)) {
- if (err)
- sprintf(err,
- "%sflagged single variable parameter default "
- "must be non-zero length",
- ME);
- else
- fprintf(stderr, "%s: panic 12\n", me);
- return 1;
+ biffAddf(HEST,
+ "%s: flagged single variable parameter default "
+ "must be non-zero length",
+ __func__);
+ return (free(tbuff), 1);
}
}
/*
@@ -668,47 +643,37 @@
sprintf(tbuff, "-%s", opt[op].flag);
if (1 == sscanf(tbuff, "%f", &tmpF)) {
if (err)
- sprintf(err, "%sopt[%d].flag (\"%s\") is numeric, bad news",
+ sprintf(err, "%sopt[%u].flag (\"%s\") is numeric, bad news",
ME, op, opt[op].flag);
return 1;
}
*/
}
+ // ------ end of if (opt[opi].flag)
if (1 == opt[opi].kind) {
if (!opt[opi].flag) {
- if (err)
- sprintf(err, "%sflags must have flags", ME);
- else
- fprintf(stderr, "%s: panic 13\n", me);
+ biffAddf(HEST, "%s: opt[%u] flag must have a flag", __func__, opi);
return 1;
}
} else {
if (!opt[opi].name) {
- if (err)
- sprintf(err, "%sopt[%d] isn't a flag: must have \"name\"", ME, opi);
- else
- fprintf(stderr, "%s: panic 14\n", me);
+ biffAddf(HEST, "%s: opt[%u] isn't a flag: must have \"name\"", __func__, opi);
return 1;
}
}
if (4 == opt[opi].kind && !opt[opi].dflt) {
- if (err)
- sprintf(err,
- "%sopt[%d] is single variable parameter, but "
- "no default set",
- ME, opi);
- else
- fprintf(stderr, "%s: panic 15\n", me);
+ biffAddf(HEST,
+ "%s: opt[%u] is single variable parameter, but "
+ "no default set",
+ __func__, opi);
return 1;
}
- numvar += ((int)opt[opi].min < _hestMax(opt[opi].max)
+ varNum += ((int)opt[opi].min < _hestMax(opt[opi].max)
&& (NULL == opt[opi].flag)); /* HEY scrutinize casts */
}
- if (numvar > 1) {
- if (err)
- sprintf(err, "%scan't have %d unflagged min<max opts, only one", ME, numvar);
- else
- fprintf(stderr, "%s: panic 16\n", me);
+ if (varNum > 1) {
+ biffAddf(HEST, "%s: can't have %u unflagged min<max options, only one", __func__,
+ varNum);
return 1;
}
return 0;
@@ -725,30 +690,21 @@
return AIR_VOIDP(hestOptFree((hestOpt *)_opt));
}
+/*
+ * hestOptCheck: check given hestOpt array `opt`, using the default hestParm.
+ * Puts any errors into newly allocated (caller responsible to free) `*errP`.
+ */
int
-hestOptCheck(hestOpt *opt, char **errP) {
- static const char me[] = "hestOptCheck";
- char *err;
- hestParm *hparm;
- int big;
-
- big = _hestErrStrlen(opt, 0, NULL);
- if (!(err = AIR_CALLOC(big, char))) {
- fprintf(stderr,
- "%s PANIC: couldn't allocate error message "
- "buffer (size %d)\n",
- me, big);
- if (errP) *errP = NULL;
- return 1;
- }
- hparm = hestParmNew();
- if (_hestOptCheck(opt, err, hparm)) {
- /* problems */
+hestOptCheck(const hestOpt *opt, char **errP) {
+ hestParm *hparm = hestParmNew();
+ if (_hestOPCheck(opt, hparm)) {
+ char *err = biffGetDone(HEST);
if (errP) {
/* they did give a pointer address; they'll free it */
*errP = err;
} else {
- /* they didn't give a pointer address; their loss */
+ /* they didn't give a pointer address; we dump to stderr */
+ fprintf(stderr, "%s: problem with given hestOpt array:\n%s", __func__, err);
free(err);
}
hestParmFree(hparm);
@@ -756,7 +712,31 @@
}
/* else, no problems */
if (errP) *errP = NULL;
- free(err);
hestParmFree(hparm);
return 0;
}
+
+/*
+ * hestOptParmCheck: check given hestOpt array `opt` in combination with the given
+ * hestParm `hparm`. Puts any errors into newly allocated (caller responsible to free)
+ * `*errP`.
+ * HEY copy-pasta
+ */
+int
+hestOptParmCheck(const hestOpt *opt, const hestParm *hparm, char **errP) {
+ if (_hestOPCheck(opt, hparm)) {
+ char *err = biffGetDone(HEST);
+ if (errP) {
+ /* they did give a pointer address; they'll free it */
+ *errP = err;
+ } else {
+ /* they didn't give a pointer address; we dump to stderr */
+ fprintf(stderr, "%s: problem with given hestOpt array:\n%s", __func__, err);
+ free(err);
+ }
+ return 1;
+ }
+ /* else, no problems */
+ if (errP) *errP = NULL;
+ return 0;
+}
Modified: teem/trunk/src/hest/parseHest.c
===================================================================
--- teem/trunk/src/hest/parseHest.c 2025-09-22 20:29:18 UTC (rev 7466)
+++ teem/trunk/src/hest/parseHest.c 2025-09-22 20:35:11 UTC (rev 7467)
@@ -46,7 +46,7 @@
single arg, and we do not do any VTAB-separating of args here.
*/
static int
-argsInResponseFiles(int *argsNumP, int *respFileNumP, const char **argv, char *err,
+argsInResponseFiles(int *argsNumP, int *respFileNumP, const char **argv,
const hestParm *hparm) {
FILE *file;
static const char me[] = "argsInResponseFiles: ";
@@ -69,7 +69,7 @@
again by copyArgv */
if (!(file = fopen(argv[argIdx] + 1, "rb"))) {
/* can't open the indicated response file for reading */
- sprintf(err, "%scouldn't open \"%s\" for reading as response file", ME,
+ fprintf(stderr, "%scouldn't open \"%s\" for reading as response file", ME,
argv[argIdx] + 1);
*argsNumP = 0;
*respFileNumP = 0;
@@ -225,35 +225,10 @@
return newArgc;
}
-uint
-_hestErrStrlen(const hestOpt *opt, int argc, const char **argv) {
- uint ret = 0;
- uint optNum = hestOptNum(opt);
- int other = AIR_FALSE;
- if (argv) {
- for (uint ai = 0; ai < (uint)argc; ai++) {
- ret = AIR_MAX(ret, airStrlen(argv[ai]));
- }
- }
- for (uint ai = 0; ai < optNum; ai++) {
- ret = AIR_MAX(ret, airStrlen(opt[ai].flag));
- ret = AIR_MAX(ret, airStrlen(opt[ai].name));
- other |= opt[ai].type == airTypeOther;
- }
- for (uint ai = airTypeUnknown + 1; ai < airTypeLast; ai++) {
- ret = AIR_MAX(ret, airStrlen(_hestTypeStr[ai]));
- }
- if (other) {
- /* the callback's error() function may sprintf an error message
- into a buffer which is size AIR_STRLEN_HUGE+1 */
- ret += AIR_STRLEN_HUGE + 1;
- }
- ret += 4 * 12; /* as many as 4 ints per error message */
- ret += 257; /* function name and text of hest's error message */
+/* uint _hestErrStrlen(const hestOpt *opt, int argc, const char **argv) ...
+ * This was a bad idea, so has been removed for TeemV2. Now hest internally uses biff
+ */
- return ret;
-}
-
/*
identStr()
copies into ident a string for identifying an option in error and usage messages
@@ -423,8 +398,7 @@
*/
static int
extractFlagged(char **optParms, unsigned int *optParmNum, int *optAprd, int *argcP,
- char **argv, hestOpt *opt, char *err, const hestParm *hparm,
- airArray *pmop) {
+ char **argv, hestOpt *opt, const hestParm *hparm, airArray *pmop) {
/* see note on ME (at top) for why me[] ends with ": " */
static const char me[] = "extractFlagged: ";
char ident1[AIR_STRLEN_HUGE + 1], ident2[AIR_STRLEN_HUGE + 1];
@@ -474,20 +448,20 @@
if (parmNum < (int)opt[optIdx].min) { /* HEY scrutinize casts */
/* didn't get minimum number of parameters */
if (!(argIdx + parmNum + 1 <= *argcP - 1)) {
- sprintf(err,
+ fprintf(stderr,
"%sgot to end of line before getting %d parameter%s "
- "for %s (got %d)",
+ "for %s (got %d)\n",
ME, opt[optIdx].min, opt[optIdx].min > 1 ? "s" : "",
identStr(ident1, opt + optIdx, hparm, AIR_TRUE), parmNum);
} else if (-2 != nextOptIdx) {
- sprintf(err, "%ssaw %s before getting %d parameter%s for %s (got %d)", ME,
+ fprintf(stderr, "%ssaw %s before getting %d parameter%s for %s (got %d)\n", ME,
identStr(ident1, opt + nextOptIdx, hparm, AIR_FALSE), opt[optIdx].min,
opt[optIdx].min > 1 ? "s" : "",
identStr(ident2, opt + optIdx, hparm, AIR_FALSE), parmNum);
} else {
- sprintf(err,
+ fprintf(stderr,
"%ssaw \"-%c\" (option-parameter-stop flag) before getting %d "
- "parameter%s for %s (got %d)",
+ "parameter%s for %s (got %d)\n",
ME, VAR_PARM_STOP_FLAG, opt[optIdx].min, opt[optIdx].min > 1 ? "s" : "",
identStr(ident2, opt + optIdx, hparm, AIR_FALSE), parmNum);
}
@@ -528,7 +502,7 @@
optNum = hestOptNum(opt);
for (op = 0; op < optNum; op++) {
if (1 != opt[op].kind && opt[op].flag && !opt[op].dflt && !optAprd[op]) {
- sprintf(err, "%sdidn't get required %s", ME,
+ fprintf(stderr, "%sdidn't get required %s\n", ME,
identStr(ident1, opt + op, hparm, AIR_FALSE));
return 1;
}
@@ -560,7 +534,7 @@
*/
static int
extractUnflagged(char **optParms, unsigned int *optParmNum, int *argcP, char **argv,
- hestOpt *opt, char *err, const hestParm *hparm, airArray *pmop) {
+ hestOpt *opt, const hestParm *hparm, airArray *pmop) {
/* see note on ME (at top) for why me[] ends with ": " */
static const char me[] = "extractUnflagged: ";
char ident[AIR_STRLEN_HUGE + 1];
@@ -597,8 +571,8 @@
}
np = opt[op].min; /* min == max, as implied by how unflagVar was set */
if (!(np <= *argcP)) {
- sprintf(err, "%sdon't have %d parameter%s %s%s%sfor %s", ME, np, np > 1 ? "s" : "",
- argv[0] ? "starting at \"" : "", argv[0] ? argv[0] : "",
+ fprintf(stderr, "%sdon't have %d parameter%s %s%s%sfor %s\n", ME, np,
+ np > 1 ? "s" : "", argv[0] ? "starting at \"" : "", argv[0] ? argv[0] : "",
argv[0] ? "\" " : "", identStr(ident, opt + op, hparm, AIR_TRUE));
return 1;
}
@@ -618,7 +592,7 @@
if (nvp < 0) {
op = nextUnflagged(unflagVar + 1, opt, optNum);
np = opt[op].min;
- sprintf(err, "%sdon't have %d parameter%s for %s", ME, np, np > 1 ? "s" : "",
+ fprintf(stderr, "%sdon't have %d parameter%s for %s\n", ME, np, np > 1 ? "s" : "",
identStr(ident, opt + op, hparm, AIR_FALSE));
return 1;
}
@@ -651,7 +625,7 @@
triggered this error message when there were zero given parms, but the default
could have supplied them */
if (nvp < AIR_INT(opt[unflagVar].min)) {
- sprintf(err, "%sdidn't get minimum of %d arg%s for %s (got %d)", ME,
+ fprintf(stderr, "%sdidn't get minimum of %d arg%s for %s (got %d)\n", ME,
opt[unflagVar].min, opt[unflagVar].min > 1 ? "s" : "",
identStr(ident, opt + unflagVar, hparm, AIR_TRUE), nvp);
return 1;
@@ -673,7 +647,7 @@
static int
_hestDefaults(char **optParms, int *optDfltd, unsigned int *optParmNum,
- const int *optAprd, const hestOpt *opt, char *err, const hestParm *hparm,
+ const int *optAprd, const hestOpt *opt, const hestParm *hparm,
airArray *mop) {
/* see note on ME (at top) for why me[] ends with ": " */
static const char me[] = "_hestDefaults: ";
@@ -756,14 +730,16 @@
if (!AIR_IN_CL(AIR_INT(opt[optIdx].min), AIR_INT(optParmNum[optIdx]),
_hestMax(opt[optIdx].max))) {
if (-1 == opt[optIdx].max) {
- sprintf(err, "%s# parameters (in default) for %s is %d, but need %d or more",
- ME, identStr(ident, opt + optIdx, hparm, AIR_TRUE), optParmNum[optIdx],
+ fprintf(stderr,
+ "%s# parameters (in default) for %s is %d, but need %d or more\n", ME,
+ identStr(ident, opt + optIdx, hparm, AIR_TRUE), optParmNum[optIdx],
opt[optIdx].min);
} else {
- sprintf(err,
- "%s# parameters (in default) for %s is %d, but need between %d and %d",
- ME, identStr(ident, opt + optIdx, hparm, AIR_TRUE), optParmNum[optIdx],
- opt[optIdx].min, _hestMax(opt[optIdx].max));
+ fprintf(
+ stderr,
+ "%s# parameters (in default) for %s is %d, but need between %d and %d\n", ME,
+ identStr(ident, opt + optIdx, hparm, AIR_TRUE), optParmNum[optIdx],
+ opt[optIdx].min, _hestMax(opt[optIdx].max));
}
return 1;
}
@@ -884,7 +860,7 @@
static int
setValues(char **optParms, int *optDfltd, unsigned int *optParmNum, int *appr,
- hestOpt *opt, char *err, const hestParm *hparm, airArray *pmop) {
+ hestOpt *opt, const hestParm *hparm, airArray *pmop) {
/* see note on ME (at top) for why me[] ends with ": " */
static const char me[] = "setValues: ";
char ident[AIR_STRLEN_HUGE + 1], cberr[AIR_STRLEN_HUGE + 1], *tok, *last,
@@ -937,7 +913,7 @@
switch (type) {
case airTypeEnum:
if (1 != airParseStrE((int *)vP, optParms[op], " ", 1, opt[op].enm)) {
- sprintf(err, "%scouldn\'t parse %s\"%s\" as %s for %s", ME,
+ fprintf(stderr, "%scouldn\'t parse %s\"%s\" as %s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], opt[op].enm->name,
ident);
return 1;
@@ -948,10 +924,10 @@
ret = opt[op].CB->parse(vP, optParms[op], cberr);
if (ret) {
if (strlen(cberr)) {
- sprintf(err, "%serror parsing \"%s\" as %s for %s:\n%s", ME, optParms[op],
- opt[op].CB->type, ident, cberr);
+ fprintf(stderr, "%serror parsing \"%s\" as %s for %s:\n%s\n", ME,
+ optParms[op], opt[op].CB->type, ident, cberr);
} else {
- sprintf(err, "%serror parsing \"%s\" as %s for %s: returned %d", ME,
+ fprintf(stderr, "%serror parsing \"%s\" as %s for %s: returned %d\n", ME,
optParms[op], opt[op].CB->type, ident, ret);
}
return ret;
@@ -967,7 +943,7 @@
if (1
!= airParseStrS((char **)vP, optParms[op], " ", 1
/*, hparm->greedySingleString */)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], _hestTypeStr[type],
ident);
return 1;
@@ -980,7 +956,7 @@
default:
/* type isn't string or enum, so no last arg to hestParseStr[type] */
if (1 != _hestParseStr[type](vP, optParms[op], " ", 1)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], _hestTypeStr[type],
ident);
return 1;
@@ -996,7 +972,7 @@
case airTypeEnum:
if (opt[op].min != /* min == max */
airParseStrE((int *)vP, optParms[op], " ", opt[op].min, opt[op].enm)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %d %s%s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], opt[op].min,
opt[op].enm->name, opt[op].min > 1 ? "s" : "", ident);
return 1;
@@ -1010,14 +986,14 @@
ret = opt[op].CB->parse(cP + p * size, tok, cberr);
if (ret) {
if (strlen(cberr))
- sprintf(err,
+ fprintf(stderr,
"%serror parsing \"%s\" (in \"%s\") as %s "
- "for %s:\n%s",
+ "for %s:\n%s\n",
ME, tok, optParms[op], opt[op].CB->type, ident, cberr);
else
- sprintf(err,
+ fprintf(stderr,
"%serror parsing \"%s\" (in \"%s\") as %s "
- "for %s: returned %d",
+ "for %s: returned %d\n",
ME, tok, optParms[op], opt[op].CB->type, ident, ret);
free(optParmsCopy);
return 1;
@@ -1036,7 +1012,7 @@
case airTypeString:
if (opt[op].min != /* min == max */
_hestParseStr[type](vP, optParms[op], " ", opt[op].min)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %d %s%s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], opt[op].min,
_hestTypeStr[type], opt[op].min > 1 ? "s" : "", ident);
return 1;
@@ -1051,7 +1027,7 @@
default:
if (opt[op].min != /* min == max */
_hestParseStr[type](vP, optParms[op], " ", opt[op].min)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %d %s%s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], opt[op].min,
_hestTypeStr[type], opt[op].min > 1 ? "s" : "", ident);
return 1;
@@ -1069,7 +1045,7 @@
/* no "inversion" for chars: using the flag with no parameter is the same as
not using the flag i.e. we just parse from the default string */
if (1 != _hestParseStr[type](vP, optParms[op], " ", 1)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], _hestTypeStr[type],
ident);
return 1;
@@ -1087,7 +1063,7 @@
pret = _hestParseStr[type](vP, optParms[op], " ",
1 /*, hparm->greedySingleString */);
if (1 != pret) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], _hestTypeStr[type],
ident);
return 1;
@@ -1104,7 +1080,7 @@
break;
case airTypeEnum:
if (1 != airParseStrE((int *)vP, optParms[op], " ", 1, opt[op].enm)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], opt[op].enm->name,
ident);
return 1;
@@ -1121,10 +1097,10 @@
ret = opt[op].CB->parse(vP, optParms[op], cberr);
if (ret) {
if (strlen(cberr))
- sprintf(err, "%serror parsing \"%s\" as %s for %s:\n%s", ME, optParms[op],
- opt[op].CB->type, ident, cberr);
+ fprintf(stderr, "%serror parsing \"%s\" as %s for %s:\n%s\n", ME,
+ optParms[op], opt[op].CB->type, ident, cberr);
else
- sprintf(err, "%serror parsing \"%s\" as %s for %s: returned %d", ME,
+ fprintf(stderr, "%serror parsing \"%s\" as %s for %s: returned %d\n", ME,
optParms[op], opt[op].CB->type, ident, ret);
return 1;
}
@@ -1137,7 +1113,7 @@
break;
default:
if (1 != _hestParseStr[type](vP, optParms[op], " ", 1)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], _hestTypeStr[type],
ident);
return 1;
@@ -1189,7 +1165,7 @@
if (optParmNum[op]
!= airParseStrE((int *)(*((void **)vP)), optParms[op], " ",
optParmNum[op], opt[op].enm)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %u %s%s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %u %s%s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], optParmNum[op],
opt[op].enm->name, optParmNum[op] > 1 ? "s" : "", ident);
return 1;
@@ -1216,15 +1192,15 @@
ret = opt[op].CB->parse(cP + p * size, tok, cberr);
if (ret) {
if (strlen(cberr))
- sprintf(err,
+ fprintf(stderr,
"%serror parsing \"%s\" (in \"%s\") as %s "
- "for %s:\n%s",
+ "for %s:\n%s\n",
ME, tok, optParms[op], opt[op].CB->type, ident, cberr);
else
- sprintf(err,
+ fprintf(stderr,
"%serror parsing \"%s\" (in \"%s\") as %s "
- "for %s: returned %d",
+ "for %s: returned %d\n",
ME, tok, optParms[op], opt[op].CB->type, ident, ret);
free(optParmsCopy);
return 1;
@@ -1247,7 +1223,7 @@
if (optParmNum[op]
!= airParseStrS((char **)(*((void **)vP)), optParms[op], " ",
optParmNum[op] /*, hparm->greedySingleString */)) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %d %s%s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], optParmNum[op],
_hestTypeStr[type], optParmNum[op] > 1 ? "s" : "", ident);
return 1;
@@ -1266,7 +1242,7 @@
if (optParmNum[op]
!= _hestParseStr[type](*((void **)vP), optParms[op], " ",
optParmNum[op])) {
- sprintf(err, "%scouldn't parse %s\"%s\" as %d %s%s for %s", ME,
+ fprintf(stderr, "%scouldn't parse %s\"%s\" as %d %s%s for %s\n", ME,
optDfltd[op] ? "(default) " : "", optParms[op], optParmNum[op],
_hestTypeStr[type], optParmNum[op] > 1 ? "s" : "", ident);
return 1;
@@ -1287,12 +1263,12 @@
** documentation?
*/
int
-hestParse(hestOpt *opt, int _argc, const char **_argv, char **_errP,
+hestParse(hestOpt *opt, int _argc, const char **_argv, char **errP,
const hestParm *_hparm) {
/* see note on ME (at top) for why me[] ends with ": " */
static const char me[] = "hestParse: ";
- char **argv, **optParms, *err;
- int a, argc, argc_used, respArgNum, *optAprd, *optDfltd, respFileNum, optNum, big, ret,
+ char **argv, **optParms;
+ int a, argc, argc_used, respArgNum, *optAprd, *optDfltd, respFileNum, optNum, ret,
sawHelp;
unsigned int *optParmNum;
airArray *mop;
@@ -1313,31 +1289,15 @@
/* how to const-correctly use hparm or _hparm in an expression */
#define HPARM (_hparm ? _hparm : hparm)
- /* -------- allocate the err string. To determine its size with total
- ridiculous safety we have to find the biggest things which can appear
- in the string. */
- big = _hestErrStrlen(opt, _argc, _argv);
- if (!(err = AIR_CALLOC(big, char))) {
- fprintf(stderr,
- "%s PANIC: couldn't allocate error message "
- "buffer (size %d)\n",
- me, big);
- /* exit(1); */
- }
- if (_errP) {
- /* if they care about the error string, than it is mopped only
- when there _wasn't_ an error */
- *_errP = err;
- airMopAdd(mop, _errP, (airMopper)airSetNull, airMopOnOkay);
- airMopAdd(mop, err, airFree, airMopOnOkay);
- } else {
- /* otherwise, we're making the error string just for our own
- convenience, and we'll always clean it up on exit */
- airMopAdd(mop, err, airFree, airMopAlways);
- }
-
/* -------- check on validity of the hestOpt array */
- if (_hestOptCheck(opt, err, HPARM)) {
+ if (_hestOPCheck(opt, HPARM)) {
+ char *err = biffGetDone(HEST);
+ if (errP) {
+ *errP = err;
+ } else {
+ airMopAdd(mop, err, airFree, airMopAlways);
+ fprintf(stderr, "%s: problem given hestOpt, hestParm:\n%s", __func__, err);
+ }
airMopError(mop);
return 1;
}
@@ -1360,7 +1320,7 @@
by seeing how many args are in the response files, and then adding
on the args from the actual argv (getting this right the first time
greatly simplifies the problem of eliminating memory leaks) */
- if (argsInResponseFiles(&respArgNum, &respFileNum, _argv, err, HPARM)) {
+ if (argsInResponseFiles(&respArgNum, &respFileNum, _argv, HPARM)) {
airMopError(mop);
return 1;
}
@@ -1393,7 +1353,7 @@
}
/* else !sawHelp; do sanity check on argc_used vs argc */
if (argc_used < argc) {
- sprintf(err, "%sargc_used %d < argc %d; sorry, confused", ME, argc_used, argc);
+ fprintf(stderr, "%sargc_used %d < argc %d; sorry, confused", ME, argc_used, argc);
airMopError(mop);
return 1;
}
@@ -1400,8 +1360,7 @@
/* -------- extract flags and their associated parameters from argv */
if (HPARM->verbosity) printf("%s: #### calling extractFlagged\n", me);
- if (extractFlagged(optParms, optParmNum, optAprd, &argc_used, argv, opt, err, HPARM,
- mop)) {
+ if (extractFlagged(optParms, optParmNum, optAprd, &argc_used, argv, opt, HPARM, mop)) {
airMopError(mop);
return 1;
}
@@ -1409,7 +1368,7 @@
/* -------- extract args for unflagged options */
if (HPARM->verbosity) printf("%s: #### calling extractUnflagged\n", me);
- if (extractUnflagged(optParms, optParmNum, &argc_used, argv, opt, err, HPARM, mop)) {
+ if (extractUnflagged(optParms, optParmNum, &argc_used, argv, opt, HPARM, mop)) {
airMopError(mop);
return 1;
}
@@ -1422,12 +1381,12 @@
char stops[3] = "-X";
stops[1] = VAR_PARM_STOP_FLAG;
if (strcmp(stops, argv[0])) {
- sprintf(err, "%sunexpected arg%s: \"%s\"", ME,
+ fprintf(stderr, "%sunexpected arg%s: \"%s\"\n", ME,
('-' == argv[0][0] ? " (or unrecognized flag)" : ""), argv[0]);
} else {
- sprintf(err,
+ fprintf(stderr,
"%sunexpected end-of-parameters flag \"%s\": "
- "not ending a flagged variable-parameter option",
+ "not ending a flagged variable-parameter option\n",
ME, stops);
}
airMopError(mop);
@@ -1436,7 +1395,7 @@
/* -------- learn defaults */
if (HPARM->verbosity) printf("%s: #### calling hestDefaults\n", me);
- if (_hestDefaults(optParms, optDfltd, optParmNum, optAprd, opt, err, HPARM, mop)) {
+ if (_hestDefaults(optParms, optDfltd, optParmNum, optAprd, opt, HPARM, mop)) {
airMopError(mop);
return 1;
}
@@ -1469,7 +1428,7 @@
/* -------- now, the actual parsing of values */
if (HPARM->verbosity) printf("%s: #### calling setValues\n", me);
/* this will also set hestOpt->parmStr */
- ret = setValues(optParms, optDfltd, optParmNum, optAprd, opt, err, HPARM, mop);
+ ret = setValues(optParms, optDfltd, optParmNum, optAprd, opt, HPARM, mop);
if (ret) {
airMopError(mop);
return ret;
@@ -1480,6 +1439,9 @@
parseEnd:
airMopOkay(mop);
+ if (*errP) {
+ *errP = NULL;
+ }
return 0;
}
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-22 20:29:18 UTC (rev 7466)
+++ teem/trunk/src/hest/parsest.c 2025-09-22 20:35:11 UTC (rev 7467)
@@ -618,15 +618,13 @@
/*
hestParse(2): parse the `argc`,`argv` commandline according to the hestOpt array `opt`.
-
+The basic phases of parsing are:
+0) Error checking on given `opt` array
*/
int
-hestParse2(hestOpt *opt, int argc, const char **argv, char **_errP,
+hestParse2(hestOpt *opt, int argc, const char **argv, char **errP,
const hestParm *_hparm) {
- /* how to const-correctly use hparm or _hparm in an expression */
-#define HPARM (_hparm ? _hparm : hparm)
-
// -------- initialize the mop
airArray *mop = airMopNew();
@@ -636,37 +634,31 @@
hparm = hestParmNew();
airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
}
+ // how to const-correctly use hparm or _hparm in an expression
+#define HPARM (_hparm ? _hparm : hparm)
if (HPARM->verbosity > 1) {
- printf("%s: hparm->verbosity %d\n", __func__, HPARM->verbosity);
+ printf("%s: (%s) hparm->verbosity %d\n", __func__, _hparm ? "given" : "default",
+ HPARM->verbosity);
}
- // -------- allocate the err string. We do it a dumb way for now.
- // TODO: make this allocation smarter
- uint eslen = 2 * AIR_STRLEN_HUGE;
- char *err = AIR_CALLOC(eslen + 1, char);
- assert(err);
- if (_errP) {
- // they care about the error string, so mop it only when there is _not_ an error
- *_errP = err;
- airMopAdd(mop, _errP, (airMopper)airSetNull, airMopOnOkay);
- airMopAdd(mop, err, airFree, airMopOnOkay);
- } else {
- /* otherwise, we're making the error string just for our own convenience,
- so we always clean it up on exit */
- airMopAdd(mop, err, airFree, airMopAlways);
+ // error string song and dance
+#define DO_ERR(WUT) \
+ char *err = biffGetDone(HEST); \
+ if (errP) { \
+ *errP = err; \
+ } else { \
+ fprintf(stderr, "%s: " WUT ":\n%s", __func__, err); \
+ free(err); \
}
- if (HPARM->verbosity > 1) {
- printf("%s: err %p\n", __func__, AIR_VOIDP(err));
- }
- // -------- check on validity of the hestOpt array
- if (_hestOptCheck(opt, err, HPARM)) {
- // error message has been sprinted into err
+ // --0--0--0--0--0-- check on validity of the hestOpt array
+ if (_hestOPCheck(opt, HPARM)) {
+ DO_ERR("problem with given hestOpt array");
airMopError(mop);
return 1;
}
if (HPARM->verbosity > 1) {
- printf("%s: _hestOptCheck passed\n", __func__);
+ printf("%s: _hestOPCheck passed\n", __func__);
}
// -------- allocate the state we use during parsing
@@ -683,16 +675,14 @@
// -------- initialize input stack w/ given argc,argv, then process it
if (histPushCommandLine(hist, argc, argv, HPARM)
|| histProcess(havec, &(opt->helpWanted), tharg, hist, HPARM)) {
- char *bferr = biffGetDone(HEST);
- airMopAdd(mop, bferr, airFree, airMopAlways);
- strcpy(err, bferr);
+ DO_ERR("problem with initial processing of command-line");
airMopError(mop);
return 1;
}
-
- // (debugging) have finished input stack, what argvec did it leave us with?
- hestArgVecPrint(__func__, havec);
-
+ if (HPARM->verbosity > 1) {
+ // have finished input stack, what argvec did it leave us with?
+ hestArgVecPrint(__func__, havec);
+ }
if (opt->helpWanted) {
// once the call for help is made, we respect it: clean up and return
airMopOkay(mop);
Modified: teem/trunk/src/hest/privateHest.h
===================================================================
--- teem/trunk/src/hest/privateHest.h 2025-09-22 20:29:18 UTC (rev 7466)
+++ teem/trunk/src/hest/privateHest.h 2025-09-22 20:35:11 UTC (rev 7467)
@@ -73,11 +73,8 @@
extern const char *const _hestBiffKey;
extern int _hestKind(const hestOpt *opt);
extern int _hestMax(int max);
-extern int _hestOptCheck(const hestOpt *opt, char *err, const hestParm *parm);
+extern int _hestOPCheck(const hestOpt *opt, const hestParm *parm);
-/* parseHest.c */
-extern uint _hestErrStrlen(const hestOpt *opt, int argc, const char **argv);
-
#ifdef __cplusplus
}
#endif
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-22 20:29:18 UTC (rev 7466)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-22 20:35:11 UTC (rev 7467)
@@ -34,7 +34,7 @@
hestParm *hparm = hestParmNew();
hparm->respectDashDashHelp = AIR_TRUE;
hparm->responseFileEnable = AIR_TRUE;
- hparm->verbosity = 0;
+ hparm->verbosity = 10;
int res[2];
hestOptAdd_2_Int(&opt, "res", "sx sy", res, NULL, "image resolution");
Modified: teem/trunk/src/hest/usage.c
===================================================================
--- teem/trunk/src/hest/usage.c 2025-09-22 20:29:18 UTC (rev 7466)
+++ teem/trunk/src/hest/usage.c 2025-09-22 20:35:11 UTC (rev 7467)
@@ -134,67 +134,6 @@
free(str);
}
-/*
-******** hestMinNumArgs
-
-The idea is that this helps quickly determine if the options given on the command line
-are insufficient, in order to produce general usage information instead of some specific
-parse error.
-
-Because hest is strictly agnostic with respect to how many command-line arguments
-actually constitute the command itself ("rmdir": one argument, "svn checkout": two
-arguments), it only concerns itself with the command-line arguments following the
-command aka argv[0].
-
-Thus, hestMinMinArgs() returns the minimum number of command-line arguments (following
-the command) that could be valid. If your command is only one argument (like "rmdir"),
-then you might use the true argc passed by the OS to main() as such:
-
- if (argc-1 < hestMinNumArgs(opt)) {
- ... usage ...
- }
-
-But if your command is two arguments (like "svn checkout"):
-
- if (argc-2 < hestMinNumArgs(opt)) {
- ... usage ...
- }
-
-HOWEVER! don't forget the response files can complicate all this: in one argument a
-response file can provide information for any number of arguments, and the argc itself is
-kind of meaningless. The code examples above only really apply when hparm->respFileEnable
-is false. For example, in unrrdu (private.h) we find:
-
- if ( (hparm->respFileEnable && !argc) ||
- (!hparm->respFileEnable && argc < hestMinNumArgs(opt)) ) {
- ... usage ...
- }
-
-*/
-int
-hestMinNumArgs(const hestOpt *opt) {
- hestParm *hparm;
- int i, count, numOpts;
-
- hparm = hestParmNew();
- if (_hestOptCheck(opt, NULL, hparm)) {
- hestParmFree(hparm);
- return _hestMax(-1);
- }
- count = 0;
- numOpts = hestOptNum(opt);
- for (i = 0; i < numOpts; i++) {
- if (!opt[i].dflt) {
- count += opt[i].min;
- if (!(0 == opt[i].min && 0 == opt[i].max)) {
- count += !!opt[i].flag;
- }
- }
- }
- hestParmFree(hparm);
- return count;
-}
-
#define HPARM (_hparm ? _hparm : hparm)
void
@@ -221,6 +160,12 @@
}
}
+// error string song and dance
+#define DO_ERR \
+ char *err = biffGetDone(HEST); \
+ fprintf(stderr, "%s: problem with given hestOpt array\n%s", __func__, err); \
+ free(err)
+
void
hestUsage(FILE *f, const hestOpt *opt, const char *argv0, const hestParm *_hparm) {
int i, numOpts;
@@ -228,12 +173,11 @@
Previous to the 2023 revisit, it was for max lenth 2*AIR_STRLEN_HUGE, but
test/ex6.c blew past that. May have to increment again in the future :) */
char buff[64 * AIR_STRLEN_HUGE + 1], tmpS[AIR_STRLEN_SMALL + 1];
- hestParm *hparm;
+ hestParm *hparm = _hparm ? NULL : hestParmNew();
- hparm = _hparm ? NULL : hestParmNew();
-
- if (_hestOptCheck(opt, NULL, HPARM)) {
+ if (_hestOPCheck(opt, HPARM)) {
/* we can't continue; the opt array is botched */
+ DO_ERR;
if (hparm) {
hestParmFree(hparm);
}
@@ -270,12 +214,11 @@
unsigned int len;
/* See note above about overflowing buff[] */
char buff[64 * AIR_STRLEN_HUGE + 1], tmpS[AIR_STRLEN_HUGE + 1];
- hestParm *hparm;
+ hestParm *hparm = _hparm ? NULL : hestParmNew();
- hparm = _hparm ? NULL : hestParmNew();
-
- if (_hestOptCheck(opt, NULL, HPARM)) {
+ if (_hestOPCheck(opt, HPARM)) {
/* we can't continue; the opt array is botched */
+ DO_ERR;
if (hparm) {
hestParmFree(hparm);
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-22 20:29:21
|
Revision: 7466
http://sourceforge.net/p/teem/code/7466
Author: kindlmann
Date: 2025-09-22 20:29:18 +0000 (Mon, 22 Sep 2025)
Log Message:
-----------
removing historical comment about a function hestMinNumArgs that's going away
Modified Paths:
--------------
teem/trunk/src/unrrdu/privateUnrrdu.h
Modified: teem/trunk/src/unrrdu/privateUnrrdu.h
===================================================================
--- teem/trunk/src/unrrdu/privateUnrrdu.h 2025-09-22 10:01:30 UTC (rev 7465)
+++ teem/trunk/src/unrrdu/privateUnrrdu.h 2025-09-22 20:29:18 UTC (rev 7466)
@@ -231,24 +231,6 @@
}
/*
-
-I nixed this because it meant unu invocations with only a
-few args (less than hestMinNumArgs()), which were botched
-because they were missing options, were not being described
-in the error messages.
-
-**
-** NB: below is an unidiomatic use of hestMinNumArgs(), because of
-** how unu's main invokes the "main" function of the different
-** commands. Normally the comparison is with argc-1, or argc-2
-** the case of cvs/svn-like commands.
-
-
-if ( (hparm->respFileEnable && !argc) || \
- (!hparm->respFileEnable && argc < hestMinNumArgs(opt)) ) { \
-*/
-
-/*
** NOTE: of all places it is inside the PARSE() macro that the
** "quiet-quit" functionality is implemented; this is defensible
** because all unu commands use PARSE
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-22 10:01:33
|
Revision: 7465
http://sourceforge.net/p/teem/code/7465
Author: kindlmann
Date: 2025-09-22 10:01:30 +0000 (Mon, 22 Sep 2025)
Log Message:
-----------
should now correctly emulate POSIC argument tokenization rules, with correct quoting
Modified Paths:
--------------
teem/trunk/src/hest/parsest.c
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-22 09:22:17 UTC (rev 7464)
+++ teem/trunk/src/hest/parsest.c 2025-09-22 10:01:30 UTC (rev 7465)
@@ -224,16 +224,29 @@
}
break;
case argstEscapeIn:
- case argstEscapeDQ:
if ('\n' == cc) {
// line continuation; ignore \ and \n
} else {
- // add escaped characters (including #) to arg
+ // add escaped character (including #) to arg
hestArgAddChar(tharg, cc);
}
- // either way, back to whatever we were in pre-escape
- *stateP = (argstEscapeIn == *stateP) ? argstInside : argstDoubleQ;
+ // back to unescaped input
+ *stateP = argstInside;
break;
+ case argstEscapeDQ:
+ if ('\n' == cc) {
+ // like above: line continuation; ignore \ and \n
+ } else if ('$' == cc || '\'' == cc || '\"' == cc || '\\' == cc) {
+ // add escaped character to arg
+ hestArgAddChar(tharg, cc);
+ } else {
+ // other character (needlessly) escaped, put in both \ and char
+ hestArgAddChar(tharg, '\\');
+ hestArgAddChar(tharg, cc);
+ }
+ // back to unescaped input
+ *stateP = argstDoubleQ;
+ break;
case argstComment:
if ('\n' == cc) {
// the newline has ended the comment, prepare for next arg
@@ -290,7 +303,8 @@
} else {
// we have gotten to the end of the given argv array, pop it as input source */
if (histPop(hist, hparm)) {
- biffAddf(HEST, "%s: trouble popping", __func__);
+ biffAddf(HEST, "%s: trouble popping %s", __func__,
+ airEnumStr(hestSource, hestSourceCommandLine));
return 1;
}
*nastP = nastTryAgain;
@@ -325,7 +339,13 @@
} else {
// we're at end; pop input; *nastP already set to nastTryAgain by argstGo()
if (histPop(hist, hparm)) {
- biffAddf(HEST, "%s: trouble popping", __func__);
+ if (hestSourceResponseFile == hin->source) {
+ biffAddf(HEST, "%s: trouble popping %s \"%s\"", __func__,
+ airEnumStr(hestSource, hin->source), hin->rfname);
+ } else {
+ biffAddf(HEST, "%s: trouble popping %s |%s|", __func__,
+ airEnumStr(hestSource, hin->source), hin->dfltStr);
+ }
return 1;
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-22 09:22:24
|
Revision: 7464
http://sourceforge.net/p/teem/code/7464
Author: kindlmann
Date: 2025-09-22 09:22:17 +0000 (Mon, 22 Sep 2025)
Log Message:
-----------
hestParse re-write work continues, and ...
air API CHANGE:
* airParseStrT() are no longer var-args; it was a mistaken way to enforce uniformity
across parsers for different types, and it was really only airParseStrE (for
parsing airEnum values) that needed it. Then airParseStrS sneakily used it for
its final "greedy" argument, which was also a bad idea to overcome bad ideas in
hestParse(), which have since been fixed with its 2025 re-write.
* Renamed airParseStrLI, airParseStrULI --> airParseStrL, airParseStrUL
* Added airParseStrH and airParseStrUH for signed and unsigned shorts
* Removed airStrtokQuoting (another bad idea; used only for "unu make")
* Moved the airTypeT enum values from air to hest, since hest was the motivation for
creating them so they should be localized to hest. To avoid needlessly breaking code
that uses hestOptAdd(), which depends on the airTypeT enum values, those have kept
their names, except:
*** added airTypeShort and airTypeUShort
*** renamed airTypeLongInt --> airTypeLong
*** renamed airTypeULongInt --> airTypeULong
* Removed the following from air to hest, renamed them, and made them private.
They were only used to implement hest, no where else in Teem, so they never
deserved to be in air:
#define AIR_TYPE_MAX --> _HEST_TYPE_MAX
const char airTypeStr[HEST_TYPE_MAX + 1][AIR_STRLEN_SMALL + 1] --> _hestTypeStr
const size_t airTypeSize[HEST_TYPE_MAX + 1] --> _hestTypeSize
unsigned int (*const airParseStr[AIR_TYPE_MAX + 1])(void *,
const char *, *const char *,
*unsigned int);
--> _hestParseStr
hest API CHANGE
* (as noted above: airType* enum values moved to hest.h)
* removed field from hestParm in hest.h:
greedySingleString, /* when parsing a single string, whether or not to be greedy
(as per airParseStrS) */
* removed the corresponding default from defaultsHest.c
HEST_EXPORT int hestDefaultGreedySingleString;
Why: these only existed as part of a bad idea to overcome other bad ideas on how
hestParse worked; those have been addressed with the re-write.
Modified Paths:
--------------
teem/trunk/src/air/air.h
teem/trunk/src/air/miscAir.c
teem/trunk/src/air/parseAir.c
teem/trunk/src/air/string.c
teem/trunk/src/bin/unu.c
teem/trunk/src/hest/adders.c
teem/trunk/src/hest/argvHest.c
teem/trunk/src/hest/defaultsHest.c
teem/trunk/src/hest/hest.h
teem/trunk/src/hest/methodsHest.c
teem/trunk/src/hest/parseHest.c
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/privateHest.h
teem/trunk/src/hest/test/ex6.c
teem/trunk/src/hest/test/tparse.c
teem/trunk/src/hest/usage.c
teem/trunk/src/nrrd/formatVTK.c
teem/trunk/src/unrrdu/make.c
Modified: teem/trunk/src/air/air.h
===================================================================
--- teem/trunk/src/air/air.h 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/air/air.h 2025-09-22 09:22:17 UTC (rev 7464)
@@ -452,61 +452,63 @@
/* ---- END non-NrrdIO */
-/*
-******** airType
-**
-** Different types which air cares about.
-** Currently only used in the command-line parsing, but perhaps will
-** be used elsewhere in air later
-*/
-enum {
- airTypeUnknown, /* 0 */
- airTypeBool, /* 1 */
- airTypeInt, /* 2 */
- airTypeUInt, /* 3 */
- airTypeLongInt, /* 4 */
- airTypeULongInt, /* 5 */
- airTypeSize_t, /* 6 */
- airTypeFloat, /* 7 */
- airTypeDouble, /* 8 */
- airTypeChar, /* 9 */
- airTypeString, /* 10 */
- airTypeEnum, /* 11 */
- airTypeOther, /* 12 */
- airTypeLast
-};
-#define AIR_TYPE_MAX 12
+/* changes for for TeemV2:
+ *** airParseStrT() are no longer var-args; it was a mistaken way to enforce uniformity
+ * across parsers for different types, and it was really only airParseStrE (for
+ * parsing airEnum values) that needed it. Then airParseStrS sneakily used it for
+ * its final "greedy" argument, which was also a bad idea to overcome bad ideas in
+ * hestParse(), which have since been fixed with its 2025 re-write.
+ *** Renamed airParseStrLI, airParseStrULI --> airParseStrL, airParseStrUL
+ *** Added airParseStrH and airParseStrUH for signed and unsigned shorts
+ *** Removed airStrtokQuoting (another bad idea; used only for "unu make")
+ *** Moved the airTypeT enum values from air to hest, since hest was the motivation for
+ * creating them so they should be localized to hest. To avoid needlessly breaking code
+ * that uses hestOptAdd(), which depends on the airTypeT enum values, those have kept
+ * their names, except:
+ * *** added airTypeShort and airTypeUShort
+ * *** renamed airTypeLongInt --> airTypeLong
+ * *** renamed airTypeULongInt --> airTypeULong
+ *** Removed the following from air to hest, renamed them, and made them private.
+ * They were only used to implement hest, no where else in Teem, so they never
+ * deserved to be in air:
+ * #define AIR_TYPE_MAX --> _HEST_TYPE_MAX
+ * const char airTypeStr[HEST_TYPE_MAX + 1][AIR_STRLEN_SMALL + 1] --> _hestTypeStr
+ * const size_t airTypeSize[HEST_TYPE_MAX + 1] --> _hestTypeSize
+ * unsigned int (*const airParseStr[AIR_TYPE_MAX + 1])(void *,
+ const char *, *const char *,
+ *unsigned int);
+ * --> _hestParseStr
+ */
/* parseAir.c */
AIR_EXPORT double airAtod(const char *str);
AIR_EXPORT int airSingleSscanf(const char *str, const char *fmt, void *ptr);
AIR_EXPORT const airEnum *const airBool;
AIR_EXPORT unsigned int airParseStrB(int *out, const char *s, const char *ct,
- unsigned int n, ... /* (nothing used) */);
+ unsigned int n);
+AIR_EXPORT unsigned int airParseStrH(short *out, const char *s, const char *ct,
+ unsigned int n);
+AIR_EXPORT unsigned int airParseStrUH(unsigned short *out, const char *s, const char *ct,
+ unsigned int n);
AIR_EXPORT unsigned int airParseStrI(int *out, const char *s, const char *ct,
- unsigned int n, ... /* (nothing used) */);
+ unsigned int n);
AIR_EXPORT unsigned int airParseStrUI(unsigned int *out, const char *s, const char *ct,
- unsigned int n, ... /* (nothing used) */);
-AIR_EXPORT unsigned int airParseStrLI(long int *out, const char *s, const char *ct,
- unsigned int n, ... /* (nothing used) */);
-AIR_EXPORT unsigned int airParseStrULI(unsigned long int *out, const char *s,
- const char *ct, unsigned int n,
- ... /* (nothing used) */);
+ unsigned int n);
+AIR_EXPORT unsigned int airParseStrL(long int *out, const char *s, const char *ct,
+ unsigned int n);
+AIR_EXPORT unsigned int airParseStrUL(unsigned long int *out, const char *s,
+ const char *ct, unsigned int n);
AIR_EXPORT unsigned int airParseStrZ(size_t *out, const char *s, const char *ct,
- unsigned int n, ... /* (nothing used) */);
+ unsigned int n);
AIR_EXPORT unsigned int airParseStrF(float *out, const char *s, const char *ct,
- unsigned int n, ... /* (nothing used) */);
+ unsigned int n);
AIR_EXPORT unsigned int airParseStrD(double *out, const char *s, const char *ct,
- unsigned int n, ... /* (nothing used) */);
+ unsigned int n);
AIR_EXPORT unsigned int airParseStrC(char *out, const char *s, const char *ct,
- unsigned int n, ... /* (nothing used) */);
+ unsigned int n);
AIR_EXPORT unsigned int airParseStrS(char **out, const char *s, const char *ct,
- unsigned int n,
- ... /* REQ'D even if n>1: int greedy */);
+ unsigned int n);
AIR_EXPORT unsigned int airParseStrE(int *out, const char *s, const char *ct,
- unsigned int n, ... /* REQUIRED: airEnum *e */);
-AIR_EXPORT unsigned int (*const airParseStr[AIR_TYPE_MAX + 1])(void *, const char *,
- const char *,
- unsigned int, ...);
+ unsigned int n, const airEnum *enm);
/* string.c */
AIR_EXPORT char *airStrdup(const char *s);
@@ -514,7 +516,6 @@
/* ---- BEGIN non-NrrdIO */
AIR_EXPORT int airStrcmp(const char *s1, const char *s2);
/* ---- END non-NrrdIO */
-AIR_EXPORT int airStrtokQuoting;
AIR_EXPORT char *airStrtok(char *s, const char *ct, char **last);
AIR_EXPORT unsigned int airStrntok(const char *s, const char *ct);
AIR_EXPORT char *airStrtrans(char *s, char from, char to);
@@ -580,8 +581,6 @@
AIR_EXPORT airULLong airIndexClampULL(double min, double val, double max, airULLong N);
AIR_EXPORT char *airDoneStr(double start, double here, double end, char *str);
AIR_EXPORT double airTime(void);
-AIR_EXPORT const char airTypeStr[AIR_TYPE_MAX + 1][AIR_STRLEN_SMALL + 1];
-AIR_EXPORT const size_t airTypeSize[AIR_TYPE_MAX + 1];
AIR_EXPORT void airEqvAdd(airArray *eqvArr, unsigned int j, unsigned int k);
AIR_EXPORT unsigned int airEqvMap(airArray *eqvArr, unsigned int *map, unsigned int len);
AIR_EXPORT unsigned int airEqvSettle(unsigned int *map, unsigned int len);
Modified: teem/trunk/src/air/miscAir.c
===================================================================
--- teem/trunk/src/air/miscAir.c 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/air/miscAir.c 2025-09-22 09:22:17 UTC (rev 7464)
@@ -624,42 +624,6 @@
#endif
}
-/* clang-format off */
-const char
-airTypeStr[AIR_TYPE_MAX+1][AIR_STRLEN_SMALL+1] = {
- "(unknown)",
- "bool",
- "int",
- "unsigned int",
- "long int",
- "unsigned long int",
- "size_t",
- "float",
- "double",
- "char",
- "string",
- "enum",
- "other",
-};
-
-const size_t
-airTypeSize[AIR_TYPE_MAX+1] = {
- 0,
- sizeof(int),
- sizeof(int),
- sizeof(unsigned int),
- sizeof(long int),
- sizeof(unsigned long int),
- sizeof(size_t),
- sizeof(float),
- sizeof(double),
- sizeof(char),
- sizeof(char*),
- sizeof(int),
- 0 /* we don't know anything about type "other" */
-};
-/* clang-format on */
-
/*
******** airEqvSettle()
**
Modified: teem/trunk/src/air/parseAir.c
===================================================================
--- teem/trunk/src/air/parseAir.c 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/air/parseAir.c 2025-09-22 09:22:17 UTC (rev 7464)
@@ -78,6 +78,8 @@
return val;
}
+// NOTE: see info n air.h about TeemV2 changes to all things airType and airParse
+
int
airSingleSscanf(const char *str, const char *fmt, void *ptr) {
char *tmp;
@@ -145,8 +147,35 @@
}
}
-#define _PARSE_STR_ARGS(type) \
- type *out, const char *_s, const char *ct, unsigned int n, ...
+unsigned int
+airParseStrB(int *out, const char *_s, const char *ct, unsigned int n) {
+ unsigned int i;
+ char *tmp, *s, *last;
+
+ /* if we got NULL, there's nothing to do */
+ if (!(out && _s && ct)) return 0;
+
+ /* copy the input so that we don't change it */
+ s = airStrdup(_s);
+
+ /* keep calling airStrtok() until we have everything */
+ for (i = 0; i < n; i++) {
+ tmp = airStrtok(i ? NULL : s, ct, &last);
+ if (!tmp) {
+ free(s);
+ return i;
+ }
+ out[i] = airEnumVal(airBool, tmp);
+ if (airEnumUnknown(airBool) == out[i]) {
+ free(s);
+ return i;
+ }
+ }
+ free(s);
+ return n;
+}
+
+#define _PARSE_STR_ARGS(type) type *out, const char *_s, const char *ct, unsigned int n
#define _PARSE_STR_BODY(format) \
unsigned int i; \
char *tmp, *s, *last; \
@@ -174,22 +203,26 @@
/*
******* airParse*()
-**
-** parse ints, floats, doubles, or single characters, from some
-** given string "s"; try to parse "n" of them, as delimited by
-** characters in "ct", and put the results in "out".
-**
-** Returns the number of things succesfully parsed- should be n;
-** there's been an error if return is < n.
-**
-** The embarrassing reason for the var-args ("...") is that I want the
-** type signature of all these functions to be the same, and I have a function
-** for parsing airEnums, in case the airEnum must be supplied as a final
-** argument.
-**
-** This uses air's thread-safe strtok() replacement: airStrtok()
+*
+* parse `n` shorts, ints, floats, doubles, or single chars, from some given string `s`;
+* the `n` of them are delimited by characters in `ct`; put the results in `out`.
+*
+* Returns the number of things succesfully parsed- should be `n`; there's been an error
+* if return is < `n`.
+*
+* This uses air's thread-safe strtok() replacement: airStrtok()
*/
unsigned int
+airParseStrH(_PARSE_STR_ARGS(short)) {
+ _PARSE_STR_BODY("%hd")
+}
+
+unsigned int
+airParseStrUH(_PARSE_STR_ARGS(unsigned short)) {
+ _PARSE_STR_BODY("%hu")
+}
+
+unsigned int
airParseStrI(_PARSE_STR_ARGS(int)) {
_PARSE_STR_BODY("%d")
}
@@ -200,12 +233,12 @@
}
unsigned int
-airParseStrLI(_PARSE_STR_ARGS(long int)) {
+airParseStrL(_PARSE_STR_ARGS(long int)) {
_PARSE_STR_BODY("%ld")
}
unsigned int
-airParseStrULI(_PARSE_STR_ARGS(unsigned long int)) {
+airParseStrUL(_PARSE_STR_ARGS(unsigned long int)) {
_PARSE_STR_BODY("%lu")
}
@@ -225,7 +258,7 @@
}
unsigned int
-airParseStrB(int *out, const char *_s, const char *ct, unsigned int n, ...) {
+airParseStrC(char *out, const char *_s, const char *ct, unsigned int n) {
unsigned int i;
char *tmp, *s, *last;
@@ -242,34 +275,6 @@
free(s);
return i;
}
- out[i] = airEnumVal(airBool, tmp);
- if (airEnumUnknown(airBool) == out[i]) {
- free(s);
- return i;
- }
- }
- free(s);
- return n;
-}
-
-unsigned int
-airParseStrC(char *out, const char *_s, const char *ct, unsigned int n, ...) {
- unsigned int i;
- char *tmp, *s, *last;
-
- /* if we got NULL, there's nothing to do */
- if (!(out && _s && ct)) return 0;
-
- /* copy the input so that we don't change it */
- s = airStrdup(_s);
-
- /* keep calling airStrtok() until we have everything */
- for (i = 0; i < n; i++) {
- tmp = airStrtok(i ? NULL : s, ct, &last);
- if (!tmp) {
- free(s);
- return i;
- }
out[i] = tmp[0];
}
free(s);
@@ -276,19 +281,15 @@
return n;
}
+/* for TeemV2: "greedy" was a dumb idea, and is gone. It used to be passed in as the last
+ * var-args argument. In the case of n==1, if greedy than the whole string was returned,
+ * else (!greedy) airStrtok() was called */
unsigned int
-airParseStrS(char **out, const char *_s, const char *ct, unsigned int n, ...) {
+airParseStrS(char **out, const char *_s, const char *ct, unsigned int n) {
unsigned int i;
- int greedy;
char *tmp, *s, *last;
airArray *mop;
- va_list ap;
- /* grab "greedy" every time, prior to error checking */
- va_start(ap, n);
- greedy = va_arg(ap, int);
- va_end(ap);
-
/* if we got NULL, there's nothing to do */
if (!(out && _s && ct)) return 0;
@@ -299,10 +300,7 @@
/* keep calling airStrtok() until we have everything */
for (i = 0; i < n; i++) {
- /* if n == 1, then with greediness, the whole string is used,
- and without greediness, we use airStrtok() to get only
- the first part of it */
- if (n > 1 || !greedy) {
+ if (n > 1) {
tmp = airStrtok(i ? NULL : s, ct, &last);
} else {
tmp = s;
@@ -323,18 +321,15 @@
}
unsigned int
-airParseStrE(int *out, const char *_s, const char *ct, unsigned int n, ...) {
+airParseStrE(int *out,
+ const char *_s,
+ const char *ct,
+ unsigned int n,
+ const airEnum *enm) {
unsigned int i;
char *tmp, *s, *last;
airArray *mop;
- va_list ap;
- airEnum *enm;
- /* grab the enum every time, prior to error checking */
- va_start(ap, n);
- enm = va_arg(ap, airEnum *);
- va_end(ap);
-
/* if we got NULL, there's nothing to do */
if (!(out && _s && ct)) {
return 0;
@@ -376,32 +371,3 @@
airMopOkay(mop);
return n;
}
-
-unsigned int (*const airParseStr[AIR_TYPE_MAX + 1])(void *, const char *, const char *,
- unsigned int, ...)
- = {
- NULL,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrB,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrI,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrUI,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrLI,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrULI,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrZ,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrF,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrD,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrC,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrS,
- (unsigned int (*)(void *, const char *, const char *, unsigned int,
- ...))airParseStrE,
- NULL /* no standard way of parsing type "other" */
-};
Modified: teem/trunk/src/air/string.c
===================================================================
--- teem/trunk/src/air/string.c 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/air/string.c 2025-09-22 09:22:17 UTC (rev 7464)
@@ -19,9 +19,11 @@
#include "air.h"
-/* this has to default to false in order for airStrtok to be a
- functional substitute for strtok() */
-int airStrtokQuoting = AIR_FALSE;
+/* removed for TeemV2:
+ * / * this has to default to false in order for airStrtok to be a
+ * functional substitute for strtok() * /
+ * int airStrtokQuoting = AIR_FALSE;
+ */
/*
******** airStrdup()
@@ -89,17 +91,18 @@
/* ---- END non-NrrdIO */
/*
******** airStrtok()
-**
-** thread-safe strtok() replacement. Use just like strtok(), but on
-** each call to parse a given string, pass as the last argument the
-** address of a char*, to be used for saving state while the string is
-** traversed. Like strtok(), this will alter the "s" array passed to
-** it on the first call, and like strtok(), this returns pointers into
-** this string (rather than allocating new strings for each token).
+*
+* thread-safe strtok() replacement. Use just like strtok(), but on each call to parse a
+* given string, pass as the last argument the address of a char*, to be used for saving
+* state while the string is traversed. Like strtok(), this will alter the "s" array
+* passed to it on the first call, and like strtok(), this returns pointers into this
+* string (rather than allocating new strings for each token).
+*
+* NOTE: TeemV2 removed global airStrtokQuoting and the code in here that used it.
*/
char *
airStrtok(char *s, const char *ct, char **last) {
- char *h, *e, *q;
+ char *h, *e;
if (!(ct && last)) {
/* can't do any work, bail */
@@ -108,24 +111,7 @@
h = s ? s : *last;
if (!airStrlen(h)) return NULL;
h += strspn(h, ct);
- if ('\"' == *h && airStrtokQuoting) {
- /* something is trying to be quoted, and, we'll respect that */
- /* have to find the next un-escaped '\"' */
- h++;
- q = h;
- while (*q && !('\"' == *q && '\\' != q[-1])) {
- q++;
- }
- if (*q) {
- /* we found an unescaped '\"' */
- e = q;
- } else {
- /* give up; pretend we never tried to do this quoting stuff */
- e = h + strcspn(h, ct);
- }
- } else {
- e = h + strcspn(h, ct);
- }
+ e = h + strcspn(h, ct);
if ('\0' == *e) {
*last = e;
} else {
Modified: teem/trunk/src/bin/unu.c
===================================================================
--- teem/trunk/src/bin/unu.c 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/bin/unu.c 2025-09-22 09:22:17 UTC (rev 7464)
@@ -70,7 +70,7 @@
hparm->respectDashDashHelp = AIR_TRUE;
/* set hparm->columns from ioctl if possible, else use unrrduDefNumColumns */
hestParmColumnsIoctl(hparm, unrrduDefNumColumns);
- hparm->greedySingleString = AIR_TRUE;
+ // Gone in TeemV2: hparm->greedySingleString = AIR_TRUE;
/* if there are no arguments, or "unu list" (or "unu all" shhh), then we give general
usage information */
Modified: teem/trunk/src/hest/adders.c
===================================================================
--- teem/trunk/src/hest/adders.c 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/hest/adders.c 2025-09-22 09:22:17 UTC (rev 7464)
@@ -301,10 +301,12 @@
(M, ATYP, CTYP) and applies it to all the simple scalar types */
#define MAP_T(MAC, M) \
MAC(M, Bool, int) \
+ MAC(M, Short, short int) \
+ MAC(M, UShort, unsigned short int) \
MAC(M, Int, int) \
MAC(M, UInt, unsigned int) \
- MAC(M, LongInt, long int) \
- MAC(M, ULongInt, unsigned long int) \
+ MAC(M, Long, long int) \
+ MAC(M, ULong, unsigned long int) \
MAC(M, Size_t, size_t) \
MAC(M, Float, float) \
MAC(M, Double, double) \
Modified: teem/trunk/src/hest/argvHest.c
===================================================================
--- teem/trunk/src/hest/argvHest.c 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/hest/argvHest.c 2025-09-22 09:22:17 UTC (rev 7464)
@@ -162,12 +162,13 @@
hinInit(void *_hin) {
hestInput *hin = (hestInput *)_hin;
hin->source = hestSourceUnknown;
- hin->dflt = NULL;
hin->argc = 0;
hin->argv = NULL;
hin->argIdx = 0;
hin->rfname = NULL;
hin->rfile = NULL;
+ hin->dfltStr = NULL;
+ hin->carIdx = 0;
hin->dashBraceComment = 0;
return;
}
@@ -183,10 +184,8 @@
static void
hinDone(void *_hin) {
hestInput *hin = (hestInput *)_hin;
- if (hin->rfile) {
- airFclose(hin->rfile);
- }
- AIR_UNUSED(hin);
+ hin->rfile = airFclose(hin->rfile);
+ hin->rfname = airFree(hin->rfname);
return;
}
Modified: teem/trunk/src/hest/defaultsHest.c
===================================================================
--- teem/trunk/src/hest/defaultsHest.c 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/hest/defaultsHest.c 2025-09-22 09:22:17 UTC (rev 7464)
@@ -31,5 +31,4 @@
int hestDefaultElideSingleEmptyStringDefault = AIR_FALSE;
int hestDefaultElideMultipleEmptyStringDefault = AIR_FALSE;
int hestDefaultNoArgsIsNoProblem = AIR_FALSE;
-int hestDefaultGreedySingleString = AIR_TRUE;
int hestDefaultCleverPluralizeOtherY = AIR_FALSE;
Modified: teem/trunk/src/hest/hest.h
===================================================================
--- teem/trunk/src/hest/hest.h 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/hest/hest.h 2025-09-22 09:22:17 UTC (rev 7464)
@@ -43,6 +43,44 @@
#endif
/*
+ * The airType values are here in hest as a transition hack for TeemV2. The parsing needs
+ * of hest are what motivated creating airTypes in the first place. The fresh perspective
+ * of TeemV2 recognizes they should have been in hest from the outset, not in air.
+ *
+ * The blissfully-type-unaware hestOptAdd() has always relied on the airTypeT enum values
+ * below. Since that function is not being removed, to avoid needless code breakage with
+ * TeemV2, these values now live in this hest header. hest users should instead be using
+ * the properly typed hestOptAdd_X_T functions, which have no need for airType
+ * pseudo-types.
+ *
+ * Other things that used to be in air, but which really only mattered to implement hest
+ * functions have been moved into privateHest.h, but with air --> hest renaming.
+ * #define AIR_TYPE_MAX
+ * const char airTypeStr[AIR_TYPE_MAX + 1][AIR_STRLEN_SMALL + 1];
+ * const size_t airTypeSize[AIR_TYPE_MAX + 1];
+ * unsigned int (*const airParseStr[AIR_TYPE_MAX + 1])(void *, const char *,const char
+ * unsigned int)
+ */
+enum {
+ airTypeUnknown, /* 0 */
+ airTypeBool, /* 1 */
+ airTypeShort, /* 2 (added for TeemV2) */
+ airTypeUShort, /* 3 (added for TeemV2) */
+ airTypeInt, /* 4 */
+ airTypeUInt, /* 5 */
+ airTypeLong, /* 6 (for TeemV2 renamed from airTypeLongInt) */
+ airTypeULong, /* 7 (for TeemV2 renamed from airTypeULongInt) */
+ airTypeSize_t, /* 8 */
+ airTypeFloat, /* 9 */
+ airTypeDouble, /* 10 */
+ airTypeChar, /* 11 */
+ airTypeString, /* 12 */
+ airTypeEnum, /* 13 */
+ airTypeOther, /* 14 */
+ airTypeLast
+};
+
+/*
******** hestSource* enum
**
** way of identifying where the info to satisfy a particular option came from.
@@ -49,9 +87,9 @@
*/
enum {
hestSourceUnknown, /* 0 */
- hestSourceDefault, /* 1 */
- hestSourceCommandLine, /* 2 (formerly called hestSourceUser) */
- hestSourceResponseFile, /* 3 */
+ hestSourceCommandLine, /* 1 (formerly called hestSourceUser) */
+ hestSourceResponseFile, /* 2 */
+ hestSourceDefault, /* 3 */
hestSourceLast
};
@@ -204,8 +242,6 @@
would be *ok* to invoke the problem without any further
command-line options. This is counter to pre-Teem-1.11 behavior
(for which no arguments *always* meant "show me usage info"). */
- greedySingleString, /* when parsing a single string, whether or not to be greedy
- (as per airParseStrS) */
cleverPluralizeOtherY, /* when printing the type for airTypeOther, when the min
number of items is > 1, and the type string ends with "y",
then pluralize with "ies" instead of "ys" */
@@ -248,15 +284,18 @@
// hestInput: what is the thing we're processing now to build up an arg vec
typedef struct {
int source; // from the hestSource* enum
- // ------ if source == hestSourceDefault ------
- const char *dflt; // we do NOT own
// ------ if source == hestSourceCommandLine ------
unsigned int argc;
const char **argv; // we do NOT own
unsigned int argIdx;
// ------ if source == hestSourceResponseFile ------
- const char *rfname; // we do NOT own: points into an argv or a hestArg
- FILE *rfile; // user opens and closes this
+ char *rfname; // we DO own
+ FILE *rfile; // user opens and closes this
+ // ------ if source == hestSourceDefault ------
+ const char *dfltStr; // we do NOT own
+ unsigned int dfltLen; // strlen(dfltStr)
+ // for both hestSourceResponseFile and hestSourceDefault
+ unsigned int carIdx; // which character are we on
// ------ general for all inputs ------
unsigned int dashBraceComment; /* not a boolean: how many -{ }- comment levels
deep are we currently; tracked this way to
@@ -281,7 +320,6 @@
HEST_EXPORT int hestDefaultElideSingleEmptyStringDefault;
HEST_EXPORT int hestDefaultElideMultipleEmptyStringDefault;
HEST_EXPORT int hestDefaultNoArgsIsNoProblem;
-HEST_EXPORT int hestDefaultGreedySingleString;
HEST_EXPORT int hestDefaultCleverPluralizeOtherY;
HEST_EXPORT unsigned int hestDefaultColumns;
@@ -355,10 +393,10 @@
// adders.c
HEST_EXPORT void hestOptAddDeclsPrint(FILE *f);
-/* Many many non-var-args alternatives to hestOptAdd, also usefully type-specific for the
-type of value to be parsed in a way that hestOptAdd_nva cannot match. These capture all
-the common uses (and then some) of hest within Teem. They are named according
-to kind, and according to the type T parameters to the option:
+/* The 99 (!) non-var-args alternatives to hestOptAdd, also usefully type-specific for
+the type of value to be parsed in a way that hestOptAdd_nva cannot match. These capture
+all the common uses (and then some) of hest within Teem. They are named according to
+kind, and according to the type T of the parms to be parsed for each option:
min, max function family kind description
min == max == 0 hestOptAdd_Flag 1 (stand-alone flag; no parameters)
@@ -367,17 +405,25 @@
min == 0; max == 1 hestOptAdd_1v_T 4 single variable parameter
min < max; max >= 2 hestOptAdd_Nv_T 5 multiple variable parameters
-An airEnum* is passed for _Enum options; or a hestCB* for _Other options. The number of
-parameters *sawP that hestParm saw on the command-line is passed for the _Nv_ options.
+The type T can be: Bool, Short, UShort, Int, UInt, Long, ULong, Size_t, Float, Double,
+Char, String, Enum, and Other. An airEnum* is passed with the T=Enum functions, or a
+hestCB* is passed for the T=Other functions. The number of parameters *sawP that hestParm
+saw on the command-line is passed for the _Nv_ options.
-All declarations below were automatically generated via hestOptAddDeclsPrint (followed by
-clang-format), which (like the implementation of all the functions) is done via lots of
-#define macro tricks. */
+All declarations below were automatically generated via hest/test/decls (which calls
+hestOptAddDeclsPrint), followed by clang-format. */
HEST_EXPORT unsigned int hestOptAdd_Flag(hestOpt **optP, const char *flag, int *valueP,
const char *info);
HEST_EXPORT unsigned int hestOptAdd_1v_Bool(hestOpt **hoptP, const char *flag,
const char *name, int *valueP,
const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_1v_Short(hestOpt **hoptP, const char *flag,
+ const char *name, short int *valueP,
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_1v_UShort(hestOpt **hoptP, const char *flag,
+ const char *name,
+ unsigned short int *valueP,
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_1v_Int(hestOpt **hoptP, const char *flag,
const char *name, int *valueP,
const char *dflt, const char *info);
@@ -384,13 +430,12 @@
HEST_EXPORT unsigned int hestOptAdd_1v_UInt(hestOpt **hoptP, const char *flag,
const char *name, unsigned int *valueP,
const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_1v_LongInt(hestOpt **hoptP, const char *flag,
- const char *name, long int *valueP,
- const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_1v_ULongInt(hestOpt **hoptP, const char *flag,
- const char *name,
- unsigned long int *valueP,
- const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_1v_Long(hestOpt **hoptP, const char *flag,
+ const char *name, long int *valueP,
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_1v_ULong(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned long int *valueP,
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_1v_Size_t(hestOpt **hoptP, const char *flag,
const char *name, size_t *valueP,
const char *dflt, const char *info);
@@ -417,6 +462,13 @@
HEST_EXPORT unsigned int hestOptAdd_1_Bool(hestOpt **hoptP, const char *flag,
const char *name, int *valueP,
const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_1_Short(hestOpt **hoptP, const char *flag,
+ const char *name, short int *valueP,
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_1_UShort(hestOpt **hoptP, const char *flag,
+ const char *name,
+ unsigned short int *valueP,
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_1_Int(hestOpt **hoptP, const char *flag,
const char *name, int *valueP,
const char *dflt, const char *info);
@@ -423,13 +475,12 @@
HEST_EXPORT unsigned int hestOptAdd_1_UInt(hestOpt **hoptP, const char *flag,
const char *name, unsigned int *valueP,
const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_1_LongInt(hestOpt **hoptP, const char *flag,
- const char *name, long int *valueP,
- const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_1_ULongInt(hestOpt **hoptP, const char *flag,
- const char *name,
- unsigned long int *valueP,
- const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_1_Long(hestOpt **hoptP, const char *flag,
+ const char *name, long int *valueP,
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_1_ULong(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned long int *valueP,
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_1_Size_t(hestOpt **hoptP, const char *flag,
const char *name, size_t *valueP,
const char *dflt, const char *info);
@@ -456,6 +507,13 @@
HEST_EXPORT unsigned int hestOptAdd_2_Bool(hestOpt **hoptP, const char *flag,
const char *name, int valueP[2],
const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_2_Short(hestOpt **hoptP, const char *flag,
+ const char *name, short int valueP[2],
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_2_UShort(hestOpt **hoptP, const char *flag,
+ const char *name,
+ unsigned short int valueP[2],
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_2_Int(hestOpt **hoptP, const char *flag,
const char *name, int valueP[2],
const char *dflt, const char *info);
@@ -462,13 +520,13 @@
HEST_EXPORT unsigned int hestOptAdd_2_UInt(hestOpt **hoptP, const char *flag,
const char *name, unsigned int valueP[2],
const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_2_LongInt(hestOpt **hoptP, const char *flag,
- const char *name, long int valueP[2],
- const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_2_ULongInt(hestOpt **hoptP, const char *flag,
- const char *name,
- unsigned long int valueP[2],
- const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_2_Long(hestOpt **hoptP, const char *flag,
+ const char *name, long int valueP[2],
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_2_ULong(hestOpt **hoptP, const char *flag,
+ const char *name,
+ unsigned long int valueP[2],
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_2_Size_t(hestOpt **hoptP, const char *flag,
const char *name, size_t valueP[2],
const char *dflt, const char *info);
@@ -495,6 +553,13 @@
HEST_EXPORT unsigned int hestOptAdd_3_Bool(hestOpt **hoptP, const char *flag,
const char *name, int valueP[3],
const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_3_Short(hestOpt **hoptP, const char *flag,
+ const char *name, short int valueP[3],
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_3_UShort(hestOpt **hoptP, const char *flag,
+ const char *name,
+ unsigned short int valueP[3],
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_3_Int(hestOpt **hoptP, const char *flag,
const char *name, int valueP[3],
const char *dflt, const char *info);
@@ -501,13 +566,13 @@
HEST_EXPORT unsigned int hestOptAdd_3_UInt(hestOpt **hoptP, const char *flag,
const char *name, unsigned int valueP[3],
const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_3_LongInt(hestOpt **hoptP, const char *flag,
- const char *name, long int valueP[3],
- const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_3_ULongInt(hestOpt **hoptP, const char *flag,
- const char *name,
- unsigned long int valueP[3],
- const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_3_Long(hestOpt **hoptP, const char *flag,
+ const char *name, long int valueP[3],
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_3_ULong(hestOpt **hoptP, const char *flag,
+ const char *name,
+ unsigned long int valueP[3],
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_3_Size_t(hestOpt **hoptP, const char *flag,
const char *name, size_t valueP[3],
const char *dflt, const char *info);
@@ -534,6 +599,13 @@
HEST_EXPORT unsigned int hestOptAdd_4_Bool(hestOpt **hoptP, const char *flag,
const char *name, int valueP[4],
const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_4_Short(hestOpt **hoptP, const char *flag,
+ const char *name, short int valueP[4],
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_4_UShort(hestOpt **hoptP, const char *flag,
+ const char *name,
+ unsigned short int valueP[4],
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_4_Int(hestOpt **hoptP, const char *flag,
const char *name, int valueP[4],
const char *dflt, const char *info);
@@ -540,13 +612,13 @@
HEST_EXPORT unsigned int hestOptAdd_4_UInt(hestOpt **hoptP, const char *flag,
const char *name, unsigned int valueP[4],
const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_4_LongInt(hestOpt **hoptP, const char *flag,
- const char *name, long int valueP[4],
- const char *dflt, const char *info);
-HEST_EXPORT unsigned int hestOptAdd_4_ULongInt(hestOpt **hoptP, const char *flag,
- const char *name,
- unsigned long int valueP[4],
- const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_4_Long(hestOpt **hoptP, const char *flag,
+ const char *name, long int valueP[4],
+ const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_4_ULong(hestOpt **hoptP, const char *flag,
+ const char *name,
+ unsigned long int valueP[4],
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_4_Size_t(hestOpt **hoptP, const char *flag,
const char *name, size_t valueP[4],
const char *dflt, const char *info);
@@ -573,6 +645,14 @@
HEST_EXPORT unsigned int hestOptAdd_N_Bool(hestOpt **hoptP, const char *flag,
const char *name, unsigned int N, int *valueP,
const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_N_Short(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned int N,
+ short int *valueP, const char *dflt,
+ const char *info);
+HEST_EXPORT unsigned int hestOptAdd_N_UShort(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned int N,
+ unsigned short int *valueP,
+ const char *dflt, const char *info);
HEST_EXPORT unsigned int hestOptAdd_N_Int(hestOpt **hoptP, const char *flag,
const char *name, unsigned int N, int *valueP,
const char *dflt, const char *info);
@@ -580,14 +660,14 @@
const char *name, unsigned int N,
unsigned int *valueP, const char *dflt,
const char *info);
-HEST_EXPORT unsigned int hestOptAdd_N_LongInt(hestOpt **hoptP, const char *flag,
- const char *name, unsigned int N,
- long int *valueP, const char *dflt,
- const char *info);
-HEST_EXPORT unsigned int hestOptAdd_N_ULongInt(hestOpt **hoptP, const char *flag,
- const char *name, unsigned int N,
- unsigned long int *valueP,
- const char *dflt, const char *info);
+HEST_EXPORT unsigned int hestOptAdd_N_Long(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned int N,
+ long int *valueP, const char *dflt,
+ const char *info);
+HEST_EXPORT unsigned int hestOptAdd_N_ULong(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned int N,
+ unsigned long int *valueP, const char *dflt,
+ const char *info);
HEST_EXPORT unsigned int hestOptAdd_N_Size_t(hestOpt **hoptP, const char *flag,
const char *name, unsigned int N,
size_t *valueP, const char *dflt,
@@ -620,6 +700,15 @@
const char *name, unsigned int min, int max,
int **valueP, const char *dflt,
const char *info, unsigned int *sawP);
+HEST_EXPORT unsigned int hestOptAdd_Nv_Short(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned int min, int max,
+ short int **valueP, const char *dflt,
+ const char *info, unsigned int *sawP);
+HEST_EXPORT unsigned int hestOptAdd_Nv_UShort(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned int min,
+ int max, unsigned short int **valueP,
+ const char *dflt, const char *info,
+ unsigned int *sawP);
HEST_EXPORT unsigned int hestOptAdd_Nv_Int(hestOpt **hoptP, const char *flag,
const char *name, unsigned int min, int max,
int **valueP, const char *dflt,
@@ -628,16 +717,15 @@
const char *name, unsigned int min, int max,
unsigned int **valueP, const char *dflt,
const char *info, unsigned int *sawP);
-HEST_EXPORT unsigned int hestOptAdd_Nv_LongInt(hestOpt **hoptP, const char *flag,
- const char *name, unsigned int min,
- int max, long int **valueP,
- const char *dflt, const char *info,
- unsigned int *sawP);
-HEST_EXPORT unsigned int hestOptAdd_Nv_ULongInt(hestOpt **hoptP, const char *flag,
- const char *name, unsigned int min,
- int max, unsigned long int **valueP,
- const char *dflt, const char *info,
- unsigned int *sawP);
+HEST_EXPORT unsigned int hestOptAdd_Nv_Long(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned int min, int max,
+ long int **valueP, const char *dflt,
+ const char *info, unsigned int *sawP);
+HEST_EXPORT unsigned int hestOptAdd_Nv_ULong(hestOpt **hoptP, const char *flag,
+ const char *name, unsigned int min, int max,
+ unsigned long int **valueP,
+ const char *dflt, const char *info,
+ unsigned int *sawP);
HEST_EXPORT unsigned int hestOptAdd_Nv_Size_t(hestOpt **hoptP, const char *flag,
const char *name, unsigned int min,
int max, size_t **valueP, const char *dflt,
Modified: teem/trunk/src/hest/methodsHest.c
===================================================================
--- teem/trunk/src/hest/methodsHest.c 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/hest/methodsHest.c 2025-09-22 09:22:17 UTC (rev 7464)
@@ -29,26 +29,87 @@
const char *const _hestBiffKey = "hest";
+// see note in hest.h about why airType things are here, renamed as hest
+/* clang-format off */
+const char
+_hestTypeStr[_HEST_TYPE_MAX+1][AIR_STRLEN_SMALL+1] = {
+ "(unknown)",
+ "bool",
+ "short",
+ "unsigned short",
+ "int",
+ "unsigned int",
+ "long int",
+ "unsigned long int",
+ "size_t",
+ "float",
+ "double",
+ "char",
+ "string",
+ "enum",
+ "other",
+};
+
+const size_t
+_hestTypeSize[_HEST_TYPE_MAX+1] = {
+ 0,
+ sizeof(int),
+ sizeof(short),
+ sizeof(unsigned short),
+ sizeof(int),
+ sizeof(unsigned int),
+ sizeof(long int),
+ sizeof(unsigned long int),
+ sizeof(size_t),
+ sizeof(float),
+ sizeof(double),
+ sizeof(char),
+ sizeof(char*),
+ sizeof(int),
+ 0 /* we don't know anything about type "other" */
+};
+/* clang-format on */
+
+unsigned int (*const _hestParseStr[_HEST_TYPE_MAX + 1])(void *, const char *,
+ const char *, unsigned int)
+ = {NULL,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrB,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrH,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrUH,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrI,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrUI,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrL,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrUL,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrZ,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrF,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrD,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrC,
+ (unsigned int (*)(void *, const char *, const char *, unsigned int))airParseStrS,
+ // airParseStrE needs final airEnum* arg, no longer enforceing fake uniformity
+ NULL,
+ // no uniform of parsing type "other"; handled via hestCB in hest
+ NULL};
+
// loving how C99 simplifies creating an airEnum at compile-time
static const airEnum _hestSource
= {.name = "source",
.M = 3,
.str = (const char *[]){"(unknown_source)", // 0
- "default", // 1
- "command-line", // 2
- "response-file"}, // 3
+ "command-line", // 1
+ "response-file", // 2
+ "default"}, // 3
.val = NULL,
- .desc = (const char *[]){"unknown source", //
- "default string in hestOpt", //
- "argc/argv command-line", //
- "a response file"},
- .strEqv = (const char *[]){"default", //
- "command-line", "cmdline", //
+ .desc = (const char *[]){"unknown source", //
+ "argc/argv command-line", //
+ "a response file", //
+ "default string in hestOpt"},
+ .strEqv = (const char *[]){"command-line", "cmdline", //
"response-file", "respfile", //
+ "default", //
""},
- .valEqv = (const int[]){hestSourceDefault, //
- hestSourceCommandLine, hestSourceCommandLine, //
- hestSourceResponseFile, hestSourceResponseFile},
+ .valEqv = (const int[]){hestSourceCommandLine, hestSourceCommandLine, //
+ hestSourceResponseFile, hestSourceResponseFile, //
+ hestSourceDefault},
.sense = AIR_FALSE};
const airEnum *const hestSource = &_hestSource;
@@ -75,8 +136,6 @@
hparm->responseFileEnable = hestDefaultResponseFileEnable;
hparm->elideSingleEnumType = hestDefaultElideSingleEnumType;
hparm->elideSingleOtherType = hestDefaultElideSingleOtherType;
- hparm->elideSingleOtherDefault = hestDefaultElideSingleOtherDefault;
- hparm->greedySingleString = hestDefaultGreedySingleString;
hparm->elideSingleNonExistFloatDefault = hestDefaultElideSingleNonExistFloatDefault;
hparm->elideMultipleNonExistFloatDefault
= hestDefaultElideMultipleNonExistFloatDefault;
@@ -102,7 +161,6 @@
abstaining from adding yet another default global variable */
hparm->respectDashBraceComments = AIR_TRUE;
hparm->noArgsIsNoProblem = hestDefaultNoArgsIsNoProblem;
- hparm->greedySingleString = hestDefaultGreedySingleString;
hparm->cleverPluralizeOtherY = hestDefaultCleverPluralizeOtherY;
/* here too: newer addition to hestParm avoid adding another default global */
hparm->dieLessVerbose = AIR_FALSE;
@@ -338,6 +396,11 @@
been moved to hestOptSingleSet.
Like hestOptAdd has done since 2013: returns UINT_MAX in case of error.
+
+Note: (as of 2023) you probably shouldn't use this function; instead use
+one of hestOptAdd_Flag, hestOptAdd_1_T, hestOptAdd_{2,3,4,N}_T, hestOptAdd_1v_T,
+or hestOptAdd_Nv_T for T=Bool, Int, UInt, LongInt, ULongInt, Size_t, Float, Double,
+Char, String, Enum, Other
*/
unsigned int
hestOptAdd_nva(hestOpt **optP, const char *flag, const char *name, int type,
Modified: teem/trunk/src/hest/parseHest.c
===================================================================
--- teem/trunk/src/hest/parseHest.c 2025-09-22 08:11:01 UTC (rev 7463)
+++ teem/trunk/src/hest/parseHest.c 2025-09-22 09:22:17 UTC (rev 7464)
@@ -202,7 +202,8 @@
airOneLinify(line);
incr = airStrntok(line, AIR_WHITESPACE);
if (hparm->verbosity) printf("%s: -1-> line: |%s|, incr=%d\n", me, line, incr);
- airParseStrS(newArgv + newArgc, line, AIR_WHITESPACE, incr, AIR_FALSE);
+ airParseStrS(newArgv + newArgc, line, AIR_WHITESPACE,
+ incr /*, greedy=AIR_FALSE */);
for (rgi = 0; rgi < incr; rgi++) {
/* This time, we did allocate memory. We can use airFree and
not airFreeP because these will not be reset before mopping */
@@ -240,7 +241,7 @@
other |= opt[ai].type == airTypeOther;
}
for (uint ai = airTypeUnknown + 1; ai < airTypeLast; ai++) {
- ret = AIR_MAX(ret, airStrlen(airTypeStr[ai]));
+ ret = AIR_MAX(ret, airStrlen(_hestTypeStr[ai]));
}
if (other) {
/* the callback's error() function may sprintf an error message
@@ -782,6 +783,12 @@
case airTypeBool:
return (*((int *)v) = !!i);
break;
+ case airTypeShort:
+ return (*((short *)v) = i);
+ break;
+ case airTypeUShort:
+ return (int)(*((unsigned short *)v) = i);
+ break;
case airTypeInt:
return (*((int *)v) = i);
break;
@@ -788,10 +795,10 @@
case airTypeUInt:
return (int)(*((unsigned int *)v) = i);
break;
- case airTypeLongInt:
+ case airTypeLong:
return (int)(*((long int *)v) = i);
break;
- case airTypeULongInt:
+ case airTypeULong:
return (int)(*((unsigned long int *)v) = i);
break;
case airTypeSize_t:
@@ -823,6 +830,12 @@
case airTypeBool:
return AIR_CAST(double, *((int *)v));
break;
+ case airTypeShort:
+ return AIR_CAST(double, *((short *)v));
+ break;
+ case airTypeUShort:
+ return AIR_CAST(double, *((unsigned short *)v));
+ break;
case airTypeInt:
return AIR_CAST(double, *((int *)v));
break;
@@ -829,10 +842,10 @@
case airTypeUInt:
return AIR_CAST(double, *((unsigned int *)v));
break;
- case airTypeLongInt:
+ case airTypeLong:
return AIR_CAST(double, *((long int *)v));
break;
- case airTypeULongInt:
+ case airTypeULong:
return AIR_CAST(double, *((unsigned long int *)v));
break;
case airTypeSize_t:
@@ -899,7 +912,7 @@
? sizeof(int)
: (airTypeOther == type /* */
? opt[op].CB->size
- : airTypeSize[type]));
+ : _hestTypeSize[type]));
cP = (char *)(vP = opt[op].valueP);
if (hparm->verbosity) {
printf("%s %d of %d: \"%s\": |%s| --> kind=%d, type=%d, size=%u\n", me, op,
@@ -952,10 +965,10 @@
break;
case airTypeString:
if (1
- != airParseStrS((char **)vP, optParms[op], " ", 1,
- hparm->greedySingleString)) {
+ != airParseStrS((char **)vP, optParms[op], " ", 1
+ /*, hparm->greedySingleString */)) {
sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s", ME,
- optDfltd[op] ? "(default) " : "", optParms[op], airTypeStr[type],
+ optDfltd[op] ? "(default) " : "", optParms[op], _hestTypeStr[type],
ident);
return 1;
}
@@ -965,10 +978,10 @@
airMopMem(pmop, vP, airMopOnError);
break;
default:
- /* type isn't string or enum, so no last arg to airParseStr[type] */
- if (1 != airParseStr[type](vP, optParms[op], " ", 1)) {
+ /* type isn't string or enum, so no last arg to hestParseStr[type] */
+ if (1 != _hestParseStr[type](vP, optParms[op], " ", 1)) {
sprintf(err, "%scouldn't parse %s\"%s\" as %s for %s", ME,
- optDfltd[op] ? "(default) " : "", optParms[op], airTypeStr[type],
+ optDfltd[op...
[truncated message content] |
|
From: <kin...@us...> - 2025-09-22 08:11:06
|
Revision: 7463
http://sourceforge.net/p/teem/code/7463
Author: kindlmann
Date: 2025-09-22 08:11:01 +0000 (Mon, 22 Sep 2025)
Log Message:
-----------
tweaks to docs
Modified Paths:
--------------
teem/trunk/src/hest/README.md
Modified: teem/trunk/src/hest/README.md
===================================================================
--- teem/trunk/src/hest/README.md 2025-09-21 10:22:48 UTC (rev 7462)
+++ teem/trunk/src/hest/README.md 2025-09-22 08:11:01 UTC (rev 7463)
@@ -10,7 +10,7 @@
`hest` has possibly non-standard terminology for the elements of command-line parsing. Here is a bottom-up description of the command-line and what `hest` can do with it:
-- What `main()` gets as `char *argv[]` is the vector of _arguments_ or _args_; each one is a `char*` string. An arg can contain spaces and other arbitrary characters if the user quoted strings or escaped characters; that is between the user and shell (the shell is responsible for taking the command-line and tokenizing it into `char *argv[]`). `hest` processes all the args in the `argv` you give it.
+- What `main()` gets as `char *argv[]` is the vector of _arguments_ or _args_; each one is a `char*` string. An arg can contain spaces and other arbitrary characters if the user quoted strings or escaped characters; that is between the user and shell (the shell is responsible for taking the command-line and tokenizing it into `char *argv[]`).
- Arguments like `-v` and `-size`, which identify the variable to be set, are called _flags_.
- Some flags are really just flags; no further information is given beyond their presence or absence. Other flags introduce subsequent arguments that together supply information for setting one variable.
- The set of arguments that logically belong together (often following a flag) in the service of setting a variable are called _parameters_ (or _parms_). There is some slippage of terminology between the `char *` string that communicates the parameter, and the value (such an `int`) parsed from the parameter string.
@@ -17,6 +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.
- 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.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <kin...@us...> - 2025-09-21 10:22:51
|
Revision: 7462
http://sourceforge.net/p/teem/code/7462
Author: kindlmann
Date: 2025-09-21 10:22:48 +0000 (Sun, 21 Sep 2025)
Log Message:
-----------
calling hestOptAddDeclsPrint now moved to test/decls
Modified Paths:
--------------
teem/trunk/src/hest/test/ex6.c
Modified: teem/trunk/src/hest/test/ex6.c
===================================================================
--- teem/trunk/src/hest/test/ex6.c 2025-09-21 10:22:03 UTC (rev 7461)
+++ teem/trunk/src/hest/test/ex6.c 2025-09-21 10:22:48 UTC (rev 7462)
@@ -376,17 +376,6 @@
unsigned int qvSaw;
hestOptAdd_Nv_Other(&opt, "qv", "quat1", 1, -1, &qv, "12.34 43.21",
"test of hestOptAdd_Nv_Other B", &qvSaw, &quatCB);
-
- if (2 == argc && !strcmp("decls", argv[1])) {
- printf("Writing decls.h and then bailing\n");
- FILE *ff = fopen("decls.h", "w");
- hestOptAddDeclsPrint(ff);
- fclose(ff);
- exit(0);
- }
- /* else not writing decls.h; remove it to ensure freshness */
- remove("decls.h");
-
hestParseOrDie(opt, argc - 1, argv + 1, parm, argv[0], info, AIR_TRUE, AIR_TRUE,
AIR_TRUE);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|