Commit 81d0912d2d221c41d649d2c36812afddf74634d2
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
block.c
... | ... | @@ -470,6 +470,15 @@ BlockDriverState *bdrv_find(const char *name) |
470 | 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 | 482 | void bdrv_info(void) |
474 | 483 | { |
475 | 484 | BlockDriverState *bs; | ... | ... |
monitor.c
... | ... | @@ -23,8 +23,10 @@ |
23 | 23 | */ |
24 | 24 | #include "vl.h" |
25 | 25 | #include "disas.h" |
26 | +#include <dirent.h> | |
26 | 27 | |
27 | 28 | //#define DEBUG |
29 | +//#define DEBUG_COMPLETION | |
28 | 30 | |
29 | 31 | #ifndef offsetof |
30 | 32 | #define offsetof(type, field) ((size_t) &((type *)0)->field) |
... | ... | @@ -32,6 +34,7 @@ |
32 | 34 | |
33 | 35 | #define TERM_CMD_BUF_SIZE 4095 |
34 | 36 | #define TERM_MAX_CMDS 64 |
37 | +#define NB_COMPLETIONS_MAX 256 | |
35 | 38 | |
36 | 39 | #define IS_NORM 0 |
37 | 40 | #define IS_ESC 1 |
... | ... | @@ -42,16 +45,28 @@ |
42 | 45 | static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1]; |
43 | 46 | static int term_cmd_buf_index; |
44 | 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 | 53 | static int term_esc_state; |
46 | 54 | static int term_esc_param; |
47 | 55 | |
48 | 56 | static char *term_history[TERM_MAX_CMDS]; |
49 | 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 | 66 | * Supported types: |
53 | 67 | * |
54 | 68 | * 'F' filename |
69 | + * 'B' block device name | |
55 | 70 | * 's' string (accept optional quote) |
56 | 71 | * 'i' integer |
57 | 72 | * '/' optional gdb-like print format (like "/10x") |
... | ... | @@ -71,17 +86,20 @@ typedef struct term_cmd_t { |
71 | 86 | static term_cmd_t term_cmds[]; |
72 | 87 | static term_cmd_t info_cmds[]; |
73 | 88 | |
89 | +static void add_completion(const char *str); | |
90 | + | |
74 | 91 | void term_printf(const char *fmt, ...) |
75 | 92 | { |
93 | + char buf[4096]; | |
76 | 94 | va_list ap; |
77 | 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 | 98 | va_end(ap); |
80 | 99 | } |
81 | 100 | |
82 | 101 | void term_flush(void) |
83 | 102 | { |
84 | - fflush(stdout); | |
85 | 103 | } |
86 | 104 | |
87 | 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 | 250 | { |
233 | 251 | BlockDriverState *bs; |
234 | 252 | |
235 | - term_printf("%d %s\n", force, filename); | |
236 | - | |
237 | 253 | bs = bdrv_find(filename); |
238 | 254 | if (!bs) { |
239 | 255 | term_printf("device not found\n"); |
... | ... | @@ -674,9 +690,9 @@ static term_cmd_t term_cmds[] = { |
674 | 690 | "subcommand", "show various information about the system state" }, |
675 | 691 | { "q|quit", "", do_quit, |
676 | 692 | "", "quit the emulator" }, |
677 | - { "eject", "-fs", do_eject, | |
693 | + { "eject", "-fB", do_eject, | |
678 | 694 | "[-f] device", "eject a removable media (use -f to force it)" }, |
679 | - { "change", "sF", do_change, | |
695 | + { "change", "BF", do_change, | |
680 | 696 | "device filename", "change a removable media" }, |
681 | 697 | { "screendump", "F", do_screen_dump, |
682 | 698 | "filename", "save screen into PPM image 'filename'" }, |
... | ... | @@ -953,6 +969,16 @@ static int expr_unary(void) |
953 | 969 | } |
954 | 970 | next(); |
955 | 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 | 982 | case '$': |
957 | 983 | { |
958 | 984 | char buf[128], *q; |
... | ... | @@ -1088,15 +1114,16 @@ static int get_str(char *buf, int buf_size, const char **pp) |
1088 | 1114 | char *q; |
1089 | 1115 | int c; |
1090 | 1116 | |
1117 | + q = buf; | |
1091 | 1118 | p = *pp; |
1092 | 1119 | while (isspace(*p)) |
1093 | 1120 | p++; |
1094 | 1121 | if (*p == '\0') { |
1095 | 1122 | fail: |
1123 | + *q = '\0'; | |
1096 | 1124 | *pp = p; |
1097 | 1125 | return -1; |
1098 | 1126 | } |
1099 | - q = buf; | |
1100 | 1127 | if (*p == '\"') { |
1101 | 1128 | p++; |
1102 | 1129 | while (*p != '\0' && *p != '\"') { |
... | ... | @@ -1140,8 +1167,8 @@ static int get_str(char *buf, int buf_size, const char **pp) |
1140 | 1167 | } |
1141 | 1168 | p++; |
1142 | 1169 | } |
1143 | - *q = '\0'; | |
1144 | 1170 | } |
1171 | + *q = '\0'; | |
1145 | 1172 | *pp = p; |
1146 | 1173 | return 0; |
1147 | 1174 | } |
... | ... | @@ -1204,6 +1231,7 @@ static void term_handle_command(const char *cmdline) |
1204 | 1231 | typestr++; |
1205 | 1232 | switch(c) { |
1206 | 1233 | case 'F': |
1234 | + case 'B': | |
1207 | 1235 | case 's': |
1208 | 1236 | { |
1209 | 1237 | int ret; |
... | ... | @@ -1221,10 +1249,17 @@ static void term_handle_command(const char *cmdline) |
1221 | 1249 | } |
1222 | 1250 | ret = get_str(buf, sizeof(buf), &p); |
1223 | 1251 | if (ret < 0) { |
1224 | - if (c == 'F') | |
1252 | + switch(c) { | |
1253 | + case 'F': | |
1225 | 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 | 1260 | term_printf("%s: string expected\n", cmdname); |
1261 | + break; | |
1262 | + } | |
1228 | 1263 | goto fail; |
1229 | 1264 | } |
1230 | 1265 | str = qemu_malloc(strlen(buf) + 1); |
... | ... | @@ -1432,19 +1467,232 @@ static void term_handle_command(const char *cmdline) |
1432 | 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 | 1651 | term_printf("(qemu) "); |
1438 | 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 | 1661 | term_cmd_buf_index = 0; |
1440 | 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 | 1696 | term_flush(); |
1449 | 1697 | } |
1450 | 1698 | |
... | ... | @@ -1456,9 +1704,7 @@ static void term_insert_char(int ch) |
1456 | 1704 | term_cmd_buf_size - term_cmd_buf_index); |
1457 | 1705 | term_cmd_buf[term_cmd_buf_index] = ch; |
1458 | 1706 | term_cmd_buf_size++; |
1459 | - term_printf("\033[@%c", ch); | |
1460 | 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 | 1712 | { |
1467 | 1713 | if (term_cmd_buf_index > 0) { |
1468 | 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 | 1719 | { |
1476 | 1720 | if (term_cmd_buf_index < term_cmd_buf_size) { |
1477 | 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 | 1728 | memmove(term_cmd_buf + term_cmd_buf_index, |
1487 | 1729 | term_cmd_buf + term_cmd_buf_index + 1, |
1488 | 1730 | term_cmd_buf_size - term_cmd_buf_index - 1); |
1489 | - term_printf("\033[P"); | |
1490 | 1731 | term_cmd_buf_size--; |
1491 | - term_flush(); | |
1492 | 1732 | } |
1493 | 1733 | } |
1494 | 1734 | |
... | ... | @@ -1502,14 +1742,12 @@ static void term_backspace(void) |
1502 | 1742 | |
1503 | 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 | 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 | 1753 | static void term_up_char(void) |
... | ... | @@ -1530,8 +1768,6 @@ static void term_up_char(void) |
1530 | 1768 | if (term_hist_entry >= 0) { |
1531 | 1769 | pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), |
1532 | 1770 | term_history[term_hist_entry]); |
1533 | - term_printf("\n"); | |
1534 | - term_print_cmdline(term_cmd_buf); | |
1535 | 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 | 1782 | } else { |
1547 | 1783 | term_hist_entry = -1; |
1548 | 1784 | } |
1549 | - term_printf("\n"); | |
1550 | - term_print_cmdline(term_cmd_buf); | |
1551 | 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 | 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 | 1898 | /* return true if command handled */ |
1604 | 1899 | static void term_handle_byte(int ch) |
1605 | 1900 | { |
... | ... | @@ -1609,9 +1904,15 @@ static void term_handle_byte(int ch) |
1609 | 1904 | case 1: |
1610 | 1905 | term_bol(); |
1611 | 1906 | break; |
1907 | + case 4: | |
1908 | + term_delete_char(); | |
1909 | + break; | |
1612 | 1910 | case 5: |
1613 | 1911 | term_eol(); |
1614 | 1912 | break; |
1913 | + case 9: | |
1914 | + term_completion(); | |
1915 | + break; | |
1615 | 1916 | case 10: |
1616 | 1917 | case 13: |
1617 | 1918 | term_cmd_buf[term_cmd_buf_size] = '\0'; |
... | ... | @@ -1684,104 +1985,29 @@ static void term_handle_byte(int ch) |
1684 | 1985 | the_end: |
1685 | 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 | 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 | 1996 | static void term_read(void *opaque, const uint8_t *buf, int size) |
1772 | 1997 | { |
1773 | 1998 | int i; |
1774 | 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 | 2007 | term_printf("QEMU %s monitor - type 'help' for more information\n", |
1782 | 2008 | QEMU_VERSION); |
1783 | 2009 | term_show_prompt(); |
1784 | 2010 | } |
1785 | 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 | } | ... | ... |