When \# or \! is decoded in a ${var@P} expansion embedded in a prompt string, the value can be off by one from that of the same sequence embedded directly in the prompt string.
$ H='\!' $ PS1='(\!:${H@P}) $' (3:2 501:500) $ * parse.y - decode_prompt_string: accept new int flag to signify a real prompt string is being decoded; update callers * externs.h - decode_prompt_string: update declaration --- eval.c | 2 +- externs.h | 2 +- parse.y | 23 ++++++++++++++++------- print_cmd.c | 2 +- subst.c | 2 +- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/eval.c b/eval.c index a08cb578..2fee976c 100644 --- a/eval.c +++ b/eval.c @@ -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); diff --git a/externs.h b/externs.h index b60fb79e..683c72f6 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 3e28d24d..3211ea64 100644 --- a/parse.y +++ b/parse.y @@ -6036,7 +6036,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) @@ -6139,10 +6139,10 @@ prompt_history_number (char *pmt) */ #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) @@ -6155,11 +6155,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++) { @@ -6175,7 +6180,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; @@ -6436,7 +6441,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; @@ -6445,7 +6450,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; @@ -6570,6 +6575,10 @@ not_escape: } dstack = save_dstack; +#if defined (PROMPT_STRING_DECODE) + if (is_prompt) + decoding_prompt = (char *)NULL; +#endif return (result); } 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/subst.c b/subst.c index 2c51021b..ee0afd67 100644 --- a/subst.c +++ b/subst.c @@ -8745,7 +8745,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); -- 2.44.0