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