Commends interpretation etc.
authorJan Kratochvil <jan.kratochvil@redhat.com>
Fri, 3 Aug 2012 11:31:02 +0000 (13:31 +0200)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Fri, 3 Aug 2012 11:31:02 +0000 (13:31 +0200)
ansidecl.h
main.c

index 7628064..b16f2b2 100644 (file)
@@ -1,4 +1,11 @@
-#if (GCC_VERSION < 2007)
+#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
+#if GCC_VERSION < 2007
 # define __attribute__(x)
 #endif
 #define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#define LENGTH(x) (sizeof (x) / sizeof (*(x)))
+
+#define bool int
+#define true 1
+#define false 0
diff --git a/main.c b/main.c
index 880c1fe..c43df32 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,9 +1,16 @@
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdarg.h>
+#include <signal.h>
 #include <readline/readline.h>
+#include <readline/history.h>
+#include <assert.h>
+#include <errno.h>
 #include "ansidecl.h"
 #include "mi_gdb.h"
 
+#define gdb_assert assert
+
 static ATTRIBUTE_NORETURN void
 fatal (const char *fmt, ...)
 {
@@ -12,15 +19,224 @@ fatal (const char *fmt, ...)
   va_start (ap, fmt);
   vfprintf (stderr, fmt, ap);
   va_end (ap);
+raise (SIGABRT);
   exit (EXIT_FAILURE);
 }
 
+static char *
+xstrdup (const char *s)
+{
+  char *retval;
+
+  gdb_assert (s != NULL);
+  retval = strdup (s);
+  gdb_assert (retval != NULL);
+  return retval;
+}
+
+static void
+xfree (void *p)
+{
+  free (p);
+}
+
+static char *
+xstrprintf (const char *fmt, ...)
+{
+  va_list ap;
+  char *retval;
+  int i;
+
+  va_start (ap, fmt);
+  i = vasprintf (&retval, fmt, ap);
+  va_end (ap);
+  gdb_assert (i > 0);
+  gdb_assert (i == strlen (retval));
+  return retval;
+}
+
 static void
 console_cb (const char *str, void *data)
 {
   fputs (str, stdout);
 }
 
+static ATTRIBUTE_UNUSED void
+to_gdb_cb (const char *str, void *data)
+{
+  printf ("to_gdb: %s\n", str);
+}
+
+static ATTRIBUTE_UNUSED void
+from_gdb_cb (const char *str, void *data)
+{
+  printf ("from_gdb: %s\n", str);
+}
+
+static void
+h_disconnect (int rc, void *arg)
+{
+  mi_h *h = arg;
+
+  mi_disconnect (h);
+}
+
+static void
+history_save (int rc, void *arg)
+{
+  const char *history_filename = arg;
+
+  write_history (history_filename);
+}
+
+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;
+
+  mi_send (h, "-interpreter-exec console \"%s\"\n", cmd);
+
+  while (count > 0)
+    {
+      mi_output *rec, *res;
+
+      res = mi_get_response_blk (h);
+      gdb_assert (res != NULL);
+
+      for (rec = res; rec != NULL; rec = rec->next)
+       switch (rec->tclass)
+       {
+         case MI_CL_DONE:
+           count--;
+           break;
+         case MI_CL_RUNNING:
+           /* We do not get MI_CL_DONE here, wait for MI_CL_STOPPED.  */
+           break;
+         case MI_CL_STOPPED:
+           count--;
+           break;
+         case MI_CL_ERROR:
+           gdb_assert (rec->c->type == t_const);
+           puts (rec->c->v.cstr);
+           break;
+         default:
+           fatal ("mi_get_rrecord == MI_CL_??? (%d)", rec->tclass);
+       }
+
+      mi_free_output (res);
+    }
+}
+
+static const struct cmd
+{
+  const char *name;
+  void (*func) (mi_h *h, const char *cmd);
+} cmds[] =
+{
+  { "q", quit_command },
+  { "qu", quit_command },
+  { "qui", quit_command },
+  { "quit", quit_command },
+};
+
+static void
+executecommand (mi_h *h, const char *cmd)
+{
+  const char *start, *end, *cs;
+  const struct cmd *cmdp;
+
+  cs = cmd;
+  while (isspace (*cs))
+    cs++;
+  start = cs;
+  while (isalnum (*cs))
+    cs++;
+  end = 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);
+
+  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);
+
+  gdb_done (h, cmd);
+  xfree (cmd);
+}
+
+static void
+gdb_set_bool (mi_h *h, const char *setting, bool value)
+{
+  gdb_set_string (h, setting, value ? "on" : "off");
+}
+
+static char *
+gdb_show_string (mi_h *h, const char *setting)
+{
+  mi_output *res;
+  char *retval;
+
+  mi_send (h, "-gdb-show %s\n", setting);
+  res = mi_get_response_blk (h);
+  gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
+             && res->c != NULL && res->c->next == NULL
+             && res->c->type == t_const && strcmp (res->c->var, "value") == 0);
+  retval = xstrdup (res->c->v.cstr);
+  mi_free_output (res);
+  return retval;
+}
+
+static int
+gdb_show_int (mi_h *h, const char *setting)
+{
+  char *string = gdb_show_string (h, setting);
+  long l;
+  int retval;
+  char *end;
+
+  errno = 0;
+  retval = l = strtol (string, &end, 10);
+  gdb_assert (errno == 0 && (end == NULL || *end == '\0') && retval == l);
+  xfree (string);
+  return retval;
+}
+
+static bool
+gdb_show_bool (mi_h *h, const char *setting)
+{
+  char *string = gdb_show_string (h, setting);
+  bool retval;
+
+  retval = strcmp (string, "on") == 0;
+  gdb_assert (retval || strcmp (string, "off") == 0);
+  xfree (string);
+  return retval;
+}
+
 int
 main (int argc, char **argv)
 {
@@ -45,37 +261,40 @@ main (int argc, char **argv)
   if (h == NULL)
     fatal ("Cannot connect to GDB");
 
+  on_exit (h_disconnect, h);
+
   mi_set_console_cb (h, console_cb, NULL);
+//  mi_set_to_gdb_cb (h, to_gdb_cb, NULL);
+//  mi_set_from_gdb_cb (h, from_gdb_cb, NULL);
 
-  for (;;)
+  if (gdb_show_bool (h, "history save"))
     {
-      mi_output *rec, *res;
+      int history_size = gdb_show_int (h, "history size");
+      char *history_filename = gdb_show_string (h, "history filename");
+
+      gdb_set_bool (h, "history save", false);
+      stifle_history (history_size);
+      read_history (history_filename);
+      on_exit (history_save, history_filename);
+      /* Do not free HISTORY_FILENAME.  */
+    }
 
+  for (;;)
+    {
       if (ex_used < ex_count)
        {
-         cmd = strdup (ex[ex_used++]);
+         cmd = xstrdup (ex[ex_used++]);
          printf ("(gdb) %s\n", cmd);
        }
       else
        {
          cmd = readline ("(gdb) ");
          if (cmd == NULL)
-           cmd = strdup ("quit");
+           cmd = xstrdup ("quit");
+         else
+           add_history (cmd);
        }
-
-      mi_send (h, "-interpreter-exec console \"%s\"\n", cmd);
-      free (cmd);
-
-      res = mi_get_response_blk (h);
-      if (res == NULL)
-       fatal ("mi_get_response_blk == NULL");
-
-      rec = mi_get_rrecord (res);
-      if (rec == NULL)
-       fatal ("mi_get_rrecord == NULL");
-      if (rec->tclass != MI_CL_DONE)
-       fatal ("mi_get_rrecord != MI_CL_DONE");
-
-      mi_free_output (res);
+      executecommand (h, cmd);
+      xfree (cmd);
     }
 }