aboutsummaryrefslogtreecommitdiff
path: root/libbb/lineedit.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-10-13 14:37:51 +0100
committerRon Yorston <rmy@pobox.com>2021-10-13 14:37:51 +0100
commit0ecf1aea459571b48dc68ddc2b7b9265740fa960 (patch)
tree491d6184a44b8b525a4ca35759d622aecd7f6344 /libbb/lineedit.c
parent4859ddcb20616718efbea12c6bf8b27c469b68de (diff)
parentaaf3d5ba74c5da97ff80b61f30cb8dd225d39096 (diff)
downloadbusybox-w32-0ecf1aea459571b48dc68ddc2b7b9265740fa960.tar.gz
busybox-w32-0ecf1aea459571b48dc68ddc2b7b9265740fa960.tar.bz2
busybox-w32-0ecf1aea459571b48dc68ddc2b7b9265740fa960.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r--libbb/lineedit.c94
1 files changed, 56 insertions, 38 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 7c46fa5db..8abc87976 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -135,10 +135,6 @@ enum {
135 : 0x7ff0 135 : 0x7ff0
136}; 136};
137 137
138#if ENABLE_USERNAME_OR_HOMEDIR
139static const char null_str[] ALIGN1 = "";
140#endif
141
142/* We try to minimize both static and stack usage. */ 138/* We try to minimize both static and stack usage. */
143struct lineedit_statics { 139struct lineedit_statics {
144 line_input_t *state; 140 line_input_t *state;
@@ -161,12 +157,13 @@ struct lineedit_statics {
161 157
162#if ENABLE_USERNAME_OR_HOMEDIR 158#if ENABLE_USERNAME_OR_HOMEDIR
163 char *user_buf; 159 char *user_buf;
164 char *home_pwd_buf; /* = (char*)null_str; */ 160 char *home_pwd_buf;
161 smallint got_user_strings;
165#endif 162#endif
166 163
167#if ENABLE_FEATURE_TAB_COMPLETION 164#if ENABLE_FEATURE_TAB_COMPLETION
168 char **matches;
169 unsigned num_matches; 165 unsigned num_matches;
166 char **matches;
170#endif 167#endif
171 168
172#if ENABLE_FEATURE_EDITING_WINCH 169#if ENABLE_FEATURE_EDITING_WINCH
@@ -192,7 +189,7 @@ struct lineedit_statics {
192}; 189};
193 190
194/* See lineedit_ptr_hack.c */ 191/* See lineedit_ptr_hack.c */
195extern struct lineedit_statics *const lineedit_ptr_to_statics; 192extern struct lineedit_statics *BB_GLOBAL_CONST lineedit_ptr_to_statics;
196 193
197#define S (*lineedit_ptr_to_statics) 194#define S (*lineedit_ptr_to_statics)
198#define state (S.state ) 195#define state (S.state )
@@ -207,15 +204,15 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics;
207#define prompt_last_line (S.prompt_last_line) 204#define prompt_last_line (S.prompt_last_line)
208#define user_buf (S.user_buf ) 205#define user_buf (S.user_buf )
209#define home_pwd_buf (S.home_pwd_buf ) 206#define home_pwd_buf (S.home_pwd_buf )
210#define matches (S.matches ) 207#define got_user_strings (S.got_user_strings)
211#define num_matches (S.num_matches ) 208#define num_matches (S.num_matches )
209#define matches (S.matches )
212#define delptr (S.delptr ) 210#define delptr (S.delptr )
213#define newdelflag (S.newdelflag ) 211#define newdelflag (S.newdelflag )
214#define delbuf (S.delbuf ) 212#define delbuf (S.delbuf )
215 213
216#define INIT_S() do { \ 214#define INIT_S() do { \
217 (*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \ 215 XZALLOC_CONST_PTR(&lineedit_ptr_to_statics, sizeof(S)); \
218 barrier(); \
219} while (0) 216} while (0)
220 217
221static void deinit_S(void) 218static void deinit_S(void)
@@ -227,14 +224,47 @@ static void deinit_S(void)
227#endif 224#endif
228#if ENABLE_USERNAME_OR_HOMEDIR 225#if ENABLE_USERNAME_OR_HOMEDIR
229 free(user_buf); 226 free(user_buf);
230 if (home_pwd_buf != null_str) 227 free(home_pwd_buf);
231 free(home_pwd_buf);
232#endif 228#endif
233 free(lineedit_ptr_to_statics); 229 free(lineedit_ptr_to_statics);
234} 230}
235#define DEINIT_S() deinit_S() 231#define DEINIT_S() deinit_S()
236 232
237 233
234#if ENABLE_USERNAME_OR_HOMEDIR
235/* Call getpwuid() only if necessary.
236 * E.g. if PS1=':', no user database reading is needed to generate prompt.
237 * (Unfortunately, default PS1='\w \$' needs it, \w abbreviates homedir
238 * as ~/... - for that it needs to *know* the homedir...)
239 */
240static void get_user_strings(void)
241{
242 struct passwd *entry;
243
244 got_user_strings = 1;
245 entry = getpwuid(geteuid());
246 if (entry) {
247 user_buf = xstrdup(entry->pw_name);
248 home_pwd_buf = xstrdup(entry->pw_dir);
249 }
250}
251
252static const char *get_username_str(void)
253{
254 if (!got_user_strings)
255 get_user_strings();
256 return user_buf ? user_buf : "";
257 /* btw, bash uses "I have no name!" string if uid has no entry */
258}
259
260static NOINLINE const char *get_homedir_or_NULL(void)
261{
262 if (!got_user_strings)
263 get_user_strings();
264 return home_pwd_buf;
265}
266#endif
267
238#if ENABLE_UNICODE_SUPPORT 268#if ENABLE_UNICODE_SUPPORT
239static size_t load_string(const char *src) 269static size_t load_string(const char *src)
240{ 270{
@@ -748,11 +778,11 @@ static char *username_path_completion(char *ud)
748 struct passwd *entry; 778 struct passwd *entry;
749#endif 779#endif
750 char *tilde_name = ud; 780 char *tilde_name = ud;
751 char *home = NULL; 781 const char *home = NULL;
752 782
753 ud++; /* skip ~ */ 783 ud++; /* skip ~ */
754 if (*ud == '/') { /* "~/..." */ 784 if (*ud == '/') { /* "~/..." */
755 home = home_pwd_buf; 785 home = get_homedir_or_NULL();
756# if !ENABLE_PLATFORM_MINGW32 786# if !ENABLE_PLATFORM_MINGW32
757 } else { 787 } else {
758 /* "~user/..." */ 788 /* "~user/..." */
@@ -1881,7 +1911,7 @@ vi_back_motion(void)
1881 input_backward(1); 1911 input_backward(1);
1882 } 1912 }
1883} 1913}
1884#endif 1914#endif /* ENABLE_FEATURE_EDITING_VI */
1885 1915
1886/* Modelled after bash 4.0 behavior of Ctrl-<arrow> */ 1916/* Modelled after bash 4.0 behavior of Ctrl-<arrow> */
1887static void ctrl_left(void) 1917static void ctrl_left(void)
@@ -1982,7 +2012,7 @@ static void ask_terminal(void)
1982 } 2012 }
1983} 2013}
1984#else 2014#else
1985#define ask_terminal() ((void)0) 2015# define ask_terminal() ((void)0)
1986#endif 2016#endif
1987 2017
1988/* Note about multi-line PS1 (e.g. "\n\w \u@\h\n> ") and prompt redrawing: 2018/* Note about multi-line PS1 (e.g. "\n\w \u@\h\n> ") and prompt redrawing:
@@ -2091,7 +2121,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2091 2121
2092 switch (c) { 2122 switch (c) {
2093 case 'u': 2123 case 'u':
2094 pbuf = user_buf ? user_buf : (char*)""; 2124 pbuf = (char*)get_username_str();
2095 break; 2125 break;
2096 case 'H': 2126 case 'H':
2097 case 'h': 2127 case 'h':
@@ -2113,14 +2143,15 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2113 case 'w': /* current dir */ 2143 case 'w': /* current dir */
2114 case 'W': /* basename of cur dir */ 2144 case 'W': /* basename of cur dir */
2115 if (!cwd_buf) { 2145 if (!cwd_buf) {
2146 const char *home;
2116 cwd_buf = xrealloc_getcwd_or_warn(NULL); 2147 cwd_buf = xrealloc_getcwd_or_warn(NULL);
2117 if (!cwd_buf) 2148 if (!cwd_buf)
2118 cwd_buf = (char *)bb_msg_unknown; 2149 cwd_buf = (char *)bb_msg_unknown;
2119 else if (home_pwd_buf[0]) { 2150 else if ((home = get_homedir_or_NULL()) != NULL && home[0]) {
2120 char *after_home_user; 2151 char *after_home_user;
2121 2152
2122 /* /home/user[/something] -> ~[/something] */ 2153 /* /home/user[/something] -> ~[/something] */
2123 after_home_user = is_prefixed_with(cwd_buf, home_pwd_buf); 2154 after_home_user = is_prefixed_with(cwd_buf, home);
2124 if (after_home_user 2155 if (after_home_user
2125 && (*after_home_user == '/' || *after_home_user == '\0') 2156 && (*after_home_user == '/' || *after_home_user == '\0')
2126 ) { 2157 ) {
@@ -2176,7 +2207,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2176 if (c == '\n') 2207 if (c == '\n')
2177 cmdedit_prmt_len = 0; 2208 cmdedit_prmt_len = 0;
2178 else if (flg_not_length != ']') { 2209 else if (flg_not_length != ']') {
2179#if ENABLE_UNICODE_SUPPORT 2210# if ENABLE_UNICODE_SUPPORT
2180 if (n == 1) { 2211 if (n == 1) {
2181 /* Only count single-byte characters and the first of multi-byte characters */ 2212 /* Only count single-byte characters and the first of multi-byte characters */
2182 if ((unsigned char)*pbuf < 0x80 /* single byte character */ 2213 if ((unsigned char)*pbuf < 0x80 /* single byte character */
@@ -2187,9 +2218,9 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2187 } else { 2218 } else {
2188 cmdedit_prmt_len += unicode_strwidth(pbuf); 2219 cmdedit_prmt_len += unicode_strwidth(pbuf);
2189 } 2220 }
2190#else 2221# else
2191 cmdedit_prmt_len += n; 2222 cmdedit_prmt_len += n;
2192#endif 2223# endif
2193 } 2224 }
2194 } 2225 }
2195 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_size+1), pbuf); 2226 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_size+1), pbuf);
@@ -2416,7 +2447,7 @@ static int32_t reverse_i_search(int timeout)
2416 } 2447 }
2417 2448
2418 /* Append this char */ 2449 /* Append this char */
2419#if ENABLE_UNICODE_SUPPORT 2450# if ENABLE_UNICODE_SUPPORT
2420 if (unicode_status == UNICODE_ON) { 2451 if (unicode_status == UNICODE_ON) {
2421 mbstate_t mbstate = { 0 }; 2452 mbstate_t mbstate = { 0 };
2422 char buf[MB_CUR_MAX + 1]; 2453 char buf[MB_CUR_MAX + 1];
@@ -2427,7 +2458,7 @@ static int32_t reverse_i_search(int timeout)
2427 strcpy(match_buf + match_buf_len, buf); 2458 strcpy(match_buf + match_buf_len, buf);
2428 } 2459 }
2429 } else 2460 } else
2430#endif 2461# endif
2431 if (match_buf_len < sizeof(match_buf) - 1) { 2462 if (match_buf_len < sizeof(match_buf) - 1) {
2432 match_buf[match_buf_len] = ic; 2463 match_buf[match_buf_len] = ic;
2433 match_buf[match_buf_len + 1] = '\0'; 2464 match_buf[match_buf_len + 1] = '\0';
@@ -2479,7 +2510,7 @@ static int32_t reverse_i_search(int timeout)
2479 2510
2480 return ic; 2511 return ic;
2481} 2512}
2482#endif 2513#endif /* ENABLE_FEATURE_REVERSE_SEARCH */
2483 2514
2484#if ENABLE_FEATURE_EDITING_WINCH 2515#if ENABLE_FEATURE_EDITING_WINCH
2485static void sigaction2(int sig, struct sigaction *act) 2516static void sigaction2(int sig, struct sigaction *act)
@@ -2521,7 +2552,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2521 //command_len = 0; - done by INIT_S() 2552 //command_len = 0; - done by INIT_S()
2522 //cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ 2553 //cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
2523 cmdedit_termw = 80; 2554 cmdedit_termw = 80;
2524 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;)
2525 IF_FEATURE_EDITING_VI(delptr = delbuf;) 2555 IF_FEATURE_EDITING_VI(delptr = delbuf;)
2526 2556
2527#if !ENABLE_PLATFORM_MINGW32 2557#if !ENABLE_PLATFORM_MINGW32
@@ -2589,18 +2619,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2589 tcsetattr_stdin_TCSANOW(&new_settings); 2619 tcsetattr_stdin_TCSANOW(&new_settings);
2590#endif 2620#endif
2591 2621
2592#if ENABLE_USERNAME_OR_HOMEDIR
2593 {
2594 struct passwd *entry;
2595
2596 entry = getpwuid(geteuid());
2597 if (entry) {
2598 user_buf = xstrdup(entry->pw_name);
2599 home_pwd_buf = xstrdup(entry->pw_dir);
2600 }
2601 }
2602#endif
2603
2604#if 0 2622#if 0
2605 for (i = 0; i <= state->max_history; i++) 2623 for (i = 0; i <= state->max_history; i++)
2606 bb_error_msg("history[%d]:'%s'", i, state->history[i]); 2624 bb_error_msg("history[%d]:'%s'", i, state->history[i]);