|
From: <kin...@us...> - 2025-09-25 21:09:55
|
Revision: 7491
http://sourceforge.net/p/teem/code/7491
Author: kindlmann
Date: 2025-09-25 21:09:48 +0000 (Thu, 25 Sep 2025)
Log Message:
-----------
added hestArgVecSprint but still debugging
Modified Paths:
--------------
teem/trunk/src/hest/argvHest.c
teem/trunk/src/hest/hest.h
teem/trunk/src/hest/parsest.c
teem/trunk/src/hest/test/tparse.c
Modified: teem/trunk/src/hest/argvHest.c
===================================================================
--- teem/trunk/src/hest/argvHest.c 2025-09-25 11:28:19 UTC (rev 7490)
+++ teem/trunk/src/hest/argvHest.c 2025-09-25 21:09:48 UTC (rev 7491)
@@ -90,10 +90,12 @@
return;
}
-void
-hestArgSetString(hestArg *harg, const char *str) {
+static void
+arg_AddOrSet_String(hestArg *harg, int resetFirst, const char *str) {
assert(harg && str);
- hestArgReset(harg);
+ if (resetFirst) {
+ hestArgReset(harg);
+ }
uint len = AIR_UINT(strlen(str));
for (uint si = 0; si < len; si++) {
hestArgAddChar(harg, str[si]);
@@ -101,6 +103,18 @@
return;
}
+void
+hestArgSetString(hestArg *harg, const char *str) {
+ arg_AddOrSet_String(harg, AIR_TRUE, str);
+ return;
+}
+
+void
+hestArgAddString(hestArg *harg, const char *str) {
+ arg_AddOrSet_String(harg, AIR_FALSE, str);
+ return;
+}
+
/* ---------------------- hestArgVec = havec = hestArgVec = havec ------------------ */
/* to avoid strict aliasing warnings */
@@ -145,6 +159,7 @@
return NULL;
}
+// return havec->harg[popIdx] and shift higher indices down
hestArg *
hestArgVecRemove(hestArgVec *havec, uint popIdx) {
hestArg *ret = NULL;
@@ -152,18 +167,7 @@
ret = havec->harg[popIdx];
uint ai;
for (ai = popIdx; ai < havec->len - 1; ai++) {
- // shuffle down info inside the hestArg elements of havec->harg
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)
- 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 */
}
// NULL out final out, using final value of ai
havec->harg[ai] = NULL;
@@ -173,7 +177,99 @@
return ret;
}
+/* hestArgVecSprint goes is opposite of the shell-style tokenization of
+parsest.c/argstGo: generate a single human-friendly string that could be tokenized to
+recover the hestArgVec we started with.
+ChatGPT helped with prototyping.
+Here are instructive examples of the same kind of argv pretty-printing:
+https://github.com/git/git/blob/master/quote.c
+and here https://www.opencoverage.net/coreutils/index_html/source_213.html
+with its (more baroque) quotearg_buffer_restyled() function
+*/
+
+// plainWord(str) is true if nothing in str needs quoting or escaping
+static int
+plainWord(const char *s) {
+ if (*s == '\0') {
+ // wut - we got the empty string, yes needs quoting
+ return 0;
+ }
+ int plain = AIR_TRUE;
+ for (; *s; s++) {
+ plain &= (isalnum(*s) //
+ || *s == '_' || *s == '-' //
+ || *s == '.' || *s == '/');
+ if (!plain) break;
+ }
+ return plain;
+}
+
+/* Assuming that `str` needs some quoting or ecaping to be retokenized as a single arg
+then figure out if that should be via single or double quoting, by doing both and picking
+the shorter one */
void
+argAddQuotedString(hestArg *harg, const char *str) {
+ hestArg *singQ = hestArgNew();
+ hestArg *doubQ = hestArgNew();
+ hestArgAddChar(singQ, '\'');
+ hestArgAddChar(doubQ, '"');
+ const char *src = str;
+ for (; *src; src++) {
+ // -- single quoting to singQ
+ if ('\'' == *src) {
+ // can't escape ' inside ''-quoting, so have to:
+ // stop ''-quoting, write (escaped) \', then re-start ''-quoting
+ hestArgAddString(singQ, "'\\''");
+ } else {
+ hestArgAddChar(singQ, *src);
+ }
+ // -- double quoting to doubQ
+ if ('"' == *src || '\\' == *src || '`' == *src || '$' == *src) {
+ // this character needs escaping
+ hestArgAddChar(doubQ, '\\');
+ }
+ hestArgAddChar(doubQ, *src);
+ }
+ hestArgAddChar(singQ, '\'');
+ hestArgAddChar(doubQ, '"');
+ // use single-quoting when it is shorter, else double-quoting
+ hestArgAddString(harg, singQ->len < doubQ->len ? singQ->str : doubQ->str);
+ hestArgNix(singQ);
+ hestArgNix(doubQ);
+}
+
+char *
+hestArgVecSprint(const hestArgVec *havec, int showIdx) {
+ if (!havec) {
+ return NULL;
+ }
+ hestArg *retArg = hestArgNew();
+ for (uint ai = 0; ai < havec->len; ai++) {
+ if (ai) {
+ // add the space between previous and this arg
+ hestArgAddChar(retArg, ' ');
+ }
+ if (showIdx) {
+ char buff[AIR_STRLEN_SMALL + 1];
+ sprintf(buff, "%u", ai);
+ hestArgAddString(retArg, buff);
+ hestArgAddChar(retArg, ':');
+ }
+ const char *astr = havec->harg[ai]->str;
+ if (plainWord(astr)) {
+ hestArgAddString(retArg, astr);
+ } else {
+ argAddQuotedString(retArg, astr);
+ }
+ }
+ // the real hestArgNix: keep the string but lose everything around it
+ char *ret = retArg->str;
+ airArrayNix(retArg->strArr);
+ free(retArg);
+ return ret;
+}
+
+void
hestArgVecAppendString(hestArgVec *havec, const char *str) {
uint idx = airArrayLenIncr(havec->hargArr, 1);
hestArgSetString(havec->harg[idx], str);
@@ -209,6 +305,11 @@
printf(" %u%c:<%s>", idx, srcch[harg->source], harg->str ? harg->str : "NULL");
}
printf("\n");
+ char *ppargs = hestArgVecSprint(havec, AIR_FALSE);
+ printf("%s%s%s OR pretty-printed as:\n%s\n", airStrlen(caller) ? caller : "", //
+ airStrlen(caller) ? ": " : "", info, ppargs);
+ free(ppargs);
+ return;
}
/* ------------------------- hestInput = hin = hestInput = hin --------------------- */
Modified: teem/trunk/src/hest/hest.h
===================================================================
--- teem/trunk/src/hest/hest.h 2025-09-25 11:28:19 UTC (rev 7490)
+++ teem/trunk/src/hest/hest.h 2025-09-25 21:09:48 UTC (rev 7491)
@@ -340,10 +340,12 @@
HEST_EXPORT void hestArgReset(hestArg *harg);
HEST_EXPORT void hestArgAddChar(hestArg *harg, char cc);
HEST_EXPORT void hestArgSetString(hestArg *harg, const char *str);
+HEST_EXPORT void hestArgAddString(hestArg *harg, const char *str);
HEST_EXPORT hestArgVec *hestArgVecNew(void);
HEST_EXPORT void hestArgVecReset(hestArgVec *havec);
HEST_EXPORT hestArgVec *hestArgVecNix(hestArgVec *havec);
HEST_EXPORT hestArg *hestArgVecRemove(hestArgVec *havec, unsigned int popIdx);
+HEST_EXPORT char *hestArgVecSprint(const hestArgVec *havec, int showIndices);
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,
Modified: teem/trunk/src/hest/parsest.c
===================================================================
--- teem/trunk/src/hest/parsest.c 2025-09-25 11:28:19 UTC (rev 7490)
+++ teem/trunk/src/hest/parsest.c 2025-09-25 21:09:48 UTC (rev 7491)
@@ -88,6 +88,7 @@
(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
+ChatGPT helped with prototyping.
Here is instructive example code https://github.com/nyuichi/dash.git
in src/parser.c see the readtoken1() function and the DFA there.
*/
@@ -327,7 +328,7 @@
biffAddf(HEST, "%s%sconfused by input source %d", _ME_, hin->source);
return 1;
}
- if (argstGo(nastP, tharg, &state, icc, hparm->verbosity > 3)) {
+ if (argstGo(nastP, tharg, &state, icc, hparm->verbosity > 4)) {
if (hestSourceResponseFile == hin->source) {
biffAddf(HEST, "%s%strouble at character %u of %s \"%s\"", _ME_, hin->carIdx,
airEnumStr(hestSource, hin->source), hin->rfname);
@@ -756,7 +757,7 @@
return 1;
}
if (!(srcIdx + num <= hvsrc->len)) {
- biffAddf(HEST, "%s%shave only %u args but want %u starting at %u", _ME_,
+ biffAddf(HEST, "%s%shave only %u args but want %u starting at index %u", _ME_,
hvsrc->len, num, srcIdx);
return 1;
}
@@ -775,9 +776,10 @@
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("\tname|%s|\t k%d (%u)--(%d) \t%s ", opt->name ? opt->name : "(null)",
+ opt->kind, opt->min, opt->max, _hestTypeStr[opt->type]);
+ printf("\t%sdflt%s%s%s\n", opt->dflt ? "" : "NO-", opt->dflt ? "|" : "",
+ opt->dflt ? opt->dflt : "", opt->dflt ? "|" : "");
printf(" source %s\n", airEnumStr(hestSource, opt->source));
hestArgVecPrint("", " havec:", opt->havec);
return;
@@ -850,7 +852,8 @@
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
+
+ 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))
@@ -873,6 +876,8 @@
"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
+ char *havStr = hestArgVecSprint(havec, AIR_TRUE);
+ biffAddf(HEST, "%s%sworking on argv: %s", havStr);
if (hitEnd) {
biffAddf(HEST,
"%s%shit end of args before getting %u parameter%s "
@@ -896,6 +901,7 @@
_ME_, theOpt->min, theOpt->min > 1 ? "s" : "", identStr(ident1, theOpt),
parmNum);
}
+ free(havStr);
return 1;
}
if (hparm->verbosity) {
Modified: teem/trunk/src/hest/test/tparse.c
===================================================================
--- teem/trunk/src/hest/test/tparse.c 2025-09-25 11:28:19 UTC (rev 7490)
+++ teem/trunk/src/hest/test/tparse.c 2025-09-25 21:09:48 UTC (rev 7491)
@@ -34,27 +34,28 @@
hestParm *hparm = hestParmNew();
hparm->respectDashDashHelp = AIR_TRUE;
hparm->responseFileEnable = AIR_TRUE;
- hparm->verbosity = 10;
+ hparm->verbosity = 4;
+ int flag;
+ hestOptAdd_Flag(&opt, "b,bingo", &flag, "a flag");
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");
+
+ int *size;
unsigned int slen;
- hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 0, -1, &res, NULL, "image resolutions",
+ hestOptAdd_Nv_Int(&opt, "s,sizes", "sx sy", 2, -1, &size, NULL, "image resolutions",
&slen);
+
int *unpB;
unsigned int sawB;
- hestOptAdd_Nv_Int(&opt, NULL, "B B", 1, -1, &unpB, "BBBB", "unflagged B", &sawB);
+ hestOptAdd_Nv_Int(&opt, NULL, "B B", 1, -1, &unpB, /* "BBBB" */ NULL, "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;
- hestOptAdd_Flag(&opt, "c,cingo", &glaf, "a flag");
int unpC[2];
- hestOptAdd_2_Int(&opt, NULL, "C C", unpC, "dfltC0 dfltC1", "unflagged C");
+ hestOptAdd_2_Int(&opt, NULL, "C C", unpC, /* "dfltC0 dfltC1" */ NULL, "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.
|