Commends interpretation etc.
[gdbmicli.git] / main.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include <signal.h>
5 #include <readline/readline.h>
6 #include <readline/history.h>
7 #include <assert.h>
8 #include <errno.h>
9 #include "ansidecl.h"
10 #include "mi_gdb.h"
11
12 #define gdb_assert assert
13
14 static ATTRIBUTE_NORETURN void
15 fatal (const char *fmt, ...)
16 {
17   va_list ap;
18
19   va_start (ap, fmt);
20   vfprintf (stderr, fmt, ap);
21   va_end (ap);
22 raise (SIGABRT);
23   exit (EXIT_FAILURE);
24 }
25
26 static char *
27 xstrdup (const char *s)
28 {
29   char *retval;
30
31   gdb_assert (s != NULL);
32   retval = strdup (s);
33   gdb_assert (retval != NULL);
34   return retval;
35 }
36
37 static void
38 xfree (void *p)
39 {
40   free (p);
41 }
42
43 static char *
44 xstrprintf (const char *fmt, ...)
45 {
46   va_list ap;
47   char *retval;
48   int i;
49
50   va_start (ap, fmt);
51   i = vasprintf (&retval, fmt, ap);
52   va_end (ap);
53   gdb_assert (i > 0);
54   gdb_assert (i == strlen (retval));
55   return retval;
56 }
57
58 static void
59 console_cb (const char *str, void *data)
60 {
61   fputs (str, stdout);
62 }
63
64 static ATTRIBUTE_UNUSED void
65 to_gdb_cb (const char *str, void *data)
66 {
67   printf ("to_gdb: %s\n", str);
68 }
69
70 static ATTRIBUTE_UNUSED void
71 from_gdb_cb (const char *str, void *data)
72 {
73   printf ("from_gdb: %s\n", str);
74 }
75
76 static void
77 h_disconnect (int rc, void *arg)
78 {
79   mi_h *h = arg;
80
81   mi_disconnect (h);
82 }
83
84 static void
85 history_save (int rc, void *arg)
86 {
87   const char *history_filename = arg;
88
89   write_history (history_filename);
90 }
91
92 static void
93 quit_command (mi_h *h, const char *cmd)
94 {
95   exit (EXIT_SUCCESS);
96 }
97
98 static void
99 default_command (mi_h *h, const char *cmd)
100 {
101   int count = 1;
102
103   mi_send (h, "-interpreter-exec console \"%s\"\n", cmd);
104
105   while (count > 0)
106     {
107       mi_output *rec, *res;
108
109       res = mi_get_response_blk (h);
110       gdb_assert (res != NULL);
111
112       for (rec = res; rec != NULL; rec = rec->next)
113         switch (rec->tclass)
114         {
115           case MI_CL_DONE:
116             count--;
117             break;
118           case MI_CL_RUNNING:
119             /* We do not get MI_CL_DONE here, wait for MI_CL_STOPPED.  */
120             break;
121           case MI_CL_STOPPED:
122             count--;
123             break;
124           case MI_CL_ERROR:
125             gdb_assert (rec->c->type == t_const);
126             puts (rec->c->v.cstr);
127             break;
128           default:
129             fatal ("mi_get_rrecord == MI_CL_??? (%d)", rec->tclass);
130         }
131
132       mi_free_output (res);
133     }
134 }
135
136 static const struct cmd
137 {
138   const char *name;
139   void (*func) (mi_h *h, const char *cmd);
140 } cmds[] =
141 {
142   { "q", quit_command },
143   { "qu", quit_command },
144   { "qui", quit_command },
145   { "quit", quit_command },
146 };
147
148 static void
149 executecommand (mi_h *h, const char *cmd)
150 {
151   const char *start, *end, *cs;
152   const struct cmd *cmdp;
153
154   cs = cmd;
155   while (isspace (*cs))
156     cs++;
157   start = cs;
158   while (isalnum (*cs))
159     cs++;
160   end = cs;
161
162   for (cmdp = cmds; cmdp < &cmds[LENGTH (cmds)]; cmdp++)
163     if (strlen (cmdp->name) == end - start
164         && strncmp (cmd, cmdp->name, end - start) == 0)
165       return cmdp->func (h, cmd);
166
167   return default_command (h, cmd);
168 }
169
170 static void
171 gdb_done (mi_h *h, const char *command)
172 {
173   mi_output *res;
174
175   mi_send (h, "%s\n", command);
176   res = mi_get_response_blk (h);
177   gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
178               && res->c == NULL);
179   mi_free_output (res);
180 }
181
182 static void
183 gdb_set_string (mi_h *h, const char *setting, const char *value)
184 {
185   char *cmd = xstrprintf ("-gdb-set %s %s", setting, value);
186
187   gdb_done (h, cmd);
188   xfree (cmd);
189 }
190
191 static void
192 gdb_set_bool (mi_h *h, const char *setting, bool value)
193 {
194   gdb_set_string (h, setting, value ? "on" : "off");
195 }
196
197 static char *
198 gdb_show_string (mi_h *h, const char *setting)
199 {
200   mi_output *res;
201   char *retval;
202
203   mi_send (h, "-gdb-show %s\n", setting);
204   res = mi_get_response_blk (h);
205   gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
206               && res->c != NULL && res->c->next == NULL
207               && res->c->type == t_const && strcmp (res->c->var, "value") == 0);
208   retval = xstrdup (res->c->v.cstr);
209   mi_free_output (res);
210   return retval;
211 }
212
213 static int
214 gdb_show_int (mi_h *h, const char *setting)
215 {
216   char *string = gdb_show_string (h, setting);
217   long l;
218   int retval;
219   char *end;
220
221   errno = 0;
222   retval = l = strtol (string, &end, 10);
223   gdb_assert (errno == 0 && (end == NULL || *end == '\0') && retval == l);
224   xfree (string);
225   return retval;
226 }
227
228 static bool
229 gdb_show_bool (mi_h *h, const char *setting)
230 {
231   char *string = gdb_show_string (h, setting);
232   bool retval;
233
234   retval = strcmp (string, "on") == 0;
235   gdb_assert (retval || strcmp (string, "off") == 0);
236   xfree (string);
237   return retval;
238 }
239
240 int
241 main (int argc, char **argv)
242 {
243   mi_h *h;
244   char *cmd;
245   const char *ex[argc];
246   unsigned ex_count = 0, ex_used = 0;
247
248   setbuf (stdout, NULL);
249
250   while (*++argv != NULL)
251     {
252       if (strcmp (*argv, "-ex") == 0 && argv[1] != NULL)
253         ex[ex_count++] = *++argv;
254       else
255         fatal ("Unknown parameter: %s", *argv);
256     }
257
258   mi_set_workaround (MI_PSYM_SEARCH, 0);
259
260   h = mi_connect_local ();
261   if (h == NULL)
262     fatal ("Cannot connect to GDB");
263
264   on_exit (h_disconnect, h);
265
266   mi_set_console_cb (h, console_cb, NULL);
267 //  mi_set_to_gdb_cb (h, to_gdb_cb, NULL);
268 //  mi_set_from_gdb_cb (h, from_gdb_cb, NULL);
269
270   if (gdb_show_bool (h, "history save"))
271     {
272       int history_size = gdb_show_int (h, "history size");
273       char *history_filename = gdb_show_string (h, "history filename");
274
275       gdb_set_bool (h, "history save", false);
276       stifle_history (history_size);
277       read_history (history_filename);
278       on_exit (history_save, history_filename);
279       /* Do not free HISTORY_FILENAME.  */
280     }
281
282   for (;;)
283     {
284       if (ex_used < ex_count)
285         {
286           cmd = xstrdup (ex[ex_used++]);
287           printf ("(gdb) %s\n", cmd);
288         }
289       else
290         {
291           cmd = readline ("(gdb) ");
292           if (cmd == NULL)
293             cmd = xstrdup ("quit");
294           else
295             add_history (cmd);
296         }
297       executecommand (h, cmd);
298       xfree (cmd);
299     }
300 }