Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / gdb / gdb / tui / tuiIO.c
1
2 /*
3 ** This module contains functions to support i/o in the TUI
4 */
5
6
7 #include <stdio.h>
8 #include "defs.h"
9 #include "terminal.h"
10 #include "tui.h"
11 #include "tuiData.h"
12 #include "tuiIO.h"
13 #include "tuiCommand.h"
14 #include "tuiWin.h"
15
16 #ifdef ANSI_PROTOTYPES
17 #include <stdarg.h>
18 #else
19 #include <varargs.h>
20 #endif
21
22 /* The Solaris header files seem to provide no declaration for this at
23    all when __STDC__ is defined.  This shouldn't conflict with
24    anything.  */
25 extern char *tgoto ();
26
27 int insert_mode = 0;
28
29 /********************************************
30 **       LOCAL STATIC FORWARD DECLS        **
31 ********************************************/
32 static void _updateCommandInfo PARAMS ((int));
33 static unsigned int _tuiHandleResizeDuringIO PARAMS ((unsigned int));
34
35
36 /*********************************************************************************
37 **                              PUBLIC FUNCTIONS                                **
38 *********************************************************************************/
39
40 /*
41 ** tuiPuts_unfiltered().
42 **        Function to put a string to the command window
43 **              When running in TUI mode, this is the "hook"
44 **              for fputs_unfiltered(). That is, all debugger
45 **              output eventually makes it's way to the bottom-level
46 **              routine fputs_unfiltered (main.c), which (in TUI
47 **              mode), calls tuiPuts_unfiltered().
48 */
49 void
50 #ifdef __STDC__
51 tuiPuts_unfiltered (
52                      const char *string,
53                      GDB_FILE * stream)
54 #else
55 tuiPuts_unfiltered (string, stream)
56      char *string;
57      GDB_FILE *stream;
58 #endif
59 {
60   int len = strlen (string);
61   int i, linech;
62
63   for (i = 0; i < len; i++)
64     {
65       if (string[i] == '\n' || string[i] == '\r')
66         m_tuiStartNewLine;
67       else
68         {
69           if ((cmdWin->detail.commandInfo.curch + 1) > cmdWin->generic.width)
70             m_tuiStartNewLine;
71
72           if (insert_mode)
73             {
74               mvwinsch (cmdWin->generic.handle,
75                         cmdWin->detail.commandInfo.curLine,
76                         cmdWin->detail.commandInfo.curch++,
77                         string[i]);
78               wmove (cmdWin->generic.handle,
79                      cmdWin->detail.commandInfo.curLine,
80                      cmdWin->detail.commandInfo.curch);
81             }
82           else
83             mvwaddch (cmdWin->generic.handle,
84                       cmdWin->detail.commandInfo.curLine,
85                       cmdWin->detail.commandInfo.curch++,
86                       string[i]);
87         }
88     }
89   tuiRefreshWin (&cmdWin->generic);
90
91   return;
92 }                               /* tuiPuts_unfiltered */
93
94 /* A cover routine for tputs().
95  * tputs() is called from the readline package to put
96  * out strings representing cursor positioning.
97  * In TUI mode (non-XDB-style), tui_tputs() is called instead.
98  *
99  * The reason we need to hook tputs() is:
100  * Since the output is going to curses and not to
101  * a raw terminal, we need to intercept these special
102  * sequences, and handle them them here.
103  *
104  * This function seems to be correctly handling all sequences
105  * aimed at hpterm's, but there is additional work to do
106  * for xterm's and dtterm's. I abandoned further work on this
107  * in favor of "XDB style". In "XDB style", the command region
108  * looks like terminal, not a curses window, and this routine
109  * is not called. - RT
110  */
111 void
112 tui_tputs (str, affcnt, putfunc)
113      char *str;
114      int affcnt;
115      int (*putfunc) PARAMS ((int));
116 {
117   extern char *rl_prompt;       /* the prompt string */
118
119   /* This set of globals are defined and initialized
120    * by the readline package.
121    *
122    * Note we're assuming tui_tputs() is being called
123    * by the readline package. That's because we're recognizing
124    * that a given string is being passed by
125    * matching the string address against readline's
126    * term_<whatever> global. To make this more general,
127    * we'd have to actually recognize the termcap sequence
128    * inside the string (more work than I want to do). - RT
129    *
130    * We don't see or need to handle every one of these here;
131    * this is just the full list defined in readline/readline.c
132    */
133   extern char *term_backspace;
134   extern char *term_clreol;
135   extern char *term_clrpag;
136   extern char *term_cr;
137   extern char *term_dc;
138   extern char *term_ei;
139   extern char *term_goto;
140   extern char *term_ic;
141   extern char *term_im;
142   extern char *term_mm;
143   extern char *term_mo;
144   extern char *term_up;
145   extern char *term_scroll_region;
146   extern char *term_memory_lock;
147   extern char *term_memory_unlock;
148   extern char *term_cursor_move;
149   extern char *visible_bell;
150
151   /* Sanity check - if not TUI, just call tputs() */
152   if (!tui_version)
153     tputs (str, affcnt, putfunc);
154
155   /* The strings we special-case are handled first */
156
157   if (str == term_backspace)
158     {
159       /* Backspace. */
160
161       /* We see this on an emacs control-B.
162      * I.e., it's like the left-arrow key (not like the backspace key).
163      * The effect that readline wants when it transmits this
164      * character to us is simply to back up one character
165      * (but not to write a space over the old character).
166      */
167
168       _updateCommandInfo (-1);
169       wmove (cmdWin->generic.handle,
170              cmdWin->detail.commandInfo.curLine,
171              cmdWin->detail.commandInfo.curch);
172       wrefresh (cmdWin->generic.handle);
173
174     }
175   else if (str == term_clreol)
176     {
177
178       /* Clear to end of line. */
179       wclrtoeol (cmdWin->generic.handle);
180       wrefresh (cmdWin->generic.handle);
181
182     }
183   else if (str == term_cr)
184     {
185
186       /* Carriage return */
187       _updateCommandInfo (-cmdWin->detail.commandInfo.curch);
188       wmove (cmdWin->generic.handle,
189              cmdWin->detail.commandInfo.curLine,
190              0 /* readline will rewrite the prompt from 0 */ );
191       wrefresh (cmdWin->generic.handle);
192
193     }
194   else if (str == term_goto)
195     {
196
197       /* This is actually a tgoto() specifying a character position,
198      * followed by either a term_IC/term_DC which [I think] means
199      * insert/delete one character at that position.
200      * There are complications with this one - need to either
201      * extract the position from the string, or have a backdoor
202      * means of communicating it from ../readline/display.c.
203      * So this one is not yet implemented.
204      * Not doing it seems to have no ill effects on command-line-editing
205      * that I've noticed so far. - RT
206      */
207
208     }
209   else if (str == term_dc)
210     {
211
212       /* Delete character at current cursor position */
213       wdelch (cmdWin->generic.handle);
214       wrefresh (cmdWin->generic.handle);
215
216     }
217   else if (str == term_im)
218     {
219
220       /* Turn on insert mode. */
221       insert_mode = 1;
222
223     }
224   else if (str == term_ei)
225     {
226
227       /* Turn off insert mode. */
228       insert_mode = 0;
229
230       /* Strings we know about but don't handle
231    * specially here are just passed along to tputs().
232    *
233    * These are not handled because (as far as I can tell)
234    * they are not actually emitted by the readline package
235    * in the course of doing command-line editing. Some of them
236    * theoretically could be used in the future, in which case we'd
237    * need to handle them.
238    */
239     }
240   else if (str == term_ic ||    /* insert character */
241            str == term_cursor_move ||   /* cursor move */
242            str == term_clrpag ||/* clear page */
243            str == term_mm ||    /* turn on meta key */
244            str == term_mo ||    /* turn off meta key */
245            str == term_up ||    /* up one line (not expected) */
246            str == term_scroll_region || /* set scroll region */
247            str == term_memory_lock ||   /* lock screen above cursor */
248            str == term_memory_unlock || /* unlock screen above cursor */
249            str == visible_bell)
250     {                           /* flash screen */
251       tputs (str, affcnt, putfunc);
252     }
253   else
254     {                           /* something else */
255       tputs (str, affcnt, putfunc);
256     }
257 }                               /* tui_tputs */
258
259
260 /*
261 ** tui_vwgetch()
262 **        Wrapper around wgetch with the window in a va_list
263 */
264 unsigned int
265 #ifdef __STDC__
266 tui_vwgetch (va_list args)
267 #else
268 tui_vwgetch (args)
269      va_list args;
270 #endif
271 {
272   unsigned int ch;
273   WINDOW *window;
274
275   window = va_arg (args, WINDOW *);
276
277   return ((unsigned int) wgetch (window));
278 }                               /* tui_vwgetch */
279
280
281 /*
282 ** tui_vread()
283 **   Wrapper around read() with paramets in a va_list
284 */
285 unsigned int
286 #ifdef __STDC__
287 tui_vread (va_list args)
288 #else
289 tui_vread (args)
290      va_list args;
291 #endif
292 {
293   int result = 0;
294   int filedes = va_arg (args, int);
295   char *buf = va_arg (args, char *);
296   int nbytes = va_arg (args, int);
297
298   result = read (filedes, buf, nbytes);
299
300   return result;
301 }                               /* tui_vread() */
302
303 /*
304 ** tuiRead()
305 **    Function to perform a read() catching resize events
306 */
307 int
308 #ifdef __STDC__
309 tuiRead (
310           int filedes,
311           char *buf,
312           int nbytes)
313 #else
314 tuiRead (filedes, buf, nbytes)
315      int filedes;
316      char *buf;
317      int nbytes;
318 #endif
319 {
320   int result = 0;
321
322   result = (int) vcatch_errors ((OpaqueFuncPtr) tui_vread, filedes, buf, nbytes);
323   *buf = _tuiHandleResizeDuringIO (*buf);
324
325   return result;
326 }                               /* tuiRead */
327
328
329 /*
330 ** tuiGetc().
331 **        Get a character from the command window.
332 **              This is called from the readline package,
333 **              that is, we have:
334 **                tuiGetc() [here], called from
335 **                readline code [in ../readline/], called from
336 **                command_line_input() in top.c
337 */
338 unsigned int
339 #ifdef __STDC__
340 tuiGetc (void)
341 #else
342 tuiGetc ()
343 #endif
344 {
345   unsigned int ch;
346   extern char *rl_prompt;
347   extern char *rl_line_buffer;
348   extern int rl_point;
349
350   /* Call the curses routine that reads one character */
351 #ifndef COMMENT
352   ch = (unsigned int) vcatch_errors ((OpaqueFuncPtr) tui_vwgetch,
353                                      cmdWin->generic.handle);
354 #else
355   ch = wgetch (cmdWin->generic.handle);
356 #endif
357   ch = _tuiHandleResizeDuringIO (ch);
358
359   if (m_isCommandChar (ch))
360     {                           /* Handle prev/next/up/down here */
361       tuiTermSetup (0);
362       ch = tuiDispatchCtrlChar (ch);
363       cmdWin->detail.commandInfo.curch = strlen (rl_prompt) + rl_point;
364       tuiTermUnsetup (0, cmdWin->detail.commandInfo.curch);
365     }
366   if (ch == '\n' || ch == '\r' || ch == '\f')
367     cmdWin->detail.commandInfo.curch = 0;
368   else
369     tuiIncrCommandCharCountBy (1);
370
371   return ch;
372 }                               /* tuiGetc */
373
374
375 /*
376 ** tuiBufferGetc().
377 */
378 /*elz: this function reads a line of input from the user and
379 puts it in a static buffer. Subsequent calls to this same function
380 obtain one char at the time, providing the caller with a behavior
381 similar to fgetc. When the input is buffered, the backspaces have
382 the needed effect, i.e. ignore the last char active in the buffer*/
383 /* so far this function is called only from the query function in
384 utils.c*/
385
386 unsigned int
387 #ifdef __STDC__
388 tuiBufferGetc (void)
389 #else
390 tuiBufferGetc ()
391 #endif
392 {
393   unsigned int ch;
394   static unsigned char _ibuffer[512];
395   static int index_read = -1;
396   static int length_of_answer = -1;
397   int pos = 0;
398
399   if (length_of_answer == -1)
400     {
401       /* this is the first time through, need to read the answer*/
402       do
403         {
404           /* Call the curses routine that reads one character */
405           ch = (unsigned int) wgetch (cmdWin->generic.handle);
406           if (ch != '\b')
407             {
408               _ibuffer[pos] = ch;
409               pos++;
410             }
411           else
412             pos--;
413         }
414       while (ch != '\r' && ch != '\n');
415
416       length_of_answer = pos;
417       index_read = 0;
418     }
419
420   ch = _ibuffer[index_read];
421   index_read++;
422
423   if (index_read == length_of_answer)
424     {
425       /*this is the last time through, reset for next query*/
426       index_read = -1;
427       length_of_answer = -1;
428     }
429
430   wrefresh (cmdWin->generic.handle);
431
432   return (ch);
433 }                               /* tuiBufferGetc */
434
435
436 /*
437 ** tuiStartNewLines().
438 */
439 void
440 #ifdef __STDC__
441 tuiStartNewLines (
442                    int numLines)
443 #else
444 tuiStartNewLines (numLines)
445      int numLines;
446 #endif
447 {
448   if (numLines > 0)
449     {
450       if (cmdWin->generic.viewportHeight > 1 &&
451         cmdWin->detail.commandInfo.curLine < cmdWin->generic.viewportHeight)
452         cmdWin->detail.commandInfo.curLine += numLines;
453       else
454         scroll (cmdWin->generic.handle);
455       cmdWin->detail.commandInfo.curch = 0;
456       wmove (cmdWin->generic.handle,
457              cmdWin->detail.commandInfo.curLine,
458              cmdWin->detail.commandInfo.curch);
459       tuiRefreshWin (&cmdWin->generic);
460     }
461
462   return;
463 }                               /* tuiStartNewLines */
464
465
466 /*
467 ** tui_vStartNewLines().
468 **        With numLines in a va_list
469 */
470 void
471 #ifdef __STDC__
472 tui_vStartNewLines (
473                      va_list args)
474 #else
475 tui_vStartNewLines (args)
476      va_list args;
477 #endif
478 {
479   int numLines = va_arg (args, int);
480
481   tuiStartNewLines (numLines);
482
483   return;
484 }                               /* tui_vStartNewLines */
485
486
487 /****************************************************************************
488 **                   LOCAL STATIC FUNCTIONS                                **
489 *****************************************************************************/
490
491
492 /*
493 ** _tuiHandleResizeDuringIO
494 **    This function manages the cleanup when a resize has occured
495 **    From within a call to getch() or read.  Returns the character
496 **    to return from getc or read.
497 */
498 static unsigned int
499 #ifdef __STDC__
500 _tuiHandleResizeDuringIO (
501                            unsigned int originalCh)     /* the char just read */
502 #else
503 _tuiHandleResizeDuringIO (originalCh)
504      unsigned int originalCh;
505 #endif
506 {
507   if (tuiWinResized ())
508     {
509       tuiDo ((TuiOpaqueFuncPtr) tuiRefreshAll);
510       dont_repeat ();
511       tuiSetWinResizedTo (FALSE);
512       rl_reset ();
513       return '\n';
514     }
515   else
516     return originalCh;
517 }                               /* _tuiHandleResizeDuringIO */
518
519
520 /*
521 ** _updateCommandInfo().
522 **        Function to update the command window information.
523 */
524 static void
525 #ifdef __STDC__
526 _updateCommandInfo (
527                      int sizeOfString)
528 #else
529 _updateCommandInfo (sizeOfString)
530      int sizeOfString;
531 #endif
532 {
533
534   if ((sizeOfString +
535        cmdWin->detail.commandInfo.curch) > cmdWin->generic.width)
536     {
537       int newCurch = sizeOfString + cmdWin->detail.commandInfo.curch;
538
539       tuiStartNewLines (1);
540       cmdWin->detail.commandInfo.curch = newCurch - cmdWin->generic.width;
541     }
542   else
543     cmdWin->detail.commandInfo.curch += sizeOfString;
544
545   return;
546 }                               /* _updateCommandInfo */
547
548
549 /* Looked at in main.c, fputs_unfiltered(), to decide
550  * if it's safe to do standard output to the command window.
551  */
552 int tui_owns_terminal = 0;
553
554 /* Called to set up the terminal for TUI (curses) I/O.
555  * We do this either on our way "in" to GDB after target
556  * program execution, or else within tuiDo just before
557  * going off to TUI routines.
558  */
559
560 void
561 #ifdef __STDC__
562 tuiTermSetup (
563                int turn_off_echo)
564 #else
565 tuiTermSetup (turn_off_echo)
566      int turn_off_echo;
567 #endif
568 {
569   char *buffer;
570   int start;
571   int end;
572   int endcol;
573   extern char *term_scroll_region;
574   extern char *term_cursor_move;
575   extern char *term_memory_lock;
576   extern char *term_memory_unlock;
577
578   /* Turn off echoing, since the TUI does not
579      * expect echoing. Below I only put in the TERMIOS
580      * case, since that is what applies on HP-UX. turn_off_echo
581      * is 1 except for the case where we're being called
582      * on a "quit", in which case we want to leave echo on.
583      */
584   if (turn_off_echo)
585     {
586 #ifdef HAVE_TERMIOS
587       struct termios tio;
588       tcgetattr (0, &tio);
589       tio.c_lflag &= ~(ECHO);
590       tcsetattr (0, TCSANOW, &tio);
591 #endif
592     }
593
594   /* Compute the start and end lines of the command
595      * region. (Actually we only use end here)
596      */
597   start = winList[CMD_WIN]->generic.origin.y;
598   end = start + winList[CMD_WIN]->generic.height - 1;
599   endcol = winList[CMD_WIN]->generic.width - 1;
600
601   if (term_memory_unlock)
602     {
603
604       /* Un-do the effect of the memory lock in terminal_inferior() */
605       tputs (term_memory_unlock, 1, (int (*)PARAMS ((int))) putchar);
606       fflush (stdout);
607
608     }
609   else if (term_scroll_region)
610     {
611
612       /* Un-do the effect of setting scroll region in terminal_inferior() */
613       /* I'm actually not sure how to do this (we don't know for
614        * sure what the scroll region was *before* we changed it),
615        * but I'll guess that setting it to the whole screen is
616        * the right thing. So, ...
617        */
618
619       /* Set scroll region to be 0..end */
620       buffer = (char *) tgoto (term_scroll_region, end, 0);
621       tputs (buffer, 1, (int (*)PARAMS ((int))) putchar);
622
623     }                           /* else we're out of luck */
624
625   /* This is an attempt to keep the logical & physical
626        * cursor in synch, going into curses. Without this,
627        * curses seems to be confused by the fact that
628        * GDB has physically moved the curser on it. One
629        * visible effect of removing this code is that the
630        * locator window fails to get updated and the line
631        * of text that *should* go into the locator window
632        * often goes to the wrong place.
633        */
634   /* What's done here is to  tell curses to write a ' '
635        * at the bottom right corner of the screen.
636        * The idea is to wind up with the cursor in a known
637        * place.
638        * Note I'm relying on refresh()
639        * only writing what changed (the space),
640        * not the whole screen.
641        */
642   standend ();
643   move (end, endcol - 1);
644   addch (' ');
645   refresh ();
646
647   tui_owns_terminal = 1;
648 }                               /* tuiTermSetup */
649
650
651 /* Called to set up the terminal for target program I/O, meaning I/O
652  * is confined to the command-window area.  We also call this on our
653  * way out of tuiDo, thus setting up the terminal this way for
654  * debugger command I/O.  */
655 void
656 #ifdef __STDC__
657 tuiTermUnsetup (
658                  int turn_on_echo,
659                  int to_column)
660 #else
661 tuiTermUnsetup (turn_on_echo, to_column)
662      int turn_on_echo;
663      int to_column;
664 #endif
665 {
666   int start;
667   int end;
668   int curline;
669   char *buffer;
670   /* The next bunch of things are from readline */
671   extern char *term_scroll_region;
672   extern char *term_cursor_move;
673   extern char *term_memory_lock;
674   extern char *term_memory_unlock;
675   extern char *term_se;
676
677   /* We need to turn on echoing, since the TUI turns it off */
678   /* Below I only put in the TERMIOS case, since that
679      * is what applies on HP-UX.
680      */
681   if (turn_on_echo)
682     {
683 #ifdef HAVE_TERMIOS
684       struct termios tio;
685       tcgetattr (0, &tio);
686       tio.c_lflag |= (ECHO);
687       tcsetattr (0, TCSANOW, &tio);
688 #endif
689     }
690
691   /* Compute the start and end lines of the command
692      * region, as well as the last "real" line of
693      * the region (normally same as end, except when
694      * we're first populating the region)
695      */
696   start = winList[CMD_WIN]->generic.origin.y;
697   end = start + winList[CMD_WIN]->generic.height - 1;
698   curline = start + winList[CMD_WIN]->detail.commandInfo.curLine;
699
700   /* We want to confine target I/O to the command region.
701      * In order to do so, we must either have "memory lock"
702      * (hpterm's) or "scroll regions" (xterm's).
703      */
704   if (term_cursor_move && term_memory_lock)
705     {
706
707       /* Memory lock means lock region above cursor.
708        * So first position the cursor, then call memory lock.
709        */
710       buffer = tgoto (term_cursor_move, 0, start);
711       tputs (buffer, 1, (int (*)PARAMS ((int))) putchar);
712       tputs (term_memory_lock, 1, (int (*)PARAMS ((int))) putchar);
713
714     }
715   else if (term_scroll_region)
716     {
717
718       /* Set the scroll region to the command window */
719       buffer = tgoto (term_scroll_region, end, start);
720       tputs (buffer, 1, (int (*)PARAMS ((int))) putchar);
721
722     }                           /* else we can't do anything about target I/O */
723
724   /* Also turn off standout mode, in case it is on */
725   if (term_se != NULL)
726     tputs (term_se, 1, (int (*)PARAMS ((int))) putchar);
727
728   /* Now go to the appropriate spot on the end line */
729   buffer = tgoto (term_cursor_move, to_column, end);
730   tputs (buffer, 1, (int (*)PARAMS ((int))) putchar);
731   fflush (stdout);
732
733   tui_owns_terminal = 0;
734 }                               /* tuiTermUnsetup */