📄 monitor.c
字号:
p++; if (*typestr == '?') { typestr++; if (*p == '\0') { /* no optional string: NULL argument */ str = NULL; goto add_str; } } ret = get_str(buf, sizeof(buf), &p); if (ret < 0) { switch(c) { case 'F': term_printf("%s: filename expected\n", cmdname); break; case 'B': term_printf("%s: block device name expected\n", cmdname); break; default: term_printf("%s: string expected\n", cmdname); break; } goto fail; } str = qemu_malloc(strlen(buf) + 1); strcpy(str, buf); str_allocated[nb_args] = str; add_str: if (nb_args >= MAX_ARGS) { error_args: term_printf("%s: too many arguments\n", cmdname); goto fail; } args[nb_args++] = str; } break; case '/': { int count, format, size; while (isspace(*p)) p++; if (*p == '/') { /* format found */ p++; count = 1; if (isdigit(*p)) { count = 0; while (isdigit(*p)) { count = count * 10 + (*p - '0'); p++; } } size = -1; format = -1; for(;;) { switch(*p) { case 'o': case 'd': case 'u': case 'x': case 'i': case 'c': format = *p++; break; case 'b': size = 1; p++; break; case 'h': size = 2; p++; break; case 'w': size = 4; p++; break; case 'g': case 'L': size = 8; p++; break; default: goto next; } } next: if (*p != '\0' && !isspace(*p)) { term_printf("invalid char in format: '%c'\n", *p); goto fail; } if (format < 0) format = default_fmt_format; if (format != 'i') { /* for 'i', not specifying a size gives -1 as size */ if (size < 0) size = default_fmt_size; } default_fmt_size = size; default_fmt_format = format; } else { count = 1; format = default_fmt_format; if (format != 'i') { size = default_fmt_size; } else { size = -1; } } if (nb_args + 3 > MAX_ARGS) goto error_args; args[nb_args++] = (void*)count; args[nb_args++] = (void*)format; args[nb_args++] = (void*)size; } break; case 'i': case 'l': { target_long val; while (isspace(*p)) p++; if (*typestr == '?' || *typestr == '.') { if (*typestr == '?') { if (*p == '\0') has_arg = 0; else has_arg = 1; } else { if (*p == '.') { p++; while (isspace(*p)) p++; has_arg = 1; } else { has_arg = 0; } } typestr++; if (nb_args >= MAX_ARGS) goto error_args; args[nb_args++] = (void *)has_arg; if (!has_arg) { if (nb_args >= MAX_ARGS) goto error_args; val = -1; goto add_num; } } if (get_expr(&val, &p)) goto fail; add_num: if (c == 'i') { if (nb_args >= MAX_ARGS) goto error_args; args[nb_args++] = (void *)(int)val; } else { if ((nb_args + 1) >= MAX_ARGS) goto error_args;#if TARGET_LONG_BITS == 64 args[nb_args++] = (void *)(int)((val >> 32) & 0xffffffff);#else args[nb_args++] = (void *)0;#endif args[nb_args++] = (void *)(int)(val & 0xffffffff); } } break; case '-': { int has_option; /* option */ c = *typestr++; if (c == '\0') goto bad_type; while (isspace(*p)) p++; has_option = 0; if (*p == '-') { p++; if (*p != c) { term_printf("%s: unsupported option -%c\n", cmdname, *p); goto fail; } p++; has_option = 1; } if (nb_args >= MAX_ARGS) goto error_args; args[nb_args++] = (void *)has_option; } break; default: bad_type: term_printf("%s: unknown type '%c'\n", cmdname, c); goto fail; } } /* check that all arguments were parsed */ while (isspace(*p)) p++; if (*p != '\0') { term_printf("%s: extraneous characters at the end of line\n", cmdname); goto fail; } switch(nb_args) { case 0: cmd->handler(); break; case 1: cmd->handler(args[0]); break; case 2: cmd->handler(args[0], args[1]); break; case 3: cmd->handler(args[0], args[1], args[2]); break; case 4: cmd->handler(args[0], args[1], args[2], args[3]); break; case 5: cmd->handler(args[0], args[1], args[2], args[3], args[4]); break; case 6: cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]); break; case 7: cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break; default: term_printf("unsupported number of arguments: %d\n", nb_args); goto fail; } fail: for(i = 0; i < MAX_ARGS; i++) qemu_free(str_allocated[i]); return;}static void cmd_completion(const char *name, const char *list){ const char *p, *pstart; char cmd[128]; int len; p = list; for(;;) { pstart = p; p = strchr(p, '|'); if (!p) p = pstart + strlen(pstart); len = p - pstart; if (len > sizeof(cmd) - 2) len = sizeof(cmd) - 2; memcpy(cmd, pstart, len); cmd[len] = '\0'; if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) { add_completion(cmd); } if (*p == '\0') break; p++; }}static void file_completion(const char *input){ DIR *ffs; struct dirent *d; char path[1024]; char file[1024], file_prefix[1024]; int input_path_len; const char *p; p = strrchr(input, '/'); if (!p) { input_path_len = 0; pstrcpy(file_prefix, sizeof(file_prefix), input); strcpy(path, "."); } else { input_path_len = p - input + 1; memcpy(path, input, input_path_len); if (input_path_len > sizeof(path) - 1) input_path_len = sizeof(path) - 1; path[input_path_len] = '\0'; pstrcpy(file_prefix, sizeof(file_prefix), p + 1); }#ifdef DEBUG_COMPLETION term_printf("input='%s' path='%s' prefix='%s'\n", input, path, file_prefix);#endif ffs = opendir(path); if (!ffs) return; for(;;) { struct stat sb; d = readdir(ffs); if (!d) break; if (strstart(d->d_name, file_prefix, NULL)) { memcpy(file, input, input_path_len); strcpy(file + input_path_len, d->d_name); /* stat the file to find out if it's a directory. * In that case add a slash to speed up typing long paths */ stat(file, &sb); if(S_ISDIR(sb.st_mode)) strcat(file, "/"); add_completion(file); } } closedir(ffs);}static void block_completion_it(void *opaque, const char *name){ const char *input = opaque; if (input[0] == '\0' || !strncmp(name, (char *)input, strlen(input))) { add_completion(name); }}/* NOTE: this parser is an approximate form of the real command parser */static void parse_cmdline(const char *cmdline, int *pnb_args, char **args){ const char *p; int nb_args, ret; char buf[1024]; p = cmdline; nb_args = 0; for(;;) { while (isspace(*p)) p++; if (*p == '\0') break; if (nb_args >= MAX_ARGS) break; ret = get_str(buf, sizeof(buf), &p); args[nb_args] = qemu_strdup(buf); nb_args++; if (ret < 0) break; } *pnb_args = nb_args;}void readline_find_completion(const char *cmdline){ const char *cmdname; char *args[MAX_ARGS]; int nb_args, i, len; const char *ptype, *str; term_cmd_t *cmd; const KeyDef *key; parse_cmdline(cmdline, &nb_args, args);#ifdef DEBUG_COMPLETION for(i = 0; i < nb_args; i++) { term_printf("arg%d = '%s'\n", i, (char *)args[i]); }#endif /* if the line ends with a space, it means we want to complete the next arg */ len = strlen(cmdline); if (len > 0 && isspace(cmdline[len - 1])) { if (nb_args >= MAX_ARGS) return; args[nb_args++] = qemu_strdup(""); } if (nb_args <= 1) { /* command completion */ if (nb_args == 0) cmdname = ""; else cmdname = args[0]; completion_index = strlen(cmdname); for(cmd = term_cmds; cmd->name != NULL; cmd++) { cmd_completion(cmdname, cmd->name); } } else { /* find the command */ for(cmd = term_cmds; cmd->name != NULL; cmd++) { if (compare_cmd(args[0], cmd->name)) goto found; } return; found: ptype = cmd->args_type; for(i = 0; i < nb_args - 2; i++) { if (*ptype != '\0') { ptype++; while (*ptype == '?') ptype++; } } str = args[nb_args - 1]; switch(*ptype) { case 'F': /* file completion */ completion_index = strlen(str); file_completion(str); break; case 'B': /* block device name completion */ completion_index = strlen(str); bdrv_iterate(block_completion_it, (void *)str); break; case 's': /* XXX: more generic ? */ if (!strcmp(cmd->name, "info")) { completion_index = strlen(str); for(cmd = info_cmds; cmd->name != NULL; cmd++) { cmd_completion(str, cmd->name); } } else if (!strcmp(cmd->name, "sendkey")) { completion_index = strlen(str); for(key = key_defs; key->name != NULL; key++) { cmd_completion(str, key->name); } } break; default: break; } } for(i = 0; i < nb_args; i++) qemu_free(args[i]);}static int term_can_read(void *opaque){ return 128;}static void term_read(void *opaque, const uint8_t *buf, int size){ int i; for(i = 0; i < size; i++) readline_handle_byte(buf[i]);}static void monitor_start_input(void);static void monitor_handle_command1(void *opaque, const char *cmdline){ monitor_handle_command(cmdline); monitor_start_input();}static void monitor_start_input(void){ readline_start("(qemu) ", 0, monitor_handle_command1, NULL);}static void term_event(void *opaque, int event){ if (event != CHR_EVENT_RESET) return; if (!hide_banner) term_printf("QEMU %s monitor - type 'help' for more information\n", QEMU_VERSION); monitor_start_input();}void monitor_init(CharDriverState *hd, int show_banner){ monitor_hd = hd; hide_banner = !show_banner; qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL);}/* XXX: use threads ? *//* modal monitor readline */static int monitor_readline_started;static char *monitor_readline_buf;static int monitor_readline_buf_size;static void monitor_readline_cb(void *opaque, const char *input){ pstrcpy(monitor_readline_buf, monitor_readline_buf_size, input); monitor_readline_started = 0;}void monitor_readline(const char *prompt, int is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -