1 /**
2 * Provides the routines for displaying the interface, and interacting with
3 * the user via keystrokes.
4 *
5 * When the window orientation is set to horizontal, cgdb will displasy as:
6 * ---------------
7 * source window
8 * ---------------
9 * status window
10 * ---------------
11 * gdb window
12 * ---------------
13 * In this mode, the winminheight determines how much a window can
14 * shrink vertically. The window_shfit variable keeps track of how far
15 * the source window has been shifted up or down.
16 *
17 * When the window orientation is set to vertical, cgdb will display as:
18 *
19 * ---------------|------------
20 * source window | gdb window
21 * |
22 * |
23 * |
24 * |
25 * ---------------|
26 * status window |
27 * ---------------|------------
28 * In this mode, the winminwidth determines how much a window can
29 * shrink horizontally. The window_shfit variable keeps track of how
30 * far the source window has been shifted left or right.
31 */
32
33 #if HAVE_CONFIG_H
34 #include "config.h"
35 #endif /* HAVE_CONFIG_H */
36
37 /* System Includes */
38 #if HAVE_SIGNAL_H
39 #include <signal.h>
40 #endif
41
42 #if HAVE_STDARG_H
43 #include <stdarg.h>
44 #endif /* HAVE_STDARG_H */
45
46 #if HAVE_STDLIB_H
47 #include <stdlib.h>
48 #endif /* HAVE_STDLIB_H */
49
50 #if HAVE_STRING_H
51 #include <string.h>
52 #endif /* HAVE_STRING_H */
53
54 #if HAVE_SYS_IOCTL_H
55 #include <sys/ioctl.h>
56 #endif /* HAVE_SYS_IOCTL_H */
57
58 #if HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif /* HAVE_UNISTD_H */
61
62 #if HAVE_TERMIOS_H
63 #include <termios.h>
64 #endif /* HAVE_TERMIOS_H */
65
66 #if HAVE_CTYPE_H
67 #include <ctype.h>
68 #endif
69
70 #include <assert.h>
71
72 #include <string>
73
74 /* Local Includes */
75 #include "sys_util.h"
76 #include "sys_win.h"
77 #include "cgdb.h"
78 #include "config.h"
79 #include "tokenizer.h"
80 #include "interface.h"
81 #include "kui_term.h"
82 #include "scroller.h"
83 #include "sources.h"
84 #include "tgdb.h"
85 #include "filedlg.h"
86 #include "cgdbrc.h"
87 #include "highlight.h"
88 #include "highlight_groups.h"
89 #include "fs_util.h"
90 #include "logo.h"
91
92 /* ----------- */
93 /* Prototypes */
94 /* ----------- */
95
96 /* ------------ */
97 /* Declarations */
98 /* ------------ */
99
100 extern struct tgdb *tgdb;
101
102 /* ----------- */
103 /* Definitions */
104 /* ----------- */
105
106 /* The minimum number of rows the user wants a window to shrink. */
107 static int interface_winminheight = 0;
108
109 /* The minimum number of columns the user wants a window to shrink. */
110 static int interface_winminwidth = 0;
111
112 /* The offset that determines allows gdb/sources window to grow or shrink */
113 static int window_shift;
114
115 /* Height and width of the terminal */
116 #define HEIGHT (screen_size.ws_row)
117 #define WIDTH (screen_size.ws_col)
118
119 /* Current window split state */
120 WIN_SPLIT_TYPE cur_win_split = WIN_SPLIT_EVEN;
121 /* Current window orientation state (horizontal or vertical) */
122 WIN_SPLIT_ORIENTATION_TYPE cur_split_orientation = WSO_HORIZONTAL;
123
124 /* --------------- */
125 /* Local Variables */
126 /* --------------- */
127 static struct scroller *gdb_scroller = NULL;
128 static struct sviewer *src_viewer = NULL; /* The source viewer window */
129 static SWINDOW *status_win = NULL; /* The status line */
130 static SWINDOW *vseparator_win = NULL; /* Separator gets own window */
131 static enum Focus focus = GDB; /* Which pane is currently focused */
132 static struct winsize screen_size; /* Screen size */
133
134 struct filedlg *fd; /* The file dialog structure */
135
136 /* The regex the user is entering */
137 static std::string regex_cur;
138
139 /* The last regex the user searched for */
140 static std::string regex_last;
141
142 /* Direction to search */
143 static int regex_direction_cur;
144 static int regex_direction_last;
145
146 /* The position of the source file, before regex was applied. */
147 static int orig_line_regex;
148
149 static char last_key_pressed = 0; /* Last key user entered in cgdb mode */
150
151 /* Line number user wants to 'G' to */
152 static std::string G_line_number;
153
154 /* The cgdb status bar command */
155 static std::string cur_sbc;
156
157 enum StatusBarCommandKind {
158 /* This is represented by a : */
159 SBC_NORMAL,
160 /* This is set when a regular expression is being entered */
161 SBC_REGEX
162 };
163
164 static enum StatusBarCommandKind sbc_kind = SBC_NORMAL;
165
166 /* --------------- */
167 /* Local Functions */
168 /* --------------- */
169
170 /* --------------------------------------
171 * Theses get the position of each window
172 * -------------------------------------- */
173
174 /* These are for the source window */
get_src_row(void)175 static int get_src_row(void)
176 {
177 return 0;
178 }
179
get_src_col(void)180 static int get_src_col(void)
181 {
182 return 0;
183 }
184
get_src_status_height(void)185 static int get_src_status_height(void)
186 {
187 return 1;
188 }
189
get_src_height(void)190 static int get_src_height(void)
191 {
192 int result;
193
194 switch (cur_split_orientation) {
195 case WSO_HORIZONTAL:
196 result = ((screen_size.ws_row + 0.5) / 2) + window_shift;
197 break;
198 case WSO_VERTICAL:
199 result = screen_size.ws_row - get_src_status_height();
200 break;
201 }
202
203 return result;
204 }
205
get_src_width(void)206 static int get_src_width(void)
207 {
208 int result;
209
210 switch (cur_split_orientation) {
211 case WSO_HORIZONTAL:
212 result = screen_size.ws_col;
213 break;
214 case WSO_VERTICAL:
215 result = ((screen_size.ws_col + 0.5) / 2) + window_shift;
216 break;
217 }
218
219 return result;
220 }
221
222 /* This is for the source window status bar */
get_src_status_row(void)223 static int get_src_status_row(void)
224 {
225 return get_src_row() + get_src_height();
226 }
227
get_src_status_col(void)228 static int get_src_status_col(void)
229 {
230 return get_src_col();
231 }
232
get_src_status_width(void)233 static int get_src_status_width(void)
234 {
235 return get_src_width();
236 }
237
238 /* These are for the separator line in horizontal split mode */
get_sep_row(void)239 static int get_sep_row(void)
240 {
241 return 0;
242 }
243
get_sep_col(void)244 static int get_sep_col(void)
245 {
246 return get_src_col() + get_src_width();
247 }
248
get_sep_height(void)249 static int get_sep_height(void)
250 {
251 return screen_size.ws_row;
252 }
253
get_sep_width(void)254 static int get_sep_width(void)
255 {
256 return 1;
257 }
258
259 /* This is for the debugger window */
get_gdb_row(void)260 static int get_gdb_row(void)
261 {
262 int result;
263
264 switch (cur_split_orientation) {
265 case WSO_HORIZONTAL:
266 result = get_src_status_row() + get_src_status_height();
267 break;
268 case WSO_VERTICAL:
269 result = 0;
270 break;
271 }
272
273 return result;
274 }
275
get_gdb_col(void)276 static int get_gdb_col(void)
277 {
278 int result;
279
280 switch (cur_split_orientation) {
281 case WSO_HORIZONTAL:
282 result = 0;
283 break;
284 case WSO_VERTICAL:
285 result = get_sep_col() + get_sep_width();
286 break;
287 }
288
289 return result;
290 }
291
get_gdb_height(void)292 int get_gdb_height(void)
293 {
294 int result;
295
296 switch (cur_split_orientation) {
297 case WSO_HORIZONTAL: {
298 int window_size = ((screen_size.ws_row / 2) - window_shift - 1);
299 int odd_screen_size = (screen_size.ws_row % 2);
300
301 result = window_size + odd_screen_size;
302 break;
303 }
304 case WSO_VERTICAL:
305 result = screen_size.ws_row;
306 break;
307 }
308
309 return result;
310 }
311
get_gdb_width(void)312 int get_gdb_width(void)
313 {
314 int result;
315
316 switch (cur_split_orientation) {
317 case WSO_HORIZONTAL:
318 result = screen_size.ws_col;
319 break;
320 case WSO_VERTICAL: {
321 int window_size = ((screen_size.ws_col / 2) - window_shift - 1);
322 int odd_screen_size = (screen_size.ws_col % 2);
323
324 result = window_size + odd_screen_size;
325 break;
326 }
327 }
328
329 return result;
330 }
331
332 /*
333 * create_swindow: (re)create window with specified position and size.
334 */
create_swindow(SWINDOW ** win,int nlines,int ncols,int begin_y,int begin_x)335 static void create_swindow(SWINDOW **win, int nlines, int ncols, int begin_y, int begin_x)
336 {
337 if (*win)
338 {
339 int x = swin_getbegx(*win);
340 int y = swin_getbegy(*win);
341 int w = swin_getmaxx(*win);
342 int h = swin_getmaxy(*win);
343
344 /* If the window position + size hasn't changed, bail */
345 if (x == begin_x && y == begin_y && w == ncols && h == nlines)
346 return;
347
348 /* Delete the existing window */
349 swin_delwin(*win);
350 *win = NULL;
351 }
352
353 if ((nlines > 0) && (ncols > 0))
354 {
355 /* Create the ncurses window */
356 *win = swin_newwin(nlines, ncols, begin_y, begin_x);
357 swin_werase(*win);
358 }
359 }
360
separator_display(int draw)361 static void separator_display(int draw)
362 {
363 int x = get_sep_col();
364 int y = get_sep_row();
365 int h = y + get_sep_height();
366 int w = draw ? 1 : 0;
367
368 /* Make sure our window is created at correct location
369 * (or destroyed if draw == 0) */
370 create_swindow(&vseparator_win, h, w, y, x);
371
372 if (vseparator_win)
373 {
374 /* Draw vertical line in window */
375 swin_wmove(vseparator_win, 0, 0);
376 swin_wvline(vseparator_win, SWIN_SYM_VLINE, h);
377
378 swin_wnoutrefresh(vseparator_win);
379 }
380 }
381
382 /* ---------------------------------------
383 * Below is the core body of the interface
384 * --------------------------------------- */
385
386 /* Updates the status bar */
update_status_win(enum win_refresh dorefresh)387 static void update_status_win(enum win_refresh dorefresh)
388 {
389 int pos;
390 int attr;
391
392 attr = hl_groups_get_attr(hl_groups_instance, HLG_STATUS_BAR);
393
394 /* Print white background */
395 swin_wattron(status_win, attr);
396
397 for (pos = 0; pos < WIDTH; pos++)
398 swin_mvwprintw(status_win, 0, pos, " ");
399 /* Show the user which window is focused */
400 if (focus == GDB)
401 swin_mvwprintw(status_win, 0, WIDTH - 1, "*");
402 else if (focus == CGDB || focus == CGDB_STATUS_BAR)
403 swin_mvwprintw(status_win, 0, WIDTH - 1, " ");
404
405 swin_wattroff(status_win, attr);
406
407 /* Print the regex that the user is looking for Forward */
408 if (sbc_kind == SBC_REGEX && regex_direction_cur) {
409 if_display_message(dorefresh, "/", regex_cur.c_str());
410 swin_curs_set(1);
411 }
412 /* Regex backwards */
413 else if (sbc_kind == SBC_REGEX) {
414 if_display_message(dorefresh, "?", regex_cur.c_str());
415 swin_curs_set(1);
416 }
417 /* A colon command typed at the status bar */
418 else if (focus == CGDB_STATUS_BAR && sbc_kind == SBC_NORMAL) {
419 if_display_message(dorefresh, ":", cur_sbc.c_str());
420 swin_curs_set(1);
421 }
422 /* Default: Current Filename */
423 else {
424 /* Print filename */
425 const char *filename = source_current_file(src_viewer);
426
427 if (filename) {
428 if_display_message(dorefresh, "", filename);
429 }
430 }
431
432 if (dorefresh == WIN_REFRESH)
433 swin_wrefresh(status_win);
434 else
435 swin_wnoutrefresh(status_win);
436 }
437
if_display_message(enum win_refresh dorefresh,const char * header,const char * msg)438 void if_display_message(enum win_refresh dorefresh,
439 const char *header, const char *msg)
440 {
441 char buf_display[MAXLINE];
442 int pos, header_length, msg_length;
443 int attr;
444 int width;
445
446 attr = hl_groups_get_attr(hl_groups_instance, HLG_STATUS_BAR);
447
448 swin_curs_set(0);
449
450 width = get_src_status_width();
451
452 header_length = strlen(header);
453 msg_length = strlen(msg);
454
455 if (header_length > width)
456 strcat(strncpy(buf_display, header, width - 1), ">");
457 else if (header_length + msg_length > width)
458 snprintf(buf_display, sizeof(buf_display), "%s>%s", header,
459 msg + (msg_length - (width - header_length) + 1));
460 else
461 snprintf(buf_display, sizeof(buf_display), "%s%s", header, msg);
462
463 /* Print white background */
464 swin_wattron(status_win, attr);
465 for (pos = 0; pos < WIDTH; pos++)
466 swin_mvwprintw(status_win, 0, pos, " ");
467
468 swin_mvwprintw(status_win, 0, 0, "%s", buf_display);
469 swin_wattroff(status_win, attr);
470
471 if (dorefresh == WIN_REFRESH)
472 swin_wrefresh(status_win);
473 else
474 swin_wnoutrefresh(status_win);
475 }
476
477 /* if_draw: Draws the interface on the screen.
478 * --------
479 */
if_draw(void)480 void if_draw(void)
481 {
482 /* Only redisplay the filedlg if it is up */
483 if (focus == FILE_DLG) {
484 filedlg_display(fd);
485 return;
486 }
487
488 update_status_win(WIN_NO_REFRESH);
489
490 if (get_src_height() != 0 && get_gdb_height() != 0)
491 swin_wnoutrefresh(status_win);
492
493 if (get_src_height() > 0)
494 source_display(src_viewer, focus == CGDB, WIN_NO_REFRESH);
495
496 separator_display(cur_split_orientation == WSO_VERTICAL);
497
498 if (get_gdb_height() > 0)
499 scr_refresh(gdb_scroller, focus == GDB, WIN_NO_REFRESH);
500
501 /* This check is here so that the cursor goes to the
502 * cgdb window. The cursor would stay in the gdb window
503 * on cygwin */
504 if (get_src_height() > 0 && focus == CGDB)
505 swin_wnoutrefresh(src_viewer->win);
506
507 swin_doupdate();
508 }
509
510 /* validate_window_sizes:
511 * ----------------------
512 *
513 * This will make sure that the gdb_window, status_bar and source window
514 * have appropriate sizes. Each of the windows will not be able to grow
515 * smaller than WINMINHEIGHT or WINMINWIDTH in size. It will also restrict the
516 * size of windows to being within the size of the terminal.
517 */
validate_window_sizes(void)518 static void validate_window_sizes(void)
519 {
520 int h_or_w = cur_split_orientation == WSO_HORIZONTAL ? HEIGHT : WIDTH;
521 int odd_size = (h_or_w + 1) % 2;
522 int max_window_size_shift = (h_or_w / 2) - odd_size;
523 int min_window_size_shift = -(h_or_w / 2);
524
525 /* update max and min based off of users winminheight request */
526 switch (cur_split_orientation) {
527 case WSO_HORIZONTAL:
528 min_window_size_shift += interface_winminheight;
529 max_window_size_shift -= interface_winminheight;
530 break;
531 case WSO_VERTICAL:
532 min_window_size_shift += interface_winminwidth;
533 max_window_size_shift -= interface_winminwidth;
534 break;
535 }
536
537 /* Make sure that the windows offset is within its bounds:
538 * This checks the window offset.
539 * */
540 if (window_shift > max_window_size_shift)
541 window_shift = max_window_size_shift;
542 else if (window_shift < min_window_size_shift)
543 window_shift = min_window_size_shift;
544 }
545
if_layout()546 int if_layout()
547 {
548 SWINDOW *gdb_scroller_win = NULL;
549 SWINDOW *src_viewer_win = NULL;
550
551 /* Verify the window size is reasonable */
552 validate_window_sizes();
553
554 /* Resize the source viewer window */
555 create_swindow(&src_viewer_win, get_src_height(), get_src_width(),
556 get_src_row(), get_src_col());
557 if (src_viewer) {
558 source_move(src_viewer, src_viewer_win);
559 } else {
560 src_viewer = source_new(src_viewer_win);
561 }
562
563 tgdb_resize_console(tgdb, get_gdb_height(), get_gdb_width());
564
565 /* Resize the GDB I/O window */
566 create_swindow(&gdb_scroller_win, get_gdb_height(), get_gdb_width(),
567 get_gdb_row(), get_gdb_col());
568 if (gdb_scroller) {
569 scr_move(gdb_scroller, gdb_scroller_win);
570 } else {
571 gdb_scroller = scr_new(gdb_scroller_win);
572 }
573
574 /* Initialize the status bar window */
575 create_swindow(&status_win, get_src_status_height(),
576 get_src_status_width(), get_src_status_row(), get_src_status_col());
577
578 /* Redraw the interface */
579 if_draw();
580
581 return 0;
582 }
583
584 /* if_resize_term: Checks if a resize event occurred, and updates display if so.
585 * ----------
586 *
587 * Return Value: Zero on success, non-zero on failure.
588 */
if_resize_term(void)589 int if_resize_term(void)
590 {
591 if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1) {
592 if (screen_size.ws_row != swin_lines() ||
593 screen_size.ws_col != swin_cols()) {
594 swin_resizeterm(screen_size.ws_row, screen_size.ws_col);
595 swin_refresh();
596 }
597
598 return if_layout();
599 }
600
601 return 0;
602 }
603
604 /*
605 * increase_win_height: Increase size of the source window
606 * ____________________
607 *
608 * Param jump - if 0, increase source window by 1
609 * if 1, jump source window to next biggest quarter
610 *
611 */
increase_win_height(int jump)612 static void increase_win_height(int jump)
613 {
614 int height = HEIGHT / 2;
615 int old_window_shift = window_shift;
616
617 if (jump) {
618 /* user input: '+' */
619 if (cur_win_split == WIN_SPLIT_FREE) {
620 /* cur position is not on mark, find nearest mark */
621 cur_win_split = (WIN_SPLIT_TYPE) ((2 * window_shift) / height);
622
623 /* handle rounding on either side of mid-way mark */
624 if (window_shift > 0) {
625 cur_win_split = (WIN_SPLIT_TYPE)(cur_win_split + 1);
626 }
627 } else {
628 /* increase to next mark */
629 cur_win_split = (WIN_SPLIT_TYPE)(cur_win_split + 1);
630 }
631
632 /* check split bounds */
633 if (cur_win_split > WIN_SPLIT_SRC_FULL) {
634 cur_win_split = WIN_SPLIT_SRC_FULL;
635 }
636
637 /* set window height to specified quarter mark */
638 window_shift = (int) (height * (cur_win_split / 2.0));
639 } else {
640 /* user input: '=' */
641 cur_win_split = WIN_SPLIT_FREE; /* cur split is not on a mark */
642 window_shift++; /* increase src window size by 1 */
643
644 }
645
646 /* reduce flicker by avoiding unnecessary redraws */
647 if (window_shift != old_window_shift) {
648 if_layout();
649 }
650 }
651
652 /*
653 * decrease_win_height: Decrease size of the source window
654 * ____________________
655 *
656 * Param jump - if 0, decrease source window by 1
657 * if 1, jump source window to next smallest quarter
658 *
659 */
decrease_win_height(int jump)660 static void decrease_win_height(int jump)
661 {
662 int height = HEIGHT / 2;
663 int old_window_shift = window_shift;
664
665 if (jump) {
666 /* user input: '_' */
667 if (cur_win_split == WIN_SPLIT_FREE) {
668 /* cur position is not on mark, find nearest mark */
669 cur_win_split = (WIN_SPLIT_TYPE) ((2 * window_shift) / height);
670
671 /* handle rounding on either side of mid-way mark */
672 if (window_shift < 0) {
673 cur_win_split = (WIN_SPLIT_TYPE)(cur_win_split - 1);
674 }
675 } else {
676 /* decrease to next mark */
677 cur_win_split = (WIN_SPLIT_TYPE)(cur_win_split - 1);
678 }
679
680 /* check split bounds */
681 if (cur_win_split < WIN_SPLIT_GDB_FULL) {
682 cur_win_split = WIN_SPLIT_GDB_FULL;
683 }
684
685 /* set window height to specified quarter mark */
686 window_shift = (int) (height * (cur_win_split / 2.0));
687 } else {
688 /* user input: '-' */
689 cur_win_split = WIN_SPLIT_FREE; /* cur split is not on a mark */
690 window_shift--; /* decrease src window size by 1 */
691
692 }
693
694 /* reduce flicker by avoiding unnecessary redraws */
695 if (window_shift != old_window_shift) {
696 if_layout();
697 }
698 }
699
700 /**
701 * The signal handler for CGDB.
702 *
703 * Pass any signals along from the signal handler to the main loop by
704 * writing the signal value to a pipe, which is later read and interpreted.
705 *
706 * Since it's non trivial to do error handling from the signal handler if an
707 * error occurs the program will terminate. Hopefully this doesn't occur.
708 */
signal_handler(int signo)709 static void signal_handler(int signo)
710 {
711 extern int resize_pipe[2];
712 extern int signal_pipe[2];
713 int fdpipe;
714
715 if (signo == SIGWINCH) {
716 fdpipe = resize_pipe[1];
717 } else {
718 fdpipe = signal_pipe[1];
719 }
720
721 assert(write(fdpipe, &signo, sizeof(signo)) == sizeof(signo));
722 }
723
if_run_command(struct sviewer * sview,const std::string & command)724 static void if_run_command(struct sviewer *sview, const std::string &command)
725 {
726 /* refresh and return if the user entered no data */
727 if (command.size() == 0) {
728 if_draw();
729 return;
730 }
731
732 if (command_parse_string(command.c_str())) {
733 if_display_message(WIN_NO_REFRESH, "Unknown command: ",
734 command.c_str());
735 } else {
736 update_status_win(WIN_NO_REFRESH);
737 }
738
739 if_draw();
740 }
741
742 /**
743 * Capture a regular expression from the user, one key at a time.
744 * This modifies the global variables regex_cur and regex_last.
745 *
746 * \param sview
747 * The source viewer.
748 *
749 * \return
750 * 0 if user gave a regex, otherwise 1.
751 */
gdb_input_regex_input(struct scroller * scr,int key)752 static int gdb_input_regex_input(struct scroller *scr, int key)
753 {
754 /* Flag to indicate we're done with regex mode, need to switch back */
755 int done = 0;
756 int matched = 0;
757
758 /* Receive a regex from the user. */
759 switch (key)
760 {
761 case '\r':
762 case '\n':
763 case CGDB_KEY_CTRL_M:
764 /* Save for future searches via 'n' or 'N' */
765 regex_direction_last = regex_direction_cur;
766 matched = scr_search_regex(scr, regex_cur.c_str());
767 if_draw();
768 done = 1;
769 break;
770 case 8:
771 case 127:
772 /* Backspace or DEL key */
773 if (regex_cur.size() == 0)
774 {
775 done = 1;
776 matched = 0;
777 }
778 else
779 {
780 regex_cur.erase(regex_cur.size() - 1);
781 matched = scr_search_regex(scr, regex_cur.c_str());
782 if_draw();
783 update_status_win(WIN_REFRESH);
784 }
785 break;
786 default:
787 if (kui_term_is_cgdb_key(key))
788 {
789 const char *keycode = kui_term_get_keycode_from_cgdb_key(key);
790 int length = strlen(keycode), i;
791
792 for (i = 0; i < length; i++)
793 regex_cur.push_back(keycode[i]);
794 }
795 else
796 {
797 regex_cur.push_back(key);
798 }
799 matched = scr_search_regex(scr, regex_cur.c_str());
800 if_draw();
801 update_status_win(WIN_REFRESH);
802 };
803
804 if (done)
805 {
806 scr_disable_search(scr, matched == 1);
807 regex_cur.clear();
808
809 sbc_kind = SBC_NORMAL;
810 if_set_focus(GDB);
811 }
812
813 return 0;
814 }
815
816 /* gdb_input: Handles user input to the GDB window.
817 * ----------
818 *
819 * key: Keystroke received.
820 *
821 * Return Value: 0 if internal key was used,
822 * 1 if input to gdb or ...
823 * -1 : Error resizing terminal -- terminal too small
824 */
gdb_input(int key,int * last_key)825 static int gdb_input(int key, int *last_key)
826 {
827 int result = 0;
828
829 if (scr_search_mode(gdb_scroller))
830 return gdb_input_regex_input(gdb_scroller, key);
831
832 if (scr_scroll_mode(gdb_scroller)) {
833
834 /* In scroll mode, all extra characters are not passed to
835 * the active GDB command. result = 0 above ensures that. */
836 switch (key) {
837 case CGDB_KEY_CTRL_U:
838 scr_up(gdb_scroller, get_gdb_height() / 2);
839 break;
840 case CGDB_KEY_PPAGE:
841 scr_up(gdb_scroller, get_gdb_height() - 1);
842 break;
843 case CGDB_KEY_CTRL_D:
844 scr_down(gdb_scroller, get_gdb_height() / 2);
845 break;
846 case CGDB_KEY_NPAGE:
847 scr_down(gdb_scroller, get_gdb_height() - 1);
848 break;
849 case CGDB_KEY_HOME:
850 case CGDB_KEY_F11:
851 scr_home(gdb_scroller);
852 break;
853 case 'G':
854 case CGDB_KEY_END:
855 case CGDB_KEY_F12:
856 scr_end(gdb_scroller);
857 break;
858 case 'k':
859 case CGDB_KEY_UP:
860 case CGDB_KEY_CTRL_P:
861 scr_up(gdb_scroller, 1);
862 break;
863 case 'j':
864 case CGDB_KEY_DOWN:
865 case CGDB_KEY_CTRL_N:
866 scr_down(gdb_scroller, 1);
867 break;
868 case CGDB_KEY_LEFT:
869 case 'h':
870 scr_left(gdb_scroller);
871 break;
872 case CGDB_KEY_RIGHT:
873 case 'l':
874 scr_right(gdb_scroller);
875 break;
876 case '0':
877 scr_beginning_of_row(gdb_scroller);
878 break;
879 case '$':
880 scr_end_of_row(gdb_scroller);
881 break;
882 case 'g':
883 if (last_key_pressed == 'g') {
884 scr_home(gdb_scroller);
885 }
886 break;
887 case 'q':
888 case 'i':
889 case '\r':
890 case '\n':
891 case CGDB_KEY_CTRL_M:
892 scr_end(gdb_scroller);
893 scr_set_scroll_mode(gdb_scroller, false);
894 break;
895 case 'n':
896 scr_search_next(gdb_scroller,
897 regex_direction_last, cgdbrc_get_int(CGDBRC_IGNORECASE));
898 break;
899 case 'N':
900 scr_search_next(gdb_scroller,
901 !regex_direction_last, cgdbrc_get_int(CGDBRC_IGNORECASE));
902 break;
903 case '/':
904 case '?':
905 /* Capturing regular expressions */
906 regex_cur = "";
907 regex_direction_cur = ('/' == key);
908 sbc_kind = SBC_REGEX;
909 scr_enable_search(gdb_scroller, regex_direction_cur,
910 cgdbrc_get_int(CGDBRC_IGNORECASE));
911 break;
912 }
913
914 } else {
915 switch (key) {
916 case CGDB_KEY_PPAGE:
917 scr_set_scroll_mode(gdb_scroller, true);
918 scr_up(gdb_scroller, get_gdb_height() - 1);
919 break;
920 case CGDB_KEY_CTRL_L:
921 // When readline clears the screen with ctrl-l, it clears by
922 // going home and sending EL.
923 // However, it would be nice to save the gdb output in the
924 // scrollback buffer before the line is cleared.
925 // TODO: Implement
926 scr_push_screen_to_scrollback(gdb_scroller);
927
928 /* The return 1 tells readline that gdb did not handle the
929 * Ctrl-l. That way readline will handle it. Because
930 * readline uses TERM=dumb, that means that it will clear
931 * a single line and put out the prompt. */
932 result = 1;
933 break;
934
935 default:
936 /* This tells the input to go to active GDB command */
937 result = 1;
938 break;
939 }
940 }
941
942 if_draw();
943
944 return result;
945 }
946
947 /**
948 * Capture a regular expression from the user, one key at a time.
949 * This modifies the global variables regex_cur and regex_last.
950 *
951 * \param sview
952 * The source viewer.
953 *
954 * \return
955 * 0 if user gave a regex, otherwise 1.
956 */
status_bar_regex_input(struct sviewer * sview,int key)957 static int status_bar_regex_input(struct sviewer *sview, int key)
958 {
959 int regex_icase = cgdbrc_get_int(CGDBRC_IGNORECASE);
960
961 /* Flag to indicate we're done with regex mode, need to switch back */
962 int done = 0;
963
964 /* Receive a regex from the user. */
965 switch (key) {
966 case '\r':
967 case '\n':
968 case CGDB_KEY_CTRL_M:
969 /* Save for future searches via 'n' or 'N' */
970 regex_last = regex_cur;
971
972 regex_direction_last = regex_direction_cur;
973 source_search_regex(sview, regex_last.c_str(), 2,
974 regex_direction_last, regex_icase);
975 if_draw();
976 done = 1;
977 break;
978 case 8:
979 case 127:
980 /* Backspace or DEL key */
981 if (regex_cur.size() == 0) {
982 done = 1;
983 source_search_regex(sview, "", 2,
984 regex_direction_cur, regex_icase);
985 } else {
986 regex_cur.erase(regex_cur.size() - 1);
987 source_search_regex(sview, regex_cur.c_str(), 1,
988 regex_direction_cur, regex_icase);
989 if_draw();
990 update_status_win(WIN_REFRESH);
991 }
992 break;
993 default:
994 if (kui_term_is_cgdb_key(key)) {
995 const char *keycode = kui_term_get_keycode_from_cgdb_key(key);
996 int length = strlen(keycode), i;
997
998 for (i = 0; i < length; i++)
999 regex_cur.push_back(keycode[i]);
1000 } else {
1001 regex_cur.push_back(key);
1002 }
1003 source_search_regex(sview, regex_cur.c_str(), 1,
1004 regex_direction_cur, regex_icase);
1005 if_draw();
1006 update_status_win(WIN_REFRESH);
1007 };
1008
1009 if (done) {
1010 regex_cur.clear();
1011
1012 sbc_kind = SBC_NORMAL;
1013 if_set_focus(CGDB);
1014 }
1015
1016 return 0;
1017 }
1018
status_bar_normal_input(int key)1019 static int status_bar_normal_input(int key)
1020 {
1021 /* Flag to indicate we're done with status mode, need to switch back */
1022 int done = 0;
1023
1024 /* The goal of this state is to receive a command from the user. */
1025 switch (key) {
1026 case '\r':
1027 case '\n':
1028 case CGDB_KEY_CTRL_M:
1029 /* Found a command */
1030 if_run_command(src_viewer, cur_sbc);
1031 done = 1;
1032 break;
1033 case 8:
1034 case 127:
1035 /* Backspace or DEL key */
1036 if (cur_sbc.size() == 0) {
1037 done = 1;
1038 } else {
1039 cur_sbc.erase(cur_sbc.size() - 1);
1040 update_status_win(WIN_REFRESH);
1041 }
1042 break;
1043 default:
1044 if (kui_term_is_cgdb_key(key)) {
1045 const char *keycode = kui_term_get_keycode_from_cgdb_key(key);
1046 int length = strlen(keycode), i;
1047
1048 for (i = 0; i < length; i++)
1049 cur_sbc.push_back(keycode[i]);
1050 } else {
1051 cur_sbc.push_back(key);
1052 }
1053 update_status_win(WIN_REFRESH);
1054 break;
1055 };
1056
1057 if (done) {
1058 cur_sbc.clear();
1059 if_set_focus(CGDB);
1060 }
1061
1062 return 0;
1063 }
1064
status_bar_input(struct sviewer * sview,int key)1065 static int status_bar_input(struct sviewer *sview, int key)
1066 {
1067 switch (sbc_kind) {
1068 case SBC_NORMAL:
1069 return status_bar_normal_input(key);
1070 case SBC_REGEX:
1071 return status_bar_regex_input(sview, key);
1072 };
1073
1074 return -1;
1075 }
1076
1077 /**
1078 * toggle a breakpoint
1079 *
1080 * \param sview
1081 * The source view
1082 *
1083 * \param t
1084 * The action to take
1085 *
1086 * \return
1087 * 0 on success, -1 on error.
1088 */
1089 static int
toggle_breakpoint(struct sviewer * sview,enum tgdb_breakpoint_action t)1090 toggle_breakpoint(struct sviewer *sview, enum tgdb_breakpoint_action t)
1091 {
1092 int line;
1093 uint64_t addr = 0;
1094 char *path = NULL;
1095
1096 if (!sview || !sview->cur || !sview->cur->path)
1097 return -1;
1098
1099 line = sview->cur->sel_line;
1100
1101 if (sview->cur->path[0] == '*')
1102 {
1103 addr = sview->cur->file_buf.addrs[line];
1104 if (!addr)
1105 return -1;
1106 }
1107 else
1108 {
1109
1110 /* Get filename (strip path off -- GDB is dumb) */
1111 path = strrchr(sview->cur->path, '/') + 1;
1112 if (path == (char *)NULL + 1)
1113 path = sview->cur->path;
1114 }
1115
1116 /* delete an existing breakpoint */
1117 if (sview->cur->lflags[line].breakpt)
1118 t = TGDB_BREAKPOINT_DELETE;
1119
1120 tgdb_request_modify_breakpoint(tgdb, path, line + 1, addr, t);
1121 return 0;
1122 }
1123
1124 /* source_input: Handles user input to the source window.
1125 * -------------
1126 *
1127 * sview: Source viewer object
1128 * key: Keystroke received.
1129 */
source_input(struct sviewer * sview,int key)1130 static void source_input(struct sviewer *sview, int key)
1131 {
1132 switch (key) {
1133 case CGDB_KEY_UP:
1134 case 'k': { /* VI-style up-arrow */
1135 int lineno = 1;
1136 cgdb_string_to_int(G_line_number.c_str(), &lineno);
1137 source_vscroll(sview, -lineno);
1138 break;
1139 }
1140 case CGDB_KEY_DOWN:
1141 case 'j': { /* VI-style down-arrow */
1142 int lineno = 1;
1143 cgdb_string_to_int(G_line_number.c_str(), &lineno);
1144 source_vscroll(sview, lineno);
1145 break;
1146 }
1147 case CGDB_KEY_LEFT:
1148 case 'h':
1149 source_hscroll(sview, -1);
1150 break;
1151 case CGDB_KEY_RIGHT:
1152 case 'l':
1153 source_hscroll(sview, 1);
1154 break;
1155 case CGDB_KEY_CTRL_U: /* VI-style 1/2 page up */
1156 source_vscroll(sview, -(get_src_height() / 2));
1157 break;
1158 case CGDB_KEY_PPAGE:
1159 case CGDB_KEY_CTRL_B: /* VI-style page up */
1160 source_vscroll(sview, -(get_src_height() - 1));
1161 break;
1162 case CGDB_KEY_CTRL_D: /* VI-style 1/2 page down */
1163 source_vscroll(sview, (get_src_height() / 2));
1164 break;
1165 case CGDB_KEY_NPAGE:
1166 case CGDB_KEY_CTRL_F: /* VI-style page down */
1167 source_vscroll(sview, get_src_height() - 1);
1168 break;
1169 case 'g': /* beginning of file */
1170 if (last_key_pressed == 'g')
1171 source_set_sel_line(sview, 1);
1172 break;
1173 case 'G': { /* end of file or a line number */
1174 int lineno = -1;
1175 cgdb_string_to_int(G_line_number.c_str(), &lineno);
1176 source_set_sel_line(sview, lineno);
1177 break;
1178 }
1179 case '=':
1180 /* inc window by 1 */
1181 increase_win_height(0);
1182 break;
1183 case '-':
1184 /* dec window by 1 */
1185 decrease_win_height(0);
1186 break;
1187 case '+':
1188 increase_win_height(1);
1189 break;
1190 case '_':
1191 decrease_win_height(1);
1192 break;
1193 case 'o':
1194 /* Causes file dialog to be opened */
1195 {
1196 extern int kui_input_acceptable;
1197
1198 kui_input_acceptable = 0;
1199
1200 tgdb_request_inferiors_source_files(tgdb);
1201 }
1202 break;
1203 case ' ':
1204 {
1205 enum tgdb_breakpoint_action t = TGDB_BREAKPOINT_ADD;
1206
1207 toggle_breakpoint(sview, t);
1208 }
1209 break;
1210 case 't':
1211 {
1212 enum tgdb_breakpoint_action t = TGDB_TBREAKPOINT_ADD;
1213
1214 toggle_breakpoint(sview, t);
1215 }
1216 break;
1217 default:
1218 break;
1219 }
1220
1221 /* Store digits into G_line_number for 'G' command. */
1222 if (key >= '0' && key <= '9') {
1223 G_line_number.push_back(key);
1224 } else {
1225 G_line_number.clear();
1226 }
1227
1228 /* Some extended features that are set by :set sc */
1229 if_draw();
1230 }
1231
1232 /* Sets up the signal handler for SIGWINCH
1233 * Returns -1 on error. Or 0 on success */
set_up_signal(void)1234 static int set_up_signal(void)
1235 {
1236 struct sigaction action;
1237
1238 action.sa_handler = signal_handler;
1239 sigemptyset(&action.sa_mask);
1240 action.sa_flags = 0;
1241
1242 if (sigaction(SIGWINCH, &action, NULL) < 0) {
1243 clog_error(CLOG_CGDB, "sigaction failed ");
1244 return -1;
1245 }
1246
1247 if (sigaction(SIGINT, &action, NULL) < 0) {
1248 clog_error(CLOG_CGDB, "sigaction failed ");
1249 return -1;
1250 }
1251
1252 if (sigaction(SIGTERM, &action, NULL) < 0) {
1253 clog_error(CLOG_CGDB, "sigaction failed ");
1254 return -1;
1255 }
1256
1257 if (sigaction(SIGQUIT, &action, NULL) < 0) {
1258 clog_error(CLOG_CGDB, "sigaction failed ");
1259 return -1;
1260 }
1261
1262 if (sigaction(SIGCHLD, &action, NULL) < 0) {
1263 clog_error(CLOG_CGDB, "sigaction failed ");
1264 return -1;
1265 }
1266
1267 return 0;
1268 }
1269
1270 /* ----------------- */
1271 /* Exposed Functions */
1272 /* ----------------- */
1273
1274 /* See interface.h for function descriptions. */
if_init(void)1275 int if_init(void)
1276 {
1277 /* Set up the signal handler to catch SIGWINCH */
1278 if (set_up_signal() == -1)
1279 {
1280 clog_error(CLOG_CGDB, "Unable to handle signal: SIGWINCH");
1281 return -1;
1282 }
1283
1284 if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1) {
1285 screen_size.ws_row = swin_lines();
1286 screen_size.ws_col = swin_cols();
1287 }
1288
1289 /* Create the file dialog object */
1290 fd = filedlg_new(0, 0, HEIGHT, WIDTH);
1291
1292 /* Set up window layout */
1293 window_shift = (int) ((HEIGHT / 2) * (cur_win_split / 2.0));
1294
1295 return 0;
1296 }
1297
1298 /**
1299 * Send input to the CGDB source window.
1300 *
1301 * @param key
1302 * The key to send to the CGDB source window.
1303 *
1304 * @param last_key
1305 * An output parameter. When set, that will tell cgdb to use the set value,
1306 * instead of the current key, as the "last_key_pressed" in the next
1307 * call to cgdb_input. This is useful to set mainly when the current input
1308 * has consumed more than one character, and the "last_key_pressed" should
1309 * be not set on the next call to cgdb_input.
1310 *
1311 * @return
1312 * Currently only returns 0.
1313 */
cgdb_input(int key,int * last_key)1314 static int cgdb_input(int key, int *last_key)
1315 {
1316 int regex_icase = cgdbrc_get_int(CGDBRC_IGNORECASE);
1317
1318 if (src_viewer && src_viewer->cur) {
1319 int ret = 0;
1320
1321 /* Handle setting (mX) and going ('X) to source buffer marks */
1322 if (last_key_pressed == 'm')
1323 ret = source_set_mark(src_viewer, key);
1324 else if (last_key_pressed == '\'')
1325 ret = source_goto_mark(src_viewer, key);
1326
1327 if (ret) {
1328 /* When m[a-zA-Z] matches, don't let the marker char
1329 * be treated as the last key. That would allow the
1330 * chars mgg, to set the marker g, and then move to the top
1331 * of the file via gg.
1332 * CGDB should see those as mg (set a local mark g), and then
1333 * an individual g.
1334 */
1335 *last_key = 0;
1336 if_draw();
1337 return 0;
1338 }
1339 }
1340
1341 switch (key) {
1342 case 's':
1343 scr_set_scroll_mode(gdb_scroller, true);
1344 if_set_focus(GDB);
1345 return 0;
1346 case 'i':
1347 if_set_focus(GDB);
1348 return 0;
1349 case ':':
1350 /* Set the type of the command the user is typing in the status bar */
1351 sbc_kind = SBC_NORMAL;
1352 if_set_focus(CGDB_STATUS_BAR);
1353 /* Since the user is about to type in a command, clear the buffer
1354 * in which this command can be stored. */
1355 cur_sbc.clear();
1356 return 0;
1357 case '/':
1358 case '?':
1359 if (src_viewer->cur) {
1360 regex_cur.clear();
1361 regex_direction_cur = ('/' == key);
1362 orig_line_regex = src_viewer->cur->sel_line;
1363
1364 sbc_kind = SBC_REGEX;
1365 if_set_focus(CGDB_STATUS_BAR);
1366
1367 /* Capturing regular expressions */
1368 source_search_regex_init(src_viewer);
1369
1370 /* Initialize the function for finding a regex and tell user */
1371 if_draw();
1372 }
1373 return 0;
1374 case 'n':
1375 source_search_regex(src_viewer, regex_last.c_str(), 2,
1376 regex_direction_last, regex_icase);
1377 if_draw();
1378 break;
1379 case 'N':
1380 source_search_regex(src_viewer, regex_last.c_str(), 2,
1381 !regex_direction_last, regex_icase);
1382 if_draw();
1383 break;
1384 case CGDB_KEY_CTRL_W:
1385 switch (cur_split_orientation) {
1386 case WSO_HORIZONTAL:
1387 cur_split_orientation = WSO_VERTICAL;
1388 break;
1389 case WSO_VERTICAL:
1390 cur_split_orientation = WSO_HORIZONTAL;
1391 break;
1392 }
1393
1394 if_layout();
1395
1396 break;
1397 case CGDB_KEY_F1:
1398 if_display_help();
1399 return 0;
1400 case CGDB_KEY_F5:
1401 /* Issue GDB run command */
1402 tgdb_request_run_debugger_command(tgdb, TGDB_RUN);
1403 return 0;
1404 case CGDB_KEY_F6:
1405 /* Issue GDB continue command */
1406 tgdb_request_run_debugger_command(tgdb, TGDB_CONTINUE);
1407 return 0;
1408 case CGDB_KEY_F7:
1409 /* Issue GDB finish command */
1410 tgdb_request_run_debugger_command(tgdb, TGDB_FINISH);
1411 return 0;
1412 case CGDB_KEY_F8:
1413 /* Issue GDB next command */
1414 tgdb_request_run_debugger_command(tgdb, TGDB_NEXT);
1415 return 0;
1416 case CGDB_KEY_F10:
1417 /* Issue GDB step command */
1418 tgdb_request_run_debugger_command(tgdb, TGDB_STEP);
1419 return 0;
1420 case CGDB_KEY_CTRL_L:
1421 if_layout();
1422 return 0;
1423 }
1424
1425 source_input(src_viewer, key);
1426 return 0;
1427 }
1428
internal_if_input(int key,int * last_key)1429 int internal_if_input(int key, int *last_key)
1430 {
1431 /* Normally, CGDB_KEY_ESC, but can be configured by the user */
1432 int cgdb_mode_key = cgdbrc_get_int(CGDBRC_CGDB_MODE_KEY);
1433
1434 /* The cgdb mode key, puts the debugger into command mode */
1435 if (focus != CGDB && key == cgdb_mode_key) {
1436 enum Focus new_focus = CGDB;
1437
1438 /* Depending on which cgdb was in, it can free some memory here that
1439 * it was previously using. */
1440 if (focus == CGDB_STATUS_BAR && sbc_kind == SBC_NORMAL) {
1441 cur_sbc.clear();
1442 } else if (focus == CGDB_STATUS_BAR && sbc_kind == SBC_REGEX) {
1443 regex_cur.clear();
1444
1445 hl_regex_free(&src_viewer->hlregex);
1446
1447 src_viewer->cur->sel_rline = orig_line_regex;
1448 src_viewer->cur->sel_line = orig_line_regex;
1449 sbc_kind = SBC_NORMAL;
1450 }
1451 else if (focus == GDB && sbc_kind == SBC_REGEX)
1452 {
1453 scr_disable_search(gdb_scroller, false);
1454 regex_cur.clear();
1455 sbc_kind = SBC_NORMAL;
1456 new_focus = GDB;
1457 }
1458
1459 if_set_focus(new_focus);
1460 return 0;
1461 }
1462 /* If you are already in cgdb mode, the cgdb mode key does nothing */
1463 else if (key == cgdb_mode_key)
1464 return 0;
1465
1466 /* Check for global keystrokes */
1467 switch (focus) {
1468 case CGDB:
1469 return cgdb_input(key, last_key);
1470 case GDB:
1471 return gdb_input(key, last_key);
1472 case FILE_DLG:
1473 {
1474 char filedlg_file[MAX_LINE];
1475 int ret = filedlg_recv_char(fd, key, filedlg_file, last_key_pressed);
1476
1477 /* The user cancelled */
1478 if (ret == -1) {
1479 if_set_focus(CGDB);
1480 return 0;
1481 /* Needs more data */
1482 } else if (ret == 0) {
1483 return 0;
1484 /* The user picked a file */
1485 } else if (ret == 1) {
1486 if_show_file(filedlg_file, 0, 0);
1487 if_set_focus(CGDB);
1488 return 0;
1489 }
1490 }
1491 return 0;
1492 case CGDB_STATUS_BAR:
1493 return status_bar_input(src_viewer, key);
1494 }
1495
1496 /* Never gets here */
1497 return 0;
1498 }
1499
if_input(int key)1500 int if_input(int key)
1501 {
1502 int last_key = key;
1503 int result = internal_if_input(key, &last_key);
1504
1505 last_key_pressed = last_key;
1506 return result;
1507 }
1508
if_print_internal(const char * buf)1509 static void if_print_internal(const char *buf)
1510 {
1511 if (!gdb_scroller) {
1512 clog_error(CLOG_CGDB, "%s", buf);
1513 return;
1514 }
1515
1516 /* Print it to the scroller */
1517 scr_add(gdb_scroller, buf);
1518
1519 if (get_gdb_height() > 0) {
1520 scr_refresh(gdb_scroller, focus == GDB, WIN_NO_REFRESH);
1521
1522 /* Make sure cursor reappears in source window if focus is there */
1523 if (focus == CGDB)
1524 swin_wnoutrefresh(src_viewer->win);
1525
1526 swin_doupdate();
1527 }
1528
1529 }
1530
if_print(const char * buf)1531 void if_print(const char *buf)
1532 {
1533 if_print_internal(buf);
1534 }
1535
if_sdc_print(const char * buf)1536 void if_sdc_print(const char *buf)
1537 {
1538 if_print_message("cgdb sdc:%s", buf);
1539 }
1540
if_print_message(const char * fmt,...)1541 void if_print_message(const char *fmt, ...)
1542 {
1543 va_list ap;
1544 char va_buf[MAXLINE];
1545
1546 /* Get the buffer with format */
1547 va_start(ap, fmt);
1548 #ifdef HAVE_VSNPRINTF
1549 vsnprintf(va_buf, sizeof (va_buf), fmt, ap); /* this is safe */
1550 #else
1551 vsprintf(va_buf, fmt, ap); /* this is not safe */
1552 #endif
1553 va_end(ap);
1554
1555 if_print(va_buf);
1556 }
1557
if_show_file(char * path,int sel_line,int exe_line)1558 void if_show_file(char *path, int sel_line, int exe_line)
1559 {
1560 if (source_set_exec_line(src_viewer, path, sel_line, exe_line) == 0)
1561 if_draw();
1562 }
1563
if_display_help(void)1564 void if_display_help(void)
1565 {
1566 char cgdb_help_file[FSUTIL_PATH_MAX];
1567 int ret_val = 0;
1568
1569 fs_util_get_path(PKGDATADIR, "cgdb.txt", cgdb_help_file);
1570
1571 /* File doesn't exist. Try to find cgdb.txt in the build dir in case
1572 * the user is running a built cgdb binary directly. */
1573 if (!fs_verify_file_exists(cgdb_help_file))
1574 fs_util_get_path(TOPBUILDDIR, "doc/cgdb.txt", cgdb_help_file);
1575
1576 ret_val = source_set_exec_line(src_viewer, cgdb_help_file, 1, 0);
1577
1578 if (ret_val == 0)
1579 {
1580 src_viewer->cur->language = TOKENIZER_LANGUAGE_CGDBHELP;
1581 source_highlight(src_viewer->cur);
1582 if_draw();
1583 }
1584 else if (ret_val == 5) /* File does not exist */
1585 if_display_message(WIN_REFRESH, "No such file: ", cgdb_help_file);
1586 }
1587
if_display_logo(int reset)1588 void if_display_logo(int reset)
1589 {
1590 if (reset)
1591 logo_reset();
1592
1593 src_viewer->cur = NULL;
1594 }
1595
if_get_sview()1596 struct sviewer *if_get_sview()
1597 {
1598 return src_viewer;
1599 }
1600
if_clear_filedlg(void)1601 void if_clear_filedlg(void)
1602 {
1603 filedlg_clear(fd);
1604 }
1605
if_add_filedlg_choice(const char * filename)1606 void if_add_filedlg_choice(const char *filename)
1607 {
1608 filedlg_add_file_choice(fd, filename);
1609 }
1610
if_filedlg_display_message(char * message)1611 void if_filedlg_display_message(char *message)
1612 {
1613 filedlg_display_message(fd, message);
1614 }
1615
if_shutdown(void)1616 void if_shutdown(void)
1617 {
1618 if (status_win) {
1619 swin_delwin(status_win);
1620 status_win = NULL;
1621 }
1622
1623 if (gdb_scroller) {
1624 scr_free(gdb_scroller);
1625 gdb_scroller = NULL;
1626 }
1627
1628 if (src_viewer) {
1629 source_free(src_viewer);
1630 src_viewer = NULL;
1631 }
1632
1633 if (vseparator_win) {
1634 swin_delwin(vseparator_win);
1635 vseparator_win = NULL;
1636 }
1637 }
1638
if_set_focus(Focus f)1639 void if_set_focus(Focus f)
1640 {
1641 switch (f) {
1642 case GDB:
1643 focus = f;
1644 if_draw();
1645 break;
1646 case CGDB:
1647 focus = f;
1648 if_draw();
1649 break;
1650 case FILE_DLG:
1651 focus = f;
1652 if_draw();
1653 break;
1654 case CGDB_STATUS_BAR:
1655 focus = f;
1656 if_draw();
1657 default:
1658 return;
1659 }
1660 }
1661
if_get_focus(void)1662 Focus if_get_focus(void)
1663 {
1664 return focus;
1665 }
1666
reset_window_shift(void)1667 void reset_window_shift(void)
1668 {
1669 int h_or_w = cur_split_orientation == WSO_HORIZONTAL ? HEIGHT : WIDTH;
1670
1671 window_shift = (int) ((h_or_w / 2) * (cur_win_split / 2.0));
1672 if_layout();
1673 }
1674
if_set_winsplitorientation(WIN_SPLIT_ORIENTATION_TYPE new_orientation)1675 void if_set_winsplitorientation(WIN_SPLIT_ORIENTATION_TYPE new_orientation)
1676 {
1677 cur_split_orientation = new_orientation;
1678 reset_window_shift();
1679 }
1680
if_set_winsplit(WIN_SPLIT_TYPE new_split)1681 void if_set_winsplit(WIN_SPLIT_TYPE new_split)
1682 {
1683 cur_win_split = new_split;
1684 reset_window_shift();
1685 }
1686
if_highlight_sviewer(enum tokenizer_language_support l)1687 void if_highlight_sviewer(enum tokenizer_language_support l)
1688 {
1689 /* src_viewer->cur is NULL when reading cgdbrc */
1690 if (src_viewer && src_viewer->cur) {
1691 if ( l == TOKENIZER_LANGUAGE_UNKNOWN )
1692 l = tokenizer_get_default_file_type(strrchr(src_viewer->cur->path, '.'));
1693
1694 src_viewer->cur->language = l;
1695 source_highlight(src_viewer->cur);
1696 if_draw();
1697 }
1698 }
1699
if_change_winminheight(int value)1700 int if_change_winminheight(int value)
1701 {
1702 if (value < 0)
1703 return -1;
1704 else if (value > HEIGHT / 2)
1705 return -1;
1706
1707 interface_winminheight = value;
1708 if_layout();
1709
1710 return 0;
1711 }
1712
if_change_winminwidth(int value)1713 int if_change_winminwidth(int value)
1714 {
1715 if (value < 0)
1716 return -1;
1717 else if (value > WIDTH / 2)
1718 return -1;
1719
1720 interface_winminwidth = value;
1721 if_layout();
1722
1723 return 0;
1724 }
1725
if_clear_line()1726 int if_clear_line()
1727 {
1728 std::string line;
1729
1730 line.push_back('\r');
1731 line.append(get_gdb_width(), ' ');
1732 line.push_back('\r');
1733
1734 if_print(line.c_str());
1735
1736 return 0;
1737 }
1738