aboutsummaryrefslogtreecommitdiff
path: root/libbb/lineedit.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r--libbb/lineedit.c112
1 files changed, 62 insertions, 50 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 8e2b37853..c8a0f37fe 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -457,7 +457,7 @@ static void put_cur_glyph_and_inc_cursor(void)
457 * have automargin (IOW: it is moving cursor to next line 457 * have automargin (IOW: it is moving cursor to next line
458 * by itself (which is wrong for VT-10x terminals)), 458 * by itself (which is wrong for VT-10x terminals)),
459 * this will break things: there will be one extra empty line */ 459 * this will break things: there will be one extra empty line */
460 puts("\r"); /* + implicit '\n' */ 460 fputs("\r\n", stderr);
461#else 461#else
462 /* VT-10x terminals don't wrap cursor to next line when last char 462 /* VT-10x terminals don't wrap cursor to next line when last char
463 * on the line is printed - cursor stays "over" this char. 463 * on the line is printed - cursor stays "over" this char.
@@ -1302,9 +1302,10 @@ static void showfiles(void)
1302 ); 1302 );
1303 } 1303 }
1304 if (ENABLE_UNICODE_SUPPORT) 1304 if (ENABLE_UNICODE_SUPPORT)
1305 puts(printable_string(matches[n])); 1305 fputs(printable_string(matches[n]), stderr);
1306 else 1306 else
1307 puts(matches[n]); 1307 fputs(matches[n], stderr);
1308 bb_putchar_stderr('\n');
1308 } 1309 }
1309} 1310}
1310 1311
@@ -1595,8 +1596,8 @@ unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp)
1595# endif 1596# endif
1596 if (hp) { 1597 if (hp) {
1597 size = atoi(hp); 1598 size = atoi(hp);
1598 if (size <= 0) 1599 if (size < 0)
1599 return 1; 1600 return 0;
1600 if (size > MAX_HISTORY) 1601 if (size > MAX_HISTORY)
1601 return MAX_HISTORY; 1602 return MAX_HISTORY;
1602 } 1603 }
@@ -1690,18 +1691,21 @@ static void load_history(line_input_t *st_parm)
1690 /* NB: do not trash old history if file can't be opened */ 1691 /* NB: do not trash old history if file can't be opened */
1691 1692
1692 fp = fopen_for_read(st_parm->hist_file); 1693 fp = fopen_for_read(st_parm->hist_file);
1693 if (fp) { 1694 if (!fp)
1694 /* clean up old history */ 1695 return;
1695 for (idx = st_parm->cnt_history; idx > 0;) { 1696
1696 idx--; 1697 /* clean up old history */
1697 free(st_parm->history[idx]); 1698 for (idx = st_parm->cnt_history; idx > 0;) {
1698 st_parm->history[idx] = NULL; 1699 idx--;
1699 } 1700 free(st_parm->history[idx]);
1701 st_parm->history[idx] = NULL;
1702 }
1700 1703
1701 /* fill temp_h[], retaining only last MAX_HISTORY lines */ 1704 /* fill temp_h[], retaining only last max_history lines */
1702 memset(temp_h, 0, sizeof(temp_h)); 1705 memset(temp_h, 0, sizeof(temp_h));
1703 idx = 0; 1706 idx = 0;
1704 st_parm->cnt_history_in_file = 0; 1707 st_parm->cnt_history_in_file = 0;
1708 if (st_parm->max_history != 0) {
1705 while ((line = xmalloc_fgetline(fp)) != NULL) { 1709 while ((line = xmalloc_fgetline(fp)) != NULL) {
1706 if (line[0] == '\0') { 1710 if (line[0] == '\0') {
1707 free(line); 1711 free(line);
@@ -1714,34 +1718,34 @@ static void load_history(line_input_t *st_parm)
1714 if (idx == st_parm->max_history) 1718 if (idx == st_parm->max_history)
1715 idx = 0; 1719 idx = 0;
1716 } 1720 }
1717 fclose(fp); 1721 }
1718 1722 fclose(fp);
1719 /* find first non-NULL temp_h[], if any */
1720 if (st_parm->cnt_history_in_file) {
1721 while (temp_h[idx] == NULL) {
1722 idx++;
1723 if (idx == st_parm->max_history)
1724 idx = 0;
1725 }
1726 }
1727 1723
1728 /* copy temp_h[] to st_parm->history[] */ 1724 /* find first non-NULL temp_h[], if any */
1729 for (i = 0; i < st_parm->max_history;) { 1725 if (st_parm->cnt_history_in_file != 0) {
1730 line = temp_h[idx]; 1726 while (temp_h[idx] == NULL) {
1731 if (!line)
1732 break;
1733 idx++; 1727 idx++;
1734 if (idx == st_parm->max_history) 1728 if (idx == st_parm->max_history)
1735 idx = 0; 1729 idx = 0;
1736 line_len = strlen(line);
1737 if (line_len >= MAX_LINELEN)
1738 line[MAX_LINELEN-1] = '\0';
1739 st_parm->history[i++] = line;
1740 } 1730 }
1741 st_parm->cnt_history = i;
1742 if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1743 st_parm->cnt_history_in_file = i;
1744 } 1731 }
1732
1733 /* copy temp_h[] to st_parm->history[] */
1734 for (i = 0; i < st_parm->max_history;) {
1735 line = temp_h[idx];
1736 if (!line)
1737 break;
1738 idx++;
1739 if (idx == st_parm->max_history)
1740 idx = 0;
1741 line_len = strlen(line);
1742 if (line_len >= MAX_LINELEN)
1743 line[MAX_LINELEN-1] = '\0';
1744 st_parm->history[i++] = line;
1745 }
1746 st_parm->cnt_history = i;
1747 if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1748 st_parm->cnt_history_in_file = i;
1745} 1749}
1746 1750
1747# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 1751# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
@@ -1749,17 +1753,27 @@ void FAST_FUNC save_history(line_input_t *st)
1749{ 1753{
1750 FILE *fp; 1754 FILE *fp;
1751 1755
1752 if (!st || !st->hist_file) 1756 /* bash compat: HISTFILE="" disables history saving */
1757 if (!st || !st->hist_file || !state->hist_file[0])
1753 return; 1758 return;
1754 if (st->cnt_history <= st->cnt_history_in_file) 1759 if (st->cnt_history <= st->cnt_history_in_file)
1755 return; 1760 return; /* no new entries were added */
1761 /* note: if st->max_history is 0, we do not abort: we truncate the history to 0 lines */
1756 1762
1757 fp = fopen(st->hist_file, "a"); 1763 fp = fopen(st->hist_file, (st->max_history == 0 ? "w" : "a"));
1758 if (fp) { 1764 if (fp) {
1759 int i, fd; 1765 int i, fd;
1760 char *new_name; 1766 char *new_name;
1761 line_input_t *st_temp; 1767 line_input_t *st_temp;
1762 1768
1769 /* max_history==0 needs special-casing in general code,
1770 * just handle it in a simpler way: */
1771 if (st->max_history == 0) {
1772 /* fopen("w") already truncated it */
1773 fclose(fp);
1774 return;
1775 }
1776
1763 for (i = st->cnt_history_in_file; i < st->cnt_history; i++) 1777 for (i = st->cnt_history_in_file; i < st->cnt_history; i++)
1764 fprintf(fp, "%s\n", st->history[i]); 1778 fprintf(fp, "%s\n", st->history[i]);
1765 fclose(fp); 1779 fclose(fp);
@@ -1769,6 +1783,8 @@ void FAST_FUNC save_history(line_input_t *st)
1769 st_temp = new_line_input_t(st->flags); 1783 st_temp = new_line_input_t(st->flags);
1770 st_temp->hist_file = st->hist_file; 1784 st_temp->hist_file = st->hist_file;
1771 st_temp->max_history = st->max_history; 1785 st_temp->max_history = st->max_history;
1786 /* load no more than max_history last lines */
1787 /* (in unlikely case that file disappeared, st_temp gets empty history) */
1772 load_history(st_temp); 1788 load_history(st_temp);
1773 1789
1774 /* write out temp file and replace hist_file atomically */ 1790 /* write out temp file and replace hist_file atomically */
@@ -1792,13 +1808,13 @@ static void save_history(char *str)
1792 int fd; 1808 int fd;
1793 int len, len2; 1809 int len, len2;
1794 1810
1795 if (!state->hist_file) 1811 /* bash compat: HISTFILE="" disables history saving */
1812 if (!state->hist_file || !state->hist_file[0])
1796 return; 1813 return;
1797 1814
1798 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); 1815 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
1799 if (fd < 0) 1816 if (fd < 0)
1800 return; 1817 return;
1801 xlseek(fd, 0, SEEK_END); /* paranoia */
1802 len = strlen(str); 1818 len = strlen(str);
1803 str[len] = '\n'; /* we (try to) do atomic write */ 1819 str[len] = '\n'; /* we (try to) do atomic write */
1804 len2 = full_write(fd, str, len + 1); 1820 len2 = full_write(fd, str, len + 1);
@@ -1853,13 +1869,10 @@ static void remember_in_history(char *str)
1853 if (str[0] == '\0') 1869 if (str[0] == '\0')
1854 return; 1870 return;
1855 i = state->cnt_history; 1871 i = state->cnt_history;
1856 /* Don't save dupes */ 1872 /* Don't save dups */
1857 if (i && strcmp(state->history[i-1], str) == 0) 1873 if (i != 0 && strcmp(state->history[i-1], str) == 0)
1858 return; 1874 return;
1859 1875
1860 free(state->history[state->max_history]); /* redundant, paranoia */
1861 state->history[state->max_history] = NULL; /* redundant, paranoia */
1862
1863 /* If history[] is full, remove the oldest command */ 1876 /* If history[] is full, remove the oldest command */
1864 /* we need to keep history[state->max_history] empty, hence >=, not > */ 1877 /* we need to keep history[state->max_history] empty, hence >=, not > */
1865 if (i >= state->max_history) { 1878 if (i >= state->max_history) {
@@ -1872,7 +1885,7 @@ static void remember_in_history(char *str)
1872 state->cnt_history_in_file--; 1885 state->cnt_history_in_file--;
1873# endif 1886# endif
1874 } 1887 }
1875 /* i <= state->max_history-1 */ 1888 /* i < state->max_history */
1876 state->history[i++] = xstrdup(str); 1889 state->history[i++] = xstrdup(str);
1877 /* i <= state->max_history */ 1890 /* i <= state->max_history */
1878 state->cur_history = i; 1891 state->cur_history = i;
@@ -2388,7 +2401,6 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
2388 errno = EINTR; 2401 errno = EINTR;
2389 return -1; 2402 return -1;
2390 } 2403 }
2391//FIXME: still races here with signals, but small window to poll() inside read_key
2392 IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) 2404 IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;)
2393 /* errno = 0; - read_key does this itself */ 2405 /* errno = 0; - read_key does this itself */
2394 ic = read_key(STDIN_FILENO, read_key_buffer, timeout); 2406 ic = read_key(STDIN_FILENO, read_key_buffer, timeout);