aboutsummaryrefslogtreecommitdiff
path: root/libbb/lineedit.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libbb/lineedit.c112
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);