diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-11-10 01:35:47 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-11-10 01:35:47 +0000 |
commit | 73cb1fdfea01a5b16d906285275fa3805cac01a3 (patch) | |
tree | 1f8753aabd27cf20c73b9b58240bc47e6e70dc04 /libbb/lineedit.c | |
parent | e7fca5125a1e683a8f92e988b6218da63a620f7a (diff) | |
download | busybox-w32-73cb1fdfea01a5b16d906285275fa3805cac01a3.tar.gz busybox-w32-73cb1fdfea01a5b16d906285275fa3805cac01a3.tar.bz2 busybox-w32-73cb1fdfea01a5b16d906285275fa3805cac01a3.zip |
lineedit: stop using both data/bss and tons of stack.
stack usage was ~10 kb!
unfortunately, noticeable code size growth:
text data bss dec hex filename
9252 12 181 9445 24e5 busybox.t7/libbb/lineedit.o
9714 4 0 9718 25f6 busybox.t8/libbb/lineedit.o
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r-- | libbb/lineedit.c | 259 |
1 files changed, 166 insertions, 93 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index f65e852b1..4d33834ce 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #define ENABLE_FEATURE_TAB_COMPLETION 0 | 41 | #define ENABLE_FEATURE_TAB_COMPLETION 0 |
42 | #define ENABLE_FEATURE_USERNAME_COMPLETION 0 | 42 | #define ENABLE_FEATURE_USERNAME_COMPLETION 0 |
43 | #define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0 | 43 | #define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0 |
44 | #define ENABLE_FEATURE_CLEAN_UP 0 | ||
45 | 44 | ||
46 | #endif /* TEST */ | 45 | #endif /* TEST */ |
47 | 46 | ||
@@ -56,35 +55,117 @@ | |||
56 | #endif | 55 | #endif |
57 | 56 | ||
58 | #define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \ | 57 | #define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \ |
59 | (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT) | 58 | (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT) |
59 | #define USE_FEATURE_GETUSERNAME_AND_HOMEDIR(...) | ||
60 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
61 | #undef USE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
62 | #define USE_FEATURE_GETUSERNAME_AND_HOMEDIR(...) __VA_ARGS__ | ||
63 | #endif | ||
60 | 64 | ||
61 | enum { MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN }; | 65 | enum { |
66 | /* We use int16_t for positions, need to limit line len */ | ||
67 | MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0 | ||
68 | ? CONFIG_FEATURE_EDITING_MAX_LEN | ||
69 | : 0x7ff0 | ||
70 | }; | ||
71 | |||
72 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
73 | static const char null_str[] ALIGN1 = ""; | ||
74 | #endif | ||
62 | 75 | ||
63 | static line_input_t *state; | 76 | /* We try to minimize both static and stack usage. */ |
77 | struct statics { | ||
78 | line_input_t *state; | ||
64 | 79 | ||
65 | static struct termios initial_settings, new_settings; | 80 | volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */ |
81 | sighandler_t previous_SIGWINCH_handler; | ||
66 | 82 | ||
67 | static volatile unsigned cmdedit_termw = 80; /* actual terminal width */ | ||
68 | 83 | ||
69 | static int cmdedit_x; /* real x terminal position */ | 84 | int cmdedit_x; /* real x terminal position */ |
70 | static int cmdedit_y; /* pseudoreal y terminal position */ | 85 | int cmdedit_y; /* pseudoreal y terminal position */ |
71 | static int cmdedit_prmt_len; /* length of prompt (without colors etc) */ | 86 | int cmdedit_prmt_len; /* length of prompt (without colors etc) */ |
72 | 87 | ||
73 | static unsigned cursor; | 88 | unsigned cursor; |
74 | static unsigned command_len; | 89 | unsigned command_len; |
75 | static char *command_ps; | 90 | char *command_ps; |
76 | static const char *cmdedit_prompt; | ||
77 | 91 | ||
92 | const char *cmdedit_prompt; | ||
78 | #if ENABLE_FEATURE_EDITING_FANCY_PROMPT | 93 | #if ENABLE_FEATURE_EDITING_FANCY_PROMPT |
79 | static char *hostname_buf; | 94 | char *hostname_buf; |
80 | static int num_ok_lines = 1; | 95 | int num_ok_lines; /* = 1; */ |
96 | #endif | ||
97 | |||
98 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | ||
99 | char *user_buf; | ||
100 | char *home_pwd_buf; /* = (char*)null_str; */ | ||
101 | #endif | ||
102 | |||
103 | #if ENABLE_FEATURE_TAB_COMPLETION | ||
104 | char **matches; | ||
105 | unsigned num_matches; | ||
81 | #endif | 106 | #endif |
82 | 107 | ||
108 | #if ENABLE_FEATURE_EDITING_VI | ||
109 | #define DELBUFSIZ 128 | ||
110 | char *delptr; | ||
111 | smallint newdelflag; /* whether delbuf should be reused yet */ | ||
112 | char delbuf[DELBUFSIZ]; /* a place to store deleted characters */ | ||
113 | #endif | ||
114 | |||
115 | /* Formerly these were big buffers on stack: */ | ||
116 | #if ENABLE_FEATURE_TAB_COMPLETION | ||
117 | char exe_n_cwd_tab_completion__dirbuf[MAX_LINELEN]; | ||
118 | char input_tab__matchBuf[MAX_LINELEN]; | ||
119 | int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */ | ||
120 | int16_t find_match__pos_buf[MAX_LINELEN + 1]; | ||
121 | #endif | ||
122 | }; | ||
123 | |||
124 | static struct statics *const ptr_to_statics __attribute__ ((section (".data"))); | ||
125 | |||
126 | #define S (*ptr_to_statics) | ||
127 | #define state (S.state ) | ||
128 | #define cmdedit_termw (S.cmdedit_termw ) | ||
129 | #define previous_SIGWINCH_handler (S.previous_SIGWINCH_handler) | ||
130 | #define cmdedit_x (S.cmdedit_x ) | ||
131 | #define cmdedit_y (S.cmdedit_y ) | ||
132 | #define cmdedit_prmt_len (S.cmdedit_prmt_len) | ||
133 | #define cursor (S.cursor ) | ||
134 | #define command_len (S.command_len ) | ||
135 | #define command_ps (S.command_ps ) | ||
136 | #define cmdedit_prompt (S.cmdedit_prompt ) | ||
137 | #define hostname_buf (S.hostname_buf ) | ||
138 | #define num_ok_lines (S.num_ok_lines ) | ||
139 | #define user_buf (S.user_buf ) | ||
140 | #define home_pwd_buf (S.home_pwd_buf ) | ||
141 | #define matches (S.matches ) | ||
142 | #define num_matches (S.num_matches ) | ||
143 | #define delptr (S.delptr ) | ||
144 | #define newdelflag (S.newdelflag ) | ||
145 | #define delbuf (S.delbuf ) | ||
146 | |||
147 | #define INIT_S() do { \ | ||
148 | (*(struct statics**)&ptr_to_statics) = xzalloc(sizeof(S)); \ | ||
149 | cmdedit_termw = 80; \ | ||
150 | USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \ | ||
151 | USE_FEATURE_GETUSERNAME_AND_HOMEDIR(home_pwd_buf = (char*)null_str;) \ | ||
152 | } while (0) | ||
153 | static void deinit_S(void) | ||
154 | { | ||
155 | #if ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
156 | free(hostname_buf); | ||
157 | /* This one is allocated only if FANCY_PROMPT is on | ||
158 | * (otherwise it points to verbatim prompt (NOT malloced) */ | ||
159 | free((char*)cmdedit_prompt); | ||
160 | #endif | ||
83 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR | 161 | #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR |
84 | static const char null_str[] = ""; | 162 | free(user_buf); |
85 | static char *user_buf; | 163 | if (home_pwd_buf != null_str) |
86 | static char *home_pwd_buf = (char*)null_str; | 164 | free(home_pwd_buf); |
87 | #endif | 165 | #endif |
166 | free(ptr_to_statics); | ||
167 | } | ||
168 | #define DEINIT_S() deinit_S() | ||
88 | 169 | ||
89 | /* Put 'command_ps[cursor]', cursor++. | 170 | /* Put 'command_ps[cursor]', cursor++. |
90 | * Advance cursor on screen. If we reached right margin, scroll text up | 171 | * Advance cursor on screen. If we reached right margin, scroll text up |
@@ -110,8 +191,7 @@ static void cmdedit_set_out_char(int next_char) | |||
110 | } else | 191 | } else |
111 | #endif | 192 | #endif |
112 | { | 193 | { |
113 | if (initial_settings.c_lflag & ECHO) | 194 | bb_putchar(c); |
114 | bb_putchar(c); | ||
115 | } | 195 | } |
116 | if (++cmdedit_x >= cmdedit_termw) { | 196 | if (++cmdedit_x >= cmdedit_termw) { |
117 | /* terminal is scrolled down */ | 197 | /* terminal is scrolled down */ |
@@ -204,13 +284,6 @@ static void redraw(int y, int back_cursor) | |||
204 | input_backward(back_cursor); | 284 | input_backward(back_cursor); |
205 | } | 285 | } |
206 | 286 | ||
207 | #if ENABLE_FEATURE_EDITING_VI | ||
208 | #define DELBUFSIZ 128 | ||
209 | static char *delbuf; /* a (malloced) place to store deleted characters */ | ||
210 | static char *delp; | ||
211 | static char newdelflag; /* whether delbuf should be reused yet */ | ||
212 | #endif | ||
213 | |||
214 | /* Delete the char in front of the cursor, optionally saving it | 287 | /* Delete the char in front of the cursor, optionally saving it |
215 | * for later putback */ | 288 | * for later putback */ |
216 | static void input_delete(int save) | 289 | static void input_delete(int save) |
@@ -223,14 +296,11 @@ static void input_delete(int save) | |||
223 | #if ENABLE_FEATURE_EDITING_VI | 296 | #if ENABLE_FEATURE_EDITING_VI |
224 | if (save) { | 297 | if (save) { |
225 | if (newdelflag) { | 298 | if (newdelflag) { |
226 | if (!delbuf) | 299 | delptr = delbuf; |
227 | delbuf = malloc(DELBUFSIZ); | ||
228 | /* safe if malloc fails */ | ||
229 | delp = delbuf; | ||
230 | newdelflag = 0; | 300 | newdelflag = 0; |
231 | } | 301 | } |
232 | if (delbuf && (delp - delbuf < DELBUFSIZ)) | 302 | if ((delptr - delbuf) < DELBUFSIZ) |
233 | *delp++ = command_ps[j]; | 303 | *delptr++ = command_ps[j]; |
234 | } | 304 | } |
235 | #endif | 305 | #endif |
236 | 306 | ||
@@ -245,7 +315,7 @@ static void input_delete(int save) | |||
245 | static void put(void) | 315 | static void put(void) |
246 | { | 316 | { |
247 | int ocursor; | 317 | int ocursor; |
248 | int j = delp - delbuf; | 318 | int j = delptr - delbuf; |
249 | 319 | ||
250 | if (j == 0) | 320 | if (j == 0) |
251 | return; | 321 | return; |
@@ -275,12 +345,8 @@ static void input_forward(void) | |||
275 | cmdedit_set_out_char(command_ps[cursor + 1]); | 345 | cmdedit_set_out_char(command_ps[cursor + 1]); |
276 | } | 346 | } |
277 | 347 | ||
278 | |||
279 | #if ENABLE_FEATURE_TAB_COMPLETION | 348 | #if ENABLE_FEATURE_TAB_COMPLETION |
280 | 349 | ||
281 | static char **matches; | ||
282 | static unsigned num_matches; | ||
283 | |||
284 | static void free_tab_completion_data(void) | 350 | static void free_tab_completion_data(void) |
285 | { | 351 | { |
286 | if (matches) { | 352 | if (matches) { |
@@ -329,11 +395,8 @@ static void username_tab_completion(char *ud, char *with_shash_flg) | |||
329 | } | 395 | } |
330 | if (home) { | 396 | if (home) { |
331 | if ((userlen + strlen(home) + 1) < MAX_LINELEN) { | 397 | if ((userlen + strlen(home) + 1) < MAX_LINELEN) { |
332 | char temp2[MAX_LINELEN]; /* argument size */ | ||
333 | |||
334 | /* /home/user/... */ | 398 | /* /home/user/... */ |
335 | sprintf(temp2, "%s%s", home, ud); | 399 | sprintf(sav_ud, "%s%s", home, ud); |
336 | strcpy(sav_ud, temp2); | ||
337 | } | 400 | } |
338 | } | 401 | } |
339 | } else { | 402 | } else { |
@@ -411,7 +474,6 @@ static void exe_n_cwd_tab_completion(char *command, int type) | |||
411 | { | 474 | { |
412 | DIR *dir; | 475 | DIR *dir; |
413 | struct dirent *next; | 476 | struct dirent *next; |
414 | char dirbuf[MAX_LINELEN]; | ||
415 | struct stat st; | 477 | struct stat st; |
416 | char *path1[1]; | 478 | char *path1[1]; |
417 | char **paths = path1; | 479 | char **paths = path1; |
@@ -419,6 +481,8 @@ static void exe_n_cwd_tab_completion(char *command, int type) | |||
419 | int i; | 481 | int i; |
420 | char *found; | 482 | char *found; |
421 | char *pfind = strrchr(command, '/'); | 483 | char *pfind = strrchr(command, '/'); |
484 | /* char dirbuf[MAX_LINELEN]; */ | ||
485 | #define dirbuf (S.exe_n_cwd_tab_completion__dirbuf) | ||
422 | 486 | ||
423 | npaths = 1; | 487 | npaths = 1; |
424 | path1[0] = (char*)"."; | 488 | path1[0] = (char*)"."; |
@@ -492,21 +556,25 @@ static void exe_n_cwd_tab_completion(char *command, int type) | |||
492 | free(paths[0]); /* allocated memory only in first member */ | 556 | free(paths[0]); /* allocated memory only in first member */ |
493 | free(paths); | 557 | free(paths); |
494 | } | 558 | } |
559 | #undef dirbuf | ||
495 | } | 560 | } |
496 | 561 | ||
497 | #define QUOT (UCHAR_MAX+1) | 562 | #define QUOT (UCHAR_MAX+1) |
498 | 563 | ||
499 | #define collapse_pos(is, in) { \ | 564 | #define collapse_pos(is, in) do { \ |
500 | memmove(int_buf+(is), int_buf+(in), (MAX_LINELEN+1-(is)-(in))*sizeof(int)); \ | 565 | memmove(int_buf+(is), int_buf+(in), (MAX_LINELEN+1-(is)-(in)) * sizeof(pos_buf[0])); \ |
501 | memmove(pos_buf+(is), pos_buf+(in), (MAX_LINELEN+1-(is)-(in))*sizeof(int)); } | 566 | memmove(pos_buf+(is), pos_buf+(in), (MAX_LINELEN+1-(is)-(in)) * sizeof(pos_buf[0])); \ |
567 | } while (0) | ||
502 | 568 | ||
503 | static int find_match(char *matchBuf, int *len_with_quotes) | 569 | static int find_match(char *matchBuf, int *len_with_quotes) |
504 | { | 570 | { |
505 | int i, j; | 571 | int i, j; |
506 | int command_mode; | 572 | int command_mode; |
507 | int c, c2; | 573 | int c, c2; |
508 | int int_buf[MAX_LINELEN + 1]; | 574 | /* int16_t int_buf[MAX_LINELEN + 1]; */ |
509 | int pos_buf[MAX_LINELEN + 1]; | 575 | /* int16_t pos_buf[MAX_LINELEN + 1]; */ |
576 | #define int_buf (S.find_match__int_buf) | ||
577 | #define pos_buf (S.find_match__pos_buf) | ||
510 | 578 | ||
511 | /* set to integer dimension characters and own positions */ | 579 | /* set to integer dimension characters and own positions */ |
512 | for (i = 0;; i++) { | 580 | for (i = 0;; i++) { |
@@ -622,8 +690,8 @@ static int find_match(char *matchBuf, int *len_with_quotes) | |||
622 | for (i = 0; int_buf[i]; i++) | 690 | for (i = 0; int_buf[i]; i++) |
623 | if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { | 691 | if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { |
624 | if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY | 692 | if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY |
625 | && matchBuf[pos_buf[0]]=='c' | 693 | && matchBuf[pos_buf[0]] == 'c' |
626 | && matchBuf[pos_buf[1]]=='d' | 694 | && matchBuf[pos_buf[1]] == 'd' |
627 | ) { | 695 | ) { |
628 | command_mode = FIND_DIR_ONLY; | 696 | command_mode = FIND_DIR_ONLY; |
629 | } else { | 697 | } else { |
@@ -657,11 +725,13 @@ static int find_match(char *matchBuf, int *len_with_quotes) | |||
657 | matchBuf[c++] = matchBuf[pos_buf[i]]; | 725 | matchBuf[c++] = matchBuf[pos_buf[i]]; |
658 | j = pos_buf[i] + 1; | 726 | j = pos_buf[i] + 1; |
659 | } | 727 | } |
660 | matchBuf[c] = 0; | 728 | matchBuf[c] = '\0'; |
661 | /* old length matchBuf with quotes symbols */ | 729 | /* old length matchBuf with quotes symbols */ |
662 | *len_with_quotes = j ? j - pos_buf[0] : 0; | 730 | *len_with_quotes = j ? j - pos_buf[0] : 0; |
663 | 731 | ||
664 | return command_mode; | 732 | return command_mode; |
733 | #undef int_buf | ||
734 | #undef pos_buf | ||
665 | } | 735 | } |
666 | 736 | ||
667 | /* | 737 | /* |
@@ -724,7 +794,7 @@ static int match_compare(const void *a, const void *b) | |||
724 | } | 794 | } |
725 | 795 | ||
726 | /* Do TAB completion */ | 796 | /* Do TAB completion */ |
727 | static void input_tab(int *lastWasTab) | 797 | static void input_tab(smallint *lastWasTab) |
728 | { | 798 | { |
729 | if (!(state->flags & TAB_COMPLETION)) | 799 | if (!(state->flags & TAB_COMPLETION)) |
730 | return; | 800 | return; |
@@ -732,7 +802,8 @@ static void input_tab(int *lastWasTab) | |||
732 | if (!*lastWasTab) { | 802 | if (!*lastWasTab) { |
733 | char *tmp, *tmp1; | 803 | char *tmp, *tmp1; |
734 | int len_found; | 804 | int len_found; |
735 | char matchBuf[MAX_LINELEN]; | 805 | /* char matchBuf[MAX_LINELEN]; */ |
806 | #define matchBuf (S.input_tab__matchBuf) | ||
736 | int find_type; | 807 | int find_type; |
737 | int recalc_pos; | 808 | int recalc_pos; |
738 | 809 | ||
@@ -782,7 +853,6 @@ static void input_tab(int *lastWasTab) | |||
782 | if (!matches) | 853 | if (!matches) |
783 | return; /* not found */ | 854 | return; /* not found */ |
784 | /* find minimal match */ | 855 | /* find minimal match */ |
785 | // ash: yet another failure in trying to achieve "we don't die on OOM" | ||
786 | tmp1 = xstrdup(matches[0]); | 856 | tmp1 = xstrdup(matches[0]); |
787 | for (tmp = tmp1; *tmp; tmp++) | 857 | for (tmp = tmp1; *tmp; tmp++) |
788 | for (len_found = 1; len_found < num_matches; len_found++) | 858 | for (len_found = 1; len_found < num_matches; len_found++) |
@@ -811,7 +881,7 @@ static void input_tab(int *lastWasTab) | |||
811 | /* have space to placed match? */ | 881 | /* have space to placed match? */ |
812 | if ((len_found - strlen(matchBuf) + command_len) < MAX_LINELEN) { | 882 | if ((len_found - strlen(matchBuf) + command_len) < MAX_LINELEN) { |
813 | /* before word for match */ | 883 | /* before word for match */ |
814 | command_ps[cursor - recalc_pos] = 0; | 884 | command_ps[cursor - recalc_pos] = '\0'; |
815 | /* save tail line */ | 885 | /* save tail line */ |
816 | strcpy(matchBuf, command_ps + cursor); | 886 | strcpy(matchBuf, command_ps + cursor); |
817 | /* add match */ | 887 | /* add match */ |
@@ -828,6 +898,7 @@ static void input_tab(int *lastWasTab) | |||
828 | redraw(cmdedit_y, command_len - recalc_pos); | 898 | redraw(cmdedit_y, command_len - recalc_pos); |
829 | } | 899 | } |
830 | free(tmp); | 900 | free(tmp); |
901 | #undef matchBuf | ||
831 | } else { | 902 | } else { |
832 | /* Ok -- the last char was a TAB. Since they | 903 | /* Ok -- the last char was a TAB. Since they |
833 | * just hit TAB again, print a list of all the | 904 | * just hit TAB again, print a list of all the |
@@ -843,8 +914,6 @@ static void input_tab(int *lastWasTab) | |||
843 | } | 914 | } |
844 | } | 915 | } |
845 | 916 | ||
846 | #else | ||
847 | #define input_tab(a) ((void)0) | ||
848 | #endif /* FEATURE_COMMAND_TAB_COMPLETION */ | 917 | #endif /* FEATURE_COMMAND_TAB_COMPLETION */ |
849 | 918 | ||
850 | 919 | ||
@@ -1079,14 +1148,14 @@ vi_back_motion(char *command) | |||
1079 | */ | 1148 | */ |
1080 | 1149 | ||
1081 | #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT | 1150 | #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT |
1082 | static void parse_prompt(const char *prmt_ptr) | 1151 | static void parse_and_put_prompt(const char *prmt_ptr) |
1083 | { | 1152 | { |
1084 | cmdedit_prompt = prmt_ptr; | 1153 | cmdedit_prompt = prmt_ptr; |
1085 | cmdedit_prmt_len = strlen(prmt_ptr); | 1154 | cmdedit_prmt_len = strlen(prmt_ptr); |
1086 | put_prompt(); | 1155 | put_prompt(); |
1087 | } | 1156 | } |
1088 | #else | 1157 | #else |
1089 | static void parse_prompt(const char *prmt_ptr) | 1158 | static void parse_and_put_prompt(const char *prmt_ptr) |
1090 | { | 1159 | { |
1091 | int prmt_len = 0; | 1160 | int prmt_len = 0; |
1092 | size_t cur_prmt_len = 0; | 1161 | size_t cur_prmt_len = 0; |
@@ -1114,7 +1183,7 @@ static void parse_prompt(const char *prmt_ptr) | |||
1114 | 1183 | ||
1115 | c = bb_process_escape_sequence(&prmt_ptr); | 1184 | c = bb_process_escape_sequence(&prmt_ptr); |
1116 | if (prmt_ptr == cp) { | 1185 | if (prmt_ptr == cp) { |
1117 | if (*cp == 0) | 1186 | if (*cp == '\0') |
1118 | break; | 1187 | break; |
1119 | c = *prmt_ptr++; | 1188 | c = *prmt_ptr++; |
1120 | switch (c) { | 1189 | switch (c) { |
@@ -1147,7 +1216,7 @@ static void parse_prompt(const char *prmt_ptr) | |||
1147 | if (l != 0 | 1216 | if (l != 0 |
1148 | && strncmp(home_pwd_buf, pbuf, l) == 0 | 1217 | && strncmp(home_pwd_buf, pbuf, l) == 0 |
1149 | && (pbuf[l]=='/' || pbuf[l]=='\0') | 1218 | && (pbuf[l]=='/' || pbuf[l]=='\0') |
1150 | && strlen(pwd_buf+l)<PATH_MAX | 1219 | && strlen(pwd_buf+l) < PATH_MAX |
1151 | ) { | 1220 | ) { |
1152 | pbuf = buf2; | 1221 | pbuf = buf2; |
1153 | *pbuf = '~'; | 1222 | *pbuf = '~'; |
@@ -1188,7 +1257,7 @@ static void parse_prompt(const char *prmt_ptr) | |||
1188 | break; | 1257 | break; |
1189 | case '[': case ']': | 1258 | case '[': case ']': |
1190 | if (c == flg_not_length) { | 1259 | if (c == flg_not_length) { |
1191 | flg_not_length = flg_not_length == '[' ? ']' : '['; | 1260 | flg_not_length = (flg_not_length == '[' ? ']' : '['); |
1192 | continue; | 1261 | continue; |
1193 | } | 1262 | } |
1194 | break; | 1263 | break; |
@@ -1210,11 +1279,6 @@ static void parse_prompt(const char *prmt_ptr) | |||
1210 | } | 1279 | } |
1211 | #endif | 1280 | #endif |
1212 | 1281 | ||
1213 | #define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp) | ||
1214 | #define getTermSettings(fd, argp) tcgetattr(fd, argp); | ||
1215 | |||
1216 | static sighandler_t previous_SIGWINCH_handler; | ||
1217 | |||
1218 | static void cmdedit_setwidth(unsigned w, int redraw_flg) | 1282 | static void cmdedit_setwidth(unsigned w, int redraw_flg) |
1219 | { | 1283 | { |
1220 | cmdedit_termw = w; | 1284 | cmdedit_termw = w; |
@@ -1261,7 +1325,9 @@ static void win_changed(int nsig) | |||
1261 | */ | 1325 | */ |
1262 | int read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st) | 1326 | int read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st) |
1263 | { | 1327 | { |
1264 | int lastWasTab = FALSE; | 1328 | #if ENABLE_FEATURE_TAB_COMPLETION |
1329 | smallint lastWasTab = FALSE; | ||
1330 | #endif | ||
1265 | unsigned int ic; | 1331 | unsigned int ic; |
1266 | unsigned char c; | 1332 | unsigned char c; |
1267 | smallint break_out = 0; | 1333 | smallint break_out = 0; |
@@ -1269,14 +1335,22 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1269 | smallint vi_cmdmode = 0; | 1335 | smallint vi_cmdmode = 0; |
1270 | smalluint prevc; | 1336 | smalluint prevc; |
1271 | #endif | 1337 | #endif |
1338 | struct termios initial_settings; | ||
1339 | struct termios new_settings; | ||
1272 | 1340 | ||
1273 | getTermSettings(0, (void *) &initial_settings); | 1341 | INIT_S(); |
1274 | /* Happens when e.g. stty -echo was run before */ | 1342 | |
1275 | if (!(initial_settings.c_lflag & ECHO)) { | 1343 | if (tcgetattr(STDIN_FILENO, &initial_settings) < 0 |
1276 | parse_prompt(prompt); | 1344 | || !(initial_settings.c_lflag & ECHO) |
1345 | ) { | ||
1346 | /* Happens when e.g. stty -echo was run before */ | ||
1347 | int len; | ||
1348 | parse_and_put_prompt(prompt); | ||
1277 | fflush(stdout); | 1349 | fflush(stdout); |
1278 | fgets(command, maxsize, stdin); | 1350 | fgets(command, maxsize, stdin); |
1279 | return strlen(command); | 1351 | len = strlen(command); |
1352 | DEINIT_S(); | ||
1353 | return len; | ||
1280 | } | 1354 | } |
1281 | 1355 | ||
1282 | // FIXME: audit & improve this | 1356 | // FIXME: audit & improve this |
@@ -1296,7 +1370,7 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1296 | command_ps = command; | 1370 | command_ps = command; |
1297 | command[0] = '\0'; | 1371 | command[0] = '\0'; |
1298 | 1372 | ||
1299 | memcpy(&new_settings, &initial_settings, sizeof(new_settings)); | 1373 | new_settings = initial_settings; |
1300 | new_settings.c_lflag &= ~ICANON; /* unbuffered input */ | 1374 | new_settings.c_lflag &= ~ICANON; /* unbuffered input */ |
1301 | /* Turn off echoing and CTRL-C, so we can trap it */ | 1375 | /* Turn off echoing and CTRL-C, so we can trap it */ |
1302 | new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); | 1376 | new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); |
@@ -1308,7 +1382,7 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1308 | #define _POSIX_VDISABLE '\0' | 1382 | #define _POSIX_VDISABLE '\0' |
1309 | #endif | 1383 | #endif |
1310 | new_settings.c_cc[VINTR] = _POSIX_VDISABLE; | 1384 | new_settings.c_cc[VINTR] = _POSIX_VDISABLE; |
1311 | setTermSettings(0, (void *) &new_settings); | 1385 | tcsetattr(STDIN_FILENO, TCSANOW, &new_settings); |
1312 | 1386 | ||
1313 | /* Now initialize things */ | 1387 | /* Now initialize things */ |
1314 | previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); | 1388 | previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); |
@@ -1319,11 +1393,6 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1319 | 1393 | ||
1320 | entry = getpwuid(geteuid()); | 1394 | entry = getpwuid(geteuid()); |
1321 | if (entry) { | 1395 | if (entry) { |
1322 | /* If we enter read_line_input for the Nth time, | ||
1323 | * they may be already allocated! Need to free. */ | ||
1324 | free(user_buf); | ||
1325 | if (home_pwd_buf != null_str) | ||
1326 | free(home_pwd_buf); | ||
1327 | user_buf = xstrdup(entry->pw_name); | 1396 | user_buf = xstrdup(entry->pw_name); |
1328 | home_pwd_buf = xstrdup(entry->pw_dir); | 1397 | home_pwd_buf = xstrdup(entry->pw_dir); |
1329 | /* They are not freed on exit (too small to bother) */ | 1398 | /* They are not freed on exit (too small to bother) */ |
@@ -1331,12 +1400,12 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1331 | } | 1400 | } |
1332 | #endif | 1401 | #endif |
1333 | /* Print out the command prompt */ | 1402 | /* Print out the command prompt */ |
1334 | parse_prompt(prompt); | 1403 | parse_and_put_prompt(prompt); |
1335 | 1404 | ||
1336 | while (1) { | 1405 | while (1) { |
1337 | fflush(stdout); | 1406 | fflush(stdout); |
1338 | 1407 | ||
1339 | if (safe_read(0, &c, 1) < 1) { | 1408 | if (safe_read(STDIN_FILENO, &c, 1) < 1) { |
1340 | /* if we can't read input then exit */ | 1409 | /* if we can't read input then exit */ |
1341 | goto prepare_to_die; | 1410 | goto prepare_to_die; |
1342 | } | 1411 | } |
@@ -1411,9 +1480,11 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1411 | input_backspace(); | 1480 | input_backspace(); |
1412 | break; | 1481 | break; |
1413 | 1482 | ||
1483 | #if ENABLE_FEATURE_TAB_COMPLETION | ||
1414 | case '\t': | 1484 | case '\t': |
1415 | input_tab(&lastWasTab); | 1485 | input_tab(&lastWasTab); |
1416 | break; | 1486 | break; |
1487 | #endif | ||
1417 | 1488 | ||
1418 | #if ENABLE_FEATURE_EDITING_FANCY_KEYS | 1489 | #if ENABLE_FEATURE_EDITING_FANCY_KEYS |
1419 | case CTRL('K'): | 1490 | case CTRL('K'): |
@@ -1526,7 +1597,7 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1526 | int nc, sc; | 1597 | int nc, sc; |
1527 | sc = cursor; | 1598 | sc = cursor; |
1528 | prevc = ic; | 1599 | prevc = ic; |
1529 | if (safe_read(0, &c, 1) < 1) | 1600 | if (safe_read(STDIN_FILENO, &c, 1) < 1) |
1530 | goto prepare_to_die; | 1601 | goto prepare_to_die; |
1531 | if (c == (prevc & 0xff)) { | 1602 | if (c == (prevc & 0xff)) { |
1532 | /* "cc", "dd" */ | 1603 | /* "cc", "dd" */ |
@@ -1587,7 +1658,7 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1587 | put(); | 1658 | put(); |
1588 | break; | 1659 | break; |
1589 | case 'r'|vbit: | 1660 | case 'r'|vbit: |
1590 | if (safe_read(0, &c, 1) < 1) | 1661 | if (safe_read(STDIN_FILENO, &c, 1) < 1) |
1591 | goto prepare_to_die; | 1662 | goto prepare_to_die; |
1592 | if (c == 0) | 1663 | if (c == 0) |
1593 | beep(); | 1664 | beep(); |
@@ -1610,19 +1681,19 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1610 | } | 1681 | } |
1611 | #endif | 1682 | #endif |
1612 | /* escape sequence follows */ | 1683 | /* escape sequence follows */ |
1613 | if (safe_read(0, &c, 1) < 1) | 1684 | if (safe_read(STDIN_FILENO, &c, 1) < 1) |
1614 | goto prepare_to_die; | 1685 | goto prepare_to_die; |
1615 | /* different vt100 emulations */ | 1686 | /* different vt100 emulations */ |
1616 | if (c == '[' || c == 'O') { | 1687 | if (c == '[' || c == 'O') { |
1617 | vi_case('['|vbit:) | 1688 | vi_case('['|vbit:) |
1618 | vi_case('O'|vbit:) | 1689 | vi_case('O'|vbit:) |
1619 | if (safe_read(0, &c, 1) < 1) | 1690 | if (safe_read(STDIN_FILENO, &c, 1) < 1) |
1620 | goto prepare_to_die; | 1691 | goto prepare_to_die; |
1621 | } | 1692 | } |
1622 | if (c >= '1' && c <= '9') { | 1693 | if (c >= '1' && c <= '9') { |
1623 | unsigned char dummy; | 1694 | unsigned char dummy; |
1624 | 1695 | ||
1625 | if (safe_read(0, &dummy, 1) < 1) | 1696 | if (safe_read(STDIN_FILENO, &dummy, 1) < 1) |
1626 | goto prepare_to_die; | 1697 | goto prepare_to_die; |
1627 | if (dummy != '~') | 1698 | if (dummy != '~') |
1628 | c = '\0'; | 1699 | c = '\0'; |
@@ -1687,7 +1758,7 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1687 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT | 1758 | #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT |
1688 | /* Control-V -- Add non-printable symbol */ | 1759 | /* Control-V -- Add non-printable symbol */ |
1689 | if (c == CTRL('V')) { | 1760 | if (c == CTRL('V')) { |
1690 | if (safe_read(0, &c, 1) < 1) | 1761 | if (safe_read(STDIN_FILENO, &c, 1) < 1) |
1691 | goto prepare_to_die; | 1762 | goto prepare_to_die; |
1692 | if (c == 0) { | 1763 | if (c == 0) { |
1693 | beep(); | 1764 | beep(); |
@@ -1727,8 +1798,10 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1727 | if (break_out) /* Enter is the command terminator, no more input. */ | 1798 | if (break_out) /* Enter is the command terminator, no more input. */ |
1728 | break; | 1799 | break; |
1729 | 1800 | ||
1801 | #if ENABLE_FEATURE_TAB_COMPLETION | ||
1730 | if (c != '\t') | 1802 | if (c != '\t') |
1731 | lastWasTab = FALSE; | 1803 | lastWasTab = FALSE; |
1804 | #endif | ||
1732 | } | 1805 | } |
1733 | 1806 | ||
1734 | if (command_len > 0) | 1807 | if (command_len > 0) |
@@ -1739,18 +1812,18 @@ int read_line_input(const char *prompt, char *command, int maxsize, line_input_t | |||
1739 | command[command_len] = '\0'; | 1812 | command[command_len] = '\0'; |
1740 | } | 1813 | } |
1741 | 1814 | ||
1742 | #if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_TAB_COMPLETION | 1815 | #if ENABLE_FEATURE_TAB_COMPLETION |
1743 | free_tab_completion_data(); | 1816 | free_tab_completion_data(); |
1744 | #endif | 1817 | #endif |
1745 | 1818 | ||
1746 | #if ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
1747 | free((char*)cmdedit_prompt); | ||
1748 | #endif | ||
1749 | /* restore initial_settings */ | 1819 | /* restore initial_settings */ |
1750 | setTermSettings(STDIN_FILENO, (void *) &initial_settings); | 1820 | tcsetattr(STDIN_FILENO, TCSANOW, &initial_settings); |
1751 | /* restore SIGWINCH handler */ | 1821 | /* restore SIGWINCH handler */ |
1752 | signal(SIGWINCH, previous_SIGWINCH_handler); | 1822 | signal(SIGWINCH, previous_SIGWINCH_handler); |
1753 | fflush(stdout); | 1823 | fflush(stdout); |
1824 | |||
1825 | DEINIT_S(); | ||
1826 | |||
1754 | return command_len; | 1827 | return command_len; |
1755 | } | 1828 | } |
1756 | 1829 | ||