diff options
Diffstat (limited to '')
-rw-r--r-- | libbb/lineedit.c | 112 |
1 files changed, 62 insertions, 50 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 151208c1c..10cc0433b 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -451,7 +451,7 @@ static void put_cur_glyph_and_inc_cursor(void) | |||
451 | * have automargin (IOW: it is moving cursor to next line | 451 | * have automargin (IOW: it is moving cursor to next line |
452 | * by itself (which is wrong for VT-10x terminals)), | 452 | * by itself (which is wrong for VT-10x terminals)), |
453 | * this will break things: there will be one extra empty line */ | 453 | * this will break things: there will be one extra empty line */ |
454 | puts("\r"); /* + implicit '\n' */ | 454 | fputs("\r\n", stderr); |
455 | #else | 455 | #else |
456 | /* VT-10x terminals don't wrap cursor to next line when last char | 456 | /* VT-10x terminals don't wrap cursor to next line when last char |
457 | * on the line is printed - cursor stays "over" this char. | 457 | * on the line is printed - cursor stays "over" this char. |
@@ -1170,9 +1170,10 @@ static void showfiles(void) | |||
1170 | ); | 1170 | ); |
1171 | } | 1171 | } |
1172 | if (ENABLE_UNICODE_SUPPORT) | 1172 | if (ENABLE_UNICODE_SUPPORT) |
1173 | puts(printable_string(matches[n])); | 1173 | fputs(printable_string(matches[n]), stderr); |
1174 | else | 1174 | else |
1175 | puts(matches[n]); | 1175 | fputs(matches[n], stderr); |
1176 | bb_putchar_stderr('\n'); | ||
1176 | } | 1177 | } |
1177 | } | 1178 | } |
1178 | 1179 | ||
@@ -1405,8 +1406,8 @@ unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) | |||
1405 | int size = MAX_HISTORY; | 1406 | int size = MAX_HISTORY; |
1406 | if (hp) { | 1407 | if (hp) { |
1407 | size = atoi(hp); | 1408 | size = atoi(hp); |
1408 | if (size <= 0) | 1409 | if (size < 0) |
1409 | return 1; | 1410 | return 0; |
1410 | if (size > MAX_HISTORY) | 1411 | if (size > MAX_HISTORY) |
1411 | return MAX_HISTORY; | 1412 | return MAX_HISTORY; |
1412 | } | 1413 | } |
@@ -1500,18 +1501,21 @@ static void load_history(line_input_t *st_parm) | |||
1500 | /* NB: do not trash old history if file can't be opened */ | 1501 | /* NB: do not trash old history if file can't be opened */ |
1501 | 1502 | ||
1502 | fp = fopen_for_read(st_parm->hist_file); | 1503 | fp = fopen_for_read(st_parm->hist_file); |
1503 | if (fp) { | 1504 | if (!fp) |
1504 | /* clean up old history */ | 1505 | return; |
1505 | for (idx = st_parm->cnt_history; idx > 0;) { | 1506 | |
1506 | idx--; | 1507 | /* clean up old history */ |
1507 | free(st_parm->history[idx]); | 1508 | for (idx = st_parm->cnt_history; idx > 0;) { |
1508 | st_parm->history[idx] = NULL; | 1509 | idx--; |
1509 | } | 1510 | free(st_parm->history[idx]); |
1511 | st_parm->history[idx] = NULL; | ||
1512 | } | ||
1510 | 1513 | ||
1511 | /* fill temp_h[], retaining only last MAX_HISTORY lines */ | 1514 | /* fill temp_h[], retaining only last max_history lines */ |
1512 | memset(temp_h, 0, sizeof(temp_h)); | 1515 | memset(temp_h, 0, sizeof(temp_h)); |
1513 | idx = 0; | 1516 | idx = 0; |
1514 | st_parm->cnt_history_in_file = 0; | 1517 | st_parm->cnt_history_in_file = 0; |
1518 | if (st_parm->max_history != 0) { | ||
1515 | while ((line = xmalloc_fgetline(fp)) != NULL) { | 1519 | while ((line = xmalloc_fgetline(fp)) != NULL) { |
1516 | if (line[0] == '\0') { | 1520 | if (line[0] == '\0') { |
1517 | free(line); | 1521 | free(line); |
@@ -1524,34 +1528,34 @@ static void load_history(line_input_t *st_parm) | |||
1524 | if (idx == st_parm->max_history) | 1528 | if (idx == st_parm->max_history) |
1525 | idx = 0; | 1529 | idx = 0; |
1526 | } | 1530 | } |
1527 | fclose(fp); | 1531 | } |
1528 | 1532 | fclose(fp); | |
1529 | /* find first non-NULL temp_h[], if any */ | ||
1530 | if (st_parm->cnt_history_in_file) { | ||
1531 | while (temp_h[idx] == NULL) { | ||
1532 | idx++; | ||
1533 | if (idx == st_parm->max_history) | ||
1534 | idx = 0; | ||
1535 | } | ||
1536 | } | ||
1537 | 1533 | ||
1538 | /* copy temp_h[] to st_parm->history[] */ | 1534 | /* find first non-NULL temp_h[], if any */ |
1539 | for (i = 0; i < st_parm->max_history;) { | 1535 | if (st_parm->cnt_history_in_file != 0) { |
1540 | line = temp_h[idx]; | 1536 | while (temp_h[idx] == NULL) { |
1541 | if (!line) | ||
1542 | break; | ||
1543 | idx++; | 1537 | idx++; |
1544 | if (idx == st_parm->max_history) | 1538 | if (idx == st_parm->max_history) |
1545 | idx = 0; | 1539 | idx = 0; |
1546 | line_len = strlen(line); | ||
1547 | if (line_len >= MAX_LINELEN) | ||
1548 | line[MAX_LINELEN-1] = '\0'; | ||
1549 | st_parm->history[i++] = line; | ||
1550 | } | 1540 | } |
1551 | st_parm->cnt_history = i; | ||
1552 | if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT) | ||
1553 | st_parm->cnt_history_in_file = i; | ||
1554 | } | 1541 | } |
1542 | |||
1543 | /* copy temp_h[] to st_parm->history[] */ | ||
1544 | for (i = 0; i < st_parm->max_history;) { | ||
1545 | line = temp_h[idx]; | ||
1546 | if (!line) | ||
1547 | break; | ||
1548 | idx++; | ||
1549 | if (idx == st_parm->max_history) | ||
1550 | idx = 0; | ||
1551 | line_len = strlen(line); | ||
1552 | if (line_len >= MAX_LINELEN) | ||
1553 | line[MAX_LINELEN-1] = '\0'; | ||
1554 | st_parm->history[i++] = line; | ||
1555 | } | ||
1556 | st_parm->cnt_history = i; | ||
1557 | if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT) | ||
1558 | st_parm->cnt_history_in_file = i; | ||
1555 | } | 1559 | } |
1556 | 1560 | ||
1557 | # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 1561 | # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
@@ -1559,17 +1563,27 @@ void FAST_FUNC save_history(line_input_t *st) | |||
1559 | { | 1563 | { |
1560 | FILE *fp; | 1564 | FILE *fp; |
1561 | 1565 | ||
1562 | if (!st || !st->hist_file) | 1566 | /* bash compat: HISTFILE="" disables history saving */ |
1567 | if (!st || !st->hist_file || !st->hist_file[0]) | ||
1563 | return; | 1568 | return; |
1564 | if (st->cnt_history <= st->cnt_history_in_file) | 1569 | if (st->cnt_history <= st->cnt_history_in_file) |
1565 | return; | 1570 | return; /* no new entries were added */ |
1571 | /* note: if st->max_history is 0, we do not abort: we truncate the history to 0 lines */ | ||
1566 | 1572 | ||
1567 | fp = fopen(st->hist_file, "a"); | 1573 | fp = fopen(st->hist_file, (st->max_history == 0 ? "w" : "a")); |
1568 | if (fp) { | 1574 | if (fp) { |
1569 | int i, fd; | 1575 | int i, fd; |
1570 | char *new_name; | 1576 | char *new_name; |
1571 | line_input_t *st_temp; | 1577 | line_input_t *st_temp; |
1572 | 1578 | ||
1579 | /* max_history==0 needs special-casing in general code, | ||
1580 | * just handle it in a simpler way: */ | ||
1581 | if (st->max_history == 0) { | ||
1582 | /* fopen("w") already truncated it */ | ||
1583 | fclose(fp); | ||
1584 | return; | ||
1585 | } | ||
1586 | |||
1573 | for (i = st->cnt_history_in_file; i < st->cnt_history; i++) | 1587 | for (i = st->cnt_history_in_file; i < st->cnt_history; i++) |
1574 | fprintf(fp, "%s\n", st->history[i]); | 1588 | fprintf(fp, "%s\n", st->history[i]); |
1575 | fclose(fp); | 1589 | fclose(fp); |
@@ -1579,6 +1593,8 @@ void FAST_FUNC save_history(line_input_t *st) | |||
1579 | st_temp = new_line_input_t(st->flags); | 1593 | st_temp = new_line_input_t(st->flags); |
1580 | st_temp->hist_file = st->hist_file; | 1594 | st_temp->hist_file = st->hist_file; |
1581 | st_temp->max_history = st->max_history; | 1595 | st_temp->max_history = st->max_history; |
1596 | /* load no more than max_history last lines */ | ||
1597 | /* (in unlikely case that file disappeared, st_temp gets empty history) */ | ||
1582 | load_history(st_temp); | 1598 | load_history(st_temp); |
1583 | 1599 | ||
1584 | /* write out temp file and replace hist_file atomically */ | 1600 | /* write out temp file and replace hist_file atomically */ |
@@ -1602,13 +1618,13 @@ static void save_history(char *str) | |||
1602 | int fd; | 1618 | int fd; |
1603 | int len, len2; | 1619 | int len, len2; |
1604 | 1620 | ||
1605 | if (!state->hist_file) | 1621 | /* bash compat: HISTFILE="" disables history saving */ |
1622 | if (!state->hist_file || !state->hist_file[0]) | ||
1606 | return; | 1623 | return; |
1607 | 1624 | ||
1608 | fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); | 1625 | fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); |
1609 | if (fd < 0) | 1626 | if (fd < 0) |
1610 | return; | 1627 | return; |
1611 | xlseek(fd, 0, SEEK_END); /* paranoia */ | ||
1612 | len = strlen(str); | 1628 | len = strlen(str); |
1613 | str[len] = '\n'; /* we (try to) do atomic write */ | 1629 | str[len] = '\n'; /* we (try to) do atomic write */ |
1614 | len2 = full_write(fd, str, len + 1); | 1630 | len2 = full_write(fd, str, len + 1); |
@@ -1663,13 +1679,10 @@ static void remember_in_history(char *str) | |||
1663 | if (str[0] == '\0') | 1679 | if (str[0] == '\0') |
1664 | return; | 1680 | return; |
1665 | i = state->cnt_history; | 1681 | i = state->cnt_history; |
1666 | /* Don't save dupes */ | 1682 | /* Don't save dups */ |
1667 | if (i && strcmp(state->history[i-1], str) == 0) | 1683 | if (i != 0 && strcmp(state->history[i-1], str) == 0) |
1668 | return; | 1684 | return; |
1669 | 1685 | ||
1670 | free(state->history[state->max_history]); /* redundant, paranoia */ | ||
1671 | state->history[state->max_history] = NULL; /* redundant, paranoia */ | ||
1672 | |||
1673 | /* If history[] is full, remove the oldest command */ | 1686 | /* If history[] is full, remove the oldest command */ |
1674 | /* we need to keep history[state->max_history] empty, hence >=, not > */ | 1687 | /* we need to keep history[state->max_history] empty, hence >=, not > */ |
1675 | if (i >= state->max_history) { | 1688 | if (i >= state->max_history) { |
@@ -1682,7 +1695,7 @@ static void remember_in_history(char *str) | |||
1682 | state->cnt_history_in_file--; | 1695 | state->cnt_history_in_file--; |
1683 | # endif | 1696 | # endif |
1684 | } | 1697 | } |
1685 | /* i <= state->max_history-1 */ | 1698 | /* i < state->max_history */ |
1686 | state->history[i++] = xstrdup(str); | 1699 | state->history[i++] = xstrdup(str); |
1687 | /* i <= state->max_history */ | 1700 | /* i <= state->max_history */ |
1688 | state->cur_history = i; | 1701 | state->cur_history = i; |
@@ -2194,7 +2207,6 @@ static int lineedit_read_key(char *read_key_buffer, int timeout) | |||
2194 | errno = EINTR; | 2207 | errno = EINTR; |
2195 | return -1; | 2208 | return -1; |
2196 | } | 2209 | } |
2197 | //FIXME: still races here with signals, but small window to poll() inside read_key | ||
2198 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) | 2210 | IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) |
2199 | /* errno = 0; - read_key does this itself */ | 2211 | /* errno = 0; - read_key does this itself */ |
2200 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); | 2212 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); |