+basic completer
authorJan Kratochvil <jan.kratochvil@redhat.com>
Fri, 10 Aug 2012 12:57:16 +0000 (14:57 +0200)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Fri, 10 Aug 2012 12:57:16 +0000 (14:57 +0200)
main.c

diff --git a/main.c b/main.c
index c43df32..54360b3 100644 (file)
--- a/main.c
+++ b/main.c
@@ -9,16 +9,20 @@
 #include "ansidecl.h"
 #include "mi_gdb.h"
 
+#define fatal(fmt...) fatal_func (__FILE__, __LINE__, __PRETTY_FUNCTION__, fmt)
 #define gdb_assert assert
+#define gdb_assert_not_reached(msg) fatal ("%s", (msg))
 
 static ATTRIBUTE_NORETURN void
-fatal (const char *fmt, ...)
+fatal_func (const char *file, int line, const char *func, const char *fmt, ...)
 {
   va_list ap;
 
+  fprintf (stderr, "%s:%d:%s:", file, line, func);
   va_start (ap, fmt);
   vfprintf (stderr, fmt, ap);
   va_end (ap);
+  fputc ('\n', stderr);
 raise (SIGABRT);
   exit (EXIT_FAILURE);
 }
@@ -34,6 +38,28 @@ xstrdup (const char *s)
   return retval;
 }
 
+static void *
+xmalloc (size_t size)
+{
+  void *p;
+
+  gdb_assert (size != 0);
+  p = malloc (size);
+  gdb_assert (p != NULL);
+  return p;
+}
+
+static void *
+xrealloc (void *p, size_t size)
+{
+  if (p == NULL)
+    return xmalloc (size);
+  gdb_assert (size != 0);
+  p = realloc (p, size);
+  gdb_assert (p != NULL);
+  return p;
+}
+
 static void
 xfree (void *p)
 {
@@ -122,6 +148,7 @@ default_command (mi_h *h, const char *cmd)
            count--;
            break;
          case MI_CL_ERROR:
+           count--;
            gdb_assert (rec->c->type == t_const);
            puts (rec->c->v.cstr);
            break;
@@ -237,6 +264,90 @@ gdb_show_bool (mi_h *h, const char *setting)
   return retval;
 }
 
+static mi_h *completion_entry_function_h;
+
+static char **completion_entry_function_data;
+static size_t completion_entry_function_data_used;
+static size_t completion_entry_function_data_allocated;
+
+static void
+completion_entry_function_console_cb (const char *str, void *data)
+{
+  int line_start = (intptr_t) data;
+  const char *cs;
+  char *s;
+
+  if (completion_entry_function_data_used
+      == completion_entry_function_data_allocated)
+    {
+      if (completion_entry_function_data_allocated > 0)
+       completion_entry_function_data_allocated *= 2;
+      else
+       completion_entry_function_data_allocated = 0x100;
+      completion_entry_function_data = xrealloc (completion_entry_function_data,
+                                 (sizeof (*completion_entry_function_data)
+                                  * completion_entry_function_data_allocated));
+    }
+
+  cs = strchr (str, '\n');
+  if (cs == NULL || cs[1] != '\0')
+    fatal ("Invalid GDB data: %s", str);
+
+  if (strncmp (rl_line_buffer, str, rl_point) != 0)
+    fatal ("Completion GDB data do not match, have \"%.*s\", got \"%.*s\".",
+          (int) rl_point, rl_line_buffer, (int) (cs - str), str);
+
+  s = xmalloc (cs - str - line_start + 1);
+  memcpy (s, &str[line_start], cs - str - line_start);
+  s[cs - str - line_start] = '\0';
+  completion_entry_function_data[completion_entry_function_data_used++] = s;
+}
+
+static char *
+completion_entry_function (const char *text, int matches)
+{
+  mi_h *h = completion_entry_function_h;
+
+  gdb_assert (matches >= 0);
+  if (matches == 0)
+    {
+      mi_output *res;
+      int line_start;
+
+      while (completion_entry_function_data_used)
+       xfree (completion_entry_function_data
+              [--completion_entry_function_data_used]);
+      xfree (completion_entry_function_data);
+      completion_entry_function_data = NULL;
+      completion_entry_function_data_used = 0;
+      completion_entry_function_data_allocated = 0;
+
+      gdb_assert (rl_point >= 0);
+      gdb_assert (strlen (rl_line_buffer) >= rl_point);
+      gdb_assert (strlen (text) <= rl_point);
+      line_start = rl_point - strlen (text);
+      gdb_assert (strncmp (text, &rl_line_buffer[line_start],
+                          strlen (text)) == 0);
+      mi_send (h, "-interpreter-exec console \"complete %.*s\"\n",
+              (int) rl_point, rl_line_buffer);
+
+      mi_set_console_cb (h, completion_entry_function_console_cb,
+                        (void *) (intptr_t) line_start);
+      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);
+      mi_set_console_cb (h, console_cb, NULL);
+    }
+
+  if (matches < completion_entry_function_data_used)
+    return xstrdup (completion_entry_function_data[matches]);
+  else if (matches == completion_entry_function_data_used)
+    return NULL;
+  else
+    gdb_assert_not_reached ("too many matches");
+}
+
 int
 main (int argc, char **argv)
 {
@@ -267,6 +378,10 @@ main (int argc, char **argv)
 //  mi_set_to_gdb_cb (h, to_gdb_cb, NULL);
 //  mi_set_from_gdb_cb (h, from_gdb_cb, NULL);
 
+  completion_entry_function_h = h;
+  rl_completion_entry_function = completion_entry_function;
+  rl_readline_name = "gdb";        
+
   if (gdb_show_bool (h, "history save"))
     {
       int history_size = gdb_show_int (h, "history size");