Commit 81d0912d2d221c41d649d2c36812afddf74634d2

Authored by bellard
1 parent d1d9f421

completion support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1020 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 348 additions and 113 deletions
@@ -470,6 +470,15 @@ BlockDriverState *bdrv_find(const char *name) @@ -470,6 +470,15 @@ BlockDriverState *bdrv_find(const char *name)
470 return NULL; 470 return NULL;
471 } 471 }
472 472
  473 +void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
  474 +{
  475 + BlockDriverState *bs;
  476 +
  477 + for (bs = bdrv_first; bs != NULL; bs = bs->next) {
  478 + it(opaque, bs->device_name);
  479 + }
  480 +}
  481 +
473 void bdrv_info(void) 482 void bdrv_info(void)
474 { 483 {
475 BlockDriverState *bs; 484 BlockDriverState *bs;
monitor.c
@@ -23,8 +23,10 @@ @@ -23,8 +23,10 @@
23 */ 23 */
24 #include "vl.h" 24 #include "vl.h"
25 #include "disas.h" 25 #include "disas.h"
  26 +#include <dirent.h>
26 27
27 //#define DEBUG 28 //#define DEBUG
  29 +//#define DEBUG_COMPLETION
28 30
29 #ifndef offsetof 31 #ifndef offsetof
30 #define offsetof(type, field) ((size_t) &((type *)0)->field) 32 #define offsetof(type, field) ((size_t) &((type *)0)->field)
@@ -32,6 +34,7 @@ @@ -32,6 +34,7 @@
32 34
33 #define TERM_CMD_BUF_SIZE 4095 35 #define TERM_CMD_BUF_SIZE 4095
34 #define TERM_MAX_CMDS 64 36 #define TERM_MAX_CMDS 64
  37 +#define NB_COMPLETIONS_MAX 256
35 38
36 #define IS_NORM 0 39 #define IS_NORM 0
37 #define IS_ESC 1 40 #define IS_ESC 1
@@ -42,16 +45,28 @@ @@ -42,16 +45,28 @@
42 static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1]; 45 static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
43 static int term_cmd_buf_index; 46 static int term_cmd_buf_index;
44 static int term_cmd_buf_size; 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 +
45 static int term_esc_state; 53 static int term_esc_state;
46 static int term_esc_param; 54 static int term_esc_param;
47 55
48 static char *term_history[TERM_MAX_CMDS]; 56 static char *term_history[TERM_MAX_CMDS];
49 static int term_hist_entry; 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 +
50 64
51 /* 65 /*
52 * Supported types: 66 * Supported types:
53 * 67 *
54 * 'F' filename 68 * 'F' filename
  69 + * 'B' block device name
55 * 's' string (accept optional quote) 70 * 's' string (accept optional quote)
56 * 'i' integer 71 * 'i' integer
57 * '/' optional gdb-like print format (like "/10x") 72 * '/' optional gdb-like print format (like "/10x")
@@ -71,17 +86,20 @@ typedef struct term_cmd_t { @@ -71,17 +86,20 @@ typedef struct term_cmd_t {
71 static term_cmd_t term_cmds[]; 86 static term_cmd_t term_cmds[];
72 static term_cmd_t info_cmds[]; 87 static term_cmd_t info_cmds[];
73 88
  89 +static void add_completion(const char *str);
  90 +
74 void term_printf(const char *fmt, ...) 91 void term_printf(const char *fmt, ...)
75 { 92 {
  93 + char buf[4096];
76 va_list ap; 94 va_list ap;
77 va_start(ap, fmt); 95 va_start(ap, fmt);
78 - vprintf(fmt, ap); 96 + vsnprintf(buf, sizeof(buf), fmt, ap);
  97 + qemu_chr_write(monitor_hd, buf, strlen(buf));
79 va_end(ap); 98 va_end(ap);
80 } 99 }
81 100
82 void term_flush(void) 101 void term_flush(void)
83 { 102 {
84 - fflush(stdout);  
85 } 103 }
86 104
87 static int compare_cmd(const char *name, const char *list) 105 static int compare_cmd(const char *name, const char *list)
@@ -232,8 +250,6 @@ static void do_eject(int force, const char *filename) @@ -232,8 +250,6 @@ static void do_eject(int force, const char *filename)
232 { 250 {
233 BlockDriverState *bs; 251 BlockDriverState *bs;
234 252
235 - term_printf("%d %s\n", force, filename);  
236 -  
237 bs = bdrv_find(filename); 253 bs = bdrv_find(filename);
238 if (!bs) { 254 if (!bs) {
239 term_printf("device not found\n"); 255 term_printf("device not found\n");
@@ -674,9 +690,9 @@ static term_cmd_t term_cmds[] = { @@ -674,9 +690,9 @@ static term_cmd_t term_cmds[] = {
674 "subcommand", "show various information about the system state" }, 690 "subcommand", "show various information about the system state" },
675 { "q|quit", "", do_quit, 691 { "q|quit", "", do_quit,
676 "", "quit the emulator" }, 692 "", "quit the emulator" },
677 - { "eject", "-fs", do_eject, 693 + { "eject", "-fB", do_eject,
678 "[-f] device", "eject a removable media (use -f to force it)" }, 694 "[-f] device", "eject a removable media (use -f to force it)" },
679 - { "change", "sF", do_change, 695 + { "change", "BF", do_change,
680 "device filename", "change a removable media" }, 696 "device filename", "change a removable media" },
681 { "screendump", "F", do_screen_dump, 697 { "screendump", "F", do_screen_dump,
682 "filename", "save screen into PPM image 'filename'" }, 698 "filename", "save screen into PPM image 'filename'" },
@@ -953,6 +969,16 @@ static int expr_unary(void) @@ -953,6 +969,16 @@ static int expr_unary(void)
953 } 969 }
954 next(); 970 next();
955 break; 971 break;
  972 + case '\'':
  973 + pch++;
  974 + if (*pch == '\0')
  975 + expr_error("character constant expected");
  976 + n = *pch;
  977 + pch++;
  978 + if (*pch != '\'')
  979 + expr_error("missing terminating \' character");
  980 + next();
  981 + break;
956 case '$': 982 case '$':
957 { 983 {
958 char buf[128], *q; 984 char buf[128], *q;
@@ -1088,15 +1114,16 @@ static int get_str(char *buf, int buf_size, const char **pp) @@ -1088,15 +1114,16 @@ static int get_str(char *buf, int buf_size, const char **pp)
1088 char *q; 1114 char *q;
1089 int c; 1115 int c;
1090 1116
  1117 + q = buf;
1091 p = *pp; 1118 p = *pp;
1092 while (isspace(*p)) 1119 while (isspace(*p))
1093 p++; 1120 p++;
1094 if (*p == '\0') { 1121 if (*p == '\0') {
1095 fail: 1122 fail:
  1123 + *q = '\0';
1096 *pp = p; 1124 *pp = p;
1097 return -1; 1125 return -1;
1098 } 1126 }
1099 - q = buf;  
1100 if (*p == '\"') { 1127 if (*p == '\"') {
1101 p++; 1128 p++;
1102 while (*p != '\0' && *p != '\"') { 1129 while (*p != '\0' && *p != '\"') {
@@ -1140,8 +1167,8 @@ static int get_str(char *buf, int buf_size, const char **pp) @@ -1140,8 +1167,8 @@ static int get_str(char *buf, int buf_size, const char **pp)
1140 } 1167 }
1141 p++; 1168 p++;
1142 } 1169 }
1143 - *q = '\0';  
1144 } 1170 }
  1171 + *q = '\0';
1145 *pp = p; 1172 *pp = p;
1146 return 0; 1173 return 0;
1147 } 1174 }
@@ -1204,6 +1231,7 @@ static void term_handle_command(const char *cmdline) @@ -1204,6 +1231,7 @@ static void term_handle_command(const char *cmdline)
1204 typestr++; 1231 typestr++;
1205 switch(c) { 1232 switch(c) {
1206 case 'F': 1233 case 'F':
  1234 + case 'B':
1207 case 's': 1235 case 's':
1208 { 1236 {
1209 int ret; 1237 int ret;
@@ -1221,10 +1249,17 @@ static void term_handle_command(const char *cmdline) @@ -1221,10 +1249,17 @@ static void term_handle_command(const char *cmdline)
1221 } 1249 }
1222 ret = get_str(buf, sizeof(buf), &p); 1250 ret = get_str(buf, sizeof(buf), &p);
1223 if (ret < 0) { 1251 if (ret < 0) {
1224 - if (c == 'F') 1252 + switch(c) {
  1253 + case 'F':
1225 term_printf("%s: filename expected\n", cmdname); 1254 term_printf("%s: filename expected\n", cmdname);
1226 - else 1255 + break;
  1256 + case 'B':
  1257 + term_printf("%s: block device name expected\n", cmdname);
  1258 + break;
  1259 + default:
1227 term_printf("%s: string expected\n", cmdname); 1260 term_printf("%s: string expected\n", cmdname);
  1261 + break;
  1262 + }
1228 goto fail; 1263 goto fail;
1229 } 1264 }
1230 str = qemu_malloc(strlen(buf) + 1); 1265 str = qemu_malloc(strlen(buf) + 1);
@@ -1432,19 +1467,232 @@ static void term_handle_command(const char *cmdline) @@ -1432,19 +1467,232 @@ static void term_handle_command(const char *cmdline)
1432 return; 1467 return;
1433 } 1468 }
1434 1469
1435 -static void term_show_prompt(void) 1470 +static void cmd_completion(const char *name, const char *list)
  1471 +{
  1472 + const char *p, *pstart;
  1473 + char cmd[128];
  1474 + int len;
  1475 +
  1476 + p = list;
  1477 + for(;;) {
  1478 + pstart = p;
  1479 + p = strchr(p, '|');
  1480 + if (!p)
  1481 + p = pstart + strlen(pstart);
  1482 + len = p - pstart;
  1483 + if (len > sizeof(cmd) - 2)
  1484 + len = sizeof(cmd) - 2;
  1485 + memcpy(cmd, pstart, len);
  1486 + cmd[len] = '\0';
  1487 + if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
  1488 + add_completion(cmd);
  1489 + }
  1490 + if (*p == '\0')
  1491 + break;
  1492 + p++;
  1493 + }
  1494 +}
  1495 +
  1496 +static void file_completion(const char *input)
  1497 +{
  1498 + DIR *ffs;
  1499 + struct dirent *d;
  1500 + char path[1024];
  1501 + char file[1024], file_prefix[1024];
  1502 + int input_path_len;
  1503 + const char *p;
  1504 +
  1505 + p = strrchr(input, '/');
  1506 + if (!p) {
  1507 + input_path_len = 0;
  1508 + pstrcpy(file_prefix, sizeof(file_prefix), input);
  1509 + strcpy(path, ".");
  1510 + } else {
  1511 + input_path_len = p - input + 1;
  1512 + memcpy(path, input, input_path_len);
  1513 + if (input_path_len > sizeof(path) - 1)
  1514 + input_path_len = sizeof(path) - 1;
  1515 + path[input_path_len] = '\0';
  1516 + pstrcpy(file_prefix, sizeof(file_prefix), p + 1);
  1517 + }
  1518 +#ifdef DEBUG_COMPLETION
  1519 + term_printf("input='%s' path='%s' prefix='%s'\n", input, path, file_prefix);
  1520 +#endif
  1521 + ffs = opendir(path);
  1522 + if (!ffs)
  1523 + return;
  1524 + for(;;) {
  1525 + struct stat sb;
  1526 + d = readdir(ffs);
  1527 + if (!d)
  1528 + break;
  1529 + if (strstart(d->d_name, file_prefix, NULL)) {
  1530 + memcpy(file, input, input_path_len);
  1531 + strcpy(file + input_path_len, d->d_name);
  1532 + /* stat the file to find out if it's a directory.
  1533 + * In that case add a slash to speed up typing long paths
  1534 + */
  1535 + stat(file, &sb);
  1536 + if(S_ISDIR(sb.st_mode))
  1537 + strcat(file, "/");
  1538 + add_completion(file);
  1539 + }
  1540 + }
  1541 + closedir(ffs);
  1542 +}
  1543 +
  1544 +static void block_completion_it(void *opaque, const char *name)
  1545 +{
  1546 + const char *input = opaque;
  1547 +
  1548 + if (input[0] == '\0' ||
  1549 + !strncmp(name, (char *)input, strlen(input))) {
  1550 + add_completion(name);
  1551 + }
  1552 +}
  1553 +
  1554 +/* NOTE: this parser is an approximate form of the real command parser */
  1555 +static void parse_cmdline(const char *cmdline,
  1556 + int *pnb_args, char **args)
  1557 +{
  1558 + const char *p;
  1559 + int nb_args, ret;
  1560 + char buf[1024];
  1561 +
  1562 + p = cmdline;
  1563 + nb_args = 0;
  1564 + for(;;) {
  1565 + while (isspace(*p))
  1566 + p++;
  1567 + if (*p == '\0')
  1568 + break;
  1569 + if (nb_args >= MAX_ARGS)
  1570 + break;
  1571 + ret = get_str(buf, sizeof(buf), &p);
  1572 + args[nb_args] = qemu_strdup(buf);
  1573 + nb_args++;
  1574 + if (ret < 0)
  1575 + break;
  1576 + }
  1577 + *pnb_args = nb_args;
  1578 +}
  1579 +
  1580 +static void find_completion(const char *cmdline)
  1581 +{
  1582 + const char *cmdname;
  1583 + char *args[MAX_ARGS];
  1584 + int nb_args, i, len;
  1585 + const char *ptype, *str;
  1586 + term_cmd_t *cmd;
  1587 +
  1588 + parse_cmdline(cmdline, &nb_args, args);
  1589 +#ifdef DEBUG_COMPLETION
  1590 + for(i = 0; i < nb_args; i++) {
  1591 + term_printf("arg%d = '%s'\n", i, (char *)args[i]);
  1592 + }
  1593 +#endif
  1594 +
  1595 + /* if the line ends with a space, it means we want to complete the
  1596 + next arg */
  1597 + len = strlen(cmdline);
  1598 + if (len > 0 && isspace(cmdline[len - 1])) {
  1599 + if (nb_args >= MAX_ARGS)
  1600 + return;
  1601 + args[nb_args++] = qemu_strdup("");
  1602 + }
  1603 + if (nb_args <= 1) {
  1604 + /* command completion */
  1605 + if (nb_args == 0)
  1606 + cmdname = "";
  1607 + else
  1608 + cmdname = args[0];
  1609 + completion_index = strlen(cmdname);
  1610 + for(cmd = term_cmds; cmd->name != NULL; cmd++) {
  1611 + cmd_completion(cmdname, cmd->name);
  1612 + }
  1613 + } else {
  1614 + /* find the command */
  1615 + for(cmd = term_cmds; cmd->name != NULL; cmd++) {
  1616 + if (compare_cmd(args[0], cmd->name))
  1617 + goto found;
  1618 + }
  1619 + return;
  1620 + found:
  1621 + ptype = cmd->args_type;
  1622 + for(i = 0; i < nb_args - 2; i++) {
  1623 + if (*ptype != '\0') {
  1624 + ptype++;
  1625 + while (*ptype == '?')
  1626 + ptype++;
  1627 + }
  1628 + }
  1629 + str = args[nb_args - 1];
  1630 + switch(*ptype) {
  1631 + case 'F':
  1632 + /* file completion */
  1633 + completion_index = strlen(str);
  1634 + file_completion(str);
  1635 + break;
  1636 + case 'B':
  1637 + /* block device name completion */
  1638 + completion_index = strlen(str);
  1639 + bdrv_iterate(block_completion_it, (void *)str);
  1640 + break;
  1641 + default:
  1642 + break;
  1643 + }
  1644 + }
  1645 + for(i = 0; i < nb_args; i++)
  1646 + qemu_free(args[i]);
  1647 +}
  1648 +
  1649 +static void term_show_prompt2(void)
1436 { 1650 {
1437 term_printf("(qemu) "); 1651 term_printf("(qemu) ");
1438 fflush(stdout); 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();
1439 term_cmd_buf_index = 0; 1661 term_cmd_buf_index = 0;
1440 term_cmd_buf_size = 0; 1662 term_cmd_buf_size = 0;
1441 - term_esc_state = IS_NORM;  
1442 } 1663 }
1443 1664
1444 -static void term_print_cmdline (const char *cmdline) 1665 +/* update the displayed command line */
  1666 +static void term_update(void)
1445 { 1667 {
1446 - term_show_prompt();  
1447 - term_printf("%s", cmdline); 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 + }
1448 term_flush(); 1696 term_flush();
1449 } 1697 }
1450 1698
@@ -1456,9 +1704,7 @@ static void term_insert_char(int ch) @@ -1456,9 +1704,7 @@ static void term_insert_char(int ch)
1456 term_cmd_buf_size - term_cmd_buf_index); 1704 term_cmd_buf_size - term_cmd_buf_index);
1457 term_cmd_buf[term_cmd_buf_index] = ch; 1705 term_cmd_buf[term_cmd_buf_index] = ch;
1458 term_cmd_buf_size++; 1706 term_cmd_buf_size++;
1459 - term_printf("\033[@%c", ch);  
1460 term_cmd_buf_index++; 1707 term_cmd_buf_index++;
1461 - term_flush();  
1462 } 1708 }
1463 } 1709 }
1464 1710
@@ -1466,8 +1712,6 @@ static void term_backward_char(void) @@ -1466,8 +1712,6 @@ static void term_backward_char(void)
1466 { 1712 {
1467 if (term_cmd_buf_index > 0) { 1713 if (term_cmd_buf_index > 0) {
1468 term_cmd_buf_index--; 1714 term_cmd_buf_index--;
1469 - term_printf("\033[D");  
1470 - term_flush();  
1471 } 1715 }
1472 } 1716 }
1473 1717
@@ -1475,8 +1719,6 @@ static void term_forward_char(void) @@ -1475,8 +1719,6 @@ static void term_forward_char(void)
1475 { 1719 {
1476 if (term_cmd_buf_index < term_cmd_buf_size) { 1720 if (term_cmd_buf_index < term_cmd_buf_size) {
1477 term_cmd_buf_index++; 1721 term_cmd_buf_index++;
1478 - term_printf("\033[C");  
1479 - term_flush();  
1480 } 1722 }
1481 } 1723 }
1482 1724
@@ -1486,9 +1728,7 @@ static void term_delete_char(void) @@ -1486,9 +1728,7 @@ static void term_delete_char(void)
1486 memmove(term_cmd_buf + term_cmd_buf_index, 1728 memmove(term_cmd_buf + term_cmd_buf_index,
1487 term_cmd_buf + term_cmd_buf_index + 1, 1729 term_cmd_buf + term_cmd_buf_index + 1,
1488 term_cmd_buf_size - term_cmd_buf_index - 1); 1730 term_cmd_buf_size - term_cmd_buf_index - 1);
1489 - term_printf("\033[P");  
1490 term_cmd_buf_size--; 1731 term_cmd_buf_size--;
1491 - term_flush();  
1492 } 1732 }
1493 } 1733 }
1494 1734
@@ -1502,14 +1742,12 @@ static void term_backspace(void) @@ -1502,14 +1742,12 @@ static void term_backspace(void)
1502 1742
1503 static void term_bol(void) 1743 static void term_bol(void)
1504 { 1744 {
1505 - while (term_cmd_buf_index > 0)  
1506 - term_backward_char(); 1745 + term_cmd_buf_index = 0;
1507 } 1746 }
1508 1747
1509 static void term_eol(void) 1748 static void term_eol(void)
1510 { 1749 {
1511 - while (term_cmd_buf_index < term_cmd_buf_size)  
1512 - term_forward_char(); 1750 + term_cmd_buf_index = term_cmd_buf_size;
1513 } 1751 }
1514 1752
1515 static void term_up_char(void) 1753 static void term_up_char(void)
@@ -1530,8 +1768,6 @@ static void term_up_char(void) @@ -1530,8 +1768,6 @@ static void term_up_char(void)
1530 if (term_hist_entry >= 0) { 1768 if (term_hist_entry >= 0) {
1531 pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), 1769 pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
1532 term_history[term_hist_entry]); 1770 term_history[term_hist_entry]);
1533 - term_printf("\n");  
1534 - term_print_cmdline(term_cmd_buf);  
1535 term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); 1771 term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
1536 } 1772 }
1537 } 1773 }
@@ -1546,8 +1782,6 @@ static void term_down_char(void) @@ -1546,8 +1782,6 @@ static void term_down_char(void)
1546 } else { 1782 } else {
1547 term_hist_entry = -1; 1783 term_hist_entry = -1;
1548 } 1784 }
1549 - term_printf("\n");  
1550 - term_print_cmdline(term_cmd_buf);  
1551 term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf); 1785 term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
1552 } 1786 }
1553 1787
@@ -1600,6 +1834,67 @@ static void term_hist_add(const char *cmdline) @@ -1600,6 +1834,67 @@ static void term_hist_add(const char *cmdline)
1600 term_hist_entry = -1; 1834 term_hist_entry = -1;
1601 } 1835 }
1602 1836
  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 +}
  1845 +
  1846 +static void term_completion(void)
  1847 +{
  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 + }
  1896 +}
  1897 +
1603 /* return true if command handled */ 1898 /* return true if command handled */
1604 static void term_handle_byte(int ch) 1899 static void term_handle_byte(int ch)
1605 { 1900 {
@@ -1609,9 +1904,15 @@ static void term_handle_byte(int ch) @@ -1609,9 +1904,15 @@ static void term_handle_byte(int ch)
1609 case 1: 1904 case 1:
1610 term_bol(); 1905 term_bol();
1611 break; 1906 break;
  1907 + case 4:
  1908 + term_delete_char();
  1909 + break;
1612 case 5: 1910 case 5:
1613 term_eol(); 1911 term_eol();
1614 break; 1912 break;
  1913 + case 9:
  1914 + term_completion();
  1915 + break;
1615 case 10: 1916 case 10:
1616 case 13: 1917 case 13:
1617 term_cmd_buf[term_cmd_buf_size] = '\0'; 1918 term_cmd_buf[term_cmd_buf_size] = '\0';
@@ -1684,104 +1985,29 @@ static void term_handle_byte(int ch) @@ -1684,104 +1985,29 @@ static void term_handle_byte(int ch)
1684 the_end: 1985 the_end:
1685 break; 1986 break;
1686 } 1987 }
1687 -}  
1688 -  
1689 -/*************************************************************/  
1690 -/* serial console support */  
1691 -  
1692 -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */  
1693 -  
1694 -static int term_got_escape, term_command;  
1695 -  
1696 -void term_print_help(void)  
1697 -{  
1698 - term_printf("\n"  
1699 - "C-a h print this help\n"  
1700 - "C-a x exit emulatior\n"  
1701 - "C-a s save disk data back to file (if -snapshot)\n"  
1702 - "C-a b send break (magic sysrq)\n"  
1703 - "C-a c switch between console and monitor\n"  
1704 - "C-a C-a send C-a\n"  
1705 - );  
1706 -}  
1707 -  
1708 -/* called when a char is received */  
1709 -static void term_received_byte(int ch)  
1710 -{  
1711 - if (!serial_console) {  
1712 - /* if no serial console, handle every command */  
1713 - term_handle_byte(ch);  
1714 - } else {  
1715 - if (term_got_escape) {  
1716 - term_got_escape = 0;  
1717 - switch(ch) {  
1718 - case 'h':  
1719 - term_print_help();  
1720 - break;  
1721 - case 'x':  
1722 - exit(0);  
1723 - break;  
1724 - case 's':  
1725 - {  
1726 - int i;  
1727 - for (i = 0; i < MAX_DISKS; i++) {  
1728 - if (bs_table[i])  
1729 - bdrv_commit(bs_table[i]);  
1730 - }  
1731 - }  
1732 - break;  
1733 - case 'b':  
1734 - if (serial_console)  
1735 - serial_receive_break(serial_console);  
1736 - break;  
1737 - case 'c':  
1738 - if (!term_command) {  
1739 - term_show_prompt();  
1740 - term_command = 1;  
1741 - } else {  
1742 - term_command = 0;  
1743 - }  
1744 - break;  
1745 - case TERM_ESCAPE:  
1746 - goto send_char;  
1747 - }  
1748 - } else if (ch == TERM_ESCAPE) {  
1749 - term_got_escape = 1;  
1750 - } else {  
1751 - send_char:  
1752 - if (term_command) {  
1753 - term_handle_byte(ch);  
1754 - } else {  
1755 - if (serial_console)  
1756 - serial_receive_byte(serial_console, ch);  
1757 - }  
1758 - }  
1759 - } 1988 + term_update();
1760 } 1989 }
1761 1990
1762 static int term_can_read(void *opaque) 1991 static int term_can_read(void *opaque)
1763 { 1992 {
1764 - if (serial_console) {  
1765 - return serial_can_receive(serial_console);  
1766 - } else {  
1767 - return 128;  
1768 - } 1993 + return 128;
1769 } 1994 }
1770 1995
1771 static void term_read(void *opaque, const uint8_t *buf, int size) 1996 static void term_read(void *opaque, const uint8_t *buf, int size)
1772 { 1997 {
1773 int i; 1998 int i;
1774 for(i = 0; i < size; i++) 1999 for(i = 0; i < size; i++)
1775 - term_received_byte(buf[i]); 2000 + term_handle_byte(buf[i]);
1776 } 2001 }
1777 2002
1778 -void monitor_init(void) 2003 +void monitor_init(CharDriverState *hd, int show_banner)
1779 { 2004 {
1780 - if (!serial_console) { 2005 + monitor_hd = hd;
  2006 + if (show_banner) {
1781 term_printf("QEMU %s monitor - type 'help' for more information\n", 2007 term_printf("QEMU %s monitor - type 'help' for more information\n",
1782 QEMU_VERSION); 2008 QEMU_VERSION);
1783 term_show_prompt(); 2009 term_show_prompt();
1784 } 2010 }
1785 term_hist_entry = -1; 2011 term_hist_entry = -1;
1786 - qemu_add_fd_read_handler(0, term_can_read, term_read, NULL); 2012 + qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL);
1787 } 2013 }