Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/libbb/lineedit.c
- Timestamp:
- Dec 20, 2016, 4:07:32 PM (7 years ago)
- Location:
- branches/3.3
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/3.3/mindi-busybox/libbb/lineedit.c
r3232 r3621 39 39 * 40 40 * PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] ' 41 * 42 * Unicode in PS1 is not fully supported: prompt length calulation is wrong, 43 * resulting in line wrap problems with long (multi-line) input. 44 * 45 * Multi-line PS1 (e.g. PS1="\n[\w]\n$ ") has problems with history 46 * browsing: up/down arrows result in scrolling. 47 * It stems from simplistic "cmdedit_y = cmdedit_prmt_len / cmdedit_termw" 48 * calculation of how many lines the prompt takes. 41 49 */ 42 #include "libbb.h" 50 #include "busybox.h" 51 #include "NUM_APPLETS.h" 43 52 #include "unicode.h" 44 53 #ifndef _POSIX_VDISABLE … … 134 143 135 144 const char *cmdedit_prompt; 136 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT137 int num_ok_lines; /* = 1; */138 #endif139 145 140 146 #if ENABLE_USERNAME_OR_HOMEDIR … … 173 179 #define command_ps (S.command_ps ) 174 180 #define cmdedit_prompt (S.cmdedit_prompt ) 175 #define num_ok_lines (S.num_ok_lines )176 181 #define user_buf (S.user_buf ) 177 182 #define home_pwd_buf (S.home_pwd_buf ) … … 186 191 barrier(); \ 187 192 cmdedit_termw = 80; \ 188 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \189 193 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ 194 IF_FEATURE_EDITING_VI(delptr = delbuf;) \ 190 195 } while (0) 191 196 … … 669 674 static NOINLINE unsigned complete_username(const char *ud) 670 675 { 671 /* Using _r function to avoid pulling in static buffers */ 672 char line_buff[256]; 673 struct passwd pwd; 674 struct passwd *result; 676 struct passwd *pw; 675 677 unsigned userlen; 676 678 … … 679 681 680 682 setpwent(); 681 while ( !getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) {683 while ((pw = getpwent()) != NULL) { 682 684 /* Null usernames should result in all users as possible completions. */ 683 if (/* !userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) {684 add_match(xasprintf("~%s/", pw d.pw_name));685 } 686 } 687 endpwent(); 685 if (/* !ud[0] || */ is_prefixed_with(pw->pw_name, ud)) { 686 add_match(xasprintf("~%s/", pw->pw_name)); 687 } 688 } 689 endpwent(); /* don't keep password file open */ 688 690 689 691 return 1 + userlen; … … 774 776 pf_len = strlen(pfind); 775 777 778 #if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 779 if (type == FIND_EXE_ONLY) { 780 const char *p = applet_names; 781 782 while (*p) { 783 if (strncmp(pfind, p, pf_len) == 0) 784 add_match(xstrdup(p)); 785 while (*p++ != '\0') 786 continue; 787 } 788 } 789 #endif 790 776 791 for (i = 0; i < npaths; i++) { 777 792 DIR *dir; … … 792 807 continue; 793 808 /* match? */ 794 if ( strncmp(name_found, pfind, pf_len) != 0)809 if (!is_prefixed_with(name_found, pfind)) 795 810 continue; /* no */ 796 811 … … 1252 1267 line_input_t *n = xzalloc(sizeof(*n)); 1253 1268 n->flags = flags; 1269 #if MAX_HISTORY > 0 1254 1270 n->max_history = MAX_HISTORY; 1271 #endif 1255 1272 return n; 1256 1273 } … … 1259 1276 #if MAX_HISTORY > 0 1260 1277 1261 unsigned size_from_HISTFILESIZE(const char *hp)1278 unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) 1262 1279 { 1263 1280 int size = MAX_HISTORY; … … 1312 1329 beep(); 1313 1330 return 0; 1331 } 1332 1333 /* Lists command history. Used by shell 'history' builtins */ 1334 void FAST_FUNC show_history(const line_input_t *st) 1335 { 1336 int i; 1337 1338 if (!st) 1339 return; 1340 for (i = 0; i < st->cnt_history; i++) 1341 printf("%4d %s\n", i, st->history[i]); 1314 1342 } 1315 1343 … … 1532 1560 save_history(str); 1533 1561 # endif 1534 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)1535 1562 } 1536 1563 … … 1754 1781 #endif 1755 1782 1783 /* Called just once at read_line_input() init time */ 1756 1784 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT 1757 1785 static void parse_and_put_prompt(const char *prmt_ptr) 1758 1786 { 1787 const char *p; 1759 1788 cmdedit_prompt = prmt_ptr; 1760 cmdedit_prmt_len = strlen(prmt_ptr); 1789 p = strrchr(prmt_ptr, '\n'); 1790 cmdedit_prmt_len = unicode_strwidth(p ? p+1 : prmt_ptr); 1761 1791 put_prompt(); 1762 1792 } … … 1764 1794 static void parse_and_put_prompt(const char *prmt_ptr) 1765 1795 { 1766 int prmt_len = 0; 1767 size_t cur_prmt_len = 0; 1796 int prmt_size = 0; 1797 char *prmt_mem_ptr = xzalloc(1); 1798 # if ENABLE_USERNAME_OR_HOMEDIR 1799 char *cwd_buf = NULL; 1800 # endif 1768 1801 char flg_not_length = '['; 1769 char *prmt_mem_ptr = xzalloc(1);1770 char *cwd_buf = xrealloc_getcwd_or_warn(NULL);1771 1802 char cbuf[2]; 1772 char c; 1773 char *pbuf; 1774 1775 cmdedit_prmt_len = 0; 1776 1777 if (!cwd_buf) { 1778 cwd_buf = (char *)bb_msg_unknown; 1779 } 1803 1804 /*cmdedit_prmt_len = 0; - already is */ 1780 1805 1781 1806 cbuf[1] = '\0'; /* never changes */ 1782 1807 1783 1808 while (*prmt_ptr) { 1809 char timebuf[sizeof("HH:MM:SS")]; 1784 1810 char *free_me = NULL; 1811 char *pbuf; 1812 char c; 1785 1813 1786 1814 pbuf = cbuf; 1787 1815 c = *prmt_ptr++; 1788 1816 if (c == '\\') { 1789 const char *cp = prmt_ptr;1817 const char *cp; 1790 1818 int l; 1791 1792 c = bb_process_escape_sequence(&prmt_ptr); 1819 /* 1820 * Supported via bb_process_escape_sequence: 1821 * \a ASCII bell character (07) 1822 * \e ASCII escape character (033) 1823 * \n newline 1824 * \r carriage return 1825 * \\ backslash 1826 * \nnn char with octal code nnn 1827 * Supported: 1828 * \$ if the effective UID is 0, a #, otherwise a $ 1829 * \w current working directory, with $HOME abbreviated with a tilde 1830 * Note: we do not support $PROMPT_DIRTRIM=n feature 1831 * \W basename of the current working directory, with $HOME abbreviated with a tilde 1832 * \h hostname up to the first '.' 1833 * \H hostname 1834 * \u username 1835 * \[ begin a sequence of non-printing characters 1836 * \] end a sequence of non-printing characters 1837 * \T current time in 12-hour HH:MM:SS format 1838 * \@ current time in 12-hour am/pm format 1839 * \A current time in 24-hour HH:MM format 1840 * \t current time in 24-hour HH:MM:SS format 1841 * (all of the above work as \A) 1842 * Not supported: 1843 * \! history number of this command 1844 * \# command number of this command 1845 * \j number of jobs currently managed by the shell 1846 * \l basename of the shell's terminal device name 1847 * \s name of the shell, the basename of $0 (the portion following the final slash) 1848 * \V release of bash, version + patch level (e.g., 2.00.0) 1849 * \d date in "Weekday Month Date" format (e.g., "Tue May 26") 1850 * \D{format} 1851 * format is passed to strftime(3). 1852 * An empty format results in a locale-specific time representation. 1853 * The braces are required. 1854 * Mishandled by bb_process_escape_sequence: 1855 * \v version of bash (e.g., 2.00) 1856 */ 1857 cp = prmt_ptr; 1858 c = *cp; 1859 if (c != 't') /* don't treat \t as tab */ 1860 c = bb_process_escape_sequence(&prmt_ptr); 1793 1861 if (prmt_ptr == cp) { 1794 1862 if (*cp == '\0') … … 1802 1870 break; 1803 1871 # endif 1872 case 'H': 1804 1873 case 'h': 1805 1874 pbuf = free_me = safe_gethostname(); 1806 *strchrnul(pbuf, '.') = '\0'; 1875 if (c == 'h') 1876 strchrnul(pbuf, '.')[0] = '\0'; 1807 1877 break; 1808 1878 case '$': 1809 1879 c = (geteuid() == 0 ? '#' : '$'); 1810 1880 break; 1881 case 'T': /* 12-hour HH:MM:SS format */ 1882 case '@': /* 12-hour am/pm format */ 1883 case 'A': /* 24-hour HH:MM format */ 1884 case 't': /* 24-hour HH:MM:SS format */ 1885 /* We show all of them as 24-hour HH:MM */ 1886 strftime_HHMMSS(timebuf, sizeof(timebuf), NULL)[-3] = '\0'; 1887 pbuf = timebuf; 1888 break; 1811 1889 # if ENABLE_USERNAME_OR_HOMEDIR 1812 case 'w': 1813 /* /home/user[/something] -> ~[/something] */ 1890 case 'w': /* current dir */ 1891 case 'W': /* basename of cur dir */ 1892 if (!cwd_buf) { 1893 cwd_buf = xrealloc_getcwd_or_warn(NULL); 1894 if (!cwd_buf) 1895 cwd_buf = (char *)bb_msg_unknown; 1896 else if (home_pwd_buf[0]) { 1897 char *after_home_user; 1898 1899 /* /home/user[/something] -> ~[/something] */ 1900 after_home_user = is_prefixed_with(cwd_buf, home_pwd_buf); 1901 if (after_home_user 1902 && (*after_home_user == '/' || *after_home_user == '\0') 1903 ) { 1904 cwd_buf[0] = '~'; 1905 overlapping_strcpy(cwd_buf + 1, after_home_user); 1906 } 1907 } 1908 } 1814 1909 pbuf = cwd_buf; 1815 l = strlen(home_pwd_buf); 1816 if (l != 0 1817 && strncmp(home_pwd_buf, cwd_buf, l) == 0 1818 && (cwd_buf[l]=='/' || cwd_buf[l]=='\0') 1819 && strlen(cwd_buf + l) < PATH_MAX 1820 ) { 1821 pbuf = free_me = xasprintf("~%s", cwd_buf + l); 1822 } 1910 if (c == 'w') 1911 break; 1912 cp = strrchr(pbuf, '/'); 1913 if (cp) 1914 pbuf = (char*)cp + 1; 1823 1915 break; 1824 1916 # endif 1825 case 'W': 1826 pbuf = cwd_buf; 1827 cp = strrchr(pbuf, '/'); 1828 if (cp != NULL && cp != pbuf) 1829 pbuf += (cp-pbuf) + 1; 1830 break; 1831 case '!': 1832 pbuf = free_me = xasprintf("%d", num_ok_lines); 1833 break; 1834 case 'e': case 'E': /* \e \E = \033 */ 1835 c = '\033'; 1836 break; 1917 // bb_process_escape_sequence does this now: 1918 // case 'e': case 'E': /* \e \E = \033 */ 1919 // c = '\033'; 1920 // break; 1837 1921 case 'x': case 'X': { 1838 1922 char buf2[4]; … … 1856 1940 case '[': case ']': 1857 1941 if (c == flg_not_length) { 1858 flg_not_length = (flg_not_length == '[' ? ']' : '['); 1942 /* Toggle '['/']' hex 5b/5d */ 1943 flg_not_length ^= 6; 1859 1944 continue; 1860 1945 } … … 1864 1949 } /* if */ 1865 1950 cbuf[0] = c; 1866 cur_prmt_len = strlen(pbuf); 1867 prmt_len += cur_prmt_len; 1868 if (flg_not_length != ']') 1869 cmdedit_prmt_len += cur_prmt_len; 1870 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); 1951 { 1952 int n = strlen(pbuf); 1953 prmt_size += n; 1954 if (c == '\n') 1955 cmdedit_prmt_len = 0; 1956 else if (flg_not_length != ']') { 1957 #if 0 /*ENABLE_UNICODE_SUPPORT*/ 1958 /* Won't work, pbuf is one BYTE string here instead of an one Unicode char string. */ 1959 /* FIXME */ 1960 cmdedit_prmt_len += unicode_strwidth(pbuf); 1961 #else 1962 cmdedit_prmt_len += n; 1963 #endif 1964 } 1965 } 1966 prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_size+1), pbuf); 1871 1967 free(free_me); 1872 1968 } /* while */ 1873 1969 1970 # if ENABLE_USERNAME_OR_HOMEDIR 1874 1971 if (cwd_buf != (char *)bb_msg_unknown) 1875 1972 free(cwd_buf); 1973 # endif 1876 1974 cmdedit_prompt = prmt_mem_ptr; 1877 1975 put_prompt(); … … 1935 2033 if (cursor == 0) { /* otherwise it may be bogus */ 1936 2034 int col = ((ic >> 32) & 0x7fff) - 1; 1937 if (col > cmdedit_prmt_len) { 2035 /* 2036 * Is col > cmdedit_prmt_len? 2037 * If yes (terminal says cursor is farther to the right 2038 * of where we think it should be), 2039 * the prompt wasn't printed starting at col 1, 2040 * there was additional text before it. 2041 */ 2042 if ((int)(col - cmdedit_prmt_len) > 0) { 2043 /* Fix our understanding of current x position */ 1938 2044 cmdedit_x += (col - cmdedit_prmt_len); 1939 2045 while (cmdedit_x >= cmdedit_termw) { … … 2026 2132 const char *matched_history_line; 2027 2133 const char *saved_prompt; 2134 unsigned saved_prmt_len; 2028 2135 int32_t ic; 2029 2136 … … 2034 2141 /* Save and replace the prompt */ 2035 2142 saved_prompt = cmdedit_prompt; 2143 saved_prmt_len = cmdedit_prmt_len; 2036 2144 goto set_prompt; 2037 2145 … … 2109 2217 set_prompt: 2110 2218 cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf); 2111 cmdedit_prmt_len = strlen(cmdedit_prompt);2219 cmdedit_prmt_len = unicode_strwidth(cmdedit_prompt); 2112 2220 goto do_redraw; 2113 2221 } … … 2131 2239 free((char*)cmdedit_prompt); 2132 2240 cmdedit_prompt = saved_prompt; 2133 cmdedit_prmt_len = s trlen(cmdedit_prompt);2241 cmdedit_prmt_len = saved_prmt_len; 2134 2242 redraw(cmdedit_y, command_len - cursor); 2135 2243 … … 2161 2269 2162 2270 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0 2163 || !(initial_settings.c_lflag & ECHO)2271 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON 2164 2272 ) { 2165 /* Happens when e.g. stty -echo was run before */ 2273 /* Happens when e.g. stty -echo was run before. 2274 * But if ICANON is not set, we don't come here. 2275 * (example: interactive python ^Z-backgrounded, 2276 * tty is still in "raw mode"). 2277 */ 2166 2278 parse_and_put_prompt(prompt); 2167 2279 /* fflush_all(); - done by parse_and_put_prompt */ … … 2512 2624 * Often, Alt-<key> generates ESC-<key>. 2513 2625 */ 2514 ic = lineedit_read_key(read_key_buffer, timeout);2626 ic = lineedit_read_key(read_key_buffer, 50); 2515 2627 switch (ic) { 2516 2628 //case KEYCODE_LEFT: - bash doesn't do this … … 2699 2811 #endif 2700 2812 2701 if (command_len > 0) 2813 if (command_len > 0) { 2702 2814 remember_in_history(command); 2815 } 2703 2816 2704 2817 if (break_out > 0) {
Note:
See TracChangeset
for help on using the changeset viewer.