Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/libbb/lineedit.c


Ignore:
Timestamp:
Dec 20, 2016, 4:07:32 PM (7 years ago)
Author:
Bruno Cornec
Message:

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

Location:
branches/3.3
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/3.3/mindi-busybox/libbb/lineedit.c

    r3232 r3621  
    3939 *
    4040 * 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.
    4149 */
    42 #include "libbb.h"
     50#include "busybox.h"
     51#include "NUM_APPLETS.h"
    4352#include "unicode.h"
    4453#ifndef _POSIX_VDISABLE
     
    134143
    135144    const char *cmdedit_prompt;
    136 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
    137     int num_ok_lines; /* = 1; */
    138 #endif
    139145
    140146#if ENABLE_USERNAME_OR_HOMEDIR
     
    173179#define command_ps       (S.command_ps      )
    174180#define cmdedit_prompt   (S.cmdedit_prompt  )
    175 #define num_ok_lines     (S.num_ok_lines    )
    176181#define user_buf         (S.user_buf        )
    177182#define home_pwd_buf     (S.home_pwd_buf    )
     
    186191    barrier(); \
    187192    cmdedit_termw = 80; \
    188     IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \
    189193    IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \
     194    IF_FEATURE_EDITING_VI(delptr = delbuf;) \
    190195} while (0)
    191196
     
    669674static NOINLINE unsigned complete_username(const char *ud)
    670675{
    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;
    675677    unsigned userlen;
    676678
     
    679681
    680682    setpwent();
    681     while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) {
     683    while ((pw = getpwent()) != NULL) {
    682684        /* 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/", pwd.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 */
    688690
    689691    return 1 + userlen;
     
    774776    pf_len = strlen(pfind);
    775777
     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
    776791    for (i = 0; i < npaths; i++) {
    777792        DIR *dir;
     
    792807                continue;
    793808            /* match? */
    794             if (strncmp(name_found, pfind, pf_len) != 0)
     809            if (!is_prefixed_with(name_found, pfind))
    795810                continue; /* no */
    796811
     
    12521267    line_input_t *n = xzalloc(sizeof(*n));
    12531268    n->flags = flags;
     1269#if MAX_HISTORY > 0
    12541270    n->max_history = MAX_HISTORY;
     1271#endif
    12551272    return n;
    12561273}
     
    12591276#if MAX_HISTORY > 0
    12601277
    1261 unsigned size_from_HISTFILESIZE(const char *hp)
     1278unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp)
    12621279{
    12631280    int size = MAX_HISTORY;
     
    13121329    beep();
    13131330    return 0;
     1331}
     1332
     1333/* Lists command history. Used by shell 'history' builtins */
     1334void 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]);
    13141342}
    13151343
     
    15321560    save_history(str);
    15331561# endif
    1534     IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
    15351562}
    15361563
     
    17541781#endif
    17551782
     1783/* Called just once at read_line_input() init time */
    17561784#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
    17571785static void parse_and_put_prompt(const char *prmt_ptr)
    17581786{
     1787    const char *p;
    17591788    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);
    17611791    put_prompt();
    17621792}
     
    17641794static void parse_and_put_prompt(const char *prmt_ptr)
    17651795{
    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
    17681801    char flg_not_length = '[';
    1769     char *prmt_mem_ptr = xzalloc(1);
    1770     char *cwd_buf = xrealloc_getcwd_or_warn(NULL);
    17711802    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 */
    17801805
    17811806    cbuf[1] = '\0'; /* never changes */
    17821807
    17831808    while (*prmt_ptr) {
     1809        char timebuf[sizeof("HH:MM:SS")];
    17841810        char *free_me = NULL;
     1811        char *pbuf;
     1812        char c;
    17851813
    17861814        pbuf = cbuf;
    17871815        c = *prmt_ptr++;
    17881816        if (c == '\\') {
    1789             const char *cp = prmt_ptr;
     1817            const char *cp;
    17901818            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);
    17931861            if (prmt_ptr == cp) {
    17941862                if (*cp == '\0')
     
    18021870                    break;
    18031871# endif
     1872                case 'H':
    18041873                case 'h':
    18051874                    pbuf = free_me = safe_gethostname();
    1806                     *strchrnul(pbuf, '.') = '\0';
     1875                    if (c == 'h')
     1876                        strchrnul(pbuf, '.')[0] = '\0';
    18071877                    break;
    18081878                case '$':
    18091879                    c = (geteuid() == 0 ? '#' : '$');
    18101880                    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;
    18111889# 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                    }
    18141909                    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;
    18231915                    break;
    18241916# 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;
    18371921                case 'x': case 'X': {
    18381922                    char buf2[4];
     
    18561940                case '[': case ']':
    18571941                    if (c == flg_not_length) {
    1858                         flg_not_length = (flg_not_length == '[' ? ']' : '[');
     1942                        /* Toggle '['/']' hex 5b/5d */
     1943                        flg_not_length ^= 6;
    18591944                        continue;
    18601945                    }
     
    18641949        } /* if */
    18651950        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);
    18711967        free(free_me);
    18721968    } /* while */
    18731969
     1970# if ENABLE_USERNAME_OR_HOMEDIR
    18741971    if (cwd_buf != (char *)bb_msg_unknown)
    18751972        free(cwd_buf);
     1973# endif
    18761974    cmdedit_prompt = prmt_mem_ptr;
    18771975    put_prompt();
     
    19352033            if (cursor == 0) { /* otherwise it may be bogus */
    19362034                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 */
    19382044                    cmdedit_x += (col - cmdedit_prmt_len);
    19392045                    while (cmdedit_x >= cmdedit_termw) {
     
    20262132    const char *matched_history_line;
    20272133    const char *saved_prompt;
     2134    unsigned saved_prmt_len;
    20282135    int32_t ic;
    20292136
     
    20342141    /* Save and replace the prompt */
    20352142    saved_prompt = cmdedit_prompt;
     2143    saved_prmt_len = cmdedit_prmt_len;
    20362144    goto set_prompt;
    20372145
     
    21092217 set_prompt:
    21102218                    cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf);
    2111                     cmdedit_prmt_len = strlen(cmdedit_prompt);
     2219                    cmdedit_prmt_len = unicode_strwidth(cmdedit_prompt);
    21122220                    goto do_redraw;
    21132221                }
     
    21312239    free((char*)cmdedit_prompt);
    21322240    cmdedit_prompt = saved_prompt;
    2133     cmdedit_prmt_len = strlen(cmdedit_prompt);
     2241    cmdedit_prmt_len = saved_prmt_len;
    21342242    redraw(cmdedit_y, command_len - cursor);
    21352243
     
    21612269
    21622270    if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
    2163      || !(initial_settings.c_lflag & ECHO)
     2271     || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON
    21642272    ) {
    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         */
    21662278        parse_and_put_prompt(prompt);
    21672279        /* fflush_all(); - done by parse_and_put_prompt */
     
    25122624             * Often, Alt-<key> generates ESC-<key>.
    25132625             */
    2514             ic = lineedit_read_key(read_key_buffer, timeout);
     2626            ic = lineedit_read_key(read_key_buffer, 50);
    25152627            switch (ic) {
    25162628                //case KEYCODE_LEFT: - bash doesn't do this
     
    26992811#endif
    27002812
    2701     if (command_len > 0)
     2813    if (command_len > 0) {
    27022814        remember_in_history(command);
     2815    }
    27032816
    27042817    if (break_out > 0) {
Note: See TracChangeset for help on using the changeset viewer.