diff options
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/cmdedit.c | 162 |
1 files changed, 62 insertions, 100 deletions
diff --git a/shell/cmdedit.c b/shell/cmdedit.c index eee32131a..b6e743eb4 100644 --- a/shell/cmdedit.c +++ b/shell/cmdedit.c | |||
| @@ -89,22 +89,17 @@ | |||
| 89 | #endif /* advanced FEATURES */ | 89 | #endif /* advanced FEATURES */ |
| 90 | 90 | ||
| 91 | 91 | ||
| 92 | |||
| 93 | struct history { | ||
| 94 | char *s; | ||
| 95 | struct history *p; | ||
| 96 | struct history *n; | ||
| 97 | }; | ||
| 98 | |||
| 99 | /* Maximum length of the linked list for the command line history */ | 92 | /* Maximum length of the linked list for the command line history */ |
| 100 | static const int MAX_HISTORY = 15; | 93 | #define MAX_HISTORY 15 |
| 101 | 94 | #if MAX_HISTORY < 1 | |
| 102 | /* First element in command line list */ | 95 | #warning cmdedit: You set MAX_HISTORY < 1. The history algorithm switched off. |
| 103 | static struct history *his_front = NULL; | 96 | #else |
| 104 | 97 | static char *history[MAX_HISTORY+1]; /* history + current */ | |
| 105 | /* Last element in command line list */ | 98 | /* saved history lines */ |
| 106 | static struct history *his_end = NULL; | 99 | static int n_history; |
| 107 | 100 | /* current pointer to history line */ | |
| 101 | static int cur_history; | ||
| 102 | #endif | ||
| 108 | 103 | ||
| 109 | #include <termios.h> | 104 | #include <termios.h> |
| 110 | #define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) | 105 | #define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) |
| @@ -116,7 +111,6 @@ static struct termios initial_settings, new_settings; | |||
| 116 | 111 | ||
| 117 | static | 112 | static |
| 118 | volatile int cmdedit_termw = 80; /* actual terminal width */ | 113 | volatile int cmdedit_termw = 80; /* actual terminal width */ |
| 119 | static int history_counter = 0; /* Number of commands in history list */ | ||
| 120 | static | 114 | static |
| 121 | volatile int handlers_sets = 0; /* Set next bites: */ | 115 | volatile int handlers_sets = 0; /* Set next bites: */ |
| 122 | 116 | ||
| @@ -148,7 +142,7 @@ static int my_euid; | |||
| 148 | #endif | 142 | #endif |
| 149 | 143 | ||
| 150 | #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT | 144 | #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT |
| 151 | static char *hostname_buf = ""; | 145 | static char *hostname_buf; |
| 152 | static int num_ok_lines = 1; | 146 | static int num_ok_lines = 1; |
| 153 | #endif | 147 | #endif |
| 154 | 148 | ||
| @@ -207,19 +201,6 @@ static void cmdedit_reset_term(void) | |||
| 207 | handlers_sets &= ~SET_WCHG_HANDLERS; | 201 | handlers_sets &= ~SET_WCHG_HANDLERS; |
| 208 | } | 202 | } |
| 209 | fflush(stdout); | 203 | fflush(stdout); |
| 210 | #if 0 | ||
| 211 | //#ifdef CONFIG_FEATURE_CLEAN_UP | ||
| 212 | if (his_front) { | ||
| 213 | struct history *n; | ||
| 214 | |||
| 215 | while (his_front != his_end) { | ||
| 216 | n = his_front->n; | ||
| 217 | free(his_front->s); | ||
| 218 | free(his_front); | ||
| 219 | his_front = n; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | #endif | ||
| 223 | } | 204 | } |
| 224 | 205 | ||
| 225 | 206 | ||
| @@ -368,7 +349,7 @@ static void parse_prompt(const char *prmt_ptr) | |||
| 368 | #endif | 349 | #endif |
| 369 | case 'h': | 350 | case 'h': |
| 370 | pbuf = hostname_buf; | 351 | pbuf = hostname_buf; |
| 371 | if (*pbuf == 0) { | 352 | if (pbuf == 0) { |
| 372 | pbuf = xcalloc(256, 1); | 353 | pbuf = xcalloc(256, 1); |
| 373 | if (gethostname(pbuf, 255) < 0) { | 354 | if (gethostname(pbuf, 255) < 0) { |
| 374 | strcpy(pbuf, "?"); | 355 | strcpy(pbuf, "?"); |
| @@ -1122,18 +1103,29 @@ static void input_tab(int *lastWasTab) | |||
| 1122 | } | 1103 | } |
| 1123 | #endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */ | 1104 | #endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */ |
| 1124 | 1105 | ||
| 1125 | static void get_previous_history(struct history **hp, struct history *p) | 1106 | #if MAX_HISTORY >= 1 |
| 1107 | static void get_previous_history(void) | ||
| 1126 | { | 1108 | { |
| 1127 | if ((*hp)->s) | 1109 | if(command_ps[0] != 0 || history[cur_history] == 0) { |
| 1128 | free((*hp)->s); | 1110 | free(history[cur_history]); |
| 1129 | (*hp)->s = xstrdup(command_ps); | 1111 | history[cur_history] = xstrdup(command_ps); |
| 1130 | *hp = p; | 1112 | } |
| 1113 | cur_history--; | ||
| 1131 | } | 1114 | } |
| 1132 | 1115 | ||
| 1133 | static inline void get_next_history(struct history **hp) | 1116 | static int get_next_history(void) |
| 1134 | { | 1117 | { |
| 1135 | get_previous_history(hp, (*hp)->n); | 1118 | int ch = cur_history; |
| 1119 | |||
| 1120 | if (ch < n_history) { | ||
| 1121 | get_previous_history(); /* save the current history line */ | ||
| 1122 | return (cur_history = ch+1); | ||
| 1123 | } else { | ||
| 1124 | beep(); | ||
| 1125 | return 0; | ||
| 1126 | } | ||
| 1136 | } | 1127 | } |
| 1128 | #endif | ||
| 1137 | 1129 | ||
| 1138 | enum { | 1130 | enum { |
| 1139 | ESC = 27, | 1131 | ESC = 27, |
| @@ -1165,7 +1157,6 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) | |||
| 1165 | int break_out = 0; | 1157 | int break_out = 0; |
| 1166 | int lastWasTab = FALSE; | 1158 | int lastWasTab = FALSE; |
| 1167 | unsigned char c = 0; | 1159 | unsigned char c = 0; |
| 1168 | struct history *hp = his_end; | ||
| 1169 | 1160 | ||
| 1170 | /* prepare before init handlers */ | 1161 | /* prepare before init handlers */ |
| 1171 | cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ | 1162 | cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ |
| @@ -1271,31 +1262,26 @@ prepare_to_die: | |||
| 1271 | printf("\033[J"); | 1262 | printf("\033[J"); |
| 1272 | break; | 1263 | break; |
| 1273 | case 12: | 1264 | case 12: |
| 1274 | { | ||
| 1275 | /* Control-l -- clear screen */ | 1265 | /* Control-l -- clear screen */ |
| 1276 | int old_cursor = cursor; | ||
| 1277 | printf("\033[H"); | 1266 | printf("\033[H"); |
| 1278 | redraw(0, len-old_cursor); | 1267 | redraw(0, len-cursor); |
| 1279 | } | ||
| 1280 | break; | 1268 | break; |
| 1269 | #if MAX_HISTORY >= 1 | ||
| 1281 | case 14: | 1270 | case 14: |
| 1282 | /* Control-n -- Get next command in history */ | 1271 | /* Control-n -- Get next command in history */ |
| 1283 | if (hp && hp->n && hp->n->s) { | 1272 | if (get_next_history()) |
| 1284 | get_next_history(&hp); | ||
| 1285 | goto rewrite_line; | 1273 | goto rewrite_line; |
| 1286 | } else { | ||
| 1287 | beep(); | ||
| 1288 | } | ||
| 1289 | break; | 1274 | break; |
| 1290 | case 16: | 1275 | case 16: |
| 1291 | /* Control-p -- Get previous command from history */ | 1276 | /* Control-p -- Get previous command from history */ |
| 1292 | if (hp && hp->p) { | 1277 | if (cur_history > 0) { |
| 1293 | get_previous_history(&hp, hp->p); | 1278 | get_previous_history(); |
| 1294 | goto rewrite_line; | 1279 | goto rewrite_line; |
| 1295 | } else { | 1280 | } else { |
| 1296 | beep(); | 1281 | beep(); |
| 1297 | } | 1282 | } |
| 1298 | break; | 1283 | break; |
| 1284 | #endif | ||
| 1299 | case 21: | 1285 | case 21: |
| 1300 | /* Control-U -- Clear line before cursor */ | 1286 | /* Control-U -- Clear line before cursor */ |
| 1301 | if (cursor) { | 1287 | if (cursor) { |
| @@ -1319,10 +1305,11 @@ prepare_to_die: | |||
| 1319 | input_tab(&lastWasTab); | 1305 | input_tab(&lastWasTab); |
| 1320 | break; | 1306 | break; |
| 1321 | #endif | 1307 | #endif |
| 1308 | #if MAX_HISTORY >= 1 | ||
| 1322 | case 'A': | 1309 | case 'A': |
| 1323 | /* Up Arrow -- Get previous command from history */ | 1310 | /* Up Arrow -- Get previous command from history */ |
| 1324 | if (hp && hp->p) { | 1311 | if (cur_history > 0) { |
| 1325 | get_previous_history(&hp, hp->p); | 1312 | get_previous_history(); |
| 1326 | goto rewrite_line; | 1313 | goto rewrite_line; |
| 1327 | } else { | 1314 | } else { |
| 1328 | beep(); | 1315 | beep(); |
| @@ -1330,21 +1317,16 @@ prepare_to_die: | |||
| 1330 | break; | 1317 | break; |
| 1331 | case 'B': | 1318 | case 'B': |
| 1332 | /* Down Arrow -- Get next command in history */ | 1319 | /* Down Arrow -- Get next command in history */ |
| 1333 | if (hp && hp->n && hp->n->s) { | 1320 | if (!get_next_history()) |
| 1334 | get_next_history(&hp); | ||
| 1335 | goto rewrite_line; | ||
| 1336 | } else { | ||
| 1337 | beep(); | ||
| 1338 | } | ||
| 1339 | break; | 1321 | break; |
| 1340 | |||
| 1341 | /* Rewrite the line with the selected history item */ | 1322 | /* Rewrite the line with the selected history item */ |
| 1342 | rewrite_line: | 1323 | rewrite_line: |
| 1343 | /* change command */ | 1324 | /* change command */ |
| 1344 | len = strlen(strcpy(command, hp->s)); | 1325 | len = strlen(strcpy(command, history[cur_history])); |
| 1345 | /* redraw and go to end line */ | 1326 | /* redraw and go to end line */ |
| 1346 | redraw(cmdedit_y, 0); | 1327 | redraw(cmdedit_y, 0); |
| 1347 | break; | 1328 | break; |
| 1329 | #endif | ||
| 1348 | case 'C': | 1330 | case 'C': |
| 1349 | /* Right Arrow -- Move forward one character */ | 1331 | /* Right Arrow -- Move forward one character */ |
| 1350 | input_forward(); | 1332 | input_forward(); |
| @@ -1428,53 +1410,33 @@ prepare_to_die: | |||
| 1428 | setTermSettings(0, (void *) &initial_settings); | 1410 | setTermSettings(0, (void *) &initial_settings); |
| 1429 | handlers_sets &= ~SET_RESET_TERM; | 1411 | handlers_sets &= ~SET_RESET_TERM; |
| 1430 | 1412 | ||
| 1413 | #if MAX_HISTORY >= 1 | ||
| 1431 | /* Handle command history log */ | 1414 | /* Handle command history log */ |
| 1415 | /* cleanup may be saved current command line */ | ||
| 1416 | free(history[MAX_HISTORY]); | ||
| 1417 | history[MAX_HISTORY] = 0; | ||
| 1432 | if (len) { /* no put empty line */ | 1418 | if (len) { /* no put empty line */ |
| 1433 | 1419 | int i = n_history; | |
| 1434 | struct history *h = his_end; | ||
| 1435 | char *ss; | ||
| 1436 | |||
| 1437 | ss = xstrdup(command); /* duplicate */ | ||
| 1438 | |||
| 1439 | if (h == 0) { | ||
| 1440 | /* No previous history -- this memory is never freed */ | ||
| 1441 | h = his_front = xmalloc(sizeof(struct history)); | ||
| 1442 | h->n = xmalloc(sizeof(struct history)); | ||
| 1443 | |||
| 1444 | h->p = NULL; | ||
| 1445 | h->s = ss; | ||
| 1446 | h->n->p = h; | ||
| 1447 | h->n->n = NULL; | ||
| 1448 | h->n->s = NULL; | ||
| 1449 | his_end = h->n; | ||
| 1450 | history_counter++; | ||
| 1451 | } else { | ||
| 1452 | /* Add a new history command -- this memory is never freed */ | ||
| 1453 | h->n = xmalloc(sizeof(struct history)); | ||
| 1454 | |||
| 1455 | h->n->p = h; | ||
| 1456 | h->n->n = NULL; | ||
| 1457 | h->n->s = NULL; | ||
| 1458 | h->s = ss; | ||
| 1459 | his_end = h->n; | ||
| 1460 | |||
| 1461 | /* After max history, remove the oldest command */ | 1420 | /* After max history, remove the oldest command */ |
| 1462 | if (history_counter >= MAX_HISTORY) { | 1421 | if (i >= MAX_HISTORY) { |
| 1463 | 1422 | free(history[0]); | |
| 1464 | struct history *p = his_front->n; | 1423 | for(i = 0; i < (MAX_HISTORY-1); i++) |
| 1465 | 1424 | history[i] = history[i+1]; | |
| 1466 | p->p = NULL; | ||
| 1467 | free(his_front->s); | ||
| 1468 | free(his_front); | ||
| 1469 | his_front = p; | ||
| 1470 | } else { | ||
| 1471 | history_counter++; | ||
| 1472 | } | ||
| 1473 | } | 1425 | } |
| 1426 | history[i++] = xstrdup(command); | ||
| 1427 | cur_history = i; | ||
| 1428 | n_history = i; | ||
| 1474 | #if defined(CONFIG_FEATURE_SH_FANCY_PROMPT) | 1429 | #if defined(CONFIG_FEATURE_SH_FANCY_PROMPT) |
| 1475 | num_ok_lines++; | 1430 | num_ok_lines++; |
| 1476 | #endif | 1431 | #endif |
| 1477 | } | 1432 | } |
| 1433 | #else /* MAX_HISTORY < 1 */ | ||
| 1434 | #if defined(CONFIG_FEATURE_SH_FANCY_PROMPT) | ||
| 1435 | if (len) { /* no put empty line */ | ||
| 1436 | num_ok_lines++; | ||
| 1437 | } | ||
| 1438 | #endif | ||
| 1439 | #endif /* MAX_HISTORY >= 1 */ | ||
| 1478 | if(break_out>0) { | 1440 | if(break_out>0) { |
| 1479 | command[len++] = '\n'; /* set '\n' */ | 1441 | command[len++] = '\n'; /* set '\n' */ |
| 1480 | command[len] = 0; | 1442 | command[len] = 0; |
