From 110872907848ccf01d1f0e372bb79bd0d2af788b Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Fri, 10 Aug 2012 21:35:39 +0200 Subject: [PATCH] Support "commands". --- main.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 143 insertions(+), 25 deletions(-) diff --git a/main.c b/main.c index 08a19d1..f4be40c 100644 --- a/main.c +++ b/main.c @@ -88,6 +88,14 @@ console_cb (const char *str, void *data) fputs (str, stdout); } +static int +time_out_cb (void *data) +{ + fatal ("GDB response has timed out"); + /* NOTREACHED */ + return 0; +} + static ATTRIBUTE_UNUSED void to_gdb_cb (const char *str, void *data) { @@ -117,16 +125,11 @@ history_save (int rc, void *arg) } static void -quit_command (mi_h *h, const char *cmd) -{ - exit (EXIT_SUCCESS); -} - -static void default_command (mi_h *h, const char *cmd) { int count = 1; + gdb_assert (strchr (cmd, '\n') == 0); mi_send (h, "-interpreter-exec console \"%s\"\n", cmd); while (count > 0) @@ -161,16 +164,139 @@ default_command (mi_h *h, const char *cmd) } } +static void +quit_command (mi_h *h, const char *cmd) +{ + exit (EXIT_SUCCESS); +} + +static char * +mi_escape (const char *cs) +{ + char *d, *retval = xmalloc (strlen (cs) * 2 + 1); + + d = retval; + while (*cs) + { + if (*cs == '"' || *cs == '\\') + *d++ = '\\'; + *d++ = *cs++; + } + *d = '\0'; + return retval; +} + +static void +gdb_done (mi_h *h, const char *command) +{ + mi_output *res; + + mi_send (h, "%s\n", command); + res = mi_get_response_blk (h); + gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE + && res->c == NULL); + mi_free_output (res); +} + +static void +commands_command_console_cb (const char *str, void *data) +{ + char **strptr = data; + + gdb_assert (*strptr == NULL); + *strptr = xstrdup (str); +} + +static void +commands_command (mi_h *h, const char *cmd_param) +{ + char *cmd = xstrdup (""); + size_t cmd_len = 0; + mi_output *res; + char *bpnum = NULL; + int nesting; + + if (*cmd_param == '\0') + { + mi_set_console_cb (h, commands_command_console_cb, &bpnum); + gdb_done (h, "output $bpnum"); + mi_set_console_cb (h, console_cb, NULL); + gdb_assert (bpnum != NULL); + cmd_param = bpnum; + } + + printf (_("Type commands for breakpoint(s) %s, one per line.\n" + "End with a line saying just \"end\".\n"), cmd_param); + + nesting = 0; + while (nesting >= 0) + { + char *prompt, *data, *data2, *start, *end; + size_t data2_len; + int do_nest = 0; + + prompt = xstrprintf ("%*s>", (int) nesting); + data = readline (prompt); + xfree (prompt); + if (data == NULL) + data = xstrdup ("end"); + + for (start = data; isspace (*start); start++); + for (end = data + strlen (data); end > start && isspace (end[-1]); end--); + data2 = xmalloc (end - start + 1); + memcpy (data2, start, end - start); + data2[end - start] = '\0'; + if (strcmp (data2, "python") == 0) + do_nest = 1; + if (strcmp (data2, "end") == 0) + do_nest = -1; + for (end = data2; *end && !isspace (*end); end++); + *end = '\0'; + + /* Here is a bug in GDB, it does not recognize command shortcuts. */ + if (strcmp (data2, "while") == 0 || strcmp (data2, "if") == 0 + || strcmp (data2, "commands") == 0 + || strcmp (data2, "while-stepping") == 0 + || strcmp (data2, "stepping") == 0 || strcmp (data2, "ws") == 0) + do_nest = 1; + xfree (data2); + + nesting += do_nest; + if (nesting < 0) + break; + + data2 = mi_escape (data); + xfree (data); + data2_len = strlen (data2); + cmd = xrealloc (cmd, cmd_len + 2 + data2_len + 2); + cmd[cmd_len] = ' '; + cmd[cmd_len + 1] = '"'; + memcpy (&cmd[cmd_len + 2], data2, data2_len); + cmd[cmd_len + 2 + data2_len] = '"'; + cmd[cmd_len + 2 + data2_len + 1] = '\0'; + cmd_len += 2 + data2_len + 1; + xfree (data2); + } + + mi_send (h, "-break-commands %s%s\n", cmd_param, cmd); + xfree (cmd); + xfree (bpnum); + + res = mi_get_response_blk (h); + gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE + && res->c == NULL); + mi_free_output (res); +} + static const struct cmd { const char *name; + int min_shortcut; void (*func) (mi_h *h, const char *cmd); } cmds[] = { - { "q", quit_command }, - { "qu", quit_command }, - { "qui", quit_command }, - { "quit", quit_command }, + { "quit", 1, quit_command }, + { "commands", 4, commands_command }, }; static void @@ -186,28 +312,18 @@ executecommand (mi_h *h, const char *cmd) while (isalnum (*cs)) cs++; end = cs; + while (isspace (*cs)) + cs++; for (cmdp = cmds; cmdp < &cmds[LENGTH (cmds)]; cmdp++) - if (strlen (cmdp->name) == end - start - && strncmp (cmd, cmdp->name, end - start) == 0) - return cmdp->func (h, cmd); + if (cmdp->min_shortcut <= end - start && end - start <= strlen (cmdp->name) + && strncmp (start, cmdp->name, end - start) == 0) + return cmdp->func (h, cs); return default_command (h, cmd); } static void -gdb_done (mi_h *h, const char *command) -{ - mi_output *res; - - mi_send (h, "%s\n", command); - res = mi_get_response_blk (h); - gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE - && res->c == NULL); - mi_free_output (res); -} - -static void gdb_set_string (mi_h *h, const char *setting, const char *value) { char *cmd = xstrprintf ("-gdb-set %s %s", setting, value); @@ -357,6 +473,8 @@ start_hook (mi_h *h) { on_exit (h_disconnect, h); mi_set_console_cb (h, console_cb, NULL); + mi_set_time_out_cb (h, time_out_cb, NULL); + // mi_set_to_gdb_cb (h, to_gdb_cb, NULL); // mi_set_from_gdb_cb (h, from_gdb_cb, NULL); } -- 1.8.3.1