1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * Copyright (C) 2004 Xavier de Gaye.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program (see the file COPYING); if not, write to the
17  * Free Software Foundation, Inc.,
18  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19  *
20  * $Id: clewn.c 225 2008-10-19 12:58:47Z xavier $
21  */
22 
23 #include <config.h>
24 
25 #include <signal.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <regex.h>
29 #include <readline/readline.h>
30 #include <readline/history.h>
31 
32 
33 #ifdef HAVE_SYS_WAIT_H
34 # include <sys/wait.h>
35 #endif
36 
37 #if defined(HAVE_SYS_SELECT_H) && \
38 	(!defined(HAVE_SYS_TIME_H) || defined(SYS_SELECT_WITH_SYS_TIME))
39 # include <sys/select.h>
40 #endif
41 
42 #ifndef HAVE_SELECT
43 # ifdef HAVE_SYS_POLL_H
44 #  include <sys/poll.h>
45 # else
46 #  ifdef HAVE_POLL_H
47 #   include <poll.h>
48 #  endif
49 # endif
50 #endif
51 
52 #ifdef HAVE_TERMIOS_H
53 # include <termios.h>
54 #else
55 # include <termio.h>
56 #endif
57 
58 /* sun's sys/ioctl.h redefines symbols from termio world */
59 #if defined(HAVE_SYS_IOCTL_H) && !defined(sun)
60 # include <sys/ioctl.h>
61 #endif
62 
63 #include "obstack.h"
64 #include "clewn.h"
65 #include "gdb.h"
66 #include "misc.h"
67 
68 /*
69  * EMX doesn't have a global way of making open() use binary I/O.
70  * Use O_BINARY for all open() calls.
71  */
72 #if defined(__EMX__) || defined(__CYGWIN32__)
73 # define O_EXTRA    O_BINARY
74 #else
75 # define O_EXTRA    0
76 #endif
77 
78 #define CLEWN_HELP "Clewn version %s using readline library revision %s.\n\
79 \n\
80 Usage: clewn [-vc gvim_cmd] [-va gvim_args]\n\
81              [-gc gdb_cmd] [-ga gdb_args]\n\
82 	     [-p project] [-x pathnames_map]\n\
83              [-a] [-nb[:<host>[:<port>[:<passwd>]]]] [-d] [-r]\n\
84 \n\
85   -vc gvim_cmd                gvim shell command or gvim pathname (default 'gvim')\n\
86   -va gvim_args               gvim command line arguments\n\
87   -gc gdb_cmd                 gdb shell command or gdb pathname (default 'gdb')\n\
88   -ga gdb_args                gdb command line arguments\n\
89   -p  project                 project file name\n\
90   -x pathnames_map            remote debugging\n\
91   -a                          enable assembly support\n\
92   -nb:<host>:<port>:<passwd>  NetBeans connection parameters\n\
93                                 <host>   default {$__NETBEANS_HOST|localhost}\n\
94                                 <port>   default {$__NETBEANS_SOCKET|3219}\n\
95                                 <passwd> default {$__NETBEANS_VIM_PASSWORD|changeme}\n\
96   -d                          enable NetBeans debug mode\n\
97   -r                          do not set SO_REUSEADDR socket option\n\
98 \n\
99 Clewn listens on host:port, with host being a name or the IP address of one\n\
100 of the local network interfaces in standard dot notation.\n\n"
101 
102 #define INPUTRC_FNAME	    "inputrc"
103 #define CLEWN_HISTORY_FILE  "/.clewn_history"
104 #define CLEWN_KEYS_FILE	    "/.clewn_keys"
105 #define HISTORY_DFLT_SIZE   50
106 #define GVIM_DEFAULT_ARG    " -c \"run clewn.vim\" -nb -g "
107 
108 int p_asm = 0;			/* assembly support when non zero */
109 
110 static int module_state = -1;		    /* initial state (not OK, nor FAIL) */
111 static char clewn_buf[MAX_BUFFSIZE];	    /* general purpose buffer */
112 
113 static char * p_vim = NULL;
114 static char * p_vc = "gvim";/* gvim shell command or gvim pathname */
115 static char * p_va = "";    /* gvim command line arguments */
116 static char * p_gdb = NULL;
117 static char * p_gc = "gdb"; /* gdb shell command or gdb pathname */
118 static char * p_ga = "";    /* gdb command line arguments */
119 static char * p_project = NULL;/* project file name */
120 static char * p_pmap = NULL;/* remote debugging pathnames map */
121 
122 static int clewn_debug = FALSE;				/* debug flag */
123 static int showBalloon = FALSE;				/* enable tooltips */
124 static char * p_gvar = VARIABLES_FNAME;			/* variables buffer extension */
125 static char *clewn_tempdir = NULL;			/* Clewn temporary directory */
126 static char *clewn_dir;					/* Clewn directory */
127 
128 static gdb_T *gdb = NULL;	/* the gdb_T instance */
129 static int got_sigint = FALSE;	/* TRUE when got SIGINT */
130 static int got_sigchld = FALSE;	/* TRUE when got SIGCHLD */
131 static int got_tab = FALSE;	/* TRUE when got a <TAB> */
132 static char *preprompt;		/* previous prompt line when prompt is multi line */
133 static char *cplt_prmpt;	/* current prompt for completion */
134 static int nl_output;		/* when TRUE, no need to output a newline */
135 static char *key_command;	/* command mapped from NetBeans key */
136 static int inside_readline = FALSE; /* TRUE when cli_getc() is called by readline() */
137 
138 #define FUNMAP_SIZE 20
139 #define CLEWN_KEYMAP_SIZE (256 + FUNMAP_SIZE)
140 #define INTBITS (sizeof(int) * 8)
141 
142 #define FUNCTION_INDEX(n) (((n) > 0 && (n) <= FUNMAP_SIZE) \
143 	? (256 + (n) - 1) : -1)
144 
145 #define IS_KEY_FLAG(t,i) (((i) >= 0 && (i) < CLEWN_KEYMAP_SIZE) \
146 	? ((t)[(i) / INTBITS] & (1 << ((i) % INTBITS))) : FALSE)
147 
148 #define SET_KEY_LINE(t,i) (((i) >= 0 && (i) < CLEWN_KEYMAP_SIZE) \
149 	? ((t)[(i) / INTBITS] |= (1 << ((i) % INTBITS))) : FALSE)
150 
151 static char * keymap[CLEWN_KEYMAP_SIZE];  /* GDB commands array indexed by key */
152 static int keyline[CLEWN_KEYMAP_SIZE / INTBITS + 1];	/* %line flag bit map */
153 static int keytext[CLEWN_KEYMAP_SIZE / INTBITS + 1];	/* %text flag bit map */
154 
155 /* The gdb keyword */
156 typedef struct
157 {
158     int type;
159     char *keyword;	/* keyword */
160     char *tail;		/* optional tail */
161 } token_T;
162 
163 static token_T tokens[] =
164 {
165     {CMD_DETACH,    "det",	"ach"	    },
166     {CMD_SHELL,	    "she",	"ll"	    },
167     {CMD_STEPI,	    "si",	""	    },
168     {CMD_STEPI,	    "stepi",	""	    },
169     {CMD_STEPI,	    "ni",	""	    },
170     {CMD_STEPI,	    "nexti",	""	    },
171     {CMD_EXECF,	    "fil",	"e"	    },
172     {CMD_EXECF,	    "ex",	"ec-file"   },
173     {CMD_EXECF,	    "cor",	"e-file"    },
174     {CMD_BREAK,	    "b",	"reak"	    },
175     {CMD_BREAK,	    "tb",	"reak"	    },
176     {CMD_BREAK,	    "hb",	"reak"	    },
177     {CMD_BREAK,	    "thb",	"reak"	    },
178     {CMD_DISPLAY,   "disp",	"lay"	    },
179     {CMD_CREATEVAR, "cr",	"eatevar"   },
180     {CMD_UP_SILENT, "up-",	"silently"  },
181     {CMD_UP,	    "up",	""	    },
182     {CMD_DOWN_SILENT,"down-",	"silently"  },
183     {CMD_DOWN,	    "do",	"wn"	    },
184     {CMD_FRAME,	    "f",	"rame"	    },
185     {CMD_DISABLE,   "disab",	"le"	    },
186     {CMD_DELETE,    "del",	"ete"	    },
187     {CMD_SLECT_FRAME,"sel",	"ect-frame" },
188     {CMD_SYMF,	    "sy",	"mbol-file" },
189     {CMD_SYMF,	    "add-sy",	"mbol-file" },
190     {CMD_SYMF,	    "so",	"urce"	    },
191     {CMD_RESTART,   "cl_",	"restart"   },
192     {CMD_QUIT,	    "q",	"uit"	    },
193     {CMD_ANY,	    NULL,	NULL	    }
194 };
195 
196 /* The gdb pattern */
197 typedef struct
198 {
199     int id;		/* pattern id */
200     char *str;		/* string pattern */
201     regex_t *regprog;	/* compiled regexp */
202 } pattern_T;
203 
204 static pattern_T patterns[] =
205 {
206     {PAT_DIR,		"^ *Source directories searched: *(.*)$", NULL},
207     {PAT_CHG_ANNO,	"^ *set +a(n|nn|nno|nnot|nnota|nnotat|nnotate) +.*$", NULL},
208     {PAT_ADD,		"^ *0x0*([0-9a-fA-F]+)", NULL},
209     {PAT_PID,		"^ *a(t|tt|tta|ttac|ttach) +([0-9]+) *$", NULL},
210 #if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
211     {PAT_SOURCE,	"^ *([^:]*):([^:]*):[^:]*:[^:]*:0x0*([0-9a-fA-F]+)$", NULL},
212     {PAT_QUERY,		"^.*\\(y or n\\) *$", NULL},
213     {PAT_YES,		"^ *(y|ye|yes) *$", NULL},
214     {PAT_SFILE,		"^Symbols from *\"([^\"]+)", NULL},
215     {PAT_BP_CONT,	"^ *(c) *|^ *(con)(t|ti|tin|tinu|tinue) *", NULL},
216     {PAT_ASM_FUNC,	"^([^ ^(]+)(\\(.*\\))* .*in section .text$", NULL},
217     {PAT_ASM_FUNC_P,	"^.*<([^ ^+]+)(\\+[0-9]+)*>$", NULL},
218     {PAT_FRAME,		"^#[0-9]+ +0x0*([0-9a-fA-F]+)", NULL},
219     {PAT_HEIGHT,	"^ *set +h(e|ei|eig|eigh|eight) +([0-9]+) *$", NULL},
220 #endif
221 #ifdef GDB_LVL2_SUPPORT
222     /* MUST add '.*' at end of each info (possibly last) breakpoint field
223      * pattern because GDB adds the hit count, in a new line, after
224      * printing the last field and within its annotation context */
225     {PAT_BP_ASM,	"^<([^ ]+)\\+[0-9]+>.*$|^<([^ ]+)>.*$", NULL},
226     {PAT_BP_SOURCE,	"^.* ([^ ]+):([0-9]+).*$", NULL},
227     {PAT_DISPLAY,	"^ *dis(p|pl|pla|play) *$", NULL},
228     {PAT_DISPINFO,	"^([0-9]+):", NULL},
229     {PAT_CREATEVAR,	"^ *c(r|re|rea|reat|reate|reatev|reateva|reatevar) +(.*)$", NULL},
230 #endif
231 #ifdef GDB_LVL3_SUPPORT
232     {PAT_CRVAR_FMT,	"^ *c(r|re|rea|reat|reate|reatev|reateva|reatevar) *(/[tdxo])* +(.*)$", NULL},
233     {PAT_INFO_FRAME,	"^Stack level ([0-9]+), frame at ", NULL},
234 #endif
235     {0,			NULL, NULL}
236 };
237 
238 #if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
239 static char *inputrc;		/* readline inputrc file name */
240 
241 /* gdb readline inputrc file content */
242 static char *inputrc_array[] = {
243     "set show-all-if-ambiguous on\n",
244     "Control-u: unix-line-discard\n",
245     NULL
246 };
247 #endif
248 
249 /* default key mappings with netbeans version < 2.3 (no specialKeys command) */
250 static char * old_keys_mapping[] =
251 {
252     "z:\032:		    # interrupt",
253     "B:info breakpoints:",
254     "L:info locals:",
255     "A:info args:",
256     "S:step:",
257     "I:stepi:",
258     "n:next:",
259     "N:nexti:		    # upper case",
260     "F:finish:",
261     "R:run:",
262     "Q:quit:",
263     "C:continue:",
264     "W:where:",
265     "u:up:",
266     "d:down:",
267     "b:break:%line	    # set breakpoint at current line",
268     "e:clear:%line	    # clear breakpoint at current line",
269     "k:break *:%text	    # set breakpoint at address at mouse position",
270     "h:clear *:%text	    # clear breakpoint at address at mouse position",
271     "p:print:%text	    # print value of word at mouse position",
272     "a:print *:%text	    # print value referenced by text at mouse position",
273     "j:createvar:%text	    # add variable (expression) at mouse position",
274     NULL
275 };
276 
277 /* default key mappings with netbeans version >= 2.3 (with specialKeys command) */
278 static char * keys_mapping[] =
279 {
280     "C-Z:\032:		    # interrupt",
281     "B:info breakpoints:",
282     "L:info locals:",
283     "A:info args:",
284     "S:step:",
285     "I:stepi:",
286     "C-N:next:",
287     "X:nexti:		    # upper case",
288     "F:finish:",
289     "R:run:",
290     "Q:quit:",
291     "C:continue:",
292     "W:where:",
293     "C-U:up:",
294     "C-D:down:",
295     "C-B:break:%line	    # set breakpoint at current line",
296     "C-E:clear:%line	    # clear breakpoint at current line",
297     "C-K:break *:%text	    # set breakpoint at address at mouse position",
298     "C-H:clear *:%text	    # clear breakpoint at address at mouse position",
299     "C-P:print:%text	    # print value of word at mouse position",
300     "C-X:print *:%text	    # print value referenced by text at mouse position",
301     "C-J:createvar:%text    # add variable (expression) at mouse position",
302     NULL
303 };
304 
305 /* storage for mtrace hooks */
306 #if defined(GDB_MTRACE) && defined(HAVE_MTRACE)
307 __ptr_t (*s_malloc) (size_t, const void *);
308 void (*s_free) (void *, const void *);
309 __ptr_t (*s_realloc) (void *, size_t, const void *);
310 #endif	/* GDB_MTRACE */
311 
312 /* readline interface */
313 static int cli_init __ARGS((void));
314 #ifdef HAVE_RL_COMMAND_FUNC_T
315 static rl_command_func_t cli_complete;
316 #else
317 static int cli_complete __ARGS((void));
318 #endif
319 static int cli_getc __ARGS((FILE *));
320 
321 /* Gdb process mgmt */
322 static RETSIGTYPE catch_sigint __ARGS((int));
323 static RETSIGTYPE catch_sigterm __ARGS((int));
324 static RETSIGTYPE catch_sigchld __ARGS((int));
325 static RETSIGTYPE catch_sigpipe __ARGS((int));
326 static void clewn_abort __ARGS((void));
327 static void clewn_getout __ARGS((void));
328 static void start_gdb_process __ARGS((void));
329 static int module_init __ARGS((void));
330 static void module_end __ARGS((void));
331 static void clear_gdb_T __ARGS((void));
332 static void exec_gdb __ARGS((void));
333 static int exec_gvim __ARGS((void));
334 static void clewn_keymap __ARGS((void));
335 static void write_project __ARGS((void));
336 
337 /* Utilities */
338 static int clewn_mktmpdir __ARGS((void));
339 static void clewn_deltempdir __ARGS((void));
340 static void print_regerror __ARGS((int, regex_t *));
341 static void clear_readline __ARGS((void));
342 static void clewn_add_history __ARGS((char *));
343 static void parse_keyline(char *);
344 static void read_keysfile __ARGS((char *));
345 static void process_nb_event __ARGS((void));
346 static char * get_keymap __ARGS((nb_event_T *));
347 
348 /*
349  * Main
350  */
351     int
main(int argc,char ** argv)352 main(int argc, char ** argv)
353 {
354     char * nbconn  = NULL;	    /* NetBeans connection parameters */
355     char intr[2]   = {KEY_INTERUPT, NUL};
356     int reuse_addr   = TRUE;
357     char *line;
358 
359 #if defined(GDB_MTRACE) && defined(HAVE_MTRACE)
360     mtrace();
361     mv_hooks();
362 #endif
363     /* register an abort function for when allocating memory fails */
364     xatabort(clewn_abort);
365     obstack_alloc_failed_handler = clewn_abort;
366 
367     /* initialize readline */
368     rl_readline_name = "Clewn";	    /* allow conditional parsing of ~/.inputrc */
369     rl_startup_hook = cli_init;	    /* change the binding of the <TAB> key */
370     rl_getc_function = cli_getc;    /* to get a character from the input stream */
371     rl_initialize();
372     if (rl_outstream == NULL)
373     {
374 	fprintf(stderr, "cannot initialize readline\n");
375 	clewn_abort();
376     }
377 
378     /*
379      * Get program options
380      */
381     argv++;
382     argc--;
383 
384     while (argc > 0)
385     {
386 	char *opt = *argv;
387 
388 	if (*opt == '-')
389 	{
390 	    switch (*(opt + 1))
391 	    {
392 		case 'v':
393 		    if (*(opt + 2) == 'c'|| *(opt + 2) == 'a') {
394 			argv++;
395 			argc--;
396 			if (argc <= 0 || ((*argv)[0] == '-' && *(opt + 2) == 'c')) {
397 			    fprintf(stderr, "Cannot parse mandatory parameter of \"%s\"\n", opt);
398 			    clewn_abort();
399 			}
400 			/* -vc gvim_cmd - gvim shell command or gvim pathname (default 'gvim') */
401 			if (*(opt + 2) == 'c')
402 			    p_vc = *argv;
403 			/* -va gvim_args - gvim command line arguments */
404 			else if (*(opt + 2) == 'a')
405 			    p_va = *argv;
406 		    }
407 		    else if (*(opt + 2) == NUL) { /* "-v" print help */
408 			fprintf(stderr, CLEWN_HELP, PACKAGE_VERSION, rl_library_version);
409 			clewn_abort();
410 		    }
411 		    else {
412 			fprintf(stderr, "Unknown command line argument \"%s\"\n", opt);
413 			clewn_abort();
414 		    }
415 		    break;
416 
417 		case 'g':
418 		    if (*(opt + 2) == 'c'|| *(opt + 2) == 'a') {
419 			argv++;
420 			argc--;
421 			if (argc <= 0 || ((*argv)[0] == '-' && *(opt + 2) == 'c')) {
422 			    fprintf(stderr, "Cannot parse mandatory parameter of \"%s\"\n", opt);
423 			    clewn_abort();
424 			}
425 			/* -gc gdb_cmd - gdb shell command or gdb pathname (default 'gdb') */
426 			if (*(opt + 2) == 'c')
427 			    p_gc = *argv;
428 			/* -ga gdb_args - gdb command line arguments */
429 			else if (*(opt + 2) == 'a')
430 			    p_ga = *argv;
431 		    }
432 		    else {
433 			fprintf(stderr, "Unknown command line argument \"%s\"\n", opt);
434 			clewn_abort();
435 		    }
436 		    break;
437 
438 		case 'p':   /* "-p" project file name */
439 		    argv++;
440 		    argc--;
441 		    if (argc <= 0 || (*argv)[0] == '-') {
442 			fprintf(stderr, "Cannot parse mandatory parameter of \"%s\"\n", opt);
443 			clewn_abort();
444 		    }
445 		    p_project = *argv;
446 		    break;
447 
448 		case 'a':   /* "-a" set assembly support */
449 		    p_asm = 1;
450 		    break;
451 
452 		case 't':   /* "-t" enable displaying GDB state in a tooltip */
453 		    showBalloon = TRUE;
454 		    break;
455 
456 		case 'r':   /* "-r" do not set SO_REUSEADDR socket option */
457 		    reuse_addr = FALSE;
458 		    break;
459 
460 		case 'x':   /* "-x" remote debugging */
461 		    argv++;
462 		    argc--;
463 		    if (argc <= 0 || (*argv)[0] == '-') {
464 			fprintf(stderr, "Cannot parse mandatory parameter of \"%s\"\n", opt);
465 			clewn_abort();
466 		    }
467 		    p_pmap = *argv;
468 		    break;
469 
470 		case 'd':   /* "-d" enable NetBeans debug output */
471 		    clewn_debug = TRUE;
472 		    break;
473 
474 		case 'n':   /* "-nb:host:port:passwd" NetBeans parameters */
475 		    if (*(opt + 2) == 'b' && *(opt + 3) == ':')
476 			nbconn = opt + 4;
477 		    break;
478 
479 		case 'h':   /* "-h" print help */
480 		    fprintf(stderr, CLEWN_HELP, PACKAGE_VERSION, rl_library_version);
481 		    clewn_abort();
482 
483 		default:
484 		    fprintf(stderr, "Unknown command line argument \"%s\"\n", opt);
485 		    clewn_abort();
486 	    }
487 	}
488 	else
489 	{
490 	    fprintf(stderr, "Unknown command line argument \"%s\"\n", opt);
491 	    clewn_abort();
492 	}
493 
494 	argv++;
495 	argc--;
496     }
497 
498     signal(SIGINT, catch_sigint);
499     signal(SIGTERM, catch_sigterm);
500     signal(SIGCHLD, catch_sigchld);
501     signal(SIGPIPE, catch_sigpipe);
502 
503 #if defined(GDB_MTRACE) && defined(HAVE_MTRACE)
504     /* the mtrace log file may get corrupted when forking a child
505      * because mtrace uses output buffering and flushes its buffer
506      * in the child when closing on exec
507      * do few dummies alloc to force the flush before the fork
508      * and avoid that problem
509      * */
510     {
511 	#define DUMMY_ALLOC_COUNT 100	/* tune this value */
512 	int i;
513 	char * dummy;
514 
515 	for (i = 0; i < DUMMY_ALLOC_COUNT; i++)
516 	    if ((dummy = (char *)xmalloc(1)) != NULL)
517 		xfree(dummy);
518     }
519 #endif
520 
521     /* start GDB, do not output unneeded newlines */
522     nl_output = TRUE;
523     start_gdb_process();
524     nl_output = TRUE;
525 
526     if (! GDB_STATE(gdb, GS_UP))
527 	clewn_getout();
528 
529     /* remote debugging and project file are not supported on level 2 */
530     if (gdb->mode == GDB_MODE_LVL2) {
531 	p_pmap = NULL;
532 	p_project = NULL;
533     }
534 
535     /* listen on a NetBeans socket */
536     if (cnb_open(nbconn, &(gdb->var_buf), clewn_debug, reuse_addr, p_pmap) != OK)
537 	clewn_getout();
538 
539     /* the gdb instance number is used to define signs in vim
540      * with a different name for each instance of gdb */
541     cnb_set_instance(gdb->instance);
542 
543     /* create variables buffer */
544     cnb_create_varbuf(gdb->var_name);
545 
546     /* fork gvim if not doing remote debugging */
547     if (! p_pmap && exec_gvim() != OK)
548 	clewn_getout();
549 
550     while (IS_NETBEANS_CONNECTED && GDB_STATE(gdb, GS_UP))
551     {
552 	/*
553 	 * 1 - Wait for GDB prompt
554 	 */
555 	(void)cli_getc(NULL);
556 
557 	/* handle interrupt */
558 	if (got_sigint)
559 	{
560 	    got_sigint = FALSE;
561             gdb_docmd((gdb_handle_T *)gdb, intr); /* send KEY_INTERUPT to GDB */
562 	    continue;
563 	}
564 
565 	/* should never happen (but make sure we do have a prompt) */
566 	if (gdb->prompt == NULL)
567 	    gdb->prompt = clewn_strsave("(gdb)  ");
568 
569 	/*
570 	 * 2 - Launch readline
571 	 */
572 	/* output readline on a new line so as not to overwrite last line */
573 	if (! nl_output)
574 	    fputs("\n", rl_outstream);
575 	nl_output = TRUE;
576 
577 	inside_readline = TRUE;
578 
579 	if ((line = readline(gdb->prompt)) == NULL)
580 	    break;
581 
582 	inside_readline = FALSE;
583 
584 	if (gdb->note == ANO_PMT_FORMORE)
585 	{
586 	    if (got_sigint || (strlen(line) == 1 && *line == 'q'))
587 		got_sigint = TRUE;	/* abort listing */
588 	    else
589 	    {
590 		free(line);
591 		gdb_docmd((gdb_handle_T *)gdb, "");   /* continue */
592 		continue;
593 	    }
594 	}
595 
596 	if (got_tab)
597 	    got_tab = FALSE;
598 	else if (got_sigint)
599 	{
600 	    got_sigint = FALSE;
601             gdb_docmd((gdb_handle_T *)gdb, intr); /* send KEY_INTERUPT to GDB */
602 	}
603 	else
604         {
605 	    clewn_add_history(line);
606 
607 	    /* when debug mode and first char is an escape character,
608 	     * handle the line as a NetBeans command or function */
609 	    if (clewn_debug && (*line == DEBUG_ESC_CMD || *line == DEBUG_ESC_FUN))
610 		cnb_send_debug((int)*line, line + 1);
611 	    else
612 		gdb_docmd((gdb_handle_T *)gdb, line);   /* send cmd to GDB */
613         }
614 
615 	free(line);
616 
617 	/* warn the user that the data socket is not connected */
618 	if (cnb_get_datasock() < 0)
619 	{
620 	    fputs("************************************************\n", rl_outstream);
621 	    fputs("The netbeans socket to Vim is not connected yet.\n", rl_outstream);
622 	    fputs("Please check that the netbeans_intg feature is compiled in your Vim version\n", rl_outstream);
623 	    fputs("by running the Vim command \":version\", and checking that this command\n", rl_outstream);
624 	    fputs("displays \"+netbeans_intg\".\n", rl_outstream);
625 	    fputs("************************************************\n", rl_outstream);
626 	}
627 
628     }
629 
630     clewn_getout();
631     return 0;
632 }
633 
634 /* Change the binding of the <TAB> key */
635     static int
cli_init()636 cli_init()
637 {
638     rl_bind_key((int)TAB, cli_complete);
639     return 0;
640 }
641 
642 /* Handle completion */
643     static int
644 #ifdef HAVE_RL_COMMAND_FUNC_T
cli_complete(whatisthis,key)645 cli_complete(whatisthis, key)
646     int whatisthis;
647     int key;
648 #else
649 cli_complete()
650 #endif
651 {
652     char * cmd;
653 
654 #ifdef HAVE_RL_COMMAND_FUNC_T
655     whatisthis = key = 0;   /* keep compiler happy */
656 #endif
657 
658     /* store the prompt for the completion result */
659     xfree(cplt_prmpt);
660     cplt_prmpt = clewn_strsave(gdb->prompt);
661 
662     /* send readline content up to cursor and <TAB> to GDB */
663     cmd = clewn_strnsave(rl_line_buffer, rl_point + 1);
664     *(cmd + rl_point) = NUL;    /* need rl_point first characters, not more */
665     strcat(cmd, "\t");
666     gdb_docmd((gdb_handle_T *)gdb, cmd);   /* send it to GDB */
667     xfree(cmd);
668 
669     got_tab = TRUE;
670     return 0;
671 }
672 
673 /*
674  * Blocking poll/select on readline instream, GDB pseudo tty and NetBeans sockets.
675  * Return one character from instream.
676  * Return NL when got SIGINT or a GDB command mapped from a received NetBeans key.
677  * Return <SPACE> when got <TAB>.
678  * Return EOF when instream is NULL and got a GDB prompt.
679  * Return EOF when IO error or end of file.
680  */
681     static int
cli_getc(instream)682 cli_getc(instream)
683     FILE *instream;	/* not NULL when called by readline */
684 {
685     int fd = -1;	/* instream file descriptor */
686     int fdcon;		/* connection socket file descriptor */
687     int fdata;		/* data socket file descriptor */
688     pid_t wait_pid;
689     int ret;
690 #ifndef HAVE_SELECT
691     struct pollfd fds[4];
692     int nfd;
693     int gdb_idx;
694     int fdcon_idx;
695     int fdata_idx;
696 #else
697     int maxfd;
698     fd_set rfds;
699 #endif
700 
701     if (instream != NULL && (fd = fileno(instream)) == -1)
702 	return EOF;
703 
704     do
705     {
706 	ret = -1;
707 
708 	/* Source the project file when the netbeans session is up,
709 	 * so that we can set the breakpoints in vim */
710 	if (gdb->project_file != NULL
711 		&& gdb->project_state == PROJ_INIT
712 		&& ! IS_OOBACTIVE(gdb)
713 		&& inside_readline
714 		&& cnb_state())
715 	{
716 	    gdb->project_state = PROJ_SOURCEIT;
717 	    gdb_docmd((gdb_handle_T *)gdb, "");
718 	}
719 
720 	/* GDB still running */
721 	if (got_sigchld || gdb->pid == -1)
722 	{
723 	    got_sigchld = FALSE;
724 
725 	    if (gdb->pid != -1)	    /* got SIGCHLD */
726 	    {
727 		wait_pid = waitpid(gdb->pid, NULL, WNOHANG);
728 
729 		if ((wait_pid == (pid_t)-1 && errno == ECHILD)
730 			|| wait_pid == gdb->pid)
731 		{
732 		    gdb->pid = -1;  /* got SIGCHLD from GDB */
733 		    fprintf(stderr, "GDB terminated       \n");
734 		}
735 	    }
736 
737 	    if (gdb->pid == -1)	    /* shutdown and exit */
738 	    {
739 		/* restart gdb if not quitting */
740 		if (! GDB_STATE(gdb, GS_QUITTING)) {
741 		    gdb_close(gdb);
742 		    start_gdb_process();
743 		}
744 
745 		if (! GDB_STATE(gdb, GS_UP))
746 		    clewn_getout();
747 
748 	    }
749 	}
750 
751 	/* got a prompt from GDB */
752 	if (instream == NULL && gdb->prompt != NULL)
753 	{
754 	    return EOF;
755 	}
756 
757 	/* got SIGINT or an interrupt in the form of a NetBeans key command */
758 	if (got_sigint || (key_command != NULL && *key_command == KEY_INTERUPT))
759 	{
760 	    /* being called by readline */
761 	    if (instream != NULL)
762 	    {
763 		rl_point = rl_end;	/* at the end of the line */
764 		rl_insert_text("Quit");
765 		rl_redisplay();
766 	    }
767 
768 	    /* consume the key command and emulate an interrupt */
769 	    if (key_command != NULL && *key_command == KEY_INTERUPT)
770 	    {
771 		got_sigint = TRUE;
772 		FREE(key_command);
773 	    }
774 	    return (int)NL;
775 	}
776 
777 	/* got <TAB>:
778 	 * tell readline we are done
779 	 * stay on same line, but set nl_output so that further lines if
780 	 * any are printed below this line */
781 	if (instream != NULL && got_tab)
782 	{
783 	    rl_done = 1;
784 	    nl_output = FALSE;
785 	    return (int)' ';
786 	}
787 
788 	/* insert winput_cmd in readline */
789 	if (gdb->winput_cmd != NULL)
790 	{
791 	    /* being called by readline */
792 	    /* we get a prompt from GDB when the completion
793 	     * result is a list (no need to provide one then) */
794 	    if (instream != NULL)
795 	    {
796 #ifdef HAVE_RL_REPLACE_LINE
797 		rl_replace_line(gdb->winput_cmd, 0);
798 		rl_point = rl_end;	/* at the end of the line */
799 #else
800 		rl_insert_text(gdb->winput_cmd);
801 #endif
802 		rl_redisplay();
803 		FREE(gdb->winput_cmd);
804 	    }
805 	    else
806 	    {
807 		/* provide the prompt to enable readline in main */
808 		/* assert: gdb->prompt == NULL */
809 		if (gdb->cli_cmd.state == CS_QUERY)
810 		{
811 		    /* a completion query: provide last line as prompt
812 		     * overwrite (identical) last line with readline prompt */
813 		    nl_output = TRUE;
814 		    gdb->prompt = clewn_strsave(gdb->line);
815 		}
816 		else
817 		{
818 		    clear_readline();
819 
820 		    /* a single completion result: provide last prompt
821 		     * as prompt and stay on same line */
822 		    nl_output = TRUE;
823 		    gdb->prompt = cplt_prmpt;
824 		    cplt_prmpt = NULL;
825 		}
826 		return EOF;
827 	    }
828 	}
829 
830 	/* a GDB command mapped from a received NetBeans key */
831 	if (instream != NULL && key_command != NULL)
832 	{
833 	    rl_insert_text(key_command);
834 	    rl_redisplay();
835 	    FREE(key_command);
836 	    return (int)NL;
837 	}
838 
839 #ifndef HAVE_SELECT
840 	nfd = 0;
841 
842 	if (fd >= 0)
843 	{
844 	    fds[nfd].fd = fd;
845 	    fds[nfd].events = POLLIN;
846 	    nfd++;
847 	}
848 
849 	if (GDB_STATE(gdb, GS_UP))
850 	{
851 	    fds[nfd].fd = gdb->fd;
852 	    fds[nfd].events = POLLIN;
853 	    gdb_idx = nfd;
854 	    nfd++;
855 	}
856 
857 	if ((fdcon = cnb_get_connsock()) >= 0)
858 	{
859 	    fds[nfd].fd = fdcon;
860 	    fds[nfd].events = POLLIN;
861 	    fdcon_idx = nfd;
862 	    nfd++;
863 	}
864 
865 	if ((fdata = cnb_get_datasock()) >= 0)
866 	{
867 	    fds[nfd].fd = fdata;
868 	    fds[nfd].events = POLLIN;
869 	    fdata_idx = nfd;
870 	    nfd++;
871 	}
872 
873 	if (nfd > 0)
874 	    ret = poll(fds, nfd, -1);
875 
876 	if (GDB_STATE(gdb, GS_UP) && ret > 0 && fds[gdb_idx].revents & POLLIN)
877 	{
878 	    ret--;
879 	    if (gdb->parse_output != NULL)
880 		(void)gdb->parse_output(gdb);
881 	}
882 
883 	if (fdcon >= 0 && ret > 0 && fds[fdcon_idx].revents & POLLIN)
884 	{
885 	    if (instream != NULL)
886 		clear_readline();
887 
888 	    ret--;
889 	    cnb_conn_evt();
890 
891 	    if (instream != NULL)   /* update readline display */
892 		rl_forced_update_display();
893 	}
894 
895 	if (fdata >= 0 && ret > 0 && fds[fdata_idx].revents & POLLIN)
896 	{
897 	    if (instream != NULL)
898 		clear_readline();
899 
900 	    ret--;
901 	    process_nb_event();
902 
903 	    clewn_keymap();	/* initialize keys mappings (only once) */
904 
905 	    if (instream != NULL)   /* update readline display */
906 		rl_forced_update_display();
907 	}
908 
909 #else /* HAVE_SELECT */
910 	maxfd = -1;
911 	FD_ZERO(&rfds);
912 
913 	if (fd >= 0)
914 	{
915 	    FD_SET(fd, &rfds);
916 	    if (maxfd < fd)
917 		maxfd = fd;
918 	}
919 
920 	if (GDB_STATE(gdb, GS_UP))
921 	{
922 	    FD_SET(gdb->fd, &rfds);
923 	    if (maxfd < gdb->fd)
924 		maxfd = gdb->fd;
925 	}
926 
927 	if ((fdcon = cnb_get_connsock()) >= 0)
928 	{
929 	    FD_SET(fdcon, &rfds);
930 	    if (maxfd < fdcon)
931 		maxfd = fdcon;
932 	}
933 
934 	if ((fdata = cnb_get_datasock()) >= 0)
935 	{
936 	    FD_SET(fdata, &rfds);
937 	    if (maxfd < fdata)
938 		maxfd = fdata;
939 	}
940 
941 	if (maxfd >= 0)
942 	    ret = select(maxfd + 1, &rfds, NULL, NULL, NULL);
943 
944 	if (GDB_STATE(gdb, GS_UP) && ret > 0 && FD_ISSET(gdb->fd, &rfds))
945 	{
946 	    ret--;
947 	    if (gdb->parse_output != NULL)
948 		(void)gdb->parse_output(gdb);
949 	}
950 
951 	if (fdcon >= 0 && ret > 0 && FD_ISSET(fdcon, &rfds))
952 	{
953 	    if (instream != NULL)
954 		clear_readline();
955 
956 	    ret--;
957 	    cnb_conn_evt();
958 
959 	    if (instream != NULL)   /* update readline display */
960 		rl_forced_update_display();
961 	}
962 
963 	if (fdata >= 0 && ret > 0 && FD_ISSET(fdata, &rfds))
964 	{
965 	    if (instream != NULL)
966 		clear_readline();
967 
968 	    ret--;
969 	    process_nb_event();
970 
971 	    clewn_keymap();	/* initialize keys mappings (only once) */
972 
973 	    if (instream != NULL)   /* update readline display */
974 		rl_forced_update_display();
975 	}
976 #endif
977     } while ((ret == 0 || (ret < 0 && errno == EINTR)) && IS_NETBEANS_CONNECTED);
978 
979     if (ret > 0)
980     {
981 	if (instream != NULL)
982 	    return rl_getc(instream);
983     }
984     else if (IS_NETBEANS_CONNECTED)
985 	perror("select() failed in cli_getc()");
986 
987     return EOF;
988 }
989 
990 /* Handle SIGINT signal */
991     static RETSIGTYPE
catch_sigint(sig)992 catch_sigint(sig)
993     int sig;
994 {
995     if (sig == SIGINT) {}   /* keep compiler happy */
996 
997     got_sigint = TRUE;
998     signal(SIGINT, catch_sigint);
999 }
1000 
1001 /* Handle SIGTERM signal */
1002     static RETSIGTYPE
catch_sigterm(sig)1003 catch_sigterm(sig)
1004     int sig;
1005 {
1006     if (sig == SIGTERM) {}   /* keep compiler happy */
1007 
1008     signal(SIGCHLD, SIG_IGN);
1009     signal(SIGPIPE, SIG_IGN);
1010     signal(SIGTERM, SIG_IGN);
1011 
1012     clewn_getout();             /* terminate GDB */
1013 }
1014 
1015 /* Handle SIGCHLD signal */
1016     static RETSIGTYPE
catch_sigchld(sig)1017 catch_sigchld(sig)
1018     int sig;
1019 {
1020     if (sig == SIGCHLD) {}   /* keep compiler happy */
1021 
1022     got_sigchld = TRUE;
1023     signal(SIGCHLD, catch_sigchld);
1024 }
1025 
1026 /* Handle SIGPIPE signal */
1027     static RETSIGTYPE
catch_sigpipe(sig)1028 catch_sigpipe(sig)
1029     int sig;
1030 {
1031     if (sig == SIGPIPE) {}   /* keep compiler happy */
1032 
1033     signal(SIGCHLD, SIG_IGN);
1034     signal(SIGPIPE, SIG_IGN);
1035     signal(SIGTERM, SIG_IGN);
1036 
1037     clear_readline();
1038     if (clewn_debug)
1039 	fprintf(stderr, "disconnected by peer in write()\n");
1040     clewn_getout();             /* terminate GDB */
1041 }
1042 
1043 /** Abort clewn */
1044     static void
clewn_abort()1045 clewn_abort()
1046 {
1047     /* we MUST NOT call any function that allocates memory */
1048     if (gdb != NULL)
1049 	gdb_close(gdb);		/* terminate GDB */
1050 
1051 #if defined(GDB_MTRACE) && defined(HAVE_MTRACE)
1052     muntrace();
1053 #endif
1054     exit(EXIT_FAILURE);
1055 }
1056 
1057 #define EXIT_TIMEOUT 10000
1058 /** Terminate clewn */
1059     static void
clewn_getout()1060 clewn_getout()
1061 {
1062     int wtime = EXIT_TIMEOUT;	/* msecs */
1063     int fdata = cnb_get_datasock();
1064     int rc;
1065 # ifndef HAVE_SELECT
1066     struct pollfd fds;
1067 # else
1068     struct timeval tv;
1069     struct timeval start_tv;
1070     fd_set rfds;
1071 
1072     signal(SIGINT, SIG_IGN);
1073     signal(SIGTERM, SIG_IGN);
1074     signal(SIGCHLD, SIG_IGN);
1075     signal(SIGPIPE, SIG_IGN);
1076 
1077     /* prevent recursion */
1078     if (gdb == NULL)
1079 	return;
1080 
1081     rl_cleanup_after_signal();  /* reset terminal so we can printf */
1082     cnb_saveAndExit();
1083 
1084 #  ifdef HAVE_GETTIMEOFDAY
1085 	gettimeofday(&start_tv, NULL);
1086 #  endif
1087 # endif
1088 
1089     /* Give vim a chance to close the netbeans socket before EXIT_TIMEOUT,
1090      * in conformance with the netbeans protocol  */
1091     while (fdata >=0 && wtime > 0) {
1092 # ifndef HAVE_SELECT
1093 	fds.fd = fdata;
1094 	fds.events = POLLIN;
1095 
1096 	rc = poll(&fds, 1, 200);
1097 # else
1098 	FD_ZERO(&rfds);
1099 	FD_SET(fdata, &rfds);
1100 
1101 	tv.tv_sec = 0;		/* do a select every 200 ms, to update the printf */
1102 	tv.tv_usec = 200000;
1103 
1104 	rc = select(fdata + 1, &rfds, NULL, NULL, &tv);
1105 # endif
1106 
1107 	if ((rc == -1 && errno == EINTR) || rc == 0) {
1108 	    /* compute remaining wait time */
1109 # if ! defined(HAVE_SELECT) || ! defined(HAVE_GETTIMEOFDAY)
1110 	    /* guess: interrupted halfway, gdb processing 10 msecs */
1111 	    wtime = wtime / 2 - 10L;
1112 # else
1113 	    gettimeofday(&tv, NULL);
1114 	    wtime -= (tv.tv_sec - start_tv.tv_sec) * 1000L
1115 			    + (tv.tv_usec - start_tv.tv_usec) / 1000L;
1116 	    start_tv.tv_sec = tv.tv_sec;
1117 	    start_tv.tv_usec = tv.tv_usec;
1118 # endif
1119 	}
1120 	else if (rc < 0)
1121 	    break;
1122 	else if (read(fdata, clewn_buf, MAX_BUFFSIZE) <= 0)
1123 	    break;
1124 	else
1125 	    wtime = EXIT_TIMEOUT;
1126 
1127 	printf("\rWaiting for gvim to close netbeans socket, exit in %02d s", wtime / 1000);
1128 	fflush(stdout);
1129     }
1130 
1131     printf("\r                                                         \n");
1132     if (wtime <= 0)
1133 	printf("Vim is still up and running\n");
1134 
1135     gdb_close(gdb);		/* terminate GDB */
1136     module_end();		/* release module resources */
1137     clear_gdb_T();
1138     FREE(gdb);
1139     cnb_close();		/* close NetBeans sockets */
1140 
1141 #if defined(GDB_MTRACE) && defined(HAVE_MTRACE)
1142     muntrace();
1143 #endif
1144     exit(EXIT_SUCCESS);
1145 }
1146 
1147 /** Send a cmd to gdb */
1148     void
gdb_docmd(gdb_inst,cmd)1149 gdb_docmd(gdb_inst, cmd)
1150     gdb_handle_T *gdb_inst;
1151     char  *cmd;	/* gdb cmd */
1152 {
1153     gdb_T *this = (gdb_T *)gdb_inst;
1154 
1155     if (this == NULL || ! GDB_STATE(this, GS_UP))
1156 	return;
1157 
1158     /* accept one cmd at a time, allow intr */
1159     if (cmd != NULL && *cmd != NUL && *(cmd + strlen(cmd) - 1) == KEY_INTERUPT)
1160 	this->oob.state |= OS_INTR;
1161     else if (this->oob.state & OS_CMD)
1162     {
1163 	if (cmd != NULL && *cmd != NUL)
1164 	    fprintf(stderr, "GDB busy: command discarded, please retry\n");
1165 	return;
1166     }
1167     else
1168 	this->oob.idx = -1;	/* needed when last oob was aborted with OS_QUITs */
1169     this->oob.state |= OS_CMD;
1170 
1171     /* reset both prompts */
1172     FREE(this->prompt);
1173     FREE(preprompt);
1174 
1175     /* call mode specific docmd */
1176     if (this->gdb_docmd != NULL)
1177 	this->gdb_docmd(this, cmd);
1178 }
1179 
1180 /** Set the cmd to be inserted at start of readline */
1181     void
gdb_setwinput(gdb_inst,cmd)1182 gdb_setwinput(gdb_inst, cmd)
1183     gdb_handle_T *gdb_inst;
1184     char *cmd;	/* cmd to insert */
1185 {
1186     gdb_T *this = (gdb_T *)gdb_inst;
1187 
1188     if (this == NULL)
1189 	return;
1190 
1191     if (cmd == NULL)
1192 	cmd = "";
1193 
1194     if (strchr(cmd, (int)NL) != NULL)	/* assert no NL in cmd */
1195 	return;
1196 
1197     xfree(this->winput_cmd);
1198     this->winput_cmd = clewn_strsave(cmd);
1199 }
1200 
1201 /** Return TRUE if we are opening the gdb input-line window */
1202     int
gdb_iswinput(gdb_inst)1203 gdb_iswinput(gdb_inst)
1204     gdb_handle_T *gdb_inst;
1205 {
1206     return (gdb_inst != NULL ? ((gdb_T *)gdb_inst)->winput_cmd != NULL : FALSE);
1207 }
1208 
1209 /* Start a gdb process */
1210     static void
start_gdb_process()1211 start_gdb_process()
1212 {
1213     if (module_init() != OK)
1214 	return;
1215 
1216     gdb->project_file = p_project;
1217     gdb->project_state = PROJ_INIT;
1218 
1219     exec_gdb();
1220 
1221     /* gdb instance count */
1222     ++gdb->instance;
1223 
1224     /* done later, after netbeans init, for the first gdb instance */
1225     if (gdb->instance != 1) {
1226 	/* the gdb instance number is used to define signs in vim
1227 	 * with a different name for each instance of gdb */
1228 	cnb_set_instance(gdb->instance);
1229 
1230 	/* empty the variables buffer */
1231 	cnb_create_varbuf(gdb->var_name);
1232 
1233 	/* free mode specific data within gdb_T */
1234 	if (gdb->clear_gdb_T != NULL)
1235 	    gdb->clear_gdb_T(gdb);
1236 
1237 	/* unlink all asm buffers */
1238 	cnb_unlink_asm();
1239     }
1240 }
1241 
1242 /*
1243  * Initialize this module: set inputrc file, define signs, compile regexp.
1244  * Return OK when succcess, FAIL otherwise.
1245  */
1246     static int
module_init()1247 module_init()
1248 {
1249     FILE *fd;
1250     char *fname = NULL;
1251     char *histsize;
1252     pattern_T *pat;
1253     int errcode;
1254     int len;
1255 #if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1256     char **p;
1257     FILE * stream;
1258 #endif
1259 
1260     if (module_state == -1)
1261     {
1262 	module_state = FAIL;		/* do it only once */
1263 
1264 	/* build gvim and gdb exec strings */
1265 	gdb_cat(&p_vim, p_vc);
1266 	gdb_cat(&p_vim, GVIM_DEFAULT_ARG);
1267 	if (p_project != NULL)
1268 	    gdb_cat(&p_vim, "-c \"let clewn_project=1\" ");
1269 	gdb_cat(&p_vim, p_va);
1270 
1271 	gdb_cat(&p_gdb, p_gc);
1272 	gdb_cat(&p_gdb, " ");
1273 	gdb_cat(&p_gdb, p_ga);
1274 
1275 	/* create a gdb_T instance */
1276 	gdb = (gdb_T *)xcalloc(sizeof(gdb_T));
1277 	gdb->version = PACKAGE_VERSION;
1278 
1279 	clear_gdb_T();
1280 
1281 	if (clewn_mktmpdir() != OK)	/* create the tmp directory */
1282 	    goto fin;
1283 
1284 	/* get clewn_dir */
1285 	if ((clewn_dir = getenv("CLEWNDIR")) == NULL)
1286 	    clewn_dir = getenv("HOME");
1287 
1288 	/* load readline history */
1289 	if (clewn_dir != NULL && *clewn_dir != NUL)
1290 	{
1291 	    gdb_cat(&fname, clewn_dir);
1292 	    gdb_cat(&fname, CLEWN_HISTORY_FILE);
1293 	    (void)read_history(fname);
1294 	    FREE(fname);
1295 	}
1296 
1297 	/* set history max size */
1298 	if ((histsize = getenv("HISTSIZE")) != NULL && (len = atoi(histsize)) > 0)
1299 	    stifle_history(len);
1300 	else
1301 	    stifle_history(HISTORY_DFLT_SIZE);
1302 
1303 #if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1304 	/* Set gdb readline inputrc file contents
1305 	 * We don't know yet if we are going to use GDB/MI, so we need to
1306 	 * setup inputrc just in case, even though it might never be used */
1307 	if ((stream = clewn_opentmpfile(INPUTRC_FNAME, &inputrc, 1)) != NULL)
1308 	{
1309 	    for (p = inputrc_array; *p; p++)
1310 		fputs(*p, stream);
1311 	    fclose(stream);
1312 	    setenv("INPUTRC", inputrc, TRUE);
1313 	}
1314 #endif
1315 
1316 	/* Compile patterns */
1317 	for (pat = patterns; pat->str != NULL; pat++)
1318 	{
1319 	    pat->regprog = (regex_t *)xcalloc(sizeof(regex_t));
1320 
1321 	    if ((errcode = regcomp(pat->regprog, pat->str, REG_EXTENDED)) != 0)
1322 	    {
1323 		print_regerror(errcode, pat->regprog);
1324 		regfree(pat->regprog);
1325 		FREE(pat->regprog);
1326 		goto fin;
1327 	    }
1328 	}
1329 
1330 	/* create variables file */
1331 	if (p_gvar != NULL && *p_gvar != NUL)
1332 	{
1333 	    if ((fd = clewn_opentmpfile(p_gvar, &(gdb->var_name), 1)) != NULL)
1334 		fclose(fd);
1335 	}
1336 
1337 	module_state = OK;
1338     }
1339 fin:
1340     return module_state;
1341 }
1342 
1343 /* Release module resources */
1344     static void
module_end()1345 module_end()
1346 {
1347     char *fname = NULL;
1348     pattern_T *pat;
1349     int i;
1350 
1351     module_state = -1;
1352 
1353     xfree(p_vim);
1354     xfree(p_gdb);
1355 
1356 # if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1357     if (inputrc != NULL)
1358 	FREE(inputrc);
1359 # endif
1360 
1361     clewn_deltempdir();	    /* remove temporary directory and its content */
1362 
1363     xfree(preprompt);
1364     xfree(cplt_prmpt);
1365     xfree(key_command);
1366 
1367     /* patterns an tokens */
1368     for (pat = patterns; pat->str != NULL; pat++)
1369     {
1370 	if (pat->regprog != NULL)
1371 	{
1372 	    regfree(pat->regprog);
1373 	    FREE(pat->regprog);
1374 	}
1375     }
1376 
1377     for (i = 0; i < CLEWN_KEYMAP_SIZE; i++)
1378 	xfree(keymap[i]);
1379 
1380     /* write readline history */
1381     if (clewn_dir != NULL && *clewn_dir != NUL)
1382     {
1383 	gdb_cat(&fname, clewn_dir);
1384 	gdb_cat(&fname, CLEWN_HISTORY_FILE);
1385 	(void)write_history(fname);
1386 	xfree(fname);
1387     }
1388 }
1389 
1390 /* Initialize a gdb_T structure */
1391     static void
clear_gdb_T()1392 clear_gdb_T()
1393 {
1394     if (gdb != NULL)
1395     {
1396 	gdb->instance = 0;
1397 	gdb->fd = -1;
1398 	gdb->pid = (pid_t)-1;
1399 #if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1400 	gdb->height = 0;
1401 #endif
1402 	gdb->state = GS_INIT;
1403 	FREE(gdb->status);
1404 	gdb->recurse = 0;
1405 
1406 	gdb->cmd_type = CMD_ANY;
1407 #if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1408 	gdb->cli_cmd.state = CS_START;
1409 	gdb->cli_cmd.cnt = 0;
1410 	FREE(gdb->cli_cmd.gdb);
1411 	FREE(gdb->cli_cmd.readline);
1412 	FREE(gdb->cli_cmd.echoed);
1413 #endif
1414 
1415 	FREE(gdb->firstcmd);	/* not used by clewn */
1416 	FREE(gdb->prompt);
1417 	FREE(gdb->pwd);
1418 	FREE(gdb->args);
1419 	FREE(gdb->winput_cmd);
1420 	FREE(gdb->directories);
1421 	FREE(gdb->sfile);
1422 
1423 #if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1424 	gdb->note = ANO_NONE;
1425 	gdb->annoted = FALSE;
1426 	gdb->newline = FALSE;
1427 	FREE(gdb->annotation);
1428 #endif
1429 	FREE(gdb->line);
1430 	FREE(gdb->pc);
1431 	FREE(gdb->frame_pc);
1432 	FREE(gdb->oob_result);
1433 	FREE(gdb->asm_add);
1434 	FREE(gdb->asm_func);
1435 
1436 #if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1437 	gdb->bp_state = 0;
1438 	gdb_free_bplist(&(gdb->tmplist));
1439 #endif
1440 	FREE(gdb->record);
1441 	gdb->cont = FALSE;
1442 	gdb_free_bplist(&(gdb->bpinfo));
1443 	gdb->frame_curlvl = -1;
1444 	gdb->frame_lnum = (linenr_T) -1;
1445 	FREE(gdb->frame_fname);
1446 
1447 	gdb->fr_buf = -1;
1448 	gdb->var_buf = -1;
1449 	FREE(gdb->var_name);
1450 	FREE(gdb->balloon_txt);
1451 
1452 	gdb->oob.state = 0;
1453 	gdb->oob.idx = -1;
1454 
1455 	gdb->pool.buf = -1;
1456 	FREE(gdb->pool.name);
1457 	gdb->pool.hilite = FALSE;
1458 
1459 	/* free mode specific data within gdb_T */
1460 	if (gdb->clear_gdb_T != NULL)
1461 	    gdb->clear_gdb_T(gdb);
1462 
1463 	gdb->oobfunc = NULL;
1464 	gdb->parse_output = NULL;
1465 	gdb->gdb_docmd = NULL;
1466 	gdb->var_delete = NULL;
1467 	gdb->clear_gdb_T = NULL;
1468     }
1469 }
1470 
1471 /* Spawn a gdb process */
1472     static void
exec_gdb()1473 exec_gdb()
1474 {
1475     char *err = NULL;
1476     int fd = -1;	/* slave pty file descriptor */
1477     char *tty;		/* pty name */
1478 # ifdef HAVE_TERMIOS_H
1479     struct termios tio;
1480 # else
1481     struct termio tio;
1482 # endif
1483 
1484     /* process already running */
1485     if (gdb->pid != (pid_t)-1 && waitpid(gdb->pid, NULL, WNOHANG) == 0)
1486 	return;
1487 
1488     /* Open pty */
1489     if ((gdb->fd = OpenPTY(&tty)) < 0
1490 	    || (fd = open(tty, O_RDWR|O_NOCTTY|O_EXTRA, 0)) < 0
1491 	    || SetupSlavePTY(fd) == -1)
1492     {
1493 	err = "Cannot open gdb pty\n";
1494 	goto err;
1495     }
1496 
1497     /* Set terminal attributes */
1498 # ifdef HAVE_TERMIOS_H
1499     if (tcgetattr(fd, &tio) == 0)
1500 # else
1501     if (ioctl(fd, TCGETA, &tio) >= 0)
1502 # endif
1503     {
1504 	tio.c_oflag &= ~ONLCR;		/* don't map NL to CR-NL on output */
1505 	tio.c_cc[VINTR] = KEY_INTERUPT;
1506 # ifdef HAVE_TERMIOS_H
1507 	if (tcsetattr(fd, TCSAFLUSH, &tio) != 0)
1508 # else
1509 	if (ioctl(fd, TCSETA, &tio) < 0)
1510 # endif
1511 	{
1512 	    err = "Cannot set gdb pty\n";
1513 	    goto err;
1514 	}
1515     }
1516     else
1517     {
1518 	err = "Cannot get gdb pty\n";
1519 	goto err;
1520     }
1521 
1522 # if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1523 #  if defined(TIOCGWINSZ) && defined(TIOCSWINSZ)
1524 	{
1525 	    struct winsize win;
1526 
1527 	    /* set tty height */
1528 	    if (ioctl(0, TIOCGWINSZ, &win) >= 0)
1529 	    {
1530 		/* Prevent use of a low height size because of "prompt-for-continue" messages.
1531 		 * The annotations lines printed by GDB are part of the lines count that
1532 		 * is used by GDB for "prompt-for-continue" messages, however we do not
1533 		 * display them. */
1534 		if (win.ws_row < MIN_SCREEN_HEIGHT)
1535 		{
1536 		    fprintf(stderr, "Please retry with a larger screen,\n");
1537 		    fprintf(stderr, "the screen height must be at least %d lines.\n", MIN_SCREEN_HEIGHT);
1538 		    fprintf(stderr, "On a console, try the unix command: \"stty rows 16\" for example.\n");
1539 		    goto err;
1540 		}
1541 
1542 		/* see the comment in gdb_parse_output_cli() about
1543 		 * the "--More--" prompt */
1544 		win.ws_row = LPP_LINES;
1545 		if (ioctl(fd, TIOCSWINSZ, &win) >= 0)
1546 		    gdb->height = win.ws_row;
1547 	    }
1548 	}
1549 #  endif
1550 # endif
1551 
1552     /* Fork */
1553     if ((gdb->pid = fork()) == (pid_t)-1)
1554     {
1555 	err = "Cannot fork gdb\n";
1556 	goto err;
1557     }
1558 /* The child */
1559     else if (gdb->pid == (pid_t)0)
1560     {
1561 	/* Grab control of terminal (from `The GNU C Library' (glibc-2.3.1)) */
1562 	setsid();
1563 # ifdef TIOCSCTTY
1564 	if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1)
1565 	    _exit(1);
1566 # else
1567 	{ int newfd;
1568 	char *fdname = ttyname(fd);
1569 
1570 	/* This might work (it does on Linux) */
1571 	if (fdname)
1572 	{
1573 	    if (fd != 0)
1574 		close (0);
1575 	    if (fd != 1)
1576 		close (1);
1577 	    if (fd != 2)
1578 		close (2);
1579 	    newfd = open(fdname, O_RDWR);
1580 	    close(newfd);
1581 	}
1582 	}
1583 # endif
1584 
1585 	close(0); dup(fd);
1586 	close(1); dup(fd);
1587 	close(2); dup(fd);
1588 
1589 	if (fd > 2)
1590 	    close(fd);
1591 
1592 	close(gdb->fd);	    /* close master pty */
1593 
1594 # ifdef GDB_MI_SUPPORT
1595 	if (p_gdbmi)
1596 	{
1597 	    /* MI mi2 is available starting with GDB 6.0 */
1598 	    execlp(p_gc, p_gc, "--interpreter=mi2", NULL);
1599 	    _exit(EXIT_FAILURE);
1600 	}
1601 # endif
1602 # if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1603 	clewn_exec(p_gdb);
1604 # endif /* defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT) */
1605 
1606 	_exit(EXIT_FAILURE);
1607     }
1608 /* The parent */
1609     else
1610     {
1611 	close(fd);
1612 
1613 # ifdef GDB_MI_SUPPORT
1614 	if (p_gdbmi)
1615 	{
1616 	    gdb->state |= GS_UP;
1617 	    if (gdb_setup_mi(gdb) != OK)
1618 	    {
1619 		gdb_cat(&err, "Cannot start GDB program \"");
1620 		gdb_cat(&err, p_gc);
1621 		gdb_cat(&err, "\" (MI)\n");
1622 		if (err != NULL)
1623 		{
1624 		    fprintf(stderr, err);
1625 		    xfree(err);
1626 		}
1627 		gdb->state = GS_INIT;
1628 	    }
1629 	}
1630 # else
1631 #  if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
1632 	fprintf(stderr, "guessing level, please wait...\r");
1633 
1634 	gdb->state |= GS_UP;
1635 	if (gdb_setup_cli(gdb) != OK)
1636 	    gdb->state = GS_INIT;
1637 
1638 #  endif
1639 # endif
1640 
1641 	return;
1642     }
1643 err:
1644     if (gdb->fd >= 0) {
1645 	close(gdb->fd);
1646 	gdb->fd = -1;
1647     }
1648     if (fd >= 0)
1649 	close(fd);
1650     if (err != NULL)
1651 	fprintf(stderr, err);
1652     return;
1653 }
1654 
1655 /* Spawn a gdb process; return OK when sucess, FAIL otherwise */
1656     static int
exec_gvim()1657 exec_gvim()
1658 {
1659     char dummy;
1660     int pipefd[2];	    /* pipe between parent and child */
1661     int pipe_error;
1662     pid_t pid;
1663 
1664     /* setup a pipe between the child and the parent, so that the parent
1665      * knows when the child has done the setsid() call and is allowed to exit */
1666     pipe_error = (pipe(pipefd) < 0);
1667 
1668     /* Fork */
1669     if ((pid = fork()) == (pid_t)-1)
1670     {
1671 	fprintf(stderr, "Cannot fork gvim\n");
1672 	return FAIL;
1673     }
1674     /* The child */
1675     else if (pid == (pid_t)0)
1676     {
1677 	setsid();
1678 
1679 	if (! pipe_error)
1680 	{
1681 	    close(pipefd[0]);
1682 	    close(pipefd[1]);
1683 	}
1684 
1685 	close(0);
1686 	close(1);
1687 	close(2);
1688 	cnb_close();	    /* close sockets */
1689 
1690 	clewn_exec(p_vim);
1691 
1692 	_exit(EXIT_FAILURE);
1693     }
1694     /* The parent */
1695     else
1696     {
1697 	if (! pipe_error)
1698 	{
1699 	    /* the read returns when the child closes the pipe (or when
1700 	     * the child dies for some reason) */
1701 	    close(pipefd[1]);
1702 	    (void)read(pipefd[0], &dummy, (size_t)1);
1703 	    close(pipefd[0]);
1704 	}
1705 
1706 	return OK;
1707     }
1708 }
1709 
1710 /* Initialize key mappings */
1711     static void
clewn_keymap()1712 clewn_keymap()
1713 {
1714     static int keymap_done  = 0;
1715     char *fname = NULL;
1716     int key;
1717     char ** line;
1718     char * ptr;
1719     char ** default_keymap;
1720 
1721     /* map the keys in vim - do it only once and when the data socket is opened */
1722     if (! keymap_done && cnb_state()) {
1723 	keymap_done = 1;
1724 
1725 	/* use the default table, depending on netbeans version */
1726 	if (cnb_specialKeys())
1727 	    default_keymap = keys_mapping;
1728 	else
1729 	    default_keymap = old_keys_mapping;
1730 
1731 	/* read the default keys mapping */
1732 	for (line = default_keymap; *line != NULL; line++)
1733 	{
1734 	    /* make a copy so that it's writeable */
1735 	    if ((ptr = clewn_strsave(*line)) != NULL)
1736 	    {
1737 		parse_keyline(ptr);
1738 		xfree(ptr);
1739 	    }
1740 	}
1741 
1742 	/* read the key mappings user configuration file*/
1743 	if (clewn_dir != NULL && *clewn_dir != NUL)
1744 	{
1745 	    gdb_cat(&fname, clewn_dir);
1746 	    gdb_cat(&fname, CLEWN_KEYS_FILE);
1747 	    read_keysfile(fname);
1748 	    xfree(fname);
1749 	}
1750 
1751 	/* if the netbeans version supports specialKeys */
1752 	if (cnb_specialKeys()) {
1753 	    /* control chars */
1754 	    for (key='A'; key<='_'; key++)
1755 		if (keymap[key - '@'] != NULL)
1756 		    cnb_keymap(KEYMAP_CONTROL, key);
1757 
1758 	    /* upper case chars */
1759 	    for (key='A'; key<='Z'; key++)
1760 		if (keymap[key] != NULL)
1761 		    cnb_keymap(KEYMAP_UPPERCASE, key);
1762 
1763 	    /* function keys */
1764 	    for (key=1; key<=FUNMAP_SIZE; key++)
1765 		if (keymap[FUNCTION_INDEX(key)] != NULL)
1766 		    cnb_keymap(KEYMAP_FUNCTION, key);
1767 	}
1768     }
1769 }
1770 
1771 /* Write project file */
1772     static void
write_project()1773 write_project()
1774 {
1775     char * res = NULL;
1776     int bp_count = 0;
1777     FILE *stream;
1778     bpinfo_T *p;
1779     char * source_file;
1780     int lnum;
1781 
1782     if (gdb->project_file == NULL)	/* no project file */
1783 	return;
1784 
1785     if (gdb->sfile == NULL) {		/* no debuggee */
1786 	fprintf(stderr, "Error: no target file, the project is not written to: %s\n", gdb->project_file);
1787 	goto end;
1788     }
1789 
1790     if ((stream = fopen(gdb->project_file, "w+")) != NULL) {
1791 	fputs("# Project file automatically generated by clewn.\n", stream);
1792 
1793 	if (gdb->pwd != NULL)		/* current working directory */
1794 	    fputs(gdb->pwd, stream);
1795 
1796 	gdb_cat(&res, "file ");
1797 	gdb_cat(&res, gdb->sfile);
1798 	gdb_cat(&res, "\n");
1799 	fputs(res, stream);		/* debuggee */
1800 	FREE(res);
1801 
1802 	if (gdb->args != NULL)		/* debuggee command line args */
1803 	    fputs(gdb->args, stream);
1804 
1805 	for (p = gdb->bpinfo; p != NULL; p = p->next) {
1806 	    if ((source_file=cnb_filename(p->buf)) != NULL) {
1807 		bp_count++;
1808 
1809 		/* get the new sign position in the vim buffer */
1810 		lnum = cnb_buf_getsign(p->buf, BP_SIGN_ID(p->id));
1811 		if (lnum == 0)
1812 		    lnum = (int)p->lnum;    /* use the original value */
1813 
1814 		gdb_cat(&res, "break ");
1815 		gdb_cat(&res, source_file);
1816 		gdb_cat(&res, ":");
1817 		gdb_cat(&res, gdb_itoa(lnum));
1818 		gdb_cat(&res, "\n");
1819 		fputs(res, stream);	/* breakpoint */
1820 		FREE(res);
1821 
1822 		/* handle disabled breakpoints */
1823 		if (! p->enabled) {
1824 		    gdb_cat(&res, "disable ");
1825 		    gdb_cat(&res, gdb_itoa(bp_count));
1826 		    gdb_cat(&res, "\n");
1827 		    fputs(res, stream);	/* disabled breakpoint */
1828 		    FREE(res);
1829 		}
1830 	    }
1831 	}
1832 
1833 	fclose(stream);
1834     }
1835     else
1836 	fprintf(stderr, "Error: cannot write project in %s\n", gdb->project_file);
1837 
1838 end:
1839     /* gdb_close may be called more than one time on exit,
1840      * on the second occurence, the breakpoint list has been freed,
1841      * prevent this to happen by setting the project_file to NULL */
1842     gdb->project_file = NULL;
1843 }
1844 
1845 #define CG_QUIT "quit\n"
1846 #define CG_YES  "yes\n"
1847 #define CG_POLL 100
1848 /* Close gdb process */
1849     void
gdb_close(this)1850 gdb_close(this)
1851     gdb_T *this;
1852 {
1853     bpinfo_T *p;
1854     pid_t pid;
1855     int rc;
1856 
1857     if (this->state & GS_CLOSING)	/* prevent recursive calls */
1858 	return;
1859     this->state |= GS_CLOSING;
1860 
1861     /* write the project file */
1862     write_project();
1863 
1864     /* remove all signs */
1865     gdb_fr_unlite(this);
1866     for (p = gdb->bpinfo; p != NULL; p = p->next)
1867 	cnb_buf_delsign(p->buf, BP_SIGN_ID(p->id));
1868 
1869     /* free breakpoints table */
1870     gdb_free_bplist(&(this->bpinfo));
1871 
1872     /*  a) attempt to gracefully terminate gdb process
1873      *  b) if this fails, SIGTERM it
1874      *  c) if this fails, too bad, just return */
1875     if (this->pid != (pid_t)-1)
1876     {
1877 	pid = waitpid(this->pid, NULL, WNOHANG);
1878 
1879 	if ((pid == (pid_t)-1 && errno == ECHILD) || pid == this->pid)
1880 	    ;	/* nop */
1881 	else	/* still running */
1882 	{
1883 	    char c     = KEY_INTERUPT;
1884 	    int killed = FALSE;
1885 	    int t;
1886 
1887 	    /* a) write an interrupt followed by a 'quit' cmd */
1888 	    write(this->fd, &c, 1);
1889 	    if (gdb_read(this, clewn_buf, MAX_BUFFSIZE, 1000) >= 0)
1890 	    {
1891 		write(this->fd, CG_QUIT, strlen(CG_QUIT));
1892 		while ((rc = gdb_read(this, clewn_buf, MAX_BUFFSIZE, 100)) > 0)
1893 		    ;
1894 
1895 		if (rc != -1)
1896 		    write(this->fd, CG_YES, strlen(CG_YES));
1897 	    }
1898 
1899 	    /* make sure gdb is terminated: poll for waitpid() */
1900 	    for (t = 0; !killed; t += CG_POLL)
1901 	    {
1902 		/* 1 second elapsed since start of polling for waitpid */
1903 		if (t >= 1000 )
1904 		{
1905 # ifdef SIGTERM
1906 		    /* b) kill it now */
1907 		    kill(this->pid, SIGTERM);
1908 # endif
1909 		    killed = TRUE;
1910 		}
1911 
1912 		clewn_sleep(CG_POLL);
1913 		pid = waitpid(this->pid, NULL, WNOHANG);
1914 		if ((pid == (pid_t)-1 && errno == ECHILD) || pid == this->pid)
1915 		    break;
1916 	    }
1917 	}
1918 	clear_readline();
1919 	fprintf(stderr, "GDB terminated\n");
1920     }
1921 
1922     if (this->fd >= 0) {
1923 	close(this->fd);
1924 	this->fd = -1;
1925     }
1926 
1927     /* keep the GS_QUITTING state of gdb; this state sets the difference
1928      * between a 'quit' command, and a 'restart' command */
1929     this->state = GS_INIT | (this->state & GS_QUITTING);
1930     this->pid = (pid_t)-1;
1931 }
1932 
1933 /* Highlite asm_add line; return TRUE when asm_add found in asm buffer */
1934     int
gdb_as_frset(this,obs)1935 gdb_as_frset(this, obs)
1936     gdb_T *this;
1937     struct obstack *obs;
1938 {
1939     int bufno;
1940     char *fname;
1941     linenr_T lnum;
1942 
1943     if (this->asm_func == NULL || this->asm_add == NULL)
1944 	return FALSE;
1945 
1946     /* Search all buffers whose name start with this->asm_func for ptrn */
1947     for (bufno = 1; ! cnb_outofbounds(bufno); bufno++)
1948     {
1949 	if ((fname = cnb_filename(bufno)) != NULL
1950 		&& strstr(fname, this->asm_func) != NULL
1951 		&& (lnum = searchfor(fname, this->asm_add)) > 0)
1952 	{
1953 	    this->pool.buf = bufno;
1954 	    this->pool.lnum = lnum;
1955 
1956 	    if (this->pool.hilite)
1957 		gdb_fr_set(this, NULL, NULL, obs);
1958 
1959 	    FREE(this->asm_add);
1960 	    return TRUE;
1961 	}
1962     }
1963     return FALSE;
1964 }
1965 
1966 /*
1967  * Highlight line within frame
1968  * Return -1 when failing to load the buffer, 0 otherwise
1969  */
1970     int
gdb_fr_set(this,file,line,obs)1971 gdb_fr_set(this, file, line, obs)
1972     gdb_T *this;
1973     char *file;
1974     linenr_T *line;
1975     struct obstack *obs;
1976 {
1977     int buf = -1;
1978     linenr_T lnum;
1979 
1980     /* Do not set frame hilite when this breakpoint has a 'commands'
1981      * with a 'continue' statement */
1982     if (this->cont)
1983     {
1984 	this->cont = FALSE;
1985 	return 0;
1986     }
1987 
1988     if (line == NULL)		/* in asm window */
1989     {
1990 	buf = this->pool.buf;
1991 	lnum = this->pool.lnum;
1992     }
1993     else			/* in source file */
1994 	lnum = *line;
1995 
1996     if (cnb_isvalid_buffer(buf) || file != NULL)
1997     {
1998 	if ((buf = gdb_edit_file(buf, file, lnum, 0, obs)) > 0)
1999 	    gdb_fr_lite(this, buf, lnum, obs);
2000 	else
2001 	    return -1;
2002     }
2003     return 0;
2004 }
2005 
2006 /* Highlite frame */
2007     void
gdb_fr_lite(this,buf,lnum,obs)2008 gdb_fr_lite(this, buf, lnum, obs)
2009     gdb_T *this;
2010     int buf;		/* buffer number where to highlite */
2011     linenr_T lnum;	/* line number */
2012     struct obstack *obs;
2013 {
2014     if (! cnb_isvalid_buffer(buf) || lnum <= 0)
2015 	return;
2016 
2017     /*
2018      * Remove previous frame sign:
2019      * GDB sends ANO_FRAME_INVALID annotations whenever stepping, running, etc...
2020      * and these annotations invoke gdb_fr_unlite() that turn off the previous frame sign.
2021      * But when moving along the stack frame with GDB 'up', 'down', 'frame' commands,
2022      * we don't get annotations and must turn off the previous frame sign.
2023      */
2024     if (this->fr_buf > 0)
2025 	gdb_unlite(FRAME_SIGN);
2026 
2027     this->fr_buf = buf;
2028     this->lnum = lnum;
2029 
2030     /* add new frame highlite */
2031     cnb_buf_addsign(buf, FRAME_SIGN, FRAME_SIGN, lnum, obs);
2032 }
2033 
2034 /* Unlite frame */
2035     void
gdb_fr_unlite(this)2036 gdb_fr_unlite(this)
2037     gdb_T *this;
2038 {
2039     if (! cnb_isvalid_buffer(this->fr_buf))
2040 	return;
2041 
2042     this->fr_buf = -1;
2043     this->lnum = 0;
2044     cnb_buf_delsign(0, FRAME_SIGN);
2045 }
2046 
2047 /* Print an error message */
2048     void
EMSG(m)2049 EMSG (m)
2050     char *m;
2051 {
2052     fputs(m, rl_outstream);
2053     fputs("\n", rl_outstream);
2054 }
2055 
2056 /*
2057  * Find the line number of the FRAME_SIGN in this buffer.
2058  * Return 0 as the line number when error.
2059  */
2060     linenr_T
find_fr_sign(buf)2061 find_fr_sign(buf)
2062     int buf;
2063 {
2064     if (gdb == NULL || ! cnb_isvalid_buffer(gdb->fr_buf) || buf != gdb->fr_buf)
2065 	return 0;
2066 
2067     return gdb->lnum;
2068 }
2069 
2070 /* Unlite a sign. */
2071     void
gdb_unlite(id)2072 gdb_unlite(id)
2073     int id;		/* sign id */
2074 {
2075     bpinfo_T *p;
2076 
2077     if (gdb == NULL || id <= 0)
2078 	return;
2079 
2080     if (id == FRAME_SIGN)
2081 	cnb_buf_delsign(0, id);
2082     else
2083     {
2084 	/* look for buf number in bp table */
2085 	for (p = gdb->bpinfo; p != NULL; p = p->next)
2086 	    if (BP_SIGN_ID(p->id) == id)
2087 	    {
2088 		cnb_buf_delsign(p->buf, id);
2089 		break;
2090 	    }
2091     }
2092     return;
2093 }
2094 
2095 /*
2096  * Define a breakpoint sign. There is one sign type per breakpoint
2097  * sign in order to have breakpoints numbers as the sign text.
2098  * Returns sign type number or -1 if error.
2099  */
2100     int
gdb_define_bpsign(bp,obs)2101 gdb_define_bpsign(bp, obs)
2102     bpinfo_T *bp;	/* the breakpoint */
2103     struct obstack *obs;
2104 {
2105     int typenr;
2106 
2107     if (bp == NULL)
2108 	return -1;
2109 
2110     /* do not define it twice, use the previous sequence number if any */
2111     if (bp->enabled && bp->typenr_en > 0)
2112 	return bp->typenr_en;
2113     else if (! bp->enabled && bp->typenr_dis > 0)
2114 	return bp->typenr_dis;
2115 
2116     if ((typenr = cnb_define_sign(bp->buf, bp->id,
2117 		    (bp->enabled ? SIGN_BP_ENABLED : SIGN_BP_DISABLED), obs)) > 0)
2118     {
2119 	if (bp->enabled)
2120 	    bp->typenr_en = typenr;
2121 	else
2122 	    bp->typenr_dis = typenr;
2123     }
2124 
2125     return typenr;
2126 }
2127 
2128 /* Append to or replace last line on rl_outstream */
2129     void
gdb_write_buf(this,chunk,add)2130 gdb_write_buf(this, chunk, add)
2131     gdb_T *this;
2132     char *chunk;	/* a chunk may contain one, many or no NL */
2133     int add;		/* TRUE when chunk is added */
2134 {
2135     if (chunk == NULL || this == NULL)
2136 	return;
2137 
2138     /* do not echo the prompt as it is already done by readline */
2139     if (this->note == ANO_PREPROMPT
2140 	    || this->note == ANO_PRECMDS
2141 	    || this->note == ANO_PREQUERY
2142 	    || this->note == ANO_PREOVERLOAD)
2143     {
2144 	/* stores the prompt in case it is a multi line prompt */
2145 	xfree(preprompt);
2146 	preprompt = clewn_strsave(chunk);
2147 	return;
2148     }
2149 
2150     /* hack to handle ANO_PRECMDS missing from GDB
2151      * avoid printing a superfluous ">" line after completion
2152      * in a "commands" or "define" */
2153     if (this->note == ANO_NONE
2154 	    && this->cli_cmd.state == CS_CHOICE
2155 	    && strcmp(chunk, ">") == 0)
2156 	return;
2157 
2158     /* do not echo user input as it is already done by readline */
2159     if (this->note == ANO_PROMPT
2160 	    || this->note == ANO_CMDS
2161 	    || this->note == ANO_QUERY
2162 	    || this->note == ANO_OVERLOAD)
2163 	return;
2164 
2165     if (add)
2166     {
2167 	if (nl_output)		/* newline already output by readline */
2168 	    nl_output = FALSE;
2169 	else
2170 	    fputs("\n", rl_outstream);
2171     }
2172     else
2173 	fputs("\r", rl_outstream);	/* overwrite last line */
2174 
2175     if (preprompt == NULL)
2176     {
2177 	/* write chunk */
2178 	fputs(chunk, rl_outstream);
2179     }
2180     else
2181     {
2182 	/* a multi line prompt: print the previous line from the multi
2183 	 * line prompt instead of this last prompt line
2184 	 * a multi line prompt occurs after GDB command 'run' when
2185 	 * debuggee is already started */
2186 	if (gdb->prompt == NULL)
2187 	{
2188 	    fputs(preprompt, rl_outstream);
2189 
2190 	    /* now store chunk as the previous line
2191 	     * from the multi line prompt */
2192 	    xfree(preprompt);
2193 	    preprompt = clewn_strsave(chunk);
2194 	}
2195 	else
2196 	{
2197 	    fputs(chunk, rl_outstream);
2198 	    FREE(preprompt);
2199 	}
2200     }
2201 }
2202 
2203 /*
2204  * Fill up buff with a NUL terminated string of max size - 1 bytes from gdb.
2205  * Return bytes read count, -1 if error or zero for nothing to read.
2206  */
2207     int
gdb_read(this,buff,size,wtime)2208 gdb_read(this, buff, size, wtime)
2209     gdb_T *this;
2210     char *buff;	/* where to write */
2211     int size;		/* buff size */
2212     int wtime;		/* msecs time out, -1 wait forever */
2213 {
2214     int len;
2215     int rc;
2216 # ifndef HAVE_SELECT
2217     struct pollfd fds;
2218 
2219     fds.fd = this->fd;
2220     fds.events = POLLIN;
2221 # else
2222     struct timeval tv;
2223     struct timeval start_tv;
2224     fd_set rfds;
2225 
2226     FD_ZERO(&rfds);
2227     FD_SET(this->fd, &rfds);
2228 
2229 #  ifdef HAVE_GETTIMEOFDAY
2230     if (wtime >= 0)
2231 	gettimeofday(&start_tv, NULL);
2232 #  endif
2233 # endif
2234 
2235     if (size <= 0 || buff == NULL || ! GDB_STATE(this, GS_UP))
2236 	return -1;
2237 
2238     /* make sure there is some data to read */
2239     while (1)
2240     {
2241 	if (this->state & GS_SIGCHLD)
2242 	    goto close;
2243 
2244 # ifndef HAVE_SELECT
2245 	if ((rc = poll(&fds, 1, wtime)) > 0)
2246 # else
2247 	if (wtime >= 0)
2248 	{
2249 	    tv.tv_sec = wtime / 1000;
2250 	    tv.tv_usec = (wtime % 1000) * (1000000/1000);
2251 	}
2252 
2253 	if ((rc = select(this->fd + 1, &rfds, NULL, NULL, (wtime >= 0) ? &tv : NULL)) > 0)
2254 # endif
2255 	    break;
2256 
2257 	if (rc == -1 && errno == EINTR)
2258 	{
2259 	    if (wtime >= 0)
2260 	    {
2261 		/* compute remaining wait time */
2262 # if ! defined(HAVE_SELECT) || ! defined(HAVE_GETTIMEOFDAY)
2263 		/* guess: interrupted halfway, gdb processing 10 msecs */
2264 		wtime = wtime / 2 - 10L;
2265 # else
2266 		gettimeofday(&tv, NULL);
2267 		wtime -= (tv.tv_sec - start_tv.tv_sec) * 1000L
2268 				+ (tv.tv_usec - start_tv.tv_usec) / 1000L;
2269 # endif
2270 		if (wtime < 0)
2271 		    return 0;
2272 	    }
2273 	}
2274 	else if (rc == 0)
2275 	    return 0;
2276 	else
2277 	    goto close;
2278     }
2279 
2280     /* read the data */
2281     if ((len = read(this->fd, (char *)buff, size - 1)) < 0)
2282 	goto close;
2283 
2284     buff[len] = NUL;
2285     return len;
2286 close:
2287     gdb_close(this);
2288     return -1;
2289 }
2290 
2291 /*
2292  * Edit a file.
2293  * Use buf number if positive, otherwise fname.
2294  * Return the buffer number or -1 when error.
2295  */
2296     int
gdb_edit_file(buf,fname,lnum,silent,obs)2297 gdb_edit_file(buf, fname, lnum, silent, obs)
2298     int buf;		/* asm buffer number to edit */
2299     char *fname;	/* file name */
2300     linenr_T lnum;	/* line number */
2301     int silent;
2302     struct obstack *obs;
2303 {
2304     if (gdb == NULL)
2305 	return -1;
2306 
2307     if (! cnb_isvalid_buffer(buf) && (fname == NULL || *fname == NUL))
2308 	return -1;
2309 
2310     if (cnb_isvalid_buffer(buf) && (fname = cnb_filename(buf)) == NULL)
2311 	return -1;
2312 
2313 #ifdef GDB_LVL3_SUPPORT
2314     return cnb_editFile(fname, lnum, gdb->directories, gdb->lvl3.source_cur,
2315 					    gdb->lvl3.source_list, silent, obs);
2316 #else
2317     return cnb_editFile(fname, lnum, gdb->directories, NULL, NULL, silent, obs);
2318 #endif
2319 }
2320 
2321 /* Do the OOB_COMPLETE part of an oob cmd and send the next one */
2322     void
gdb_oob_send(this,obs)2323 gdb_oob_send(this, obs)
2324     gdb_T *this;
2325     struct obstack *obs;
2326 {
2327     int keep    = FALSE;    /* when TRUE, do not switch to next oob function */
2328     char *res   = NULL;
2329     int *pi     = &(this->oob.idx);
2330     int s_a     = (this->state & GS_ALLOWED);
2331 
2332     /* prevent recursive calls to parse_output() since breakpoint
2333      * or frame highlighting may cause Vim to query the user when
2334      * changes have been made in the previous buffer */
2335     this->state &= ~GS_ALLOWED;
2336 
2337     if (this->oobfunc == NULL)
2338 	return;
2339 
2340     if (*pi == -1)
2341     {
2342 	this->oob.state &= ~OS_INTR;
2343 	if (this->oob.state & OS_QUIT)
2344 	    goto quit;
2345     }
2346 
2347     if (*pi >= 0 && (this->oobfunc)[*pi].oob != NULL) /* assert != NULL */
2348     {
2349 	if ((this->oobfunc)[*pi].oob(this, OOB_COMPLETE, NULL, obs) != NULL)
2350 	    keep = TRUE;
2351 
2352 	if (this->oob.state & OS_QUIT)
2353 	    goto quit;
2354     }
2355 
2356     if (! keep)
2357 	++(*pi);
2358 
2359     while ((this->oobfunc)[*pi].oob != NULL && !(this->oob.state & OS_INTR))
2360     {
2361 	if ((res = (this->oobfunc)[*pi].oob(this, OOB_CMD, NULL, obs)) != NULL)
2362 	{
2363 	    this->oob.cnt = 0;
2364 
2365 	    /* send the command to GDB */
2366 	    write(this->fd, (char *)res, strlen(res));
2367 
2368 	    this->state &= ~GS_ALLOWED;
2369 	    if (s_a)
2370 		this->state |= GS_ALLOWED;
2371 	    return;
2372 	}
2373 
2374 	++(*pi);
2375     }
2376 
2377     *pi = -1;
2378 quit:
2379     this->oob.state &= ~OS_CMD;
2380     this->oob.state &= ~OS_QUIT;
2381 
2382     this->state &= ~GS_ALLOWED;
2383     if (s_a)
2384 	this->state |= GS_ALLOWED;
2385 }
2386 
2387 /* Receive out of band response to idx cmd */
2388     void
gdb_oob_receive(this,chunk,obs)2389 gdb_oob_receive(this, chunk, obs)
2390     gdb_T *this;
2391     char *chunk;	/* response (possibly incomplete) */
2392     struct obstack *obs;
2393 {
2394     char *res = NULL;
2395     int s_a = (this->state & GS_ALLOWED);
2396 
2397     /* prevent recursive calls to parse_output() since breakpoint
2398      * or frame highlighting may cause Vim to query the user when
2399      * changes have been made in the previous buffer */
2400     this->state &= ~GS_ALLOWED;
2401 
2402     if (this->oobfunc == NULL)
2403 	return;
2404 
2405     if(IS_OOBACTIVE(this))
2406     {
2407 	/* silently discard when interrupted */
2408 	if (!(this->oob.state & OS_INTR) && chunk != NULL)
2409 	{
2410 	    if (this->parser != PS_PREPROMPT && this->parser != PS_PROMPT
2411 		&& (this->oobfunc)[this->oob.idx].oob != NULL) /* assert != NULL */
2412 	    {
2413 		this->oob.cnt++;
2414 		(void)(this->oobfunc)[this->oob.idx].oob(this, OOB_COLLECT, chunk, obs);
2415 
2416 		this->state &= ~GS_ALLOWED;
2417 		if (s_a)
2418 		    this->state |= GS_ALLOWED;
2419 		return;
2420 	    }
2421 	}
2422 
2423 	/* keep the last prompt */
2424 	if (this->parser == PS_PREPROMPT)
2425 	{
2426 	    gdb_cat(&res, this->line);
2427 	    gdb_cat(&res, chunk);
2428 	    xfree(this->line);
2429 	    this->line = res;
2430 	}
2431     }
2432 
2433     this->state &= ~GS_ALLOWED;
2434     if (s_a)
2435 	this->state |= GS_ALLOWED;
2436 }
2437 
2438 /*
2439  * Remove in the bpinfo list the records corresponding to the signs in bufno,
2440  * the signs themselves are removed by Vim in free_buffer()
2441  */
2442     void
gdb_free_records(bufno)2443 gdb_free_records(bufno)
2444     int bufno;
2445 {
2446     bpinfo_T *p, **pt;
2447 
2448     if (gdb == NULL)
2449 	return;
2450 
2451     for (pt = &(gdb->bpinfo); *pt != NULL; )
2452     {
2453 	p = *pt;
2454 	if (p->buf == bufno)
2455 	{
2456 	    *pt = p->next;	/* unlink record */
2457 	    xfree(p);
2458 	}
2459 	else
2460 	    pt = &(p->next);
2461     }
2462 }
2463 
2464 /* Free a bpinfo_T list and set address referenced by plist to NULL */
2465     void
gdb_free_bplist(plist)2466 gdb_free_bplist (plist)
2467     bpinfo_T ** plist;
2468 {
2469     bpinfo_T *p, *next;
2470 
2471     if (plist == NULL)
2472 	return;
2473 
2474     for (p = *plist; p != NULL; p = next)
2475     {
2476 	next = p->next;
2477 	xfree(p);
2478     }
2479 
2480     *plist = NULL;
2481 }
2482 
2483 /* Get the GDB command type */
2484     void
gdb_cmd_type(this,cmd)2485 gdb_cmd_type(this, cmd)
2486     gdb_T *this;
2487     char *cmd;
2488 {
2489     token_T *tok;
2490     char *ptr;
2491     char *last;
2492     char *tail;
2493 
2494     this->cmd_type = CMD_ANY;
2495 
2496     if (cmd == NULL)
2497 	return;
2498 
2499     while (isspace(*cmd))
2500 	cmd++;
2501 
2502     if (*cmd == NUL)
2503 	return;
2504 
2505     /* find the token 'keyword:tail' that matches cmd */
2506     for (tok = tokens; tok->keyword != NULL; tok++)
2507     {
2508 	if (strstr(cmd, tok->keyword) == cmd)
2509 	{
2510 	    last = ptr = cmd + strlen(tok->keyword);
2511 
2512 	    /* get first space after token */
2513 	    while (*last && ! isspace(*last))
2514 		last++;
2515 
2516 	    /* get a copy of last part */
2517 	    if (last != ptr)
2518 	    {
2519 		tail = clewn_strnsave(ptr, last - ptr);
2520 
2521 		if (strstr(tok->tail, tail) != tok->tail)
2522 		{
2523 		    xfree(tail);
2524 		    continue;	/* tail do not match */
2525 		}
2526 		xfree(tail);
2527 	    }
2528 
2529 	    /* match */
2530 	    this->cmd_type = tok->type;
2531 	    break;
2532 	}
2533     }
2534 }
2535 
2536 /* Create a private temporary directory */
2537     static int
clewn_mktmpdir()2538 clewn_mktmpdir()
2539 {
2540     char *(tempdirs[]) = {TEMPDIRNAMES};
2541     char itmp[TEMPNAMELEN];
2542     char *tmpdir;
2543     char *buf;
2544     mode_t umask_save;
2545     DIR *dir;
2546     int ret;
2547     unsigned i;
2548     long nr;
2549     long off;
2550 
2551     if (clewn_tempdir == NULL)
2552     {
2553 	/* try the entries in TEMPDIRNAMES to create the temp directory */
2554 	for (i = 0; i < sizeof(tempdirs) / sizeof(char *); i++)
2555 	{
2556 	    if ((*(tempdirs[i]) == '$' && (tmpdir = getenv(tempdirs[i] + 1)) != NULL)
2557 		    || (*(tempdirs[i]) != '$' && (tmpdir = tempdirs[i])))
2558 	    {
2559 		/* leave room for "/c1dddddd" and check directory exists*/
2560 		if (strlen(tmpdir) < TEMPNAMELEN - 10
2561 			&& (dir = opendir(tmpdir)) != NULL)
2562 		{
2563 		    closedir(dir);
2564 		    nr = (long)getpid() % 1000000L;
2565 
2566 		    /* try up to 10000 different values */
2567 		    for (off = nr; off < nr + 10000L; off++)
2568 		    {
2569 			sprintf(itmp, "%s/c%ld", tmpdir, off);
2570 
2571 			umask_save = umask(077);
2572 			ret = mkdir(itmp, 0700);
2573 			(void)umask(umask_save);
2574 
2575 			if (ret == 0)
2576 			{
2577 			    /* expand to full path */
2578 			    buf = (char *)xmalloc(MAXPATHL + 1);
2579 
2580 			    if (! clewn_fullpath(itmp, buf, MAXPATHL, FALSE))
2581 				strcpy(buf, itmp);
2582 
2583 			    if (*buf != NUL && *(buf + strlen(buf) - 1) != '/')
2584 				strcat(buf, "/");
2585 
2586 			    clewn_tempdir = clewn_strsave(buf);
2587 			    xfree(buf);
2588 
2589 			    return clewn_tempdir != NULL ? OK : FAIL;
2590 			}
2591 			else if (errno != EEXIST)
2592 			    break; /* probably can't create any dir here, try another place */
2593 		    }
2594 		}
2595 	    }
2596 	}
2597     }
2598     else
2599 	return OK;
2600 
2601     return FAIL;
2602 }
2603 
2604 /*
2605  * Create and open a file in the temporary directory whose name
2606  * is prefixed by 'filename'. The new name is 'filename{nb}' where
2607  * 'nb' are digits appended to 'filename' so that it's a new file.
2608  * When 'fullpath' is not NULL and operation was successful, the
2609  * address pointed to by 'fullpath' is set to an allocated full
2610  * pathname of this file.
2611  * Return a pointer to the stream, NULL when failed.
2612  */
2613     FILE *
clewn_opentmpfile(filename,fullpath,instance)2614 clewn_opentmpfile(filename, fullpath, instance)
2615     char *filename;
2616     char **fullpath;
2617     int instance;
2618 {
2619     FILE *stream = NULL;
2620     char *res    = NULL;
2621     int i        = instance;
2622     struct stat st;
2623     char *buf;
2624 
2625     if (clewn_tempdir != NULL && filename != NULL && *filename != NUL)
2626     {
2627 	/* find a non existing file name in this directory */
2628 	do
2629 	{
2630 	    buf = gdb_itoa(i);
2631 	    if (i == 1)
2632 		*buf = NUL;
2633 	    i++;
2634 
2635 	    FREE(res);
2636 	    gdb_cat(&res, clewn_tempdir);
2637 	    gdb_cat(&res, buf);
2638 	    gdb_cat(&res, filename);
2639 	} while (stat((char *)res, &st) == 0);
2640 
2641 	/* open the file */
2642 	if ((stream = fopen(res, "w+")) != NULL && fullpath != NULL)
2643 	    *fullpath = res;
2644 	else
2645 	    xfree(res);
2646     }
2647     return stream;
2648 }
2649 
2650 /* Remove Clewn temporary directory and its content */
2651     static void
clewn_deltempdir()2652 clewn_deltempdir()
2653 {
2654     char itmp[TEMPNAMELEN];
2655     DIR *dp;
2656     struct dirent *ep;
2657 
2658     if (clewn_tempdir != NULL)
2659     {
2660 	if ((dp = opendir(clewn_tempdir)) != NULL)
2661 	{
2662 	    while ((ep = readdir(dp)) != NULL)
2663 	    {
2664 		sprintf(itmp, "%s%s", clewn_tempdir, ep->d_name);
2665 		(void)unlink(itmp);
2666 	    }
2667 
2668 	    (void)closedir(dp);
2669 	    (void)rmdir(clewn_tempdir);
2670 	}
2671 
2672 	FREE(clewn_tempdir);
2673     }
2674 }
2675 
2676 /*
2677  * Append src to string pointed to by pdest or copy src to a new allocated
2678  * string when *pdest is NULL.
2679  * *pdest is reallocated to make room for src.
2680  * Append an empty string when src is NULL.
2681  */
2682     void
gdb_cat(pdest,src)2683 gdb_cat(pdest, src)
2684     char **pdest;	/* string address to append to */
2685     char *src;		/* string to append */
2686 {
2687     int ldest = (*pdest != NULL ? strlen(*pdest) : 0);
2688     int lsrc  = (src != NULL ? strlen(src) : 0);
2689     char *res;
2690 
2691     if (lsrc != 0 || *pdest == NULL)
2692     {
2693 	res = (char *)xmalloc(ldest + lsrc + 1);
2694 
2695 	if (ldest == 0)
2696 	{
2697 	    if (lsrc != 0)
2698 		strcpy(res, src);
2699 	    else
2700 		strcpy(res, "");
2701 	}
2702 	else
2703 	{
2704 	    strcpy(res, *pdest);
2705 	    strcat(res, src);	/* assert src != NULL */
2706 	}
2707 
2708 	xfree(*pdest);
2709 	*pdest = res;
2710     }
2711 }
2712 
2713 /* Print the regexp error message string to stderr. */
2714     static void
print_regerror(errcode,compiled)2715 print_regerror(errcode, compiled)
2716     int errcode;
2717     regex_t *compiled;
2718 {
2719     size_t length = regerror(errcode, compiled, NULL, 0);
2720     char *buffer;
2721 
2722     buffer = (char *)xmalloc(length);
2723     (void)regerror(errcode, compiled, buffer, length);
2724     fprintf(stderr, buffer);
2725     xfree(buffer);
2726 }
2727 
2728 /*
2729  * Return an allocated string that is the sub-match indexed by subid ([0-9])
2730  * using compiled pattern id. The string is allocated in an obstack when
2731  * obs is not NULL.
2732  * Return NULL if str does not match (or no such sub-match in pattern).
2733  */
2734     char *
gdb_regexec(str,id,subid,obs)2735 gdb_regexec(str, id, subid, obs)
2736     char *str;		    /* string to match against */
2737     int id;		    /* pattern id */
2738     int subid;		    /* sub-match index */
2739     struct obstack *obs;    /* obstack to use for allocating memory */
2740 {
2741     regmatch_t match[10];
2742     pattern_T *pat;
2743 
2744     if (str == NULL || *str == NUL || subid < 0 || subid > 9)
2745 	return NULL;
2746 
2747     for (pat = patterns; pat->str != NULL; pat++)
2748     {
2749 	if (pat->id == id)
2750 	{
2751 	    if (pat->regprog != NULL && regexec(pat->regprog, str, 10, match, 0) == 0
2752 		    && match[subid].rm_eo != -1
2753 		    && match[subid].rm_so != -1)
2754 	    {
2755 		if (obs != NULL)
2756 		    return (char *)obstack_copy0(obs, str + match[subid].rm_so,
2757 			    (int)(match[subid].rm_eo - match[subid].rm_so));
2758 		else
2759 		    return clewn_strnsave(str + match[subid].rm_so,
2760 			    (int)(match[subid].rm_eo - match[subid].rm_so));
2761 	    }
2762 	    break;
2763 	}
2764     }
2765     return NULL;
2766 }
2767 
2768 /* Return an integer as a string */
2769     char *
gdb_itoa(i)2770 gdb_itoa(i)
2771     int i;		/* integer to stringify */
2772 {
2773     static char buf[NUMBUFLEN];
2774 
2775     sprintf(buf, "%ld", (long)i);
2776     return buf;
2777 }
2778 
2779     char *
clewn_stripwhite(string)2780 clewn_stripwhite(string)
2781     char *string;
2782 {
2783     char *s;
2784     char *t;
2785 
2786     for (s = string; isspace(*s); s++)
2787 	;
2788 
2789     if (*s == NUL)
2790 	return s;
2791 
2792     t = s + strlen(s) - 1;
2793     while (t > s && isspace(*t))
2794 	t--;
2795     *++t = NUL;
2796 
2797     return s;
2798 }
2799 
2800 /* Clear realine and set cursor at line start */
2801     static void
clear_readline()2802 clear_readline()
2803 {
2804     int len = 0;
2805 
2806     if (gdb->prompt != NULL)	    /* find out how many spaces are needed */
2807 	len = strlen(gdb->prompt);
2808     if (rl_line_buffer != NULL)
2809 	len += strlen(rl_line_buffer);
2810 
2811     len = (len < MAX_BUFFSIZE ? len: MAX_BUFFSIZE -1);
2812     memset((void *)clewn_buf, (int)' ', (size_t)len);
2813     clewn_buf[len] = NUL;
2814 
2815     fprintf(rl_outstream, "\r%s\r", clewn_buf);    /* clear the line */
2816     fflush(rl_outstream);
2817 }
2818 
2819 /* Add line to readline history after having stripped whites and
2820  * removed a previous identical entry in the history */
2821     static void
clewn_add_history(line)2822 clewn_add_history(line)
2823     char *line;
2824 {
2825     HIST_ENTRY * entry;
2826     char *str;
2827     int offset;
2828 
2829     /* make a copy */
2830     str = clewn_strsave(line);
2831 
2832     line = clewn_stripwhite(str);
2833     if (*line == NUL)
2834     {
2835 	xfree(str);
2836 	return;
2837     }
2838 
2839     for (offset = 0; offset + history_base < history_length
2840 	    && (offset = history_search_pos(line, 1, offset)) >= 0; )
2841     {
2842 	if((entry = history_get(offset + history_base)) != NULL
2843 		&& entry->line != NULL
2844 		&& strcmp(line, entry->line) == 0
2845 		&& (entry = remove_history(offset)) != NULL)
2846 	{
2847 	    if (entry->line != NULL)
2848 		free(entry->line);
2849 	    free(entry);
2850 	}
2851 	else
2852 	    offset++;
2853     }
2854 
2855     add_history(line);
2856     xfree(str);
2857 }
2858 
2859 /*
2860  * Parse a line of key mapping
2861  * Key definitions are of the form `KEY:GDB COMMAND:{%line|%text}'
2862  * where:
2863  *   %text: the text below the mouse is added to the GDB command
2864  *   %line: 'fname:lnum' are added to the GDB command, where fname is the
2865  *          current buffer full pathname, and lnum the line number at
2866  *          cursor position
2867  *
2868  * All characters following `#' up to the next new line are ignored.
2869  * Leading blanks on each line are ignored. Empty lines are ignored.
2870  *
2871  * Supported key names:
2872  *  key functions: F1 to F20, example: `F11:continue'
2873  *  all ASCII printable characters except '#'
2874  *  control characters written as C-...
2875  */
2876     static void
parse_keyline(line)2877 parse_keyline(line)
2878     char * line;
2879 {
2880     char *end;
2881     int key;
2882     int fnum;
2883 
2884     while (isspace(*line))			/* skip blanks */
2885 	line++;
2886 
2887     key = *line++;
2888     if (key > 0 && key < 256 && isalnum(key))
2889     {
2890 	if (key == '#')				/* a comment */
2891 	    return;
2892 
2893 	else if (key == 'F' && *line != ':')	/* a function key */
2894 	{
2895 	    fnum = (int)strtol((char *)line, &end, 10);
2896 
2897 	    /* advance ptr to next separator */
2898 	    if (*end != ':')
2899 		return;
2900 	    line = end;
2901 
2902 	    /* set key to fnum function key index in table */
2903 	    if ((key = FUNCTION_INDEX(fnum)) == -1)
2904 		return;
2905 	}
2906 
2907 	else if (key == 'C' && *line == '-') {	/* a control character */
2908 	    line++;
2909 	    key = *line++;
2910 	    if (key < 'A' || key > '_')
2911 		return;
2912 	    key = key - '@';
2913 	}
2914 
2915 	/* parse GDB command, it must be surrounded by ':' and not empty */
2916 	if (*line++ != ':')
2917 	    return;
2918 	/* remove a key mapping when the GDB command is empty */
2919 	else if (*line == ':') {
2920 	    FREE(keymap[key]);
2921 	    return;
2922 	}
2923 	else if ((end = strchr(line, ':')) == NULL)
2924 	    return;
2925 
2926 	*end++ = NUL;		    /* terminate command string */
2927 
2928 	/* set GDB command in table */
2929 	xfree(keymap[key]);
2930 	keymap[key] = clewn_strsave(line);
2931 
2932 	/* parse %line or %text */
2933 	if (strstr(end, "%line") == end)
2934 	    SET_KEY_LINE(keyline, key);
2935 	else if (strstr(end, "%text") == end)
2936 	    SET_KEY_LINE(keytext, key);
2937     }
2938 }
2939 
2940 /*
2941  * Read the key mappings file and build the keymap array and
2942  * bit map flags.
2943  */
2944     static void
read_keysfile(fname)2945 read_keysfile(fname)
2946     char *fname;
2947 {
2948     FILE *fd;
2949     char *ptr;
2950 
2951     if ((fd = fopen(fname, "r")) == NULL)
2952 	return;
2953 
2954     /* read the key mappings file */
2955     while ((ptr = fgets(clewn_buf, MAX_BUFFSIZE, fd)) != NULL)
2956 	parse_keyline(ptr);
2957 
2958     fclose(fd);
2959 }
2960 
2961 /* Process a netbeans event */
2962     static void
process_nb_event()2963 process_nb_event()
2964 {
2965     nb_event_T * event;
2966 
2967     if ((event = cnb_data_evt()) != NULL)
2968     {
2969 	/* process a keyAtPos event */
2970 	if (event->key != NULL) {
2971 	    xfree(key_command);
2972 	    key_command = get_keymap(event);
2973 	}
2974 
2975 	/* process a balloonText event */
2976 	else if (event->text_event && gdb != NULL && ! IS_OOBACTIVE(gdb)) {
2977 
2978 	    xfree(gdb->balloon_txt);
2979 	    if ((gdb->balloon_txt = clewn_strsave(event->text)) != NULL) {
2980 
2981 		/* need a static array since gdb->oobfunc is referenced later
2982 		 * by gdb_oob_receive */
2983 		static oobfunc_T print_value_oobfunc[] = {
2984 		    {gdb_print_value},
2985 		    {NULL}
2986 		};
2987 		struct obstack obs;
2988 
2989 		(void)obstack_init(&obs);
2990 
2991 		/* the standard oobfunc table will be reset
2992 		 * after the prompt processing in process_annotation() */
2993 		gdb->oobfunc = print_value_oobfunc;
2994 		gdb_oob_send(gdb, &obs);
2995 
2996 		obstack_free(&obs, NULL);
2997 	    }
2998 	}
2999 
3000 	event->text_event = FALSE;	/* maybe lost when IS_OOBACTIVE */
3001     }
3002 }
3003 
3004 /*
3005  * Use keyinfo to build the corresponding GDB command that is
3006  * found in keymap[].
3007  * If this key is flagged as `%line': build `command pathname:lnum'
3008  * If this key is flagged as `%text': build `command text`
3009  * Return an allocated GDB command.
3010  */
3011     static char *
get_keymap(keyinfo)3012 get_keymap(keyinfo)
3013     nb_event_T *keyinfo;
3014 {
3015     char *res = NULL;
3016     char *ptr;
3017     char *end;
3018     int fnum;
3019     int key;
3020 
3021     if (keyinfo == NULL || (ptr = keyinfo->key) == NULL || *ptr == NUL)
3022 	return NULL;
3023 
3024     key = *ptr++;
3025 
3026     if (key == 'F' && *ptr != NUL)	/* a function key */
3027     {
3028 	fnum = (int)strtol((char *)ptr, &end, 10);
3029 
3030 	if (*end != NUL)
3031 	    return NULL;
3032 
3033 	/* set key to fnum function key index in table */
3034 	if ((key = FUNCTION_INDEX(fnum)) == -1)
3035 	    return NULL;
3036     }
3037 
3038     else if (key == 'S' && *ptr == '-') {/* an uppercase key */
3039 	key = *++ptr;
3040 	if (key < 'A' || key > 'Z')
3041 	    return NULL;
3042     }
3043 
3044     else if (key == 'C' && *ptr == '-') {/* a control character */
3045 	key = *++ptr;
3046 	if (key < 'A' || key > '_')
3047 	    return NULL;
3048 	key = key - '@';
3049     }
3050 
3051     else if (*ptr != NUL)		/* only one character keys */
3052 	return NULL;
3053 
3054     if (keymap[key] == NULL)		/* key is not mapped */
3055 	return NULL;
3056 
3057     /* build `command pathname:lnum'*/
3058     if (IS_KEY_FLAG(keyline, key))
3059     {
3060 	gdb_cat(&res, keymap[key]);
3061 	gdb_cat(&res, " \"");
3062 	gdb_cat(&res, keyinfo->pathname);
3063 	gdb_cat(&res, ":");
3064 	gdb_cat(&res, keyinfo->lnum);
3065 	gdb_cat(&res, "\"");
3066 	return res;
3067     }
3068     /* build `command text'*/
3069     else if (IS_KEY_FLAG(keytext, key))
3070     {
3071 	if (keyinfo->text != NULL)
3072 	{
3073 	    gdb_cat(&res, keymap[key]);
3074 	    gdb_cat(&res, " ");
3075 	    gdb_cat(&res, keyinfo->text);
3076 	    return res;
3077 	}
3078     }
3079     else
3080 	return clewn_strsave(keymap[key]);
3081 
3082     return NULL;
3083 }
3084 
3085 /*
3086  * Search for a line in file fname that matches regexp PAT_ADD
3087  * and contains needle. Abort when addresses are greater than needle.
3088  * Return the line number or -1 when error.
3089  */
3090     linenr_T
searchfor(fname,needle)3091 searchfor(fname, needle)
3092     char *fname;
3093     char *needle;
3094 {
3095     struct obstack obs;	    /* use an obstack for speed */
3096     char *add;
3097     FILE *fd;
3098     linenr_T lnum;
3099     int compare;
3100 
3101 
3102     if (needle != NULL && fname != NULL && (fd = fopen(fname, "r")) != NULL)
3103     {
3104 	lnum = 0;
3105 	(void)obstack_init(&obs);
3106 
3107 	while (fgets(clewn_buf, MAX_BUFFSIZE, fd) != NULL)
3108 	{
3109 	    lnum++;
3110 	    if ((add = gdb_regexec(clewn_buf, PAT_ADD, 1, &obs)) != NULL)
3111 	    {
3112 		if ((compare = strcmp(add, needle)) == 0)
3113 		{
3114 		    obstack_free(&obs, NULL);
3115 		    fclose(fd);
3116 		    return lnum;
3117 		}
3118 		else if (compare > 0)	/* addresses are greater, abort */
3119 		{
3120 		    obstack_free(&obs, NULL);
3121 		    fclose(fd);
3122 		    return -1;
3123 		}
3124 	    }
3125 	}
3126 	obstack_free(&obs, NULL);
3127 	fclose(fd);
3128     }
3129     return -1;
3130 }
3131 
3132 /* Show the text in a balloon. */
3133     void
gdb_showBalloon(text,obs)3134 gdb_showBalloon(text, obs)
3135     char * text;
3136     struct obstack *obs;
3137 {
3138     cnb_showBalloon(text, FALSE, obs);
3139 }
3140 
3141 /* Show the status in a ballon. */
3142     void
gdb_status(this,status,obs)3143 gdb_status(this, status, obs)
3144     gdb_T *this;
3145     char *status;	/* gdb status */
3146     struct obstack *obs;
3147 {
3148     char *p, *q;
3149 
3150     if (showBalloon && this != NULL && GDB_STATE(this, GS_UP))
3151     {
3152 	obstack_strcat(obs, "gdb ");
3153 	if (this->sfile != NULL)
3154 	{
3155 	    obstack_strcat(obs, "- ");
3156 	    /* get the tail of this pathname */
3157 	    for (p = q = this->sfile; *q; q++)
3158 		if (*q == '/')
3159 		    p = q + 1;
3160 	    obstack_strcat(obs, p);
3161 	}
3162 
3163 	obstack_strcat(obs, " [");
3164 	obstack_strcat(obs, status);
3165 	obstack_strcat0(obs, "]");
3166 	p = (char *)obstack_finish(obs);
3167 	cnb_showBalloon(p, TRUE, obs);
3168     }
3169 }
3170 
3171 /* Display a cmd line busy msg */
3172     void
gdb_msg_busy(str)3173 gdb_msg_busy(str)
3174     char *str;
3175 {
3176 #define BUSY_LINE_SIZE	82
3177     static char *prop[] = { "/", "-", "\\", "|" };
3178     static char busy[BUSY_LINE_SIZE];
3179     static int cnt;
3180     char *p;
3181 
3182     /* set busy string */
3183     if (str != NULL && strcmp(str, "FIN") == 0)
3184     {
3185 	for (p = busy; *p && p < busy + BUSY_LINE_SIZE - 6; p++)
3186 	    *p = ' ';
3187 	*p++ = ' '; *p++ = ' '; *p++ = ' '; *p++ = ' '; *p++ = '\r';
3188 	*p = NUL;
3189 	busy[0] = '\r';
3190 	fprintf(stderr, busy);
3191 	fflush(stderr);
3192 	rl_forced_update_display();
3193     }
3194     else if (str != NULL)
3195     {
3196 	busy[0] = '\r';
3197 	strncpy(busy + 1, str, BUSY_LINE_SIZE - 2);
3198 	busy[BUSY_LINE_SIZE - 1] = NUL;
3199     }
3200     else
3201     {
3202 	fprintf(stderr, busy);
3203 	fprintf(stderr, " [");
3204 	fprintf(stderr, prop[(++cnt % 4)]);
3205 	fprintf(stderr, "]");
3206 	fflush(stderr);
3207     }
3208 }
3209 
3210