From 469998015f57a552718420a4050d90e5dae6a6fd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 29 Jul 2017 21:12:29 +0200 Subject: [PATCH] ash: [PARSER] Add FAKEEOFMARK for expandstr Upstream commit: Date: Thu, 27 Dec 2007 13:54:16 +1100 [PARSER] Add FAKEEOFMARK for expandstr Previously expandstr used the string "" to indicate that it needs to be treated just like a here-doc except that there is no terminator. However, the string "" is in fact a valid here-doc terminator so now that we deal with it correctly expandstr no longer works in the presence of new-lines in the prompt. This patch introduces the FAKEEOFMARK macro which does not equal any real EOF marker but is distinct from the NULL pointer which is used to indicate non-here-doc contexts. Thanks to Markus Triska for reporting this regression. Signed-off-by: Herbert Xu Unfortunately, I did not find the failing example for this old fix. I also tweaked the code which was added by this commit: " Date: Mon Sep 24 18:30:02 2007 +0000 ash: fix prompt expansion (Natanael Copa ) " since other parts of code do expect expandstr() to use DQSYNTAX, not PSSYNTAX. function old new delta parse_stream 2609 2634 +25 setprompt_if 128 133 +5 read_profile 32 37 +5 evalcommand 1334 1339 +5 expandstr 122 120 -2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/1 up/down: 40/-2) Total: 38 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 2bfec83e6..3184249f5 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2488,8 +2488,18 @@ putprompt(const char *s) #endif /* expandstr() needs parsing machinery, so it is far away ahead... */ -static const char *expandstr(const char *ps); +static const char *expandstr(const char *ps, int syntax_type); +/* Values for syntax param */ +#define BASESYNTAX 0 /* not in quotes */ +#define DQSYNTAX 1 /* in double quotes */ +#define SQSYNTAX 2 /* in single quotes */ +#define ARISYNTAX 3 /* in arithmetic */ +#define PSSYNTAX 4 /* prompt. never passed to SIT() */ +/* PSSYNTAX expansion is identical to DQSYNTAX, except keeping '\$' as '\$' */ +/* + * called by editline -- any expansions to the prompt should be added here. + */ static void setprompt_if(smallint do_set, int whichprompt) { @@ -2513,7 +2523,7 @@ setprompt_if(smallint do_set, int whichprompt) } #if ENABLE_ASH_EXPAND_PRMT pushstackmark(&smark, stackblocksize()); - putprompt(expandstr(prompt)); + putprompt(expandstr(prompt, PSSYNTAX)); popstackmark(&smark); #else putprompt(prompt); @@ -2838,13 +2848,6 @@ enum { /* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF, * caller must ensure proper cast on it if c is *char_ptr! */ -/* Values for syntax param */ -#define BASESYNTAX 0 /* not in quotes */ -#define DQSYNTAX 1 /* in double quotes */ -#define SQSYNTAX 2 /* in single quotes */ -#define ARISYNTAX 3 /* in arithmetic */ -#define PSSYNTAX 4 /* prompt. never passed to SIT() */ - #if USE_SIT_FUNCTION static int @@ -9709,7 +9712,7 @@ evalcommand(union node *cmd, int flags) if (xflag) { const char *pfx = ""; - fdprintf(preverrout_fd, "%s", expandstr(ps4val())); + fdprintf(preverrout_fd, "%s", expandstr(ps4val(), DQSYNTAX)); sp = varlist.list; while (sp) { @@ -11522,6 +11525,15 @@ decode_dollar_squote(void) } #endif +/* Used by expandstr to get here-doc like behaviour. */ +#define FAKEEOFMARK ((char*)(uintptr_t)1) + +static ALWAYS_INLINE int +realeofmark(const char *eofmark) +{ + return eofmark && eofmark != FAKEEOFMARK; +} + /* * If eofmark is NULL, read a word or a redirection symbol. If eofmark * is not NULL, read a here document. In the latter case, eofmark is the @@ -11767,7 +11779,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) * we are at the end of the here document, this routine sets the c to PEOF. */ checkend: { - if (eofmark) { + if (realeofmark(eofmark)) { int markloc; char *p; @@ -12472,22 +12484,18 @@ parseheredoc(void) } -/* - * called by editline -- any expansions to the prompt should be added here. - */ static const char * -expandstr(const char *ps) +expandstr(const char *ps, int syntax_type) { union node n; int saveprompt; - /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value, - * and token processing _can_ alter it (delete NULs etc). */ + /* XXX Fix (char *) cast. */ setinputstring((char *)ps); saveprompt = doprompt; doprompt = 0; - readtoken1(pgetc(), PSSYNTAX, nullstr, 0); + readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); doprompt = saveprompt; popfile(); @@ -13548,7 +13556,7 @@ procargs(char **argv) static void read_profile(const char *name) { - name = expandstr(name); + name = expandstr(name, DQSYNTAX); if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) return; cmdloop(0);