fix parser state with funsubs in PS2 and line continuations; fix for @P transformation in prompt strings

This commit is contained in:
Chet Ramey
2024-04-01 12:20:58 -04:00
parent 4f2595eff3
commit 2532a2ccef
14 changed files with 108 additions and 30 deletions
+41
View File
@@ -8997,3 +8997,44 @@ Makefile.in
- distclean,maintainer-clean: remove $(CREATED_HEADERS) and
$(CREATED_MACOS)
- maintainer-clean: remove ctags/etags files
3/28
----
bashline.c,bashline.h
- uw_restore_parser_state: moved to parse.y and declaration to shell.h
shell.c,shell.h
- parsing_command: new flag, set to 1 when calling yyparse; saved and
restored by save_parser_state/restore_parser_state
parse.y,shell.h
- parsing_command: new element of sh_parser_state_t
sig.c
- throw_to_top_level: reset executing and parsing_command to 0
parse.y
- parse_comsub: set parsing_command to 1 before calling yyparse()
eval.c
- parse_command: set parsing_command to 1 before calling yyparse(),
restore old value when yyparse returns
subst.c
- function_substitute: if we are parsing a command, save the parser
state with save_parser_state and add an unwind-protect to restore it
From a report from Grisha Levit <grishalevit@gmail.com>
- function_substitute: only save and restore the pipestatus array if
we are not parsing a command, since save_parser_state saves it
parse.y,externs.h
- decode_prompt_string: now takes an additional argument to determine
whether this is expanding PS[0124] or the @P transformation
- decode_prompt_string: keep track of the (last) real prompt string
being decoded so a @P expansion embedded in the prompt returns the
same result as the prompt string itself for the \! and \# expansions
From a patch from Grisha Levit <grishalevit@gmail.com>
parse.y,print_cmd.c,eval.c,subst.c
- decode_prompt_string: changed all callers
+4 -3
View File
@@ -586,7 +586,8 @@ CREATED_SUPPORT = signames.h recho$(EXEEXT) zecho$(EXEEXT) printenv$(EXEEXT) \
CREATED_MACOS = recho.dSYM zecho.dSYM printenv.dSYM xcase.dSYM \
bashversion.dSYM mksyntax.dSYM ${DEFDIR}/psize.aux.dSYM
CREATED_CONFIGURE = config.h config.cache config.status config.log \
stamp-h po/POTFILES config.status.lineno
stamp-h po/POTFILES config.status.lineno \
stdckdint.h
CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \
lib/readline/Makefile lib/glob/Makefile \
lib/sh/Makefile lib/tilde/Makefile lib/malloc/Makefile \
@@ -595,7 +596,7 @@ CREATED_MAKEFILES = Makefile builtins/Makefile doc/Makefile \
examples/loadables/perl/Makefile support/Makefile \
lib/intl/Makefile po/Makefile po/Makefile.in
CREATED_HEADERS = signames.h config.h pathnames.h version.h y.tab.h \
${DEFDIR}/builtext.h stdckdint.h
${DEFDIR}/builtext.h
OTHER_DOCS = $(srcdir)/CHANGES $(srcdir)/COMPAT $(srcdir)/NEWS $(srcdir)/POSIX \
$(srcdir)/RBASH $(srcdir)/README
@@ -988,7 +989,7 @@ maintainer-clean: basic-clean
done
-( cd $(PO_DIR) ; $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ )
-( cd $(LOADABLES_DIR) && $(MAKE) $(MFLAGS) DESTDIR=$(DESTDIR) $@ )
$(RM) $(CREATED_CONFIGURE) Makefile $(CREATED_MAKEFILES) tags TAGS
$(RM) $(CREATED_CONFIGURE) Makefile $(CREATED_MAKEFILES)
$(RM) $(CREATED_SUPPORT) $(CREATED_HEADERS)
$(RM) -rf $(CREATED_MACOS)
-6
View File
@@ -4490,12 +4490,6 @@ readline_set_char_offset (int ind, int *varp)
}
}
void
uw_restore_parser_state (void *ps)
{
restore_parser_state (ps);
}
void
uw_rl_set_signals (void *ignore)
{
+1 -2
View File
@@ -1,6 +1,6 @@
/* bashline.h -- interface to the bash readline functions in bashline.c. */
/* Copyright (C) 1993-2023 Free Software Foundation, Inc.
/* Copyright (C) 1993-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -46,7 +46,6 @@ extern int bash_re_edit (const char *);
extern void bashline_set_event_hook (void);
extern void bashline_reset_event_hook (void);
extern void uw_restore_parser_state (void *);
extern void uw_rl_set_signals (void *);
extern int bind_keyseq_to_unix_command (char *);
+6 -3
View File
@@ -1,6 +1,6 @@
/* eval.c -- reading and evaluating commands. */
/* Copyright (C) 1996-2022 Free Software Foundation, Inc.
/* Copyright (C) 1996-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -157,7 +157,7 @@ reader_loop (void)
old_eof = EOF_Reached;
EOF_Reached = 0;
ps0_string = decode_prompt_string (ps0_prompt);
ps0_string = decode_prompt_string (ps0_prompt, 1);
if (ps0_string && *ps0_string)
{
fprintf (stderr, "%s", ps0_string);
@@ -329,7 +329,7 @@ execute_prompt_command (void)
int
parse_command (void)
{
int r;
int r, old_parsing;
need_here_doc = 0;
if ((parser_state & (PST_CMDSUBST|PST_FUNSUBST)) == 0)
@@ -352,11 +352,14 @@ parse_command (void)
send_pwd_to_eterm (); /* Yuck */
}
old_parsing = parsing_command;
parsing_command = 1;
current_command_line_count = 0;
r = yyparse ();
if (need_here_doc)
gather_here_documents ();
parsing_command = old_parsing;
return (r);
}
+1 -1
View File
@@ -128,7 +128,7 @@ extern void clear_shell_input_line (void);
extern int handle_ignoreeof (int);
extern char *decode_prompt_string (char *);
extern char *decode_prompt_string (char *, int);
extern int get_current_prompt_level (void);
extern void set_current_prompt_level (int);
+30 -8
View File
@@ -4462,6 +4462,7 @@ parse_comsub (int qc, int open, int close, size_t *lenp, int flags)
current_token = '\n'; /* XXX */
token_to_read = (open == '(') ? DOLPAREN : DOLBRACE; /* let's trick the parser ) */
parsing_command = 1; /* saved as part of sh_parser_state_t */
r = yyparse ();
if (open == '{')
@@ -5879,7 +5880,7 @@ reset_readline_prompt (void)
if (prompt_string_pointer)
{
temp_prompt = (*prompt_string_pointer)
? decode_prompt_string (*prompt_string_pointer)
? decode_prompt_string (*prompt_string_pointer, 1)
: (char *)NULL;
if (temp_prompt == 0)
@@ -6040,7 +6041,7 @@ prompt_again (int force)
prompt_string_pointer = &ps1_prompt;
temp_prompt = *prompt_string_pointer
? decode_prompt_string (*prompt_string_pointer)
? decode_prompt_string (*prompt_string_pointer, 1)
: (char *)NULL;
if (temp_prompt == 0)
@@ -6140,13 +6141,16 @@ prompt_history_number (char *pmt)
\\ a backslash
\[ begin a sequence of non-printing chars
\] end a sequence of non-printing chars
IS_PROMPT is non-zero if we are decoding one of the PS[0124] prompt strings
instead of an arbitrary string applying the @P transformation.
*/
#define PROMPT_GROWTH 48
char *
decode_prompt_string (char *string)
decode_prompt_string (char *string, int is_prompt)
{
WORD_LIST *list;
char *result, *t, *orig_string, *last_lastarg;
char *result, *t, *last_lastarg;
struct dstack save_dstack;
int last_exit_value, last_comsub_pid, last_comsub_status;
#if defined (PROMPT_STRING_DECODE)
@@ -6159,11 +6163,16 @@ decode_prompt_string (char *string)
char timebuf[128];
char *timefmt;
size_t tslen;
static char *decoding_prompt;
result = (char *)xmalloc (result_size = PROMPT_GROWTH);
result[result_index = 0] = 0;
temp = (char *)NULL;
orig_string = string;
/* Keep track of which (real) prompt string is being decoded so that we can
process embedded ${var@P} expansions correctly. */
if (is_prompt)
decoding_prompt = string;
while (c = *string++)
{
@@ -6179,7 +6188,7 @@ decode_prompt_string (char *string)
#if !defined (HISTORY)
temp = savestring ("1");
#else /* HISTORY */
temp = itos (prompt_history_number (orig_string));
temp = itos (prompt_history_number (decoding_prompt));
#endif /* HISTORY */
string--; /* add_string increments string again. */
goto add_string;
@@ -6440,7 +6449,7 @@ decode_prompt_string (char *string)
n = current_command_number;
/* If we have already incremented current_command_number (PS4,
${var@P}), compensate */
if (orig_string != ps0_prompt && orig_string != ps1_prompt && orig_string != ps2_prompt)
if (decoding_prompt != ps0_prompt && decoding_prompt != ps1_prompt && decoding_prompt != ps2_prompt)
n--;
temp = itos (n);
goto add_string;
@@ -6449,7 +6458,7 @@ decode_prompt_string (char *string)
#if !defined (HISTORY)
temp = savestring ("1");
#else /* HISTORY */
temp = itos (prompt_history_number (orig_string));
temp = itos (prompt_history_number (decoding_prompt));
#endif /* HISTORY */
goto add_string;
@@ -6574,6 +6583,10 @@ not_escape:
}
dstack = save_dstack;
#if defined (PROMPT_STRING_DECODE)
if (is_prompt)
decoding_prompt = (char *)NULL;
#endif
return (result);
}
@@ -7081,6 +7094,8 @@ save_parser_state (sh_parser_state_t *ps)
ps->parser_state = parser_state;
ps->token_state = save_token_state ();
ps->parsing_command = parsing_command;
ps->input_line_terminator = shell_input_line_terminator;
ps->eof_encountered = eof_encountered;
ps->eol_lookahead = eol_ungetc_lookahead;
@@ -7143,6 +7158,7 @@ restore_parser_state (sh_parser_state_t *ps)
restore_token_state (ps->token_state);
free (ps->token_state);
}
parsing_command = ps->parsing_command;
shell_input_line_terminator = ps->input_line_terminator;
eof_encountered = ps->eof_encountered;
@@ -7195,6 +7211,12 @@ restore_parser_state (sh_parser_state_t *ps)
shell_eof_token = ps->eof_token;
}
void
uw_restore_parser_state (void *ps)
{
restore_parser_state (ps);
}
/* Free the parts of a parser state struct that have allocated memory. */
void
flush_parser_state (sh_parser_state_t *ps)
+1 -1
View File
@@ -1,7 +1,7 @@
/* parser.h -- Everything you wanted to know about the parser, but were
afraid to ask. */
/* Copyright (C) 1995-2021 Free Software Foundation, Inc.
/* Copyright (C) 1995-2024 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1 -1
View File
@@ -460,7 +460,7 @@ indirection_level_string (void)
return (indirection_string);
old = change_flag ('x', FLAG_OFF);
ps4 = decode_prompt_string (ps4);
ps4 = decode_prompt_string (ps4, 1);
if (old)
change_flag ('x', FLAG_ON);
+3
View File
@@ -170,6 +170,9 @@ int debugging_login_shell = 0;
/* The environment that the shell passes to other commands. */
char **shell_environment;
/* Non-zero when we are parsing a command, managed by parse_command/parse_comsub */
int parsing_command = 0;
/* Non-zero when we are executing a top-level command. */
int executing = 0;
+3
View File
@@ -97,6 +97,7 @@ extern char *command_execution_string;
extern int debugging_mode;
extern int executing, login_shell;
extern int parsing_command;
extern int interactive, interactive_shell;
extern int startup_state;
extern int reading_shell_script;
@@ -175,6 +176,7 @@ typedef struct _sh_parser_state_t
/* parsing state */
int parser_state;
int *token_state;
int parsing_command;
char *token;
size_t token_buffer_size;
@@ -240,6 +242,7 @@ extern char *parser_remaining_input (void);
extern sh_parser_state_t *save_parser_state (sh_parser_state_t *);
extern void restore_parser_state (sh_parser_state_t *);
extern void flush_parser_state (sh_parser_state_t *);
extern void uw_restore_parser_state (void *);
extern sh_input_line_state_t *save_input_line_state (sh_input_line_state_t *);
extern void restore_input_line_state (sh_input_line_state_t *);
+2
View File
@@ -468,6 +468,8 @@ throw_to_top_level (void)
comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
variable_context = 0;
executing = parsing_command = 0;
if (interactive && print_newline)
{
fflush (stdout);
+14 -4
View File
@@ -6961,9 +6961,10 @@ function_substitute (char *string, int quoted, int flags)
char *afn;
sigset_t set, oset;
sh_getopt_state_t *gs;
sh_parser_state_t ps;
SHELL_VAR *gv;
#if defined (ARRAY_VARS)
ARRAY *ps;
ARRAY *psa;
#endif
if (valsub = (string && *string == '|'))
@@ -7014,9 +7015,18 @@ function_substitute (char *string, int quoted, int flags)
add_unwind_protect (uw_pop_var_context, 0);
add_unwind_protect (uw_maybe_restore_getopt_state, gs);
if (parsing_command)
{
save_parser_state (&ps);
add_unwind_protect (uw_restore_parser_state, &ps);
}
#if defined (ARRAY_VARS)
ps = save_pipestatus_array ();
add_unwind_protect (uw_restore_pipestatus_array, ps);
if (parsing_command == 0)
{
psa = save_pipestatus_array ();
add_unwind_protect (uw_restore_pipestatus_array, psa);
}
#endif
subst_assign_varlist = 0;
@@ -8756,7 +8766,7 @@ string_transform (int xc, SHELL_VAR *v, char *s)
ret = ansicstr (s, strlen (s), 0, 0, 0);
break;
case 'P':
ret = decode_prompt_string (s);
ret = decode_prompt_string (s, 0);
break;
case 'Q':
ret = sh_quote_reusable (s, 0);
+1 -1
View File
@@ -206,7 +206,7 @@ sh_xrealloc (PTR_T pointer, size_t bytes, char *file, int line)
}
PTR_T
sh_xreallocarray (PTR_T ptr, size_t nmemb, size_t size, const char *file, int line)
sh_xreallocarray (PTR_T ptr, size_t nmemb, size_t size, char *file, int line)
{
size_t nbytes;