diff --git a/Fixes b/Fixes index 134ac096..1ce15a32 100644 --- a/Fixes +++ b/Fixes @@ -1,3 +1,5 @@ + 7. alxwded@github, keep track of the :g and :a modifiers per modifier they + affect. 6. alzwded@github, fix infinite loop with :gas variable modifier 5. PR/88: Add a Q: modifier that preserves empty arguments leaving :q alone. diff --git a/sh.dol.c b/sh.dol.c index af69661f..b1a15125 100644 --- a/sh.dol.c +++ b/sh.dol.c @@ -64,8 +64,10 @@ static Char *dolp; /* Remaining chars from this word */ static Char **dolnxt; /* Further words */ static int dolcnt; /* Count of further words */ static struct Strbuf dolmod; /* = Strbuf_INIT; : modifier characters */ -static int dolmcnt; /* :gx -> INT_MAX, else 1 */ -static int dol_flag_a; /* :ax -> 1, else 0 */ + +static int ndolflags; /* keep track of mod counts for each modifier */ +static int *dolmcnts; /* :gx -> INT_MAX, else 1 */ +static int *dolaflags; /* :ax -> 1, else 0 */ static Char **Dfix2 (Char *const *); static int Dpack (struct Strbuf *); @@ -378,7 +380,7 @@ Dgetdol(void) static Char *dolbang = NULL; cleanup_push(name, Strbuf_free); - dolmod.len = dolmcnt = dol_flag_a = 0; + dolmod.len = ndolflags = 0; c = sc = DgetC(0); if (c == DEOF) { stderror(ERR_SYNTAX); @@ -718,21 +720,27 @@ fixDolMod(void) c = DgetC(0); if (c == ':') { + ndolflags = 0; do { - c = DgetC(0), dolmcnt = 1, dol_flag_a = 0; + ++ndolflags; + dolmcnts = xrealloc(dolmcnts, ndolflags); + dolaflags = xrealloc(dolaflags, ndolflags); + c = DgetC(0), dolmcnts[ndolflags - 1] = 1, dolaflags[ndolflags - 1] = 0; if (c == 'g' || c == 'a') { - if (c == 'g') - dolmcnt = INT_MAX; - else - dol_flag_a = 1; + if (c == 'g') { + dolmcnts[ndolflags - 1] = INT_MAX; + } else { + dolaflags[ndolflags - 1] = 1; + } c = DgetC(0); } - if ((c == 'g' && dolmcnt != INT_MAX) || - (c == 'a' && dol_flag_a == 0)) { - if (c == 'g') - dolmcnt = INT_MAX; - else - dol_flag_a = 1; + if ((c == 'g' && dolmcnts[ndolflags - 1] != INT_MAX) || + (c == 'a' && dolaflags[ndolflags - 1] == 0)) { + if (c == 'g') { + dolmcnts[ndolflags - 1] = INT_MAX; + } else { + dolaflags[ndolflags - 1] = 1; + } c = DgetC(0); } @@ -761,8 +769,9 @@ fixDolMod(void) if (!any(TCSH_MODIFIERS, c)) stderror(ERR_BADMOD, (int)c); Strbuf_append1(&dolmod, (Char) c); - if (c == 'q') - dolmcnt = INT_MAX; + if (c == 'q') { + dolmcnts[ndolflags - 1] = INT_MAX; + } } while ((c = DgetC(0)) == ':'); unDredc(c); @@ -771,13 +780,25 @@ fixDolMod(void) unDredc(c); } +static int +all_dolmcnts_are_0() +{ + int i = 0; + for(; i < ndolflags; ++i) { + if(dolmcnts[i] != 0) + return 0; + } + return 1; +} + static void setDolp(Char *cp) { Char *dp; size_t i; + int nthMod = 0; - if (dolmod.len == 0 || dolmcnt == 0) { + if (dolmod.len == 0 || all_dolmcnts_are_0()) { dolp = cp; return; } @@ -812,36 +833,38 @@ setDolp(Char *cp) strip(lhsub); strip(rhsub); - strip(cp); - dp = cp; - do { - dp = Strstr(dp + last_match, lhsub); - if (dp) { - ptrdiff_t diff = dp - cp; - size_t len = (Strlen(cp) + 1 - lhlen + rhlen); - np = xmalloc(len * sizeof(Char)); - (void) Strncpy(np, cp, diff); - (void) Strcpy(np + diff, rhsub); - (void) Strcpy(np + diff + rhlen, dp + lhlen); - last_match = diff + rhlen; - - xfree(cp); - dp = cp = np; - cp[--len] = '\0'; - didmod = 1; - if (diff >= (ssize_t)len) - break; - } else { - /* should this do a seterror? */ - break; - } - } - while (dol_flag_a != 0); + if(dolmcnts[nthMod] != 0) { + strip(cp); + dp = cp; + do { + dp = Strstr(dp + last_match, lhsub); + if (dp) { + ptrdiff_t diff = dp - cp; + size_t len = (Strlen(cp) + 1 - lhlen + rhlen); + np = xmalloc(len * sizeof(Char)); + (void) Strncpy(np, cp, diff); + (void) Strcpy(np + diff, rhsub); + (void) Strcpy(np + diff + rhlen, dp + lhlen); + last_match = diff + rhlen; + + xfree(cp); + dp = cp = np; + cp[--len] = '\0'; + didmod = 1; + if (diff >= (ssize_t)len) + break; + } else { + /* should this do a seterror? */ + break; + } + } + while (dolaflags[nthMod] != 0); + } /* * restore dolmod for additional words */ dolmod.s[i] = rhsub[-1] = (Char) delim; - } else { + } else if(dolmcnts[nthMod] != 0) { do { if ((dp = domod(cp, dolmod.s[i])) != NULL) { @@ -859,14 +882,16 @@ setDolp(Char *cp) else break; } - while (dol_flag_a != 0); + while (dolaflags[nthMod] != 0); } - if (didmod && dolmcnt != INT_MAX) - dolmcnt--; + if(didmod && dolmcnts[nthMod] != INT_MAX) + dolmcnts[nthMod]--; #ifdef notdef else break; #endif + + ++nthMod; } addla(cp); diff --git a/sh.lex.c b/sh.lex.c index 69ff3014..d7d0ac59 100644 --- a/sh.lex.c +++ b/sh.lex.c @@ -596,7 +596,7 @@ getdol(void) int gmodflag = 0, amodflag = 0; do { - Strbuf_append1(&name, c), c = getC(DOEXCL); + Strbuf_append1(&name, c), c = getC(DOEXCL), gmodflag = 0, amodflag = 0; if (c == 'g' || c == 'a') { if (c == 'g') gmodflag++; diff --git a/tests/lexical.at b/tests/lexical.at index 68ea4070..5eea377e 100644 --- a/tests/lexical.at +++ b/tests/lexical.at @@ -627,6 +627,28 @@ AT_CHECK([tcsh -f escape_echo.csh], 0, AT_CLEANUP +AT_SETUP([:gas work as described in the man pages]) + +AT_DATA([gas.csh], +[[set x=(aa bb aa bb) +echo $x:gas/a/c/:gs/b/d/ +foreach i ( "$x:gas/a/c/:q" ) + echo $i +end +echo $x:gas/a/q/:gs/b/w/:s/b/e/ +echo $x:gas/a/q/:gs/b/w/:s/b/e/:gas/q/Q/ +exit 0 +]]) + +AT_CHECK([tcsh -f gas.csh], 0, +[cc db cc db +cc bb cc bb +qq we qq wb +QQ we QQ wb +]) + +AT_CLEANUP + AT_SETUP([avoid infinite loop in :gas]) AT_DATA([replace_all.csh],