1 /*****************************************************************************
2  *
3  *  xdbx - X Window System interface to the dbx debugger
4  *
5  *  Copyright 1989 The University of Texas at Austin
6  *  Copyright 1990 Microelectronics and Computer Technology Corporation
7  *
8  *  Permission to use, copy, modify, and distribute this software and its
9  *  documentation for any purpose and without fee is hereby granted,
10  *  provided that the above copyright notice appear in all copies and that
11  *  both that copyright notice and this permission notice appear in
12  *  supporting documentation, and that the name of The University of Texas
13  *  and Microelectronics and Computer Technology Corporation (MCC) not be
14  *  used in advertising or publicity pertaining to distribution of
15  *  the software without specific, written prior permission.  The
16  *  University of Texas and MCC makes no representations about the
17  *  suitability of this software for any purpose.  It is provided "as is"
18  *  without express or implied warranty.
19  *
20  *  THE UNIVERSITY OF TEXAS AND MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO
21  *  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  *  FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR MCC BE LIABLE FOR
23  *  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
24  *  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
25  *  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26  *  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27  *
28  *  Author:  	Po Cheung
29  *  Created:   	March 10, 1989
30  *
31  *****************************************************************************
32  *
33  *  xxgdb - X Window System interface to the gdb debugger
34  *
35  * 	Copyright 1990,1993 Thomson Consumer Electronics, Inc.
36  *
37  *  Permission to use, copy, modify, and distribute this software and its
38  *  documentation for any purpose and without fee is hereby granted,
39  *  provided that the above copyright notice appear in all copies and that
40  *  both that copyright notice and this permission notice appear in
41  *  supporting documentation, and that the name of Thomson Consumer
42  *  Electronics (TCE) not be used in advertising or publicity pertaining
43  *  to distribution of the software without specific, written prior
44  *  permission.  TCE makes no representations about the suitability of
45  *  this software for any purpose.  It is provided "as is" without express
46  *  or implied warranty.
47  *
48  *  TCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
49  *  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
50  *  SHALL TCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
51  *  OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
52  *  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
53  *  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
54  *  SOFTWARE.
55  *
56  *  Adaptation to GDB:  Pierre Willard
57  *  XXGDB Created:   	December, 1990
58  *
59  *****************************************************************************/
60 
61 /*  dataDpy.c:
62  *
63  *   Provide graphical display of C pointers and structures.
64  *
65  *   BuildLinePos():	Construct an array indexing the character position of
66  *			each line.
67  *   PositionToLine():	Return the character position of a given line.
68  *   SelectPointer():	Action proc for double click on a pointer value,
69  *   CreateDataPopup():	Create a popup to display the object pointed to by a
70  *			pointer.
71  *   UpdateDataPopup(): Update an unused popupshell to display data.
72  *   AppendList():	Append a popup to the list.
73  *   DeleteList():	Delete a popup from the list.
74  *   pop_down():	pop down the popup and free storage.
75  *   DestroyDataPopup():event handler for destroying a popup, call DeleteList()
76  *			and pop_down() (CRL mod 25)
77  *   MovePopup():	Position the popup.
78  *   print_handler():	Action handler for displaying pointers and structures.
79  */
80 
81 /*
82  * 01FEB94: bugs fixed (klamer)
83  *		xxgdb does not allow the graphically displaying of members of parents
84  *   		from a class.
85  *		xxgdb does not allow the graphically displaying of data through a
86  *		   reference.
87  */
88 
89 #include <string.h>
90 #include 	"global.h"
91 #include 	"regex.h"
92 #include 	"datadpy.h"
93 
94 #define		MAXLEVELS	20	/* max level of indentation */
95 #ifdef GDB
96 #define		INDENT		2	/* # of spaces for each indentation */
97 #else
98 #define		INDENT		8	/* # of spaces for each indentation */
99 #endif /* GDB */
100 #define 	EMPTY           0
101 #define 	UNUSED          1
102 #define 	USED            2
103 #define 	LEFT_MARGIN	10
104 #define 	SCROLLBAR_WIDTH	15
105 
106 
107 static DataDpyRec	**dataDpyTable;
108 static int		dataDpyTableSize = 0;
109 static DataDpyRec	*Parent = NULL;
110 static DataDpyList	*TopParentList = NULL;
111 static int		font_height, font_width;
112 
113 #ifdef OBSOLETE
114 static void		DestroyDataPopup();
115 #else
116 /* CRL mod 25 4/12/91 GWC - changed label widget to command widget in popups */
117 static void		DestroyDataCallback();
118 #endif
119 
120 /*
121  *  Build an array which gives the starting text position of each line.
122  *  Very similar to the routine in source.c.
123  */
BuildLinePos(dataDpy)124 static void BuildLinePos(dataDpy)
125 DataDpyRec *dataDpy;
126 {
127     char *p;
128     int	 line, nlines;
129     int	 max=0;
130 
131     nlines = MAX(1, dataDpy->buflen/CHARS_PER_LINE);
132     dataDpy->linepos = (XawTextPosition *)
133                     XtMalloc ((nlines+2) * sizeof(XawTextPosition));
134     p = dataDpy->buf;
135     line = 0;
136     dataDpy->linepos[line++] = 0;
137     dataDpy->linepos[line++] = 0;
138     while (*p) {
139         if (*p++ == '\n') {
140             if (line == nlines) {       /* buffer full, need more memory */
141                 dataDpy->linepos = (XawTextPosition *)XtRealloc( (void*)dataDpy->linepos,
142                           (nlines + ADD_LINES) * sizeof(XawTextPosition));
143                 nlines += ADD_LINES;
144             }
145             dataDpy->linepos[line] = p - dataDpy->buf;
146 	    AssignMax(max, dataDpy->linepos[line] - dataDpy->linepos[line-1]);
147 	    line++;
148         }
149     }
150     dataDpy->numlines = line - 2;
151     dataDpy->maxLineLength = max;
152     /* shrink to min size */
153     dataDpy->linepos = (XawTextPosition *) XtRealloc
154                         ((void*)dataDpy->linepos, line * sizeof(XawTextPosition));
155 }
156 
157 /*
158  *  Return the line number for the specified text position.
159  */
PositionToLine(dataDpy,pos)160 static int PositionToLine(dataDpy, pos)
161 DataDpyRec *dataDpy;
162 XawTextPosition pos;
163 {
164     int	 line;
165 
166     if (dataDpy && pos >= 0) {
167     	for (line = 1; pos >= dataDpy->linepos[line]; line++);
168     	return (line-1);
169     }
170     else
171 	return (0);
172 }
173 
174 /* ARGSUSED */
175 /*
176  *  Called by double click of pointer button.
177  *  If the selected text is a valid pointer, this routine parses the data
178  *  output to obtain the full qualified name of the pointer, and asks
179  *  dbx to print the value of the object the pointer is pointing to.
180  */
SelectPointer(w,event,params,num_params)181 static void SelectPointer(w, event, params, num_params)
182     Widget w;
183     XEvent *event;
184     String *params;
185     Cardinal *num_params;
186 {
187 #ifndef GDB
188     struct re_registers regs;
189 	char *field[MAXLEVELS];
190 	int line, n, r, level, newlevel;
191 	char		name[LINESIZ];
192 #endif
193     XawTextPosition 	left, right;
194     char		*selection, *p;
195     DataDpyRec		*dataDpy;
196     int			fromLine;
197     int			i, nbytes;
198     char		command[LINESIZ];
199 
200     /* Find out which data display output does the selection belong to */
201     dataDpy = NULL;
202     for (i=0; dataDpyTable[i]; i++)
203 	if ((Widget) w == (Widget) dataDpyTable[i]->dataDpyWindow) {
204 	    dataDpy = dataDpyTable[i];
205 	    Parent = dataDpy;
206 	    break;
207 	}
208     if (!dataDpy) return;
209 
210     /* Get the selection and check if it's a pointer value, 0x???? */
211     selection = XFetchBytes(display, &nbytes);
212     if (re_match(dataPattern[D_POINTER].buf, selection, strlen(selection), 0, 0)
213 	< 0) {
214 	Parent = NULL;
215 	return;
216     }
217 
218     /* Parse the output to get the fully qualified name of the pointer */
219     XawTextGetSelectionPos(w, &left, &right);
220     fromLine = PositionToLine(dataDpy, left);
221     p = dataDpy->buf + dataDpy->linepos[fromLine];
222 
223 #ifdef GDB	/* (PW)  we now use a new parser which should work better,
224 	in particular for arrays */
225 	{
226 	char *parse_gdb_print();
227 	char *newcommand;
228 
229     newcommand = parse_gdb_print(command, dataDpy->buf, dataDpy->buf + left );
230     if (*newcommand)
231     	{
232 		if (strchr(selection, '@'))
233 		{
234 			char	*p = strchr(newcommand, '*');
235 			if (p != 0)
236 				*p = ' ';
237 		}
238 		PopupMode = True;
239     	query_gdb(newcommand, PARSE_ON | ECHO_OFF | FILTER_OFF);
240     	}
241     }
242 #else	/* not GDB */
243 
244     if (re_match(dataPattern[D_FIELD].buf, p, strlen(p), 0, &regs) >= 0) {
245 	r = dataPattern[D_FIELD].reg_token[TK_POINTER];
246 	if (strncmp(selection, p+regs.start[r], regs.end[r]-regs.start[r]))
247 	    return;
248 	r = dataPattern[D_FIELD].reg_token[TK_INDENT];
249 	level = regs.end[r]/INDENT;
250 	field[level+1] = NULL;
251 
252 	r = dataPattern[D_FIELD].reg_token[TK_FIELD];
253 	n = regs.end[r] - regs.start[r];
254 	field[level] = (char *) XtMalloc ((n+1) * sizeof(char));
255 	strncpy(field[level], p+regs.start[r], n);
256 	field[level][n] = '\0';
257 
258 	for (line = fromLine-1; line > 0; line--) {
259 	    p = dataDpy->buf + dataDpy->linepos[line];
260 	    if (re_match(dataPattern[D_STRUCT].buf, p, strlen(p), 0, &regs)>=0){
261 		r = dataPattern[D_STRUCT].reg_token[TK_INDENT];
262 		newlevel = regs.end[r]/INDENT;
263 		if (newlevel == level-1) {
264 		    level--;
265 		    r = dataPattern[D_STRUCT].reg_token[TK_FIELD];
266 		    n = regs.end[r] - regs.start[r];
267 		    field[level] = (char *) XtMalloc ((n+1) * sizeof(char));
268 		    strncpy(field[level], p+regs.start[r], n);
269 		    field[level][n] = '\0';
270 		}
271 	    }
272 	}
273 	if (*field[0] == '*' && field[1])
274 	    sprintf(name, "(%s)", field[0]+1);
275 	else
276 	    strcpy(name, field[0]);
277 
278 	for (i=1; field[i]; i++) {
279 	    strcat(name, ".");
280 	    strcat(name, field[i]);
281 	}
282 	sprintf(command, "print *(%s)\n", name);
283 	PopupMode = True;
284 #ifdef GDB
285     query_gdb(command, PARSE_ON | ECHO_OFF | FILTER_OFF);
286 #else
287 	query_dbx(command);
288 #endif	/* GDB */
289     }
290 #endif /* GDB */
291 }
292 
293 
294 /*
295  *  Create a data display with a label.
296  *  The popupshell has a form widget which consists of a label and a text
297  *  widget.
298  */
CreateDataPopup(dataDpy,label)299 static void CreateDataPopup(dataDpy, label)
300 DataDpyRec *dataDpy;
301 char	   *label;
302 {
303     Arg         args[MAXARGS];
304     Cardinal    n;
305     Dimension	dataDpyHeight, dataDpyWidth;
306     XFontStruct	*text_font;
307 
308     static XtActionsRec datadpy_actions[] = {
309         {"SelectPointer", (XtActionProc) SelectPointer},
310         {NULL, NULL}
311     };
312 
313     static String translations = "#override \n\
314         <Btn1Down>:     SelectStart() SelectWord() SelectPointer() \n\
315         <Btn1Up>:       SelectEnd() \n\
316     ";
317 
318     n = 0;
319     dataDpy->popupshell = XtCreatePopupShell("Data Popup",
320 	transientShellWidgetClass, toplevel, args, n);
321 
322     n = 0;
323     XtSetArg(args[n], XtNdefaultDistance, 0);                           n++;
324     dataDpy->popup = XtCreateManagedWidget("popup", formWidgetClass,
325 	dataDpy->popupshell, args, n);
326 
327     /* Create the label */
328     n = 0;
329     XtSetArg(args[n], XtNtop, (XtArgVal) XawChainTop);                  n++;
330     XtSetArg(args[n], XtNbottom, (XtArgVal) XawChainTop);               n++;
331     XtSetArg(args[n], XtNright, (XtArgVal) XawChainRight);              n++;
332     XtSetArg(args[n], XtNleft, (XtArgVal) XawChainLeft);               	n++;
333     XtSetArg(args[n], XtNlabel, (XtArgVal) label);                     	n++;
334     XtSetArg(args[n], XtNresize, (XtArgVal) False);                    	n++;
335     XtSetArg(args[n], XtNjustify, (XtArgVal) XtJustifyCenter);         	n++;
336 
337 #ifdef OBSOLETE
338     dataDpy->label = XtCreateManagedWidget("label", labelWidgetClass,
339 	dataDpy->popup, args, n);
340 /*	GWC says it is better to use ButtonReleaseMask instead of ButtonPressMask.*/
341 	XtAddEventHandler(dataDpy->label, (EventMask) ButtonPressMask, False,
342 	DestroyDataPopup, dataDpy);
343 #else
344 /* CRL mod 25 4/12/91 GWC - changed label widget to command widget in
345 popups */
346 	dataDpy->label = XtCreateManagedWidget("command", commandWidgetClass,
347   		dataDpy->popup, args, n);
348     XtAddCallback(dataDpy->label, XtNcallback, DestroyDataCallback, dataDpy);
349 #endif
350 
351     /* Create the text window */
352     n = 0;
353     XtSetArg(args[n], XtNfromVert, (XtArgVal) dataDpy->label);          n++;
354     XtSetArg(args[n], XtNtop, (XtArgVal) XawChainTop);                  n++;
355     XtSetArg(args[n], XtNbottom, (XtArgVal) XawChainBottom);            n++;
356     XtSetArg(args[n], XtNright, (XtArgVal) XawChainRight);              n++;
357     XtSetArg(args[n], XtNleft, (XtArgVal) XawChainLeft);               	n++;
358 
359     XtSetArg(args[n], XtNleftMargin, (XtArgVal) LEFT_MARGIN); 		n++;
360     XtSetArg(args[n], XtNuseStringInPlace, (XtArgVal) True); 		n++;
361     XtSetArg(args[n], XtNstring, (XtArgVal) dataDpy->buf);            	n++;
362     XtSetArg(args[n], XtNlength, (XtArgVal) dataDpy->buflen);  		n++;
363     XtSetArg(args[n], XtNeditType, (XtArgVal) XawtextRead);             n++;
364     XtSetArg(args[n], XtNscrollHorizontal, XawtextScrollWhenNeeded);	n++;
365     XtSetArg(args[n], XtNscrollVertical, XawtextScrollWhenNeeded);	n++;
366     XtSetArg(args[n], XtNtranslations, XtParseTranslationTable(translations));
367                                                                         n++;
368     dataDpy->dataDpyWindow = XtCreateManagedWidget("dataDpyWindow",
369 	asciiTextWidgetClass, dataDpy->popup, args, n);
370     XtAppAddActions(app_context, datadpy_actions, XtNumber(datadpy_actions));
371 
372     /* Get the text font */
373     n = 0;
374     XtSetArg(args[n], XtNfont, &text_font);                  		n++;
375     XtGetValues(dataDpy->dataDpyWindow, args, n);
376 
377     /* Estimate the size of the text widget, dataDpyWindow, with the number
378        of lines and the maximum length of a line.  Assume fixed font width.
379     */
380     font_height = text_font->ascent + text_font->descent;
381     font_width = text_font->max_bounds.width;
382     dataDpyHeight = dataDpy->numlines * font_height + 5;
383     dataDpyWidth = dataDpy->maxLineLength * font_width + LEFT_MARGIN;
384     if (dataDpyHeight > app_resources.dataDpyMaxHeight)
385 	dataDpyWidth += SCROLLBAR_WIDTH;
386 
387 #if 1	/*(PW)17DEC90 : bug ! */
388 #define 	SCROLLBAR_HEIGHT	15
389     if (dataDpyWidth > app_resources.dataDpyMaxWidth)
390 	dataDpyHeight += SCROLLBAR_HEIGHT;
391 #endif
392 
393     AssignMin(dataDpyHeight, app_resources.dataDpyMaxHeight);
394     AssignMin(dataDpyWidth, app_resources.dataDpyMaxWidth);
395 
396     n = 0;
397     XtSetArg(args[n], XtNheight, (XtArgVal) dataDpyHeight); 		n++;
398     XtSetArg(args[n], XtNwidth, (XtArgVal) dataDpyWidth); 		n++;
399     XtSetValues(dataDpy->dataDpyWindow, args, n);
400 
401     n = 0;
402     XtSetArg(args[n], XtNwidth, (XtArgVal) dataDpyWidth); 		n++;
403     XtSetValues(dataDpy->label, args, n);
404 }
405 
406 /*
407  *  Instead of creating a new popupshell, this routine uses an already
408  *  existing popupshell for data display.
409  *  It changes the label, calculates the size of the popupshell,
410  *  and sets the source of the text window to that of the new data.
411  */
UpdateDataPopup(dataDpy,label)412 static void UpdateDataPopup(dataDpy, label)
413 DataDpyRec *dataDpy;
414 char	   *label;
415 {
416     Arg args[MAXARGS];
417     Cardinal n;
418     Dimension	popupHeight, popupWidth, dataDpyHeight, dataDpyWidth,
419 		labelHeight, labelBorderWidth, dataDpyBorderWidth;
420 
421     /* Update the label */
422     n = 0;
423     XtSetArg(args[n], XtNlabel, (XtArgVal) label);                     	n++;
424     XtSetValues(dataDpy->label, args, n);
425 
426     /* Calculate the size of popupshell */
427     dataDpyHeight = dataDpy->numlines * font_height + 5;
428     dataDpyWidth = dataDpy->maxLineLength * font_width + 2*10;
429 
430 #if 1	/*(PW)18DEC90 : bug ! */
431     if (dataDpyHeight > app_resources.dataDpyMaxHeight)
432 	dataDpyWidth += SCROLLBAR_WIDTH;
433 
434     if (dataDpyWidth > app_resources.dataDpyMaxWidth)
435 	dataDpyHeight += SCROLLBAR_HEIGHT;
436 #endif
437 
438     AssignMin(dataDpyHeight, app_resources.dataDpyMaxHeight);
439     AssignMin(dataDpyWidth, app_resources.dataDpyMaxWidth);
440 
441     n = 0;
442     XtSetArg(args[n], XtNheight, (XtArgVal) &labelHeight); 		n++;
443     XtSetArg(args[n], XtNborderWidth, (XtArgVal) &labelBorderWidth); 	n++;
444     XtGetValues(dataDpy->label, args, n);
445     n = 0;
446     XtSetArg(args[n], XtNborderWidth, (XtArgVal) &dataDpyBorderWidth); 	n++;
447     XtGetValues(dataDpy->dataDpyWindow, args, n);
448 
449     popupHeight = dataDpyHeight + labelHeight + 2*labelBorderWidth +
450 		  2*dataDpyBorderWidth;
451     popupWidth = dataDpyWidth;
452 
453     n = 0;
454     XtSetArg(args[n], XtNheight, (XtArgVal) popupHeight); 		n++;
455     XtSetArg(args[n], XtNwidth, (XtArgVal) popupWidth);			n++;
456     XtSetValues(dataDpy->popupshell, args, n);
457 
458     /* Set the text source */
459     n = 0;
460     XtSetArg(args[n], XtNstring, (XtArgVal) dataDpy->buf);		n++;
461     XtSetArg(args[n], XtNlength, (XtArgVal) dataDpy->buflen);           n++;
462     XawTextSetSource(dataDpy->dataDpyWindow,
463 		     XtCreateWidget("textsrc", asciiSrcObjectClass,
464 				    dataDpy->dataDpyWindow, args, n),
465 		     0);
466 }
467 
468 /*
469  *  Append dataDpy to a DataDpyList pointed to by head.
470  */
AppendList(head,dataDpy)471 static void AppendList(head, dataDpy)
472 DataDpyList **head;
473 DataDpyRec  *dataDpy;
474 {
475     DataDpyList	*p, *q, *r;
476 
477     p = (DataDpyList *) XtNew (DataDpyList);
478     p->dataDpy = dataDpy;
479     p->next = NULL;
480     q = *head;
481     if (!q)
482 	*head = p;
483     else {
484 	while ((r = q->next))
485 	    q = r;
486 	q->next = p;
487     }
488 }
489 
490 /*
491  *  Removes a dataDpy from its parent's list of children.
492  */
DeleteList(head,dataDpy)493 static void DeleteList(head, dataDpy)
494 DataDpyList **head;
495 DataDpyRec  *dataDpy;
496 {
497     DataDpyList *p, *q;
498 
499     if ((p = *head)) {
500 	if (p->dataDpy == dataDpy)
501 	    *head = p->next;
502 	else {
503 	    for (q = p->next; q && q->dataDpy != dataDpy;) {
504 		p = q;
505 		q = p->next;
506 	    }
507 	    if (q) p->next = q->next;
508 	}
509     }
510 }
511 
512 /*
513  *  Pop down a dataDpy and all its descendants, freeing storage and
514  *  reinitializing fields.
515  */
pop_down(dataDpy)516 static void pop_down(dataDpy)
517 DataDpyRec *dataDpy;
518 {
519     DataDpyList *p, *q;
520 
521     XtPopdown(dataDpy->popupshell);
522     XtFree((void*)dataDpy->linepos);
523     XtFree(dataDpy->buf);
524     dataDpy->buf = NULL;
525     dataDpy->buflen = 0;
526     dataDpy->linepos = NULL;
527     dataDpy->state = UNUSED;
528     dataDpy->parent = NULL;
529     for (p = dataDpy->childlist; p;) {
530 	pop_down(p->dataDpy);
531 	q = p;
532 	p = p->next;
533 	XtFree((void*)q);
534     }
535     dataDpy->childlist = NULL;
536 }
537 
538 /*
539  *  Invoked by a ButtonPress event on the label of a data display to
540  *  pop down itself and its descendants.
541  */
542 /* ARGSUSED */
543 
544 #ifdef OBSOLETE
DestroyDataPopup(w,dataDpy,event)545 static void DestroyDataPopup(w, dataDpy, event)
546     Widget w;
547     DataDpyRec *dataDpy;
548     XEvent *event;
549 #else
550 /* CRL mod 25 4/12/91 GWC - changed label widget to command widget */
551 static void DestroyDataCallback(w, dataDpy, call_data)
552     Widget w;
553     DataDpyRec *dataDpy;
554     caddr_t call_data;
555 #endif
556 {
557     if (!dataDpy->parent)
558     	DeleteList(&TopParentList, dataDpy);
559     else
560     	DeleteList(&dataDpy->parent->childlist, dataDpy);
561     pop_down(dataDpy);
562 }
563 
564 /*
565  *  Position the data display on the screen to reflect the parent-child
566  *  relationship.
567  */
MovePopup(dataDpy)568 static void MovePopup(dataDpy)
569 DataDpyRec *dataDpy;
570 {
571     Arg         args[MAXARGS];
572     Cardinal    n;
573     Screen	*screen;
574     int		popupHeight, popupWidth, screenHeight, screenWidth;
575     Position	x, y;
576     Dimension	dataDpyWidth, dataDpyHeight, dataDpyBorderWidth,
577 		labelHeight, labelBorderWidth, width, height, borderWidth;
578     DataDpyList	*p, *q;
579 
580     Parent = NULL;
581     if (!dataDpy->parent)
582 	p = TopParentList;
583     else
584 	p = dataDpy->parent->childlist;
585 
586     /*  Look for its previous sibling  */
587     for (q = p->next; q && q->dataDpy != dataDpy;) {
588 	p = q;
589 	q = q->next;
590     }
591     /*  If a sibling exists, place the new popup right next to it  */
592     if (q) {
593 	n = 0;
594 	XtSetArg(args[n], XtNwidth, (XtArgVal) &width);             n++;
595 	XtSetArg(args[n], XtNborderWidth, (XtArgVal) &borderWidth);	n++;
596 	XtGetValues(p->dataDpy->popupshell, args, n);
597 	XtTranslateCoords(p->dataDpy->popupshell, 0, 0, &x, &y);
598 	x += width;
599 	y -= borderWidth;
600     }
601     else {	/* no siblings */
602 	/*  this is the very first popup  */
603 	if (!dataDpy->parent) {
604 	    x = 0;
605 	    y = 0;
606 	}
607 	/*  place it under its parent  */
608 	else {
609 	    n = 0;
610 	    XtSetArg(args[n], XtNheight, (XtArgVal) &height);		n++;
611 	    XtGetValues(dataDpy->parent->popupshell, args, n);
612 	    XtTranslateCoords(dataDpy->parent->popupshell, 30, (Position)height,
613 		 &x, &y);
614 	}
615     }
616 
617     /* Make sure the popup does not go outside of the screen */
618     n = 0;
619     XtSetArg(args[n], XtNwidth, (XtArgVal) &dataDpyWidth);             	n++;
620     XtSetArg(args[n], XtNheight, (XtArgVal) &dataDpyHeight);           	n++;
621     XtSetArg(args[n], XtNborderWidth, (XtArgVal) &dataDpyBorderWidth); 	n++;
622     XtGetValues(dataDpy->dataDpyWindow, args, n);
623 
624     n = 0;
625     XtSetArg(args[n], XtNheight, (XtArgVal) &labelHeight); 		n++;
626     XtSetArg(args[n], XtNborderWidth, (XtArgVal) &labelBorderWidth); 	n++;
627     XtGetValues(dataDpy->label, args, n);
628 
629     popupHeight = dataDpyHeight + labelHeight + 2*labelBorderWidth +
630 		  2*dataDpyBorderWidth;
631     popupWidth = dataDpyWidth;
632 
633     screen = XtScreen(toplevel);
634     screenHeight = XHeightOfScreen(screen);
635     screenWidth = XWidthOfScreen(screen);
636 
637     if (x + popupWidth > screenWidth && y + popupHeight > screenHeight) {
638 	x = screenWidth - popupWidth;
639 	y = screenHeight - popupHeight;
640     }
641     else if (x + popupWidth > screenWidth)
642 	x = screenWidth - popupWidth;
643     else if (y + popupHeight > screenHeight)
644 	y = screenHeight - popupHeight;
645 
646     n = 0;
647     XtSetArg(args[n], XtNx, x);						n++;
648     XtSetArg(args[n], XtNy, y);						n++;
649     XtSetValues(dataDpy->popupshell, args, n);
650 }
651 
652 /*
653  *  Handler procedure called by parse().
654  *  The main function to popup a data display.
655  */
print_handler(output)656 void print_handler(output)
657 char *output;
658 {
659     DataDpyRec 	*dataDpy;
660     int		i, j;
661 
662     if (!output) return;
663     if (!PopupMode) return;
664     PopupMode = False;
665     XDefineCursor(display, XtWindow(toplevel), watch);
666     if (Parent)
667     	XDefineCursor(display, XtWindow(Parent->dataDpyWindow), watch);
668     UpdateMessageWindow("Click the label to pop down the data popup",NULL);
669 
670     /* Searches the table for an unused or empty slot */
671     /* (PW)17OCT91 : test i < dataDpyTableSize first (else segment violation)*/
672     for (i=0; dataDpyTable && i < dataDpyTableSize && dataDpyTable[i]
673     	&& dataDpyTable[i]->state == USED ; i++);
674     if (i == dataDpyTableSize) {			/* Table full */
675 	dataDpyTableSize += ADD_SIZE;
676 	dataDpyTable = (DataDpyRec **) XtRealloc ((void*)dataDpyTable,
677 			   dataDpyTableSize * sizeof(DataDpyRec *));
678 	for (j=i; j<dataDpyTableSize; j++)
679 	    dataDpyTable[j] = NULL;
680     }
681 
682     /*  Empty slot found, allocate a data structure and initializes some
683 	of the fields.  */
684     if (dataDpyTable[i] == NULL) {
685 	dataDpyTable[i] = (DataDpyRec *) XtMalloc (sizeof(DataDpyRec));
686 	dataDpyTable[i]->state = EMPTY;
687 	dataDpyTable[i]->parent = NULL;
688 	dataDpyTable[i]->childlist = NULL;
689     }
690 
691     dataDpy = dataDpyTable[i];
692     dataDpy->id = i;					/* not needed */
693     dataDpy->buf = XtNewString(output);
694     dataDpy->buflen = strlen(output);
695     BuildLinePos(dataDpy);
696 
697     if (dataDpy->state == EMPTY)
698 	CreateDataPopup(dataDpy, Token.mesg);
699     else if (dataDpy->state == UNUSED)
700 	UpdateDataPopup(dataDpy, Token.mesg);
701 
702     dataDpy->state = USED;				/* mark it used */
703     if ((dataDpy->parent = Parent))
704     	AppendList(&Parent->childlist, dataDpy);
705     else
706     	AppendList(&TopParentList, dataDpy);
707 
708     MovePopup(dataDpy);
709     XtPopup(dataDpy->popupshell, XtGrabNone);
710     if (dataDpy->parent)
711     	XUndefineCursor(display, XtWindow(dataDpy->parent->dataDpyWindow));
712     XUndefineCursor(display, XtWindow(toplevel));
713 }
714 
715 
716 #ifdef GDB
717 #define GOODCHARNAME(c)							\
718 			(	(((c) >='a') &&  ((c) <= 'z'))	\
719 			||	(((c) >='A') &&  ((c) <= 'Z'))	\
720 			||	(((c) >='0') &&  ((c) <= '9'))	\
721 			||	((c) == '_')					\
722 			||	((c) == '$')					\
723 			)
724 
725 static char *result;		/* start of result buffer */
726 static int result_index;	/* current index in result buffer */
727 static char *start_txt;		/* pointer 1st char of output to parse */
728 static char *curr_txt;		/* current pointer in output to parse */
729 
730 /*--------------------------------------------------------------------------+
731 |																			|
732 |	Store a character into the buffer.										|
733 |																			|
734 |	Note that characters are added to the buffer RIGHT TO LEFT !			|
735 |	This is because we parse the output from right to left.					|
736 |																			|
737 |	If the result buffer is full, we set result to "".						|
738 |																			|
739 +--------------------------------------------------------------------------*/
add_char(c)740 static void add_char(c)
741 char c;
742 {
743 	if (result_index == 0)	/* buffer full */
744 		{
745 		*result = 0;
746 		return;
747 		}
748 
749         if ((c == '.') && (result[result_index] == '.'))
750                 return;         /* To prevent $1..name for pointers in
751 				   g++ parents */
752 
753 	result_index--;
754 	*(result+result_index) = c;
755 }
756 
757 /*--------------------------------------------------------------------------+
758 |																			|
759 |	Store a string into the buffer.											|
760 |																			|
761 +--------------------------------------------------------------------------*/
add_string(s)762 static void add_string(s)
763 char *s;
764 {
765 int nbchar;
766 
767 	nbchar = strlen(s);
768 
769 	/* copy number from last digit */
770 
771 	while (nbchar > 0)
772 		add_char(*(s + (--nbchar)));
773 }
774 
775 /*--------------------------------------------------------------------------+
776 |																			|
777 |	Store a number into the buffer.											|
778 |																			|
779 +--------------------------------------------------------------------------*/
add_num(number)780 static void add_num(number)
781 int number;
782 {
783 char tmpnum[128];
784 
785 	sprintf(tmpnum,"%d",number);
786 	add_string(tmpnum);
787 }
788 
789 /*--------------------------------------------------------------------------+
790 |																			|
791 |	Init buffer.															|
792 |																			|
793 |	Store a NULL character (as end of string).								|
794 |																			|
795 +--------------------------------------------------------------------------*/
init_result(buffer,buflen)796 static void init_result(buffer,buflen)
797 char *buffer;
798 int buflen;
799 {
800 	result = buffer;
801 	result_index = buflen;
802 	add_char(0);			/* end result by null char */
803 }
804 
805 /*--------------------------------------------------------------------------+
806 |																			|
807 |	Store the current variable or struct name.								|
808 |																			|
809 |	input :		curr_txt points to '=' character,							|
810 |				start_txt points to beginning of the parse string.			|
811 |																			|
812 |	output :	curr_txt points to character before 1st character of		|
813 |					name.													|
814 |																			|
815 |	Note : we have to test for the beginning of the parse string,			|
816 |	because add_name() is called also for adding the "$n" name				|
817 |	of the gdb output.														|
818 |																			|
819 +--------------------------------------------------------------------------*/
add_name()820 static void add_name ()
821 {
822 	curr_txt--;								/* point before '=' */
823 	while (*curr_txt == ' ') curr_txt--;	/* skip spaces */
824 
825 	/* loop over name */
826 	while ((curr_txt >= start_txt) && GOODCHARNAME(*curr_txt))
827 		add_char(*curr_txt--);
828 }
829 
830 /*--------------------------------------------------------------------------+
831 |																			|
832 |	Skip all previous characters until corresponding " or ' character.		|
833 |																			|
834 |	input : curr_txt points before ' or " character							|
835 |																			|
836 |	output : curr_txt points before corresponding ' or " character.			|
837 |																			|
838 +--------------------------------------------------------------------------*/
search_char(c)839 void search_char(c)
840 char c;
841 {
842 	while(1)
843 		{
844 		while(c != *(curr_txt--));
845 
846 		/* make sure there is not a '\' just before */
847 
848 		if (*curr_txt != '\\')
849 			return;
850 		}
851 }
852 
853 /*--------------------------------------------------------------------------+
854 |																			|
855 |	Skip all previous characters until previous corresponding '{'.			|
856 |	All "{...}" sequences are skip.											|
857 |	Return the array item number (if applicable)							|
858 |																			|
859 |	input :		curr_txt points to string.									|
860 |																			|
861 |	output :	curr_txt points to character before '{'						|
862 |				return number of commas										|
863 |																			|
864 +--------------------------------------------------------------------------*/
skip_level()865 static int skip_level()
866 {
867 int nbcommas;
868 char c;
869 
870 	nbcommas = 0;
871 
872 	while(1)
873 		{
874 		switch (c = *(curr_txt--))
875 			{
876 			case '{' :
877 				return nbcommas;
878 
879 			case ',' :
880 				nbcommas++;
881 				break;
882 
883 			case '}' :
884 				skip_level();
885 				break;
886 
887 			case '"' :
888 			case '\'' :
889 				search_char(c);
890 				break;
891 
892 			default:
893 				break;
894 			}
895 		}
896 }
897 
898 /*--------------------------------------------------------------------------+
899 |																			|
900 |	Function to parse an output of a gdb print from							|
901 |	a pointer (0x...) and return a command line to							|
902 |	print *(0x...)															|
903 |																			|
904 |	input : command line pointer (LINESIZ size),							|
905 |			pointer print output,											|
906 |			pointer 0x...													|
907 |																			|
908 |	output : command line (stored RIGHT justified in commandline)			|
909 |																			|
910 |	example																	|
911 |																			|
912 |		start = "$1 = { (struct foo *) 0x1224}"								|
913 |		current points to 0x1224 in start,									|
914 |																			|
915 |		commandline = "print *($1)"											|
916 |																			|
917 +--------------------------------------------------------------------------*/
parse_gdb_print(commandline,start,current)918 char *parse_gdb_print (commandline, start, current)
919 char *commandline;
920 char *start;
921 char *current;
922 {
923 char *begin;
924 
925 	start_txt = start;		/* in static variables */
926 	curr_txt = current;
927 
928 	begin = strchr(start,'=');	/* find '=' in "$n =" */
929 
930 	if (!begin)
931 		return NULL;
932 
933 	init_result(commandline,LINESIZ);
934 
935 	add_string(")\n");
936 
937 	while (begin <= curr_txt)
938 		{
939 		switch (*curr_txt)
940 			{
941 			case '=':
942 				add_name();
943 
944 				/* stop now if we just parsed the '=' in "$n =" */
945 				if (curr_txt >= start_txt)
946 					{
947 					add_char('.');
948 					skip_level();
949 					}
950 				break;
951 
952 			case ',':
953 			case '{':
954 				add_char(']');
955 				add_num(skip_level());
956 				add_char('[');
957 				break;
958 
959 			default:
960 				curr_txt--;
961 			}
962 		}
963 
964 	add_string("print *(");
965 
966 	if (debug)
967 		fprintf(stderr,"datadpy=%s\n",result+result_index);
968 
969 	return result+result_index;
970 }
971 
972 #endif /* GDB */
973