From d7a6d947dfdbb41d806f4bd65f8a74bffb5acbb4 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Mon, 13 Feb 2023 10:48:05 -0500 Subject: [PATCH] fix for $_ when executing $PROMPT_COMMAND; fix for extra line in history after here-document in command substitution --- CWRU/CWRU.chlog | 37 ++++++++++++++--- bashline.c | 21 ++++------ builtins/declare.def | 16 ++++++-- doc/bash.1 | 4 +- doc/bashref.texi | 4 +- examples/loadables/mkdir.c | 82 ++++++++++++++++++++++--------------- execute_cmd.c | 3 +- execute_cmd.h | 1 + parse.y | 24 ++++++++++- po/zh_TW.gmo | Bin 168812 -> 168819 bytes po/zh_TW.po | 20 ++++----- 11 files changed, 140 insertions(+), 72 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 51dbb384..8f41fe84 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -5272,8 +5272,9 @@ arrayfunc.c --- parse.y - discard_until: now returns the last character read. If we get an - EOF while processing a comment, return EOF - - shell_getc: if discard_until returns EOF, return yacc_EOF + EOF while processing a comment, return EOF (rarely happens; + shell_getc returns EOF only under certain circumstances) + - read_token: if discard_until returns EOF, return yacc_EOF input.h - bclearerror: new macro, clears the B_ERROR flag in the buffered @@ -5294,7 +5295,31 @@ doc/{bash.1,bashref.texi} 2/8 --- bashline.c - - alias_expand_line: if alias_expand doesn't change rl_line_buffer, - just return right away without changing rl_point. Inspired by a - report from Addison Brendtro - - history_expand_line: ditto + - set_up_new__line: if the new line doesn't change rl_line_buffer, + just return right away without changing rl_point. Affects + alias-expand-line, history-expand-line, and history-and-alias-expand-line. + Inspired by a report from + Addison Brendtro + +builtins/declare.def + - declare_internal: make multiple calls to `local -' at the same + context have no effect after the first one. That way we don't keep + overwriting the saved option set. Report and fix from + Emanuele Torre + + 2/10 + ---- +execute_cmd.[ch] + - bind_lastarg: now a public function + +parse.y + - execute_variable_command: call bind_lastarg instead of bind_variable + to avoid exporting $_ if allexport is set. Fix from + Emanuele Torre + +bashhist.c + - history_delimiting_chars: if we're parsing some kind of delimited + construct that's *not* a quoted string, don't bother adding an extra + newline to the history if the current history entry already ends in + a newline. From https://savannah.gnu.org/support/?110838 via + Ganapathi Kamath diff --git a/bashline.c b/bashline.c index f4665759..dfe5ab9b 100644 --- a/bashline.c +++ b/bashline.c @@ -2713,6 +2713,13 @@ set_up_new_line (char *new_line) { int old_point, at_end; + /* If we didn't expand anything, don't change anything. */ + if (STREQ (new_line, rl_line_buffer)) + { + free (new_line); + return; + } + old_point = rl_point; at_end = rl_point == rl_end; @@ -2741,13 +2748,6 @@ alias_expand_line (int count, int ignore) new_line = alias_expand (rl_line_buffer); - /* If we didn't expand anything, don't change anything. */ - if (new_line && STREQ (new_line, rl_line_buffer)) - { - free (new_line); - return (0); - } - if (new_line) { set_up_new_line (new_line); @@ -2770,13 +2770,6 @@ history_expand_line (int count, int ignore) new_line = history_expand_line_internal (rl_line_buffer); - /* If we didn't expand anything, don't change anything. */ - if (new_line && STREQ (new_line, rl_line_buffer)) - { - free (new_line); - return (0); - } - if (new_line) { set_up_new_line (new_line); diff --git a/builtins/declare.def b/builtins/declare.def index f7dac728..28100de1 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -409,11 +409,19 @@ declare_internal (WORD_LIST *list, int local_var) if (local_var && variable_context && STREQ (name, "-")) { + int o; + + o = localvar_inherit; + localvar_inherit = 0; var = make_local_variable ("-", 0); - FREE (value_cell (var)); /* just in case */ - value = get_current_options (); - var_setvalue (var, value); - VSETATTR (var, att_invisible); + localvar_inherit = o; + + if (value_cell (var) == NULL) /* no duplicate instances */ + { + value = get_current_options (); + var_setvalue (var, value); + VSETATTR (var, att_invisible); + } NEXT_VARIABLE (); } diff --git a/doc/bash.1 b/doc/bash.1 index 4efb6765..376e347e 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -9278,7 +9278,9 @@ is used within a function, it causes the variable to have a visible scope restricted to that function and its children. If \fIname\fP is \-, the set of shell options is made local to the function in which \fBlocal\fP is invoked: shell options changed using the -\fBset\fP builtin inside the function are restored to their original values +\fBset\fP builtin inside the function +after the call to \fBlocal\fP +are restored to their original values when the function returns. The restore is effected as if a series of \fBset\fP commands were executed to restore the values that were in place before the function. diff --git a/doc/bashref.texi b/doc/bashref.texi index 5b44ce74..bd24d715 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -4787,7 +4787,9 @@ The @var{option} can be any of the options accepted by @code{declare}. children. If @var{name} is @samp{-}, the set of shell options is made local to the function in which @code{local} is invoked: shell options changed using -the @code{set} builtin inside the function are restored to their original +the @code{set} builtin inside the function +after the call to @code{local} +are restored to their original values when the function returns. The restore is effected as if a series of @code{set} commands were executed to restore the values that were in place before the function. diff --git a/examples/loadables/mkdir.c b/examples/loadables/mkdir.c index b0df8f0d..55ffbd07 100644 --- a/examples/loadables/mkdir.c +++ b/examples/loadables/mkdir.c @@ -3,7 +3,7 @@ /* See Makefile for compilation details. */ /* - Copyright (C) 1999-2009,2022 Free Software Foundation, Inc. + Copyright (C) 1999-2009,2022-2023 Free Software Foundation, Inc. This file is part of GNU Bash. Bash is free software: you can redistribute it and/or modify @@ -135,10 +135,12 @@ mkdir_builtin (WORD_LIST *list) static int make_path (char *path, int user_mode, int nmode, int parent_mode) { - int oumask; + mode_t oumask; struct stat sb; char *p, *npath; + int tail; + /* If we don't have to do any work, don't do any work. */ if (stat (path, &sb) == 0) { if (S_ISDIR (sb.st_mode) == 0) @@ -166,48 +168,64 @@ make_path (char *path, int user_mode, int nmode, int parent_mode) while (*p == '/') p++; - while (p = strchr (p, '/')) + tail = 0; + while (tail == 0) { - *p = '\0'; - if (stat (npath, &sb) != 0) + if (*p == '\0') + tail = 1; + else + p = strchr (p, '/'); + if (p) + *p = '\0'; + else + tail = 1; + if (mkdir (npath, 0) < 0) { - if (mkdir (npath, 0)) + /* "Each dir operand that names an existing directory shall be + ignored without error." */ + if (errno == EEXIST || errno == EISDIR) + { + int e = errno; + int fail = 0; + + if (stat (npath, &sb) != 0) + { + fail = 1; + builtin_error ("cannot create directory `%s': %s", npath, strerror (e)); + } + else if (e == EEXIST && S_ISDIR (sb.st_mode) == 0) + { + fail = 1; + builtin_error ("`%s': file exists but is not a directory", npath); + } + if (fail) + { + umask (original_umask); + free (npath); + return 1; + } + } + else { builtin_error ("cannot create directory `%s': %s", npath, strerror (errno)); umask (original_umask); free (npath); return 1; } - if (chmod (npath, parent_mode) != 0) - { - builtin_error ("cannot chmod directory `%s': %s", npath, strerror (errno)); - umask (original_umask); - free (npath); - return 1; - } } - else if (S_ISDIR (sb.st_mode) == 0) - { - builtin_error ("`%s': file exists but is not a directory", npath); - umask (original_umask); - free (npath); - return 1; - } - - *p++ = '/'; /* restore slash */ - while (*p == '/') + if (chmod (npath, (tail == 0) ? parent_mode : nmode) != 0) + { + builtin_error ("cannot chmod directory `%s': %s", npath, strerror (errno)); + umask (original_umask); + free (npath); + return 1; + } + if (tail == 0) + *p++ = '/'; /* restore slash */ + while (p && *p == '/') /* skip consecutive slashes or trailing slash */ p++; } - /* Create the final directory component. */ - if (stat (npath, &sb) && mkdir (npath, nmode)) - { - builtin_error ("cannot create directory `%s': %s", npath, strerror (errno)); - umask (original_umask); - free (npath); - return 1; - } - umask (original_umask); free (npath); return 0; diff --git a/execute_cmd.c b/execute_cmd.c index d4c082d0..18540409 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -121,7 +121,6 @@ extern int close (int); /* Static functions defined and used in this file. */ static void close_pipes (int, int); static void do_piping (int, int); -static void bind_lastarg (char *); static int shell_control_structure (enum command_type); static void cleanup_redirects (REDIRECT *); @@ -4000,7 +3999,7 @@ execute_cond_command (COND_COM *cond_command) } #endif /* COND_COMMAND */ -static void +void bind_lastarg (char *arg) { SHELL_VAR *var; diff --git a/execute_cmd.h b/execute_cmd.h index 37e386ab..d9c3e7b1 100644 --- a/execute_cmd.h +++ b/execute_cmd.h @@ -120,4 +120,5 @@ extern void close_all_files (void); extern void restore_funcarray_state (struct func_array_state *); #endif +extern void bind_lastarg (char *); #endif /* _EXECUTE_CMD_H_ */ diff --git a/parse.y b/parse.y index 379fdaad..9178e9a7 100644 --- a/parse.y +++ b/parse.y @@ -2849,7 +2849,7 @@ execute_variable_command (const char *command, const char *vname) parse_and_execute (savestring (command), vname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOOPTIMIZE); restore_parser_state (&ps); - bind_variable ("_", last_lastarg, 0); + bind_lastarg (last_lastarg); FREE (last_lastarg); if (token_to_read == '\n') /* reset_parser was called */ @@ -5636,7 +5636,27 @@ history_delimiting_chars (const char *line) last_was_heredoc = 0; if (dstack.delimiter_depth != 0) - return ("\n"); + { + char ch; + HIST_ENTRY *current; + size_t curlen; + + ch = current_delimiter(dstack); + if (shellquote(ch)) + return ("\n"); + else if (ch == '(') /* ) and maybe for other non-quote-char delimiters */ + { + using_history (); + current = previous_history (); + curlen = current ? strlen (current->line) : 0; + /* If we're not reading some kind of quoted string, don't bother + adding a newline if the current history entry already ends in a + newline. It's just extra. */ + return ((curlen > 0 && current->line[curlen - 1] == '\n') ? "" : "\n"); + } + else + return ("\n"); + } /* We look for current_command_line_count == 2 because we are looking to add the first line of the body of the here document (the second line diff --git a/po/zh_TW.gmo b/po/zh_TW.gmo index 9dd7546f07248c44a395e1f7799c47f982dd372b..a56fe55c75266bcd659458f9740b30e4b2516bf1 100644 GIT binary patch delta 3791 zcmXZfdw7rM9mnzS{YV_rrHDf#&Lyg8LaeTr>e_T>T8GxD4!?+QS2J~(&0O~WUC&p8N2<55MG}Tcd7m zjjH(dW1&8gX7v_0YiVXL^2oM%bl&ptO{q0$Nsm=Sv1z&?W`F##Y1Wkj}cezb=I1O|4`|ykQYxLbXH1v=3kt> zLpybjIeSPvZoOZU2 zxZl_QfWAHFY!&a{#xuC+yt6zUeZkoeuo{)AI~WmR7J1QG9C6eY-*{|HoEG9CjfY`) z5(}{jW?uDQoE5k>umT^Y{upYBzQ!25j8S+Sm9dAYfi$@0+Z^?NhagVC3B;jZJiJ5( z%J2d+{YRCv*m`Dv{?=JrW_;zQv!~Fz!Y6Sp<+T~&-ljL#CW!!0kvxC*$zD2 z+_UMFFKXf0T{RHr*>d8VmYxkHp4Hm3!T1S|qCBRJXJ2AgThE4JzxIB|?>+9-Zt{)z zGy^z*4eErJN_Us59uI=jCB|gkZ@hpp6_w3=>8+5R#zh}Q;lSQ&&+7Xuz z^lCG49KRsGgqq>*LBw=$2$k|RuXwdfRE*7uKMedBqv_wi;z6h2Iwlgg9pZnOj*k%! z#}+sV)j$rujHQ^xch&eJamK5j{fAVq$Nt1?NBW*cEm=#>r1nH&U@C^*V#Wh_&~Dr@ z%CpgU7~5dnk38#&si^vifwQqU9j(M{2JqP!uXeYmjU{uuHx%QkPyU%d^O1C-V>=Ob zjMb@5$I7?7Q0=kUKtU@C_F+7p!p?X>MBR8#+jVJ~)lN@fIori4#0a#g|cQnS)AU9>!ux;4ah*j|E;v z9m{{CW*Rlovu+rNPh)xzFADL{hk`w*2EGqosQmcWBiDy*MlHp5)ziNn;XyM!jasuB zOhoTpf23Ve4P*py2z4B{pi)|i+Cx`R-?g3L88@({qjq@)a*x?KREFO{ZOSqXX-zA5 z7>*}V4R@O9XQVf3KqK&39FJPdt@sR{Ld~$zFa4B1f$HFO)WC94o9y?fJ$3=LbTQd} zJTRN{-;RR06exuoQ8PG-8sTkJW+GMm2l}HIRs9zCBU9I1{yG>oFZaMs?J1xxZIhpnfGgp)xZFb!;bMNEP#W zsNGb76{s8U5b6pIqxM3F75+?9Q7IgTO8FGj&uskD@a19cmMGS?N0jhY?RjT{xejmZApRVf|J9h4Uop`=6pF zv=Mvb`BfYTJv3YGr*v>&2$g{fRO-(LM&|qPr=U8VgmrNpY9bp@1FS%0S|uJG`@0ayesS<-Mve4N|)r+cFD=l^hmDkJi(1|byAX2Dwj=k zS+TBN<(&oYL`1*v!rkGVEm!B~jeGOz{FT=Zm0n+XAbfCb)!KbE2lK+Y1=S@VgqP;t zc>lfY?=P;}v8yV-G+eRb`ud$W@)lR^%L%XBxo(LYQPgpTYf?0RiECIVyyj3*_7YbT z8!j&nuU@CG$}7XGcU5mI<`Zfw6PCLDF0!boYFkNB^)mN)QOi8nr1I!;SN^t_TTnUU Ij=Q_z|H+_}^Z)<= delta 3780 zcmXZfdvwqD9mnza=Nq?#Xx&4Rl%?XHWU9gD+O!NYowLq*35udx>eiUc&ovSvk-DTI z)6G;9MKeY?Zaq8Q=~->=EsdGFBz{$@R?V?v*z@)Ke*f|KzCWMu_j7rFF2DF;Tg=UE zG38rZg!=`~R{K(lh8vgqZ zXLqTXzSCI&PAGTAcFl;V?(B-{PlTKe;)Q`HomEqiecIW}4Cu`>&JN(`XPxb(qh((@D<$q- z=@01Y1!wuZe+$py{C_#i!%-KVHNeZLOnry7YMDL6R>V^`D}a=nOW-N{qo>e4ohZ@+O7|*)U&wWgbvXCV;^lUE`V;gzKH`b!DX9pNiv!36)kofp~UMc9)8?7`@$ zklBqy&x*;--6YSB(qVpg&o1#{Myh91$#u6Lo{gh}O#?mqkWKaw6NtAB_9B`149^gs zN6m1@5Mnymhf4X%;a+5k3b8ry*1&@pOaFG72c3eiu?unB2>-)$Y(YE>TjF?B0}F8| zuE(i-cNx=(Ge&y$UsAme2NLK1+V>P{$(nK|wI>n-Q!zAw8TaEsyYYk3p1p(>*cO}o z*0b)IimD$MI1AJ0C>!T8fTOQ^k=@>F44LD-A(%*g$Fcs*N6?9m?Kspi&O)7z>%f=8LC0G7yG*ZekbfmoQZ8P z7d4O%Uk~{W?WI5;oWL}^iON9YB+q)`v#7OPh)UsdjKg;WKSIs$)4)p9vHTu2)2PXw zrC<~6iRnQ+Kg7e&DAwNIw)iyR091$X z1QrGL6{s0k;?J@E+n#O4Ay|%K)E+D5hoKYqj~(SfzkWAR9oL!Zchm&caZl`kqfmQb zK90hrsDYnHWuU<4NF82h?7uA6n?IQ6p4C@u&+T6*aKQ$giyBVhk3d22g?;U>WLyIv3c832CN7gNtnj zjwjAT&HN7PqHD6q?>CejJoH5^!7x+P>_pFvCDEV@|Vs4OeNlnx=_NX23uzP zr{H(V#AwP3QA@cAd(gja<6#J1K+QBU$M0Yq>ev;c z8a{~{$b-Ocx&AKBL@n7m9EJx`9o1Xu@0G@=D>ojMnSrQdI}Sstn9D^8E{^9qRkvpe9s=Y4}Ax$3YJb z3;fhRADD&8Kp86arve|M-tWA|?{GZUAud2oWCLn|WvGlCLk;XUYLm7q^vj2#{y#81 z#DmW7D%7#~8>)dDsH?WYyZ&1CLEUWWs7*L3a0#lTa#Vw7Q3Jn?I?gTD`hUpuM`bh< z9qLxp)x0z(u_7nYtsNMf+BNx^uBmAW$tk^)(<+iCxmR6OO1G4X+{tcgTt&@dcd}NW z>+4FZHypaUDDSoLR~N0W&RcQq;MS^wrPb^ASFb6lDqmHVlN~O8pMSsExbFJKW!E?D z`X+B#RZda(kEKO*SGZALPIl2ND_lYppB61z;fmwJrQ5647w~TN&Wfsn-Qm*r_=4Js jlpJ@!)h;a#Z_g{bo$LO=rxk}+x+7Ecu;52m^ZWk;^-Yf~ diff --git a/po/zh_TW.po b/po/zh_TW.po index 91724f83..cae84392 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -11,7 +11,7 @@ msgstr "" "Project-Id-Version: bash 5.2-rc1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-01-11 14:50-0500\n" -"PO-Revision-Date: 2022-07-28 01:08+0800\n" +"PO-Revision-Date: 2023-02-09 00:40+0800\n" "Last-Translator: Yi-Jyun Pan \n" "Language-Team: Chinese (traditional) \n" "Language: zh_TW\n" @@ -20,7 +20,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Bugs: Report translation errors to the Language-Team address.\n" -"X-Generator: Poedit 3.1.1\n" +"X-Generator: Poedit 3.2.2\n" #: arrayfunc.c:66 msgid "bad array subscript" @@ -2762,7 +2762,7 @@ msgstr "" " 變更目前目錄至 <目錄>。預設的 <目錄> 是 shell 變數 HOME\n" " 的值。\n" " \n" -" 變數 CDPATH 定義了含有 <目錄> 的目錄搜尋路徑,其中不同的目錄名稱由冒號 (:)分隔。\n" +" 變數 CDPATH 定義了含有 <目錄> 的目錄搜尋路徑,其中不同的目錄名稱由冒號 (:) 分隔。\n" " 一個空的目錄名稱表示目前目錄。如果要切換到的 <目錄> 由斜線 (/) 開頭,則 CDPATH\n" " 變數不會被使用。\n" " \n" @@ -3188,7 +3188,7 @@ msgstr "" " Getopts 被 shell 過程用來將可定位的參數解析為選項。\n" " \n" " <選項字串> 字串包含待識別的選項字母。如果一個字母後面跟\n" -" 著分號,則該選項需要一個參數,這個參數應利用空格與選項分開。\n" +" 著冒號,則該選項需要一個參數,這個參數應利用空格與選項分開。\n" " \n" " 每次呼叫時,getopts 會將下一個選項放到 shell 變數 $name\n" " 中,如果 name 變數不存在則先將其初始化,而下一個待處\n" @@ -5007,22 +5007,22 @@ msgstr "" "常用 shell 變數名稱和使用。\n" " \n" " BASH_VERSION\t目前 Bash 的版本資訊。\n" -" CDPATH\t用於「cd」指令參數搜尋分號分隔的目錄列表\n" +" CDPATH\t傳入「cd」作為引數,冒號分隔的欲搜尋目錄清單\n" " GLOBIGNORE\t路徑擴充套件時忽略的檔名符合模式列表,\n" -" \t\t以分號分隔。\n" -" HISTFILE\t您的指令歷史記錄存放的檔案名稱。\n" +" \t\t以冒號分隔。\n" +" HISTFILE\t您的命令歷史記錄存放的檔案名稱。\n" " HISTFILESIZE\t歷史記錄檔案最多可以儲存的列數。\n" -" HISTSIZE\t一個執行的 shell 最多可以訪問的歷史記錄指令列數。\n" +" HISTSIZE\t一個執行的 shell 最多可以存取的歷史記錄命令列數。\n" " HOME\t您登入目錄的完整路徑。\n" " HOSTNAME\t目前主機的主機名稱。\n" " HOSTTYPE\t目前版本的 BASH 在其之上執行的 CPU 類型。\n" " IGNOREEOF\t控制 shell 收到檔案結束符做為單一輸入後的\n" " \t\t動作。如果設定這個變數,則它的值是 shell 結束之前在\n" " \t\t一個空列上可以連續看到的檔案結束符數量(預設為 10)。\n" -" \t\t未設定時,檔案結束符標誌著輸入的結束。\n" +" \t\t未設定時,檔案結束符旗標著輸入的結束。\n" " MACHTYPE\t描述目前執行 Bash 的系統字串。\n" " MAILCHECK\tBash 檢測新郵件的頻率,以秒為單位。\n" -" MAILPATH\tBash 從中檢測新郵件的檔案列表,以分號分隔。\n" +" MAILPATH\tBash 從中檢測新郵件的檔案列表,以冒號分隔。\n" " OSTYPE\t執行 Bash 的 Unix 版本。\n" " PATH\t當尋找指令時搜尋的目錄列表,以冒號分隔。\n" " PROMPT_COMMAND\t印出每一個主提示符之前執行的命\n"