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: gdb_lvl3.c 222 2008-10-13 14:38:07Z xavier $
21  */
22 
23 # ifdef HAVE_CLEWN
24 #  include <config.h>
25 #  include "obstack.h"
26 #  include "clewn.h"
27 static int got_int;	/* not used with Clewn */
28 # else
29 #  include "vim.h"
30 #  include "clewn/obstack.h"
31 # endif
32 
33 #if defined(FEAT_GDB) || defined(HAVE_CLEWN)
34 
35 # include "gdb.h"
36 # include "misc.h"
37 
38 # if defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT)
39 
40 static char gdb_buf[MAX_BUFFSIZE];  /* general purpose buffer */
41 
42 typedef struct
43 {
44     int id;	    /* annoted identifier */
45     char_u *str;    /* GDB annotation */
46 } annotation_T;
47 
48 static annotation_T annotations[] = {
49     {ANO_PREPROMPT,		(char_u *)"pre-prompt"},
50     {ANO_PROMPT,		(char_u *)"prompt"},
51     {ANO_POSTPROMPT,		(char_u *)"post-prompt"},
52     {ANO_PRECMDS,		(char_u *)"pre-commands"},
53     {ANO_CMDS,			(char_u *)"commands"},
54     {ANO_PREOVERLOAD,		(char_u *)"pre-overload-choice"},
55     {ANO_OVERLOAD,		(char_u *)"overload-choice"},
56     {ANO_PREQUERY,		(char_u *)"pre-query"},
57     {ANO_QUERY,			(char_u *)"query"},
58     {ANO_PREPMT_FORMORE,	(char_u *)"pre-prompt-for-continue"},
59     {ANO_PMT_FORMORE,		(char_u *)"prompt-for-continue"},
60     {ANO_POSTPMT_FORMORE,	(char_u *)"post-prompt-for-continue"},
61     {ANO_QUIT,			(char_u *)"quit"},
62     {ANO_ERROR_BEG,		(char_u *)"error-begin"},
63     {ANO_FRAME_INVALID,		(char_u *)"frames-invalid"},
64     {ANO_BP_INVALID,		(char_u *)"breakpoints-invalid"},
65     {ANO_STARTING,		(char_u *)"starting"},
66     {ANO_STOPPED,		(char_u *)"stopped"},
67     {ANO_EXITED,		(char_u *)"exited"},
68     {ANO_SIGNALLED,		(char_u *)"signalled"},
69     {ANO_BREAKPOINT,		(char_u *)"breakpoint"},
70 #  ifdef GDB_LVL2_SUPPORT
71     {ANO_SOURCE,		(char_u *)"source"},
72     {ANO_FRAME_BEGIN,		(char_u *)"frame-begin"},
73     {ANO_FRAME_END,		(char_u *)"frame-end"},
74     {ANO_BP_HEADER,		(char_u *)"breakpoints-headers"},
75     {ANO_BP_TABLE,		(char_u *)"breakpoints-table"},
76     {ANO_BP_RECORD,		(char_u *)"record"},
77     {ANO_BP_FIELD0,		(char_u *)"field 0"},
78     {ANO_BP_FIELD1,		(char_u *)"field 1"},
79     {ANO_BP_FIELD2,		(char_u *)"field 2"},
80     {ANO_BP_FIELD3,		(char_u *)"field 3"},
81     {ANO_BP_FIELD4,		(char_u *)"field 4"},
82     {ANO_BP_FIELD5,		(char_u *)"field 5"},
83     {ANO_BP_FIELD6,		(char_u *)"field 6"},
84     {ANO_BP_FIELD7,		(char_u *)"field 7"},
85     {ANO_BP_FIELD8,		(char_u *)"field 8"},
86     {ANO_BP_FIELD9,		(char_u *)"field 9"},
87     {ANO_BP_END,		(char_u *)"breakpoints-table-end"},
88     {ANO_DISP_BEG,		(char_u *)"display-begin"},
89     {ANO_DISP_NUMEND,		(char_u *)"display-number-end"},
90     {ANO_DISP_FMT,		(char_u *)"display-format"},
91     {ANO_DISP_EXP,		(char_u *)"display-expression"},
92     {ANO_DISP_EXPEND,		(char_u *)"display-expression-end"},
93     {ANO_DISP_VALUE,		(char_u *)"display-value"},
94     {ANO_DISP_END,		(char_u *)"display-end"},
95     {ANO_FIELD_BEG,		(char_u *)"field-begin"},
96     {ANO_FIELD_NAMEND,		(char_u *)"field-name-end"},
97     {ANO_FIELD_VALUE,		(char_u *)"field-value"},
98     {ANO_FIELD_END,		(char_u *)"field-end"},
99     {ANO_ARRAY_BEG,		(char_u *)"array-section-begin"},
100     {ANO_ARRAY_ELT,		(char_u *)"elt"},
101     {ANO_ARRAY_ELTREP,		(char_u *)"elt-rep"},
102     {ANO_ARRAY_ELTEND,		(char_u *)"elt-rep-end"},
103     {ANO_ARRAY_END,		(char_u *)"array-section-end"},
104 #  endif
105     {0,				NULL}
106 };
107 
108 /* User interface */
109 static char_u *process_cmd __ARGS((gdb_T *, char_u *));
110 
111 /* Vim low level hook */
112 /* Not allowed after ^O in INS REP mode or from the input-line window */
113 static char_u *process_annotation __ARGS((gdb_T *, char_u *, struct obstack *));
114 static char_u * process_completion __ARGS((cli_cmd_T *, char_u *, struct obstack *));
115 static char_u * eol_choices __ARGS((cli_cmd_T *, struct obstack *));
116 
117 #  ifdef GDB_LVL3_SUPPORT
118 /* Gdb process mgmt */
119 static void clear_gdb_T __ARGS((gdb_T *));
120 
121 /* Out Of Band */
122 static char *get_lastbp __ARGS((gdb_T *, int, char_u *, struct obstack *));
123 static char *get_bp __ARGS((gdb_T *, int, char_u *, struct obstack *));
124 static void process_record __ARGS((gdb_T *, char_u *, struct obstack *));
125 static char *varobj_update __ARGS((gdb_T *, int, char_u *, struct obstack *));
126 static char *varobj_complete __ARGS((gdb_T *, struct obstack *));
127 static void varobj_hilite __ARGS((gdb_T *, varobj_T *, int, struct obstack *));
128 static void varobj_replace __ARGS((gdb_T *, varobj_T *, char_u *, struct obstack *));
129 static void remove_object __ARGS((gdb_T *, varobj_T *));
130 #  endif
131 
132 /* Utilities */
133 static char_u * parse_note __ARGS((gdb_T *, char_u *));
134 #  ifndef FEAT_GDB
135 static int get_note __ARGS((gdb_T *, char_u *));
136 #  endif
137 
138 #  ifdef GDB_LVL3_SUPPORT
139 /* The function ordering in this array is important as some of
140  * these functions must be invoked in the right order */
141 static oobfunc_T oobfunc[] = {
142     {gdb_get_pc},
143     {gdb_get_frame},
144     {gdb_get_sourcedir},
145 #ifndef FEAT_GDB
146     {gdb_source_project},
147     {gdb_get_pwd},
148     {gdb_get_args},
149 #endif
150     {gdb_source_cur},
151     {gdb_source_list},
152     {gdb_get_sfile},
153     {gdb_info_frame},
154     {gdb_stack_frame},	    /* after gdb_info_frame */
155     {get_lastbp},	    /* after gdb_get_frame */
156     {gdb_get_asmfunc},	    /* after get_lastbp */
157     {gdb_get_asmfunc_hack}, /* after gdb_get_asmfunc */
158     {gdb_get_asm},	    /* after gdb_get_asmfunc */
159     {get_bp},		    /* after gdb_get_asm and get_lastbp */
160     {varobj_update},
161     {NULL}
162 };
163 #  endif
164 
165 /** Send a cmd to gdb */
166     void
gdb_docmd_cli(this,cmd)167 gdb_docmd_cli(this, cmd)
168     gdb_T *this;
169     char_u  *cmd;	/* gdb cmd */
170 {
171 #  ifdef GDB_LVL3_SUPPORT
172     char_u *expression = NULL;
173     varobj_T *varobj;
174 #  endif
175     char_u *res;
176     char_u *ptr;
177     char_u *last;
178     int len;
179 
180     /* make a copy so we can mess with it */
181     if (cmd == NULL)
182     {
183 	this->cmd_type = CMD_ANY;
184 	goto empty_cmd;
185     }
186     cmd = (char_u *)clewn_strsave((char *)cmd);
187 
188     /* remove illegal characters */
189     for (ptr = last = cmd; *last != NUL; last++)
190 	if (*last == NL
191 		|| *last == TAB
192 		|| *last == KEY_INTERUPT
193 		|| !iscntrl((int)(*last)))
194 	    *ptr++ = *last;
195     *ptr = NUL;
196 
197     /* remove backslash at last position */
198     if (ptr != cmd && *(ptr - 1) == '\\')
199 	*(ptr - 1) = NUL;
200 
201     if (this->cli_cmd.state == CS_QUERY || this->note == ANO_QUERY)
202     {
203 	if (*cmd == NUL)
204 	    goto empty_cmd;
205 	goto send;
206     }
207 
208     /* now we can forget last cmd */
209     this->cmd_type = CMD_ANY;
210 
211     /* an interrupt */
212     if (STRCHR(cmd, KEY_INTERUPT) != NULL)
213 	goto send;
214 
215     /* a TAB */
216     if (STRCHR(cmd, TAB) != NULL)
217     {
218 	gdb_cmd_type(this, cmd);	/* get cmd type */
219 
220 	/* handle completion for all non-gdb commands */
221 	if (this->cmd_type == CMD_RESTART) {
222 	    gdb_setwinput((gdb_handle_T *)this, (char_u *)"cl_restart ");
223 	    xfree(cmd);
224 	    this->oob.state &= ~OS_CMD;
225 	    return;
226 	}
227 	else if (this->cmd_type == CMD_CREATEVAR)
228 	{
229 	    gdb_setwinput((gdb_handle_T *)this, (char_u *)"createvar ");
230 	    xfree(cmd);
231 	    this->oob.state &= ~OS_CMD;
232 	    return;
233 	}
234 	goto send;
235     }
236 
237     if ((res = gdb_regexec(cmd, PAT_CHG_ANNO, 0, NULL)) != NULL)
238     {
239 	EMSG(_("Sorry, cannot change annotation level"));
240 	xfree(res);
241 	goto empty_cmd;
242     }
243 
244 #  ifndef FEAT_GDB  /* Clewn follows GDB behavior with empty commands */
245     if (*cmd == NUL)
246     {
247 	gdb_send_cmd(this, (char_u *)"\n");
248 	xfree(cmd);
249 	return;
250     }
251 #  endif
252 
253     /* process the cmd */
254     if ((res = process_cmd(this, cmd)) != NULL)
255     {
256 	xfree(cmd);
257 	cmd = res;
258 
259 #  ifdef GDB_LVL3_SUPPORT
260 	/* a |+gdb| createvar command is processed later in oob varobj_update() */
261 	if (this->mode == GDB_MODE_LVL3 && this->cmd_type == CMD_CREATEVAR)
262 	{
263 #   ifdef FEAT_GDB
264 	    if (this->var_buf == NULL)
265 #   else
266 	    if (this->var_buf <= 0)
267 #   endif
268 	    {
269 		EMSG(_("Variables buffer does not exist anymore: unable to create variable"));
270 		goto empty_cmd;
271 	    }
272 
273 	    if (
274 #   ifdef FEAT_GDB
275 		    (expression = gdb_regexec(cmd, PAT_CRVAR_FMT, 2, NULL)) != NULL
276 #   else
277 		    (expression = gdb_regexec(cmd, PAT_CRVAR_FMT, 3, NULL)) != NULL
278 #   endif
279 		    && *expression != NUL)
280 	    {
281 		varobj = (varobj_T *)xcalloc(sizeof(varobj_T));
282 
283 		/* create a new varobj_T element and link it to the list */
284 		varobj->state      = VS_INIT;
285 		varobj->children   = FALSE;
286 #   ifdef FEAT_GDB
287 		varobj->format     = gdb_regexec(cmd, PAT_CRVAR_FMT, 1, NULL);
288 #   else
289 		varobj->format     = gdb_regexec(cmd, PAT_CRVAR_FMT, 2, NULL);
290 #   endif
291 		varobj->expression = expression;
292 		varobj->next = this->lvl3.varlist;
293 		this->lvl3.varlist = varobj;
294 
295 		goto empty_cmd;
296 	    }
297 
298 	    xfree(expression);
299 	    EMSG(_("Unvalid arguments to \"createvar\" command"));
300 	    goto empty_cmd;
301 	}
302 #  endif
303     }
304     else
305 	goto empty_cmd;
306 
307     /* add a newline to cmd if needed */
308     len = STRLEN(cmd);
309     if (len == 0 || *(cmd + len - 1) != NL)
310     {
311 	res = NULL;
312 	gdb_cat(&res, cmd);
313 	gdb_cat(&res, (char_u *)"\n");
314 	xfree(cmd);
315 	cmd = res;
316     }
317 send:
318     gdb_send_cmd(this, cmd);
319     xfree(cmd);
320     return;
321 empty_cmd:
322     gdb_send_cmd(this, (char_u *)" \n");
323     xfree(cmd);
324     return;
325 }
326 
327 /*
328  * Process a gdb cmd according to its type.
329  * Return an allocated sanitized cmd or NULL if error.
330  */
331     static char_u *
process_cmd(this,cmd)332 process_cmd(this, cmd)
333     gdb_T *this;
334     char_u  *cmd;	/* user's gdb cmd */
335 {
336     char_u *delete  = NULL;
337     char_u *range   = NULL;
338     char_u *res;
339 #  ifdef FEAT_GDB
340     int i;
341     buf_T *buf	    = NULL;
342     win_T *oldwin   = curwin;
343 #  endif
344 
345     /* make a copy so we can mess with it */
346     if (cmd == NULL || *cmd == NUL)
347 	return NULL;
348     cmd = (char_u *)clewn_strsave((char *)cmd);
349 
350     gdb_cmd_type(this, cmd);	/* get cmd type */
351 
352 #  ifdef GDB_LVL2_SUPPORT
353     /* Replace "createvar" command with GDB "display" command */
354     if (this->mode == GDB_MODE_LVL2 && this->cmd_type == CMD_CREATEVAR)
355     {
356 #   ifdef FEAT_GDB
357 	if ((res = gdb_regexec(cmd, PAT_CREATEVAR, 1, NULL)) != NULL)
358 #   else
359 	if ((res = gdb_regexec(cmd, PAT_CREATEVAR, 2, NULL)) != NULL)
360 #   endif
361 	{
362 	    /* replace */
363 	    this->cmd_type = CMD_DISPLAY;
364 	    FREE(cmd);
365 	    gdb_cat(&cmd, (char_u *)"display ");
366 	    gdb_cat(&cmd, res);
367 	    xfree(res);
368 
369 	    if (cmd == NULL)
370 	    {
371 		this->cmd_type = CMD_ANY;
372 		return NULL;
373 	    }
374 	}
375     }
376 #  endif
377 
378 #  ifndef FEAT_GDB
379     /* Prevent use of a low height size because of "prompt-for-continue" messages.
380      * The annotations lines printed by GDB are part of the lines count that
381      * is used by GDB for "prompt-for-continue" messages, however we do not
382      * display them. */
383     if ((res = gdb_regexec(cmd, PAT_HEIGHT, 2, NULL)) != NULL)
384     {
385 	fprintf(stderr, "Cannot change the screen size\n");
386 	xfree(cmd);
387 	xfree(res);
388 	return NULL;
389     }
390 #  endif
391 
392     /* Cannot attach to oneself */
393 #  ifdef FEAT_GDB
394     if ((res = gdb_regexec(cmd, PAT_PID, 1, NULL)) != NULL)
395 #  else
396     if ((res = gdb_regexec(cmd, PAT_PID, 2, NULL)) != NULL)
397 #  endif
398     {
399 	if (getpid() == atoi((char *)res))
400 	{
401 	    EMSG(_("I refuse to debug myself!"));
402 	    xfree(cmd);
403 	    xfree(res);
404 	    return NULL;
405 	}
406 	xfree(res);
407     }
408 
409     /* no processing for 'define' type cmds */
410     if (this->note == ANO_CMDS || this->note == ANO_OVERLOAD)
411 	return cmd;
412 
413     switch (this->cmd_type)
414     {
415 #  ifdef GDB_LVL2_SUPPORT
416 	case CMD_DISPLAY:
417 	    /* A "display" command without argument is equivalent to the
418 	     * debuggee being stopped */
419 	    if ((res = gdb_regexec(cmd, PAT_DISPLAY, 0, NULL)) != NULL)
420 	    {
421 		xfree(res);
422 		this->cmd_type = CMD_ANY;
423 #   ifdef FEAT_GDB
424 		if (this->var_buf != NULL)
425 #   else
426 		if (this->var_buf > 0)
427 #   endif
428 		    this->lvl2.varlist.state = DSP_STOPPED;
429 	    }
430 	    break;
431 #  endif
432 
433 	case CMD_SHELL:
434 	    EMSG(_("Sorry, cannot spawn a shell"));
435 	    xfree(cmd);
436 	    return NULL;
437 
438 	/* unlite frame on 'detach' */
439 	case CMD_DETACH:
440 	    gdb_fr_unlite(this);
441 	    break;
442 
443 	/* clear dirty asm buffers */
444 	case CMD_EXECF:
445 #  ifdef FEAT_GDB
446 	    for (i = 0; i < this->pool.max; i++)
447 	    {
448 		if ((curbuf = this->pool.buf[i]) == NULL)
449 		    continue;
450 
451 		/* clear the buffer */
452 		gdb_clear_asmbuf(this, curbuf);
453 
454 		/* asm buffer is displayed */
455 		if ((curwin = gdb_btowin(curbuf)) != NULL)
456 		{
457 		    check_cursor();
458 		    buf = curbuf;
459 		}
460 		curwin = oldwin;
461 	    }
462 	    curbuf = curwin->w_buffer;
463 	    gdb_redraw(buf);	/* redraw only if one asm displayed */
464 #  else
465 	    /* unlink all asm buffers */
466 	    cnb_unlink_asm();
467 #  endif
468 
469 #  ifdef GDB_LVL3_SUPPORT
470 	    /* get source files list */
471 	    this->lvl3.get_source_list = TRUE;
472 #  endif
473 	    break;
474 
475 	case CMD_SYMF:
476 #  ifdef GDB_LVL3_SUPPORT
477 	    /* get source files list */
478 	    this->lvl3.get_source_list = TRUE;
479 #  endif
480 	    break;
481 
482 	case CMD_UP:
483 	case CMD_UP_SILENT:
484 	case CMD_DOWN:
485 	case CMD_DOWN_SILENT:
486 	case CMD_FRAME:
487 	case CMD_SLECT_FRAME:
488 	    if (this->mode != GDB_MODE_LVL3)
489 	    {
490 		this->pool.hilite = TRUE;
491 
492 		/* this should not be necessary but sometimes we
493 		 * don't get the ANO_FRAME_INVALID */
494 		this->bp_state |= BPS_FR_INVALID;
495 	    }
496 	    break;
497 
498 	case CMD_DELETE:
499 	case CMD_DISABLE:
500 	    /* keep BPS_FR_INVALID state */
501 	    this->bp_state &= BPS_FR_INVALID;
502 	    this->bp_state |= BPS_INVALID;
503 	    break;
504 
505 	/* the restart command is mapped to the gdb 'quit' command,
506 	 * and that will cause gdb to be restarted (the 'quit'
507 	 * command itself is trapped and
508 	 * causes a clean termination of clewn and vim) */
509 	case CMD_RESTART:
510 	    xfree(cmd);
511 	    cmd = (char_u *)clewn_strsave("quit");
512 	    break;
513 
514 	/* terminate clewn and vim */
515 	case CMD_QUIT:
516 	    this->state |= GS_QUITTING;
517 	    break;
518 
519 	default:
520 	    break;
521     }
522     xfree(range);
523     xfree(delete);
524     return cmd;
525 }
526 
527 /* Send a cmd to gdb */
528     void
gdb_send_cmd(this,cmd)529 gdb_send_cmd(this, cmd)
530     gdb_T *this;
531     char_u  *cmd;	/* gdb cmd */
532 {
533     int do_free = TRUE;		/* TRUE when readline must be freed */
534     int offset = 0;
535     char_u *res;
536     char_u *start;
537     int len;
538     int l;
539 
540     if ( ! GDB_STATE(this, GS_UP))
541 	return;
542 
543     this->intr_sent = FALSE;
544 
545     /* make a copy so we can mess with it */
546     if (cmd == NULL || (len = STRLEN(cmd)) == 0 )
547 	return;
548     cmd = (char_u *)clewn_strsave((char *)cmd);
549 
550     /* paranoia: trim after NL */
551     if ((res = STRCHR(cmd, (int)NL)) != NULL)
552 	*(res + 1) = NUL;
553 
554     /* answering to a query: any stuff not 'y[es]' is converted to 'no' */
555     if (this->cli_cmd.state == CS_QUERY || this->note == ANO_QUERY)
556     {
557 	len = 1;
558 	if ((res = gdb_regexec(cmd, PAT_YES, 0, NULL)) != NULL)
559 	{
560 	    *cmd = 'y';
561 	    xfree(res);
562 	}
563 	else
564 	    *cmd = 'n';
565 
566 #  ifdef FEAT_GDB
567 	/* CMD_DIR is acted upon when parsing gdb output */
568 	if (this->cmd_type != CMD_DIR)
569 	    this->cmd_type = CMD_ANY;
570 #  endif
571 
572 	if (this->cli_cmd.state == CS_QUERY)	/* no NL when a completion */
573 	{
574 	    this->cli_cmd.state = CS_CHOICE;
575 	    do_free = FALSE;
576 
577 	    /* a standalone <Tab> */
578 	    if (this->cli_cmd.readline == NULL
579 		    && this->cli_cmd.gdb != NULL && *(this->cli_cmd.gdb) == NUL)
580 		this->oob.state &= ~OS_CMD;
581 	}
582 	else
583 	{
584 	    this->cli_cmd.state = CS_START;
585 	    *(cmd + 1) = NL;
586 	    len = 2;	/* enough room since cmd length not zero */
587 	}
588 	goto write_answer;
589     }
590 
591     /* an interrupt */
592     if (STRCHR(cmd, KEY_INTERUPT) != NULL)
593     {
594 	this->intr_sent = TRUE;
595 	this->cli_cmd.state = CS_START;
596 	goto write_answer;
597     }
598 
599     /* a cmd following a completion response by gdb */
600     if (this->cli_cmd.state == CS_DONE && this->cli_cmd.readline != NULL)
601     {
602 	/* readline matches start of cmd: send 'user cmd - readline' */
603 	if (STRSTR(cmd, this->cli_cmd.readline) == cmd)
604 	{
605 	    offset = STRLEN(this->cli_cmd.readline);
606 	    len -= offset;
607 	    do_free = FALSE;
608 	}
609 	/* no match */
610 	else
611 	{
612 	    /* send KEY_KILL to erase gdb's readline */
613 	    gdb_buf[0] = KEY_KILL;
614 	    write(this->fd, gdb_buf, 1);
615 
616 	    /* discard gdb answer:
617 	     * '\r' plus the termcap entry 'ce' (clear to end of line) */
618 	    l = gdb_read(this, (char_u *)gdb_buf, MAX_BUFFSIZE, 1000);
619 
620 	    /* do what the discarded stuff above was meant to do:
621 	     * replace last line by getting rid of readline */
622 	    /* find the rightmost match */
623 	    res = NULL;
624 	    for (start = this->line; *start != NUL; start++)
625 		if ((start = STRSTR(start, this->cli_cmd.readline)) != NULL)
626 		    res = start;
627 		else
628 		    break;
629 
630 	    if (res != NULL)
631 	    {
632 		*res = NUL;
633 		gdb_write_buf(this, this->line, FALSE);
634 	    }
635 	    FREE(this->cli_cmd.echoed);
636 	}
637     }
638 
639     this->cli_cmd.state = CS_START;
640 
641     /* a completion request */
642     if (*(cmd + offset + len - 1) == TAB)
643     {
644 	this->cli_cmd.state = CS_PENDING;
645 
646 	xfree(this->cli_cmd.gdb);
647 	this->cli_cmd.gdb = (char_u *)clewn_strsave((char *)(cmd + offset));
648 	*(this->cli_cmd.gdb + len - 1) = NUL;	/* remove <Tab> */
649     }
650 write_answer:
651     if (do_free)
652 	FREE(this->cli_cmd.readline);
653     write(this->fd, (char *)cmd + offset, len);
654     xfree(cmd);
655     return;
656 }
657 
658 #  ifdef FEAT_GDB
659 #   if defined(MACOS_X) || defined(MACOS_X_UNIX)
660 /* Strip terminating carriage return from a line */
661     static void
strip_cr(line)662 strip_cr(line)
663     char_u *line;
664 {
665     int len = STRLEN(line);
666 
667     if (len != 0 && line[len - 1] == '\r')
668 	line[len - 1] = NUL;
669 }
670 #   endif
671 #  endif
672 
673 #  ifndef FEAT_GDB
674     /* Handle "prompt-for-continue" annotations.
675      * This is not needed by VimGDB as the screen height is very large. */
676 #   define MANAGE_PRMPT_FORMORE
677 
678      /* The fix for writing through readline the concatenation of multiple
679       * lines output by gdb, is only correctly implemented for clewn */
680 #   define FIX_CONCATENATION_WRITE
681 #  endif
682 /*
683  * Parse gdb output for annotation and completion. Update gdb console.
684  * Return TRUE when the user must be prompted by the input-line window.
685  */
686     int
gdb_parse_output_cli(this)687 gdb_parse_output_cli(this)
688     gdb_T *this;
689 {
690 #  ifdef FIX_CONCATENATION_WRITE
691     static int pending_write = FALSE;   /* TRUE, this->line content has not been written yet */
692 #  endif
693     struct obstack obs;	/* use an obstack for temporary allocated memory */
694     char_u *start;
695     char_u *end;
696     char_u *line;
697     char_u *res;
698     int rc;
699     int len;
700 #  ifdef MANAGE_PRMPT_FORMORE
701     int do_newline;
702 #  endif
703 
704     /* read gdb data */
705     if (this == NULL || ! GDB_STATE(this, GS_UP)
706 	    || gdb_read(this, (char_u *)gdb_buf, MAX_BUFFSIZE, 0) <= 0)
707 	return FALSE;
708 
709     (void)obstack_init(&obs);
710 
711     /* Process line after line */
712     for (start = end = (char_u *)gdb_buf; end != NULL; start = end)
713     {
714 	/* Get next line */
715 	if ((end = STRCHR(start, NL)) != NULL)
716 	    *end++ = NUL;
717 	else if (*start == NUL) /* nothing left to read */
718 	    break;
719 
720 	/* concatenate with incomplete annotation */
721 	if (this->annotation != NULL)
722 	{
723 	    obstack_strcat(&obs, this->annotation);
724 	    obstack_strcat0(&obs, start);
725 	    line = (char_u *)obstack_finish(&obs);
726 	}
727 	else
728 	    line = obstack_strsave(&obs, start);
729 
730 #  ifdef FEAT_GDB
731 #   if defined(MACOS_X) || defined(MACOS_X_UNIX)
732 	strip_cr(line);
733 #   endif
734 #  endif
735 
736 	/* With GDB 6.0, completion giving as a result a long list of items causes
737 	 * a "--More--" prompt to be issued after what GDB (or readline) considers
738 	 * the height of the terminal (unfortunately not using the GDB height
739 	 * settings). In case we could not size the terminal to a very big height
740 	 * with an ioctl call in exec_gdb(), we must answer to the prompt. */
741 	if (this->height == 0				/* height not set */
742 		&& this->cli_cmd.state == CS_CHOICE	/* a completion list */
743 		&& end == NULL
744 		&& STRCMP(line, "--More--") == 0)	/* standalone prompt */
745 	{
746 	    write(this->fd, " ", 1);	/* prompt for more */
747 	    this->annoted = FALSE;
748 	    break;
749 	}
750 
751 #  ifdef FEAT_GDB   /* Clewn does not use hiliting */
752 	/* some fuzzy gdb annotation corner: rewrite '(gdb) Quit' so that
753 	 * it gets highlited (must be done before the newline stuff) */
754 	if (parse_note(this, line) != NULL && this->note == ANO_QUIT)
755 	    gdb_write_buf(this, this->line, FALSE);
756 #  endif
757 
758 	/* two consecutive NL: start a new line except when this annotation
759 	 * just follows another annotation
760 	 * IS_ANNOTATION() does not handle a standalone '\032' */
761 	if (this->newline && (*line != '\032' || !this->annoted))
762 	{
763 #  ifdef MANAGE_PRMPT_FORMORE
764 	    do_newline = TRUE;
765 
766 	    /* do not start a new line when parsing annotations and
767 	     *	. the next chunk is a "pre-prompt-for-continue" and
768 	     *	  the previous chunk was an annotation
769 	     *	. or this is a "pre-prompt-for-continue" annotation */
770 	    if (this->mode == GDB_MODE_LVL2
771 		    && ! IS_OOBACTIVE(this) && (this->state & GS_ANO))
772 	    {
773 		if (end != NULL && get_note(this, end) == ANO_PREPMT_FORMORE
774 			&& this->prev_note != ANO_NONE)
775 		    do_newline = FALSE;
776 		if (line != NULL && get_note(this, line) == ANO_PREPMT_FORMORE)
777 		    do_newline = FALSE;
778 	    }
779 
780 	    if (do_newline)
781 #  endif
782 	    {
783 		if (this->line == NULL && *line != '\032')
784 		{
785 		    if (IS_OOBACTIVE(this))
786 			gdb_oob_receive(this, (char_u *)"", &obs);
787 		    else
788 			gdb_write_buf(this, (char_u *)"", TRUE);
789 		}
790 
791 #  ifdef FIX_CONCATENATION_WRITE
792 		if (pending_write)
793 		    gdb_write_buf(this, this->line, TRUE);
794 #  endif
795 
796 		FREE(this->line);	/* start a new line */
797 		this->note = ANO_NONE;
798 	    }
799 	}
800 	this->newline = FALSE;
801 
802 	/* Parse for annotations */
803 	/* we cannot parse "\n\032\032annotation\n" directly
804 	 * as any stuff may be split across two buff read;
805 	 * must concatenate line when interleaved with annotations */
806 	if (*line == NUL)
807 	{
808 	    /* ignore echoed NL after ANO_PMT_FORMORE msg */
809 	    if (this->note != ANO_PMT_FORMORE)
810 		this->newline = TRUE;
811 
812 #  ifdef MANAGE_PRMPT_FORMORE
813 	    /* start a new line */
814 	    if (this->mode == GDB_MODE_LVL2 && this->prev_note == ANO_POSTPMT_FORMORE)
815 	    {
816 		FREE(this->line);
817 		this->note = ANO_NONE;
818 	    }
819 #  endif
820 	}
821 	/* a complete annotation */
822 	else if (IS_ANNOTATION(line) && end != NULL)
823 	{
824 	    /* remember last annotation type */
825 	    if (this->note != ANO_PREPMT_FORMORE
826 		    && this->note != ANO_PMT_FORMORE
827 		    && this->note != ANO_POSTPMT_FORMORE)
828 		this->valid_note = this->note;
829 
830 	    res = parse_note(this, line); /* assert != NULL */
831 
832 	    if ((res = process_annotation(this, res, &obs)) != NULL)
833 	    {
834 		gdb_setwinput((gdb_handle_T *)this, res);
835 		xfree(res);
836 
837 		/* fake an interrupt: will empty stuff and typeahead
838 		 * buffers aborting insert mode, pending mappings
839 		 * and operations */
840 		got_int = TRUE;
841 	    }
842 
843 	    FREE(this->annotation);
844 	    this->annoted = TRUE;
845 
846 #  ifdef GDB_LVL2_SUPPORT
847 	    /* ANO_DISP_END has no content and must be trapped here */
848 	    if (
849 #   ifdef FEAT_GDB
850 		    this->mode == GDB_MODE_LVL2 && this->var_buf != NULL
851 #   else
852 		    this->mode == GDB_MODE_LVL2 && this->var_buf > 0
853 #   endif
854 		    && this->note == ANO_DISP_END)
855 	    {
856 		gdb_process_display(this, (char_u *)"", &obs);
857 	    }
858 #  endif
859 
860 #  ifdef MANAGE_PRMPT_FORMORE
861 	    /* start a new line when end of annotation list or table */
862 	    if (this->mode == GDB_MODE_LVL2
863 		    && this->prev_note == ANO_POSTPMT_FORMORE
864 		    && (this->note == ANO_BP_TABLE
865 			|| this->note == ANO_BP_RECORD
866 			|| this->note == ANO_BP_END
867 			|| this->note == ANO_FRAME_END
868 			|| this->note == ANO_DISP_END))
869 	    {
870 		FREE(this->line);	/* start a new line */
871 		this->note = ANO_NONE;
872 	    }
873 #  endif
874 
875 	    /* store current annotation type */
876 	    this->prev_note = this->note;
877 
878 	    /* restore annotation type */
879 	    if (this->note == ANO_POSTPMT_FORMORE)
880 		this->note = this->valid_note;
881 	}
882 	/* a partial annotation */
883 	else if (*line == '\032'
884 		&& (*(line + 1) == NUL || *(line + 1) == '\032')
885 		&& end == NULL)
886 	{
887 	    xfree(this->annotation);
888 	    this->annotation = (char_u *)clewn_strsave((char *)line);
889 	    break;
890 	}
891 	else
892 	{
893 #  ifdef MANAGE_PRMPT_FORMORE
894 	    /* The breakpoint table:
895 	     * start a new line when line starts with <TAB>.*/
896 	    if (this->mode == GDB_MODE_LVL2
897 		    && this->prev_note == ANO_POSTPMT_FORMORE
898 		    && line != NULL && *line == TAB)
899 	    {
900 		FREE(this->line);	/* start a new line */
901 		this->note = ANO_NONE;
902 	    }
903 #  endif
904 
905 	    if (this->note == ANO_PREPMT_FORMORE)
906 	    {
907 #  ifdef MANAGE_PRMPT_FORMORE
908 		if (! IS_OOBACTIVE(this))
909 		{
910 		    /* Starting with GDB 6.0, GDB sends an ANO_PREPMT_FORMORE
911 		     * whenever ^C have been typed more that gdb_screen_height/2. */
912 		    if (this->state & GS_ANO || this->intr_sent)
913 		    {
914 			write(this->fd, "\n", 1);	/* prompt for more */
915 		    }
916 		    else
917 		    {
918 			this->oob.state &= ~OS_CMD;	/* enable next command */
919 			xfree(this->prompt);
920 			if (line != NULL)
921 			    this->prompt = (char_u *)clewn_strsave((char *)line);
922 			else
923 			    this->prompt = (char_u *)clewn_strsave(
924 				"---type <return> to continue, or q <return> to quit---");
925 		    }
926 		    this->intr_sent = FALSE;
927 		}
928 #  endif
929 		line = NULL;		/* remove ANO_PMT_FORMORE msg */
930 	    }
931 
932 #  ifdef GDB_LVL2_SUPPORT
933 	    /* handle a display annotation content
934 	     * take care of nested structures and arrays in value content */
935 #   ifdef FEAT_GDB
936 	    if (this->mode == GDB_MODE_LVL2 && this->var_buf != NULL)
937 #   else
938 	    if (this->mode == GDB_MODE_LVL2 && this->var_buf > 0)
939 #   endif
940 	    {
941 		if ((this->note >= ANO_DISP_BEG && this->note <= ANO_DISP_END)
942 			|| (this->lvl2.doing_value && this->note >= ANO_FIELD_BEG
943 			    && this->note <= ANO_FIELD_END)
944 			|| (this->lvl2.doing_value && this->note >= ANO_ARRAY_BEG
945 			    && this->note <= ANO_ARRAY_END))
946 		{
947 		    gdb_process_display(this, line, &obs);
948 		    line = NULL;
949 		}
950 	    }
951 #  endif
952 
953 	    if (IS_OOBACTIVE(this))
954 	    {
955 		gdb_oob_receive(this, line, &obs);
956 	    }
957 	    else
958 	    {
959 		if (this->note == ANO_PROMPT || this->note == ANO_CMDS)
960 		    gdb_cat(&(this->cli_cmd.echoed), line);
961 
962 		/* update line cnt before doing cpltn */
963 		if (this->line == NULL || !this->annoted)
964 		    this->cli_cmd.cnt++;
965 
966 		/* Parse for completion */
967 		if ((res = process_completion( &(this->cli_cmd), line, &obs)) != NULL)
968 		{
969 		    gdb_setwinput((gdb_handle_T *)this, res);
970 		    xfree(res);
971 		    got_int = TRUE;
972 		}
973 
974 		if (line != NULL && (len = STRLEN(line)) != 0
975 			&& *(line + len - 1) == BELL)
976 		    *(line + len - 1) = NUL;
977 
978 		/* concatenate after an annotation and replace, otherwise add */
979 		if (this->line != NULL && this->annoted)
980 		{
981 		    if (this->note == ANO_ERROR_BEG && STRCMP(line, "Quit") == 0)
982 			this->syntax = TRUE;
983 
984 		    obstack_strcat(&obs, this->line);
985 		    obstack_strcat0(&obs, line);
986 		    line = (char_u *)obstack_finish(&obs);
987 
988 #  ifndef FEAT_GDB  /* do not write "(gdb) Quit"  with Clewn (already done) */
989 		    if (this->note != ANO_ERROR_BEG)
990 #  endif
991 		    {
992 #  ifdef FIX_CONCATENATION_WRITE
993 			/* write a complete line */
994 			if (end != NULL)
995 			{
996 			    if (pending_write)
997 				gdb_write_buf(this, line, TRUE);
998 			    else
999 				gdb_write_buf(this, line, FALSE);
1000 			}
1001 #  else
1002 			gdb_write_buf(this, line, FALSE);
1003 #  endif
1004 		    }
1005 
1006 		}
1007 		else
1008 		{
1009 #  ifdef FEAT_GDB   /* no need to map T_CE when running Clewn */
1010 		    /* a completion list */
1011 		    if (this->height == 0		/* height not set */
1012 			    && this->cli_cmd.state == CS_CHOICE)
1013 		    {
1014 			char_u *ptr;
1015 
1016 			/* discard "^\rT_CE\r" which is sent by readline
1017 			 * after answering to a prompt in a completion list
1018 			 * (not needed on systems where TIOCSWINSZ ioctls are
1019 			 * available) */
1020 			if (STRSTR(line, T_CE) == line + 1
1021 				&& STRLEN(line) >= STRLEN(T_CE) + 2)
1022 			{
1023 			    ptr = line + STRLEN(T_CE) + 2;
1024 			    line = obstack_strsave(&obs, ptr);
1025 			}
1026 		    }
1027 		    gdb_write_buf(this, line, TRUE);
1028 #  else
1029 		    /* do not write the query prompt */
1030 		    if (this->cli_cmd.state == CS_QUERY)
1031 			gdb_write_buf(this, (char_u *)"", TRUE);
1032 		    else
1033 		    {
1034 #  ifdef FIX_CONCATENATION_WRITE
1035 			/* write a complete line */
1036 			if (end != NULL)
1037 			{
1038 			    gdb_write_buf(this, line, TRUE);
1039 			}
1040 #  else
1041 			gdb_write_buf(this, line, TRUE);
1042 #  endif
1043 		    }
1044 #  endif
1045 		}
1046 
1047 		xfree(this->line);
1048 		this->line = (line != NULL ? (char_u *)clewn_strsave((char *)line) : NULL);
1049 	    }
1050 
1051 #  ifdef FIX_CONCATENATION_WRITE
1052 	    pending_write = FALSE;
1053 	    if (end == NULL)	/* incomplete line */
1054 	    {
1055 		pending_write = TRUE;
1056 		this->annoted = TRUE;	/* force concatenation on next read */
1057 		break;
1058 	    }
1059 #  else
1060 	    if (end == NULL)	/* incomplete line */
1061 	    {
1062 		this->annoted = TRUE;	/* force concatenation on next read */
1063 		break;
1064 	    }
1065 #  endif
1066 	    this->annoted = FALSE;
1067 	    this->note = ANO_NONE;
1068 	}
1069     }	/* for (...) */
1070 
1071     obstack_free(&obs, NULL);
1072 
1073     if (IS_OOBACTIVE(this))
1074 	return FALSE;
1075 
1076 #  ifdef FEAT_GDB
1077     /* redraw gdb console window when displayed */
1078     gdb_redraw(this->buf);
1079 #  endif
1080 
1081     /* Wait till we get the prompt to send the first cmd */
1082     if (this->firstcmd != NULL && this->note == ANO_PROMPT)
1083     {
1084 	gdb_docmd((gdb_handle_T *)this, this->firstcmd);
1085 	FREE(this->firstcmd);
1086     }
1087 
1088     if ((rc = gdb_iswinput((gdb_handle_T *)this)) == TRUE)
1089 	this->oob.state &= ~OS_CMD;
1090     return rc;
1091 }
1092 
1093 /*
1094  * Process an annotation.
1095  * Return cmd to prompt the user with or NULL if none.
1096  */
1097     static char_u *
process_annotation(this,str,obs)1098 process_annotation(this, str, obs)
1099     gdb_T *this;
1100     char_u *str;	/* annotation's content */
1101     struct obstack *obs;
1102 {
1103     int s_a = (this->state & GS_ALLOWED);
1104     char_u *file = NULL;
1105     char_u *line = NULL;
1106     linenr_T linenumber;
1107     char_u *cpn;
1108     int bp_number;
1109     bpinfo_T *r;
1110 
1111     this->syntax = FALSE;
1112     this->parser = PS_ANY;
1113 
1114     switch (this->note)
1115     {
1116 	/* Output end: run directory function */
1117 	case ANO_PREPROMPT:
1118 	    this->syntax = TRUE;
1119 	    this->parser = PS_PREPROMPT;
1120 	    this->cmd_type = CMD_ANY;
1121 	    this->state &= ~GS_ANO;
1122 	    break;
1123 
1124 	/* Send out of band cmd */
1125 	case ANO_PROMPT:
1126 	    this->syntax = TRUE;
1127 	    this->parser = PS_PROMPT;
1128 	    this->cli_cmd.cnt = 1;
1129 	    FREE(this->cli_cmd.echoed);
1130 #  ifndef FEAT_GDB	/* store the prompt */
1131 	    if (! IS_OOBACTIVE(this) || (this->oob.state & OS_INTR))
1132 	    {
1133 		xfree(this->prompt);
1134 		if (this->line != NULL)
1135 		    this->prompt = (char_u *)clewn_strsave((char *)this->line);
1136 		else
1137 		    this->prompt = (char_u *)clewn_strsave("(gdb)   ");
1138 	    }
1139 #  endif
1140 	    if (this->cli_cmd.state == CS_START) {
1141 		gdb_oob_send(this, obs);
1142 
1143 		/* reset the standard oobfunc table after invocation
1144 		 * of a one function oobfunc array */
1145 		this->oobfunc = this->std_oobfunc;
1146 	    }
1147 	    break;
1148 
1149 	case ANO_CMDS:
1150 	    this->syntax = TRUE;
1151 	    this->cli_cmd.cnt = 1;
1152 	    this->oob.state &= ~OS_CMD;
1153 	    FREE(this->cli_cmd.echoed);
1154 #  ifndef FEAT_GDB	/* store the prompt */
1155 	    if (! IS_OOBACTIVE(this) || (this->oob.state & OS_INTR))
1156 	    {
1157 		xfree(this->prompt);
1158 		if (this->line != NULL)
1159 		    this->prompt = (char_u *)clewn_strsave((char *)this->line);
1160 		else
1161 		    this->prompt = (char_u *)clewn_strsave(">  ");
1162 	    }
1163 #  endif
1164 
1165 	    /* should be in process_completion, but bug in gdb
1166 	     * annotations where 'pre-commands' is missing in completions */
1167 	    if (this->cli_cmd.state == CS_CHOICE
1168 		    && (cpn = eol_choices(&(this->cli_cmd), obs)) != NULL)
1169 		return cpn;
1170 
1171 	    /* a lone <Tab> does not prompt the user except in define mode */
1172 	    if ((this->cli_cmd.state != CS_PENDING
1173 			&& this->cli_cmd.state != CS_CHOICE)
1174 		    || (this->cli_cmd.readline == NULL && this->cli_cmd.gdb != NULL
1175 			    && *(this->cli_cmd.gdb) == NUL))
1176 		return (char_u *)clewn_strsave("");
1177 	    break;
1178 
1179 	case ANO_OVERLOAD:
1180 	case ANO_QUERY:
1181 	    this->oob.state &= ~OS_CMD;
1182 #  ifndef FEAT_GDB	/* store the prompt */
1183 	    if (! IS_OOBACTIVE(this) || (this->oob.state & OS_INTR))
1184 	    {
1185 		xfree(this->prompt);
1186 		if (this->line != NULL)
1187 		    this->prompt = (char_u *)clewn_strsave((char *)this->line);
1188 		else
1189 		    this->prompt = (char_u *)clewn_strsave(">   ");
1190 	    }
1191 #  endif
1192 	    return (char_u *)clewn_strsave("");
1193 
1194 	case ANO_PMT_FORMORE:
1195 #  ifndef FEAT_GDB	/* handle ANO_PMT_FORMORE when IS_OOBACTIVE */
1196 	    if (IS_OOBACTIVE(this))
1197 #  endif
1198 	    {
1199 		if (this->oob.state & OS_INTR)
1200 		{
1201 		    clewn_beep();
1202 		    gdb_send_cmd(this, (char_u *)"q\n");	/* abort */
1203 		}
1204 		else
1205 		    gdb_send_cmd(this, (char_u *)"\n");	/* get more lines */
1206 	    }
1207 	    break;
1208 
1209 	case ANO_QUIT:
1210 	    this->syntax = TRUE;
1211 	    this->oob.state |= OS_QUIT;
1212 	    break;
1213 
1214 	case ANO_ERROR_BEG:
1215 	    this->pool.hilite = FALSE;
1216 #  ifdef GDB_LVL2_SUPPORT
1217 	    /* a display expression parse error */
1218 	    this->lvl2.doing_value = FALSE;
1219 	    FREE(this->lvl2.dentry.num);
1220 	    FREE(this->lvl2.dentry.expression);
1221 	    FREE(this->lvl2.dentry.value);
1222 #  endif
1223 #  ifdef GDB_LVL3_SUPPORT
1224 	    if (this->lvl3.varitem != NULL)
1225 		this->lvl3.varitem->state |= VS_ERROR;
1226 #  endif
1227 	    break;
1228 
1229 	case ANO_STARTING:
1230 	    this->frame_curlvl = -1;
1231 	    this->frame_lnum = (linenr_T) -1;
1232 	    FREE(this->frame_fname);
1233 
1234 	    FREE(this->frame_pc);
1235 	    this->state &= ~GS_STOPPED;
1236 	    gdb_status(this, (char_u *)"running...", obs);
1237 
1238 	    if (this->mode == GDB_MODE_LVL3)
1239 	    {
1240 		this->pool.hilite = FALSE;
1241 		if (p_asm != 0 && this->cmd_type == CMD_STEPI)  /* asm frame highlite: when stepi nexti */
1242 		    this->pool.hilite = TRUE;
1243 	    }
1244 	    else
1245 	    {
1246 		this->pool.hilite = TRUE;
1247 	    }
1248 	case ANO_FRAME_INVALID:
1249 	    gdb_fr_unlite(this);
1250 	    this->bp_state |= BPS_FR_INVALID;
1251 	    break;
1252 
1253 	case ANO_BP_INVALID:
1254 	    /* keep BPS_FR_INVALID state */
1255 	    this->bp_state &= BPS_FR_INVALID;
1256 	    this->bp_state |= BPS_INVALID;
1257 
1258 	    /* note the fact that the user is setting a
1259 	     * breakpoint */
1260 	    if (p_asm != 0 && this->cmd_type == CMD_BREAK)
1261 		this->bp_state |= BPS_BP_SET;
1262 	    break;
1263 
1264 	case ANO_STOPPED:
1265 	    this->state |= GS_STOPPED;
1266 	    gdb_status(this, (char_u *)"stopped", obs);
1267 #  ifdef GDB_LVL2_SUPPORT
1268 #   ifdef FEAT_GDB
1269 	    if (this->var_buf != NULL)
1270 #   else
1271 	    if (this->var_buf > 0)
1272 #   endif
1273 		this->lvl2.varlist.state = DSP_STOPPED;
1274 #  endif
1275 	    break;
1276 
1277 	case ANO_EXITED:
1278 	case ANO_SIGNALLED:
1279 	    FREE(this->frame_pc);
1280 
1281 	    this->state |= GS_STOPPED;
1282 	    gdb_status(this, (char_u *)"exited", obs);
1283 
1284 #  ifdef FEAT_GDB
1285 	    /* remove phantom highlite */
1286 	    gdb_unlite(PHANTOM_SIGN);
1287 #  endif
1288 	    break;
1289 
1290 	/* Breakpoint hit */
1291 	case ANO_BREAKPOINT:
1292 	    /* Look for this breakpoint in bpinfo list */
1293 	    if (str != NULL && (bp_number = atoi((char *)str)) > 0)
1294 	    {
1295 		for (r = this->bpinfo; r != NULL; r = r->next)
1296 		{
1297 		    if (r->id == bp_number)
1298 		    {
1299 			/* Set this->cont TRUE if this breakpoint's 'commands'
1300 			 * includes a 'continue' as last statement */
1301 			if (r->cont)
1302 			    this->cont = TRUE;
1303 
1304 #  ifdef BP_INVALID_ANO_MISSING
1305 			/* Trigger get_bp(): the breakpoint we hit is
1306 			 * 'enable once' */
1307 			if (r->enabled && ! r->disposition)
1308 			{
1309 			    /* keep BPS_FR_INVALID state */
1310 			    this->bp_state &= BPS_FR_INVALID;
1311 			    this->bp_state |= BPS_INVALID | BPS_BP_HIT;
1312 			}
1313 #  endif
1314 			break;
1315 		    }
1316 		}
1317 
1318 		/* Not found in the list. An asm buffer holding this bp
1319 		 * can possibly be disassembled next by oob get_asm().
1320 		 * Trigger oob get_bp() */
1321 		if (r == NULL && p_asm != 0)
1322 		{
1323 		    /* keep BPS_FR_INVALID state */
1324 		    this->bp_state &= BPS_FR_INVALID;
1325 		    this->bp_state |= BPS_INVALID | BPS_BP_HIT;
1326 		}
1327 	    }
1328 	    break;
1329 
1330 #  ifdef GDB_LVL2_SUPPORT
1331 	case ANO_SOURCE:
1332 	    /* gdb stats the file when doing ANO_SOURCE, so we can't rely on
1333 	     * that annotation for remote debugging with clewn when the source
1334 	     * files are on the host and not on the target
1335 	     * => use ANO_BREAKPOINT instead in level 3
1336 	     */
1337 
1338 	    if (! IS_OOBACTIVE(this) && this->mode == GDB_MODE_LVL2)
1339 	    {
1340 		/* Uncomment next line to print source text in gdb buffer */
1341 		/* gdb_write_buf(this, str, TRUE); */
1342 
1343 #   ifdef FEAT_GDB
1344 		gdb_popup_console(this);
1345 #   endif
1346 
1347 		this->pool.hilite = FALSE;
1348 
1349 		/* asm frame highlite: when stepi nexti */
1350 		if (p_asm != 0 && this->cmd_type == CMD_STEPI)
1351 		    this->pool.hilite = TRUE;
1352 		else
1353 		{
1354 		    /* prevent recursive calls to parse_output() since breakpoint
1355 		     * or frame highlighting may cause Vim to query the user when
1356 		     * changes have been made in the previous buffer */
1357 		    this->state &= ~GS_ALLOWED;
1358 
1359 		    if ((line = gdb_regexec(str, PAT_SOURCE, 2, obs)) != NULL)
1360 		    {
1361 			file = gdb_regexec(str, PAT_SOURCE, 1, obs);
1362 			linenumber = atoi((char *)line);
1363 			gdb_fr_set(this, file, &linenumber, obs);
1364 		    }
1365 
1366 		    this->state &= ~GS_ALLOWED;
1367 		    if (s_a)
1368 			this->state |= GS_ALLOWED;
1369 		}
1370 	    }
1371 	    break;
1372 
1373 	case ANO_FRAME_BEGIN:
1374 	case ANO_BP_HEADER:
1375 	case ANO_DISP_BEG:
1376 	    this->state |= GS_ANO;
1377 	    break;
1378 
1379 	case ANO_FRAME_END:
1380 	case ANO_DISP_END:
1381 	    break;
1382 
1383 	/* Get the source for this frame */
1384 	case ANO_BP_RECORD:
1385 	    this->bp_state |= BPS_RECORD;
1386 	    this->bp_state |= BPS_START;
1387 	    break;
1388 
1389 	case ANO_BP_FIELD0:
1390 	case ANO_BP_FIELD1:
1391 	case ANO_BP_FIELD2:
1392 	case ANO_BP_FIELD3:
1393 	case ANO_BP_FIELD4:
1394 	case ANO_BP_FIELD5:
1395 	case ANO_BP_FIELD6:
1396 	case ANO_BP_FIELD7:
1397 	case ANO_BP_FIELD8:
1398 	case ANO_BP_FIELD9:
1399 	    this->bp_state = SET_RECORD_IDX(this->bp_state,
1400 			(this->note - ANO_BP_FIELD0) + BI_NUM);
1401 	    break;
1402 
1403 	case ANO_BP_END:
1404 	    /* Initialize state but do not forget some of them.
1405 	     * ANO_BP_END can be the one we get when fetching the
1406 	     * table with oob function get_lastbp(): get_bp() still
1407 	     * needs those states */
1408 	    this->bp_state &= (BPS_INVALID | BPS_BP_HIT | BPS_FR_INVALID);
1409 	    break;
1410 #  endif
1411     }
1412     return NULL;
1413 }
1414 
1415 /*
1416  * Parse gdb output for completion.
1417  * Return cmd to prompt the user with or NULL if none.
1418  */
1419     static char_u *
process_completion(cmd,line,obs)1420 process_completion(cmd, line, obs)
1421     cli_cmd_T *cmd;
1422     char_u *line;	/* line to parse */
1423     struct obstack *obs;
1424 {
1425     char_u *res;
1426     char_u *start;
1427     int len;
1428 
1429     if (line == NULL || *line == NUL)
1430 	return NULL;
1431 
1432     switch (cmd->state)
1433     {
1434 	case CS_PENDING:
1435 	    /* A completion query */
1436 	    if (cmd->cnt == 2 && gdb_regexec(line, PAT_QUERY, 0, obs) != NULL)
1437 	    {
1438 		cmd->state = CS_QUERY;
1439 		return (char_u *)clewn_strsave("");
1440 	    }
1441 
1442 	    /* A positive completion */
1443 	    if (cmd->cnt == 1 && cmd->echoed != NULL
1444 		    && (len = (cmd->gdb != NULL ? STRLEN(cmd->gdb) : 0)) > 0)
1445 	    {
1446 		/* find the rightmost match */
1447 		res = NULL;
1448 		for (start = cmd->echoed; *start != NUL; start++)
1449 		    if ((start = STRSTR(start, cmd->gdb)) != NULL)
1450 			res = start;
1451 		    else
1452 			break;
1453 
1454 		/* strictly greater and not followed by NL */
1455 		if (res != NULL && *(res + len) != NL
1456 		    && cmd->echoed + STRLEN(cmd->echoed) > res + len)
1457 		{
1458 		    if (*(res + len) == BELL)
1459 		    {
1460 			clewn_beep();
1461 			*(res + len) = NUL;
1462 		    }
1463 		    xfree(cmd->readline);
1464 		    cmd->readline = (char_u *)clewn_strsave((char *)cmd->echoed);
1465 		    cmd->state = CS_DONE;
1466 		    return (char_u *)clewn_strsave((char *)cmd->readline);
1467 		}
1468 	    }
1469 
1470 	    /* A BELL: first character */
1471 	    if (cmd->cnt == 1 && *line == BELL)
1472 	    {
1473 		*line = NUL;
1474 		clewn_beep();
1475 		cmd->state = CS_DONE;
1476 		return (cmd->readline != NULL ?
1477 			(char_u *)clewn_strsave((char *)cmd->readline) : NULL);
1478 	    }
1479 
1480 	    if (cmd->cnt > 1)
1481 		cmd->state = CS_CHOICE;
1482 	    break;
1483 
1484 	case CS_CHOICE:
1485 	    /* The end of a list of completion choices */
1486 	    if (cmd->cnt == 1 && (res = eol_choices(cmd, obs)) != NULL)
1487 		return res;
1488 	    break;
1489     }
1490     return NULL;
1491 }
1492 
1493 /*
1494  * The end of a list of completion choices.
1495  * Return cmd to prompt the user with.
1496  */
1497     static char_u *
eol_choices(cmd,obs)1498 eol_choices(cmd, obs)
1499     cli_cmd_T *cmd;
1500     struct obstack *obs;
1501 {
1502     char_u *new;
1503 
1504     obstack_strcat(obs, cmd->readline);
1505     obstack_strcat0(obs, cmd->gdb);
1506     new = (char_u *)obstack_finish(obs);
1507 
1508     /* a match with the new readline */
1509     if (cmd->echoed != NULL && STRSTR(cmd->echoed, new) == cmd->echoed)
1510     {
1511 	xfree(cmd->readline);
1512 	cmd->readline = (char_u *)clewn_strsave((char *)cmd->echoed);
1513 	cmd->state = CS_DONE;
1514 	return (char_u *)clewn_strsave((char *)cmd->echoed);
1515     }
1516     return NULL;
1517 }
1518 
1519 #  ifdef GDB_LVL3_SUPPORT
1520 /* Initialize the gdb_T structure lvl3 component that lvl3 is responsible for */
1521     static void
clear_gdb_T(this)1522 clear_gdb_T(this)
1523     gdb_T *this;
1524 {
1525     varobj_T *item, *next;
1526 
1527     if (this != NULL)
1528     {
1529 	FREE(this->lvl3.result);
1530 
1531 	this->lvl3.get_source_list = TRUE;
1532 	FREE(this->lvl3.source_cur);
1533 	FREE(this->lvl3.source_list);
1534 
1535 	for (item = this->lvl3.varlist; item != NULL; item = next)
1536 	{
1537 	    next = item->next;
1538 	    xfree(item->name);
1539 	    xfree(item->format);
1540 	    xfree(item->expression);
1541 	    xfree(item);
1542 	}
1543 	this->lvl3.varlist = NULL;
1544 	this->lvl3.varitem = NULL;
1545     }
1546 }
1547 
1548 /* Initialize lvl3 function pointers */
1549     void
gdb_lvl3_init(this)1550 gdb_lvl3_init(this)
1551     gdb_T *this;
1552 {
1553     this->mode = GDB_MODE_LVL3;
1554     this->oobfunc = oobfunc;
1555     this->std_oobfunc = oobfunc;
1556     this->parse_output = gdb_parse_output_cli;
1557     this->gdb_docmd = gdb_docmd_cli;
1558     this->var_delete = NULL;
1559     this->clear_gdb_T = clear_gdb_T;
1560 }
1561 #  endif /* GDB_LVL3_SUPPORT */
1562 
1563 #  ifdef FEAT_GDB
1564 #   define SG_INTRO_2	"Vim |+gdb| level 2 mode\n\n"
1565 #   define SG_INTRO_3	"Vim |+gdb| level 3 mode\n\n"
1566 #  else
1567 #   define SG_INTRO_2	"...             \
1568                         \n... Clewn running GDB in level 2 mode\n...\n"
1569 #   define SG_INTRO_3	"...             \
1570                         \n... Clewn %s running GDB in level 3 mode\n...\n"
1571 #  endif
1572 #  define SG_INTERP	"server interpreter-exec mi -gdb-version\n"
1573 #  define SG_LVL_2	"server set annotate 2\n"
1574 #  define SG_LVL_3	"server set annotate 3\n"
1575 #  define SG_HEIGHT	"server set height "
1576 #  define SG_WIDTH	"server set width 0\n "
1577 #  define SG_EDITING	"server set editing on\n"
1578 #  define SG_VERSION	"server show version\n"
1579 
1580 /* SG_TIMEOUT must be quite big as we may have Clewn, Vim and GDB all
1581  * starting at the same time. Unless things go pretty bad in the parsing, we
1582  * always find the needle, so the user never wait SG_TIMEOUT. */
1583 #  define SG_TIMEOUT 120000 /* msecs for when the needle cannot be found */
1584 /*
1585  * Initialize gdb CLI (command line interface)
1586  * return OK when sucess, FAIL otherwise
1587  */
1588     int
gdb_setup_cli(this)1589 gdb_setup_cli(this)
1590     gdb_T *this;
1591 {
1592     char *err     = NULL;
1593     int needle    = FALSE;	/* defines when we can start writing to gdb console */
1594     int gdb_cnt   = 0;		/* count of received "(gdb)" prompts */
1595     int lvl3_mode = FALSE;	/* level */
1596     char_u *buff  = (char_u *)gdb_buf;/* can't add an int to the reference to an array */
1597     char * tty_name = NULL;
1598 #   ifndef FEAT_GDB
1599     char tmp[128];
1600 #   endif
1601     char_u *last;
1602     char_u *ptr;
1603     char_u *lpp_lines;
1604     char_u *line;
1605     int len;
1606 
1607     this->note = ANO_NONE;
1608 
1609     /* Does this GDB process supports "interpreter-exec" command ?
1610      * if yes we will use level 3 mode, otherwise level 2 mode */
1611     write(this->fd, SG_INTERP, strlen(SG_INTERP));
1612 
1613     /* discard gdb output till we find the needle SG_VERSION
1614      * MAX_BUFFSIZE must be greater than max gdb line length */
1615     for (last = (char_u *)gdb_buf; buff + MAX_BUFFSIZE - last > 1; )
1616     {
1617 	if ((len = gdb_read(this, last,
1618 			buff + MAX_BUFFSIZE - last, SG_TIMEOUT)) < 0)
1619 	{
1620 	    err = "Unable to read from GDB pseudo tty";
1621 	    goto fail;
1622 	}
1623 	else if (len == 0)	/* needle not found */
1624 	    break;
1625 
1626 	last += len;
1627 	ptr = (char_u *)gdb_buf;
1628 
1629 	/* First step: determine which level, process line by line */
1630 	do
1631 	{
1632 	    if (gdb_cnt >= 2)
1633 		break;
1634 
1635             if (*ptr == NL)
1636                 ptr++;
1637 
1638 	    if (STRSTR(ptr, "^done") == ptr)
1639 		lvl3_mode = TRUE;
1640 
1641 	    /* the first prompt is newline terminated (count it only once) */
1642 	    if (STRSTR(ptr, "(gdb) ") == ptr
1643 		    && (gdb_cnt == 1 || STRCHR(ptr, NL) != NULL))
1644 		gdb_cnt++;
1645 
1646 	    if (gdb_cnt == 2)
1647 	    {
1648 #  ifdef GDB_LVL3_SUPPORT
1649 		/* set annotation level 3 */
1650 		if (lvl3_mode)
1651 		    write(this->fd, SG_LVL_3, strlen(SG_LVL_3));
1652 		else
1653 #   ifdef GDB_LVL2_SUPPORT
1654 		    write(this->fd, SG_LVL_2, strlen(SG_LVL_2));
1655 #   else
1656 		{
1657 		    err = "This |+gdb| version does not support level 2 mode";
1658 		    goto fail;
1659 		}
1660 #   endif
1661 #  else /* LVL3 */
1662 		lvl3_mode = FALSE;
1663 #   ifdef GDB_LVL2_SUPPORT
1664 		/* set annotation level 2 */
1665 		if (! lvl3_mode)
1666 		    write(this->fd, SG_LVL_2, strlen(SG_LVL_2));
1667 #   endif
1668 #  endif /* LVL3 */
1669 
1670 #  ifdef FEAT_GDB   /* Clewn does not need this */
1671 		/* ANO_PMT_FORMORE happen every LPP_LINES and provide us a mean to abort
1672 		 * large output (in get_asm for example or any user cmd) */
1673 		write(this->fd, SG_HEIGHT, strlen(SG_HEIGHT));
1674 		lpp_lines = gdb_itoa(LPP_LINES);
1675 		write(this->fd, (char *)lpp_lines, strlen((char *)lpp_lines));
1676 		write(this->fd, "\n", 1);
1677 		write(this->fd, SG_WIDTH, strlen(SG_WIDTH));
1678 		write(this->fd, SG_EDITING, strlen(SG_EDITING));
1679 #  else
1680 		/* number of lines in a page is unlimited */
1681 		write(this->fd, SG_HEIGHT, strlen(SG_HEIGHT));
1682 		lpp_lines = gdb_itoa(0);
1683 		write(this->fd, lpp_lines, strlen(lpp_lines));
1684 		write(this->fd, "\n", 1);
1685 		write(this->fd, SG_WIDTH, strlen(SG_WIDTH));
1686 		write(this->fd, SG_EDITING, strlen(SG_EDITING));
1687 		write(this->fd, " \n", 2); /* avoid Undefined command: "server".  Try "help". */
1688 
1689 		/* `run' commands do input and output on clewn own terminal when possible */
1690 		if (isatty(1) && (tty_name=ttyname(1)) != NULL) {
1691 		    char_u * res = NULL;
1692 
1693 		    gdb_cat(&res, (char_u *)"server tty ");
1694 		    gdb_cat(&res, tty_name);
1695 		    gdb_cat(&res, (char_u *)"\n");
1696 		    write(this->fd, res, STRLEN(res));
1697 		    xfree(res);
1698 		}
1699 #  endif
1700 		write(this->fd, SG_VERSION, strlen(SG_VERSION));
1701 	    }
1702 	} while ((ptr = STRCHR(ptr, NL)) != NULL);
1703 
1704 	/* Second step: find the needle, process line by line */
1705 	do
1706 	{
1707 	    if (ptr == NULL)
1708 		break;
1709 
1710             if (*ptr == NL)
1711                 ptr++;
1712 
1713 	    /* looking for the needle after a prompt */
1714 	    if (this->note == ANO_PROMPT && STRSTR(ptr, SG_VERSION) == ptr)
1715 	    {
1716 		ptr += strlen(SG_VERSION);
1717 		needle = TRUE;
1718 	    }
1719 
1720 	    /* discard post-prompt */
1721 	    if (needle && this->note == ANO_POSTPROMPT)
1722 	    {
1723 		/* store a partial last line for later parse_output */
1724                 if ((line = (char_u *)strrchr(gdb_buf, (int)NL)) != NULL
1725                         && *(line + 1) != NUL)
1726                 {
1727                     xfree(this->line);
1728                     this->line = (char_u *)clewn_strsave((char *)(line + 1));
1729                     this->annoted = TRUE;
1730                 }
1731 
1732 		if (lvl3_mode)
1733 #  ifdef GDB_LVL3_SUPPORT
1734 		{
1735 #   ifdef FEAT_GDB
1736 		    gdb_popup_console(this);
1737 #   endif
1738 
1739 		    this->syntax = TRUE;	/* force syntax highlite */
1740 #   ifdef FEAT_GDB
1741 		    gdb_write_buf(this, (char_u *)SG_INTRO_3, TRUE);
1742 #   else
1743 		    sprintf(tmp, SG_INTRO_3, this->version);
1744 		    gdb_write_buf(this, tmp, TRUE);
1745 #   endif
1746 		    this->syntax = FALSE;
1747 
1748 #   ifdef FEAT_GDB  /* write unconditionally with Clewn */
1749 		    /* write the remaining part and display it */
1750 		    if (*ptr != NUL)
1751 #   endif
1752 			gdb_write_buf(this, ptr, TRUE);
1753 
1754 #   ifdef FEAT_GDB
1755 		    /* redraw gdb console window when displayed */
1756 		    gdb_redraw(this->buf);
1757 #   endif
1758 
1759 		    gdb_lvl3_init(this);
1760 		}
1761 #  else
1762 		{
1763 		    err = "This |+gdb| version does not support level 3 mode";
1764 		    goto fail;
1765 		}
1766 #  endif
1767 		else
1768 #  ifdef GDB_LVL2_SUPPORT
1769 		{
1770 #   ifdef FEAT_GDB
1771 		    gdb_popup_console(this);
1772 #   endif
1773 
1774 		    this->syntax = TRUE;	/* force syntax highlite */
1775 		    gdb_write_buf(this, (char_u *)SG_INTRO_2, TRUE);
1776 		    this->syntax = FALSE;
1777 
1778 #   ifdef FEAT_GDB   /* write unconditionally with Clewn */
1779 		    /* write the remaining part and display it */
1780 		    if (*ptr != NUL)
1781 #   endif
1782 			gdb_write_buf(this, ptr, TRUE);
1783 
1784 #   ifdef FEAT_GDB
1785 		    /* redraw gdb console window when displayed */
1786 		    gdb_redraw(this->buf);
1787 #   endif
1788 
1789 		    gdb_lvl2_init(this);
1790 		}
1791 #  else
1792 		{
1793 		    err = "This |+gdb| version does not support level 2 mode";
1794 		    goto fail;
1795 		}
1796 #  endif
1797 		if (tty_name)
1798 		    fprintf(stderr, "`run' commands do input and output on the terminal %s\n", tty_name);
1799 
1800 		return OK;
1801 	    }
1802 	} while ((ptr = parse_note(this, ptr)) != NULL);
1803 
1804 	/* left shift buffer to last start of line */
1805 	if ((ptr = (char_u *)strrchr((char *)gdb_buf, (int)NL)) != NULL)
1806 	{
1807 	    len = STRLEN(ptr + 1);
1808 	    clewn_memmove(gdb_buf, ptr + 1, len);
1809 	    last = (char_u *)gdb_buf + len;
1810 	}
1811     }
1812 
1813 #  ifdef GDB_LVL2_SUPPORT
1814     /* could not find the needle: hope for the best and fall back
1815      * to annotation level 2 and send version again */
1816     write(this->fd, SG_LVL_2, strlen(SG_LVL_2));
1817     write(this->fd, SG_VERSION, strlen(SG_VERSION));
1818 #   ifdef FEAT_GDB
1819     gdb_popup_console(this);
1820 #   endif
1821 
1822     this->syntax = TRUE;	/* force syntax highlite */
1823     gdb_write_buf(this, (char_u *)SG_INTRO_2, TRUE);
1824     this->syntax = FALSE;
1825 
1826     gdb_lvl2_init(this);
1827     return OK;
1828 #  else
1829     err = "This |+gdb| version does not support level 2 mode";
1830     goto fail;
1831 #  endif
1832 fail:
1833     gdb_close(this);
1834 
1835     if (err != NULL)
1836 	EMSG(_(err));
1837 
1838     return FAIL;
1839 }
1840 
1841 #  ifdef GDB_LVL3_SUPPORT
1842 /* Print a value in a netbeans balloon */
1843 #   define PRINT_VALUE	    "^done,value=\""
1844     char *
gdb_print_value(this,state,line,obs)1845 gdb_print_value(this, state, line, obs)
1846     gdb_T *this;
1847     int state;
1848     char_u *line;
1849     struct obstack *obs;
1850 {
1851 #   ifdef HAVE_CLEWN
1852     char_u * res = NULL;
1853     char_u * ptr;
1854     char_u * quote;
1855 
1856     switch(state)
1857     {
1858 	case OOB_CMD:
1859 	    if (this->balloon_txt != NULL) {
1860 		obstack_strcat(obs, "server interpreter-exec mi \"-data-evaluate-expression ");
1861 		obstack_strcat(obs, this->balloon_txt);
1862 		obstack_strcat0(obs, "\"\n");
1863 
1864 		FREE(this->lvl3.result);
1865 		return (char_u *)obstack_finish(obs);
1866 	    }
1867 	    break;
1868 
1869 	case OOB_COLLECT:
1870 	    gdb_cat(&res, this->lvl3.result);
1871 	    gdb_cat(&res, line);
1872 	    xfree(this->lvl3.result);
1873 	    this->lvl3.result = res;
1874 	    break;
1875 
1876 	case OOB_COMPLETE:
1877 	    if (this->lvl3.result != NULL
1878 		    && (ptr = STRSTR(this->lvl3.result, PRINT_VALUE)) != NULL
1879 		    && (ptr += strlen(PRINT_VALUE))
1880 		    && (quote = (char_u *)strrchr(ptr, '"')) != NULL)
1881 	    {
1882 		*quote = NUL;
1883 		obstack_strcat(obs, "\" ");
1884 		obstack_strcat(obs, this->balloon_txt);
1885 		obstack_strcat(obs, " = ");
1886 		obstack_strcat(obs, ptr);
1887 		obstack_strcat0(obs, " \"");
1888 
1889 		res = (char_u *)obstack_finish(obs);
1890 		gdb_showBalloon(res, obs);
1891 	    }
1892 
1893 	    FREE(this->balloon_txt);
1894 	    FREE(this->lvl3.result);
1895 	    break;
1896     }
1897 #   endif   /* HAVE_CLEWN*/
1898     return NULL;
1899 }
1900 #  endif    /* GDB_LVL3_SUPPORT */
1901 
1902 /* Get instruction at $pc */
1903     char *
gdb_get_pc(this,state,line,obs)1904 gdb_get_pc(this, state, line, obs)
1905     gdb_T *this;
1906     int state;
1907     char_u *line;
1908     struct obstack *obs;
1909 {
1910     char_u *ptr;
1911 
1912     if (obs) {}	    /* keep compiler happy */
1913 
1914     switch(state)
1915     {
1916 	case OOB_CMD:
1917 	    FREE(this->pc);
1918 
1919 	    if (this->state & GS_STOPPED)
1920 	    {
1921 		this->state &= ~GS_STOPPED;
1922 		return "server x/i $pc\n";
1923 	    }
1924 	    break;
1925 
1926 	case OOB_COLLECT:
1927 	    if ((this->pc = gdb_regexec(line, PAT_ADD, 1, NULL)) != NULL)
1928 	    {
1929 		/* Replace TAB with a space */
1930 		for (ptr = line; *ptr != NUL; ptr++)
1931 		    if (*ptr == TAB)
1932 			*ptr = ' ';
1933 
1934 		gdb_status(this, line, obs);
1935 	    }
1936 	    break;
1937     }
1938     return NULL;
1939 }
1940 
1941 /* Get frame info */
1942     char *
gdb_get_frame(this,state,line,obs)1943 gdb_get_frame(this, state, line, obs)
1944     gdb_T *this;
1945     int state;
1946     char_u *line;
1947     struct obstack *obs;
1948 {
1949     char_u *res = NULL;
1950 
1951     if (obs) {}	    /* keep compiler happy */
1952 
1953     switch(state)
1954     {
1955 	case OOB_CMD:
1956 	    FREE(this->oob_result);
1957 	    return "server frame\n";
1958 
1959 	case OOB_COLLECT:
1960 	    gdb_cat(&res, this->oob_result);
1961 	    gdb_cat(&res, line);
1962 	    xfree(this->oob_result);
1963 	    this->oob_result = res;
1964 	    break;
1965 
1966 	case OOB_COMPLETE:
1967 	    xfree(this->frame_pc);
1968 	    if (this->oob_result != NULL
1969 		    && (this->frame_pc = gdb_regexec(this->oob_result, PAT_FRAME, 1, NULL)) != NULL) {
1970 		xfree(this->asm_add);
1971 		this->asm_add = (char_u *)clewn_strsave((char *)this->frame_pc);
1972 	    }
1973 	    else {
1974 		if (this->pc != NULL) {
1975 		    this->frame_pc = (char_u *)clewn_strsave((char *)this->pc);
1976 		    xfree(this->asm_add);
1977 		    this->asm_add = (char_u *)clewn_strsave((char *)this->frame_pc);
1978 		}
1979 	    }
1980 
1981 	    FREE(this->oob_result);
1982 	    break;
1983     }
1984     return NULL;
1985 }
1986 
1987 #  ifdef GDB_LVL3_SUPPORT
1988 /* Stack info frame */
1989     char *
gdb_info_frame(this,state,line,obs)1990 gdb_info_frame(this, state, line, obs)
1991     gdb_T *this;
1992     int state;
1993     char_u *line;
1994     struct obstack *obs;
1995 {
1996     char_u *res = NULL;
1997 
1998     if (obs) {}	    /* keep compiler happy */
1999 
2000     switch(state)
2001     {
2002 	case OOB_CMD:
2003 	    FREE(this->lvl3.result);
2004 	    return "server info frame\n";
2005 
2006 	case OOB_COLLECT:
2007 	    gdb_cat(&res, this->lvl3.result);
2008 	    gdb_cat(&res, line);
2009 	    xfree(this->lvl3.result);
2010 	    this->lvl3.result = res;
2011 	    break;
2012 
2013 	case OOB_COMPLETE:
2014 	    this->frame_curlvl = -1;
2015 	    if (this->lvl3.result != NULL
2016 		    && (res = gdb_regexec(this->lvl3.result, PAT_INFO_FRAME, 1, NULL)) != NULL) {
2017 		this->frame_curlvl = atoi((char *)res);
2018 		xfree(res);
2019 	    }
2020 
2021 	    FREE(this->lvl3.result);
2022 	    break;
2023     }
2024     return NULL;
2025 }
2026 
2027 #   define SOURCE_FILENAME  "\",file=\""
2028 #   define SOURCE_LINENUM   "\",line=\""
2029 /* Change frame highlight according to new frame level */
2030     char *
gdb_stack_frame(this,state,line,obs)2031 gdb_stack_frame(this, state, line, obs)
2032     gdb_T *this;
2033     int state;
2034     char_u *line;
2035     struct obstack *obs;
2036 {
2037     char_u * res = NULL;
2038     int rc	 = -1;
2039     char tmp[32];
2040     char_u * fname;
2041     char_u * pnum;
2042     char_u * quote;
2043     char_u * ptr;
2044     linenr_T lnum;
2045 
2046     switch(state)
2047     {
2048 	case OOB_CMD:
2049 	    /* get info about frame_curlvl:
2050 	     * ^done,stack=[frame={level="1",addr="0x080483bb",func="main",file="cltest_main.c",line="12"}] */
2051 	    if (this->frame_curlvl >= 0) {
2052 		FREE(this->lvl3.result);
2053 
2054 		sprintf(tmp, "%d %d", this->frame_curlvl, this->frame_curlvl);
2055 		obstack_strcat(obs, "server interpreter-exec mi \"-stack-list-frames ");
2056 		obstack_strcat(obs, tmp);
2057 		obstack_strcat0(obs, "\"\n");
2058 		return (char *)obstack_finish(obs);
2059 	    }
2060 	    break;
2061 
2062 	case OOB_COLLECT:
2063 	    gdb_cat(&res, this->lvl3.result);
2064 	    gdb_cat(&res, line);
2065 	    xfree(this->lvl3.result);
2066 	    this->lvl3.result = res;
2067 	    break;
2068 
2069 	case OOB_COMPLETE:
2070 	    if (this->lvl3.result != NULL
2071 		    && (ptr = STRSTR(this->lvl3.result, SOURCE_FILENAME)) != NULL
2072 		    && (pnum = STRSTR(this->lvl3.result, SOURCE_LINENUM)) != NULL)
2073 	    {
2074 		pnum += strlen(SOURCE_FILENAME);
2075 		lnum = atoi((char *)pnum);
2076 
2077 		ptr += strlen(SOURCE_FILENAME);
2078 
2079 		if ((quote = STRCHR(ptr, '"')) != NULL) {
2080 		    fname = (char_u *)obstack_copy0(obs, ptr, (quote - ptr));
2081 
2082 		    rc = 0;
2083 
2084 		    /* set frame sign only if this is a new fname/lnum position */
2085 		    if (this->frame_fname == NULL
2086 			    || STRCMP(this->frame_fname, fname) != 0 || this->frame_lnum != lnum) {
2087 			FREE(this->frame_fname);
2088 			this->frame_fname = (char_u *)clewn_strsave((char *)fname);
2089 			this->frame_lnum = lnum;
2090 			rc = gdb_fr_set(this, fname, &lnum, obs);
2091 		    }
2092 		}
2093 	    }
2094 
2095 	    if (rc != 0 && p_asm != 0)
2096 		this->pool.hilite = TRUE;   /* do asm frame highliting */
2097 	    FREE(this->lvl3.result);
2098 	    break;
2099     }
2100     return NULL;
2101 }
2102 #  endif /* GDB_LVL3_SUPPORT */
2103 
2104 /* Get symbol file name */
2105     char *
gdb_get_sfile(this,state,line,obs)2106 gdb_get_sfile(this, state, line, obs)
2107     gdb_T *this;
2108     int state;
2109     char_u *line;
2110     struct obstack *obs;
2111 {
2112     char_u *res = NULL;
2113 
2114     switch(state)
2115     {
2116 	case OOB_CMD:
2117 	    return "server info target\n";
2118 
2119 	case OOB_COLLECT:
2120 	    if (this->oob.cnt == 1
2121 		    && (res = gdb_regexec(line, PAT_SFILE, 1, obs)) != NULL
2122 		    && (this->sfile == NULL || STRCMP(res, this->sfile) != 0))
2123 	    {
2124 		gdb_status(this, (char_u *)"new symbols", obs);
2125 		xfree(this->sfile);
2126 		this->sfile = (char_u *)clewn_strsave((char *)res);
2127 	    }
2128 	    break;
2129 
2130 	case OOB_COMPLETE:
2131 	    if (this->oob.cnt == 0)
2132 	    {
2133 		gdb_status(this, (char_u *)"empty target", obs);
2134 		FREE(this->sfile);
2135 	    }
2136 	    break;
2137     }
2138     return NULL;
2139 }
2140 
2141 /* Get GDB source directories */
2142     char *
gdb_get_sourcedir(this,state,line,obs)2143 gdb_get_sourcedir(this, state, line, obs)
2144     gdb_T *this;
2145     int state;
2146     char_u *line;
2147     struct obstack *obs;
2148 {
2149     char_u *res = NULL;
2150 
2151     if (obs) {}	    /* keep compiler happy */
2152 
2153     switch(state)
2154     {
2155 	case OOB_CMD:
2156 	    FREE(this->lvl3.result);
2157 	    return "server show directories\n";
2158 
2159 	case OOB_COLLECT:
2160 	    gdb_cat(&res, this->lvl3.result);
2161 	    gdb_cat(&res, line);
2162 	    xfree(this->lvl3.result);
2163 	    this->lvl3.result = res;
2164 	    break;
2165 
2166 	case OOB_COMPLETE:
2167 	    if (this->lvl3.result != NULL)
2168 	    {
2169 		xfree(this->directories);
2170 		this->directories = gdb_regexec(this->lvl3.result, PAT_DIR, 1, NULL);
2171 		FREE(this->lvl3.result);
2172 	    }
2173 	    break;
2174     }
2175     return NULL;
2176 }
2177 
2178 #ifdef GDB_LVL3_SUPPORT
2179 # ifndef FEAT_GDB
2180 /* Source the project file */
2181     char *
gdb_source_project(this,state,line,obs)2182 gdb_source_project(this, state, line, obs)
2183     gdb_T *this;
2184     int state;
2185     char_u *line;
2186     struct obstack *obs;
2187 {
2188     switch(state)
2189     {
2190 	case OOB_CMD:
2191 	    if (this->project_file != NULL
2192 		    && cnb_state()
2193 		    && this->project_state == PROJ_SOURCEIT)
2194 	    {
2195 		this->project_state = PROJ_DONE;
2196 		fprintf(stderr, "source %s\n", this->project_file);
2197 
2198 		if (this->sfile != NULL)
2199 		    fprintf(stderr, "Warning: symbol table \"%s\" was loaded before sourcing the project file\n", this->sfile);
2200 
2201 		obstack_strcat(obs, "server source ");
2202 		obstack_strcat(obs, this->project_file);
2203 		obstack_strcat0(obs, "\n");
2204 		return (char_u *)obstack_finish(obs);
2205 	    }
2206 	    break;
2207 
2208 	case OOB_COLLECT:
2209 	    if (line != NULL)
2210 		fprintf(stderr, "%s\n", line);
2211 	    break;
2212 
2213 	case OOB_COMPLETE:
2214 	    /* force getting the source file list from gdb */
2215 	    this->lvl3.get_source_list = TRUE;
2216 
2217 	    /* this is required after 'restart' to display the gdb prompt */
2218 	    fprintf(stderr, this->prompt);
2219 	    break;
2220     }
2221 
2222     return NULL;
2223 }
2224 
2225 #   define CWD_VALUE	"^done,cwd=\""
2226 /* Get current working directory */
2227     char *
gdb_get_pwd(this,state,line,obs)2228 gdb_get_pwd(this, state, line, obs)
2229     gdb_T *this;
2230     int state;
2231     char_u *line;
2232     struct obstack *obs;
2233 {
2234     char_u * res = NULL;
2235     char_u * ptr;
2236     char_u * quote;
2237 
2238     if (obs) {}	    /* keep compiler happy */
2239 
2240     switch(state)
2241     {
2242 	case OOB_CMD:
2243 	    if (this->mode != GDB_MODE_LVL2) {
2244 		FREE(this->lvl3.result);
2245 		return "server interpreter-exec mi \"-environment-pwd\"\n";
2246 	    }
2247 	    break;
2248 
2249 	case OOB_COLLECT:
2250 	    gdb_cat(&res, this->lvl3.result);
2251 	    gdb_cat(&res, line);
2252 	    xfree(this->lvl3.result);
2253 	    this->lvl3.result = res;
2254 	    break;
2255 
2256 	case OOB_COMPLETE:
2257 	    if (this->lvl3.result != NULL
2258 		    && (ptr = STRSTR(this->lvl3.result, CWD_VALUE)) != NULL
2259 		    && (ptr += strlen(CWD_VALUE))
2260 		    && (quote = (char_u *)strrchr(ptr, '"')) != NULL)
2261 	    {
2262 		*quote = NUL;
2263 		gdb_cat(&res, (char_u *)"cd ");
2264 		gdb_cat(&res, ptr);
2265 		gdb_cat(&res, (char_u *)"\n");
2266 		xfree(this->pwd);
2267 		this->pwd = res;
2268 	    }
2269 
2270 	    FREE(this->lvl3.result);
2271 	    break;
2272     }
2273     return NULL;
2274 }
2275 
2276 #   define ARGS_VALUE	"Argument list to give program being debugged when it is started is \""
2277 /* Get args */
2278     char *
gdb_get_args(this,state,line,obs)2279 gdb_get_args(this, state, line, obs)
2280     gdb_T *this;
2281     int state;
2282     char_u *line;
2283     struct obstack *obs;
2284 {
2285     char_u * res = NULL;
2286     char_u * ptr;
2287     char_u * quote;
2288 
2289     if (obs) {}	    /* keep compiler happy */
2290 
2291     switch(state)
2292     {
2293 	case OOB_CMD:
2294 	    FREE(this->lvl3.result);
2295 	    return "server show args\n";
2296 
2297 	case OOB_COLLECT:
2298 	    gdb_cat(&res, this->lvl3.result);
2299 	    gdb_cat(&res, line);
2300 	    xfree(this->lvl3.result);
2301 	    this->lvl3.result = res;
2302 	    break;
2303 
2304 	case OOB_COMPLETE:
2305 	    if (this->lvl3.result != NULL
2306 		    && (ptr = STRSTR(this->lvl3.result, ARGS_VALUE)) != NULL
2307 		    && (ptr += strlen(ARGS_VALUE))
2308 		    && (quote = (char_u *)strrchr(ptr, '"')) != NULL)
2309 	    {
2310 		*quote = NUL;
2311 		gdb_cat(&res, "set args ");
2312 		gdb_cat(&res, ptr);
2313 		gdb_cat(&res, "\n");
2314 		xfree(this->args);
2315 		this->args = res;
2316 	    }
2317 
2318 	    FREE(this->lvl3.result);
2319 	    break;
2320     }
2321     return NULL;
2322 }
2323 # endif
2324 
2325 /* Get GDB current source file */
2326     char *
gdb_source_cur(this,state,line,obs)2327 gdb_source_cur(this, state, line, obs)
2328     gdb_T *this;
2329     int state;
2330     char_u *line;
2331     struct obstack *obs;
2332 {
2333     char_u *res = NULL;
2334 
2335     if (obs) {}	    /* keep compiler happy */
2336 
2337     switch(state)
2338     {
2339 	case OOB_CMD:
2340 	    FREE(this->lvl3.source_cur);
2341 	    return "server interpreter-exec mi \"-file-list-exec-source-file\"\n";
2342 
2343 	case OOB_COLLECT:
2344 	    gdb_cat(&res, this->lvl3.source_cur);
2345 	    gdb_cat(&res, line);
2346 	    xfree(this->lvl3.source_cur);
2347 	    this->lvl3.source_cur = res;
2348 	    break;
2349 
2350 	case OOB_COMPLETE:
2351 	    break;
2352     }
2353     return NULL;
2354 }
2355 
2356 /* Get GDB current source file */
2357     char *
gdb_source_list(this,state,line,obs)2358 gdb_source_list(this, state, line, obs)
2359     gdb_T *this;
2360     int state;
2361     char_u *line;
2362     struct obstack *obs;
2363 {
2364     char_u *res = NULL;
2365 
2366     if (obs) {}	    /* keep compiler happy */
2367 
2368     switch(state)
2369     {
2370 	case OOB_CMD:
2371 	    if (this->lvl3.get_source_list || this->lvl3.source_list == NULL) {
2372 		FREE(this->lvl3.source_list);
2373 		this->lvl3.get_source_list = FALSE;
2374 		return "server interpreter-exec mi \"-file-list-exec-source-files\"\n";
2375 	    }
2376 	    break;
2377 
2378 	case OOB_COLLECT:
2379 	    gdb_cat(&res, this->lvl3.source_list);
2380 	    gdb_cat(&res, line);
2381 	    xfree(this->lvl3.source_list);
2382 	    this->lvl3.source_list = res;
2383 	    break;
2384 
2385 	case OOB_COMPLETE:
2386 	    break;
2387     }
2388     return NULL;
2389 }
2390 #endif /* GDB_LVL3_SUPPORT */
2391 
2392 #  ifdef GDB_LVL3_SUPPORT
2393 #   define BKPT_RECORD	"bkpt={number=\""
2394 #   define BKPT_ADDR	"\",addr=\""
2395 /*
2396  * When a breakpoint is being set and asm option is on, get the
2397  * instruction address of the last breakpoint, the one being set.
2398  * This address is used in get_asm() to disassemble the function
2399  * containing this address.
2400  */
2401     static char *
get_lastbp(this,state,line,obs)2402 get_lastbp(this, state, line, obs)
2403     gdb_T *this;
2404     int state;
2405     char_u *line;
2406     struct obstack *obs;
2407 {
2408     char_u *res    = NULL;
2409     int found      = FALSE;
2410     char_u *record = NULL;
2411     char_u *ptr;
2412     char_u *addr;
2413     bpinfo_T *p;
2414     int bp_num;
2415 
2416     if (obs) {}	    /* keep compiler happy */
2417 
2418     switch (state)
2419     {
2420 	case OOB_CMD:
2421 	    /* GDB sends sometimes ANO_BP_INVALID when stepping, even
2422 	     * though no breakpoints have been changed.
2423 	     * Avoid checking for last bp in this case, because this
2424 	     * may cause hiliting a bp in a new buffer when what is
2425 	     * expected is a new frame */
2426 	    if (this->bp_state & BPS_FR_INVALID)
2427 		return NULL;
2428 
2429 	    /* A breakpoint is being set in assembly */
2430 	    if (p_asm != 0 && (this->bp_state & BPS_INVALID)
2431 		    && (this->bp_state & BPS_BP_SET))
2432 	    {
2433 		this->bp_state &= ~BPS_BP_SET;
2434 		FREE(this->lvl3.result);
2435 
2436 		/* fetch GDB bp table info */
2437 		return "server interpreter-exec mi -break-list\n";
2438 	    }
2439 	    break;
2440 
2441 	case OOB_COLLECT:
2442 	    gdb_cat(&res, this->lvl3.result);
2443 	    gdb_cat(&res, line);
2444 	    xfree(this->lvl3.result);
2445 	    this->lvl3.result = res;
2446 	    break;
2447 
2448 	case OOB_COMPLETE:
2449 	    if ((ptr = this->lvl3.result) != NULL)
2450 	    {
2451 		/* search for last record in breakpoint table */
2452 		do
2453 		{
2454 		    if ((ptr = STRSTR(ptr, BKPT_RECORD)) != NULL)
2455 		    {
2456 			record = ptr;
2457 			ptr++;
2458 		    }
2459 		}
2460 		while (ptr != NULL);
2461 
2462 		/* last record */
2463 		if (record != NULL
2464 			&& (bp_num = atoi((char *)(record + strlen(BKPT_RECORD)))) > 0)
2465 		{
2466 		    /* look it up in bpinfo list */
2467 		    for (p = this->bpinfo; p != NULL; p = p->next)
2468 		    {
2469 			if (bp_num == p->id)
2470 			{
2471 			    found = TRUE;
2472 			    break;
2473 			}
2474 		    }
2475 
2476 		    /* not found: set asm_add so that get_asm will
2477 		     * do the disassembling */
2478 		    if (! found && (addr = STRSTR(record, BKPT_ADDR)) != NULL)
2479 		    {
2480 			xfree(this->asm_add);
2481 			this->asm_add =
2482 			    gdb_regexec(addr + strlen(BKPT_ADDR), PAT_ADD, 1, NULL);
2483 		    }
2484 		}
2485 
2486 		FREE(this->lvl3.result);
2487 	    }
2488 	    break;
2489     }
2490     return NULL;
2491 }
2492 #  endif /* GDB_LVL3_SUPPORT */
2493 
2494 /* Get the function name corresponding to asm_add */
2495     char *
gdb_get_asmfunc(this,state,line,obs)2496 gdb_get_asmfunc(this, state, line, obs)
2497     gdb_T *this;
2498     int state;
2499     char_u *line;
2500     struct obstack *obs;
2501 {
2502     switch(state)
2503     {
2504 	case OOB_CMD:
2505 	    if (this->asm_add != NULL)
2506 	    {
2507 		obstack_strcat(obs, "server info symbol 0x");
2508 		obstack_strcat(obs, this->asm_add);
2509 		obstack_strcat0(obs, "\n");
2510 		return (char *)obstack_finish(obs);
2511 	    }
2512 	    FREE(this->asm_func);
2513 	    break;
2514 
2515 	case OOB_COLLECT:
2516 	    xfree(this->asm_func);
2517 	    this->asm_func = gdb_regexec(line, PAT_ASM_FUNC, 1, NULL);
2518 	    break;
2519     }
2520     return NULL;
2521 }
2522 
2523 /*
2524  * This function is a hack to fix errors occuring in GDB command
2525  * "info symbol ADDR" that sometimes cannot find the symbol corresponding to
2526  * a given ADDR, when GDB command "print/a ADDR" can.
2527  * "print/a ADDR" is used as a last resort because it changes the value history.
2528  * "output/a ADDR" does not change the value history, but the output of this
2529  * command misses a newline.
2530  */
2531     char *
gdb_get_asmfunc_hack(this,state,line,obs)2532 gdb_get_asmfunc_hack(this, state, line, obs)
2533     gdb_T *this;
2534     int state;
2535     char_u *line;
2536     struct obstack *obs;
2537 {
2538     switch(state)
2539     {
2540 	case OOB_CMD:
2541 	    if (this->asm_add != NULL && this->asm_func == NULL)
2542 	    {
2543 		obstack_strcat(obs, "server print/a 0x");
2544 		obstack_strcat(obs, this->asm_add);
2545 		obstack_strcat0(obs, "\n");
2546 		return (char *)obstack_finish(obs);
2547 	    }
2548 	    break;
2549 
2550 	case OOB_COLLECT:
2551 	    xfree(this->asm_func);
2552 	    this->asm_func = gdb_regexec(line, PAT_ASM_FUNC_P, 1, NULL);
2553 	    break;
2554     }
2555     return NULL;
2556 }
2557 
2558 #  define ASM_ABORTED "DISASSEMBLY ABORTED"
2559 
2560 /*
2561  * Disassemble new function containing asm_add and highlight asm_add
2562  * if this->pool.hilite is TRUE
2563  */
2564     char *
gdb_get_asm(this,state,line,obs)2565 gdb_get_asm(this, state, line, obs)
2566     gdb_T *this;
2567     int state;
2568     char_u *line;
2569     struct obstack *obs;
2570 #  ifdef FEAT_GDB
2571 {
2572     buf_T *buf = this->pool.buf[this->pool.idx];
2573     buf_T *oldbuf = curbuf;
2574     char_u *res = NULL;
2575     int oldest  = 0;
2576     int age	= 0;
2577     linenr_T lnum;
2578     win_T *win;
2579     int i;
2580 
2581     if (p_asm == 0)
2582     {
2583 	FREE(this->asm_add);
2584 	return NULL;
2585     }
2586 
2587     lnum = (buf != NULL ? BUFLASTL(buf) : 0);
2588 
2589     switch (state)
2590     {
2591 	case OOB_CMD:
2592 	    if (this->asm_add != NULL && !gdb_as_frset(this, obs))
2593 	    {
2594 		/* pickup least recent buffer */
2595 		for (i = this->pool.max; i > 0; )
2596 		{
2597 		    i--;
2598 		    if (this->pool.age[i] >= age && this->pool.buf[i] != NULL)
2599 		    {
2600 			age = this->pool.age[i];
2601 			oldest = i;
2602 		    }
2603 		}
2604 
2605 		/* no buffers in pool */
2606 		if ((buf = this->pool.buf[oldest]) == NULL)
2607 		{
2608 		    this->pool.hilite = FALSE;
2609 		    FREE(this->asm_add);
2610 		    return NULL;
2611 		}
2612 		this->pool.idx = oldest;
2613 
2614 		/* clear the buffer */
2615 		gdb_clear_asmbuf(this, buf);
2616 
2617 		/* init msg_busy */
2618 		obstack_strcat(obs, "Disassembling 0x");
2619 		obstack_strcat0(obs, this->asm_add);
2620 		res = (char_u *)obstack_finish(obs);
2621 		gdb_msg_busy(res);
2622 
2623 		/* send cmd */
2624 		obstack_strcat(obs, "server disassemble 0x");
2625 		obstack_strcat(obs, this->asm_add);
2626 		obstack_strcat0(obs, "\n");
2627 		return (char *)obstack_finish(obs);
2628 	    }
2629 	    this->pool.hilite = FALSE;
2630 	    break;
2631 
2632 	case OOB_COLLECT:
2633 	    if (buf == NULL)
2634 		return NULL;
2635 	    curbuf = buf;
2636 
2637 	    /* concatenate with line after an annotation
2638 	     * and replace line, otherwise add */
2639 	    if (this->line != NULL && this->annoted)
2640 	    {
2641 		obstack_strcat(obs, this->line);
2642 		obstack_strcat0(obs, line);
2643 		line = (char_u *)obstack_finish(obs);
2644 		ml_delete(lnum--, FALSE);
2645 	    }
2646 
2647 	    /* first line: remove empty line after the inserted one */
2648 	    if (ml_append(lnum, line, 0, 0) == OK && lnum == 0)
2649 		ml_delete(buf->b_ml.ml_line_count, FALSE);
2650 	    curbuf = oldbuf;
2651 
2652 	    if ((this->oob.cnt % 1000) == 0)
2653 		gdb_msg_busy(NULL);
2654 
2655 	    xfree(this->line);
2656 	    this->line = (char_u *)clewn_strsave((char *)line);
2657 	    break;
2658 
2659 	case OOB_COMPLETE:
2660 	    if (buf == NULL)
2661 		return NULL;
2662 	    curbuf = buf;
2663 
2664 	    if (this->oob.state & OS_INTR)
2665 	    {
2666 		if (lnum >= 1 && STRCMP(ASM_ABORTED, ml_get(1)) != 0)
2667 		{
2668 		    /* Clear buffer when interrupted */
2669 		    while (lnum-- > 0)
2670 			ml_delete(buf->b_ml.ml_line_count, FALSE);
2671 
2672 		    ml_append(0, (char_u *)ASM_ABORTED, 0, 0);
2673 		    lnum = buf->b_ml.ml_line_count;
2674 		    changed_lines(1, 0, lnum, lnum);
2675 		    curbuf = oldbuf;
2676 
2677 		    this->pool.age[this->pool.idx] = ASM_OLD;
2678 		    gdb_edit_file(this, buf, NULL, 1, obs);
2679 		}
2680 
2681 		/* write the prompt */
2682 		gdb_write_buf(this, this->line, TRUE);
2683 		gdb_redraw(buf);
2684 	    }
2685 	    else
2686 	    {
2687 		changed_lines(1, 0, lnum, lnum);
2688 
2689 		/* set buffer name to function name */
2690 		if (this->asm_func != NULL)
2691 		{
2692 		    obstack_strcat(obs, this->asm_func);
2693 		    obstack_strcat0(obs, "-asm");
2694 		    res = (char_u *)obstack_finish(obs);
2695 		    gdb_as_setname(res);
2696 		}
2697 		curbuf = oldbuf;
2698 
2699 		/* highlite $asm_add and update window if displayed */
2700 		if (! gdb_as_frset(this, obs) && (win = gdb_btowin(buf)) != NULL)
2701 		{
2702 		    gdb_set_cursor(win, 1);
2703 		    redraw_win_later(win, NOT_VALID);
2704 		}
2705 	    }
2706 
2707 	    msg_clr_cmdline();
2708 	    FREE(this->asm_add);
2709 	    this->pool.hilite = FALSE;
2710 	    break;
2711     }
2712     return NULL;
2713 }
2714 #  else
2715 {
2716     char_u *res  = NULL;
2717     char_u *fname;
2718 
2719     if (p_asm == 0)
2720     {
2721 	FREE(this->asm_add);
2722 	return NULL;
2723     }
2724 
2725     switch (state)
2726     {
2727 	case OOB_CMD:
2728 	    if (this->asm_add != NULL && ! gdb_as_frset(this, obs))
2729 	    {
2730 		FREE(this->pool.name);
2731 
2732 		/* get a unique file name for this disassembled function
2733 		 * and open the file for creation
2734 		 * the file name suffix is '.clasm' so that it can be set
2735 		 * to 'autoread' by the runtime file clewn.vim */
2736 		if (this->asm_func != NULL) {
2737 		    obstack_strcat(obs, this->asm_func);
2738 		    obstack_strcat0(obs, ".clasm");
2739 		    fname = (char_u *)obstack_finish(obs);
2740 		}
2741 		if (this->asm_func == NULL || (this->pool.fd = clewn_opentmpfile(fname,
2742 			&(this->pool.name), 1)) == NULL)
2743 		{
2744 		    this->pool.hilite = FALSE;
2745 		    return NULL;
2746 		}
2747 		this->pool.line_offset = 0L;
2748 
2749 		/* create the buffer */
2750 		if ((this->pool.buf = cnb_create_buf(this->pool.name)) == -1)
2751 		{
2752 		    this->pool.hilite = FALSE;
2753 
2754 		    fclose(this->pool.fd);
2755 		    this->pool.fd = NULL;
2756 		    if (this->pool.name != NULL)
2757 			(void)unlink(this->pool.name);
2758 		    FREE(this->pool.name);
2759 		    return NULL;
2760 		}
2761 
2762 		/* init msg_busy */
2763 		obstack_strcat(obs, "Disassembling 0x");
2764 		obstack_strcat0(obs, this->asm_add);
2765 		res = (char_u *)obstack_finish(obs);
2766 		gdb_msg_busy(res);
2767 
2768 		/* send cmd */
2769 		this->lastline = 0;
2770 		obstack_strcat(obs, "server disassemble 0x");
2771 		obstack_strcat(obs, this->asm_add);
2772 		obstack_strcat0(obs, "\n");
2773 		return (char_u *)obstack_finish(obs);
2774 	    }
2775 	    this->pool.hilite = FALSE;
2776 	    break;
2777 
2778 	case OOB_COLLECT:
2779 	    if (this->pool.fd == NULL)
2780 		goto fail;
2781 
2782 	    /* ignore when interrupted */
2783 	    if (this->oob.state & OS_INTR)
2784 		return NULL;
2785 
2786 	    /* concatenate with line after an annotation
2787 	     * and replace line, otherwise add */
2788 	    if (this->line != NULL && this->annoted)
2789 	    {
2790 		obstack_strcat(obs, this->line);
2791 		obstack_strcat0(obs, line);
2792 		line = (char_u *)obstack_finish(obs);
2793 
2794 		this->lastline--;
2795 		if (fseek(this->pool.fd, this->pool.line_offset, SEEK_SET) != 0)
2796 		    goto fail;
2797 	    }
2798 
2799 	    /* write a newline except at first line */
2800 	    if (this->lastline != 0)
2801 	    {
2802 		if ((this->pool.line_offset = ftell(this->pool.fd)) == -1
2803 			|| fputs("\n", this->pool.fd) < 0)
2804 		    goto fail;
2805 	    }
2806 	    this->lastline++;
2807 
2808 	    /* write the line */
2809 	    if (fputs(line, this->pool.fd) < 0)
2810 		goto fail;
2811 
2812 	    if ((this->oob.cnt % 400) == 0)
2813 		gdb_msg_busy(NULL);
2814 
2815 	    xfree(this->line);
2816 	    this->line = (char_u *)clewn_strsave((char *)line);
2817 	    break;
2818 
2819 	case OOB_COMPLETE:
2820 	    if (this->pool.fd == NULL)
2821 		goto fail;
2822 
2823 	    if (this->oob.state & OS_INTR)
2824 	    {
2825 		FREE(this->asm_add);
2826 		this->pool.hilite = FALSE;
2827 		goto fail;
2828 	    }
2829 	    else
2830 	    {
2831 		/* highlite $asm_add */
2832 		(void)gdb_as_frset(this, obs);
2833 
2834 		/* write last new line */
2835 		if (fputs("\n", this->pool.fd) < 0)
2836 		    goto fail;
2837 
2838 		/* clear the line */
2839 		gdb_msg_busy("FIN");
2840 
2841 		/* set the buffer as an asm buffer */
2842 		cnb_set_asm(this->pool.buf);
2843 	    }
2844 
2845 	    FREE(this->asm_add);
2846 
2847 	    this->pool.buf = -1;
2848 	    fclose(this->pool.fd);
2849 	    this->pool.fd = NULL;
2850 	    FREE(this->pool.name);
2851 	    this->pool.hilite = FALSE;
2852 	    break;
2853     }
2854     return NULL;
2855 fail:
2856     /* clear the line */
2857     gdb_msg_busy("FIN");
2858 
2859     cnb_kill(this->pool.buf);
2860     this->pool.buf = -1;
2861 
2862     if (this->pool.fd != NULL)
2863 	fclose(this->pool.fd);
2864     this->pool.fd = NULL;
2865 
2866     if (this->pool.name != NULL)
2867 	(void)unlink(this->pool.name);
2868     FREE(this->pool.name);
2869     return NULL;
2870 }
2871 #  endif /* FEAT_GDB */
2872 
2873 #  ifdef GDB_LVL3_SUPPORT
2874 /*
2875  * Get the breakpoints info record table.
2876  */
2877     static char *
get_bp(this,state,line,obs)2878 get_bp(this, state, line, obs)
2879     gdb_T *this;
2880     int state;
2881     char_u *line;
2882     struct obstack *obs;
2883 {
2884     char_u *res    = NULL;
2885     char_u *record = NULL;
2886     char_u *ptr;
2887     bpinfo_T *p;
2888 
2889     switch (state)
2890     {
2891 	case OOB_CMD:
2892 	    /* gdb 6.4 does not provide anymore the right annotations for breakpoints
2893 	     * when in level 3 (note that they are still there when setting annotate
2894 	     * level 2, I thought level 2 was deprecated, what a zoo !), so we look
2895 	     * for new or changed breakpoints systematically now */
2896 	    if (this->mode == GDB_MODE_LVL3)
2897 		this->bp_state = BPS_INVALID;
2898 
2899 	    /* When an ANO_BP_INVALID annotation has been received,
2900 	     * or when we are stepping (more accurately: got a new frame):
2901 	     * fetch bp table */
2902 	    if (this->bp_state & BPS_INVALID || this->bp_state & BPS_FR_INVALID)
2903 	    {
2904 		FREE(this->lvl3.result);
2905 		this->bufIsChanged = FALSE;
2906 
2907 		/* handle case where an error occured last time */
2908 		FREE(this->record);
2909 		gdb_free_bplist(&(this->tmplist));
2910 
2911 		/* fetch GDB bp table info */
2912 		return "server interpreter-exec mi -break-list\n";
2913 	    }
2914 
2915 	    this->bp_state &= ~BPS_INVALID;
2916 	    this->bp_state &= ~BPS_FR_INVALID;
2917 	    this->bp_state &= ~BPS_BP_HIT;
2918 	    break;
2919 
2920 	case OOB_COLLECT:
2921 	    gdb_cat(&res, this->lvl3.result);
2922 	    gdb_cat(&res, line);
2923 	    xfree(this->lvl3.result);
2924 	    this->lvl3.result = res;
2925 	    break;
2926 
2927 	case OOB_COMPLETE:
2928 	    if ((ptr = this->lvl3.result) != NULL)
2929 	    {
2930 		/* process all records except last */
2931 		do
2932 		{
2933 		    if ((ptr = STRSTR(ptr, BKPT_RECORD)) != NULL
2934 			    && ptr > this->lvl3.result)
2935 		    {
2936 			*(ptr - 1) = NUL;
2937 			if (record != NULL)
2938 			    process_record(this, record, obs);
2939 
2940 			record = ptr;
2941 			ptr++;
2942 		    }
2943 		}
2944 		while (ptr != NULL);
2945 
2946 		/* process last  record */
2947 		if (record != NULL)
2948 		    process_record(this, record, obs);
2949 
2950 		FREE(this->record);
2951 
2952 		/* All records left in the old table are breakpoints that have
2953 		 * been deleted: delete the corresponding highliting sign */
2954 		for (p = this->bpinfo; p != NULL; p = p->next)
2955 		    gdb_unlite(BP_SIGN_ID(p->id));
2956 
2957 		this->bp_state &= ~BPS_INVALID;
2958 		this->bp_state &= ~BPS_FR_INVALID;
2959 		this->bp_state &= ~BPS_BP_HIT;
2960 
2961 		/* replace with new table */
2962 		gdb_free_bplist(&(this->bpinfo));
2963 		this->bpinfo = this->tmplist;
2964 		this->tmplist = NULL;
2965 
2966 		FREE(this->lvl3.result);
2967 	    }
2968 	    break;
2969     }
2970     return NULL;
2971 }
2972 
2973 #   define BKPT_ENABLED	    "\",enabled=\""
2974 #   define BKPT_DISP	    "\",disp=\""
2975 #   define BKPT_SCRIPT	    "\",script={"
2976 #   define BKPT_TYPE	    "\",type=\"breakpoint\""
2977 #   define BKPT_LINE	    "\",line=\""
2978 #   define BKPT_SOURCE	    "\",file=\""
2979 #   define BKPT_AT	    "\",at=\"<"
2980 /* Process the current info record */
2981     static void
process_record(this,record,obs)2982 process_record(this, record, obs)
2983     gdb_T *this;
2984     char_u *record;
2985     struct obstack *obs;
2986 {
2987     char_u *bp_add    = NULL;
2988     char_u *bp_line   = NULL;
2989     char_u *bp_source = NULL;
2990     char_u *bp_at     = NULL;
2991     char_u *ptr;
2992     char_u *end;
2993     char_u *quote;
2994     char_u *plus;
2995 
2996     /* allocate a new record or reuse an existing one
2997      * and initialize its fields */
2998     if (this->record == NULL)
2999 	this->record = (bpinfo_T *)xcalloc(sizeof(bpinfo_T));
3000 
3001     this->record->id		= -1;
3002     this->record->enabled	= TRUE;
3003 #   ifdef BP_INVALID_ANO_MISSING
3004     this->record->disposition	= TRUE;
3005 #   endif
3006     this->record->cont		= FALSE;
3007 #   ifdef FEAT_GDB
3008     this->record->buf		= NULL;
3009 #   else
3010     this->record->buf		= -1;
3011     this->record->typenr_en	= -1;
3012     this->record->typenr_dis	= -1;
3013 #   endif
3014     this->record->lnum		= 0;
3015     this->record->next		= NULL;
3016 
3017     /* breakpoint number */
3018     this->record->id = atoi((char *)(record + strlen(BKPT_RECORD)));
3019 
3020     /* enabled state */
3021     if ((ptr = STRSTR(record, BKPT_ENABLED)) != NULL
3022 	    && *(ptr + strlen(BKPT_ENABLED)) == 'n')
3023 	this->record->enabled = FALSE;
3024 
3025 #   ifdef BP_INVALID_ANO_MISSING
3026     /* disposition */
3027     if ((ptr = STRSTR(record, BKPT_DISP)) != NULL
3028 	    && STRSTR(ptr + strlen(BKPT_DISP), "keep") == NULL)
3029 	this->record->disposition = FALSE;
3030 #   endif
3031 
3032     /* parse script for 'continue' as last statement */
3033     if ((ptr = STRSTR(record, BKPT_SCRIPT)) != NULL)
3034     {
3035 	ptr += strlen(BKPT_SCRIPT);
3036 	if ((end = STRCHR(ptr, '}')) != NULL)
3037 	{
3038 	    while ((ptr = STRCHR(ptr, '"')) != NULL && ptr < end)
3039 	    {
3040 		ptr++;
3041 		if (gdb_regexec(ptr, PAT_BP_CONT, 1, obs) != NULL
3042 			|| gdb_regexec(ptr, PAT_BP_CONT, 2, obs) != NULL)
3043 		{
3044 		    this->record->cont = TRUE;    /* continue */
3045 		    break;
3046 		}
3047 	    }
3048 	}
3049     }
3050 
3051     /* sanity check and discard watchpoints and others */
3052     if (this->record->id <= 0 || STRSTR(record, BKPT_TYPE) == NULL)
3053 	return;
3054 
3055     /* address */
3056     if ((ptr = STRSTR(record, BKPT_ADDR)) != NULL)
3057 	bp_add = gdb_regexec(ptr + strlen(BKPT_ADDR), PAT_ADD, 1, obs);
3058 
3059     /* line */
3060     if ((ptr = STRSTR(record, BKPT_LINE)) != NULL)
3061     {
3062 	ptr += strlen(BKPT_LINE);
3063 	if ((quote = STRCHR(ptr, '"')) != NULL)
3064 	    bp_line = (char_u *)obstack_copy0(obs, ptr, (quote - ptr));
3065     }
3066 
3067     /* source */
3068     if ((ptr = STRSTR(record, BKPT_SOURCE)) != NULL)
3069     {
3070 	ptr += strlen(BKPT_SOURCE);
3071 	if ((quote = STRCHR(ptr, '"')) != NULL)
3072 	    bp_source = (char_u *)obstack_copy0(obs, ptr, (quote - ptr));
3073     }
3074 
3075     /* at */
3076     if ((ptr = STRSTR(record, BKPT_AT)) != NULL)
3077     {
3078 	ptr += strlen(BKPT_AT);
3079 	if ((quote = STRCHR(ptr, '>')) != NULL)
3080 	{
3081 	    if ((plus = STRCHR(ptr, '+')) != NULL && plus < quote)
3082 		bp_at = (char_u *)obstack_copy0(obs, ptr, (plus - ptr));
3083 	    else
3084 		bp_at = (char_u *)obstack_copy0(obs, ptr, (quote - ptr));
3085 	}
3086     }
3087 
3088     gdb_process_record(this, bp_add, bp_at, bp_line, bp_source, obs);
3089 }
3090 
3091 /* Update the variables objects and the variables window */
3092     static char *
varobj_update(this,state,line,obs)3093 varobj_update(this, state, line, obs)
3094     gdb_T *this;
3095     int state;
3096     char_u *line;
3097     struct obstack *obs;
3098 {
3099 #  ifdef FEAT_GDB
3100     char_u *ptrn;
3101 #  else
3102     static char *result = NULL;	    /* mark the start and end of object operations */
3103 #  endif
3104     char_u *res  = NULL;
3105     varobj_T *obj;
3106 
3107     switch (state)
3108     {
3109 	case OOB_CMD:
3110 	    if (this->lvl3.varitem == NULL)
3111 	    {
3112 		/* start with first in list */
3113 		this->lvl3.varitem = this->lvl3.varlist;
3114 		this->lvl3.varnext_cmd = VCMD_INIT;
3115 	    }
3116 oob_cmd:
3117     /* next OOB_CMD */
3118 	    if ((obj = this->lvl3.varitem) != NULL)
3119 	    {
3120 		FREE(this->lvl3.result);
3121 
3122 		/* create a new object and give it a name */
3123 		if (this->lvl3.varnext_cmd == VCMD_INIT && obj->name == NULL)
3124 		{
3125 		    if (
3126 #   ifdef FEAT_GDB
3127 			    this->var_buf != NULL
3128 #   else
3129 			    this->var_buf > 0
3130 #   endif
3131 		       )
3132 		    {
3133 			if (obj->format != NULL)
3134 			    this->lvl3.varnext_cmd = VCMD_FORMAT;
3135 			else
3136 			    this->lvl3.varnext_cmd = VCMD_PRINT;
3137 
3138 			this->lvl3.varcmd = VCMD_CREATE;
3139 
3140 			obstack_strcat(obs, "server interpreter-exec mi \"-var-create - * (");
3141 			obstack_strcat(obs, obj->expression);
3142 			obstack_strcat0(obs, ")\"\n");
3143 			return (char *)obstack_finish(obs);
3144 		    }
3145 		    else
3146 		    {
3147 			/* remove silently from list */
3148 			remove_object(this, obj);
3149 			goto oob_cmd;
3150 		    }
3151 		}
3152 
3153 		/* sanity check: an object must have a name
3154 		 * this should never occur */
3155 		if (obj->name == NULL)
3156 		{
3157 		    /* silently ignore this error */
3158 		    this->lvl3.varnext_cmd = VCMD_INIT;
3159 		    this->lvl3.varitem = obj->next;
3160 		    goto oob_cmd;
3161 		}
3162 
3163 		/* search for the object in the variables window
3164 		 * if it does not exist, then -var-delete it */
3165 		if (this->lvl3.varnext_cmd == VCMD_INIT)
3166 		{
3167 #  ifdef FEAT_GDB
3168 		    pos_T pos;
3169 
3170 		    pos.lnum = 1;
3171 		    pos.col = 0;
3172 
3173 		    obstack_strcat(obs, "^\\s*");
3174 		    obstack_strcat(obs, obj->name);
3175 		    obstack_strcat0(obs, ":");
3176 		    ptrn = (char_u *)obstack_finish(obs);
3177 
3178 		    if (this->var_buf == NULL
3179 			    || (this->var_buf->b_ml.ml_flags & ML_EMPTY)
3180 			    || (searchit(NULL, this->var_buf, &pos,
3181 				    FORWARD, ptrn, 1L, SEARCH_KEEP, RE_LAST, (linenr_T)0, NULL) == FAIL))
3182 #  else
3183 		    int lnum;
3184 
3185 		    if (this->var_buf <= 0 || cnb_search_obj(obj->name, &lnum) == NULL)
3186 #  endif
3187 		    {
3188 			/* not in gdb variables window, delete it */
3189 			this->lvl3.varcmd = VCMD_DELETE;
3190 
3191 			obstack_strcat(obs, "server interpreter-exec mi \"-var-delete var");
3192 			obstack_strcat(obs, obj->name);
3193 			obstack_strcat0(obs, "\"\n");
3194 			return (char *)obstack_finish(obs);
3195 		    }
3196 		}
3197 
3198 		/* list children if any (need to run this cmd before update) */
3199 		if (this->lvl3.varnext_cmd == VCMD_INIT)
3200 		{
3201 		    this->lvl3.varnext_cmd = VCMD_UPDATE;
3202 
3203 		    if (obj->children)
3204 		    {
3205 			this->lvl3.varcmd = VCMD_CHILDREN;
3206 
3207 			obstack_strcat(obs, "server interpreter-exec mi \"-var-list-children var");
3208 			obstack_strcat(obs, obj->name);
3209 			obstack_strcat0(obs, "\"\n");
3210 			return (char *)obstack_finish(obs);
3211 		    }
3212 		}
3213 
3214 		/* set the format */
3215 		if (this->lvl3.varnext_cmd == VCMD_FORMAT)
3216 		{
3217 		    if (obj->format != NULL && STRLEN(obj->format) == 2)
3218 		    {
3219 			obstack_strcat(obs, "server interpreter-exec mi \"-var-set-format var");
3220 			obstack_strcat(obs, obj->name);
3221 
3222 			switch(*(obj->format + 1))
3223 			{
3224 			    case 't':
3225 				obstack_strcat0(obs, " binary\"\n");
3226 				break;
3227 			    case 'd':
3228 				obstack_strcat0(obs, " decimal\"\n");
3229 				break;
3230 			    case 'x':
3231 				obstack_strcat0(obs, " hexadecimal\"\n");
3232 				break;
3233 			    case 'o':
3234 				obstack_strcat0(obs, " octal\"\n");
3235 				break;
3236 			    default:
3237 				obstack_strcat0(obs, " natural\"\n");
3238 				break;
3239 			}
3240 
3241 			this->lvl3.varnext_cmd = VCMD_PRINT;
3242 			this->lvl3.varcmd = VCMD_FORMAT;
3243 
3244 			return (char *)obstack_finish(obs);
3245 		    }
3246 		    else
3247 		    {
3248 			this->lvl3.varnext_cmd = VCMD_INIT;
3249 			this->lvl3.varitem = obj->next;
3250 			goto oob_cmd;
3251 		    }
3252 		}
3253 
3254 		/* update object */
3255 		if (this->lvl3.varnext_cmd == VCMD_UPDATE)
3256 		{
3257 		    this->lvl3.varnext_cmd = VCMD_PRINT;
3258 		    this->lvl3.varcmd = VCMD_UPDATE;
3259 
3260 		    obstack_strcat(obs, "server interpreter-exec mi \"-var-update var");
3261 		    obstack_strcat(obs, obj->name);
3262 		    obstack_strcat0(obs, "\"\n");
3263 		    return (char *)obstack_finish(obs);
3264 		}
3265 
3266 		/* print */
3267 		if (this->lvl3.varnext_cmd == VCMD_PRINT)
3268 		{
3269 		    obj->state &= ~VS_ERROR;
3270 		    this->lvl3.varcmd = VCMD_PRINT;
3271 
3272 		    obstack_strcat(obs, "server output ");
3273 		    obstack_strcat(obs, obj->format);
3274 		    obstack_strcat(obs, " ");
3275 		    obstack_strcat(obs, obj->expression);
3276 		    obstack_strcat0(obs, "\n");
3277 		    return (char *)obstack_finish(obs);
3278 		}
3279 
3280 		/* evaluate object expression */
3281 		if (this->lvl3.varnext_cmd == VCMD_EVALUATE)
3282 		{
3283 		    this->lvl3.varcmd = VCMD_EVALUATE;
3284 
3285 		    obstack_strcat(obs, "server interpreter-exec mi \"-var-evaluate-expression var");
3286 		    obstack_strcat(obs, obj->name);
3287 		    obstack_strcat0(obs, "\"\n");
3288 		    return (char *)obstack_finish(obs);
3289 		}
3290 	    }
3291 	    break;
3292 
3293 	case OOB_COLLECT:
3294 	    gdb_cat(&res, this->lvl3.result);
3295 	    gdb_cat(&res, line);
3296 	    xfree(this->lvl3.result);
3297 	    this->lvl3.result = res;
3298 	    break;
3299 
3300 	case OOB_COMPLETE:
3301 #  ifdef FEAT_GDB
3302 	    return varobj_complete(this, obs);
3303 #  else
3304 	    /* start of object operations */
3305 	    if (result == NULL && this->var_buf > 0)
3306 		cnb_startAtomic(this->var_buf);
3307 
3308 	    result = varobj_complete(this, obs);
3309 
3310 	    /* end of object operations */
3311 	    if (result == NULL && this->var_buf > 0)
3312 		cnb_endAtomic(this->var_buf);
3313 
3314 	    return result;
3315 #  endif
3316     }
3317 
3318     return NULL;
3319 }
3320 
3321 #   define VOBJ_NAME	    "^done,name=\"var"
3322 #   define VOBJ_CHILD	    "\",numchild=\""
3323 #   define VOBJ_SCOPE	    "\",in_scope=\""
3324 #   define VOBJ_VALUE	    "^done,value=\""
3325 /*
3326  * Process the OOB_COMPLETE part of varobj_update()
3327  * Return anything not NULL except when last object in varlist
3328  * and after the last varcmd which may be: a failed VCMD_CREATE,
3329  * VCMD_DELETE, highlighted VCMD_UPDATE, VCMD_PRINT, VCMD_EVALUATE
3330  */
3331     static char *
varobj_complete(this,obs)3332 varobj_complete(this, obs)
3333     gdb_T *this;
3334     struct obstack *obs;
3335 {
3336     char_u *displine;	/* the new display item line */
3337     char_u *res;
3338 #  ifdef FEAT_GDB
3339     buf_T *oldbuf    = curbuf;
3340     linenr_T lnum;
3341     win_T *win;
3342 #  endif
3343     varobj_T *obj;
3344     char_u *ptr;
3345     char_u *last;
3346     char_u *child;
3347     char_u *quote;
3348 
3349     if ((obj = this->lvl3.varitem) != NULL)
3350     {
3351 	switch (this->lvl3.varcmd)
3352 	{
3353 	    case VCMD_CREATE:
3354 		/* result of object creation */
3355 		if (this->lvl3.result != NULL
3356 			&& (ptr = STRSTR(this->lvl3.result, VOBJ_NAME)) != NULL
3357 			&& (ptr += strlen(VOBJ_NAME))
3358 			&& (quote = STRCHR(ptr, '"')) != NULL
3359 			&& (child = STRSTR(this->lvl3.result, VOBJ_CHILD)) != NULL)
3360 		{
3361 		    obj->name = (char_u *)clewn_strnsave((char *)ptr, (quote - ptr));
3362 		    obj->children = (atoi((char *)(child + strlen(VOBJ_CHILD))) > 0);
3363 
3364 		    FREE(this->lvl3.result);
3365 		    return (char *)obj;   /* next command */
3366 		}
3367 		else
3368 		{
3369 		    EMSG(_("Unable to create variable object"));
3370 		    remove_object(this, obj);
3371 		    FREE(this->lvl3.result);
3372 		    this->lvl3.varnext_cmd = VCMD_INIT;
3373 		    return (char *)this->lvl3.varitem;  /* next object */
3374 		}
3375 		break;
3376 
3377 	    case VCMD_DELETE:
3378 		remove_object(this, obj);
3379 		FREE(this->lvl3.result);
3380 		this->lvl3.varnext_cmd = VCMD_INIT;
3381 		return (char *)this->lvl3.varitem;  /* next object */
3382 
3383 	    case VCMD_CHILDREN:
3384 		FREE(this->lvl3.result);
3385 		return (char *)obj;   /* next command */
3386 
3387 	    case VCMD_FORMAT:
3388 		FREE(this->lvl3.result);
3389 		return (char *)obj;   /* next command */
3390 
3391 	    case VCMD_UPDATE:
3392 		if (this->lvl3.result != NULL
3393 			&&(ptr = STRSTR(this->lvl3.result, VOBJ_SCOPE)) != NULL)
3394 		{
3395 		    ptr += strlen(VOBJ_SCOPE);
3396 		    if ((STRSTR(ptr, "false")) == ptr)
3397 		    {
3398 			/* set "out of scope" highlighting (={-}) */
3399 			varobj_hilite(this, obj, (int)'-', obs);
3400 			goto nextobj;
3401 		    }
3402 		    else
3403 		    {
3404 			/* object needs updating */
3405 			FREE(this->lvl3.result);
3406 			return (char *)obj;   /* next command */
3407 		    }
3408 		}
3409 		else
3410 		{
3411 		    /* turn off highlighting */
3412 		    varobj_hilite(this, obj, (int)'=', obs);
3413 		    goto nextobj;
3414 		}
3415 		break;
3416 
3417 	    case VCMD_PRINT:
3418 		/* fall back to GDB/MI when unable to print expression
3419 		 * because it's not the right frame */
3420 		if (obj->state & VS_ERROR)
3421 		{
3422 		    obj->state &= ~VS_ERROR;
3423 		    this->lvl3.varnext_cmd = VCMD_EVALUATE;
3424 		    FREE(this->lvl3.result);
3425 		    return (char *)obj;   /* next command */
3426 		}
3427 
3428 		/* build the display line including ={*}, the hiliting sign */
3429 		obstack_strcat(obs, obj->name);
3430 		obstack_strcat(obs, ":");
3431 		obstack_strcat(obs, obj->format);
3432 		obstack_strcat(obs, " ");
3433 		obstack_strcat(obs, obj->expression);
3434 		obstack_strcat(obs, " ={*} ");
3435 		if (this->lvl3.result != NULL) {
3436 		    obstack_strcat0(obs, this->lvl3.result);
3437 		}
3438 		displine = (char_u *)obstack_finish(obs);
3439 
3440 		/* add the newly created object to variables window */
3441 		if (obj->state & VS_INIT)
3442 		{
3443 #  ifdef FEAT_GDB
3444 		    if (this->var_buf != NULL)
3445 		    {
3446 			lnum = BUFLASTL(this->var_buf);
3447 
3448 			/* edit variables buffer in available window */
3449 			if (gdb_edit_file(this, this->var_buf, NULL, lnum, obs) != NULL)
3450 			{
3451 			    /* add to variables buffer */
3452 			    if (ml_append(lnum, displine, 0, 0) == OK)
3453 			    {
3454 				/* first line ever: remove empty line after the
3455 				 * one just inserted */
3456 				if (lnum == 0)
3457 				    ml_delete(this->var_buf->b_ml.ml_line_count, FALSE);
3458 
3459 				changed_lines(this->var_buf->b_ml.ml_line_count - 1,
3460 					0, this->var_buf->b_ml.ml_line_count, 1);
3461 			    }
3462 
3463 			    /* update top line */
3464 			    curwin->w_cursor.lnum = this->var_buf->b_ml.ml_line_count;
3465 			    update_topline();
3466 
3467 			    /* status line changed */
3468 			    curwin->w_redr_status = TRUE;
3469 
3470 			    /* move back to previous window if still there */
3471 			    if ((win = gdb_btowin(oldbuf)) != NULL)
3472 				win_goto(win);
3473 			}
3474 			obj->state &= ~VS_INIT;
3475 		    }
3476 #  else
3477 		    if (this->var_buf > 0)
3478 		    {
3479 			cnb_append(this->var_buf, displine, obs);
3480 			obj->state &= ~VS_INIT;
3481 		    }
3482 #  endif
3483 		}
3484 
3485 		/* update and highlight object value */
3486 		else
3487 		    varobj_replace(this, obj, displine, obs);
3488 
3489 		goto nextobj;
3490 
3491 	    case VCMD_EVALUATE:
3492 		if (this->lvl3.result != NULL
3493 			&& (ptr = STRSTR(this->lvl3.result, VOBJ_VALUE)) != NULL
3494 			&& (ptr += strlen(VOBJ_VALUE))
3495 			&& (quote = (char_u *)strrchr((char *)ptr, '"')) != NULL)
3496 		{
3497 		    res = (char_u *)obstack_copy0(obs, ptr, (quote - ptr));
3498 
3499 		    /* remove all `\' in `\"' */
3500 		    for (ptr = last = res; *ptr; ptr++)
3501 		    {
3502 			if (*ptr != '\\' || *(ptr + 1) != '"')
3503 			    *last++ = *ptr;
3504 		    }
3505 		    *last = NUL;
3506 
3507 		    /* build the display line including ={*}, the hiliting sign */
3508 		    obstack_strcat(obs, obj->name);
3509 		    obstack_strcat(obs, ":");
3510 		    obstack_strcat(obs, obj->format);
3511 		    obstack_strcat(obs, " ");
3512 		    obstack_strcat(obs, obj->expression);
3513 		    obstack_strcat(obs, " ={*} ");
3514 		    obstack_strcat0(obs, res);
3515 		    displine = (char_u *)obstack_finish(obs);
3516 
3517 
3518 		    /* update and highlight object value */
3519 		    varobj_replace(this, obj, displine, obs);
3520 
3521 		}
3522 		goto nextobj;
3523 	}
3524     }
3525 
3526     return NULL;
3527 nextobj:
3528     FREE(this->lvl3.result);
3529     this->lvl3.varitem = obj->next;
3530     this->lvl3.varnext_cmd = VCMD_INIT;
3531 
3532     /* When not at the end of varlist, return a non null object
3533      * to get gdb_oob_send() to call again varobj_update() for
3534      * the next object */
3535     return (char *)this->lvl3.varitem;
3536 }
3537 
3538 #   define OBHI_CHANGED	    " ={*} "
3539 #   define OBHI_UNCHANGED   " ={=} "
3540 #   define OBHI_DESCOPED    " ={-} "
3541 /* Change object highlighting to type */
3542     static void
varobj_hilite(this,obj,type,obs)3543 varobj_hilite(this, obj, type, obs)
3544     gdb_T *this;
3545     varobj_T *obj;
3546     int type;	    /* hiliting type, may be '*', '=' or '-' */
3547     struct obstack *obs;
3548 #  ifdef FEAT_GDB
3549 {
3550     buf_T *oldbuf = curbuf;
3551     char_u *ptrn;
3552     char_u *line;
3553     char_u *oldline;
3554     char_u *ptr;
3555     pos_T pos;
3556     win_T *win;
3557 
3558     pos.lnum = 1;
3559     pos.col = 0;
3560 
3561     /* search for obj in variables window */
3562     obstack_strcat(obs, "^\\s*");
3563     obstack_strcat(obs, obj->name);
3564     obstack_strcat0(obs, ":");
3565     ptrn = (char_u *)obstack_finish(obs);
3566 
3567     if (this->var_buf != NULL && obj != NULL && obj->name != NULL
3568 	    && ! (this->var_buf->b_ml.ml_flags & ML_EMPTY)
3569 	    && searchit(NULL, this->var_buf, &pos,
3570 		FORWARD, ptrn, 1L, SEARCH_KEEP, RE_LAST, (linenr_T)0, NULL) != FAIL)
3571     {
3572 	line = ml_get_buf(this->var_buf, pos.lnum, FALSE);
3573 	oldline = obstack_strsave(obs, line);
3574 
3575 	if ((type == '-' && ((ptr = STRSTR(oldline, OBHI_CHANGED)) != NULL
3576 			|| (ptr = STRSTR(oldline, OBHI_UNCHANGED)) != NULL))
3577 		|| (type == '*' && ((ptr = STRSTR(oldline, OBHI_UNCHANGED)) != NULL
3578 			|| (ptr = STRSTR(oldline, OBHI_DESCOPED)) != NULL))
3579 		|| (type == '=' && ((ptr = STRSTR(oldline, OBHI_DESCOPED)) != NULL
3580 			|| (ptr = STRSTR(oldline, OBHI_CHANGED)) != NULL)))
3581 	{
3582 	    *(ptr + 3) = type;
3583 
3584 	    /* replace line */
3585 	    curbuf = this->var_buf;
3586 	    ml_replace(pos.lnum, oldline, TRUE);
3587 	    changed_lines(pos.lnum, 0, pos.lnum + 1, 0);
3588 	    curbuf = oldbuf;
3589 
3590 	    if ((win = gdb_btowin(this->var_buf)) != NULL)
3591 		redraw_win_later(win, NOT_VALID);
3592 	}
3593     }
3594 }
3595 #  else
3596 {
3597     char_u *oldline;
3598     char_u *line;
3599     char_u *ptr;
3600     int lnum;
3601 
3602     /* search for obj in variables buffer */
3603     if (this->var_buf > 0 && obj != NULL && obj->name != NULL
3604 	    && (oldline = cnb_search_obj(obj->name, &lnum)) != NULL)
3605     {
3606 	line = obstack_strsave(obs, oldline);
3607 
3608 	if ((type == '-' && ((ptr = STRSTR(line, OBHI_CHANGED)) != NULL
3609 			|| (ptr = STRSTR(line, OBHI_UNCHANGED)) != NULL))
3610 		|| (type == '*' && ((ptr = STRSTR(line, OBHI_UNCHANGED)) != NULL
3611 			|| (ptr = STRSTR(line, OBHI_DESCOPED)) != NULL))
3612 		|| (type == '=' && ((ptr = STRSTR(line, OBHI_DESCOPED)) != NULL
3613 			|| (ptr = STRSTR(line, OBHI_CHANGED)) != NULL)))
3614 	{
3615 	    *(ptr + 3) = type;
3616 
3617 	    /* replace line */
3618 	    cnb_replace(this->var_buf, line, lnum, obs);
3619 	}
3620     }
3621 }
3622 #  endif
3623 
3624 /* Replace object line in variables buffer with line */
3625     static void
varobj_replace(this,obj,line,obs)3626 varobj_replace(this, obj, line, obs)
3627     gdb_T *this;
3628     varobj_T *obj;
3629     char_u *line;
3630     struct obstack *obs;
3631 #  ifdef FEAT_GDB
3632 {
3633     buf_T *oldbuf = curbuf;
3634     win_T *oldwin = curwin;
3635     char_u *ptrn;
3636     linenr_T lnum;
3637     win_T *win;
3638     pos_T pos;
3639 
3640     pos.lnum = 1;
3641     pos.col = 0;
3642 
3643     /* search for object in variables window */
3644     obstack_strcat(obs, "^\\s*");
3645     obstack_strcat(obs, obj->name);
3646     obstack_strcat0(obs, ":");
3647     ptrn = (char_u *)obstack_finish(obs);
3648 
3649     if (this->var_buf != NULL && obj != NULL && obj->name != NULL
3650 	    && ! (this->var_buf->b_ml.ml_flags & ML_EMPTY)
3651 	    && searchit(NULL, this->var_buf, &pos,
3652 		FORWARD, ptrn, 1L, SEARCH_KEEP, RE_LAST, (linenr_T)0, NULL) != FAIL)
3653     {
3654 	lnum = pos.lnum;
3655 
3656 	/* replace line */
3657 	curbuf = this->var_buf;
3658 	ml_replace(lnum, line, TRUE);
3659 	changed_lines(lnum, 0, lnum + 1, 0);
3660 
3661 	if ((win = gdb_btowin(this->var_buf)) != NULL)
3662 	{
3663 	    win->w_cursor.lnum = lnum;
3664 
3665 	    curwin = win;
3666 	    check_cursor();
3667 	    update_topline();
3668 	    curwin = oldwin;
3669 
3670 	    win->w_redr_status = TRUE;
3671 
3672 	    redraw_win_later(win, NOT_VALID);
3673 	}
3674 	curbuf = oldbuf;
3675     }
3676 }
3677 #  else
3678 {
3679     int lnum;
3680 
3681     /* search for object in variables buffer */
3682     if (this->var_buf > 0 && obj != NULL && obj->name != NULL
3683 	    && cnb_search_obj(obj->name, &lnum) != NULL)
3684 	cnb_replace(this->var_buf, line, lnum, obs);
3685 }
3686 #  endif
3687 
3688 /* Remove varobj item from valist */
3689     static void
remove_object(this,item)3690 remove_object(this, item)
3691     gdb_T *this;
3692     varobj_T *item;
3693 {
3694     varobj_T **pt;
3695     varobj_T *next;
3696 
3697     for (pt = &(this->lvl3.varlist); *pt != NULL; pt = &((*pt)->next))
3698 	if (*pt == item)
3699 	{
3700 	    next = (*pt)->next;
3701 	    this->lvl3.varitem = next;
3702 
3703 	    xfree(item->name);
3704 	    xfree(item->format);
3705 	    xfree(item->expression);
3706 	    xfree(item);
3707 	    *pt = next;
3708 	    return;
3709 	}
3710 }
3711 #  endif /* GDB_LVL3_SUPPORT */
3712 
3713 /*
3714  * Add a breakpoint record to the head of the tmp list and highlite
3715  * the corresponding sign if the record refers to a loaded buffer
3716  * or to an editable file, and in this case load it.
3717  */
3718     void
gdb_process_record(this,address,at,line,source,obs)3719 gdb_process_record(this, address, at, line, source, obs)
3720     gdb_T *this;
3721     char_u *address;	/* breakpoint address */
3722     char_u *at;		/* breakpoint function */
3723     char_u *line;	/* breakpoint line in source */
3724     char_u *source;	/* breakpoint source file name */
3725     struct obstack *obs;
3726 #  ifdef FEAT_GDB
3727 {
3728     win_T *oldwin    = curwin;
3729     bpinfo_T *record = this->record;
3730     char_u *bp_file  = NULL;
3731     buf_T *buf       = NULL;
3732     char_u *ptrn;
3733     bpinfo_T *p, **pt;
3734     pos_T pos;
3735     int i;
3736     int lnum;
3737 
3738     /*
3739      * Look for this breakpoint in previous list
3740      */
3741     for (pt = &(this->bpinfo); *pt != NULL; pt = &((*pt)->next))
3742     {
3743 	p = *pt;
3744 
3745 	/* The breakpoint number exists in the old table:
3746 	 *	update the highliting sign and do not even parse
3747 	 *	the line (assume the file and line of a breakpoint
3748 	 *	are immutable)
3749 	 *	move the old record to tmplist and update its sign
3750 	 */
3751 	if (record->id == p->id)
3752 	{
3753 	    /* update enabled */
3754 	    if (record->enabled != p->enabled)
3755 	    {
3756 		p->enabled = record->enabled;
3757 		if ((p->typenr = gdb_define_sign(p->id, p->enabled)) != -1)
3758 		{
3759 		    buf_addsign(p->buf, BP_SIGN_ID(p->id), p->lnum, p->typenr);
3760 		    update_debug_sign(p->buf, p->lnum);
3761 		}
3762 	    }
3763 
3764 #  ifdef BP_INVALID_ANO_MISSING
3765 	    /* update disposition */
3766 	    p->disposition = record->disposition;
3767 #  endif
3768 
3769 	    /* update 'continue' */
3770 	    p->cont = record->cont;
3771 
3772 	    /* move from old list to new list */
3773 	    *pt = p->next;		    /* unlink from old list */
3774 	    p->next = this->tmplist;	    /* link to head of new table */
3775 	    this->tmplist = p;
3776 	    return;			    /* record may be reused */
3777 	}
3778     }
3779 
3780     /*
3781      * A new breakpoint number: edit the file if possible
3782      */
3783     /* An asm breakpoint */
3784     if (address != NULL && at != NULL)
3785     {
3786 	bp_file = obstack_strsave(obs, at);
3787 
3788 	/* Search all buffers in the asm buffer pool whose name starts
3789 	 * with bp_file and find the one containing a line starting
3790 	 * with address */
3791 	obstack_strcat(obs, "^\\s*0x0*");
3792 	obstack_strcat0(obs, address);
3793 	ptrn = (char_u *)obstack_finish(obs);
3794 
3795 	for (i = 0; i < this->pool.max; i++)
3796 	{
3797 	    pos.lnum = 1;
3798 	    pos.col = 0;
3799 
3800 	    if (this->pool.buf[i] != NULL
3801 		    && STRSTR(this->pool.buf[i]->b_fname, bp_file) != NULL
3802 		    && !(this->pool.buf[i]->b_ml.ml_flags & ML_EMPTY)
3803 		    && searchit(NULL, this->pool.buf[i], &pos,
3804 			FORWARD, ptrn, 1L, SEARCH_KEEP, RE_LAST, (linenr_T)0, NULL) != FAIL)
3805 	    {
3806 		this->pool.age[i] = 0;
3807 		record->lnum = pos.lnum;
3808 		buf = this->pool.buf[i];
3809 		break;
3810 	    }
3811 	}
3812 
3813 	bp_file = NULL;
3814     }
3815 
3816     /* A plain breakpoint */
3817     else if (line != NULL && (record->lnum = atoi((char *)line)) > 0
3818 	    && source != NULL)
3819     {
3820 	bp_file = obstack_strsave(obs, source);
3821     }
3822 
3823     /*
3824      * Edit the file or asm buffer
3825      * when the table is reported by GDB as having changed
3826      * or when this buffer is the frame buffer and the frame
3827      * is invalid (because: we might be setting a frame in
3828      * a newly disassembled buffer and must set again all
3829      * its breakpoints)
3830      */
3831     if ((bp_file != NULL || buf != NULL)
3832 	    && (this->bp_state & BPS_INVALID
3833 		    || (p_asm != 0
3834 			&& buf != NULL
3835 			&& buf == this->fr_buf
3836 			&& (this->bp_state & BPS_FR_INVALID)))
3837 	    )
3838     {
3839 	/* bufIsChanged is TRUE when previous gdb_edit_file() failed because
3840 	 * the user cancelled the operation after having been warned the
3841 	 * buffer is changed. In this case, do not try to gdb_edit_file()
3842 	 * again for the next new breakpoints
3843 	 * (as the operation is cancelled). */
3844 	if (! this->bufIsChanged)
3845 	{
3846 	    if (gdb_edit_file(this, buf, bp_file, record->lnum, obs) != NULL)
3847 	    {
3848 		/* MUST redraw the screen before calling update_debug_sign():
3849 		 *  update_debug_sign() invokes win_update()
3850 		 *  the screen might have been scrolled when Vim ask the
3851 		 *  user to confirm changes made to the previous buffer */
3852 		gdb_redraw(curwin->w_buffer);
3853 
3854 		record->buf = curwin->w_buffer;
3855 
3856 		if ((record->typenr =
3857 			    gdb_define_sign(record->id, record->enabled)) != -1)
3858 		{
3859 		    /* add bp sign */
3860 		    buf_addsign(record->buf, BP_SIGN_ID(record->id),
3861 			    record->lnum, record->typenr);
3862 		    update_debug_sign(record->buf, record->lnum);
3863 
3864 		    /* Set the frame sign again in case this is
3865 		     * a newly disassembled buffer */
3866 		    if (this->frame_pc != NULL
3867 			    && p_asm != 0
3868 			    && this->fr_buf == NULL
3869 			    && ! (record->buf->b_ml.ml_flags & ML_EMPTY))
3870 		    {
3871 			pos.lnum = 1;
3872 			pos.col = 0;
3873 
3874 			obstack_strcat(obs, "^\\s*0x0*");
3875 			obstack_strcat0(obs, this->frame_pc);
3876 			ptrn = (char_u *)obstack_finish(obs);
3877 
3878 			if (ptrn != NULL
3879 				&& searchit(NULL, record->buf, &pos, FORWARD,
3880 				    ptrn, 1L, SEARCH_KEEP, RE_LAST, (linenr_T)0, NULL) != FAIL)
3881 			{
3882 			    gdb_fr_lite(this, record->buf, pos.lnum, obs);
3883 			}
3884 		    }
3885 
3886 		    /* Handle the case where bps are set after the frame sign:
3887 		     * new disassembled code or reediting a wiped-out plain
3888 		     * buffer or stepping in a newly disassembled buffer */
3889 		    if (record->buf == this->fr_buf
3890 			    && (this->bp_state & BPS_BP_HIT
3891 				|| (p_asm != 0
3892 				    && (this->bp_state & BPS_FR_INVALID)))
3893 			    && (lnum =
3894 				buf_findsign(this->fr_buf, FRAME_SIGN)) != 0)
3895 		    {
3896 			/* remove frame sign and add it again on top
3897 			 * of this new breakpoint */
3898 			if (lnum == record->lnum)
3899 			    gdb_fr_lite(this, this->fr_buf, lnum, obs);
3900 
3901 			/* move back cursor to frame */
3902 			gdb_set_cursor(gdb_btowin(this->fr_buf), lnum);
3903 		    }
3904 		}
3905 
3906 		record->next = this->tmplist;	/* link to head of new table */
3907 		this->tmplist = record;
3908 		this->record = NULL;		/* forget record */
3909 	    }
3910 	    else
3911 	    {
3912 		this->bufIsChanged = bufIsChanged(curbuf);
3913 		win_goto(oldwin);
3914 	    }
3915 	}
3916     }
3917 
3918     return;
3919 }
3920 #  else
3921 {
3922     bpinfo_T *record = this->record;
3923     char_u *bp_file  = NULL;
3924     int buf          = -1;
3925     bpinfo_T *p, **pt;
3926     char_u *fname;
3927     linenr_T lnum;
3928     int bufno;
3929 
3930     /*
3931      * Look for this breakpoint in previous list
3932      */
3933     for (pt = &(this->bpinfo); *pt != NULL; pt = &((*pt)->next))
3934     {
3935 	p = *pt;
3936 
3937 	/* The breakpoint number exists in the old table:
3938 	 *	remove old sign and replace by new one
3939 	 *	move the old record to tmplist and update its sign
3940 	 */
3941 	if (record->id == p->id)
3942 	{
3943 	    /* update enabled */
3944 	    if (record->enabled != p->enabled)
3945 	    {
3946 		p->enabled = record->enabled;
3947 		if ((p->typenr = gdb_define_bpsign(p, obs)) != -1)
3948 		{
3949 		    cnb_buf_delsign(p->buf, BP_SIGN_ID(p->id));
3950 		    cnb_buf_addsign(p->buf, BP_SIGN_ID(p->id), p->typenr, p->lnum, obs);
3951 		}
3952 	    }
3953 
3954 #  ifdef BP_INVALID_ANO_MISSING
3955 	    /* update disposition */
3956 	    p->disposition = record->disposition;
3957 #  endif
3958 
3959 	    /* update 'continue' */
3960 	    p->cont = record->cont;
3961 
3962 	    /* move from old list to new list */
3963 	    *pt = p->next;		    /* unlink from old list */
3964 	    p->next = this->tmplist;	    /* link to head of new table */
3965 	    this->tmplist = p;
3966 	    return;			    /* record may be reused */
3967 	}
3968     }
3969 
3970     /*
3971      * A new breakpoint number: edit the file if possible
3972      */
3973     /* An asm breakpoint */
3974     if (address != NULL && at != NULL)
3975     {
3976 	bp_file = obstack_strsave(obs, at);
3977 
3978 	/* Search all buffers in the asm buffer pool whose name starts
3979 	 * with bp_file and find the one containing a line starting
3980 	 * with address */
3981 	for (bufno = 1; ! cnb_outofbounds(bufno); bufno++)
3982 	{
3983 	    if ((fname = cnb_filename(bufno)) != NULL
3984 		    && STRSTR(fname, bp_file) != NULL
3985 		    && (lnum = searchfor(fname, address)) > 0)
3986 	    {
3987 		record->lnum = lnum;
3988 		buf = bufno;
3989 		break;
3990 	    }
3991 	}
3992 
3993 	bp_file = NULL;
3994     }
3995 
3996     /* A plain breakpoint */
3997     else if (line != NULL && (record->lnum = atoi((char *)line)) > 0
3998 	    && source != NULL)
3999     {
4000 	bp_file = obstack_strsave(obs, source);
4001     }
4002 
4003     /*
4004      * Edit the file or asm buffer
4005      * when the table is reported by GDB as having changed
4006      * or when this buffer is the frame buffer and the frame
4007      * is invalid (because: we might be setting a frame in
4008      * a newly disassembled buffer and must set again all
4009      * its breakpoints)
4010      */
4011     if ((bp_file != NULL || cnb_isvalid_buffer(buf))
4012 	    && (this->bp_state & BPS_INVALID
4013 		    || (p_asm != 0
4014 			&& cnb_isvalid_buffer(buf)
4015 			&& buf == this->fr_buf
4016 			&& (this->bp_state & BPS_FR_INVALID)))
4017 	    )
4018     {
4019 	if ((record->buf = gdb_edit_file(buf, bp_file, record->lnum, 1, obs)) > 0)
4020 	{
4021 	    if ((record->typenr = gdb_define_bpsign(record, obs)) != -1)
4022 	    {
4023 		/* add bp sign */
4024 		cnb_buf_addsign(record->buf, BP_SIGN_ID(record->id),
4025 			record->typenr, record->lnum, obs);
4026 
4027 		/* Set the frame sign again in case this is
4028 		 * a newly disassembled buffer */
4029 		if (this->frame_pc != NULL
4030 			&& p_asm != 0
4031 			&& ! cnb_isvalid_buffer(this->fr_buf)
4032 			&& (fname = cnb_filename(record->buf)) != NULL
4033 			&& (lnum = searchfor(fname, this->frame_pc)) > 0)
4034 		{
4035 		    gdb_fr_lite(this, record->buf, lnum, obs);
4036 		}
4037 
4038 		/* Handle the case where bps are set after the frame sign:
4039 		 * new disassembled code or reediting a wiped-out plain
4040 		 * buffer or stepping in a newly disassembled buffer */
4041 		if (record->buf == this->fr_buf
4042 			&& (this->bp_state & BPS_BP_HIT
4043 			    || (p_asm != 0
4044 				&& (this->bp_state & BPS_FR_INVALID)))
4045 			&& (lnum = find_fr_sign(this->fr_buf)) != 0)
4046 		{
4047 		    /* remove frame sign and add it again on top
4048 		     * of this new breakpoint */
4049 		    if (lnum == record->lnum)
4050 			gdb_fr_lite(this, this->fr_buf, lnum, obs);
4051 		}
4052 	    }
4053 
4054 	    record->next = this->tmplist;	/* link to head of new table */
4055 	    this->tmplist = record;
4056 	    this->record = NULL;		/* forget record */
4057 	}
4058     }
4059 
4060     return;
4061 }
4062 #  endif /* FEAT_GDB */
4063 
4064 /*
4065  * Parse str for annotation, set this->note.
4066  * Return byte address following annotation, NULL if none found.
4067  * Return byte address following ^Z^Z when unknown annotation.
4068  */
4069     static char_u *
parse_note(this,str)4070 parse_note(this, str)
4071     gdb_T *this;
4072     char_u *str;	/* string to parse */
4073 {
4074     char_u *note = NULL;
4075     annotation_T *pt;
4076     int len;
4077 
4078     if (str != NULL && (note = STRSTR(str, "\032\032")) != NULL)
4079     {
4080 	this->note = ANO_ANY;
4081 	note += 2;
4082 
4083 	for (pt = annotations; pt->str != NULL; pt++)
4084 	{
4085 	    len = STRLEN(pt->str);
4086 
4087 	    if (STRSTR(note, pt->str) == note
4088 		    && (*(note + len) == NUL || isspace(*(note + len))))
4089 	    {
4090 		this->note = pt->id;
4091 		return note + strlen((char *)pt->str);
4092 	    }
4093 	}
4094     }
4095     return note;
4096 }
4097 
4098 #  ifndef FEAT_GDB
4099 /* Return annotation type of 'str' or ANO_NONE when not found. */
4100     static int
get_note(this,str)4101 get_note(this, str)
4102     gdb_T *this;
4103     char_u *str;	/* string to parse */
4104 {
4105     int oldnote = this->note;
4106     int note    = ANO_NONE;
4107 
4108     if (IS_ANNOTATION(str) && parse_note(this, str) != NULL)
4109 	note = this->note;
4110 
4111     this->note = oldnote;
4112     return note;
4113 }
4114 #  endif /* FEAT_GDB */
4115 # endif /* defined(GDB_LVL2_SUPPORT) || defined(GDB_LVL3_SUPPORT) */
4116 #endif /* defined(FEAT_GDB) || defined(HAVE_CLEWN) */
4117