From: Chet Ramey Date: Mon, 1 Apr 2024 16:20:58 +0000 (-0400) Subject: fix parser state with funsubs in PS2 and line continuations; fix for @P transformatio... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2532a2ccefc50e26a32ddd430286af6f5c43d881;p=thirdparty%2Fbash.git fix parser state with funsubs in PS2 and line continuations; fix for @P transformation in prompt strings --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 8f18eaa1..a4f78006 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -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 + - 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 + +parse.y,print_cmd.c,eval.c,subst.c + - decode_prompt_string: changed all callers + diff --git a/Makefile.in b/Makefile.in index 8069162a..14092c41 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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) diff --git a/bashline.c b/bashline.c index 353e8b1e..eedb09ff 100644 --- a/bashline.c +++ b/bashline.c @@ -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) { diff --git a/bashline.h b/bashline.h index 514c07ce..430e369f 100644 --- a/bashline.h +++ b/bashline.h @@ -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 *); diff --git a/eval.c b/eval.c index a08cb578..cbf408f0 100644 --- a/eval.c +++ b/eval.c @@ -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); } diff --git a/externs.h b/externs.h index bc6f5cc1..a7c41928 100644 --- a/externs.h +++ b/externs.h @@ -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); diff --git a/parse.y b/parse.y index 368c3423..d129dd28 100644 --- a/parse.y +++ b/parse.y @@ -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) diff --git a/parser.h b/parser.h index 14cd4149..bef71707 100644 --- a/parser.h +++ b/parser.h @@ -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. diff --git a/print_cmd.c b/print_cmd.c index 9d3ab73b..36268e19 100644 --- a/print_cmd.c +++ b/print_cmd.c @@ -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); diff --git a/shell.c b/shell.c index add8b1cd..01fffac2 100644 --- a/shell.c +++ b/shell.c @@ -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; diff --git a/shell.h b/shell.h index 5a18f405..b9d259a5 100644 --- a/shell.h +++ b/shell.h @@ -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 *); diff --git a/sig.c b/sig.c index d902b5cf..8c1b9567 100644 --- a/sig.c +++ b/sig.c @@ -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); diff --git a/subst.c b/subst.c index f4254b13..a29eb5be 100644 --- a/subst.c +++ b/subst.c @@ -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); diff --git a/xmalloc.c b/xmalloc.c index 05de3874..340ce84d 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -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;