[comp.sources.x] REPOST: v11i055: xxgdb - X front end for gdb, Part08/08

pierre@tce.COM (Pierre Willard) (03/07/91)

Submitted-by: pierre@tce.COM (Pierre Willard)
Posting-number: Volume 11, Issue 55
Archive-name: xxgdb/part08



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 7 (of 8)."
# Contents:  command.c datadpy.c
# Wrapped by gilbert@phi on Tue Jan 15 13:12:50 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'command.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'command.c'\"
else
echo shar: Extracting \"'command.c'\" \(23715 characters\)
sed "s/^X//" >'command.c' <<'END_OF_FILE'
X/*****************************************************************************
X *
X *  xdbx - X Window System interface to the dbx debugger
X *
X *  Copyright 1989 The University of Texas at Austin
X *  Copyright 1990 Microelectronics and Computer Technology Corporation
X *
X *  Permission to use, copy, modify, and distribute this software and its
X *  documentation for any purpose and without fee is hereby granted,
X *  provided that the above copyright notice appear in all copies and that
X *  both that copyright notice and this permission notice appear in
X *  supporting documentation, and that the name of The University of Texas
X *  and Microelectronics and Computer Technology Corporation (MCC) not be 
X *  used in advertising or publicity pertaining to distribution of
X *  the software without specific, written prior permission.  The
X *  University of Texas and MCC makes no representations about the 
X *  suitability of this software for any purpose.  It is provided "as is" 
X *  without express or implied warranty.
X *
X *  THE UNIVERSITY OF TEXAS AND MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO
X *  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
X *  FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR MCC BE LIABLE FOR
X *  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
X *  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
X *  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
X *  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
X *
X *  Author:  	Po Cheung
X *  Created:   	March 10, 1989
X * 
X *****************************************************************************
X * 
X *  xxgdb - X Window System interface to the gdb debugger
X *  
X * 	Copyright 1990 Thomson Consumer Electronics, Inc.
X *  
X *  Permission to use, copy, modify, and distribute this software and its
X *  documentation for any purpose and without fee is hereby granted,
X *  provided that the above copyright notice appear in all copies and that
X *  both that copyright notice and this permission notice appear in
X *  supporting documentation, and that the name of Thomson Consumer
X *  Electronics (TCE) not be used in advertising or publicity pertaining
X *  to distribution of the software without specific, written prior
X *  permission.  TCE makes no representations about the suitability of
X *  this software for any purpose.  It is provided "as is" without express
X *  or implied warranty.
X *
X *  TCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
X *  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
X *  SHALL TCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
X *  OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
X *  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
X *  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X *  SOFTWARE.
X *
X *  Adaptation to GDB:  Pierre Willard
X *  XXGDB Created:   	December, 1990
X *
X *****************************************************************************/
X
X/*  command.c
X *
X *    Create the command window, the command buttons and their callbacks.
X *
X *    CreateCommandPanel() : 	Create a window with command buttons
X *    CreateButtons() :		Create command buttons in panel
X *    AddButton() :		Add a command button into the command window
X *    ButtonSet() :		Action proc for command button translation
X *
X *    Command callbacks for the command buttons:
X *
X *    forwardSearch() :		forward string search
X *    reverseSearch() :		reverse string search
X *    Search() :		call either forwardSearch() or reverseSearch()
X *    PopupSearch() :		command callback for search button
X *    DoneSearch() :		command callback for DONE button in search panel
X *    CreateSearchPopup() :	create search panel
X *
X *    Command queue manipulation routines:
X *	send_command():		send a command to dbx and record in the queue
X *	get_command():		read command off head of queue
X *	insert_command():	insert command at the head of queue
X *	delete_command():	delete command from head of queue
X */
X 
X#include <signal.h>
X#include <ctype.h>
X#include <sys/wait.h>
X#include "global.h"
X
X#define	 REVERSE	0
X#define	 FORWARD	1
X
XWidget		commandWindow;			/* command panel with buttons */
XBoolean		PopupMode = False;
Xstatic int	Button;
Xstatic Widget	searchPopupShell, searchPopup;
Xstatic Widget	AddButton();
Xstatic Widget	button[30];
Xstatic char	SearchString[BUFSIZ] = "";	/* search string buffer */
Xstatic char	command[LINESIZ];
Xstatic CommandRec *commandQueue = NULL;
X#ifdef BSD
Xstatic char	savedCommand[LINESIZ] = ""; 
X#endif
X
X/* ARGSUSED */
Xstatic void ButtonSet(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    Button = atoi(params[0]);
X}
X
X/* ARGSUSED */
X/*  Execute the dbx command specifed in client_data
X */
Xstatic void DoIt (w, command, call_data)
X    Widget w;
X    XtPointer command;
X    XtPointer call_data;
X{
X    /* run, cont, next, step, where, up, down, status */
X    send_command(command);
X    AppendDialogText(command);
X}
X
X#ifndef GDB	/* >>>>>>>>>> NOT USED FOR GDB <<<<<<<<<<<<<<< */
X/* ARGSUSED */
Xstatic void Return (w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    char *funcname;
X    int  nbytes;
X
X    funcname = XFetchBytes(display, &nbytes);	/* from CUT_BUFFER0 */
X    if (nbytes == 0)
X    	strcpy(command, "return\n");
X    else
X    	sprintf(command, "return %s\n", funcname);
X    send_command(command);
X    AppendDialogText(command);
X}
X#endif /* NOT GDB */
X
X#ifdef GDB	/* >>>>>>>>>>>>>> GDB ONLY <<<<<<<<<<<<<<<< */
X/*
X	here client_data is "break" or "tbreak"
X
X*/
Xstatic void Break(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    XawTextPosition pos;
X    int line;
X    char *funcname;
X    int  nbytes;
X    char *s;
X
X    funcname = XFetchBytes(display, &nbytes);	/* from CUT_BUFFER0 */
X	if (nbytes) 
X		{
X		s = funcname;
X		while (*s == ' ') s++;	/* skip leading spaces (if any) */
X		if ((*s >= '0') && (*s <= '9'))
X			sprintf(command, "%s *%s\n",client_data,funcname);
X		else
X			sprintf(command, "%s %s\n",client_data,funcname);
X		}
X	else
X		{
X		if (displayedFile != NULL)
X			{
X			pos = XawTextGetInsertionPoint(sourceWindow);
X			line = TextPositionToLine(pos);
X			sprintf(command, "%s %d\n",client_data,line);
X			}
X		else
X			{
X			UpdateMessageWindow(BREAK_HELP, NULL);
X			bell(0);
X			return;
X			}
X		}
X		
X    send_command(command);
X    AppendDialogText(command);
X}
X
X#else	/* >>>>>>>>>> NOT USED FOR GDB <<<<<<<<<<<<<<< */
X
X/* ARGSUSED */
Xstatic void Stop_at(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    XawTextPosition pos;
X    int line;
X
X    if (displayedFile == NULL) {
X	UpdateMessageWindow(STOP_AT_HELP, NULL);
X	bell(0);
X	return;
X    }
X    pos = XawTextGetInsertionPoint(sourceWindow);
X    line = TextPositionToLine(pos);
X    sprintf(command, "stop at %d\n", line);
X    send_command(command);
X    AppendDialogText(command);
X}
X
X/* ARGSUSED */
Xstatic void Stop_in(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    char *funcname;
X    int  nbytes;
X
X    funcname = XFetchBytes(display, &nbytes);	/* from CUT_BUFFER0 */
X    if (nbytes == 0) {
X	UpdateMessageWindow(STOP_IN_HELP, NULL);
X	bell(0);
X	return;
X    }
X    sprintf(command, "stop in %s\n", funcname);
X    send_command(command);
X    AppendDialogText(command);
X}
X
X#endif /* NOT GDB */
X
X/*  Delete removes the stop_no associated with a given line number.
X *  RemoveStop() is called to undisplay the stop sign only when there
X *  are no more stop_no's associated with that line number.
X */
X/* ARGSUSED */
Xstatic void Delete(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    XawTextPosition pos;
X    char	    *string;
X    int		    stop_no, line, nbytes;
X
X    string = XFetchBytes(display, &nbytes);
X    if (nbytes > 0 && (stop_no = atoi(string)) > 0) {
X    	sprintf(command, "delete %d\n", stop_no);
X	send_command(command);
X	AppendDialogText(command);
X	return;
X    }
X    else if (displayedFile) {
X	pos = XawTextGetInsertionPoint(sourceWindow);
X	line = TextPositionToLine(pos);
X	if (stop_no = LineToStop_no(line)) {
X	    sprintf(command, "delete %d\n", stop_no);
X	    send_command(command);
X	    AppendDialogText(command);
X	    return;
X	}
X    }
X    UpdateMessageWindow(DELETE_HELP, NULL);
X    bell(0);
X}
X
X/* ARGSUSED */
Xstatic void Print(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    char *string;
X    int nbytes;
X
X    if (Button == 3) PopupMode = True;
X
X    string = XFetchBytes(display, &nbytes);
X    if (nbytes == 0) {
X	UpdateMessageWindow(PRINT_HELP, NULL);
X	bell(0);
X	return;
X    }
X    if (client_data == (XtPointer)0)
X	sprintf(command, "print %s\n", string);
X    else if (client_data == (XtPointer)1)
X	sprintf(command, "print *%s\n", string);
X    send_command(command);
X#ifdef GDB
X	if (!PopupMode)		/* for GDB don't display print if everything goes in a window */
X#endif
X    AppendDialogText(command);
X}
X
X#ifndef GDB /* >>>>>>>>>> NOT USED FOR GDB <<<<<<<<<<<<<<< */
X/* ARGSUSED */
Xstatic void Func(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    char *funcname;
X    int nbytes;
X
X    funcname = XFetchBytes(display, &nbytes);
X    if (nbytes == 0)
X    	strcpy(command, "func\n");
X    else
X    	sprintf(command, "func %s\n", funcname);
X    send_command(command);
X    AppendDialogText(command);
X}
X#endif /* NOT GDB */
X
X/* ARGSUSED */
Xstatic void Quit(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    union wait status;
X
X    write_dbx("quit\n");
X    XtDestroyApplicationContext(app_context);
X    kill(dbxpid, SIGKILL);
X    wait3(&status, WNOHANG, NULL);
X    exit(0);
X}
X
X
X/* ARGSUSED */
Xstatic void Display_(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    char *string;
X    int nbytes;
X
X    string = XFetchBytes(display, &nbytes);
X    sprintf(command, "display %s\n", string);
X    send_command(command);
X    AppendDialogText(command);
X}
X
X#ifdef GDB	/* >>>>>>>>>>>>>> GDB ONLY <<<<<<<<<<<<<<<< */
X/* ARGSUSED */
Xstatic void Undisplay(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    char *string;
X    int	 stop_no, nbytes;
X
X    string = XFetchBytes(display, &nbytes);
X    if (nbytes != 0)
X    	{
X		if ((stop_no = atoi(string)) > 0)
X			sprintf(command, "undisplay %d\n", stop_no);
X   		else
X   			{
X			UpdateMessageWindow(UNDISPLAY_HELP, NULL);
X			bell(0);
X			return;
X   			}
X   		}
X   	else
X		sprintf(command, "undisplay\n");
X   		
X	send_command(command);
X	AppendDialogText(command);
X}
X
X#else	/* >>>>>>>>>> NOT USED FOR GDB <<<<<<<<<<<<<<< */
X
X/* ARGSUSED */
Xstatic void Undisplay(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    char *string;
X    int	 stop_no, nbytes;
X
X    string = XFetchBytes(display, &nbytes);
X    if (nbytes == 0) {
X	UpdateMessageWindow(UNDISPLAY_HELP, NULL);
X	bell(0);
X	return;
X    }
X    if ((stop_no = atoi(string)) > 0)
X	sprintf(command, "undisplay %d\n", stop_no);
X    else
X    	sprintf(command, "undisplay %s\n", string);
X    send_command(command);
X    AppendDialogText(command);
X}
X#endif /* NOT GDB */
X
X#ifndef GDB	/* >>>>>>>>>> NOT USED FOR GDB <<<<<<<<<<<<<<< */
X/* ARGSUSED */
Xstatic void Dump(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    char *funcname;
X    int nbytes;
X
X    funcname = XFetchBytes(display, &nbytes);
X    if (nbytes == 0)
X    	strcpy(command, "dump\n");
X    else
X    	sprintf(command, "dump %s\n", funcname);
X    send_command(command);
X    AppendDialogText(command);
X}
X#endif /* NOT GDB */
X
X
X/*  Beginning from startpos, this routine searches text forward for 
X *  searchstring, and returns 1 if searchstring is found, also returning 
X *  the left and right positions of the matched string in left and right; 
X *  else 0 is returned.
X *  It also does wrap-around search.
X */
Xstatic forwardSearch(text, startpos, searchstring, left, right)
X    char *text;
X    int  startpos;
X    char *searchstring;
X    XawTextPosition  *left, *right;
X{
X    int  searchlength, searchsize, i, n=0;
X    char *s1, *s2;
X
X    searchlength = strlen(searchstring);
X    searchsize = strlen(text) - searchlength;
X    for (i=startpos; i < searchsize; i++) {
X	n = searchlength;
X	s1 = &text[i];
X	s2 = searchstring;
X	while (--n >= 0 && *++s1 == *s2++);
X	if (n < 0) break;
X    }
X    if (n < 0) {
X    	*left = i+1;
X    	*right = i+1+searchlength;
X    	return 1;
X    }
X    else {
X	for (i=0; i < startpos; i++) {
X	    n = searchlength;
X	    s1 = &text[i];
X	    s2 = searchstring;
X	    while (--n >= 0 && *++s1 == *s2++);
X	    if (n < 0) break;
X	}
X	if (n < 0) {
X	    *left = i+1;
X	    *right = i+1+searchlength;
X	    return 1;
X	}
X	return 0;
X    }
X}
X	
X
X/*  Similar to forwardSearch(), except that it does a reverse search
X */
Xstatic reverseSearch(text, startpos, searchstring, left, right)
X    char 	    *text;
X    XawTextPosition  startpos;
X    char 	    *searchstring;
X    XawTextPosition  *left, *right;
X{
X    int  searchlength, i, n=0;
X    char *s1, *s2;
X
X    searchlength = strlen(searchstring);
X    for (i=startpos; i > searchlength; i--) {
X	n = searchlength;
X	s1 = &text[i];
X	s2 = &searchstring[searchlength-1];
X	while (--n >= 0 && *--s1 == *s2--);
X	if (n < 0) break;
X    }
X    if (n < 0) {
X    	*right = i;
X    	*left = *right-searchlength;
X    	return 1;
X    }
X    else {
X	for (i=strlen(text)-1; i > startpos; i--) {
X	    n = searchlength;
X	    s1 = &text[i];
X	    s2 = &searchstring[searchlength-1];
X	    while (--n >= 0 && *--s1 == *s2--);
X	    if (n < 0) break;
X	}
X	if (n < 0) {
X            *right = i;
X            *left = *right-searchlength;
X	    return 1;
X	}
X	return 0;
X    }
X}
X
X/* ARGSUSED */
Xstatic void PopupSearch(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    Arg 	args[MAXARGS];
X    Cardinal 	n;
X    Dimension	popup_width, dialog_width;
X    Position	x, y;
X
X    if (!displayedFile) {
X	UpdateMessageWindow(SEARCH_HELP, NULL);
X	bell(0);
X    }
X    else {
X	XtRealizeWidget(searchPopupShell);
X	n = 0;
X	XtSetArg(args[n], XtNwidth, &popup_width);			n++;
X	XtGetValues(searchPopupShell, args, n);
X	n = 0;
X	XtSetArg(args[n], XtNwidth, &dialog_width);			n++;
X	XtGetValues(dialogWindow, args, n);
X	XtTranslateCoords(dialogWindow, 
X			  (Position)(dialog_width - popup_width)/2, 10, &x, &y);
X	n = 0;
X	XtSetArg(args[n], XtNx, x);					n++;
X	XtSetArg(args[n], XtNy, y);					n++;
X	XtSetValues(searchPopupShell, args, n);
X	XtPopup(searchPopupShell, XtGrabNone);
X    }
X}
X
X
X/* ARGSUSED */
X/*  This routine handles both forward and reverse text search.
X *  If no text has been entered, the contents of the cut buffer are used
X *  for searching.
X */ 
Xstatic void Search(w, direction, call_data)
X    Widget w;
X    XtPointer direction;
X    XtPointer call_data;
X{
X    XawTextBlock    	textblock;
X    XawTextPosition	pos, left, right;
X    char		*searchString;
X
X    searchString = XawDialogGetValueString(searchPopup);
X    if (strlen(searchString) == 0) {
X	textblock.ptr = XFetchBytes(display, &textblock.length);
X	if (!textblock.ptr) {
X	    UpdateMessageWindow("No search string selected", NULL);
X	    bell(0);
X	    return;
X	}
X	searchString = textblock.ptr;
X    }
X    pos = XawTextGetInsertionPoint(sourceWindow);
X    if ((direction == (XtPointer)FORWARD && 
X	forwardSearch(displayedFile->buf, pos, searchString, &left, &right)) ||
X        (direction == (XtPointer)REVERSE && 
X	reverseSearch(displayedFile->buf, pos, searchString, &left, &right))) {
X        AdjustText(TextPositionToLine(left));
X        XawTextSetSelection(sourceWindow, left, right);
X        XawTextSetInsertionPoint(sourceWindow, left);
X    }
X    else {
X        if (direction == (XtPointer)FORWARD)
X            UpdateMessageWindow("String not found", NULL);
X        else if (direction == (XtPointer)REVERSE)
X            UpdateMessageWindow("String not found", NULL);
X        else
X#ifdef GDB
X            UpdateMessageWindow("xxgdb error: illegal search direction", NULL);
X#else
X            UpdateMessageWindow("xdbx error: illegal search direction", NULL);
X#endif
X        bell(0);
X    }
X}
X
X/* ARGSUSED */
Xstatic void DoneSearch(w, client_data, call_data)
X    Widget w;
X    XtPointer client_data;
X    XtPointer call_data;
X{
X    XtPopdown(client_data);
X}
X
X/* ARGSUSED */
Xstatic void Activate(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    Search(w, (XtPointer)FORWARD, NULL);
X    DoneSearch(w, (XtPointer)searchPopupShell, NULL);
X}
X
Xstatic void CreateSearchPopup()
X{
X    Widget	dialogValue;
X    Arg 	args[MAXARGS];
X    Cardinal 	n;
X
X    static XtActionsRec search_actions[] = {
X        {"Activate", Activate},
X        {NULL, NULL}
X    };
X
X    static String translations = "#override\n\
X        <Key>Return:         Activate() \n\
X    ";
X
X    n = 0;
X    XtSetArg(args[n], XtNinput, True);					n++;
X    XtSetArg(args[n], XtNallowShellResize, True);			n++;
X    searchPopupShell = XtCreatePopupShell("Search", transientShellWidgetClass, 
X	toplevel, args, n);
X
X    n = 0;
X    XtSetArg(args[n], XtNlabel, "Enter search string :");		n++;
X    XtSetArg(args[n], XtNvalue, SearchString);				n++;
X    searchPopup = XtCreateManagedWidget("searchPopup", dialogWidgetClass, 
X	searchPopupShell, args, n);
X    
X    AddButton(searchPopup, "<<", Search, (XtPointer) REVERSE);
X    AddButton(searchPopup, ">>", Search, (XtPointer) FORWARD);
X    AddButton(searchPopup, "DONE", DoneSearch, (XtPointer)searchPopupShell);
X
X    dialogValue = XtNameToWidget(searchPopup, "value");
X    XtOverrideTranslations(dialogValue, XtParseTranslationTable(translations));
X    XtAppAddActions(app_context, search_actions, XtNumber(search_actions));
X}
X
X
X
Xstatic Widget AddButton(parent, name, function, client_data)
XWidget parent;
Xchar *name;
Xvoid (*function) ();
XXtPointer client_data;		/* callback registered data */
X{
X    Widget 	button;
X    Arg 	args[MAXARGS];
X    Cardinal 	n;
X
X    static XtActionsRec command_actions[] = {
X	{"ButtonSet", (XtActionProc) ButtonSet},
X        {NULL, NULL}
X    };
X
X    static String translations = "\
X	<EnterWindow>:	highlight() \n\
X	<LeaveWindow>:	reset() \n\
X	<Btn1Down>:	set()\n\
X	<Btn1Up>:	ButtonSet(1) notify() unset() \n\
X	<Btn3Down>:	set()\n\
X	<Btn3Up>:	ButtonSet(3) notify() unset()\n\
X    ";
X
X    n = 0;
X    XtSetArg(args[n], XtNresize, (XtArgVal) False);			n++;
X    if (strcmp(name, "print") == NULL || strcmp(name, "print *") == NULL) {
X	XtSetArg(args[n], XtNtranslations, 
X	    XtParseTranslationTable(translations)); 			n++;
X    }
X    button = XtCreateManagedWidget(name, commandWidgetClass, parent, args, n);
X    XtAddCallback(button, XtNcallback, function, client_data);
X    XtAppAddActions(app_context, command_actions, XtNumber(command_actions));
X    return (button);
X}
X
X
Xstatic void CreateButtons (parent)
XWidget parent;
X{
X    int i=0;
X
X#ifdef GDB	/* >>>>>>>>>>>>>> GDB ONLY <<<<<<<<<<<<<<<< */
X    button[i++] = AddButton (parent, "run", DoIt, "run\n");
X    button[i++] = AddButton (parent, "cont", DoIt, "cont\n");
X    button[i++] = AddButton (parent, "next", DoIt, "next\n");
X    button[i++] = AddButton (parent, "step", DoIt, "step\n");
X    button[i++] = AddButton (parent, "finish", DoIt, "finish\n");
X    button[i++] = AddButton (parent, "break", Break, "break");
X    button[i++] = AddButton (parent, "tbreak", Break, "tbreak");
X    button[i++] = AddButton (parent, "delete", Delete, NULL);
X    button[i++] = AddButton (parent, "up", DoIt, "up\n");
X    button[i++] = AddButton (parent, "down", DoIt, "down\n");
X    button[i++] = AddButton (parent, "print", Print, (XtPointer)0);
X    button[i++] = AddButton (parent, "print *", Print, (XtPointer)1);
X    button[i++] = AddButton (parent, "display", Display_, NULL);
X    button[i++] = AddButton (parent, "undisplay", Undisplay, NULL);
X    button[i++] = AddButton (parent, "args", DoIt, "info args\n");
X    button[i++] = AddButton (parent, "locals", DoIt, "info locals\n");
X    button[i++] = AddButton (parent, "stack", DoIt, "info stack\n");
X    button[i++] = AddButton (parent, "search", PopupSearch, NULL);
X    button[i++] = AddButton (parent, "file", File, NULL);
X    button[i++] = AddButton (parent, "quit", Quit, NULL);
X#else	/* >>>>>>>>>> IF NOT GDB <<<<<<<<<<<<<<< */
X
X
X    button[i++] = AddButton (parent, "run", DoIt, "run\n");
X    button[i++] = AddButton (parent, "cont", DoIt, "cont\n");
X    button[i++] = AddButton (parent, "next", DoIt, "next\n");
X    button[i++] = AddButton (parent, "step", DoIt, "step\n");
X#ifdef BSD
X    button[i++] = AddButton (parent, "return", Return, "return\n");
X#endif
X    button[i++] = AddButton (parent, "stop at", Stop_at, NULL);
X    button[i++] = AddButton (parent, "stop in", Stop_in, NULL);
X    button[i++] = AddButton (parent, "delete", Delete, NULL);
X    button[i++] = AddButton (parent, "where", DoIt, "where\n");
X    button[i++] = AddButton (parent, "up", DoIt, "up\n");
X    button[i++] = AddButton (parent, "down", DoIt, "down\n");
X    button[i++] = AddButton (parent, "print", Print, (XtPointer)0);
X    button[i++] = AddButton (parent, "print *", Print, (XtPointer)1);
X    button[i++] = AddButton (parent, "func", Func, NULL);
X    button[i++] = AddButton (parent, "file", File, NULL);
X    button[i++] = AddButton (parent, "status", DoIt, "status\n");
X#ifndef BSD
X    button[i++] = AddButton (parent, "display", Display_, NULL);
X    button[i++] = AddButton (parent, "undisplay", Undisplay, NULL);
X#endif
X    button[i++] = AddButton (parent, "dump", Dump, NULL);
X    button[i++] = AddButton (parent, "search", PopupSearch, NULL);
X    button[i++] = AddButton (parent, "quit", Quit, NULL);
X#endif /* NOT GDB */
X
X    button[i++] = NULL;
X    CreateSearchPopup();
X}
X
X
X/*  Create a command widget, and the buttons.  */
X
Xvoid CreateCommandPanel(parent)
XWidget parent;
X{
X    Arg args[10];
X    Cardinal n;
X
X    n = 0;
X    commandWindow = XtCreateManagedWidget("commandWindow", boxWidgetClass, 
X					  parent, args, n);
X    CreateButtons(commandWindow);
X    getwd(cwd);
X}
X
X/**************************************************************************
X *
X *  Command queue functions
X *
X **************************************************************************/
X
X/*  Append command to end of the command queue and send the command to dbx */
X
Xvoid send_command(command)
Xchar *command;
X{
X    CommandRec *p, *q, *r;
X
X#ifdef BSD 
X    /* Save the command if it is not a blank command; else use the 
X       last saved command instead */
X    if (strcspn(command, " \n"))
X	strcpy(savedCommand, command);
X    else
X	strcpy(command, savedCommand);
X#endif
X
X    p = (CommandRec *)XtNew(CommandRec);
X    p->command = XtNewString(command);
X    p->next = NULL;
X    if (!commandQueue)
X	commandQueue = p;
X    else {
X	q = commandQueue;
X	while (r = q->next)
X	    q = r;
X	q->next = p;
X    }
X    write_dbx(command);
X}
X
X/*  Read command at the head of the command queue */
X
Xchar *get_command()
X{
X    if (commandQueue) {
X	return (commandQueue->command);
X    }
X    else
X	return NULL;
X}
X
X/*  Delete command from the head of the command queue */
X
Xvoid delete_command()
X{
X    CommandRec *p;
X
X    if (p = commandQueue) {
X	commandQueue = p->next;
X	XtFree(p->command);
X	XtFree(p);
X    }
X}
X
X/*  Insert command into head of queue */
X
Xvoid insert_command(command)
Xchar *command;
X{
X    CommandRec *p;
X
X    p = (CommandRec *)XtNew(CommandRec);
X    p->command = XtNewString(command);
X    p->next = NULL;
X    if (!commandQueue)
X	commandQueue = p;
X    else {
X	p->next = commandQueue;
X	commandQueue = p;
X    }
X}
END_OF_FILE
if test 23715 -ne `wc -c <'command.c'`; then
    echo shar: \"'command.c'\" unpacked with wrong size!
fi
# end of 'command.c'
fi
if test -f 'datadpy.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'datadpy.c'\"
else
echo shar: Extracting \"'datadpy.c'\" \(21580 characters\)
sed "s/^X//" >'datadpy.c' <<'END_OF_FILE'
X/*****************************************************************************
X *
X *  xdbx - X Window System interface to the dbx debugger
X *
X *  Copyright 1989 The University of Texas at Austin
X *  Copyright 1990 Microelectronics and Computer Technology Corporation
X *
X *  Permission to use, copy, modify, and distribute this software and its
X *  documentation for any purpose and without fee is hereby granted,
X *  provided that the above copyright notice appear in all copies and that
X *  both that copyright notice and this permission notice appear in
X *  supporting documentation, and that the name of The University of Texas
X *  and Microelectronics and Computer Technology Corporation (MCC) not be 
X *  used in advertising or publicity pertaining to distribution of
X *  the software without specific, written prior permission.  The
X *  University of Texas and MCC makes no representations about the 
X *  suitability of this software for any purpose.  It is provided "as is" 
X *  without express or implied warranty.
X *
X *  THE UNIVERSITY OF TEXAS AND MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO
X *  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
X *  FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR MCC BE LIABLE FOR
X *  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
X *  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
X *  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
X *  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
X *
X *  Author:  	Po Cheung
X *  Created:   	March 10, 1989
X * 
X *****************************************************************************
X * 
X *  xxgdb - X Window System interface to the gdb debugger
X *  
X * 	Copyright 1990 Thomson Consumer Electronics, Inc.
X *  
X *  Permission to use, copy, modify, and distribute this software and its
X *  documentation for any purpose and without fee is hereby granted,
X *  provided that the above copyright notice appear in all copies and that
X *  both that copyright notice and this permission notice appear in
X *  supporting documentation, and that the name of Thomson Consumer
X *  Electronics (TCE) not be used in advertising or publicity pertaining
X *  to distribution of the software without specific, written prior
X *  permission.  TCE makes no representations about the suitability of
X *  this software for any purpose.  It is provided "as is" without express
X *  or implied warranty.
X *
X *  TCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
X *  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
X *  SHALL TCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
X *  OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
X *  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
X *  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X *  SOFTWARE.
X *
X *  Adaptation to GDB:  Pierre Willard
X *  XXGDB Created:   	December, 1990
X *
X *****************************************************************************/
X
X/*  dataDpy.c:
X *
X *   Provide graphical display of C pointers and structures.
X *
X *   BuildLinePos():	Construct an array indexing the character position of 
X *			each line.
X *   PositionToLine():	Return the character position of a given line.   
X *   SelectPointer():	Action proc for double click on a pointer value,
X *   CreateDataPopup():	Create a popup to display the object pointed to by a
X *			pointer.
X *   UpdateDataPopup(): Update an unused popupshell to display data.
X *   AppendList():	Append a popup to the list.
X *   DeleteList():	Delete a popup from the list.
X *   pop_down():	pop down the popup and free storage.
X *   DestroyDataPopup():event handler for destroying a popup, call DeleteList()
X *			and pop_down().
X *   MovePopup():	Position the popup.
X *   print_handler():	Action handler for displaying pointers and structures.
X */
X
X#include 	"global.h"
X#include 	"regex.h"
X#include 	"datadpy.h"
X
X#define		MAXLEVELS	20	/* max level of indentation */
X#ifdef GDB
X#define		INDENT		2	/* # of spaces for each indentation */
X#else
X#define		INDENT		8	/* # of spaces for each indentation */
X#endif /* GDB */
X#define 	EMPTY           0
X#define 	UNUSED          1
X#define 	USED            2
X#define 	LEFT_MARGIN	10
X#define 	SCROLLBAR_WIDTH	15
X
X
Xstatic DataDpyRec	**dataDpyTable;
Xstatic int		dataDpyTableSize = 0;
Xstatic DataDpyRec	*Parent = NULL;
Xstatic DataDpyList	*TopParentList = NULL;
Xstatic int		font_height, font_width;
Xstatic void		DestroyDataPopup();
X
X/* 
X *  Build an array which gives the starting text position of each line.
X *  Very similar to the routine in source.c.
X */
Xstatic void BuildLinePos(dataDpy)
XDataDpyRec *dataDpy;
X{
X    char *p;
X    int	 line, nlines;
X    int	 max=0;
X
X    nlines = MAX(1, dataDpy->buflen/CHARS_PER_LINE);
X    dataDpy->linepos = (XawTextPosition *)
X                    XtMalloc ((nlines+2) * sizeof(XawTextPosition));
X    p = dataDpy->buf;
X    line = 0;
X    dataDpy->linepos[line++] = 0;
X    dataDpy->linepos[line++] = 0;
X    while (*p) {
X        if (*p++ == '\n') {
X            if (line == nlines) {       /* buffer full, need more memory */
X                dataDpy->linepos = (XawTextPosition *)XtRealloc(dataDpy->linepos,
X                          (nlines + ADD_LINES) * sizeof(XawTextPosition));
X                nlines += ADD_LINES;
X            }
X            dataDpy->linepos[line] = p - dataDpy->buf;
X	    AssignMax(max, dataDpy->linepos[line] - dataDpy->linepos[line-1]);
X	    line++;
X        }
X    }
X    dataDpy->numlines = line - 2;
X    dataDpy->maxLineLength = max;
X    /* shrink to min size */
X    dataDpy->linepos = (XawTextPosition *) XtRealloc     
X                        (dataDpy->linepos, line * sizeof(XawTextPosition));
X}
X
X/*
X *  Return the line number for the specified text position.
X */
Xstatic int PositionToLine(dataDpy, pos)
XDataDpyRec *dataDpy;
XXawTextPosition pos;
X{
X    int	 line;
X
X    if (dataDpy && pos >= 0) {
X    	for (line = 1; pos >= dataDpy->linepos[line]; line++);
X    	return (line-1);
X    }
X    else
X	return (0);
X}
X
X/* ARGSUSED */
X/*  
X *  Called by double click of pointer button.
X *  If the selected text is a valid pointer, this routine parses the data 
X *  output to obtain the full qualified name of the pointer, and asks
X *  dbx to print the value of the object the pointer is pointing to.
X */
Xstatic void SelectPointer(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    struct re_registers regs;
X    XawTextPosition 	left, right;
X    char		*selection, *p, *field[MAXLEVELS];
X    DataDpyRec		*dataDpy;
X    int			fromLine, line;
X    int			i, n, nbytes, r, level, newlevel;
X    char		name[LINESIZ], command[LINESIZ];
X
X    /* Find out which data display output does the selection belong to */
X    dataDpy = NULL;
X    for (i=0; dataDpyTable[i]; i++)
X	if ((Widget) w == (Widget) dataDpyTable[i]->dataDpyWindow) {
X	    dataDpy = dataDpyTable[i];
X	    Parent = dataDpy;
X	    break;
X	}
X    if (!dataDpy) return;
X
X    /* Get the selection and check if it's a pointer value, 0x???? */
X    selection = XFetchBytes(display, &nbytes);
X    if (re_match(dataPattern[D_POINTER].buf, selection, strlen(selection), 0, 0)
X	< 0) {
X	Parent = NULL;
X	return;
X    }
X
X    /* Parse the output to get the fully qualified name of the pointer */
X    XawTextGetSelectionPos(w, &left, &right);
X    fromLine = PositionToLine(dataDpy, left);
X    p = dataDpy->buf + dataDpy->linepos[fromLine];
X
X    if (re_match(dataPattern[D_FIELD].buf, p, strlen(p), 0, &regs) >= 0) {
X	r = dataPattern[D_FIELD].reg_token[TK_POINTER];
X	if (strncmp(selection, p+regs.start[r], regs.end[r]-regs.start[r]))
X	    return;
X	r = dataPattern[D_FIELD].reg_token[TK_INDENT];
X	level = regs.end[r]/INDENT;
X	field[level+1] = NULL;
X
X	r = dataPattern[D_FIELD].reg_token[TK_FIELD];
X	n = regs.end[r] - regs.start[r];
X	field[level] = (char *) XtMalloc ((n+1) * sizeof(char));
X	strncpy(field[level], p+regs.start[r], n);
X	field[level][n] = '\0';
X
X	for (line = fromLine-1; line > 0; line--) {
X	    p = dataDpy->buf + dataDpy->linepos[line];
X	    if (re_match(dataPattern[D_STRUCT].buf, p, strlen(p), 0, &regs)>=0){
X		r = dataPattern[D_STRUCT].reg_token[TK_INDENT];
X		newlevel = regs.end[r]/INDENT;
X		if (newlevel == level-1) {
X		    level--;
X		    r = dataPattern[D_STRUCT].reg_token[TK_FIELD];
X		    n = regs.end[r] - regs.start[r];
X		    field[level] = (char *) XtMalloc ((n+1) * sizeof(char));
X		    strncpy(field[level], p+regs.start[r], n);
X		    field[level][n] = '\0';
X		}
X	    }
X	}
X	if (*field[0] == '*' && field[1])
X	    sprintf(name, "(%s)", field[0]+1);
X	else
X	    strcpy(name, field[0]);
X	for (i=1; field[i]; i++) {
X	    strcat(name, ".");
X	    strcat(name, field[i]);
X	}
X	sprintf(command, "print *(%s)\n", name);
X	PopupMode = True;
X	query_dbx(command);
X    }
X}
X
X    
X/*
X *  Create a data display with a label.
X *  The popupshell has a form widget which consists of a label and a text
X *  widget.
X */
Xstatic void CreateDataPopup(dataDpy, label)
XDataDpyRec *dataDpy;
Xchar	   *label;
X{
X    Arg         args[MAXARGS];
X    Cardinal    n;
X    Dimension	dataDpyHeight, dataDpyWidth;
X    XFontStruct	*text_font;
X
X    static XtActionsRec datadpy_actions[] = {
X        {"SelectPointer", (XtActionProc) SelectPointer},
X        {NULL, NULL}
X    };
X
X    static String translations = "#override \n\
X        <Btn1Down>:     SelectStart() SelectWord() SelectPointer() \n\
X        <Btn1Up>:       SelectEnd() \n\
X    ";
X
X    n = 0;
X    dataDpy->popupshell = XtCreatePopupShell("Data Popup", 
X	transientShellWidgetClass, toplevel, args, n);
X
X    n = 0;
X    XtSetArg(args[n], XtNdefaultDistance, 0);                           n++;
X    dataDpy->popup = XtCreateManagedWidget("popup", formWidgetClass,
X	dataDpy->popupshell, args, n);
X
X    /* Create the label */
X    n = 0;
X    XtSetArg(args[n], XtNtop, (XtArgVal) XawChainTop);                  n++;
X    XtSetArg(args[n], XtNbottom, (XtArgVal) XawChainTop);               n++;
X    XtSetArg(args[n], XtNright, (XtArgVal) XawChainRight);              n++;
X    XtSetArg(args[n], XtNleft, (XtArgVal) XawChainLeft);               	n++;
X    XtSetArg(args[n], XtNlabel, (XtArgVal) label);                     	n++;
X    XtSetArg(args[n], XtNresize, (XtArgVal) False);                    	n++;
X    XtSetArg(args[n], XtNjustify, (XtArgVal) XtJustifyCenter);         	n++;
X    dataDpy->label = XtCreateManagedWidget("label", labelWidgetClass, 
X	dataDpy->popup, args, n);
X    XtAddEventHandler(dataDpy->label, (EventMask) ButtonPressMask, False, 
X	DestroyDataPopup, dataDpy);
X
X    /* Create the text window */
X    n = 0;
X    XtSetArg(args[n], XtNfromVert, (XtArgVal) dataDpy->label);          n++;
X    XtSetArg(args[n], XtNtop, (XtArgVal) XawChainTop);                  n++;
X    XtSetArg(args[n], XtNbottom, (XtArgVal) XawChainBottom);            n++;
X    XtSetArg(args[n], XtNright, (XtArgVal) XawChainRight);              n++;
X    XtSetArg(args[n], XtNleft, (XtArgVal) XawChainLeft);               	n++;
X
X    XtSetArg(args[n], XtNleftMargin, (XtArgVal) LEFT_MARGIN); 		n++;
X    XtSetArg(args[n], XtNuseStringInPlace, (XtArgVal) True); 		n++;
X    XtSetArg(args[n], XtNstring, (XtArgVal) dataDpy->buf);            	n++;
X    XtSetArg(args[n], XtNlength, (XtArgVal) dataDpy->buflen);  		n++;
X    XtSetArg(args[n], XtNeditType, (XtArgVal) XawtextRead);             n++;
X    XtSetArg(args[n], XtNscrollHorizontal, XawtextScrollWhenNeeded);	n++;
X    XtSetArg(args[n], XtNscrollVertical, XawtextScrollWhenNeeded);	n++;
X    XtSetArg(args[n], XtNtranslations, XtParseTranslationTable(translations));
X                                                                        n++;
X    dataDpy->dataDpyWindow = XtCreateManagedWidget("dataDpyWindow", 
X	asciiTextWidgetClass, dataDpy->popup, args, n);
X    XtAppAddActions(app_context, datadpy_actions, XtNumber(datadpy_actions));
X
X    /* Get the text font */
X    n = 0;
X    XtSetArg(args[n], XtNfont, &text_font);                  		n++;
X    XtGetValues(dataDpy->dataDpyWindow, args, n);
X
X    /* Estimate the size of the text widget, dataDpyWindow, with the number
X       of lines and the maximum length of a line.  Assume fixed font width.
X    */
X    font_height = text_font->ascent + text_font->descent;
X    font_width = text_font->max_bounds.width;
X    dataDpyHeight = dataDpy->numlines * font_height + 5;
X    dataDpyWidth = dataDpy->maxLineLength * font_width + LEFT_MARGIN;
X    if (dataDpyHeight > app_resources.dataDpyMaxHeight)
X	dataDpyWidth += SCROLLBAR_WIDTH;
X	
X#if 1	/*(PW)17DEC90 : bug ! */
X#define 	SCROLLBAR_HEIGHT	15
X    if (dataDpyWidth > app_resources.dataDpyMaxWidth)
X	dataDpyHeight += SCROLLBAR_HEIGHT;
X#endif
X
X    AssignMin(dataDpyHeight, app_resources.dataDpyMaxHeight);
X    AssignMin(dataDpyWidth, app_resources.dataDpyMaxWidth);
X		
X    n = 0;
X    XtSetArg(args[n], XtNheight, (XtArgVal) dataDpyHeight); 		n++;
X    XtSetArg(args[n], XtNwidth, (XtArgVal) dataDpyWidth); 		n++;
X    XtSetValues(dataDpy->dataDpyWindow, args, n);
X
X    n = 0;
X    XtSetArg(args[n], XtNwidth, (XtArgVal) dataDpyWidth); 		n++;
X    XtSetValues(dataDpy->label, args, n);
X}
X
X/*
X *  Instead of creating a new popupshell, this routine uses an already
X *  existing popupshell for data display.
X *  It changes the label, calculates the size of the popupshell,
X *  and sets the source of the text window to that of the new data.
X */
Xstatic void UpdateDataPopup(dataDpy, label)
XDataDpyRec *dataDpy;
Xchar	   *label;
X{
X    Arg args[MAXARGS];
X    Cardinal n;
X    Dimension	popupHeight, popupWidth, dataDpyHeight, dataDpyWidth,
X		labelHeight, labelBorderWidth, dataDpyBorderWidth;
X
X    /* Update the label */
X    n = 0;
X    XtSetArg(args[n], XtNlabel, (XtArgVal) label);                     	n++;
X    XtSetValues(dataDpy->label, args, n);
X
X    /* Calculate the size of popupshell */
X    dataDpyHeight = dataDpy->numlines * font_height + 5;
X    dataDpyWidth = dataDpy->maxLineLength * font_width + 2*10;
X    
X#if 1	/*(PW)18DEC90 : bug ! */
X    if (dataDpyHeight > app_resources.dataDpyMaxHeight)
X	dataDpyWidth += SCROLLBAR_WIDTH;
X	
X    if (dataDpyWidth > app_resources.dataDpyMaxWidth)
X	dataDpyHeight += SCROLLBAR_HEIGHT;
X#endif
X
X    AssignMin(dataDpyHeight, app_resources.dataDpyMaxHeight);
X    AssignMin(dataDpyWidth, app_resources.dataDpyMaxWidth);
X
X    n = 0;
X    XtSetArg(args[n], XtNheight, (XtArgVal) &labelHeight); 		n++;
X    XtSetArg(args[n], XtNborderWidth, (XtArgVal) &labelBorderWidth); 	n++;
X    XtGetValues(dataDpy->label, args, n);
X    n = 0;
X    XtSetArg(args[n], XtNborderWidth, (XtArgVal) &dataDpyBorderWidth); 	n++;
X    XtGetValues(dataDpy->dataDpyWindow, args, n);
X
X    popupHeight = dataDpyHeight + labelHeight + 2*labelBorderWidth +
X		  2*dataDpyBorderWidth;
X    popupWidth = dataDpyWidth;
X    
X    n = 0;
X    XtSetArg(args[n], XtNheight, (XtArgVal) popupHeight); 		n++;
X    XtSetArg(args[n], XtNwidth, (XtArgVal) popupWidth);			n++;
X    XtSetValues(dataDpy->popupshell, args, n);
X
X    /* Set the text source */
X    n = 0;
X    XtSetArg(args[n], XtNstring, (XtArgVal) dataDpy->buf);		n++;
X    XtSetArg(args[n], XtNlength, (XtArgVal) dataDpy->buflen);           n++;
X    XawTextSetSource(dataDpy->dataDpyWindow, 
X		     XtCreateWidget("textsrc", asciiSrcObjectClass, 
X				    dataDpy->dataDpyWindow, args, n),
X		     0);
X}
X
X/*
X *  Append dataDpy to a DataDpyList pointed to by head.
X */
Xstatic void AppendList(head, dataDpy)
XDataDpyList **head;
XDataDpyRec  *dataDpy;
X{
X    DataDpyList	*p, *q, *r;
X
X    p = (DataDpyList *) XtNew (DataDpyList);
X    p->dataDpy = dataDpy;
X    p->next = NULL;
X    q = *head;
X    if (!q)
X	*head = p;
X    else {
X	while (r = q->next)
X	    q = r;
X	q->next = p;
X    }
X}
X
X/*
X *  Removes a dataDpy from its parent's list of children.
X */
Xstatic void DeleteList(head, dataDpy)
XDataDpyList **head;
XDataDpyRec  *dataDpy;
X{
X    DataDpyList *p, *q;
X
X    if (p = *head) {
X	if (p->dataDpy == dataDpy)
X	    *head = p->next;
X	else {
X	    for (q = p->next; q && q->dataDpy != dataDpy;) {
X		p = q; 
X		q = p->next;
X	    }
X	    if (q) p->next = q->next;
X	}
X    }
X}
X	    
X/*
X *  Pop down a dataDpy and all its descendants, freeing storage and
X *  reinitializing fields.
X */
Xstatic void pop_down(dataDpy)
XDataDpyRec *dataDpy;
X{
X    DataDpyList *p, *q;
X
X    XtPopdown(dataDpy->popupshell);
X    XtFree(dataDpy->linepos);
X    XtFree(dataDpy->buf);
X    dataDpy->buf = NULL;
X    dataDpy->buflen = 0;
X    dataDpy->linepos = NULL;
X    dataDpy->state = UNUSED; 
X    dataDpy->parent = NULL; 
X    for (p = dataDpy->childlist; p;) {
X	pop_down(p->dataDpy);
X	q = p;
X	p = p->next;
X	XtFree(q);
X    }
X    dataDpy->childlist = NULL;
X}
X
X/*
X *  Invoked by a ButtonPress event on the label of a data display to
X *  pop down itself and its descendants.
X */
X/* ARGSUSED */
Xstatic void DestroyDataPopup(w, dataDpy, event)
X    Widget w;
X    DataDpyRec *dataDpy;
X    XEvent *event;
X{
X    if (!dataDpy->parent)
X    	DeleteList(&TopParentList, dataDpy);
X    else
X    	DeleteList(&dataDpy->parent->childlist, dataDpy);
X    pop_down(dataDpy);
X}
X
X/*
X *  Position the data display on the screen to reflect the parent-child
X *  relationship.
X */
Xstatic void MovePopup(dataDpy)
XDataDpyRec *dataDpy;
X{
X    Arg         args[MAXARGS];
X    Cardinal    n;
X    Screen	*screen;
X    int		popupHeight, popupWidth, screenHeight, screenWidth;
X    Position	x, y;
X    Dimension	dataDpyWidth, dataDpyHeight, dataDpyBorderWidth, 
X		labelHeight, labelBorderWidth, width, height, borderWidth;
X    DataDpyList	*p, *q;
X
X    Parent = NULL;
X    if (!dataDpy->parent)
X	p = TopParentList;
X    else
X	p = dataDpy->parent->childlist;
X
X    /*  Look for its previous sibling  */
X    for (q = p->next; q && q->dataDpy != dataDpy;) {
X	p = q;
X	q = q->next;
X    }
X    /*  If a sibling exists, place the new popup right next to it  */
X    if (q) {
X	n = 0;
X	XtSetArg(args[n], XtNwidth, (XtArgVal) &width);             n++;
X	XtSetArg(args[n], XtNborderWidth, (XtArgVal) &borderWidth);	n++;
X	XtGetValues(p->dataDpy->popupshell, args, n);
X	XtTranslateCoords(p->dataDpy->popupshell, 0, 0, &x, &y);
X	x += width;
X	y -= borderWidth;
X    }
X    else {	/* no siblings */
X	/*  this is the very first popup  */
X	if (!dataDpy->parent) {
X	    x = 0;
X	    y = 0;
X	}
X	/*  place it under its parent  */
X	else {
X	    n = 0;
X	    XtSetArg(args[n], XtNheight, (XtArgVal) &height);		n++;
X	    XtGetValues(dataDpy->parent->popupshell, args, n);
X	    XtTranslateCoords(dataDpy->parent->popupshell, 30, (Position)height,
X		 &x, &y);
X	}
X    }
X
X    /* Make sure the popup does not go outside of the screen */
X    n = 0;
X    XtSetArg(args[n], XtNwidth, (XtArgVal) &dataDpyWidth);             	n++;
X    XtSetArg(args[n], XtNheight, (XtArgVal) &dataDpyHeight);           	n++;
X    XtSetArg(args[n], XtNborderWidth, (XtArgVal) &dataDpyBorderWidth); 	n++;
X    XtGetValues(dataDpy->dataDpyWindow, args, n);
X
X    n = 0;
X    XtSetArg(args[n], XtNheight, (XtArgVal) &labelHeight); 		n++;
X    XtSetArg(args[n], XtNborderWidth, (XtArgVal) &labelBorderWidth); 	n++;
X    XtGetValues(dataDpy->label, args, n);
X
X    popupHeight = dataDpyHeight + labelHeight + 2*labelBorderWidth +
X		  2*dataDpyBorderWidth;
X    popupWidth = dataDpyWidth;
X
X    screen = XtScreen(toplevel);
X    screenHeight = XHeightOfScreen(screen);
X    screenWidth = XWidthOfScreen(screen);
X
X    if (x + popupWidth > screenWidth && y + popupHeight > screenHeight) {
X	x = screenWidth - popupWidth;
X	y = screenHeight - popupHeight;
X    }
X    else if (x + popupWidth > screenWidth)
X	x = screenWidth - popupWidth;
X    else if (y + popupHeight > screenHeight)
X	y = screenHeight - popupHeight;
X
X    n = 0;
X    XtSetArg(args[n], XtNx, x);						n++;
X    XtSetArg(args[n], XtNy, y);						n++;
X    XtSetValues(dataDpy->popupshell, args, n);
X}
X
X/*
X *  Handler procedure called by parse().
X *  The main function to popup a data display.
X */
Xvoid print_handler(output)
Xchar *output;
X{
X    DataDpyRec 	*dataDpy;
X    int		i, j;
X
X    if (!output) return;
X    if (!PopupMode) return;
X    PopupMode = False;
X    XDefineCursor(display, XtWindow(toplevel), watch);
X    if (Parent)
X    	XDefineCursor(display, XtWindow(Parent->dataDpyWindow), watch);
X    UpdateMessageWindow("Click the label to pop down the data popup");
X
X    /* Searches the table for an unused or empty slot */
X    for (i=0; dataDpyTable && dataDpyTable[i] && dataDpyTable[i]->state == USED 
X	      && i < dataDpyTableSize; i++);
X    if (i == dataDpyTableSize) {			/* Table full */
X	dataDpyTableSize += ADD_SIZE;
X	dataDpyTable = (DataDpyRec **) XtRealloc (dataDpyTable, 
X			   dataDpyTableSize * sizeof(DataDpyRec *));
X	for (j=i; j<dataDpyTableSize; j++)
X	    dataDpyTable[j] = NULL;
X    }
X
X    /*  Empty slot found, allocate a data structure and initializes some
X	of the fields.  */
X    if (dataDpyTable[i] == NULL) {
X	dataDpyTable[i] = (DataDpyRec *) XtMalloc (sizeof(DataDpyRec));
X	dataDpyTable[i]->state = EMPTY;
X	dataDpyTable[i]->parent = NULL;
X	dataDpyTable[i]->childlist = NULL;
X    }
X
X    dataDpy = dataDpyTable[i];
X    dataDpy->id = i;					/* not needed */
X    dataDpy->buf = XtNewString(output);
X    dataDpy->buflen = strlen(output);
X    BuildLinePos(dataDpy);
X
X    if (dataDpy->state == EMPTY)
X	CreateDataPopup(dataDpy, Token.mesg);
X    else if (dataDpy->state == UNUSED)
X	UpdateDataPopup(dataDpy, Token.mesg);
X
X    dataDpy->state = USED;				/* mark it used */
X    if (dataDpy->parent = Parent)
X    	AppendList(&Parent->childlist, dataDpy);
X    else
X    	AppendList(&TopParentList, dataDpy);
X
X    MovePopup(dataDpy);
X    XtPopup(dataDpy->popupshell, XtGrabNone);
X    if (dataDpy->parent)
X    	XUndefineCursor(display, XtWindow(dataDpy->parent->dataDpyWindow));
X    XUndefineCursor(display, XtWindow(toplevel));
X}
END_OF_FILE
if test 21580 -ne `wc -c <'datadpy.c'`; then
    echo shar: \"'datadpy.c'\" unpacked with wrong size!
fi
# end of 'datadpy.c'
fi
echo shar: End of archive 7 \(of 8\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 8 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

--
Dan Heller
------------------------------------------------
O'Reilly && Associates		 Z-Code Software
Senior Writer			       President
argv@ora.com			argv@zipcode.com