Commit 7e2515e87c41e2e658aaed466e11cbdf1ea8bcb1

Authored by bellard
1 parent 3d2cfdf1

separated readline from monitor code - added password input support - added output buffer


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1034 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 521 additions and 385 deletions
monitor.c
... ... @@ -32,36 +32,6 @@
32 32 #define offsetof(type, field) ((size_t) &((type *)0)->field)
33 33 #endif
34 34  
35   -#define TERM_CMD_BUF_SIZE 4095
36   -#define TERM_MAX_CMDS 64
37   -#define NB_COMPLETIONS_MAX 256
38   -
39   -#define IS_NORM 0
40   -#define IS_ESC 1
41   -#define IS_CSI 2
42   -
43   -#define printf do_not_use_printf
44   -
45   -static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
46   -static int term_cmd_buf_index;
47   -static int term_cmd_buf_size;
48   -
49   -static char term_last_cmd_buf[TERM_CMD_BUF_SIZE + 1];
50   -static int term_last_cmd_buf_index;
51   -static int term_last_cmd_buf_size;
52   -
53   -static int term_esc_state;
54   -static int term_esc_param;
55   -
56   -static char *term_history[TERM_MAX_CMDS];
57   -static int term_hist_entry;
58   -static CharDriverState *monitor_hd;
59   -
60   -static int nb_completions;
61   -static int completion_index;
62   -static char *completions[NB_COMPLETIONS_MAX];
63   -
64   -
65 35 /*
66 36 * Supported types:
67 37 *
... ... @@ -83,23 +53,52 @@ typedef struct term_cmd_t {
83 53 const char *help;
84 54 } term_cmd_t;
85 55  
  56 +static CharDriverState *monitor_hd;
  57 +
86 58 static term_cmd_t term_cmds[];
87 59 static term_cmd_t info_cmds[];
88 60  
89   -static void add_completion(const char *str);
  61 +static char term_outbuf[1024];
  62 +static int term_outbuf_index;
90 63  
91   -void term_printf(const char *fmt, ...)
  64 +static void monitor_start_input(void);
  65 +
  66 +void term_flush(void)
  67 +{
  68 + if (term_outbuf_index > 0) {
  69 + qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index);
  70 + term_outbuf_index = 0;
  71 + }
  72 +}
  73 +
  74 +/* flush at every end of line or if the buffer is full */
  75 +void term_puts(const char *str)
  76 +{
  77 + int c;
  78 + for(;;) {
  79 + c = *str++;
  80 + if (c == '\0')
  81 + break;
  82 + term_outbuf[term_outbuf_index++] = c;
  83 + if (term_outbuf_index >= sizeof(term_outbuf) ||
  84 + c == '\n')
  85 + term_flush();
  86 + }
  87 +}
  88 +
  89 +void term_vprintf(const char *fmt, va_list ap)
92 90 {
93 91 char buf[4096];
94   - va_list ap;
95   - va_start(ap, fmt);
96 92 vsnprintf(buf, sizeof(buf), fmt, ap);
97   - qemu_chr_write(monitor_hd, buf, strlen(buf));
98   - va_end(ap);
  93 + term_puts(buf);
99 94 }
100 95  
101   -void term_flush(void)
  96 +void term_printf(const char *fmt, ...)
102 97 {
  98 + va_list ap;
  99 + va_start(ap, fmt);
  100 + term_vprintf(fmt, ap);
  101 + va_end(ap);
103 102 }
104 103  
105 104 static int compare_cmd(const char *name, const char *list)
... ... @@ -159,8 +158,9 @@ static void do_commit(void)
159 158 int i;
160 159  
161 160 for (i = 0; i < MAX_DISKS; i++) {
162   - if (bs_table[i])
  161 + if (bs_table[i]) {
163 162 bdrv_commit(bs_table[i]);
  163 + }
164 164 }
165 165 }
166 166  
... ... @@ -215,11 +215,14 @@ static void do_info_registers(void)
215 215 static void do_info_history (void)
216 216 {
217 217 int i;
218   -
219   - for (i = 0; i < TERM_MAX_CMDS; i++) {
220   - if (term_history[i] == NULL)
221   - break;
222   - term_printf("%d: '%s'\n", i, term_history[i]);
  218 + const char *str;
  219 +
  220 + i = 0;
  221 + for(;;) {
  222 + str = readline_get_history(i);
  223 + if (!str)
  224 + break;
  225 + term_printf("%d: '%s'\n", i, str);
223 226 }
224 227 }
225 228  
... ... @@ -261,6 +264,8 @@ static void do_eject(int force, const char *filename)
261 264 static void do_change(const char *device, const char *filename)
262 265 {
263 266 BlockDriverState *bs;
  267 + int i;
  268 + char password[256];
264 269  
265 270 bs = bdrv_find(device);
266 271 if (!bs) {
... ... @@ -270,6 +275,15 @@ static void do_change(const char *device, const char *filename)
270 275 if (eject_device(bs, 0) < 0)
271 276 return;
272 277 bdrv_open(bs, filename, 0);
  278 + if (bdrv_is_encrypted(bs)) {
  279 + term_printf("%s is encrypted.\n", device);
  280 + for(i = 0; i < 3; i++) {
  281 + monitor_readline("Password: ", 1, password, sizeof(password));
  282 + if (bdrv_set_key(bs, password) == 0)
  283 + break;
  284 + term_printf("invalid password\n");
  285 + }
  286 + }
273 287 }
274 288  
275 289 static void do_screen_dump(const char *filename)
... ... @@ -1178,7 +1192,7 @@ static int default_fmt_size = 4;
1178 1192  
1179 1193 #define MAX_ARGS 16
1180 1194  
1181   -static void term_handle_command(const char *cmdline)
  1195 +static void monitor_handle_command(const char *cmdline)
1182 1196 {
1183 1197 const char *p, *pstart, *typestr;
1184 1198 char *q;
... ... @@ -1577,7 +1591,7 @@ static void parse_cmdline(const char *cmdline,
1577 1591 *pnb_args = nb_args;
1578 1592 }
1579 1593  
1580   -static void find_completion(const char *cmdline)
  1594 +void readline_find_completion(const char *cmdline)
1581 1595 {
1582 1596 const char *cmdname;
1583 1597 char *args[MAX_ARGS];
... ... @@ -1646,368 +1660,65 @@ static void find_completion(const char *cmdline)
1646 1660 qemu_free(args[i]);
1647 1661 }
1648 1662  
1649   -static void term_show_prompt2(void)
1650   -{
1651   - term_printf("(qemu) ");
1652   - fflush(stdout);
1653   - term_last_cmd_buf_index = 0;
1654   - term_last_cmd_buf_size = 0;
1655   - term_esc_state = IS_NORM;
1656   -}
1657   -
1658   -static void term_show_prompt(void)
1659   -{
1660   - term_show_prompt2();
1661   - term_cmd_buf_index = 0;
1662   - term_cmd_buf_size = 0;
1663   -}
1664   -
1665   -/* update the displayed command line */
1666   -static void term_update(void)
1667   -{
1668   - int i, delta;
1669   -
1670   - if (term_cmd_buf_size != term_last_cmd_buf_size ||
1671   - memcmp(term_cmd_buf, term_last_cmd_buf, term_cmd_buf_size) != 0) {
1672   - for(i = 0; i < term_last_cmd_buf_index; i++) {
1673   - term_printf("\033[D");
1674   - }
1675   - term_cmd_buf[term_cmd_buf_size] = '\0';
1676   - term_printf("%s", term_cmd_buf);
1677   - term_printf("\033[K");
1678   - memcpy(term_last_cmd_buf, term_cmd_buf, term_cmd_buf_size);
1679   - term_last_cmd_buf_size = term_cmd_buf_size;
1680   - term_last_cmd_buf_index = term_cmd_buf_size;
1681   - }
1682   - if (term_cmd_buf_index != term_last_cmd_buf_index) {
1683   - delta = term_cmd_buf_index - term_last_cmd_buf_index;
1684   - if (delta > 0) {
1685   - for(i = 0;i < delta; i++) {
1686   - term_printf("\033[C");
1687   - }
1688   - } else {
1689   - delta = -delta;
1690   - for(i = 0;i < delta; i++) {
1691   - term_printf("\033[D");
1692   - }
1693   - }
1694   - term_last_cmd_buf_index = term_cmd_buf_index;
1695   - }
1696   - term_flush();
1697   -}
1698   -
1699   -static void term_insert_char(int ch)
1700   -{
1701   - if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
1702   - memmove(term_cmd_buf + term_cmd_buf_index + 1,
1703   - term_cmd_buf + term_cmd_buf_index,
1704   - term_cmd_buf_size - term_cmd_buf_index);
1705   - term_cmd_buf[term_cmd_buf_index] = ch;
1706   - term_cmd_buf_size++;
1707   - term_cmd_buf_index++;
1708   - }
1709   -}
1710   -
1711   -static void term_backward_char(void)
1712   -{
1713   - if (term_cmd_buf_index > 0) {
1714   - term_cmd_buf_index--;
1715   - }
1716   -}
1717   -
1718   -static void term_forward_char(void)
1719   -{
1720   - if (term_cmd_buf_index < term_cmd_buf_size) {
1721   - term_cmd_buf_index++;
1722   - }
1723   -}
1724   -
1725   -static void term_delete_char(void)
1726   -{
1727   - if (term_cmd_buf_index < term_cmd_buf_size) {
1728   - memmove(term_cmd_buf + term_cmd_buf_index,
1729   - term_cmd_buf + term_cmd_buf_index + 1,
1730   - term_cmd_buf_size - term_cmd_buf_index - 1);
1731   - term_cmd_buf_size--;
1732   - }
1733   -}
1734   -
1735   -static void term_backspace(void)
  1663 +static int term_can_read(void *opaque)
1736 1664 {
1737   - if (term_cmd_buf_index > 0) {
1738   - term_backward_char();
1739   - term_delete_char();
1740   - }
  1665 + return 128;
1741 1666 }
1742 1667  
1743   -static void term_bol(void)
  1668 +static void term_read(void *opaque, const uint8_t *buf, int size)
1744 1669 {
1745   - term_cmd_buf_index = 0;
  1670 + int i;
  1671 + for(i = 0; i < size; i++)
  1672 + readline_handle_byte(buf[i]);
1746 1673 }
1747 1674  
1748   -static void term_eol(void)
1749   -{
1750   - term_cmd_buf_index = term_cmd_buf_size;
1751   -}
  1675 +static void monitor_start_input(void);
1752 1676  
1753   -static void term_up_char(void)
  1677 +static void monitor_handle_command1(void *opaque, const char *cmdline)
1754 1678 {
1755   - int idx;
1756   -
1757   - if (term_hist_entry == 0)
1758   - return;
1759   - if (term_hist_entry == -1) {
1760   - /* Find latest entry */
1761   - for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
1762   - if (term_history[idx] == NULL)
1763   - break;
1764   - }
1765   - term_hist_entry = idx;
1766   - }
1767   - term_hist_entry--;
1768   - if (term_hist_entry >= 0) {
1769   - pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
1770   - term_history[term_hist_entry]);
1771   - term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
1772   - }
  1679 + monitor_handle_command(cmdline);
  1680 + monitor_start_input();
1773 1681 }
1774 1682  
1775   -static void term_down_char(void)
  1683 +static void monitor_start_input(void)
1776 1684 {
1777   - if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1)
1778   - return;
1779   - if (term_history[++term_hist_entry] != NULL) {
1780   - pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
1781   - term_history[term_hist_entry]);
1782   - } else {
1783   - term_hist_entry = -1;
1784   - }
1785   - term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
  1685 + readline_start("(qemu) ", 0, monitor_handle_command1, NULL);
1786 1686 }
1787 1687  
1788   -static void term_hist_add(const char *cmdline)
  1688 +void monitor_init(CharDriverState *hd, int show_banner)
1789 1689 {
1790   - char *hist_entry, *new_entry;
1791   - int idx;
1792   -
1793   - if (cmdline[0] == '\0')
1794   - return;
1795   - new_entry = NULL;
1796   - if (term_hist_entry != -1) {
1797   - /* We were editing an existing history entry: replace it */
1798   - hist_entry = term_history[term_hist_entry];
1799   - idx = term_hist_entry;
1800   - if (strcmp(hist_entry, cmdline) == 0) {
1801   - goto same_entry;
1802   - }
1803   - }
1804   - /* Search cmdline in history buffers */
1805   - for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
1806   - hist_entry = term_history[idx];
1807   - if (hist_entry == NULL)
1808   - break;
1809   - if (strcmp(hist_entry, cmdline) == 0) {
1810   - same_entry:
1811   - new_entry = hist_entry;
1812   - /* Put this entry at the end of history */
1813   - memmove(&term_history[idx], &term_history[idx + 1],
1814   - &term_history[TERM_MAX_CMDS] - &term_history[idx + 1]);
1815   - term_history[TERM_MAX_CMDS - 1] = NULL;
1816   - for (; idx < TERM_MAX_CMDS; idx++) {
1817   - if (term_history[idx] == NULL)
1818   - break;
1819   - }
1820   - break;
1821   - }
1822   - }
1823   - if (idx == TERM_MAX_CMDS) {
1824   - /* Need to get one free slot */
1825   - free(term_history[0]);
1826   - memcpy(term_history, &term_history[1],
1827   - &term_history[TERM_MAX_CMDS] - &term_history[1]);
1828   - term_history[TERM_MAX_CMDS - 1] = NULL;
1829   - idx = TERM_MAX_CMDS - 1;
  1690 + monitor_hd = hd;
  1691 + if (show_banner) {
  1692 + term_printf("QEMU %s monitor - type 'help' for more information\n",
  1693 + QEMU_VERSION);
1830 1694 }
1831   - if (new_entry == NULL)
1832   - new_entry = strdup(cmdline);
1833   - term_history[idx] = new_entry;
1834   - term_hist_entry = -1;
  1695 + qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL);
  1696 + monitor_start_input();
1835 1697 }
1836 1698  
1837   -/* completion support */
1838   -
1839   -static void add_completion(const char *str)
1840   -{
1841   - if (nb_completions < NB_COMPLETIONS_MAX) {
1842   - completions[nb_completions++] = qemu_strdup(str);
1843   - }
1844   -}
  1699 +/* XXX: use threads ? */
  1700 +/* modal monitor readline */
  1701 +static int monitor_readline_started;
  1702 +static char *monitor_readline_buf;
  1703 +static int monitor_readline_buf_size;
1845 1704  
1846   -static void term_completion(void)
  1705 +static void monitor_readline_cb(void *opaque, const char *input)
1847 1706 {
1848   - int len, i, j, max_width, nb_cols;
1849   - char *cmdline;
1850   -
1851   - nb_completions = 0;
1852   -
1853   - cmdline = qemu_malloc(term_cmd_buf_index + 1);
1854   - if (!cmdline)
1855   - return;
1856   - memcpy(cmdline, term_cmd_buf, term_cmd_buf_index);
1857   - cmdline[term_cmd_buf_index] = '\0';
1858   - find_completion(cmdline);
1859   - qemu_free(cmdline);
1860   -
1861   - /* no completion found */
1862   - if (nb_completions <= 0)
1863   - return;
1864   - if (nb_completions == 1) {
1865   - len = strlen(completions[0]);
1866   - for(i = completion_index; i < len; i++) {
1867   - term_insert_char(completions[0][i]);
1868   - }
1869   - /* extra space for next argument. XXX: make it more generic */
1870   - if (len > 0 && completions[0][len - 1] != '/')
1871   - term_insert_char(' ');
1872   - } else {
1873   - term_printf("\n");
1874   - max_width = 0;
1875   - for(i = 0; i < nb_completions; i++) {
1876   - len = strlen(completions[i]);
1877   - if (len > max_width)
1878   - max_width = len;
1879   - }
1880   - max_width += 2;
1881   - if (max_width < 10)
1882   - max_width = 10;
1883   - else if (max_width > 80)
1884   - max_width = 80;
1885   - nb_cols = 80 / max_width;
1886   - j = 0;
1887   - for(i = 0; i < nb_completions; i++) {
1888   - term_printf("%-*s", max_width, completions[i]);
1889   - if (++j == nb_cols || i == (nb_completions - 1)) {
1890   - term_printf("\n");
1891   - j = 0;
1892   - }
1893   - }
1894   - term_show_prompt2();
1895   - }
  1707 + pstrcpy(monitor_readline_buf, monitor_readline_buf_size, input);
  1708 + monitor_readline_started = 0;
1896 1709 }
1897 1710  
1898   -/* return true if command handled */
1899   -static void term_handle_byte(int ch)
  1711 +void monitor_readline(const char *prompt, int is_password,
  1712 + char *buf, int buf_size)
1900 1713 {
1901   - switch(term_esc_state) {
1902   - case IS_NORM:
1903   - switch(ch) {
1904   - case 1:
1905   - term_bol();
1906   - break;
1907   - case 4:
1908   - term_delete_char();
1909   - break;
1910   - case 5:
1911   - term_eol();
1912   - break;
1913   - case 9:
1914   - term_completion();
1915   - break;
1916   - case 10:
1917   - case 13:
1918   - term_cmd_buf[term_cmd_buf_size] = '\0';
1919   - term_hist_add(term_cmd_buf);
1920   - term_printf("\n");
1921   - term_handle_command(term_cmd_buf);
1922   - term_show_prompt();
1923   - break;
1924   - case 27:
1925   - term_esc_state = IS_ESC;
1926   - break;
1927   - case 127:
1928   - case 8:
1929   - term_backspace();
1930   - break;
1931   - case 155:
1932   - term_esc_state = IS_CSI;
1933   - break;
1934   - default:
1935   - if (ch >= 32) {
1936   - term_insert_char(ch);
1937   - }
1938   - break;
1939   - }
1940   - break;
1941   - case IS_ESC:
1942   - if (ch == '[') {
1943   - term_esc_state = IS_CSI;
1944   - term_esc_param = 0;
1945   - } else {
1946   - term_esc_state = IS_NORM;
1947   - }
1948   - break;
1949   - case IS_CSI:
1950   - switch(ch) {
1951   - case 'A':
1952   - case 'F':
1953   - term_up_char();
1954   - break;
1955   - case 'B':
1956   - case 'E':
1957   - term_down_char();
1958   - break;
1959   - case 'D':
1960   - term_backward_char();
1961   - break;
1962   - case 'C':
1963   - term_forward_char();
1964   - break;
1965   - case '0' ... '9':
1966   - term_esc_param = term_esc_param * 10 + (ch - '0');
1967   - goto the_end;
1968   - case '~':
1969   - switch(term_esc_param) {
1970   - case 1:
1971   - term_bol();
1972   - break;
1973   - case 3:
1974   - term_delete_char();
1975   - break;
1976   - case 4:
1977   - term_eol();
1978   - break;
1979   - }
1980   - break;
1981   - default:
1982   - break;
1983   - }
1984   - term_esc_state = IS_NORM;
1985   - the_end:
1986   - break;
  1714 + if (is_password) {
  1715 + qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS);
1987 1716 }
1988   - term_update();
1989   -}
1990   -
1991   -static int term_can_read(void *opaque)
1992   -{
1993   - return 128;
1994   -}
1995   -
1996   -static void term_read(void *opaque, const uint8_t *buf, int size)
1997   -{
1998   - int i;
1999   - for(i = 0; i < size; i++)
2000   - term_handle_byte(buf[i]);
2001   -}
2002   -
2003   -void monitor_init(CharDriverState *hd, int show_banner)
2004   -{
2005   - monitor_hd = hd;
2006   - if (show_banner) {
2007   - term_printf("QEMU %s monitor - type 'help' for more information\n",
2008   - QEMU_VERSION);
2009   - term_show_prompt();
  1717 + readline_start(prompt, is_password, monitor_readline_cb, NULL);
  1718 + monitor_readline_buf = buf;
  1719 + monitor_readline_buf_size = buf_size;
  1720 + monitor_readline_started = 1;
  1721 + while (monitor_readline_started) {
  1722 + main_loop_wait(10);
2010 1723 }
2011   - term_hist_entry = -1;
2012   - qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL);
2013 1724 }
... ...
readline.c 0 โ†’ 100644
  1 +/*
  2 + * QEMU readline utility
  3 + *
  4 + * Copyright (c) 2003-2004 Fabrice Bellard
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include "vl.h"
  25 +
  26 +#define TERM_CMD_BUF_SIZE 4095
  27 +#define TERM_MAX_CMDS 64
  28 +#define NB_COMPLETIONS_MAX 256
  29 +
  30 +#define IS_NORM 0
  31 +#define IS_ESC 1
  32 +#define IS_CSI 2
  33 +
  34 +#define printf do_not_use_printf
  35 +
  36 +static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
  37 +static int term_cmd_buf_index;
  38 +static int term_cmd_buf_size;
  39 +
  40 +static char term_last_cmd_buf[TERM_CMD_BUF_SIZE + 1];
  41 +static int term_last_cmd_buf_index;
  42 +static int term_last_cmd_buf_size;
  43 +
  44 +static int term_esc_state;
  45 +static int term_esc_param;
  46 +
  47 +static char *term_history[TERM_MAX_CMDS];
  48 +static int term_hist_entry = -1;
  49 +
  50 +static int nb_completions;
  51 +int completion_index;
  52 +static char *completions[NB_COMPLETIONS_MAX];
  53 +
  54 +static ReadLineFunc *term_readline_func;
  55 +static int term_is_password;
  56 +static char term_prompt[256];
  57 +static void *term_readline_opaque;
  58 +
  59 +static void term_show_prompt2(void)
  60 +{
  61 + term_printf("%s", term_prompt);
  62 + term_flush();
  63 + term_last_cmd_buf_index = 0;
  64 + term_last_cmd_buf_size = 0;
  65 + term_esc_state = IS_NORM;
  66 +}
  67 +
  68 +static void term_show_prompt(void)
  69 +{
  70 + term_show_prompt2();
  71 + term_cmd_buf_index = 0;
  72 + term_cmd_buf_size = 0;
  73 +}
  74 +
  75 +/* update the displayed command line */
  76 +static void term_update(void)
  77 +{
  78 + int i, delta, len;
  79 +
  80 + if (term_cmd_buf_size != term_last_cmd_buf_size ||
  81 + memcmp(term_cmd_buf, term_last_cmd_buf, term_cmd_buf_size) != 0) {
  82 + for(i = 0; i < term_last_cmd_buf_index; i++) {
  83 + term_printf("\033[D");
  84 + }
  85 + term_cmd_buf[term_cmd_buf_size] = '\0';
  86 + if (term_is_password) {
  87 + len = strlen(term_cmd_buf);
  88 + for(i = 0; i < len; i++)
  89 + term_printf("*");
  90 + } else {
  91 + term_printf("%s", term_cmd_buf);
  92 + }
  93 + term_printf("\033[K");
  94 + memcpy(term_last_cmd_buf, term_cmd_buf, term_cmd_buf_size);
  95 + term_last_cmd_buf_size = term_cmd_buf_size;
  96 + term_last_cmd_buf_index = term_cmd_buf_size;
  97 + }
  98 + if (term_cmd_buf_index != term_last_cmd_buf_index) {
  99 + delta = term_cmd_buf_index - term_last_cmd_buf_index;
  100 + if (delta > 0) {
  101 + for(i = 0;i < delta; i++) {
  102 + term_printf("\033[C");
  103 + }
  104 + } else {
  105 + delta = -delta;
  106 + for(i = 0;i < delta; i++) {
  107 + term_printf("\033[D");
  108 + }
  109 + }
  110 + term_last_cmd_buf_index = term_cmd_buf_index;
  111 + }
  112 + term_flush();
  113 +}
  114 +
  115 +static void term_insert_char(int ch)
  116 +{
  117 + if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
  118 + memmove(term_cmd_buf + term_cmd_buf_index + 1,
  119 + term_cmd_buf + term_cmd_buf_index,
  120 + term_cmd_buf_size - term_cmd_buf_index);
  121 + term_cmd_buf[term_cmd_buf_index] = ch;
  122 + term_cmd_buf_size++;
  123 + term_cmd_buf_index++;
  124 + }
  125 +}
  126 +
  127 +static void term_backward_char(void)
  128 +{
  129 + if (term_cmd_buf_index > 0) {
  130 + term_cmd_buf_index--;
  131 + }
  132 +}
  133 +
  134 +static void term_forward_char(void)
  135 +{
  136 + if (term_cmd_buf_index < term_cmd_buf_size) {
  137 + term_cmd_buf_index++;
  138 + }
  139 +}
  140 +
  141 +static void term_delete_char(void)
  142 +{
  143 + if (term_cmd_buf_index < term_cmd_buf_size) {
  144 + memmove(term_cmd_buf + term_cmd_buf_index,
  145 + term_cmd_buf + term_cmd_buf_index + 1,
  146 + term_cmd_buf_size - term_cmd_buf_index - 1);
  147 + term_cmd_buf_size--;
  148 + }
  149 +}
  150 +
  151 +static void term_backspace(void)
  152 +{
  153 + if (term_cmd_buf_index > 0) {
  154 + term_backward_char();
  155 + term_delete_char();
  156 + }
  157 +}
  158 +
  159 +static void term_bol(void)
  160 +{
  161 + term_cmd_buf_index = 0;
  162 +}
  163 +
  164 +static void term_eol(void)
  165 +{
  166 + term_cmd_buf_index = term_cmd_buf_size;
  167 +}
  168 +
  169 +static void term_up_char(void)
  170 +{
  171 + int idx;
  172 +
  173 + if (term_hist_entry == 0)
  174 + return;
  175 + if (term_hist_entry == -1) {
  176 + /* Find latest entry */
  177 + for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
  178 + if (term_history[idx] == NULL)
  179 + break;
  180 + }
  181 + term_hist_entry = idx;
  182 + }
  183 + term_hist_entry--;
  184 + if (term_hist_entry >= 0) {
  185 + pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
  186 + term_history[term_hist_entry]);
  187 + term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
  188 + }
  189 +}
  190 +
  191 +static void term_down_char(void)
  192 +{
  193 + if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1)
  194 + return;
  195 + if (term_history[++term_hist_entry] != NULL) {
  196 + pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
  197 + term_history[term_hist_entry]);
  198 + } else {
  199 + term_hist_entry = -1;
  200 + }
  201 + term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
  202 +}
  203 +
  204 +static void term_hist_add(const char *cmdline)
  205 +{
  206 + char *hist_entry, *new_entry;
  207 + int idx;
  208 +
  209 + if (cmdline[0] == '\0')
  210 + return;
  211 + new_entry = NULL;
  212 + if (term_hist_entry != -1) {
  213 + /* We were editing an existing history entry: replace it */
  214 + hist_entry = term_history[term_hist_entry];
  215 + idx = term_hist_entry;
  216 + if (strcmp(hist_entry, cmdline) == 0) {
  217 + goto same_entry;
  218 + }
  219 + }
  220 + /* Search cmdline in history buffers */
  221 + for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
  222 + hist_entry = term_history[idx];
  223 + if (hist_entry == NULL)
  224 + break;
  225 + if (strcmp(hist_entry, cmdline) == 0) {
  226 + same_entry:
  227 + new_entry = hist_entry;
  228 + /* Put this entry at the end of history */
  229 + memmove(&term_history[idx], &term_history[idx + 1],
  230 + &term_history[TERM_MAX_CMDS] - &term_history[idx + 1]);
  231 + term_history[TERM_MAX_CMDS - 1] = NULL;
  232 + for (; idx < TERM_MAX_CMDS; idx++) {
  233 + if (term_history[idx] == NULL)
  234 + break;
  235 + }
  236 + break;
  237 + }
  238 + }
  239 + if (idx == TERM_MAX_CMDS) {
  240 + /* Need to get one free slot */
  241 + free(term_history[0]);
  242 + memcpy(term_history, &term_history[1],
  243 + &term_history[TERM_MAX_CMDS] - &term_history[1]);
  244 + term_history[TERM_MAX_CMDS - 1] = NULL;
  245 + idx = TERM_MAX_CMDS - 1;
  246 + }
  247 + if (new_entry == NULL)
  248 + new_entry = strdup(cmdline);
  249 + term_history[idx] = new_entry;
  250 + term_hist_entry = -1;
  251 +}
  252 +
  253 +/* completion support */
  254 +
  255 +void add_completion(const char *str)
  256 +{
  257 + if (nb_completions < NB_COMPLETIONS_MAX) {
  258 + completions[nb_completions++] = qemu_strdup(str);
  259 + }
  260 +}
  261 +
  262 +static void term_completion(void)
  263 +{
  264 + int len, i, j, max_width, nb_cols;
  265 + char *cmdline;
  266 +
  267 + nb_completions = 0;
  268 +
  269 + cmdline = qemu_malloc(term_cmd_buf_index + 1);
  270 + if (!cmdline)
  271 + return;
  272 + memcpy(cmdline, term_cmd_buf, term_cmd_buf_index);
  273 + cmdline[term_cmd_buf_index] = '\0';
  274 + readline_find_completion(cmdline);
  275 + qemu_free(cmdline);
  276 +
  277 + /* no completion found */
  278 + if (nb_completions <= 0)
  279 + return;
  280 + if (nb_completions == 1) {
  281 + len = strlen(completions[0]);
  282 + for(i = completion_index; i < len; i++) {
  283 + term_insert_char(completions[0][i]);
  284 + }
  285 + /* extra space for next argument. XXX: make it more generic */
  286 + if (len > 0 && completions[0][len - 1] != '/')
  287 + term_insert_char(' ');
  288 + } else {
  289 + term_printf("\n");
  290 + max_width = 0;
  291 + for(i = 0; i < nb_completions; i++) {
  292 + len = strlen(completions[i]);
  293 + if (len > max_width)
  294 + max_width = len;
  295 + }
  296 + max_width += 2;
  297 + if (max_width < 10)
  298 + max_width = 10;
  299 + else if (max_width > 80)
  300 + max_width = 80;
  301 + nb_cols = 80 / max_width;
  302 + j = 0;
  303 + for(i = 0; i < nb_completions; i++) {
  304 + term_printf("%-*s", max_width, completions[i]);
  305 + if (++j == nb_cols || i == (nb_completions - 1)) {
  306 + term_printf("\n");
  307 + j = 0;
  308 + }
  309 + }
  310 + term_show_prompt2();
  311 + }
  312 +}
  313 +
  314 +/* return true if command handled */
  315 +void readline_handle_byte(int ch)
  316 +{
  317 + switch(term_esc_state) {
  318 + case IS_NORM:
  319 + switch(ch) {
  320 + case 1:
  321 + term_bol();
  322 + break;
  323 + case 4:
  324 + term_delete_char();
  325 + break;
  326 + case 5:
  327 + term_eol();
  328 + break;
  329 + case 9:
  330 + term_completion();
  331 + break;
  332 + case 10:
  333 + case 13:
  334 + term_cmd_buf[term_cmd_buf_size] = '\0';
  335 + if (!term_is_password)
  336 + term_hist_add(term_cmd_buf);
  337 + term_printf("\n");
  338 + /* NOTE: readline_start can be called here */
  339 + term_readline_func(term_readline_opaque, term_cmd_buf);
  340 + break;
  341 + case 27:
  342 + term_esc_state = IS_ESC;
  343 + break;
  344 + case 127:
  345 + case 8:
  346 + term_backspace();
  347 + break;
  348 + case 155:
  349 + term_esc_state = IS_CSI;
  350 + break;
  351 + default:
  352 + if (ch >= 32) {
  353 + term_insert_char(ch);
  354 + }
  355 + break;
  356 + }
  357 + break;
  358 + case IS_ESC:
  359 + if (ch == '[') {
  360 + term_esc_state = IS_CSI;
  361 + term_esc_param = 0;
  362 + } else {
  363 + term_esc_state = IS_NORM;
  364 + }
  365 + break;
  366 + case IS_CSI:
  367 + switch(ch) {
  368 + case 'A':
  369 + case 'F':
  370 + term_up_char();
  371 + break;
  372 + case 'B':
  373 + case 'E':
  374 + term_down_char();
  375 + break;
  376 + case 'D':
  377 + term_backward_char();
  378 + break;
  379 + case 'C':
  380 + term_forward_char();
  381 + break;
  382 + case '0' ... '9':
  383 + term_esc_param = term_esc_param * 10 + (ch - '0');
  384 + goto the_end;
  385 + case '~':
  386 + switch(term_esc_param) {
  387 + case 1:
  388 + term_bol();
  389 + break;
  390 + case 3:
  391 + term_delete_char();
  392 + break;
  393 + case 4:
  394 + term_eol();
  395 + break;
  396 + }
  397 + break;
  398 + default:
  399 + break;
  400 + }
  401 + term_esc_state = IS_NORM;
  402 + the_end:
  403 + break;
  404 + }
  405 + term_update();
  406 +}
  407 +
  408 +void readline_start(const char *prompt, int is_password,
  409 + ReadLineFunc *readline_func, void *opaque)
  410 +{
  411 + pstrcpy(term_prompt, sizeof(term_prompt), prompt);
  412 + term_readline_func = readline_func;
  413 + term_readline_opaque = opaque;
  414 + term_is_password = is_password;
  415 + term_show_prompt();
  416 +}
  417 +
  418 +const char *readline_get_history(unsigned int index)
  419 +{
  420 + if (index >= TERM_MAX_CMDS)
  421 + return NULL;
  422 + return term_history[index];
  423 +}
  424 +
  425 +
... ...