sh: Solve the alias recursion problem in a less hackish way.

Add the space to avoid alias recursion when the alias is expanded, not when
it is added.

As a result, displaying an alias via command -v, command -V or type no
longer erroneously appends a space. Adjust the tests so they now require
this bug to be absent.
This commit is contained in:
Jilles Tjoelker 2014-01-24 16:40:51 +00:00
parent 51fcfa2666
commit 4b489a60e1
5 changed files with 11 additions and 48 deletions

View File

@ -68,18 +68,7 @@ setalias(const char *name, const char *val)
if (equal(name, ap->name)) {
INTOFF;
ckfree(ap->val);
/* See HACK below. */
#ifdef notyet
ap->val = savestr(val);
#else
{
size_t len = strlen(val);
ap->val = ckmalloc(len + 2);
memcpy(ap->val, val, len);
ap->val[len] = ' ';
ap->val[len+1] = '\0';
}
#endif
INTON;
return;
}
@ -88,34 +77,7 @@ setalias(const char *name, const char *val)
INTOFF;
ap = ckmalloc(sizeof (struct alias));
ap->name = savestr(name);
/*
* XXX - HACK: in order that the parser will not finish reading the
* alias value off the input before processing the next alias, we
* dummy up an extra space at the end of the alias. This is a crock
* and should be re-thought. The idea (if you feel inclined to help)
* is to avoid alias recursions. The mechanism used is: when
* expanding an alias, the value of the alias is pushed back on the
* input as a string and a pointer to the alias is stored with the
* string. The alias is marked as being in use. When the input
* routine finishes reading the string, it marks the alias not
* in use. The problem is synchronization with the parser. Since
* it reads ahead, the alias is marked not in use before the
* resulting token(s) is next checked for further alias sub. The
* H A C K is that we add a little fluff after the alias value
* so that the string will not be exhausted. This is a good
* idea ------- ***NOT***
*/
#ifdef notyet
ap->val = savestr(val);
#else /* hack */
{
size_t len = strlen(val);
ap->val = ckmalloc(len + 2);
memcpy(ap->val, val, len);
ap->val[len] = ' '; /* fluff */
ap->val[len+1] = '\0';
}
#endif
ap->flag = 0;
ap->next = *app;
*app = ap;
@ -207,14 +169,8 @@ comparealiases(const void *p1, const void *p2)
static void
printalias(const struct alias *a)
{
char *p;
out1fmt("%s=", a->name);
/* Don't print the space added above. */
p = a->val + strlen(a->val) - 1;
*p = '\0';
out1qstr(a->val);
*p = ' ';
out1c('\n');
}

View File

@ -226,7 +226,14 @@ preadbuffer(void)
int more;
char savec;
if (parsefile->strpush) {
while (parsefile->strpush) {
/*
* Add a space to the end of an alias to ensure that the
* alias remains in use while parsing its last word.
* This avoids alias recursions.
*/
if (parsenleft == -1 && parsefile->strpush->ap != NULL)
return ' ';
popstring();
if (--parsenleft >= 0)
return (*parsenextc++);

View File

@ -4,4 +4,4 @@ true
fun
break
if
alias foo='bar '
alias foo=bar

View File

@ -5,4 +5,4 @@ fun is a shell function
break is a special shell builtin
if is a shell keyword
{ is a shell keyword
foo is an alias for bar
foo is an alias for bar

View File

@ -4,4 +4,4 @@ fun is a shell function
break is a special shell builtin
if is a shell keyword
{ is a shell keyword
foo is an alias for bar
foo is an alias for bar