Implemented pagination.
[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 <setjmp.h>
10 #include "ansidecl.h"
11 #include "mi_gdb.h"
12
13 #define fatal(fmt...) fatal_func (__FILE__, __LINE__, __PRETTY_FUNCTION__, fmt)
14 #define gdb_assert assert
15 #define gdb_assert_not_reached(msg) fatal ("%s", (msg))
16 #define _(x) x
17
18 static ATTRIBUTE_NORETURN void
19 fatal_func (const char *file, int line, const char *func, const char *fmt, ...)
20 {
21   va_list ap;
22
23   fprintf (stderr, "%s:%d:%s:", file, line, func);
24   va_start (ap, fmt);
25   vfprintf (stderr, fmt, ap);
26   va_end (ap);
27   fputc ('\n', stderr);
28 raise (SIGABRT);
29   exit (EXIT_FAILURE);
30 }
31
32 static char *
33 xstrdup (const char *s)
34 {
35   char *retval;
36
37   gdb_assert (s != NULL);
38   retval = strdup (s);
39   gdb_assert (retval != NULL);
40   return retval;
41 }
42
43 static void *
44 xmalloc (size_t size)
45 {
46   void *p;
47
48   gdb_assert (size != 0);
49   p = malloc (size);
50   gdb_assert (p != NULL);
51   return p;
52 }
53
54 static void *
55 xrealloc (void *p, size_t size)
56 {
57   if (p == NULL)
58     return xmalloc (size);
59   gdb_assert (size != 0);
60   p = realloc (p, size);
61   gdb_assert (p != NULL);
62   return p;
63 }
64
65 static void
66 xfree (void *p)
67 {
68   free (p);
69 }
70
71 static char *
72 xstrprintf (const char *fmt, ...)
73 {
74   va_list ap;
75   char *retval;
76   int i;
77
78   va_start (ap, fmt);
79   i = vasprintf (&retval, fmt, ap);
80   va_end (ap);
81   gdb_assert (i > 0);
82   gdb_assert (i == strlen (retval));
83   return retval;
84 }
85
86 static jmp_buf gdb_readline_jmp_buf;
87
88 static void
89 gdb_readline_sigint_handler (int signum)
90 {
91   gdb_assert (signum == SIGINT);
92   longjmp (gdb_readline_jmp_buf, 1);
93 }
94
95 static char *
96 gdb_readline (const char *prompt)
97 {
98   char *retval;
99   sighandler_t saved_handler;
100   sigset_t mask;
101   int i;
102
103   i = sigprocmask (SIG_SETMASK, NULL, &mask);
104   assert (i == 0);
105   saved_handler = signal (SIGINT, gdb_readline_sigint_handler);
106   if (setjmp (gdb_readline_jmp_buf) != 0)
107     {
108       rl_free_line_state ();
109       rl_cleanup_after_signal ();
110
111       /* GDB prints this.  */
112       puts ("Quit");
113
114       i = sigprocmask (SIG_SETMASK, &mask, NULL);
115       assert (i == 0);
116     }
117   retval = readline (prompt);
118   saved_handler = signal (SIGINT, saved_handler);
119   gdb_assert (saved_handler == gdb_readline_sigint_handler);
120   return retval;
121 }
122
123 static int console_cb_rows, console_cb_columns, console_cb_row, console_cb_column;
124 static bool console_cb_drop;
125
126 static void
127 console_cb (const char *str, void *data)
128 {
129   const char *cs;
130
131   if (console_cb_drop)
132     return;
133   if (console_cb_rows == 0)
134     {
135       fputs (str, stdout);
136       return;
137     }
138
139   while (*str != '\0')
140     {
141       int columns;
142       size_t size;
143       char *answer;
144
145       cs = strchr (str, '\n');
146       if (cs == NULL)
147         cs = &str[strlen (str)];
148       columns = min (cs - str, console_cb_columns - console_cb_column);
149       if (columns > 0)
150         {
151           size = fwrite (str, 1, columns, stdout);
152           gdb_assert (size == columns);
153           str += columns;
154           console_cb_column += columns;
155           continue;
156         }
157       if (*str == '\n')
158         str++;
159       else if (console_cb_column < console_cb_columns)
160         gdb_assert_not_reached ("we should not get here");
161       putchar ('\n');
162       console_cb_row++;
163       console_cb_column = 0;
164       if (console_cb_row < console_cb_rows - 1)
165         continue;
166       answer = gdb_readline (_("---Type <return> to continue, "
167                                "or q <return> to quit---"));
168       for (cs = answer; isspace (*cs); cs++);
169       if (*cs == 'q')
170         {
171           xfree (answer);
172           puts ("Quit");
173           console_cb_drop = true;
174           return;
175         }
176       xfree (answer);
177       console_cb_row = 0;
178     }
179 }
180
181 static int
182 time_out_cb (void *data)
183 {
184   fatal ("GDB response has timed out");
185   /* NOTREACHED */
186   return 0;
187 }
188
189 static ATTRIBUTE_UNUSED void
190 to_gdb_cb (const char *str, void *data)
191 {
192   printf ("to_gdb: %s\n", str);
193 }
194
195 static ATTRIBUTE_UNUSED void
196 from_gdb_cb (const char *str, void *data)
197 {
198   printf ("from_gdb: %s\n", str);
199 }
200
201 static void
202 h_disconnect (int rc, void *arg)
203 {
204   mi_h *h = arg;
205
206   mi_disconnect (h);
207 }
208
209 static void
210 history_save (int rc, void *arg)
211 {
212   const char *history_filename = arg;
213
214   write_history (history_filename);
215 }
216
217 static void
218 default_command (mi_h *h, const char *cmd)
219 {
220   int count = 1;
221
222   gdb_assert (strchr (cmd, '\n') == 0);
223   mi_send (h, "-interpreter-exec console \"%s\"\n", cmd);
224
225   while (count > 0)
226     {
227       mi_output *rec, *res;
228
229       res = mi_get_response_blk (h);
230       gdb_assert (res != NULL);
231
232       for (rec = res; rec != NULL; rec = rec->next)
233         switch (rec->tclass)
234         {
235           case MI_CL_DONE:
236             count--;
237             break;
238           case MI_CL_RUNNING:
239             /* We do not get MI_CL_DONE here, wait for MI_CL_STOPPED.  */
240             break;
241           case MI_CL_STOPPED:
242             count--;
243             break;
244           case MI_CL_ERROR:
245             count--;
246             gdb_assert (rec->c->type == t_const);
247             puts (rec->c->v.cstr);
248             break;
249           default:
250             fatal ("mi_get_rrecord == MI_CL_??? (%d)", rec->tclass);
251         }
252
253       mi_free_output (res);
254     }
255 }
256
257 static void
258 quit_command (mi_h *h, const char *cmd)
259 {
260   exit (EXIT_SUCCESS);
261 }
262
263 static char *
264 mi_escape (const char *cs)
265 {
266   char *d, *retval = xmalloc (strlen (cs) * 2 + 1);
267
268   d = retval;
269   while (*cs)
270     {
271       if (*cs == '"' || *cs == '\\')
272         *d++ = '\\';
273       *d++ = *cs++;
274     }
275   *d = '\0';
276   return retval;
277 }
278
279 static void
280 gdb_done (mi_h *h, const char *command)
281 {
282   mi_output *res;
283
284   mi_send (h, "%s\n", command);
285   res = mi_get_response_blk (h);
286   gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
287               && res->c == NULL);
288   mi_free_output (res);
289 }
290
291 static void
292 commands_command_console_cb (const char *str, void *data)
293 {
294   char **strptr = data;
295
296   gdb_assert (*strptr == NULL);
297   *strptr = xstrdup (str);
298 }
299
300 static void
301 commands_command (mi_h *h, const char *cmd_param)
302 {
303   char *cmd = xstrdup ("");
304   size_t cmd_len = 0;
305   mi_output *res;
306   char *bpnum = NULL;
307   int nesting;
308
309   if (*cmd_param == '\0')
310     {
311       mi_set_console_cb (h, commands_command_console_cb, &bpnum);
312       gdb_done (h, "output $bpnum");
313       mi_set_console_cb (h, console_cb, NULL);
314       gdb_assert (bpnum != NULL);
315       cmd_param = bpnum;
316     }
317
318   printf (_("Type commands for breakpoint(s) %s, one per line.\n"
319             "End with a line saying just \"end\".\n"), cmd_param);
320
321   nesting = 0;
322   while (nesting >= 0)
323     {
324       char *prompt, *data, *data2, *start, *end;
325       size_t data2_len;
326       int do_nest = 0;
327
328       prompt = xstrprintf ("%*s>", (int) nesting);
329       data = gdb_readline (prompt);
330       xfree (prompt);
331       if (data == NULL)
332         data = xstrdup ("end");
333
334       for (start = data; isspace (*start); start++);
335       for (end = data + strlen (data); end > start && isspace (end[-1]); end--);
336       data2 = xmalloc (end - start + 1);
337       memcpy (data2, start, end - start);
338       data2[end - start] = '\0';
339       if (strcmp (data2, "python") == 0)
340         do_nest = 1;
341       if (strcmp (data2, "end") == 0)
342         do_nest = -1;
343       for (end = data2; *end && !isspace (*end); end++);
344       *end = '\0';
345
346       /* Here is a bug in GDB, it does not recognize command shortcuts.  */
347       if (strcmp (data2, "while") == 0 || strcmp (data2, "if") == 0
348           || strcmp (data2, "commands") == 0
349           || strcmp (data2, "while-stepping") == 0
350           || strcmp (data2, "stepping") == 0 || strcmp (data2, "ws") == 0)
351         do_nest = 1;
352       xfree (data2);
353
354       nesting += do_nest;
355       if (nesting < 0)
356         break;
357
358       data2 = mi_escape (data);
359       xfree (data);
360       data2_len = strlen (data2);
361       cmd = xrealloc (cmd, cmd_len + 2 + data2_len + 2);
362       cmd[cmd_len] = ' ';
363       cmd[cmd_len + 1] = '"';
364       memcpy (&cmd[cmd_len + 2], data2, data2_len);
365       cmd[cmd_len + 2 + data2_len] = '"';
366       cmd[cmd_len + 2 + data2_len + 1] = '\0';
367       cmd_len += 2 + data2_len + 1;
368       xfree (data2);
369     }
370
371   mi_send (h, "-break-commands %s%s\n", cmd_param, cmd);
372   xfree (cmd);
373   xfree (bpnum);
374
375   res = mi_get_response_blk (h);
376   gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
377               && res->c == NULL);
378   mi_free_output (res);
379 }
380
381 static const struct cmd
382 {
383   const char *name;
384   int min_shortcut;
385   void (*func) (mi_h *h, const char *cmd);
386 } cmds[] =
387 {
388   { "quit", 1, quit_command },
389   { "commands", 4, commands_command },
390 };
391
392 static void
393 executecommand (mi_h *h, const char *cmd)
394 {
395   const char *start, *end, *cs;
396   const struct cmd *cmdp;
397
398   cs = cmd;
399   while (isspace (*cs))
400     cs++;
401   start = cs;
402   while (isalnum (*cs))
403     cs++;
404   end = cs;
405   while (isspace (*cs))
406     cs++;
407
408   for (cmdp = cmds; cmdp < &cmds[LENGTH (cmds)]; cmdp++)
409     if (cmdp->min_shortcut <= end - start && end - start <= strlen (cmdp->name)
410         && strncmp (start, cmdp->name, end - start) == 0)
411       return cmdp->func (h, cs);
412
413   return default_command (h, cmd);
414 }
415
416 static void
417 gdb_set_string (mi_h *h, const char *setting, const char *value)
418 {
419   char *cmd = xstrprintf ("-gdb-set %s %s", setting, value);
420
421   gdb_done (h, cmd);
422   xfree (cmd);
423 }
424
425 static void
426 gdb_set_bool (mi_h *h, const char *setting, bool value)
427 {
428   gdb_set_string (h, setting, value ? "on" : "off");
429 }
430
431 static char *
432 gdb_show_string (mi_h *h, const char *setting)
433 {
434   mi_output *res;
435   char *retval;
436
437   mi_send (h, "-gdb-show %s\n", setting);
438   res = mi_get_response_blk (h);
439   gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
440               && res->c != NULL && res->c->next == NULL
441               && res->c->type == t_const && strcmp (res->c->var, "value") == 0);
442   retval = xstrdup (res->c->v.cstr);
443   mi_free_output (res);
444   return retval;
445 }
446
447 static int
448 gdb_show_int (mi_h *h, const char *setting)
449 {
450   char *string = gdb_show_string (h, setting);
451   long l;
452   int retval;
453   char *end;
454
455   errno = 0;
456   retval = l = strtol (string, &end, 10);
457   gdb_assert (errno == 0 && (end == NULL || *end == '\0') && retval == l);
458   xfree (string);
459   return retval;
460 }
461
462 static bool
463 gdb_show_bool (mi_h *h, const char *setting)
464 {
465   char *string = gdb_show_string (h, setting);
466   bool retval;
467
468   retval = strcmp (string, "on") == 0;
469   gdb_assert (retval || strcmp (string, "off") == 0);
470   xfree (string);
471   return retval;
472 }
473
474 static mi_h *completion_entry_function_h;
475
476 static char **completion_entry_function_data;
477 static size_t completion_entry_function_data_used;
478 static size_t completion_entry_function_data_allocated;
479
480 static void
481 completion_entry_function_console_cb (const char *str, void *data)
482 {
483   int line_start = (intptr_t) data;
484   const char *cs;
485   char *s;
486
487   if (completion_entry_function_data_used
488       == completion_entry_function_data_allocated)
489     {
490       if (completion_entry_function_data_allocated > 0)
491         completion_entry_function_data_allocated *= 2;
492       else
493         completion_entry_function_data_allocated = 0x100;
494       completion_entry_function_data = xrealloc (completion_entry_function_data,
495                                   (sizeof (*completion_entry_function_data)
496                                    * completion_entry_function_data_allocated));
497     }
498
499   cs = strchr (str, '\n');
500   if (cs == NULL || cs[1] != '\0')
501     fatal ("Invalid GDB data: %s", str);
502
503   if (strncmp (rl_line_buffer, str, rl_point) != 0)
504     fatal ("Completion GDB data do not match, have \"%.*s\", got \"%.*s\".",
505            (int) rl_point, rl_line_buffer, (int) (cs - str), str);
506
507   s = xmalloc (cs - str - line_start + 1);
508   memcpy (s, &str[line_start], cs - str - line_start);
509   s[cs - str - line_start] = '\0';
510   completion_entry_function_data[completion_entry_function_data_used++] = s;
511 }
512
513 static char *
514 completion_entry_function (const char *text, int matches)
515 {
516   mi_h *h = completion_entry_function_h;
517
518   gdb_assert (matches >= 0);
519   if (matches == 0)
520     {
521       mi_output *res;
522       int line_start;
523
524       while (completion_entry_function_data_used)
525         xfree (completion_entry_function_data
526                [--completion_entry_function_data_used]);
527       xfree (completion_entry_function_data);
528       completion_entry_function_data = NULL;
529       completion_entry_function_data_used = 0;
530       completion_entry_function_data_allocated = 0;
531
532       gdb_assert (rl_point >= 0);
533       gdb_assert (strlen (rl_line_buffer) >= rl_point);
534       gdb_assert (strlen (text) <= rl_point);
535       line_start = rl_point - strlen (text);
536       gdb_assert (strncmp (text, &rl_line_buffer[line_start],
537                            strlen (text)) == 0);
538       mi_send (h, "-interpreter-exec console \"complete %.*s\"\n",
539                (int) rl_point, rl_line_buffer);
540
541       mi_set_console_cb (h, completion_entry_function_console_cb,
542                          (void *) (intptr_t) line_start);
543       res = mi_get_response_blk (h);
544       gdb_assert (res != NULL && res->next == NULL && res->tclass == MI_CL_DONE
545                   && res->c == NULL);
546       mi_free_output (res);
547       mi_set_console_cb (h, console_cb, NULL);
548     }
549
550   if (matches < completion_entry_function_data_used)
551     return xstrdup (completion_entry_function_data[matches]);
552   else if (matches == completion_entry_function_data_used)
553     return NULL;
554   else
555     gdb_assert_not_reached ("too many matches");
556 }
557
558 extern char **mi_gdb_argv;
559 extern void (*mi_gdb_start_hook) (mi_h *h);
560
561 static void
562 start_hook (mi_h *h)
563 {
564   on_exit (h_disconnect, h);
565   mi_set_console_cb (h, console_cb, NULL);
566   mi_set_time_out_cb (h, time_out_cb, NULL);
567
568 //  mi_set_to_gdb_cb (h, to_gdb_cb, NULL);
569 //  mi_set_from_gdb_cb (h, from_gdb_cb, NULL);
570 }
571
572 int
573 main (int argc, char **argv)
574 {
575   mi_h *h;
576   mi_output *res;
577
578   setbuf (stdout, NULL);
579
580   mi_gdb_argv = xmalloc ((argc + 2) * sizeof (*mi_gdb_argv));
581   memcpy (&mi_gdb_argv[2], &argv[1], argc * sizeof (*mi_gdb_argv));
582   mi_gdb_argv[0] = "gdb";
583   mi_gdb_argv[1] = "--interpreter=mi";
584
585   mi_gdb_start_hook = start_hook;
586
587   h = mi_connect_local ();
588   if (h == NULL)
589     fatal ("Cannot connect to GDB");
590
591   /* First eat the prompt.  Then run empty command so that additional results
592      from -ex or -x during mi_connect_local are flushed.  */
593   res = mi_get_response_blk (h);
594   gdb_assert (res == NULL);
595   default_command (h, "echo");
596
597   completion_entry_function_h = h;
598   rl_completion_entry_function = completion_entry_function;
599   rl_readline_name = "gdb";        
600
601   if (gdb_show_bool (h, "history save"))
602     {
603       int history_size = gdb_show_int (h, "history size");
604       char *history_filename = gdb_show_string (h, "history filename");
605
606       gdb_set_bool (h, "history save", false);
607       stifle_history (history_size);
608       read_history (history_filename);
609       on_exit (history_save, history_filename);
610       /* Do not free HISTORY_FILENAME.  */
611     }
612
613   for (;;)
614     {
615       char *prompt, *cmd;
616       
617       prompt = gdb_show_string (h, "prompt");
618       cmd = gdb_readline (prompt);
619       xfree (prompt);
620
621       /* FIXME: -ex commands do not have pagination set.  */
622       if (!gdb_show_bool (h, "pagination"))
623         console_cb_rows = 0;
624       else
625         rl_get_screen_size (&console_cb_rows, &console_cb_columns);
626       console_cb_drop = false;
627       console_cb_row = console_cb_column = 0;
628
629       if (cmd == NULL)
630         cmd = xstrdup ("quit");
631       else
632         add_history (cmd);
633
634       executecommand (h, cmd);
635       xfree (cmd);
636     }
637 }