diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-21 19:18:19 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-01-21 19:18:19 +0000 |
commit | 82b39e83ab13660f0b76a52519e1ac44e30fff7c (patch) | |
tree | 196849676460770eb35aaf240cbe68cb5238de45 | |
parent | 7b1f23610f4e9ba08b1f12e25fb1301b321bf584 (diff) | |
download | busybox-w32-82b39e83ab13660f0b76a52519e1ac44e30fff7c.tar.gz busybox-w32-82b39e83ab13660f0b76a52519e1ac44e30fff7c.tar.bz2 busybox-w32-82b39e83ab13660f0b76a52519e1ac44e30fff7c.zip |
sanitize cmdedit a bit (group functions by task etc)
-rw-r--r-- | shell/cmdedit.c | 759 | ||||
-rw-r--r-- | shell/cmdedit.h | 4 |
2 files changed, 368 insertions, 395 deletions
diff --git a/shell/cmdedit.c b/shell/cmdedit.c index 32001324f..617f3a29a 100644 --- a/shell/cmdedit.c +++ b/shell/cmdedit.c | |||
@@ -28,19 +28,11 @@ | |||
28 | - not true viewing if length prompt less terminal width | 28 | - not true viewing if length prompt less terminal width |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include "busybox.h" | ||
32 | #include <sys/ioctl.h> | 31 | #include <sys/ioctl.h> |
33 | 32 | #include "busybox.h" | |
34 | #include "cmdedit.h" | 33 | #include "cmdedit.h" |
35 | 34 | ||
36 | 35 | ||
37 | #if ENABLE_LOCALE_SUPPORT | ||
38 | #define Isprint(c) isprint(c) | ||
39 | #else | ||
40 | #define Isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233')) | ||
41 | #endif | ||
42 | |||
43 | |||
44 | /* FIXME: obsolete CONFIG item? */ | 36 | /* FIXME: obsolete CONFIG item? */ |
45 | #define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0 | 37 | #define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0 |
46 | 38 | ||
@@ -56,38 +48,34 @@ | |||
56 | #endif /* TEST */ | 48 | #endif /* TEST */ |
57 | 49 | ||
58 | 50 | ||
51 | /* Entire file (except TESTing part) sits inside this #if */ | ||
59 | #if ENABLE_FEATURE_COMMAND_EDITING | 52 | #if ENABLE_FEATURE_COMMAND_EDITING |
60 | 53 | ||
54 | |||
55 | #if ENABLE_LOCALE_SUPPORT | ||
56 | #define Isprint(c) isprint(c) | ||
57 | #else | ||
58 | #define Isprint(c) ((c) >= ' ' && (c) != ((unsigned char)'\233')) | ||
59 | #endif | ||
60 | |||
61 | #define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \ | 61 | #define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \ |
62 | (ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT) | 62 | (ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT) |
63 | 63 | ||
64 | /* Maximum length of the linked list for the command line history */ | 64 | /* Maximum length of command line history */ |
65 | #if !ENABLE_FEATURE_COMMAND_HISTORY | 65 | #if !ENABLE_FEATURE_COMMAND_HISTORY |
66 | #define MAX_HISTORY 15 | 66 | #define MAX_HISTORY 15 |
67 | #else | 67 | #else |
68 | #define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0) | 68 | #define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0) |
69 | #endif | 69 | #endif |
70 | 70 | ||
71 | #if MAX_HISTORY > 0 | ||
72 | static char *history[MAX_HISTORY+1]; /* history + current */ | ||
73 | /* saved history lines */ | ||
74 | static int n_history; | ||
75 | /* current pointer to history line */ | ||
76 | static int cur_history; | ||
77 | #endif | ||
78 | 71 | ||
79 | #define setTermSettings(fd,argp) tcsetattr(fd, TCSANOW, argp) | 72 | /* Current termios and the previous termios before starting sh */ |
80 | #define getTermSettings(fd,argp) tcgetattr(fd, argp); | ||
81 | |||
82 | /* Current termio and the previous termio before starting sh */ | ||
83 | static struct termios initial_settings, new_settings; | 73 | static struct termios initial_settings, new_settings; |
84 | 74 | ||
85 | |||
86 | static | 75 | static |
87 | volatile int cmdedit_termw = 80; /* actual terminal width */ | 76 | volatile unsigned cmdedit_termw = 80; /* actual terminal width */ |
88 | static | 77 | static |
89 | volatile int handlers_sets = 0; /* Set next bites: */ | 78 | volatile int handlers_sets = 0; /* Set next bits: */ |
90 | |||
91 | enum { | 79 | enum { |
92 | SET_ATEXIT = 1, /* when atexit() has been called | 80 | SET_ATEXIT = 1, /* when atexit() has been called |
93 | and get euid,uid,gid to fast compare */ | 81 | and get euid,uid,gid to fast compare */ |
@@ -98,84 +86,46 @@ enum { | |||
98 | 86 | ||
99 | static int cmdedit_x; /* real x terminal position */ | 87 | static int cmdedit_x; /* real x terminal position */ |
100 | static int cmdedit_y; /* pseudoreal y terminal position */ | 88 | static int cmdedit_y; /* pseudoreal y terminal position */ |
101 | static int cmdedit_prmt_len; /* lenght prompt without colores string */ | 89 | static int cmdedit_prmt_len; /* length of prompt without colores string */ |
102 | |||
103 | static int cursor; /* required globals for signal handler */ | ||
104 | static int len; /* --- "" - - "" -- -"- --""-- --""--- */ | ||
105 | static char *command_ps; /* --- "" - - "" -- -"- --""-- --""--- */ | ||
106 | static SKIP_FEATURE_SH_FANCY_PROMPT(const) char *cmdedit_prompt; /* -- */ | ||
107 | 90 | ||
108 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | 91 | static int cursor; |
109 | static char *user_buf = ""; | 92 | static int len; |
110 | static char *home_pwd_buf = ""; | 93 | static char *command_ps; |
111 | static int my_euid; | 94 | static SKIP_FEATURE_SH_FANCY_PROMPT(const) char *cmdedit_prompt; |
112 | #endif | ||
113 | 95 | ||
114 | #if ENABLE_FEATURE_SH_FANCY_PROMPT | 96 | #if ENABLE_FEATURE_SH_FANCY_PROMPT |
115 | static char *hostname_buf; | 97 | static char *hostname_buf; |
116 | static int num_ok_lines = 1; | 98 | static int num_ok_lines = 1; |
117 | #endif | 99 | #endif |
118 | 100 | ||
101 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
102 | static char *user_buf = ""; | ||
103 | static char *home_pwd_buf = ""; | ||
104 | #endif | ||
119 | 105 | ||
120 | #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION | 106 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR || ENABLE_FEATURE_COMMAND_TAB_COMPLETION |
121 | |||
122 | #if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
123 | static int my_euid; | 107 | static int my_euid; |
124 | #endif | 108 | #endif |
125 | 109 | ||
110 | #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION | ||
126 | static int my_uid; | 111 | static int my_uid; |
127 | static int my_gid; | 112 | static int my_gid; |
113 | #endif | ||
128 | 114 | ||
129 | #endif /* FEATURE_COMMAND_TAB_COMPLETION */ | 115 | /* Put 'command_ps[cursor]', cursor++. |
130 | 116 | * Advance cursor on screen. If we reached right margin, scroll text up | |
131 | static void cmdedit_setwidth(int w, int redraw_flg); | 117 | * and remove terminal margin effect by printing 'next_char' */ |
132 | |||
133 | static void win_changed(int nsig) | ||
134 | { | ||
135 | static sighandler_t previous_SIGWINCH_handler; /* for reset */ | ||
136 | |||
137 | /* emulate || signal call */ | ||
138 | if (nsig == -SIGWINCH || nsig == SIGWINCH) { | ||
139 | int width = 0; | ||
140 | get_terminal_width_height(0, &width, NULL); | ||
141 | cmdedit_setwidth(width, nsig == SIGWINCH); | ||
142 | } | ||
143 | /* Unix not all standard in recall signal */ | ||
144 | |||
145 | if (nsig == -SIGWINCH) /* save previous handler */ | ||
146 | previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); | ||
147 | else if (nsig == SIGWINCH) /* signaled called handler */ | ||
148 | signal(SIGWINCH, win_changed); /* set for next call */ | ||
149 | else /* nsig == 0 */ | ||
150 | /* set previous handler */ | ||
151 | signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */ | ||
152 | } | ||
153 | |||
154 | static void cmdedit_reset_term(void) | ||
155 | { | ||
156 | if (handlers_sets & SET_RESET_TERM) { | ||
157 | /* sparc and other have broken termios support: use old termio handling. */ | ||
158 | setTermSettings(STDIN_FILENO, (void *) &initial_settings); | ||
159 | handlers_sets &= ~SET_RESET_TERM; | ||
160 | } | ||
161 | if (handlers_sets & SET_WCHG_HANDLERS) { | ||
162 | /* reset SIGWINCH handler to previous (default) */ | ||
163 | win_changed(0); | ||
164 | handlers_sets &= ~SET_WCHG_HANDLERS; | ||
165 | } | ||
166 | fflush(stdout); | ||
167 | } | ||
168 | |||
169 | |||
170 | /* special for recount position for scroll and remove terminal margin effect */ | ||
171 | static void cmdedit_set_out_char(int next_char) | 118 | static void cmdedit_set_out_char(int next_char) |
172 | { | 119 | { |
173 | int c = (unsigned char)command_ps[cursor]; | 120 | int c = (unsigned char)command_ps[cursor]; |
174 | 121 | ||
175 | if (c == 0) | 122 | if (c == '\0') { |
176 | c = ' '; /* destroy end char? */ | 123 | /* erase character after end of input string */ |
124 | c = ' '; | ||
125 | } | ||
177 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT | 126 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT |
178 | if (!Isprint(c)) { /* Inverse put non-printable characters */ | 127 | /* Display non-printable characters in reverse */ |
128 | if (!Isprint(c)) { | ||
179 | if (c >= 128) | 129 | if (c >= 128) |
180 | c -= 128; | 130 | c -= 128; |
181 | if (c < ' ') | 131 | if (c < ' ') |
@@ -193,21 +143,19 @@ static void cmdedit_set_out_char(int next_char) | |||
193 | /* terminal is scrolled down */ | 143 | /* terminal is scrolled down */ |
194 | cmdedit_y++; | 144 | cmdedit_y++; |
195 | cmdedit_x = 0; | 145 | cmdedit_x = 0; |
196 | |||
197 | if (!next_char) | ||
198 | next_char = ' '; | ||
199 | /* destroy "(auto)margin" */ | 146 | /* destroy "(auto)margin" */ |
200 | putchar(next_char); | 147 | putchar(next_char); |
201 | putchar('\b'); | 148 | putchar('\b'); |
202 | } | 149 | } |
150 | // Huh? What if command_ps[cursor] == '\0' (we are at the end already?) | ||
203 | cursor++; | 151 | cursor++; |
204 | } | 152 | } |
205 | 153 | ||
206 | /* Move to end line. Bonus: rewrite line from cursor */ | 154 | /* Move to end of line (by printing all chars till the end) */ |
207 | static void input_end(void) | 155 | static void input_end(void) |
208 | { | 156 | { |
209 | while (cursor < len) | 157 | while (cursor < len) |
210 | cmdedit_set_out_char(0); | 158 | cmdedit_set_out_char(' '); |
211 | } | 159 | } |
212 | 160 | ||
213 | /* Go to the next line */ | 161 | /* Go to the next line */ |
@@ -238,26 +186,32 @@ static void input_backward(int num) | |||
238 | num = cursor; | 186 | num = cursor; |
239 | cursor -= num; /* new cursor (in command, not terminal) */ | 187 | cursor -= num; /* new cursor (in command, not terminal) */ |
240 | 188 | ||
241 | if (cmdedit_x >= num) { /* no to up line */ | 189 | if (cmdedit_x >= num) { |
242 | cmdedit_x -= num; | 190 | cmdedit_x -= num; |
243 | if (num < 4) | 191 | if (num <= 4) |
244 | while (num-- > 0) | 192 | while (num > 0) { |
245 | putchar('\b'); | 193 | putchar('\b'); |
194 | num--; | ||
195 | } | ||
246 | else | 196 | else |
247 | printf("\033[%dD", num); | 197 | printf("\033[%dD", num); |
248 | } else { | 198 | } else { |
199 | /* Need to go one or more lines up */ | ||
249 | int count_y; | 200 | int count_y; |
250 | 201 | ||
251 | if (cmdedit_x) { | 202 | //if (cmdedit_x) { |
252 | putchar('\r'); /* back to first terminal pos. */ | 203 | // /* back to first column */ |
253 | num -= cmdedit_x; /* set previous backward */ | 204 | // putchar('\r'); |
254 | } | 205 | // num -= cmdedit_x; |
206 | //} | ||
207 | num -= cmdedit_x;// | ||
255 | count_y = 1 + num / cmdedit_termw; | 208 | count_y = 1 + num / cmdedit_termw; |
256 | printf("\033[%dA", count_y); | 209 | //printf("\033[%dA", count_y); |
257 | cmdedit_y -= count_y; | 210 | cmdedit_y -= count_y; |
258 | /* require forward after uping */ | ||
259 | cmdedit_x = cmdedit_termw * count_y - num; | 211 | cmdedit_x = cmdedit_termw * count_y - num; |
260 | printf("\033[%dC", cmdedit_x); /* set term cursor */ | 212 | //printf("\033[%dC", cmdedit_x); |
213 | /* go to 1st col; go up; go to correct column */ | ||
214 | printf("\r" "\033[%dA" "\033[%dC", count_y, cmdedit_x);// | ||
261 | } | 215 | } |
262 | } | 216 | } |
263 | 217 | ||
@@ -269,136 +223,6 @@ static void put_prompt(void) | |||
269 | cmdedit_y = 0; /* new quasireal y */ | 223 | cmdedit_y = 0; /* new quasireal y */ |
270 | } | 224 | } |
271 | 225 | ||
272 | #if !ENABLE_FEATURE_SH_FANCY_PROMPT | ||
273 | static void parse_prompt(const char *prmt_ptr) | ||
274 | { | ||
275 | cmdedit_prompt = prmt_ptr; | ||
276 | cmdedit_prmt_len = strlen(prmt_ptr); | ||
277 | put_prompt(); | ||
278 | } | ||
279 | #else | ||
280 | static void parse_prompt(const char *prmt_ptr) | ||
281 | { | ||
282 | int prmt_len = 0; | ||
283 | size_t cur_prmt_len = 0; | ||
284 | char flg_not_length = '['; | ||
285 | char *prmt_mem_ptr = xzalloc(1); | ||
286 | char *pwd_buf = xgetcwd(0); | ||
287 | char buf2[PATH_MAX + 1]; | ||
288 | char buf[2]; | ||
289 | char c; | ||
290 | char *pbuf; | ||
291 | |||
292 | if (!pwd_buf) { | ||
293 | pwd_buf = (char *)bb_msg_unknown; | ||
294 | } | ||
295 | |||
296 | while (*prmt_ptr) { | ||
297 | pbuf = buf; | ||
298 | pbuf[1] = 0; | ||
299 | c = *prmt_ptr++; | ||
300 | if (c == '\\') { | ||
301 | const char *cp = prmt_ptr; | ||
302 | int l; | ||
303 | |||
304 | c = bb_process_escape_sequence(&prmt_ptr); | ||
305 | if (prmt_ptr == cp) { | ||
306 | if (*cp == 0) | ||
307 | break; | ||
308 | c = *prmt_ptr++; | ||
309 | switch (c) { | ||
310 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
311 | case 'u': | ||
312 | pbuf = user_buf; | ||
313 | break; | ||
314 | #endif | ||
315 | case 'h': | ||
316 | pbuf = hostname_buf; | ||
317 | if (pbuf == 0) { | ||
318 | pbuf = xzalloc(256); | ||
319 | if (gethostname(pbuf, 255) < 0) { | ||
320 | strcpy(pbuf, "?"); | ||
321 | } else { | ||
322 | char *s = strchr(pbuf, '.'); | ||
323 | if (s) | ||
324 | *s = 0; | ||
325 | } | ||
326 | hostname_buf = pbuf; | ||
327 | } | ||
328 | break; | ||
329 | case '$': | ||
330 | c = (my_euid == 0 ? '#' : '$'); | ||
331 | break; | ||
332 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
333 | case 'w': | ||
334 | pbuf = pwd_buf; | ||
335 | l = strlen(home_pwd_buf); | ||
336 | if (home_pwd_buf[0] != 0 | ||
337 | && strncmp(home_pwd_buf, pbuf, l) == 0 | ||
338 | && (pbuf[l]=='/' || pbuf[l]=='\0') | ||
339 | && strlen(pwd_buf+l)<PATH_MAX | ||
340 | ) { | ||
341 | pbuf = buf2; | ||
342 | *pbuf = '~'; | ||
343 | strcpy(pbuf+1, pwd_buf+l); | ||
344 | } | ||
345 | break; | ||
346 | #endif | ||
347 | case 'W': | ||
348 | pbuf = pwd_buf; | ||
349 | cp = strrchr(pbuf,'/'); | ||
350 | if (cp != NULL && cp != pbuf) | ||
351 | pbuf += (cp-pbuf) + 1; | ||
352 | break; | ||
353 | case '!': | ||
354 | snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines); | ||
355 | break; | ||
356 | case 'e': case 'E': /* \e \E = \033 */ | ||
357 | c = '\033'; | ||
358 | break; | ||
359 | case 'x': case 'X': | ||
360 | for (l = 0; l < 3;) { | ||
361 | int h; | ||
362 | buf2[l++] = *prmt_ptr; | ||
363 | buf2[l] = 0; | ||
364 | h = strtol(buf2, &pbuf, 16); | ||
365 | if (h > UCHAR_MAX || (pbuf - buf2) < l) { | ||
366 | l--; | ||
367 | break; | ||
368 | } | ||
369 | prmt_ptr++; | ||
370 | } | ||
371 | buf2[l] = 0; | ||
372 | c = (char)strtol(buf2, 0, 16); | ||
373 | if (c == 0) | ||
374 | c = '?'; | ||
375 | pbuf = buf; | ||
376 | break; | ||
377 | case '[': case ']': | ||
378 | if (c == flg_not_length) { | ||
379 | flg_not_length = flg_not_length == '[' ? ']' : '['; | ||
380 | continue; | ||
381 | } | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | if (pbuf == buf) | ||
387 | *pbuf = c; | ||
388 | cur_prmt_len = strlen(pbuf); | ||
389 | prmt_len += cur_prmt_len; | ||
390 | if (flg_not_length != ']') | ||
391 | cmdedit_prmt_len += cur_prmt_len; | ||
392 | prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); | ||
393 | } | ||
394 | if (pwd_buf!=(char *)bb_msg_unknown) | ||
395 | free(pwd_buf); | ||
396 | cmdedit_prompt = prmt_mem_ptr; | ||
397 | put_prompt(); | ||
398 | } | ||
399 | #endif | ||
400 | |||
401 | |||
402 | /* draw prompt, editor line, and clear tail */ | 226 | /* draw prompt, editor line, and clear tail */ |
403 | static void redraw(int y, int back_cursor) | 227 | static void redraw(int y, int back_cursor) |
404 | { | 228 | { |
@@ -407,7 +231,7 @@ static void redraw(int y, int back_cursor) | |||
407 | putchar('\r'); | 231 | putchar('\r'); |
408 | put_prompt(); | 232 | put_prompt(); |
409 | input_end(); /* rewrite */ | 233 | input_end(); /* rewrite */ |
410 | printf("\033[J"); /* destroy tail after cursor */ | 234 | printf("\033[J"); /* erase after cursor */ |
411 | input_backward(back_cursor); | 235 | input_backward(back_cursor); |
412 | } | 236 | } |
413 | 237 | ||
@@ -444,14 +268,16 @@ static void input_delete(int save) | |||
444 | strcpy(command_ps + j, command_ps + j + 1); | 268 | strcpy(command_ps + j, command_ps + j + 1); |
445 | len--; | 269 | len--; |
446 | input_end(); /* rewrite new line */ | 270 | input_end(); /* rewrite new line */ |
447 | cmdedit_set_out_char(0); /* destroy end char */ | 271 | cmdedit_set_out_char(' '); /* erase char */ |
448 | input_backward(cursor - j); /* back to old pos cursor */ | 272 | input_backward(cursor - j); /* back to old pos cursor */ |
449 | } | 273 | } |
450 | 274 | ||
451 | #if ENABLE_FEATURE_COMMAND_EDITING_VI | 275 | #if ENABLE_FEATURE_COMMAND_EDITING_VI |
452 | static void put(void) | 276 | static void put(void) |
453 | { | 277 | { |
454 | int ocursor, j = delp - delbuf; | 278 | int ocursor; |
279 | int j = delp - delbuf; | ||
280 | |||
455 | if (j == 0) | 281 | if (j == 0) |
456 | return; | 282 | return; |
457 | ocursor = cursor; | 283 | ocursor = cursor; |
@@ -481,60 +307,6 @@ static void input_forward(void) | |||
481 | cmdedit_set_out_char(command_ps[cursor + 1]); | 307 | cmdedit_set_out_char(command_ps[cursor + 1]); |
482 | } | 308 | } |
483 | 309 | ||
484 | static void cmdedit_setwidth(int w, int redraw_flg) | ||
485 | { | ||
486 | cmdedit_termw = cmdedit_prmt_len + 2; | ||
487 | if (w <= cmdedit_termw) { | ||
488 | cmdedit_termw = cmdedit_termw % w; | ||
489 | } | ||
490 | if (w > cmdedit_termw) { | ||
491 | cmdedit_termw = w; | ||
492 | |||
493 | if (redraw_flg) { | ||
494 | /* new y for current cursor */ | ||
495 | int new_y = (cursor + cmdedit_prmt_len) / w; | ||
496 | |||
497 | /* redraw */ | ||
498 | redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); | ||
499 | fflush(stdout); | ||
500 | } | ||
501 | } | ||
502 | } | ||
503 | |||
504 | static void cmdedit_init(void) | ||
505 | { | ||
506 | cmdedit_prmt_len = 0; | ||
507 | if (!(handlers_sets & SET_WCHG_HANDLERS)) { | ||
508 | /* emulate usage handler to set handler and call yours work */ | ||
509 | win_changed(-SIGWINCH); | ||
510 | handlers_sets |= SET_WCHG_HANDLERS; | ||
511 | } | ||
512 | |||
513 | if (!(handlers_sets & SET_ATEXIT)) { | ||
514 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
515 | struct passwd *entry; | ||
516 | |||
517 | my_euid = geteuid(); | ||
518 | entry = getpwuid(my_euid); | ||
519 | if (entry) { | ||
520 | user_buf = xstrdup(entry->pw_name); | ||
521 | home_pwd_buf = xstrdup(entry->pw_dir); | ||
522 | } | ||
523 | #endif | ||
524 | |||
525 | #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION | ||
526 | |||
527 | #if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
528 | my_euid = geteuid(); | ||
529 | #endif | ||
530 | my_uid = getuid(); | ||
531 | my_gid = getgid(); | ||
532 | #endif /* FEATURE_COMMAND_TAB_COMPLETION */ | ||
533 | handlers_sets |= SET_ATEXIT; | ||
534 | atexit(cmdedit_reset_term); /* be sure to do this only once */ | ||
535 | } | ||
536 | } | ||
537 | |||
538 | #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION | 310 | #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION |
539 | 311 | ||
540 | static char **matches; | 312 | static char **matches; |
@@ -550,20 +322,6 @@ static void add_match(char *matched) | |||
550 | num_matches++; | 322 | num_matches++; |
551 | } | 323 | } |
552 | 324 | ||
553 | /* | ||
554 | static int is_execute(const struct stat *st) | ||
555 | { | ||
556 | if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) | ||
557 | || (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) | ||
558 | || (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) | ||
559 | || (st->st_mode & S_IXOTH) | ||
560 | ) { | ||
561 | return TRUE; | ||
562 | } | ||
563 | return FALSE; | ||
564 | } | ||
565 | */ | ||
566 | |||
567 | #if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION | 325 | #if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION |
568 | 326 | ||
569 | static void username_tab_completion(char *ud, char *with_shash_flg) | 327 | static void username_tab_completion(char *ud, char *with_shash_flg) |
@@ -624,15 +382,16 @@ enum { | |||
624 | 382 | ||
625 | #if ENABLE_ASH | 383 | #if ENABLE_ASH |
626 | const char *cmdedit_path_lookup; | 384 | const char *cmdedit_path_lookup; |
627 | #else | ||
628 | #define cmdedit_path_lookup getenv("PATH") | ||
629 | #endif | 385 | #endif |
630 | |||
631 | static int path_parse(char ***p, int flags) | 386 | static int path_parse(char ***p, int flags) |
632 | { | 387 | { |
633 | int npth; | 388 | int npth; |
634 | const char *tmp; | 389 | const char *tmp; |
390 | #if ENABLE_ASH | ||
635 | const char *pth = cmdedit_path_lookup; | 391 | const char *pth = cmdedit_path_lookup; |
392 | #else | ||
393 | const char *pth = getenv("PATH") | ||
394 | #endif | ||
636 | 395 | ||
637 | /* if not setenv PATH variable, to search cur dir "." */ | 396 | /* if not setenv PATH variable, to search cur dir "." */ |
638 | if (flags != FIND_EXE_ONLY) | 397 | if (flags != FIND_EXE_ONLY) |
@@ -649,7 +408,7 @@ static int path_parse(char ***p, int flags) | |||
649 | tmp = strchr(tmp, ':'); | 408 | tmp = strchr(tmp, ':'); |
650 | if (!tmp) | 409 | if (!tmp) |
651 | break; | 410 | break; |
652 | if (*++tmp == 0) | 411 | if (*++tmp == '\0') |
653 | break; /* :<empty> */ | 412 | break; /* :<empty> */ |
654 | } | 413 | } |
655 | 414 | ||
@@ -672,20 +431,6 @@ static int path_parse(char ***p, int flags) | |||
672 | return npth; | 431 | return npth; |
673 | } | 432 | } |
674 | 433 | ||
675 | static char *add_quote_for_spec_chars(char *found) | ||
676 | { | ||
677 | int l = 0; | ||
678 | char *s = xmalloc((strlen(found) + 1) * 2); | ||
679 | |||
680 | while (*found) { | ||
681 | if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found)) | ||
682 | s[l++] = '\\'; | ||
683 | s[l++] = *found++; | ||
684 | } | ||
685 | s[l] = 0; | ||
686 | return s; | ||
687 | } | ||
688 | |||
689 | static void exe_n_cwd_tab_completion(char *command, int type) | 434 | static void exe_n_cwd_tab_completion(char *command, int type) |
690 | { | 435 | { |
691 | DIR *dir; | 436 | DIR *dir; |
@@ -699,6 +444,7 @@ static void exe_n_cwd_tab_completion(char *command, int type) | |||
699 | char *found; | 444 | char *found; |
700 | char *pfind = strrchr(command, '/'); | 445 | char *pfind = strrchr(command, '/'); |
701 | 446 | ||
447 | npaths = 1; | ||
702 | path1[0] = "."; | 448 | path1[0] = "."; |
703 | 449 | ||
704 | if (pfind == NULL) { | 450 | if (pfind == NULL) { |
@@ -706,20 +452,15 @@ static void exe_n_cwd_tab_completion(char *command, int type) | |||
706 | npaths = path_parse(&paths, type); | 452 | npaths = path_parse(&paths, type); |
707 | pfind = command; | 453 | pfind = command; |
708 | } else { | 454 | } else { |
709 | /* with dir */ | 455 | /* dirbuf = ".../.../.../" */ |
710 | /* save for change */ | 456 | safe_strncpy(dirbuf, command, (pfind - command) + 2); |
711 | strcpy(dirbuf, command); | ||
712 | /* set dir only */ | ||
713 | dirbuf[(pfind - command) + 1] = 0; | ||
714 | #if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION | 457 | #if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION |
715 | if (dirbuf[0] == '~') /* ~/... or ~user/... */ | 458 | if (dirbuf[0] == '~') /* ~/... or ~user/... */ |
716 | username_tab_completion(dirbuf, dirbuf); | 459 | username_tab_completion(dirbuf, dirbuf); |
717 | #endif | 460 | #endif |
718 | /* "strip" dirname in command */ | ||
719 | pfind++; | ||
720 | |||
721 | paths[0] = dirbuf; | 461 | paths[0] = dirbuf; |
722 | npaths = 1; /* only 1 dir */ | 462 | /* point to 'l' in "..../last_component" */ |
463 | pfind++; | ||
723 | } | 464 | } |
724 | 465 | ||
725 | for (i = 0; i < npaths; i++) { | 466 | for (i = 0; i < npaths; i++) { |
@@ -994,6 +735,20 @@ static int match_compare(const void *a, const void *b) | |||
994 | return strcmp(*(char**)a, *(char**)b); | 735 | return strcmp(*(char**)a, *(char**)b); |
995 | } | 736 | } |
996 | 737 | ||
738 | static char *add_quote_for_spec_chars(char *found) | ||
739 | { | ||
740 | int l = 0; | ||
741 | char *s = xmalloc((strlen(found) + 1) * 2); | ||
742 | |||
743 | while (*found) { | ||
744 | if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found)) | ||
745 | s[l++] = '\\'; | ||
746 | s[l++] = *found++; | ||
747 | } | ||
748 | s[l] = 0; | ||
749 | return s; | ||
750 | } | ||
751 | |||
997 | static void input_tab(int *lastWasTab) | 752 | static void input_tab(int *lastWasTab) |
998 | { | 753 | { |
999 | /* Do TAB completion */ | 754 | /* Do TAB completion */ |
@@ -1121,7 +876,15 @@ static void input_tab(int *lastWasTab) | |||
1121 | } | 876 | } |
1122 | #endif /* FEATURE_COMMAND_TAB_COMPLETION */ | 877 | #endif /* FEATURE_COMMAND_TAB_COMPLETION */ |
1123 | 878 | ||
879 | |||
1124 | #if MAX_HISTORY > 0 | 880 | #if MAX_HISTORY > 0 |
881 | |||
882 | static char *history[MAX_HISTORY+1]; /* history + current */ | ||
883 | /* saved history lines */ | ||
884 | static int n_history; | ||
885 | /* current pointer to history line */ | ||
886 | static int cur_history; | ||
887 | |||
1125 | static void get_previous_history(void) | 888 | static void get_previous_history(void) |
1126 | { | 889 | { |
1127 | if (command_ps[0] != 0 || history[cur_history] == 0) { | 890 | if (command_ps[0] != 0 || history[cur_history] == 0) { |
@@ -1193,14 +956,9 @@ void save_history (const char *tofile) | |||
1193 | fclose(fp); | 956 | fclose(fp); |
1194 | } | 957 | } |
1195 | } | 958 | } |
1196 | #endif | 959 | #endif /* FEATURE_COMMAND_SAVEHISTORY */ |
1197 | |||
1198 | #endif | ||
1199 | 960 | ||
1200 | enum { | 961 | #endif /* MAX_HISTORY > 0 */ |
1201 | ESC = 27, | ||
1202 | DEL = 127, | ||
1203 | }; | ||
1204 | 962 | ||
1205 | 963 | ||
1206 | /* | 964 | /* |
@@ -1217,14 +975,13 @@ enum { | |||
1217 | * CTL-t -- Transpose two characters | 975 | * CTL-t -- Transpose two characters |
1218 | * | 976 | * |
1219 | * Minimalist vi-style command line editing available if configured. | 977 | * Minimalist vi-style command line editing available if configured. |
1220 | * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us> | 978 | * vi mode implemented 2005 by Paul Fox <pgf@foxharp.boston.ma.us> |
1221 | * | ||
1222 | */ | 979 | */ |
1223 | 980 | ||
1224 | #if ENABLE_FEATURE_COMMAND_EDITING_VI | 981 | #if ENABLE_FEATURE_COMMAND_EDITING_VI |
1225 | static int vi_mode; | 982 | static int vi_mode; |
1226 | 983 | ||
1227 | void setvimode ( int viflag ) | 984 | void setvimode(int viflag) |
1228 | { | 985 | { |
1229 | vi_mode = viflag; | 986 | vi_mode = viflag; |
1230 | } | 987 | } |
@@ -1320,6 +1077,225 @@ vi_back_motion(char *command) | |||
1320 | input_backward(1); | 1077 | input_backward(1); |
1321 | } | 1078 | } |
1322 | } | 1079 | } |
1080 | #else | ||
1081 | enum { vi_mode = 0 }; | ||
1082 | #endif | ||
1083 | |||
1084 | |||
1085 | /* | ||
1086 | * cmdedit_read_input and its helpers | ||
1087 | */ | ||
1088 | |||
1089 | #define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp) | ||
1090 | #define getTermSettings(fd, argp) tcgetattr(fd, argp); | ||
1091 | |||
1092 | static sighandler_t previous_SIGWINCH_handler; | ||
1093 | |||
1094 | static void cmdedit_reset_term(void) | ||
1095 | { | ||
1096 | if (handlers_sets & SET_RESET_TERM) { | ||
1097 | setTermSettings(STDIN_FILENO, (void *) &initial_settings); | ||
1098 | handlers_sets &= ~SET_RESET_TERM; | ||
1099 | } | ||
1100 | if (handlers_sets & SET_WCHG_HANDLERS) { | ||
1101 | /* restore SIGWINCH handler */ | ||
1102 | signal(SIGWINCH, previous_SIGWINCH_handler); | ||
1103 | handlers_sets &= ~SET_WCHG_HANDLERS; | ||
1104 | } | ||
1105 | fflush(stdout); | ||
1106 | } | ||
1107 | |||
1108 | static void cmdedit_setwidth(int w, int redraw_flg) | ||
1109 | { | ||
1110 | cmdedit_termw = cmdedit_prmt_len + 2; | ||
1111 | if (w <= cmdedit_termw) { | ||
1112 | cmdedit_termw = cmdedit_termw % w; | ||
1113 | } | ||
1114 | if (w > cmdedit_termw) { | ||
1115 | cmdedit_termw = w; | ||
1116 | |||
1117 | if (redraw_flg) { | ||
1118 | /* new y for current cursor */ | ||
1119 | int new_y = (cursor + cmdedit_prmt_len) / w; | ||
1120 | |||
1121 | /* redraw */ | ||
1122 | redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); | ||
1123 | fflush(stdout); | ||
1124 | } | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | static void win_changed(int nsig) | ||
1129 | { | ||
1130 | int width; | ||
1131 | get_terminal_width_height(0, &width, NULL); | ||
1132 | cmdedit_setwidth(width, nsig /* - just a yes/no flag */); | ||
1133 | if (nsig == SIGWINCH) | ||
1134 | signal(SIGWINCH, win_changed); /* rearm ourself */ | ||
1135 | } | ||
1136 | |||
1137 | static void cmdedit_init(void) | ||
1138 | { | ||
1139 | cmdedit_prmt_len = 0; | ||
1140 | if (!(handlers_sets & SET_WCHG_HANDLERS)) { | ||
1141 | previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); | ||
1142 | win_changed(0); /* do initial resizing */ | ||
1143 | handlers_sets |= SET_WCHG_HANDLERS; | ||
1144 | } | ||
1145 | |||
1146 | if (!(handlers_sets & SET_ATEXIT)) { | ||
1147 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
1148 | struct passwd *entry; | ||
1149 | |||
1150 | my_euid = geteuid(); | ||
1151 | entry = getpwuid(my_euid); | ||
1152 | if (entry) { | ||
1153 | user_buf = xstrdup(entry->pw_name); | ||
1154 | home_pwd_buf = xstrdup(entry->pw_dir); | ||
1155 | } | ||
1156 | #endif | ||
1157 | |||
1158 | #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION | ||
1159 | |||
1160 | #if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
1161 | my_euid = geteuid(); | ||
1162 | #endif | ||
1163 | my_uid = getuid(); | ||
1164 | my_gid = getgid(); | ||
1165 | #endif /* FEATURE_COMMAND_TAB_COMPLETION */ | ||
1166 | handlers_sets |= SET_ATEXIT; | ||
1167 | // Crap. We should be able to do it without atexit. | ||
1168 | atexit(cmdedit_reset_term); /* be sure to do this only once */ | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | #if !ENABLE_FEATURE_SH_FANCY_PROMPT | ||
1173 | static void parse_prompt(const char *prmt_ptr) | ||
1174 | { | ||
1175 | cmdedit_prompt = prmt_ptr; | ||
1176 | cmdedit_prmt_len = strlen(prmt_ptr); | ||
1177 | put_prompt(); | ||
1178 | } | ||
1179 | #else | ||
1180 | static void parse_prompt(const char *prmt_ptr) | ||
1181 | { | ||
1182 | int prmt_len = 0; | ||
1183 | size_t cur_prmt_len = 0; | ||
1184 | char flg_not_length = '['; | ||
1185 | char *prmt_mem_ptr = xzalloc(1); | ||
1186 | char *pwd_buf = xgetcwd(0); | ||
1187 | char buf2[PATH_MAX + 1]; | ||
1188 | char buf[2]; | ||
1189 | char c; | ||
1190 | char *pbuf; | ||
1191 | |||
1192 | if (!pwd_buf) { | ||
1193 | pwd_buf = (char *)bb_msg_unknown; | ||
1194 | } | ||
1195 | |||
1196 | while (*prmt_ptr) { | ||
1197 | pbuf = buf; | ||
1198 | pbuf[1] = 0; | ||
1199 | c = *prmt_ptr++; | ||
1200 | if (c == '\\') { | ||
1201 | const char *cp = prmt_ptr; | ||
1202 | int l; | ||
1203 | |||
1204 | c = bb_process_escape_sequence(&prmt_ptr); | ||
1205 | if (prmt_ptr == cp) { | ||
1206 | if (*cp == 0) | ||
1207 | break; | ||
1208 | c = *prmt_ptr++; | ||
1209 | switch (c) { | ||
1210 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
1211 | case 'u': | ||
1212 | pbuf = user_buf; | ||
1213 | break; | ||
1214 | #endif | ||
1215 | case 'h': | ||
1216 | pbuf = hostname_buf; | ||
1217 | if (!pbuf) { | ||
1218 | pbuf = xzalloc(256); | ||
1219 | if (gethostname(pbuf, 255) < 0) { | ||
1220 | strcpy(pbuf, "?"); | ||
1221 | } else { | ||
1222 | char *s = strchr(pbuf, '.'); | ||
1223 | if (s) | ||
1224 | *s = '\0'; | ||
1225 | } | ||
1226 | hostname_buf = pbuf; | ||
1227 | } | ||
1228 | break; | ||
1229 | case '$': | ||
1230 | c = (my_euid == 0 ? '#' : '$'); | ||
1231 | break; | ||
1232 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
1233 | case 'w': | ||
1234 | pbuf = pwd_buf; | ||
1235 | l = strlen(home_pwd_buf); | ||
1236 | if (home_pwd_buf[0] != 0 | ||
1237 | && strncmp(home_pwd_buf, pbuf, l) == 0 | ||
1238 | && (pbuf[l]=='/' || pbuf[l]=='\0') | ||
1239 | && strlen(pwd_buf+l)<PATH_MAX | ||
1240 | ) { | ||
1241 | pbuf = buf2; | ||
1242 | *pbuf = '~'; | ||
1243 | strcpy(pbuf+1, pwd_buf+l); | ||
1244 | } | ||
1245 | break; | ||
1246 | #endif | ||
1247 | case 'W': | ||
1248 | pbuf = pwd_buf; | ||
1249 | cp = strrchr(pbuf,'/'); | ||
1250 | if (cp != NULL && cp != pbuf) | ||
1251 | pbuf += (cp-pbuf) + 1; | ||
1252 | break; | ||
1253 | case '!': | ||
1254 | snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines); | ||
1255 | break; | ||
1256 | case 'e': case 'E': /* \e \E = \033 */ | ||
1257 | c = '\033'; | ||
1258 | break; | ||
1259 | case 'x': case 'X': | ||
1260 | for (l = 0; l < 3;) { | ||
1261 | int h; | ||
1262 | buf2[l++] = *prmt_ptr; | ||
1263 | buf2[l] = 0; | ||
1264 | h = strtol(buf2, &pbuf, 16); | ||
1265 | if (h > UCHAR_MAX || (pbuf - buf2) < l) { | ||
1266 | l--; | ||
1267 | break; | ||
1268 | } | ||
1269 | prmt_ptr++; | ||
1270 | } | ||
1271 | buf2[l] = 0; | ||
1272 | c = (char)strtol(buf2, NULL, 16); | ||
1273 | if (c == 0) | ||
1274 | c = '?'; | ||
1275 | pbuf = buf; | ||
1276 | break; | ||
1277 | case '[': case ']': | ||
1278 | if (c == flg_not_length) { | ||
1279 | flg_not_length = flg_not_length == '[' ? ']' : '['; | ||
1280 | continue; | ||
1281 | } | ||
1282 | break; | ||
1283 | } | ||
1284 | } | ||
1285 | } | ||
1286 | if (pbuf == buf) | ||
1287 | *pbuf = c; | ||
1288 | cur_prmt_len = strlen(pbuf); | ||
1289 | prmt_len += cur_prmt_len; | ||
1290 | if (flg_not_length != ']') | ||
1291 | cmdedit_prmt_len += cur_prmt_len; | ||
1292 | prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); | ||
1293 | } | ||
1294 | if (pwd_buf!=(char *)bb_msg_unknown) | ||
1295 | free(pwd_buf); | ||
1296 | cmdedit_prompt = prmt_mem_ptr; | ||
1297 | put_prompt(); | ||
1298 | } | ||
1323 | #endif | 1299 | #endif |
1324 | 1300 | ||
1325 | /* | 1301 | /* |
@@ -1337,18 +1313,19 @@ vi_back_motion(char *command) | |||
1337 | #define vi_case(caselabel) USE_FEATURE_COMMAND_EDITING(caselabel) | 1313 | #define vi_case(caselabel) USE_FEATURE_COMMAND_EDITING(caselabel) |
1338 | 1314 | ||
1339 | /* convert uppercase ascii to equivalent control char, for readability */ | 1315 | /* convert uppercase ascii to equivalent control char, for readability */ |
1340 | #define CNTRL(uc_char) ((uc_char) - 0x40) | 1316 | #undef CTRL |
1317 | #define CTRL(a) ((a) & ~0x40) | ||
1341 | 1318 | ||
1342 | 1319 | ||
1343 | int cmdedit_read_input(char *prompt, char command[BUFSIZ]) | 1320 | int cmdedit_read_input(char *prompt, char command[BUFSIZ]) |
1344 | { | 1321 | { |
1345 | int break_out = 0; | ||
1346 | int lastWasTab = FALSE; | 1322 | int lastWasTab = FALSE; |
1347 | unsigned char c; | ||
1348 | unsigned int ic; | 1323 | unsigned int ic; |
1324 | unsigned char c; | ||
1325 | smallint break_out = 0; | ||
1349 | #if ENABLE_FEATURE_COMMAND_EDITING_VI | 1326 | #if ENABLE_FEATURE_COMMAND_EDITING_VI |
1350 | unsigned int prevc; | 1327 | smallint vi_cmdmode = 0; |
1351 | int vi_cmdmode = 0; | 1328 | smalluint prevc; |
1352 | #endif | 1329 | #endif |
1353 | /* prepare before init handlers */ | 1330 | /* prepare before init handlers */ |
1354 | cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ | 1331 | cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ |
@@ -1401,20 +1378,20 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1401 | goto_new_line(); | 1378 | goto_new_line(); |
1402 | break_out = 1; | 1379 | break_out = 1; |
1403 | break; | 1380 | break; |
1404 | case CNTRL('A'): | 1381 | case CTRL('A'): |
1405 | vi_case( case '0'|vbit: ) | 1382 | vi_case( case '0'|vbit: ) |
1406 | /* Control-a -- Beginning of line */ | 1383 | /* Control-a -- Beginning of line */ |
1407 | input_backward(cursor); | 1384 | input_backward(cursor); |
1408 | break; | 1385 | break; |
1409 | case CNTRL('B'): | 1386 | case CTRL('B'): |
1410 | vi_case( case 'h'|vbit: ) | 1387 | vi_case( case 'h'|vbit: ) |
1411 | vi_case( case '\b'|vbit: ) | 1388 | vi_case( case '\b'|vbit: ) |
1412 | vi_case( case DEL|vbit: ) | 1389 | vi_case( case '\x7f'|vbit: ) /* DEL */ |
1413 | /* Control-b -- Move back one character */ | 1390 | /* Control-b -- Move back one character */ |
1414 | input_backward(1); | 1391 | input_backward(1); |
1415 | break; | 1392 | break; |
1416 | case CNTRL('C'): | 1393 | case CTRL('C'): |
1417 | vi_case( case CNTRL('C')|vbit: ) | 1394 | vi_case( case CTRL('C')|vbit: ) |
1418 | /* Control-c -- stop gathering input */ | 1395 | /* Control-c -- stop gathering input */ |
1419 | goto_new_line(); | 1396 | goto_new_line(); |
1420 | #if !ENABLE_ASH | 1397 | #if !ENABLE_ASH |
@@ -1427,39 +1404,41 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1427 | break_out = -1; /* to control traps */ | 1404 | break_out = -1; /* to control traps */ |
1428 | #endif | 1405 | #endif |
1429 | break; | 1406 | break; |
1430 | case CNTRL('D'): | 1407 | case CTRL('D'): |
1431 | /* Control-d -- Delete one character, or exit | 1408 | /* Control-d -- Delete one character, or exit |
1432 | * if the len=0 and no chars to delete */ | 1409 | * if the len=0 and no chars to delete */ |
1433 | if (len == 0) { | 1410 | if (len == 0) { |
1434 | errno = 0; | 1411 | errno = 0; |
1435 | prepare_to_die: | 1412 | prepare_to_die: |
1413 | // So, our API depends on whether we have ash compiled in or not? Crap... | ||
1436 | #if !ENABLE_ASH | 1414 | #if !ENABLE_ASH |
1437 | printf("exit"); | 1415 | printf("exit"); |
1438 | goto_new_line(); | 1416 | goto_new_line(); |
1439 | /* cmdedit_reset_term() called in atexit */ | 1417 | /* cmdedit_reset_term() called in atexit */ |
1418 | // FIXME. this is definitely not good | ||
1440 | exit(EXIT_SUCCESS); | 1419 | exit(EXIT_SUCCESS); |
1441 | #else | 1420 | #else |
1442 | /* to control stopped jobs */ | 1421 | /* to control stopped jobs */ |
1443 | len = break_out = -1; | 1422 | break_out = len = -1; |
1444 | break; | 1423 | break; |
1445 | #endif | 1424 | #endif |
1446 | } else { | 1425 | } else { |
1447 | input_delete(0); | 1426 | input_delete(0); |
1448 | } | 1427 | } |
1449 | break; | 1428 | break; |
1450 | case CNTRL('E'): | 1429 | case CTRL('E'): |
1451 | vi_case( case '$'|vbit: ) | 1430 | vi_case( case '$'|vbit: ) |
1452 | /* Control-e -- End of line */ | 1431 | /* Control-e -- End of line */ |
1453 | input_end(); | 1432 | input_end(); |
1454 | break; | 1433 | break; |
1455 | case CNTRL('F'): | 1434 | case CTRL('F'): |
1456 | vi_case( case 'l'|vbit: ) | 1435 | vi_case( case 'l'|vbit: ) |
1457 | vi_case( case ' '|vbit: ) | 1436 | vi_case( case ' '|vbit: ) |
1458 | /* Control-f -- Move forward one character */ | 1437 | /* Control-f -- Move forward one character */ |
1459 | input_forward(); | 1438 | input_forward(); |
1460 | break; | 1439 | break; |
1461 | case '\b': | 1440 | case '\b': |
1462 | case DEL: | 1441 | case '\x7f': /* DEL */ |
1463 | /* Control-h and DEL */ | 1442 | /* Control-h and DEL */ |
1464 | input_backspace(); | 1443 | input_backspace(); |
1465 | break; | 1444 | break; |
@@ -1468,28 +1447,28 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1468 | input_tab(&lastWasTab); | 1447 | input_tab(&lastWasTab); |
1469 | #endif | 1448 | #endif |
1470 | break; | 1449 | break; |
1471 | case CNTRL('K'): | 1450 | case CTRL('K'): |
1472 | /* Control-k -- clear to end of line */ | 1451 | /* Control-k -- clear to end of line */ |
1473 | command[cursor] = 0; | 1452 | command[cursor] = 0; |
1474 | len = cursor; | 1453 | len = cursor; |
1475 | printf("\033[J"); | 1454 | printf("\033[J"); |
1476 | break; | 1455 | break; |
1477 | case CNTRL('L'): | 1456 | case CTRL('L'): |
1478 | vi_case( case CNTRL('L')|vbit: ) | 1457 | vi_case( case CTRL('L')|vbit: ) |
1479 | /* Control-l -- clear screen */ | 1458 | /* Control-l -- clear screen */ |
1480 | printf("\033[H"); | 1459 | printf("\033[H"); |
1481 | redraw(0, len - cursor); | 1460 | redraw(0, len - cursor); |
1482 | break; | 1461 | break; |
1483 | #if MAX_HISTORY > 0 | 1462 | #if MAX_HISTORY > 0 |
1484 | case CNTRL('N'): | 1463 | case CTRL('N'): |
1485 | vi_case( case CNTRL('N')|vbit: ) | 1464 | vi_case( case CTRL('N')|vbit: ) |
1486 | vi_case( case 'j'|vbit: ) | 1465 | vi_case( case 'j'|vbit: ) |
1487 | /* Control-n -- Get next command in history */ | 1466 | /* Control-n -- Get next command in history */ |
1488 | if (get_next_history()) | 1467 | if (get_next_history()) |
1489 | goto rewrite_line; | 1468 | goto rewrite_line; |
1490 | break; | 1469 | break; |
1491 | case CNTRL('P'): | 1470 | case CTRL('P'): |
1492 | vi_case( case CNTRL('P')|vbit: ) | 1471 | vi_case( case CTRL('P')|vbit: ) |
1493 | vi_case( case 'k'|vbit: ) | 1472 | vi_case( case 'k'|vbit: ) |
1494 | /* Control-p -- Get previous command from history */ | 1473 | /* Control-p -- Get previous command from history */ |
1495 | if (cur_history > 0) { | 1474 | if (cur_history > 0) { |
@@ -1500,16 +1479,16 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1500 | } | 1479 | } |
1501 | break; | 1480 | break; |
1502 | #endif | 1481 | #endif |
1503 | case CNTRL('U'): | 1482 | case CTRL('U'): |
1504 | vi_case( case CNTRL('U')|vbit: ) | 1483 | vi_case( case CTRL('U')|vbit: ) |
1505 | /* Control-U -- Clear line before cursor */ | 1484 | /* Control-U -- Clear line before cursor */ |
1506 | if (cursor) { | 1485 | if (cursor) { |
1507 | strcpy(command, command + cursor); | 1486 | strcpy(command, command + cursor); |
1508 | redraw(cmdedit_y, len -= cursor); | 1487 | redraw(cmdedit_y, len -= cursor); |
1509 | } | 1488 | } |
1510 | break; | 1489 | break; |
1511 | case CNTRL('W'): | 1490 | case CTRL('W'): |
1512 | vi_case( case CNTRL('W')|vbit: ) | 1491 | vi_case( case CTRL('W')|vbit: ) |
1513 | /* Control-W -- Remove the last word */ | 1492 | /* Control-W -- Remove the last word */ |
1514 | while (cursor > 0 && isspace(command[cursor-1])) | 1493 | while (cursor > 0 && isspace(command[cursor-1])) |
1515 | input_backspace(); | 1494 | input_backspace(); |
@@ -1645,7 +1624,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1645 | break; | 1624 | break; |
1646 | #endif /* FEATURE_COMMAND_EDITING_VI */ | 1625 | #endif /* FEATURE_COMMAND_EDITING_VI */ |
1647 | 1626 | ||
1648 | case ESC: | 1627 | case '\x1b': /* ESC */ |
1649 | 1628 | ||
1650 | #if ENABLE_FEATURE_COMMAND_EDITING_VI | 1629 | #if ENABLE_FEATURE_COMMAND_EDITING_VI |
1651 | if (vi_mode) { | 1630 | if (vi_mode) { |
@@ -1676,7 +1655,6 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1676 | switch (c) { | 1655 | switch (c) { |
1677 | #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION | 1656 | #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION |
1678 | case '\t': /* Alt-Tab */ | 1657 | case '\t': /* Alt-Tab */ |
1679 | |||
1680 | input_tab(&lastWasTab); | 1658 | input_tab(&lastWasTab); |
1681 | break; | 1659 | break; |
1682 | #endif | 1660 | #endif |
@@ -1686,24 +1664,19 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
1686 | if (cur_history > 0) { | 1664 | if (cur_history > 0) { |
1687 | get_previous_history(); | 1665 | get_previous_history(); |
1688 | goto rewrite_line; | 1666 | goto rewrite_line; |
1689 | } else { | ||
1690 | beep(); | ||
1691 | } | 1667 | } |
1668 | beep(); | ||
1692 | break; | 1669 | break; |
1693 | case 'B': | 1670 | case 'B': |
1694 | /* Down Arrow -- Get next command in history */ | 1671 | /* Down Arrow -- Get next command in history */ |
1695 | if (!get_next_history()) | 1672 | if (!get_next_history()) |
1696 | break; | 1673 | break; |
1697 | /* Rewrite the line with the selected history item */ | 1674 | /* Rewrite the line with the selected history item */ |
1698 | rewrite_line: | 1675 | rewrite_line: |
1699 | /* change command */ | 1676 | /* change command */ |
1700 | len = strlen(strcpy(command, history[cur_history])); | 1677 | len = strlen(strcpy(command, history[cur_history])); |
1701 | /* redraw and go to eol (bol, in vi */ | 1678 | /* redraw and go to eol (bol, in vi */ |
1702 | #if ENABLE_FEATURE_COMMAND_EDITING_VI | 1679 | redraw(cmdedit_y, vi_mode ? 9999 : 0); |
1703 | redraw(cmdedit_y, vi_mode ? 9999:0); | ||
1704 | #else | ||
1705 | redraw(cmdedit_y, 0); | ||
1706 | #endif | ||
1707 | break; | 1680 | break; |
1708 | #endif | 1681 | #endif |
1709 | case 'C': | 1682 | case 'C': |
@@ -1737,7 +1710,7 @@ rewrite_line: | |||
1737 | default: /* If it's regular input, do the normal thing */ | 1710 | default: /* If it's regular input, do the normal thing */ |
1738 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT | 1711 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT |
1739 | /* Control-V -- Add non-printable symbol */ | 1712 | /* Control-V -- Add non-printable symbol */ |
1740 | if (c == CNTRL('V')) { | 1713 | if (c == CTRL('V')) { |
1741 | if (safe_read(0, &c, 1) < 1) | 1714 | if (safe_read(0, &c, 1) < 1) |
1742 | goto prepare_to_die; | 1715 | goto prepare_to_die; |
1743 | if (c == 0) { | 1716 | if (c == 0) { |
@@ -1763,7 +1736,7 @@ rewrite_line: | |||
1763 | if (cursor == (len - 1)) { /* Append if at the end of the line */ | 1736 | if (cursor == (len - 1)) { /* Append if at the end of the line */ |
1764 | *(command + cursor) = c; | 1737 | *(command + cursor) = c; |
1765 | *(command + cursor + 1) = 0; | 1738 | *(command + cursor + 1) = 0; |
1766 | cmdedit_set_out_char(0); | 1739 | cmdedit_set_out_char(' '); |
1767 | } else { /* Insert otherwise */ | 1740 | } else { /* Insert otherwise */ |
1768 | int sc = cursor; | 1741 | int sc = cursor; |
1769 | 1742 | ||
@@ -1796,7 +1769,7 @@ rewrite_line: | |||
1796 | 1769 | ||
1797 | free(history[MAX_HISTORY]); | 1770 | free(history[MAX_HISTORY]); |
1798 | history[MAX_HISTORY] = 0; | 1771 | history[MAX_HISTORY] = 0; |
1799 | /* After max history, remove the oldest command */ | 1772 | /* After max history, remove the oldest command */ |
1800 | if (i >= MAX_HISTORY) { | 1773 | if (i >= MAX_HISTORY) { |
1801 | free(history[0]); | 1774 | free(history[0]); |
1802 | for (i = 0; i < MAX_HISTORY-1; i++) | 1775 | for (i = 0; i < MAX_HISTORY-1; i++) |
@@ -1805,24 +1778,22 @@ rewrite_line: | |||
1805 | history[i++] = xstrdup(command); | 1778 | history[i++] = xstrdup(command); |
1806 | cur_history = i; | 1779 | cur_history = i; |
1807 | n_history = i; | 1780 | n_history = i; |
1808 | #if ENABLE_FEATURE_SH_FANCY_PROMPT | 1781 | USE_FEATURE_SH_FANCY_PROMPT(num_ok_lines++;) |
1809 | num_ok_lines++; | ||
1810 | #endif | ||
1811 | } | ||
1812 | #else /* MAX_HISTORY == 0 */ | ||
1813 | #if ENABLE_FEATURE_SH_FANCY_PROMPT | ||
1814 | if (len > 0) { /* no put empty line */ | ||
1815 | num_ok_lines++; | ||
1816 | } | 1782 | } |
1817 | #endif | 1783 | #else /* MAX_HISTORY == 0 */ |
1818 | #endif /* MAX_HISTORY > 0 */ | 1784 | /* dont put empty line */ |
1785 | USE_FEATURE_SH_FANCY_PROMPT(if (len > 0) num_ok_lines++;) | ||
1786 | #endif /* MAX_HISTORY */ | ||
1787 | |||
1819 | if (break_out > 0) { | 1788 | if (break_out > 0) { |
1820 | command[len++] = '\n'; /* set '\n' */ | 1789 | command[len++] = '\n'; |
1821 | command[len] = 0; | 1790 | command[len] = '\0'; |
1822 | } | 1791 | } |
1792 | |||
1823 | #if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION | 1793 | #if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION |
1824 | input_tab(0); /* strong free */ | 1794 | input_tab(0); |
1825 | #endif | 1795 | #endif |
1796 | |||
1826 | #if ENABLE_FEATURE_SH_FANCY_PROMPT | 1797 | #if ENABLE_FEATURE_SH_FANCY_PROMPT |
1827 | free(cmdedit_prompt); | 1798 | free(cmdedit_prompt); |
1828 | #endif | 1799 | #endif |
@@ -1833,13 +1804,15 @@ rewrite_line: | |||
1833 | #endif /* FEATURE_COMMAND_EDITING */ | 1804 | #endif /* FEATURE_COMMAND_EDITING */ |
1834 | 1805 | ||
1835 | 1806 | ||
1836 | #ifdef TEST | 1807 | /* |
1808 | * Testing | ||
1809 | */ | ||
1837 | 1810 | ||
1838 | const char *applet_name = "debug stuff usage"; | 1811 | #ifdef TEST |
1839 | 1812 | ||
1840 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT | ||
1841 | #include <locale.h> | 1813 | #include <locale.h> |
1842 | #endif | 1814 | |
1815 | const char *applet_name = "debug stuff usage"; | ||
1843 | 1816 | ||
1844 | int main(int argc, char **argv) | 1817 | int main(int argc, char **argv) |
1845 | { | 1818 | { |
diff --git a/shell/cmdedit.h b/shell/cmdedit.h index f5863921a..4a32cf63e 100644 --- a/shell/cmdedit.h +++ b/shell/cmdedit.h | |||
@@ -4,11 +4,11 @@ | |||
4 | 4 | ||
5 | int cmdedit_read_input(char* promptStr, char* command); | 5 | int cmdedit_read_input(char* promptStr, char* command); |
6 | 6 | ||
7 | #ifdef CONFIG_ASH | 7 | #if ENABLE_ASH |
8 | extern const char *cmdedit_path_lookup; | 8 | extern const char *cmdedit_path_lookup; |
9 | #endif | 9 | #endif |
10 | 10 | ||
11 | #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY | 11 | #if ENABLE_FEATURE_COMMAND_SAVEHISTORY |
12 | void load_history(const char *fromfile); | 12 | void load_history(const char *fromfile); |
13 | void save_history(const char *tofile); | 13 | void save_history(const char *tofile); |
14 | #endif | 14 | #endif |