summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-01-21 19:19:46 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-01-21 19:19:46 +0000
commit5592fac30812f3ca908961cd75a08a009baa7bb6 (patch)
treef9d2ab7fcb1188d0e0d387914ab025afcee2c433
parent47bdb3ac482e8ccfa073b1c17fdf52d3721952b6 (diff)
downloadbusybox-w32-5592fac30812f3ca908961cd75a08a009baa7bb6.tar.gz
busybox-w32-5592fac30812f3ca908961cd75a08a009baa7bb6.tar.bz2
busybox-w32-5592fac30812f3ca908961cd75a08a009baa7bb6.zip
cmdedit: more optimizations
-rw-r--r--shell/cmdedit.c246
1 files changed, 109 insertions, 137 deletions
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
index 1143ded77..39cab19a0 100644
--- a/shell/cmdedit.c
+++ b/shell/cmdedit.c
@@ -119,14 +119,6 @@ static struct termios initial_settings, new_settings;
119 119
120static 120static
121volatile unsigned cmdedit_termw = 80; /* actual terminal width */ 121volatile unsigned cmdedit_termw = 80; /* actual terminal width */
122static
123volatile int handlers_sets = 0; /* Set next bits: */
124enum {
125 SET_ATEXIT = 1, /* when atexit() has been called
126 and get euid,uid,gid to fast compare */
127 SET_WCHG_HANDLERS = 2, /* winchg signal handler */
128 SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */
129};
130 122
131 123
132static int cmdedit_x; /* real x terminal position */ 124static int cmdedit_x; /* real x terminal position */
@@ -148,10 +140,6 @@ static char *user_buf = "";
148static char *home_pwd_buf = ""; 140static char *home_pwd_buf = "";
149#endif 141#endif
150 142
151#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR || ENABLE_FEATURE_COMMAND_TAB_COMPLETION
152static int my_euid;
153#endif
154
155#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION 143#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
156static int my_uid; 144static int my_uid;
157static int my_gid; 145static int my_gid;
@@ -339,7 +327,6 @@ static void input_backspace(void)
339 } 327 }
340} 328}
341 329
342
343/* Move forward one character */ 330/* Move forward one character */
344static void input_forward(void) 331static void input_forward(void)
345{ 332{
@@ -347,10 +334,21 @@ static void input_forward(void)
347 cmdedit_set_out_char(command_ps[cursor + 1]); 334 cmdedit_set_out_char(command_ps[cursor + 1]);
348} 335}
349 336
337
350#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION 338#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
351 339
352static char **matches; 340static char **matches;
353static int num_matches; 341static unsigned num_matches;
342
343static void free_tab_completion_data(void)
344{
345 if (matches) {
346 while (num_matches)
347 free(matches[--num_matches]);
348 free(matches);
349 matches = NULL;
350 }
351}
354 352
355static void add_match(char *matched) 353static void add_match(char *matched)
356{ 354{
@@ -363,7 +361,6 @@ static void add_match(char *matched)
363} 361}
364 362
365#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION 363#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
366
367static void username_tab_completion(char *ud, char *with_shash_flg) 364static void username_tab_completion(char *ud, char *with_shash_flg)
368{ 365{
369 struct passwd *entry; 366 struct passwd *entry;
@@ -504,7 +501,6 @@ static void exe_n_cwd_tab_completion(char *command, int type)
504 } 501 }
505 502
506 for (i = 0; i < npaths; i++) { 503 for (i = 0; i < npaths; i++) {
507
508 dir = opendir(paths[i]); 504 dir = opendir(paths[i]);
509 if (!dir) /* Don't print an error */ 505 if (!dir) /* Don't print an error */
510 continue; 506 continue;
@@ -559,7 +555,6 @@ static void exe_n_cwd_tab_completion(char *command, int type)
559 } 555 }
560} 556}
561 557
562
563#define QUOT (UCHAR_MAX+1) 558#define QUOT (UCHAR_MAX+1)
564 559
565#define collapse_pos(is, in) { \ 560#define collapse_pos(is, in) { \
@@ -580,8 +575,8 @@ static int find_match(char *matchBuf, int *len_with_quotes)
580 if (int_buf[i] == 0) { 575 if (int_buf[i] == 0) {
581 pos_buf[i] = -1; /* indicator end line */ 576 pos_buf[i] = -1; /* indicator end line */
582 break; 577 break;
583 } else 578 }
584 pos_buf[i] = i; 579 pos_buf[i] = i;
585 } 580 }
586 581
587 /* mask \+symbol and convert '\t' to ' ' */ 582 /* mask \+symbol and convert '\t' to ' ' */
@@ -731,9 +726,9 @@ static int find_match(char *matchBuf, int *len_with_quotes)
731} 726}
732 727
733/* 728/*
734 display by column original ideas from ls applet, 729 * display by column (original idea from ls applet,
735 very optimize by my :) 730 * very optimized by me :)
736*/ 731 */
737static void showfiles(void) 732static void showfiles(void)
738{ 733{
739 int ncols, row; 734 int ncols, row;
@@ -770,11 +765,6 @@ static void showfiles(void)
770 } 765 }
771} 766}
772 767
773static int match_compare(const void *a, const void *b)
774{
775 return strcmp(*(char**)a, *(char**)b);
776}
777
778static char *add_quote_for_spec_chars(char *found) 768static char *add_quote_for_spec_chars(char *found)
779{ 769{
780 int l = 0; 770 int l = 0;
@@ -789,18 +779,14 @@ static char *add_quote_for_spec_chars(char *found)
789 return s; 779 return s;
790} 780}
791 781
782static int match_compare(const void *a, const void *b)
783{
784 return strcmp(*(char**)a, *(char**)b);
785}
786
787/* Do TAB completion */
792static void input_tab(int *lastWasTab) 788static void input_tab(int *lastWasTab)
793{ 789{
794 /* Do TAB completion */
795 if (lastWasTab == 0) { /* free all memory */
796 if (matches) {
797 while (num_matches > 0)
798 free(matches[--num_matches]);
799 free(matches);
800 matches = (char **) NULL;
801 }
802 return;
803 }
804 if (!*lastWasTab) { 790 if (!*lastWasTab) {
805 char *tmp, *tmp1; 791 char *tmp, *tmp1;
806 int len_found; 792 int len_found;
@@ -813,12 +799,12 @@ static void input_tab(int *lastWasTab)
813 /* Make a local copy of the string -- up 799 /* Make a local copy of the string -- up
814 * to the position of the cursor */ 800 * to the position of the cursor */
815 tmp = strncpy(matchBuf, command_ps, cursor); 801 tmp = strncpy(matchBuf, command_ps, cursor);
816 tmp[cursor] = 0; 802 tmp[cursor] = '\0';
817 803
818 find_type = find_match(matchBuf, &recalc_pos); 804 find_type = find_match(matchBuf, &recalc_pos);
819 805
820 /* Free up any memory already allocated */ 806 /* Free up any memory already allocated */
821 input_tab(0); 807 free_tab_completion_data();
822 808
823#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION 809#if ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION
824 /* If the word starts with `~' and there is no slash in the word, 810 /* If the word starts with `~' and there is no slash in the word,
@@ -829,24 +815,24 @@ static void input_tab(int *lastWasTab)
829 if (!matches) 815 if (!matches)
830#endif 816#endif
831 /* Try to match any executable in our path and everything 817 /* Try to match any executable in our path and everything
832 * in the current working directory that matches. */ 818 * in the current working directory */
833 exe_n_cwd_tab_completion(matchBuf, find_type); 819 exe_n_cwd_tab_completion(matchBuf, find_type);
834 /* Sort, then remove any duplicates found */ 820 /* Sort, then remove any duplicates found */
835 if (matches) { 821 if (matches) {
836 int i, n = 0; 822 int i, n = 0;
837 qsort(matches, num_matches, sizeof(char*), match_compare); 823 qsort(matches, num_matches, sizeof(char*), match_compare);
838 for (i = 0; i < num_matches - 1; ++i) { 824 for (i = 0; i < num_matches - 1; ++i) {
839 if (matches[i] && matches[i+1]) { 825 if (matches[i] && matches[i+1]) { /* paranoia */
840 if (strcmp(matches[i], matches[i+1]) == 0) { 826 if (strcmp(matches[i], matches[i+1]) == 0) {
841 free(matches[i]); 827 free(matches[i]);
842 matches[i] = 0; 828 matches[i] = NULL; /* paranoia */
843 } else { 829 } else {
844 matches[n++] = matches[i]; 830 matches[n++] = matches[i];
845 } 831 }
846 } 832 }
847 } 833 }
848 matches[n++] = matches[num_matches-1]; 834 matches[n] = matches[i];
849 num_matches = n; 835 num_matches = n + 1;
850 } 836 }
851 /* Did we find exactly one match? */ 837 /* Did we find exactly one match? */
852 if (!matches || num_matches > 1) { 838 if (!matches || num_matches > 1) {
@@ -858,10 +844,10 @@ static void input_tab(int *lastWasTab)
858 for (tmp = tmp1; *tmp; tmp++) 844 for (tmp = tmp1; *tmp; tmp++)
859 for (len_found = 1; len_found < num_matches; len_found++) 845 for (len_found = 1; len_found < num_matches; len_found++)
860 if (matches[len_found][(tmp - tmp1)] != *tmp) { 846 if (matches[len_found][(tmp - tmp1)] != *tmp) {
861 *tmp = 0; 847 *tmp = '\0';
862 break; 848 break;
863 } 849 }
864 if (*tmp1 == 0) { /* have unique */ 850 if (*tmp1 == '\0') { /* have unique */
865 free(tmp1); 851 free(tmp1);
866 return; 852 return;
867 } 853 }
@@ -881,7 +867,6 @@ static void input_tab(int *lastWasTab)
881 len_found = strlen(tmp); 867 len_found = strlen(tmp);
882 /* have space to placed match? */ 868 /* have space to placed match? */
883 if ((len_found - strlen(matchBuf) + len) < BUFSIZ) { 869 if ((len_found - strlen(matchBuf) + len) < BUFSIZ) {
884
885 /* before word for match */ 870 /* before word for match */
886 command_ps[cursor - recalc_pos] = 0; 871 command_ps[cursor - recalc_pos] = 0;
887 /* save tail line */ 872 /* save tail line */
@@ -914,6 +899,7 @@ static void input_tab(int *lastWasTab)
914 } 899 }
915 } 900 }
916} 901}
902
917#endif /* FEATURE_COMMAND_TAB_COMPLETION */ 903#endif /* FEATURE_COMMAND_TAB_COMPLETION */
918 904
919 905
@@ -927,7 +913,7 @@ static int cur_history;
927 913
928static void get_previous_history(void) 914static void get_previous_history(void)
929{ 915{
930 if (command_ps[0] != 0 || history[cur_history] == 0) { 916 if (command_ps[0] != '\0' || history[cur_history] == NULL) {
931 free(history[cur_history]); 917 free(history[cur_history]);
932 history[cur_history] = xstrdup(command_ps); 918 history[cur_history] = xstrdup(command_ps);
933 } 919 }
@@ -1126,81 +1112,6 @@ enum { vi_mode = 0 };
1126 * cmdedit_read_input and its helpers 1112 * cmdedit_read_input and its helpers
1127 */ 1113 */
1128 1114
1129#define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp)
1130#define getTermSettings(fd, argp) tcgetattr(fd, argp);
1131
1132static sighandler_t previous_SIGWINCH_handler;
1133
1134static void cmdedit_reset_term(void)
1135{
1136 if (handlers_sets & SET_RESET_TERM) {
1137 setTermSettings(STDIN_FILENO, (void *) &initial_settings);
1138 handlers_sets &= ~SET_RESET_TERM;
1139 }
1140 if (handlers_sets & SET_WCHG_HANDLERS) {
1141 /* restore SIGWINCH handler */
1142 signal(SIGWINCH, previous_SIGWINCH_handler);
1143 handlers_sets &= ~SET_WCHG_HANDLERS;
1144 }
1145 fflush(stdout);
1146}
1147
1148static void cmdedit_setwidth(unsigned w, int redraw_flg)
1149{
1150 cmdedit_termw = w;
1151 if (redraw_flg) {
1152 /* new y for current cursor */
1153 int new_y = (cursor + cmdedit_prmt_len) / w;
1154 /* redraw */
1155 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
1156 fflush(stdout);
1157 }
1158}
1159
1160static void win_changed(int nsig)
1161{
1162 int width;
1163 get_terminal_width_height(0, &width, NULL);
1164 cmdedit_setwidth(width, nsig /* - just a yes/no flag */);
1165 if (nsig == SIGWINCH)
1166 signal(SIGWINCH, win_changed); /* rearm ourself */
1167}
1168
1169static void cmdedit_init(void)
1170{
1171 cmdedit_prmt_len = 0;
1172 if (!(handlers_sets & SET_WCHG_HANDLERS)) {
1173 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
1174 win_changed(0); /* do initial resizing */
1175 handlers_sets |= SET_WCHG_HANDLERS;
1176 }
1177
1178 if (!(handlers_sets & SET_ATEXIT)) {
1179#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1180 struct passwd *entry;
1181
1182 my_euid = geteuid();
1183 entry = getpwuid(my_euid);
1184 if (entry) {
1185 user_buf = xstrdup(entry->pw_name);
1186 home_pwd_buf = xstrdup(entry->pw_dir);
1187 }
1188#endif
1189
1190#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
1191
1192#if !ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1193 my_euid = geteuid();
1194#endif
1195 my_uid = getuid();
1196 my_gid = getgid();
1197#endif /* FEATURE_COMMAND_TAB_COMPLETION */
1198 handlers_sets |= SET_ATEXIT;
1199// Crap. We should be able to do it without atexit.
1200 atexit(cmdedit_reset_term); /* be sure to do this only once */
1201 }
1202}
1203
1204#if !ENABLE_FEATURE_SH_FANCY_PROMPT 1115#if !ENABLE_FEATURE_SH_FANCY_PROMPT
1205static void parse_prompt(const char *prmt_ptr) 1116static void parse_prompt(const char *prmt_ptr)
1206{ 1117{
@@ -1259,7 +1170,7 @@ static void parse_prompt(const char *prmt_ptr)
1259 } 1170 }
1260 break; 1171 break;
1261 case '$': 1172 case '$':
1262 c = (my_euid == 0 ? '#' : '$'); 1173 c = (geteuid() == 0 ? '#' : '$');
1263 break; 1174 break;
1264#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR 1175#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1265 case 'w': 1176 case 'w':
@@ -1283,7 +1194,8 @@ static void parse_prompt(const char *prmt_ptr)
1283 pbuf += (cp-pbuf) + 1; 1194 pbuf += (cp-pbuf) + 1;
1284 break; 1195 break;
1285 case '!': 1196 case '!':
1286 snprintf(pbuf = buf2, sizeof(buf2), "%d", num_ok_lines); 1197 pbuf = buf2;
1198 snprintf(buf2, sizeof(buf2), "%d", num_ok_lines);
1287 break; 1199 break;
1288 case 'e': case 'E': /* \e \E = \033 */ 1200 case 'e': case 'E': /* \e \E = \033 */
1289 c = '\033'; 1201 c = '\033';
@@ -1330,11 +1242,71 @@ static void parse_prompt(const char *prmt_ptr)
1330} 1242}
1331#endif 1243#endif
1332 1244
1245#define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp)
1246#define getTermSettings(fd, argp) tcgetattr(fd, argp);
1247
1248static sighandler_t previous_SIGWINCH_handler;
1249
1250static void cmdedit_reset_term(void)
1251{
1252 setTermSettings(STDIN_FILENO, (void *) &initial_settings);
1253 /* restore SIGWINCH handler */
1254 signal(SIGWINCH, previous_SIGWINCH_handler);
1255 fflush(stdout);
1256}
1257
1258static void cmdedit_setwidth(unsigned w, int redraw_flg)
1259{
1260 cmdedit_termw = w;
1261 if (redraw_flg) {
1262 /* new y for current cursor */
1263 int new_y = (cursor + cmdedit_prmt_len) / w;
1264 /* redraw */
1265 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor);
1266 fflush(stdout);
1267 }
1268}
1269
1270static void win_changed(int nsig)
1271{
1272 int width;
1273 get_terminal_width_height(0, &width, NULL);
1274 cmdedit_setwidth(width, nsig /* - just a yes/no flag */);
1275 if (nsig == SIGWINCH)
1276 signal(SIGWINCH, win_changed); /* rearm ourself */
1277}
1278
1279static void cmdedit_init(void)
1280{
1281 cmdedit_prmt_len = 0;
1282 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
1283 win_changed(0); /* do initial resizing */
1284
1285#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
1286 {
1287 struct passwd *entry;
1288
1289 entry = getpwuid(geteuid());
1290 if (entry) {
1291 user_buf = xstrdup(entry->pw_name);
1292 home_pwd_buf = xstrdup(entry->pw_dir);
1293 }
1294 }
1295#endif
1296
1297#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION
1298 my_uid = getuid();
1299 my_gid = getgid();
1300#endif
1301// Crap. We should be able to do it without atexit.
1302 atexit(cmdedit_reset_term); /* be sure to do this only once */
1303}
1304
1333/* 1305/*
1334 * the emacs and vi modes share much of the code in the big 1306 * The emacs and vi modes share much of the code in the big
1335 * command loop. commands entered when in vi's command mode (aka 1307 * command loop. Commands entered when in vi's command mode (aka
1336 * "escape mode") get an extra bit added to distinguish them -- 1308 * "escape mode") get an extra bit added to distinguish them --
1337 * this keeps them from being self-inserted. this clutters the 1309 * this keeps them from being self-inserted. This clutters the
1338 * big switch a bit, but keeps all the code in one place. 1310 * big switch a bit, but keeps all the code in one place.
1339 */ 1311 */
1340 1312
@@ -1379,7 +1351,6 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1379#endif 1351#endif
1380 new_settings.c_cc[VINTR] = _POSIX_VDISABLE; 1352 new_settings.c_cc[VINTR] = _POSIX_VDISABLE;
1381 setTermSettings(0, (void *) &new_settings); 1353 setTermSettings(0, (void *) &new_settings);
1382 handlers_sets |= SET_RESET_TERM;
1383 1354
1384 /* Now initialize things */ 1355 /* Now initialize things */
1385 cmdedit_init(); 1356 cmdedit_init();
@@ -1387,11 +1358,12 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1387 parse_prompt(prompt); 1358 parse_prompt(prompt);
1388 1359
1389 while (1) { 1360 while (1) {
1390 fflush(stdout); /* buffered out to fast */ 1361 fflush(stdout);
1391 1362
1392 if (safe_read(0, &c, 1) < 1) 1363 if (safe_read(0, &c, 1) < 1) {
1393 /* if we can't read input then exit */ 1364 /* if we can't read input then exit */
1394 goto prepare_to_die; 1365 goto prepare_to_die;
1366 }
1395 1367
1396 ic = c; 1368 ic = c;
1397 1369
@@ -1789,23 +1761,22 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1789 lastWasTab = FALSE; 1761 lastWasTab = FALSE;
1790 } 1762 }
1791 1763
1792 setTermSettings(0, (void *) &initial_settings);
1793 handlers_sets &= ~SET_RESET_TERM;
1794
1795#if MAX_HISTORY > 0 1764#if MAX_HISTORY > 0
1796 /* Handle command history log */ 1765 /* Handle command history log */
1797 /* cleanup may be saved current command line */ 1766 /* cleanup may be saved current command line */
1798 if (len > 0) { /* no put empty line */ 1767 if (len > 0) {
1799 int i = n_history; 1768 int i = n_history;
1800 1769
1801 free(history[MAX_HISTORY]); 1770 free(history[MAX_HISTORY]);
1802 history[MAX_HISTORY] = 0; 1771 history[MAX_HISTORY] = NULL;
1803 /* After max history, remove the oldest command */ 1772 /* After max history, remove the oldest command */
1804 if (i >= MAX_HISTORY) { 1773 if (i >= MAX_HISTORY) {
1805 free(history[0]); 1774 free(history[0]);
1806 for (i = 0; i < MAX_HISTORY-1; i++) 1775 for (i = 0; i < MAX_HISTORY-1; i++)
1807 history[i] = history[i+1]; 1776 history[i] = history[i+1];
1808 } 1777 }
1778// Maybe "if (!i || strcmp(history[i-1], command) != 0) ..."
1779// (i.e. do not save dups?)
1809 history[i++] = xstrdup(command); 1780 history[i++] = xstrdup(command);
1810 cur_history = i; 1781 cur_history = i;
1811 n_history = i; 1782 n_history = i;
@@ -1822,12 +1793,13 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ])
1822 } 1793 }
1823 1794
1824#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION 1795#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION
1825 input_tab(0); 1796 free_tab_completion_data();
1826#endif 1797#endif
1827 1798
1828#if ENABLE_FEATURE_SH_FANCY_PROMPT 1799#if ENABLE_FEATURE_SH_FANCY_PROMPT
1829 free(cmdedit_prompt); 1800 free(cmdedit_prompt);
1830#endif 1801#endif
1802 /* restore initial_settings and SIGWINCH handler */
1831 cmdedit_reset_term(); 1803 cmdedit_reset_term();
1832 return len; 1804 return len;
1833} 1805}