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