mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-13 11:42:21 +00:00
Port more shell lint improvements from illumos and ksh93v- (#374)
This commit adds onto <https://github.com/ksh93/ksh/pull/353> by porting
over two additional improvements to the shell linter:
1) The changes in the aforementioned pull request were merged into
illumos-gate with an additional change.[*] The illumos revision of
the patch improved the warning for (( $foo = $? )) to specify '$foo'
causes the warning.[**] Example:
$ ksh -n -c '(( $? != $bar ))'
ksh: warning: line 1: in '(( $? != $bar ))', using '$' as in '$bar' is slower and can introduce rounding errors
While I was porting the illumos patch I did notice one problem. The
string it uses from paramsub() skips over the initial '{' in
'${var}', resulting in the warning printing '$var}' instead:
$ ksh -n -c '(( ${.sh.pid} != $$ ))'
... in '(( ${.sh.pid} != $$ ))', using '$' as in '$.sh.pid}' is slower ...
This was fixed by including the missing '{' in the string returned by
paramsub for ${var} variables.
2) In ksh93v-, parsing x=$((expr)) with the shell linter will cause ksh
to warn the user x=$((expr)) is slower than ((x=expr)). This
improvement has been backported with a modified warning:
# Result from this commit
$ ksh -n -c 'x=$((1 + 2))'
ksh: warning: line 1: x=$((1 + 2)) is slower than ((x=1 + 2))
# Result from ksh93v-
$ ksh93v -n -c 'x=$((1 + 2))'
ksh93v: warning: line 1: ((x=1 + 2)) is more efficient than x=$((1 + 2))
Minor note: the ksh93v- patch had an invalid use of memcmp; this
version of the patch uses strncmp instead.
References:
be548e87bc
https://code.illumos.org/c/illumos-gate/+/1834/comment/65722363_22fdf8e7/
This commit is contained in:
parent
66a50ece82
commit
cd562b16e2
5 changed files with 36 additions and 8 deletions
6
NEWS
6
NEWS
|
@ -9,6 +9,12 @@ Any uppercase BUG_* names are modernish shell bug IDs.
|
||||||
as SIGINT due to Ctrl+C) while the user is entering a multi-line command
|
as SIGINT due to Ctrl+C) while the user is entering a multi-line command
|
||||||
substitution in an interactive shell.
|
substitution in an interactive shell.
|
||||||
|
|
||||||
|
- The shell linter's warning for variable expansion in ((...)) now tells the
|
||||||
|
user which variable is causing performance degradation.
|
||||||
|
|
||||||
|
- The shell linter now warns the user x=$((expr)) is slower than ((x=expr))
|
||||||
|
when assigning a value to a variable.
|
||||||
|
|
||||||
2021-12-09:
|
2021-12-09:
|
||||||
|
|
||||||
- Increased the general robustness of discipline function handling, fixing
|
- Increased the general robustness of discipline function handling, fixing
|
||||||
|
|
|
@ -430,7 +430,8 @@ const char e_lexsyntax2[] = "syntax error: `%s' %s";
|
||||||
const char e_lexsyntax3[] = "syntax error at line %d: duplicate label %s";
|
const char e_lexsyntax3[] = "syntax error at line %d: duplicate label %s";
|
||||||
const char e_lexsyntax4[] = "syntax error at line %d: invalid reference list";
|
const char e_lexsyntax4[] = "syntax error at line %d: invalid reference list";
|
||||||
const char e_lexsyntax5[] = "syntax error at line %d: `<<%s' here-document not contained within command substitution";
|
const char e_lexsyntax5[] = "syntax error at line %d: `<<%s' here-document not contained within command substitution";
|
||||||
const char e_lexwarnvar[] = "line %d: in '((%s))', using '$' is slower and can introduce rounding errors";
|
const char e_lexwarnvar[] = "line %d: in '((%s))', using '$' as in '$%.*s' is slower and can introduce rounding errors";
|
||||||
|
const char e_lexarithwarn[] = "line %d: %s is slower than ((%.*s%s";
|
||||||
const char e_lexlabignore[] = "line %d: label %s ignored";
|
const char e_lexlabignore[] = "line %d: label %s ignored";
|
||||||
const char e_lexlabunknown[] = "line %d: %s unknown label";
|
const char e_lexlabunknown[] = "line %d: %s unknown label";
|
||||||
const char e_lexobsolete1[] = "line %d: `...` obsolete, use $(...)";
|
const char e_lexobsolete1[] = "line %d: `...` obsolete, use $(...)";
|
||||||
|
|
|
@ -138,6 +138,7 @@ extern const char e_lexsyntax3[];
|
||||||
extern const char e_lexsyntax4[];
|
extern const char e_lexsyntax4[];
|
||||||
extern const char e_lexsyntax5[];
|
extern const char e_lexsyntax5[];
|
||||||
extern const char e_lexwarnvar[];
|
extern const char e_lexwarnvar[];
|
||||||
|
extern const char e_lexarithwarn[];
|
||||||
extern const char e_lexobsolete1[];
|
extern const char e_lexobsolete1[];
|
||||||
extern const char e_lexobsolete2[];
|
extern const char e_lexobsolete2[];
|
||||||
extern const char e_lexobsolete3[];
|
extern const char e_lexobsolete3[];
|
||||||
|
|
|
@ -1327,7 +1327,16 @@ breakloop:
|
||||||
state = lp->arg->argval;
|
state = lp->arg->argval;
|
||||||
lp->comp_assign = assignment;
|
lp->comp_assign = assignment;
|
||||||
if(assignment)
|
if(assignment)
|
||||||
|
{
|
||||||
lp->arg->argflag |= ARG_ASSIGN;
|
lp->arg->argflag |= ARG_ASSIGN;
|
||||||
|
if(sh_isoption(SH_NOEXEC))
|
||||||
|
{
|
||||||
|
char *cp = strchr(state, '=');
|
||||||
|
if(cp && strncmp(++cp, "$((", 3) == 0)
|
||||||
|
errormsg(SH_DICT, ERROR_warn(0), e_lexarithwarn, shp->inlineno,
|
||||||
|
state, cp - state, state, cp + 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if(!lp->lex.skipword)
|
else if(!lp->lex.skipword)
|
||||||
lp->assignok = 0;
|
lp->assignok = 0;
|
||||||
lp->arg->argchn.cp = 0;
|
lp->arg->argchn.cp = 0;
|
||||||
|
|
|
@ -250,7 +250,7 @@ static Shnode_t *makeparent(Lex_t *lp, int flag, Shnode_t *child)
|
||||||
return(par);
|
return(par);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int paramsub(const char *str)
|
static const char *paramsub(const char *str)
|
||||||
{
|
{
|
||||||
register int c,sub=0,lit=0;
|
register int c,sub=0,lit=0;
|
||||||
while(c= *str++)
|
while(c= *str++)
|
||||||
|
@ -258,16 +258,20 @@ static int paramsub(const char *str)
|
||||||
if(c=='$' && !lit)
|
if(c=='$' && !lit)
|
||||||
{
|
{
|
||||||
if(*str=='(')
|
if(*str=='(')
|
||||||
return(0);
|
return(NIL(const char*));
|
||||||
if(sub)
|
if(sub)
|
||||||
continue;
|
continue;
|
||||||
if(*str=='{')
|
if(*str=='{')
|
||||||
str++;
|
str++;
|
||||||
if(!isdigit(*str) && strchr("?#@*!$ ",*str)==0)
|
if(!isdigit(*str) && strchr("?#@*!$ ",*str)==0)
|
||||||
return(1);
|
{
|
||||||
|
if(str[-1]=='{')
|
||||||
|
str--; /* variable in the form of ${var} */
|
||||||
|
return(str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(c=='`')
|
else if(c=='`')
|
||||||
return(0);
|
return(NIL(const char*));
|
||||||
else if(c=='[' && !lit)
|
else if(c=='[' && !lit)
|
||||||
sub++;
|
sub++;
|
||||||
else if(c==']' && !lit)
|
else if(c==']' && !lit)
|
||||||
|
@ -275,7 +279,7 @@ static int paramsub(const char *str)
|
||||||
else if(c=='\'')
|
else if(c=='\'')
|
||||||
lit = !lit;
|
lit = !lit;
|
||||||
}
|
}
|
||||||
return(0);
|
return(NIL(const char*));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
|
static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
|
||||||
|
@ -288,8 +292,15 @@ static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
|
||||||
t->ar.arcomp = sh_arithcomp(lp->sh,ap->argval);
|
t->ar.arcomp = sh_arithcomp(lp->sh,ap->argval);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(sh_isoption(SH_NOEXEC) && (ap->argflag&ARG_MAC) && paramsub(ap->argval))
|
const char *p, *q;
|
||||||
errormsg(SH_DICT,ERROR_warn(0),e_lexwarnvar,lp->sh->inlineno,ap->argval);
|
if(sh_isoption(SH_NOEXEC) && (ap->argflag&ARG_MAC) &&
|
||||||
|
((p = paramsub(ap->argval)) != NIL(const char*)))
|
||||||
|
{
|
||||||
|
for(q = p; !isspace(*q) && *q != '\0'; q++)
|
||||||
|
;
|
||||||
|
errormsg(SH_DICT, ERROR_warn(0), e_lexwarnvar,
|
||||||
|
lp->sh->inlineno, ap->argval, q - p, p);
|
||||||
|
}
|
||||||
t->ar.arcomp = 0;
|
t->ar.arcomp = 0;
|
||||||
}
|
}
|
||||||
return(t);
|
return(t);
|
||||||
|
|
Loading…
Reference in a new issue