ash: parser: Fix handling of empty aliases

Upstream commit:

    Date: Tue, 28 Apr 2020 01:15:26 +1000
    parser: Fix handling of empty aliases

    Dash was incorrectly handling empty aliases. When attempting to use an
    empty alias with nothing else, I'm (incorrectly) prompted for more
    input:

    ```
    $ alias empty=''
    $ empty
    >
    ```

    Other shells (e.g., bash, yash) correctly handle the lone, empty alias as an
    empty command:

    ```
    $ alias empty=''
    $ empty
    $
    ```

    The problem here is that we incorrectly enter the loop eating TNLs
    in readtoken().  This patch fixes it by setting checkkwd correctly.

function                                             old     new   delta
list                                                 351     355      +4

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2021-09-08 00:39:16 +02:00
parent 6a9b3f7acf
commit 30af5938af

View File

@ -11755,27 +11755,28 @@ static union node *andor(void);
static union node *pipeline(void); static union node *pipeline(void);
static union node *parse_command(void); static union node *parse_command(void);
static void parseheredoc(void); static void parseheredoc(void);
static int peektoken(void);
static int readtoken(void); static int readtoken(void);
static union node * static union node *
list(int nlflag) list(int nlflag)
{ {
int chknl = nlflag & 1 ? 0 : CHKNL;
union node *n1, *n2, *n3; union node *n1, *n2, *n3;
int tok; int tok;
n1 = NULL; n1 = NULL;
for (;;) { for (;;) {
switch (readtoken()) { checkkwd = chknl | CHKKWD | CHKALIAS;
tok = readtoken();
switch (tok) {
case TNL: case TNL:
if (!(nlflag & 1))
break;
parseheredoc(); parseheredoc();
return n1; return n1;
case TEOF: case TEOF:
if (!n1 && (nlflag & 1)) if (!n1 && !chknl)
n1 = NODE_EOF; n1 = NODE_EOF;
out_eof:
parseheredoc(); parseheredoc();
tokpushback++; tokpushback++;
lasttoken = TEOF; lasttoken = TEOF;
@ -11783,8 +11784,7 @@ list(int nlflag)
} }
tokpushback++; tokpushback++;
checkkwd = CHKNL | CHKKWD | CHKALIAS; if (nlflag == 2 && ((1 << tok) & tokendlist))
if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
return n1; return n1;
nlflag |= 2; nlflag |= 2;
@ -11813,15 +11813,16 @@ list(int nlflag)
n1 = n3; n1 = n3;
} }
switch (tok) { switch (tok) {
case TNL:
case TEOF: case TEOF:
goto out_eof;
case TNL:
tokpushback = 1; tokpushback = 1;
/* fall through */ /* fall through */
case TBACKGND: case TBACKGND:
case TSEMI: case TSEMI:
break; break;
default: default:
if ((nlflag & 1)) if (!chknl)
raise_error_unexpected_syntax(-1); raise_error_unexpected_syntax(-1);
tokpushback = 1; tokpushback = 1;
return n1; return n1;
@ -11995,8 +11996,9 @@ simplecmd(void)
switch (t) { switch (t) {
#if BASH_FUNCTION #if BASH_FUNCTION
case TFUNCTION: case TFUNCTION:
if (peektoken() != TWORD) if (readtoken() != TWORD)
raise_error_unexpected_syntax(TWORD); raise_error_unexpected_syntax(TWORD);
tokpushback = 1;
function_flag = 1; function_flag = 1;
break; break;
#endif #endif
@ -12033,7 +12035,9 @@ simplecmd(void)
#if BASH_FUNCTION #if BASH_FUNCTION
if (function_flag) { if (function_flag) {
checkkwd = CHKNL | CHKKWD; checkkwd = CHKNL | CHKKWD;
switch (peektoken()) { t = readtoken();
tokpushback = 1;
switch (t) {
case TBEGIN: case TBEGIN:
case TIF: case TIF:
case TCASE: case TCASE:
@ -13306,16 +13310,6 @@ readtoken(void)
return t; return t;
} }
static int
peektoken(void)
{
int t;
t = readtoken();
tokpushback = 1;
return t;
}
/* /*
* Read and parse a command. Returns NODE_EOF on end of file. * Read and parse a command. Returns NODE_EOF on end of file.
* (NULL is a valid parse tree indicating a blank line.) * (NULL is a valid parse tree indicating a blank line.)