import gdb-1999-10-18 snapshot
[platform/upstream/binutils.git] / gdb / tui / tui.c
1 /*
2    ** tui.c
3    **         General functions for the WDB TUI
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <ctype.h>
9 #include <malloc.h>
10 #include <curses.h>
11 #ifdef HAVE_TERM_H
12 #include <term.h>
13 #endif
14 #include <signal.h>
15 #include <fcntl.h>
16 #include <termio.h>
17 #include <setjmp.h>
18 #include "defs.h"
19 #include "gdbcmd.h"
20 #include "tui.h"
21 #include "tuiData.h"
22 #include "tuiLayout.h"
23 #include "tuiIO.h"
24 #include "tuiRegs.h"
25 #include "tuiWin.h"
26
27 /* The Solaris header files seem to provide no declaration for this at
28    all when __STDC__ is defined.  This shouldn't conflict with
29    anything.  */
30 extern char *tgoto ();
31
32 /***********************
33 ** Local Definitions
34 ************************/
35 #define FILEDES         2
36 /* Solaris <sys/termios.h> defines CTRL. */
37 #ifndef CTRL
38 #define CTRL(x)         (x & ~0140)
39 #endif
40 #define CHK(val, dft)   (val<=0 ? dft : val)
41
42 #define TOGGLE_USAGE "Usage:toggle breakpoints"
43 #define TUI_TOGGLE_USAGE "Usage:\ttoggle $fregs\n\ttoggle breakpoints"
44
45 /*****************************
46 ** Local static forward decls
47 ******************************/
48 static void _tuiReset PARAMS ((void));
49 static void _toggle_command PARAMS ((char *, int));
50 static void _tui_vToggle_command PARAMS ((va_list));
51 static Opaque _tui_vDo PARAMS ((TuiOpaqueFuncPtr, va_list));
52
53
54
55 /***********************
56 ** Public Functions
57 ************************/
58
59 /*
60    ** tuiInit().
61  */
62 void
63 #ifdef __STDC__
64 tuiInit (char *argv0)
65 #else
66 tuiInit (argv0)
67      char *argv0;
68 #endif
69 {
70   extern void init_page_info ();
71   extern void initialize_tui_files PARAMS ((void));
72
73   initialize_tui_files ();
74   initializeStaticData ();
75   initscr ();
76   refresh ();
77   setTermHeightTo (LINES);
78   setTermWidthTo (COLS);
79   tuiInitWindows ();
80   wrefresh (cmdWin->generic.handle);
81   init_page_info ();
82   /* Don't hook debugger output if doing command-window
83      * the XDB way. However, one thing we do want to do in
84      * XDB style is set up the scrolling region to be
85      * the bottom of the screen (tuiTermUnsetup()).
86    */
87   fputs_unfiltered_hook = NULL;
88   rl_initialize ();             /* need readline initialization to
89                                    * create termcap sequences
90                                  */
91   tuiTermUnsetup (1, cmdWin->detail.commandInfo.curch);
92
93   return;
94 }                               /* tuiInit */
95
96
97 /*
98    ** tuiInitWindows().
99  */
100 void
101 #ifdef __STDC__
102 tuiInitWindows (void)
103 #else
104 tuiInitWindows ()
105 #endif
106 {
107   TuiWinType type;
108
109   tuiSetLocatorContent (0);
110   showLayout (SRC_COMMAND);
111   keypad (cmdWin->generic.handle, TRUE);
112   echo ();
113   crmode ();
114   nl ();
115   tuiSetWinFocusTo (srcWin);
116
117   return;
118 }                               /* tuiInitWindows */
119
120
121 /*
122    ** tuiCleanUp().
123    **        Kill signal handler and cleanup termination method
124  */
125 void
126 #ifdef __STDC__
127 tuiResetScreen (void)
128 #else
129 tuiResetScreen ()
130 #endif
131 {
132   TuiWinType type = SRC_WIN;
133
134   keypad (cmdWin->generic.handle, FALSE);
135   for (; type < MAX_MAJOR_WINDOWS; type++)
136     {
137       if (m_winPtrNotNull (winList[type]) &&
138           winList[type]->generic.type != UNDEFINED_WIN &&
139           !winList[type]->generic.isVisible)
140         tuiDelWindow (winList[type]);
141     }
142   endwin ();
143   initscr ();
144   refresh ();
145   echo ();
146   crmode ();
147   nl ();
148
149   return;
150 }                               /* tuiResetScreen */
151
152
153 /*
154    ** tuiCleanUp().
155    **        Kill signal handler and cleanup termination method
156  */
157 void
158 #ifdef __STDC__
159 tuiCleanUp (void)
160 #else
161 tuiCleanUp ()
162 #endif
163 {
164   char *buffer;
165   extern char *term_cursor_move;
166
167   signal (SIGINT, SIG_IGN);
168   tuiTermSetup (0);             /* Restore scrolling region to whole screen */
169   keypad (cmdWin->generic.handle, FALSE);
170   freeAllWindows ();
171   endwin ();
172   buffer = tgoto (term_cursor_move, 0, termHeight ());
173   tputs (buffer, 1, putchar);
174   _tuiReset ();
175
176   return;
177 }                               /* tuiCleanUp */
178
179
180 /*
181    ** tuiError().
182  */
183 void
184 #ifdef __STDC__
185 tuiError (
186            char *string,
187            int exitGdb)
188 #else
189 tuiError (string, exitGdb)
190      char *string;
191      int exitGdb;
192 #endif
193 {
194   puts_unfiltered (string);
195   if (exitGdb)
196     {
197       tuiCleanUp ();
198       exit (-1);
199     }
200
201   return;
202 }                               /* tuiError */
203
204
205 /*
206    ** tui_vError()
207    **        tuiError with args in a va_list.
208  */
209 void
210 #ifdef __STDC__
211 tui_vError (
212              va_list args)
213 #else
214 tui_vError (args)
215      va_list args;
216 #endif
217 {
218   char *string;
219   int exitGdb;
220
221   string = va_arg (args, char *);
222   exitGdb = va_arg (args, int);
223
224   tuiError (string, exitGdb);
225
226   return;
227 }                               /* tui_vError */
228
229
230 /*
231    ** tuiFree()
232    **    Wrapper on top of free() to ensure that input address is greater than 0x0
233  */
234 void
235 #ifdef __STDC__
236 tuiFree (
237           char *ptr)
238 #else
239 tuiFree (ptr)
240      char *ptr;
241 #endif
242 {
243   if (ptr != (char *) NULL)
244     {
245       free (ptr);
246     }
247
248   return;
249 }                               /* tuiFree */
250
251
252 /* tuiGetLowDisassemblyAddress().
253    **        Determine what the low address will be to display in the TUI's
254    **        disassembly window.  This may or may not be the same as the
255    **        low address input.
256  */
257 Opaque
258 #ifdef __STDC__
259 tuiGetLowDisassemblyAddress (
260                               Opaque low,
261                               Opaque pc)
262 #else
263 tuiGetLowDisassemblyAddress (low, pc)
264      Opaque low;
265      Opaque pc;
266 #endif
267 {
268   int line;
269   Opaque newLow;
270
271   /*
272      ** Determine where to start the disassembly so that the pc is about in the
273      ** middle of the viewport.
274    */
275   for (line = 0, newLow = pc;
276        (newLow > low &&
277         line < (tuiDefaultWinViewportHeight (DISASSEM_WIN,
278                                              DISASSEM_COMMAND) / 2));)
279     {
280       bfd_byte buffer[4];
281
282       newLow -= sizeof (bfd_getb32 (buffer));
283       line++;
284     }
285
286   return newLow;
287 }                               /* tuiGetLowDisassemblyAddress */
288
289
290 /* tui_vGetLowDisassemblyAddress().
291    **        Determine what the low address will be to display in the TUI's
292    **        disassembly window with args in a va_list.
293  */
294 Opaque
295 #ifdef __STDC__
296 tui_vGetLowDisassemblyAddress (
297                                 va_list args)
298 #else
299 tui_vGetLowDisassemblyAddress (args)
300      va_list args;
301 #endif
302 {
303   int line;
304   Opaque newLow;
305   Opaque low;
306   Opaque pc;
307
308   low = va_arg (args, Opaque);
309   pc = va_arg (args, Opaque);
310
311   return (tuiGetLowDisassemblyAddress (low, pc));
312
313 }                               /* tui_vGetLowDisassemblyAddress */
314
315
316 /*
317    ** tuiDo().
318    **        General purpose function to execute a tui function.  Transitions
319    **        between curses and the are handled here.  This function is called
320    **        by non-tui gdb functions.
321    **
322    **        Errors are caught here.
323    **        If there is no error, the value returned by 'func' is returned.
324    **        If there is an error, then zero is returned.
325    **
326    **       Must not be called with immediate_quit in effect (bad things might
327    **       happen, say we got a signal in the middle of a memcpy to quit_return).
328    **       This is an OK restriction; with very few exceptions immediate_quit can
329    **       be replaced by judicious use of QUIT.
330  */
331 Opaque
332 #ifdef __STDC__
333 tuiDo (
334         TuiOpaqueFuncPtr func,...)
335 #else
336 tuiDo (func, va_alist)
337      TuiOpaqueFuncPtr func;
338      va_dcl
339 #endif
340 {
341   extern int terminal_is_ours;
342
343   Opaque ret = (Opaque) NULL;
344
345   /* It is an error to be tuiDo'ing if we
346      * don't own the terminal.
347    */
348   if (!terminal_is_ours)
349     return ret;
350
351   if (tui_version)
352     {
353       va_list args;
354
355 #ifdef __STDC__
356       va_start (args, func);
357 #else
358       va_start (args);
359 #endif
360       ret = _tui_vDo (func, args);
361       va_end (args);
362     }
363
364   return ret;
365 }                               /* tuiDo */
366
367
368 /*
369    ** tuiDoAndReturnToTop().
370    **        General purpose function to execute a tui function.  Transitions
371    **        between curses and the are handled here.  This function is called
372    **        by non-tui gdb functions who wish to reset gdb to the top level.
373    **        After the tuiDo is performed, a return to the top level occurs.
374    **
375    **        Errors are caught here.
376    **        If there is no error, the value returned by 'func' is returned.
377    **        If there is an error, then zero is returned.
378    **
379    **       Must not be called with immediate_quit in effect (bad things might
380    **       happen, say we got a signal in the middle of a memcpy to quit_return).
381    **       This is an OK restriction; with very few exceptions immediate_quit can
382    **       be replaced by judicious use of QUIT.
383    **
384  */
385 Opaque
386 #ifdef __STDC__
387 tuiDoAndReturnToTop (
388                       TuiOpaqueFuncPtr func,...)
389 #else
390 tuiDoAndReturnToTop (func, va_alist)
391      TuiOpaqueFuncPtr func;
392      va_dcl
393 #endif
394 {
395   extern int terminal_is_ours;
396
397   Opaque ret = (Opaque) NULL;
398
399   /* It is an error to be tuiDo'ing if we
400      * don't own the terminal.
401    */
402   if (!terminal_is_ours)
403     return ret;
404
405   if (tui_version)
406     {
407       va_list args;
408
409 #ifdef __STDC__
410       va_start (args, func);
411 #else
412       va_start (args);
413 #endif
414       ret = _tui_vDo (func, args);
415
416       /* force a return to the top level */
417       return_to_top_level (RETURN_ERROR);
418     }
419
420   return ret;
421 }                               /* tuiDoAndReturnToTop */
422
423
424 void
425 #ifdef __STDC__
426 tui_vSelectSourceSymtab (
427                           va_list args)
428 #else
429 tui_vSelectSourceSymtab (args)
430      va_list args;
431 #endif
432 {
433   struct symtab *s = va_arg (args, struct symtab *);
434
435   select_source_symtab (s);
436   return;
437 }                               /* tui_vSelectSourceSymtab */
438
439
440 /*
441    ** _initialize_tui().
442    **      Function to initialize gdb commands, for tui window manipulation.
443  */
444 void
445 _initialize_tui ()
446 {
447 #if 0
448   if (tui_version)
449     {
450       add_com ("toggle", class_tui, _toggle_command,
451                "Toggle Terminal UI Features\n\
452 Usage: Toggle $fregs\n\
453 \tToggles between single and double precision floating point registers.\n");
454     }
455 #endif
456   char *helpStr;
457
458   if (tui_version)
459     helpStr = "Toggle Specified Features\n\
460 Usage:\ttoggle $fregs\n\ttoggle breakpoints";
461   else
462     helpStr = "Toggle Specified Features\nUsage:toggle breakpoints";
463   add_abbrev_prefix_cmd ("toggle",
464                          class_tui,
465                          _toggle_command,
466                          helpStr,
467                          &togglelist,
468                          "toggle ",
469                          1,
470                          &cmdlist);
471 }                               /* _initialize_tui */
472
473
474 /*
475    ** va_catch_errors().
476    **       General purpose function to execute a function, catching errors.
477    **       If there is no error, the value returned by 'func' is returned.
478    **       If there is error, then zero is returned.
479    **       Note that 'func' must take a variable argument list as well.
480    **
481    **       Must not be called with immediate_quit in effect (bad things might
482    **       happen, say we got a signal in the middle of a memcpy to quit_return).
483    **       This is an OK restriction; with very few exceptions immediate_quit can
484    **       be replaced by judicious use of QUIT.
485  */
486 Opaque
487 #ifdef __STDC__
488 va_catch_errors (
489                   TuiOpaqueFuncPtr func,
490                   va_list args)
491 #else
492 va_catch_errors (func, args)
493      TuiOpaqueFuncPtr func;
494      va_list args;
495 #endif
496 {
497   Opaque ret = (Opaque) NULL;
498
499   /*
500      ** We could have used catch_errors(), but it doesn't handle variable args.
501      ** Also, for the tui, we always want to catch all errors, so we don't
502      ** need to pass a mask, or an error string.
503    */
504   jmp_buf saved_error;
505   jmp_buf saved_quit;
506   jmp_buf tmp_jmp;
507   struct cleanup *saved_cleanup_chain;
508   char *saved_error_pre_print;
509   char *saved_quit_pre_print;
510   extern jmp_buf error_return;
511   extern jmp_buf quit_return;
512
513   saved_cleanup_chain = save_cleanups ();
514   saved_error_pre_print = error_pre_print;
515   saved_quit_pre_print = quit_pre_print;
516
517   memcpy ((char *) saved_error, (char *) error_return, sizeof (jmp_buf));
518   error_pre_print = "";
519   memcpy (saved_quit, quit_return, sizeof (jmp_buf));
520   quit_pre_print = "";
521
522   if (setjmp (tmp_jmp) == 0)
523     {
524       va_list argList = args;
525       memcpy (error_return, tmp_jmp, sizeof (jmp_buf));
526       memcpy (quit_return, tmp_jmp, sizeof (jmp_buf));
527       ret = func (argList);
528     }
529   restore_cleanups (saved_cleanup_chain);
530   memcpy (error_return, saved_error, sizeof (jmp_buf));
531   error_pre_print = saved_error_pre_print;
532   memcpy (quit_return, saved_quit, sizeof (jmp_buf));
533   quit_pre_print = saved_quit_pre_print;
534
535   return ret;
536 }
537
538 /*
539    ** vcatch_errors().
540    **        Catch errors occurring in tui or non tui function, handling
541    **        variable param lists. Note that 'func' must take a variable
542    **        argument list as well.
543  */
544 Opaque
545 #ifdef __STDC__
546 vcatch_errors (
547                 OpaqueFuncPtr func,...)
548 #else
549 vcatch_errors (va_alist)
550      va_dcl
551 /*
552    vcatch_errors(func, va_alist)
553    OpaqueFuncPtr    func;
554    va_dcl
555  */
556 #endif
557 {
558   Opaque ret = (Opaque) NULL;
559   va_list args;
560 #ifdef __STDC__
561   va_start (args, func);
562 /*
563    va_arg(args, OpaqueFuncPtr);
564  */
565 #else
566   OpaqueFuncPtr func;
567
568   va_start (args);
569   func = va_arg (args, OpaqueFuncPtr);
570 #endif
571   ret = va_catch_errors (func, args);
572   va_end (args);
573
574   return ret;
575 }
576
577
578 void
579 #ifdef __STDC__
580 strcat_to_buf (
581                 char *buf,
582                 int buflen,
583                 char *itemToAdd)
584 #else
585 strcat_to_buf (buf, buflen, itemToAdd)
586      char *buf;
587      int buflen;
588      char *itemToAdd;
589 #endif
590 {
591   if (itemToAdd != (char *) NULL && buf != (char *) NULL)
592     {
593       if ((strlen (buf) + strlen (itemToAdd)) <= buflen)
594         strcat (buf, itemToAdd);
595       else
596         strncat (buf, itemToAdd, (buflen - strlen (buf)));
597     }
598
599   return;
600 }                               /* strcat_to_buf */
601
602 /* VARARGS */
603 void
604 #ifdef ANSI_PROTOTYPES
605 strcat_to_buf_with_fmt (
606                          char *buf,
607                          int bufLen,
608                          char *format,...)
609 #else
610 strcat_to_buf_with_fmt (va_alist)
611      va_dcl
612 #endif
613 {
614   char *linebuffer;
615   struct cleanup *old_cleanups;
616   va_list args;
617 #ifdef ANSI_PROTOTYPES
618   va_start (args, format);
619 #else
620   char *buf;
621   int bufLen;
622   char *format;
623
624   va_start (args);
625   buf = va_arg (args, char *);
626   bufLen = va_arg (args, int);
627   format = va_arg (args, char *);
628 #endif
629   vasprintf (&linebuffer, format, args);
630   old_cleanups = make_cleanup (free, linebuffer);
631   strcat_to_buf (buf, bufLen, linebuffer);
632   do_cleanups (old_cleanups);
633   va_end (args);
634 }
635
636
637
638
639
640 /***********************
641 ** Static Functions
642 ************************/
643
644
645 /*
646    ** _tui_vDo().
647    **        General purpose function to execute a tui function.  Transitions
648    **        between curses and the are handled here.  This function is called
649    **        by non-tui gdb functions.
650    **
651    **        Errors are caught here.
652    **        If there is no error, the value returned by 'func' is returned.
653    **        If there is an error, then zero is returned.
654    **
655    **       Must not be called with immediate_quit in effect (bad things might
656    **       happen, say we got a signal in the middle of a memcpy to quit_return).
657    **       This is an OK restriction; with very few exceptions immediate_quit can
658    **       be replaced by judicious use of QUIT.
659  */
660 static Opaque
661 #ifdef __STDC__
662 _tui_vDo (
663            TuiOpaqueFuncPtr func,
664            va_list args)
665 #else
666 _tui_vDo (func, args)
667      TuiOpaqueFuncPtr func;
668      va_list args;
669 #endif
670 {
671   extern int terminal_is_ours;
672
673   Opaque ret = (Opaque) NULL;
674
675   /* It is an error to be tuiDo'ing if we
676      * don't own the terminal.
677    */
678   if (!terminal_is_ours)
679     return ret;
680
681   if (tui_version)
682     {
683       /* If doing command window the "XDB way" (command window
684          * is unmanaged by curses...
685        */
686       /* Set up terminal for TUI */
687       tuiTermSetup (1);
688
689       ret = va_catch_errors (func, args);
690
691       /* Set up terminal for command window */
692       tuiTermUnsetup (1, cmdWin->detail.commandInfo.curch);
693     }
694
695   return ret;
696 }                               /* _tui_vDo */
697
698
699 static void
700 #ifdef __STDC__
701 _toggle_command (
702                   char *arg,
703                   int fromTTY)
704 #else
705 _toggle_command (arg, fromTTY)
706      char *arg;
707      int fromTTY;
708 #endif
709 {
710   printf_filtered ("Specify feature to toggle.\n%s\n",
711                    (tui_version) ? TUI_TOGGLE_USAGE : TOGGLE_USAGE);
712 /*
713    tuiDo((TuiOpaqueFuncPtr)_Toggle_command, arg, fromTTY);
714  */
715 }
716
717 /*
718    ** _tui_vToggle_command().
719  */
720 static void
721 #ifdef __STDC__
722 _tui_vToggle_command (
723                        va_list args)
724 #else
725 _tui_vToggle_command (args)
726      va_list args;
727 #endif
728 {
729   char *arg;
730   int fromTTY;
731
732   arg = va_arg (args, char *);
733
734   if (arg == (char *) NULL)
735     printf_filtered (TOGGLE_USAGE);
736   else
737     {
738       char *ptr = (char *) tuiStrDup (arg);
739       int i;
740
741       for (i = 0; (ptr[i]); i++)
742         ptr[i] = toupper (arg[i]);
743
744       if (subsetCompare (ptr, TUI_FLOAT_REGS_NAME))
745         tuiToggleFloatRegs ();
746 /*        else if (subsetCompare(ptr, "ANOTHER TOGGLE OPTION"))
747    ...
748  */
749       else
750         printf_filtered (TOGGLE_USAGE);
751       tuiFree (ptr);
752     }
753
754   return;
755 }                               /* _tuiToggle_command */
756
757
758 static void
759 #ifdef __STDC__
760 _tuiReset (void)
761 #else
762 _tuiReset ()
763 #endif
764 {
765   struct termio mode;
766
767   /*
768      ** reset the teletype mode bits to a sensible state.
769      ** Copied tset.c
770    */
771 #if ! defined (USG) && defined (TIOCGETC)
772   struct tchars tbuf;
773 #endif /* !USG && TIOCGETC */
774 #ifdef UCB_NTTY
775   struct ltchars ltc;
776
777   if (ldisc == NTTYDISC)
778     {
779       ioctl (FILEDES, TIOCGLTC, &ltc);
780       ltc.t_suspc = CHK (ltc.t_suspc, CTRL ('Z'));
781       ltc.t_dsuspc = CHK (ltc.t_dsuspc, CTRL ('Y'));
782       ltc.t_rprntc = CHK (ltc.t_rprntc, CTRL ('R'));
783       ltc.t_flushc = CHK (ltc.t_flushc, CTRL ('O'));
784       ltc.t_werasc = CHK (ltc.t_werasc, CTRL ('W'));
785       ltc.t_lnextc = CHK (ltc.t_lnextc, CTRL ('V'));
786       ioctl (FILEDES, TIOCSLTC, &ltc);
787     }
788 #endif /* UCB_NTTY */
789 #ifndef USG
790 #ifdef TIOCGETC
791   ioctl (FILEDES, TIOCGETC, &tbuf);
792   tbuf.t_intrc = CHK (tbuf.t_intrc, CTRL ('?'));
793   tbuf.t_quitc = CHK (tbuf.t_quitc, CTRL ('\\'));
794   tbuf.t_startc = CHK (tbuf.t_startc, CTRL ('Q'));
795   tbuf.t_stopc = CHK (tbuf.t_stopc, CTRL ('S'));
796   tbuf.t_eofc = CHK (tbuf.t_eofc, CTRL ('D'));
797   /* brkc is left alone */
798   ioctl (FILEDES, TIOCSETC, &tbuf);
799 #endif /* TIOCGETC */
800   mode.sg_flags &= ~(RAW
801 #ifdef CBREAK
802                      | CBREAK
803 #endif /* CBREAK */
804                      | VTDELAY | ALLDELAY);
805   mode.sg_flags |= XTABS | ECHO | CRMOD | ANYP;
806 #else /*USG */
807   ioctl (FILEDES, TCGETA, &mode);
808   mode.c_cc[VINTR] = CHK (mode.c_cc[VINTR], CTRL ('?'));
809   mode.c_cc[VQUIT] = CHK (mode.c_cc[VQUIT], CTRL ('\\'));
810   mode.c_cc[VEOF] = CHK (mode.c_cc[VEOF], CTRL ('D'));
811
812   mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | INLCR | IGNCR | IUCLC | IXOFF);
813   mode.c_iflag |= (BRKINT | ISTRIP | ICRNL | IXON);
814   mode.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |
815                     NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
816   mode.c_oflag |= (OPOST | ONLCR);
817   mode.c_cflag &= ~(CSIZE | PARODD | CLOCAL);
818 #ifndef hp9000s800
819   mode.c_cflag |= (CS8 | CREAD);
820 #else /*hp9000s800 */
821   mode.c_cflag |= (CS8 | CSTOPB | CREAD);
822 #endif /* hp9000s800 */
823   mode.c_lflag &= ~(XCASE | ECHONL | NOFLSH);
824   mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOK);
825   ioctl (FILEDES, TCSETAW, &mode);
826 #endif /* USG */
827
828   return;
829 }                               /* _tuiReset */