[comp.sources.x] v08i109: xdbx -- Dbx for X11, Part05/07

cheung%SW.MCC.COM@MCC.COM (Po Cheung) (08/28/90)

Submitted-by: cheung%SW.MCC.COM@MCC.COM (Po Cheung)
Posting-number: Volume 8, Issue 109
Archive-name: xdbx/part05

#! /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 5 (of 7)."
# Contents:  command.c source.c
# Wrapped by cheung@espresso.sw.mcc.com on Fri Aug 24 03:24:51 1990
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'\" \(18726 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/*  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/* 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
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
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    AppendDialogText(command);
X}
X
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
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
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
X
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
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            UpdateMessageWindow("xdbx error: illegal search direction", NULL);
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    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    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 18726 -ne `wc -c <'command.c'`; then
    echo shar: \"'command.c'\" unpacked with wrong size!
fi
# end of 'command.c'
fi
if test -f 'source.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'source.c'\"
else
echo shar: Extracting \"'source.c'\" \(19496 characters\)
sed "s/^X//" >'source.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/*  source.c
X *
X *    Create the source window and handle display of file.
X *
X *    source_init(): 	Initialization routine.
X *    Update():		Action proc to update source window on scrollbar action.
X *    NotifyResize():	Action proc to update source window on resize.
X *    CreateSourceWindow(): Create the source window.
X *    BuildLinePos():	Build an array of starting text position of each line.
X *    LookUpFileTable():Check out source file info from a file table.
X *    SaveDisplayedFileInfo(): records displayed file info into file table.
X *    DisplayFile():	Display a file on the source window
X *    LoadFile():	Search for a file and open it for display.
X */
X
X#include <X11/Xos.h>
X#include <sys/stat.h>
X#include <pwd.h>
X#include "global.h"
X
X#define	MAXDIRS	256			/* max number of dirs in dirList */
X
Xchar		CurrentFile[MAXNAME];	/* current contents of file variable */
XWidget		sourceForm,		/* parent of sourceWindow */
X		sourceWindow;		/* text window for source file */
XFileRec  	*displayedFile;		/* pointer to table entry of currently
X					   displayed file */
X
Xstatic FileRec	**fileTable;		/* table of file records */
Xstatic int	fileTableSize;		/* size of file table */
Xstatic char 	*dirList[MAXDIRS];	/* list of dirs for searching files */
X
Xvoid source_init()
X{
X    dirList[0] = NULL;
X}
X
X/*
X *  Update topline, bottomline, arrow sign, updown sign, stop signs, and
X *  line label.
X */
X/* ARGSUSED */
Xvoid Update(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    XawTextPosition     pos;
X    int			topline;
X    FileRec 		*file;
X
X    if (displayedFile) {
X    	file = displayedFile;
X	pos = XawTextTopPosition(sourceWindow);
X	file->topPosition = pos;
X	topline = TextPositionToLine(pos);
X	/* Update the symbols only if the text scrolls */
X	if (file->topline != topline) {
X	    file->topline = topline;
X	    file->bottomline = MIN (file->topline + file->lines - 1, 
X				    file->lastline);
X	    XawTextSetInsertionPoint(sourceWindow, file->linepos[file->topline]);
X	    UpdateLineLabel(file->topline);
X    	    UpdateStops(file);
X    	    UpdateArrow(file);
X    	    UpdateUpdown(file);
X    	    UpdateBomb(file);
X	}
X	else {/* Update caret position only */
X	    pos = XawTextGetInsertionPoint(sourceWindow);
X	    UpdateLineLabel(TextPositionToLine(pos));
X	}
X    }
X}
X
X/*
X *  Update bottomline, arrow sign, updown sign and stop signs on resize.
X *  Invoked by ConfigureNotify event.
X */
X/* ARGSUSED */
Xstatic void NotifyResize(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    XawTextPosition pos;
X    TextWidget  ctx = (TextWidget) sourceWindow;
X    FileRec	*file;
X
X    if (file = displayedFile) {
X	file->lines = ctx->text.lt.lines;
X	pos = XawTextTopPosition(sourceWindow);
X	file->topline = TextPositionToLine(pos);
X        file->bottomline = MIN (file->topline + file->lines - 1, 
X				file->lastline);
X        UpdateStops(file);
X        UpdateArrow(file);
X        UpdateUpdown(file);
X        UpdateBomb(file);
X    }
X}
X
X/*  Update the position of the caret */
X/*  ARGSUSED */
X#ifdef notdef
Xvoid UpdateLine(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    XawTextPosition pos;
X    int	line;
X
X    pos = XawTextGetInsertionPoint(w);
X    line = TextPositionToLine(pos);
X    UpdateLineLabel(line);
X}
X#endif
X
X/*  My select-start routine that cancels the effect of automatic scrolling
X *  near the bottom of an Athena text widget window.
X */
X/*  ARGSUSED */
Xvoid SelectStart(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    XawTextPosition topPosition;
X
X    /* remember the top display position before automatic scrolling */
X    /* displayedFile->topPosition = XawTextTopPosition(w); */
X    topPosition = XawTextTopPosition(w);
X
X    XtCallActionProc(w, "select-start", event, params, num_params);
X
X    /* reset to remembered position if top position changed */
X    /* if (XawTextTopPosition(w) != displayedFile->topPosition)
X    	TextSetTopPosition(w, displayedFile->topPosition); */
X    if (XawTextTopPosition(w) != topPosition)
X    	TextSetTopPosition(w, topPosition);
X}
X
X/*  My select-end routine to store the text selection into both the PRIMARY
X *  selection and cut buffer 0. 
X */
X/*  ARGSUSED */
Xvoid SelectEnd(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    XawTextPosition begin, end, start;
X    Widget textsrc;
X    XawTextBlock buffer;
X    char s[10000];
X    int nchars;
X
X    XawTextGetSelectionPos(w, &begin, &end);
X    XawTextSetSelection(w, begin, end);
X    if (begin == end) return;
X    textsrc = XawTextGetSource(w);
X    strcpy(s, "");
X    for (start=begin, nchars=end-begin; nchars > 0; 
X	start=begin+buffer.length, nchars-=buffer.length) {
X    	XawTextSourceRead(textsrc, start, &buffer, nchars);
X	strncat(s, buffer.ptr, buffer.length);
X    }
X    XStoreBytes(display, s, strlen(s));
X}
X
X/*  This is my own select word routine to replace the standard action
X *  procedure provided by the Text widget.
X *  It selects a word delimited by DELIMITERS, not whitespace.
X */
X/* ARGSUSED */
Xvoid SelectWord(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    XawTextPosition pos, left, right, start;
X    XawTextBlock buffer;
X    Widget	textsrc;
X    char 	s[LINESIZ];
X    char 	*p, *ls, *rs;
X    int		nchars;
X
X    pos = XawTextGetInsertionPoint(w);
X    textsrc = XawTextGetSource(w);
X
X    XawTextSourceRead(textsrc, pos, &buffer, 1);
X    if (buffer.length == 0 || (buffer.length == 1 &&
X	strchr(app_resources.delimiters, (int)*(buffer.ptr)) != NULL)) {
X	XStoreBytes(display, NULL, 0);
X	return;
X    }
X
X    left = XawTextSourceScan(textsrc, pos+1, XawstWhiteSpace, XawsdLeft, 1,
X                             FALSE);
X    right = XawTextSourceScan(textsrc, left, XawstWhiteSpace, XawsdRight, 1,
X                              FALSE);
X    
X    strcpy(s, "");
X    for (start=left, nchars=right-left; nchars > 0; 
X	start=left+buffer.length, nchars-=buffer.length) {
X    	XawTextSourceRead(textsrc, start, &buffer, nchars);
X	strncat(s, buffer.ptr, buffer.length);
X    }
X
X    if (!strcmp(s, "")) return;
X    p = s+pos-left;
X    ls = (char *) strtok(s, app_resources.delimiters);
X    rs = (char *) strtok(NULL, app_resources.delimiters);
X    if (!ls) return;
X    while (rs<=p && rs!=NULL) {
X	ls = rs;
X	rs = (char *) strtok(NULL, app_resources.delimiters);
X    }
X    left = left + ls - s;
X    right = left + strlen(ls) - 1; 
X
X    XawTextUnsetSelection(w);
X    XStoreBytes(display, ls, strlen(ls));
X    XawTextSetSelection(w, left, right+1);
X}
X
X/*  Print the value of the expression  in cut buffer 0. */
X/*  ARGSUSED */
Xvoid PrintSelection(w, event, params, num_params)
X    Widget w;
X    XEvent *event;
X    String *params;
X    Cardinal *num_params;
X{
X    char command[LINESIZ];
X    char *string;
X    int nbytes;
X
X    string = XFetchBytes(display, &nbytes);
X    if (nbytes == 0) {
X        UpdateMessageWindow(PRINT_HELP, NULL);
X        bell(0);
X        return;
X    }
X    sprintf(command, "print %s\n", string);
X    send_command(command);
X    AppendDialogText(command);
X}
X
X/* 
X *  On top of a form widget, we have a text widget with scrollbar, label
X *  widgets for the stop sign, arrow sign, and updown signs.
X */
Xvoid CreateSourceWindow(parent)
XWidget parent;
X{
X    TextWidget ctx;
X    Arg args[MAXARGS];
X    Cardinal n;
X
X    static XtActionsRec sbar_actions[] = {
X        {"NotifyResize",   NotifyResize},
X        {"Update", 	   Update},
X        {NULL, NULL}
X    };
X
X    static String sbarTranslations = "\
X        <Configure>:    NotifyResize() \n\
X        <Btn2Down>:     StartScroll(Continuous) MoveThumb() NotifyThumb() \
X                        Update() \n\
X        <Btn2Motion>:   MoveThumb() NotifyThumb() Update() \n\
X        <BtnUp>:        NotifyScroll(Proportional) EndScroll() Update() \n\
X    ";
X
X    n = 0;
X    XtSetArg(args[n], XtNdefaultDistance, 0);                           n++;
X    sourceForm = XtCreateManagedWidget("sourceForm", formWidgetClass, 
X					 parent, args, n);
X
X    n = 0;
X    XtSetArg(args[n], XtNborderWidth, 0);				n++;
X    XtSetArg(args[n], XtNtype, (XtArgVal)XawAsciiFile);			n++;
X    XtSetArg(args[n], XtNstring, (XtArgVal)"/dev/null");		n++;
X    XtSetArg(args[n], XtNscrollVertical, (XtArgVal) XawtextScrollAlways);n++;
X    sourceWindow = XtCreateManagedWidget("sourceWindow", asciiTextWidgetClass,
X					  sourceForm, args, n);
X
X    ctx = (TextWidget) sourceWindow;
X    if (ctx->text.vbar)
X    	XtOverrideTranslations(ctx->text.vbar, 
X				XtParseTranslationTable(sbarTranslations));
X    XtAppAddActions(app_context, sbar_actions, XtNumber(sbar_actions));
X}
X
X
X/*
X *  Build the array which gives the starting text position of each line.
X *  > Estimate the number of lines in the file and allocate memory buffer.
X *  > Starting position of line #1 is 0, and is stored in linepos[1].
X *  > Search for '\n' till end of buffer.
X */
Xstatic void BuildLinePos(file)
XFileRec *file;
X{
X    char *p;
X    int	 line, nlines;
X
X    nlines = MAX(1, file->filesize/CHARS_PER_LINE);
X    file->linepos = (XawTextPosition *)
X		    XtMalloc ((nlines+2) * sizeof(XawTextPosition));
X    p = file->buf;
X    line = 0;
X    file->linepos[line++] = 0;
X    file->linepos[line++] = 0;
X    while (*p) {
X	if (*p++ == '\n') {
X	    if (line == nlines) { 	/* buffer full, need more memory */
X                file->linepos = (XawTextPosition *) XtRealloc (file->linepos, 
X			  (nlines + ADD_LINES) * sizeof(XawTextPosition));
X		nlines += ADD_LINES;
X            }
X            file->linepos[line++] = p - file->buf;
X	}
X    }
X    file->lastline = line - 2;
X    file->linepos = (XawTextPosition *) XtRealloc 	/* shrink to min size */
X			(file->linepos, line * sizeof(XawTextPosition));
X}
X
X
X/*
X * Look up the file table for an entry with "filename"
X * If not found, create an entry and initialize proper fields,
X * else, return pointer to entry found.
X */
Xstatic LookUpFileTable(pathname, filename, file)
Xchar *pathname, *filename;
XFileRec **file;
X{
X    struct stat fileinfo;
X    int  	fd;
X    int 	i, j, n;
X
X    for (i=0; fileTable && fileTable[i] && i<fileTableSize; i++) {
X	if (strcmp(fileTable[i]->pathname, pathname) == NULL) { /* file found */
X	    if (stat(pathname, &fileinfo) == -1) {
X		UpdateMessageWindow("Error: cannot stat file %s", pathname);
X	        *file = fileTable[i];
X		return 0;
X	    }
X	    if (fileinfo.st_mtime > fileTable[i]->mtime) { /* file modified */
X		XtFree((char *)fileTable[i]->buf);
X		XtFree((char *)fileTable[i]->linepos);
X		XtFree((char *)fileTable[i]);
X		displayedFile = NULL;
X		break;
X	    }
X	    else if (displayedFile && 		/* same as displayed file */
X		     strcmp(pathname, displayedFile->pathname) == 0) {
X		*file = NULL;
X		return 0;
X	    }
X	    else {
X	    	*file = fileTable[i];
X		return 0;
X	    }
X	}
X    }
X
X    /* Record file into file table */
X
X    if (i == fileTableSize) {		/* file table full, enlarge it */
X	fileTableSize += ADD_SIZE;
X	fileTable = (FileRec **) 
X		     XtRealloc (fileTable, fileTableSize * sizeof(FileRec *));
X	for (j=i; j<fileTableSize; j++)
X	    fileTable[j] = NULL;
X    }
X    if ((fd = open(pathname, O_RDONLY)) == -1) {
X	UpdateMessageWindow("Error: cannot open file %s", pathname);
X	return -1;
X    }
X    if (fstat(fd, &fileinfo) == -1) {
X	UpdateMessageWindow("Error: cannot fstat file %s", pathname);
X	close(fd);
X	return -1;
X    }
X    fileTable[i] = (FileRec *) XtMalloc (sizeof(FileRec));
X    fileTable[i]->filesize = fileinfo.st_size + 1;
X    fileTable[i]->mtime = fileinfo.st_mtime;
X    fileTable[i]->buf = XtMalloc((int)fileTable[i]->filesize);
X    if ((n = read(fd, fileTable[i]->buf, (int) fileTable[i]->filesize)) == -1) {
X	UpdateMessageWindow("Error: cannot read file %s", pathname);
X	XtFree(fileTable[i]->buf);
X	XtFree(fileTable[i]);
X	fileTable[i] = NULL;
X	close(fd);
X	return -1;
X    }
X    fileTable[i]->buf[n] = '\0';
X    fileTable[i]->pathname = XtNewString(pathname);
X    fileTable[i]->filename = XtNewString(filename);
X    fileTable[i]->currentline = 1;
X    fileTable[i]->topline = 1;
X    fileTable[i]->bottomline = 0;
X    fileTable[i]->topPosition = 0;
X    BuildLinePos(fileTable[i]);
X    close(fd);
X    *file = fileTable[i];
X    return 0;
X}
X
X/*  
X *  Remember file position and current line before closing.
X */
Xstatic void SaveDisplayedFileInfo()
X{
X    XawTextPosition pos;
X
X    if (displayedFile) {
X    	displayedFile->topPosition = XawTextTopPosition(sourceWindow);
X	pos = XawTextGetInsertionPoint(sourceWindow);
X	displayedFile->currentline = TextPositionToLine(pos);
X    }
X}
X
X
X/*   DisplayFile() displays the file onto the source window.  It
X *     uses topPosition to remember where it was last opened.  But it
X *     must recalculate bottomline because the window size might be
X *     different.
X */
Xstatic void DisplayFile(file)
XFileRec *file;
X{
X    Arg 	args[MAXARGS];
X    Cardinal 	n;
X    TextWidget 	ctx = (TextWidget) sourceWindow;
X
X    n = 0;
X    XtSetArg(args[n], XtNdisplayPosition, (XtArgVal)file->topPosition);	n++;
X    XtSetArg(args[n], XtNstring, (XtArgVal) file->pathname);		n++;
X    XtSetArg(args[n], XtNeditType, (XtArgVal) XawtextRead);		n++;
X    XtSetValues(sourceWindow, args, n);
X    file->lines = ctx->text.lt.lines;
X    file->bottomline = MIN (file->topline + file->lines - 1, file->lastline);
X}
X
X
X/*  Given a filename starting with a tilde (`~'), it expands ~[user] to
X *  the home directory of that user, or to the login home directory if user
X *  is not specified.
X */
Xstatic char *expand(filename)
Xchar *filename;
X{
X    struct passwd *pwd;
X    char 	  *string, *name, newfile[MAXNAME];
X
X    string = XtNewString(filename+1);
X    if (*string == '\0' || *string == '/')
X	name = (char *) getlogin();
X    else
X    	name = (char *) strtok(string, "/");
X    if (name == NULL)
X	return filename;
X    pwd = (struct passwd *) getpwnam(name);
X    if (pwd && pwd->pw_dir) {
X    	sprintf(newfile, "%s%s", pwd->pw_dir, filename+strlen(name)+1);
X    	return XtNewString(newfile);
X    }
X    else
X	return filename;
X}
X
X
X/*  Create a list of directories for searching source files.
X *  It reads the list of directories specified by the user, adding
X *  the current directory into the list if it is not already there.
X *
X *  With fix from Dave Gagne (daveg@fs1.ee.ubc.ca) 7/30/90
X */
Xvoid MakeDirList(output)
Xchar *output;
X{
X    char *s, list[BUFSIZ], command[LINESIZ];
X    int  i, use_cwd;
X
X    for (i=0; dirList[i]; i++)			/* remove old list */
X	XtFree(dirList[i]);
X    i = 0;
X    use_cwd = TRUE;
X    if (output) {                                        /* create list */
X        s = (char *) strtok(output, " \n");
X        while (s) {
X            dirList[i] = XtNewString(s);
X
X            if (dirList[i][0] == '~')                   /* expand '~' */
X                dirList[i] = expand(dirList[i]);
X            if (LASTCH(dirList[i]) == '/')              /* remove last '/' */
X                LASTCH(dirList[i]) = '\0';
X            if (strcmp(dirList[i], ".") == NULL)        /* watch for "." */
X                use_cwd = FALSE;
X
X            ++i;
X            s = (char *) strtok(NULL, " \n");
X        }
X        dirList[i] = NULL;
X    }
X
X    if (use_cwd) {				/* include current dir */
X	dirList[i++] = XtNewString(".");		
X    	dirList[i] = NULL;
X    }
X    strcpy(list, "");				/* tell dbx our new list */
X    for (i=0; dirList[i]; i++) {
X	strcat(list, dirList[i]);
X	strcat(list, " ");
X    }
X    sprintf(command, "use %s\n", list);
X    Parse = False;
X    query_dbx(command);
X}
X
X
X/*  Returns the full pathname of a given file.
X *  It searches for the file from a list of directories.
X */
Xchar *GetPathname(filename)
Xchar *filename;
X{
X    char	pathname[LINESIZ];
X    int 	i;
X
X    if (filename == NULL || strcmp(filename, "") == NULL)
X	return NULL;
X    for (i=0; dirList[i]; i++) {
X	if (*filename == '/' && access(filename, R_OK) == -1) { 
X	    /* this handles the exceptional case of sun4 dbx output */
X	    strcpy(filename, &filename[1]);
X	}
X	if (*filename == '/' || *filename == '~')
X	     strcpy(pathname, filename);
X	else if (strcmp(dirList[i], ".") == NULL)
X	     sprintf(pathname, "%s/%s", cwd, filename);
X	else if (*dirList[i] == '/' || *dirList[i] == '~')
X	     sprintf(pathname, "%s/%s", dirList[i], filename);
X	else
X	     sprintf(pathname, "%s/%s/%s", cwd, dirList[i], filename);
X	if (access(pathname, R_OK) == 0)
X	    return XtNewString(pathname);
X    }
X    UpdateMessageWindow("File not found: %s", filename);
X    return NULL;
X}
X
X/*
X * Given a file name, LoadFile attempts to open it and displays it onto
X * the source window:
X *   1. get the full pathname of the file
X *   2. LookUpFileTable() returns a pointer to the file's entry if it's
X *      already in the table; else, creates an entry and return a pointer.
X *   3. save the current displayedFile info
X *   4. display the file
X *   5. update the file label and the various signs on the source window.
X *  LoadFile returns 0 upon successful completion, -1 otherwise.
X */
Xint LoadFile(filename)
Xchar *filename;
X{
X    FileRec 	*file;
X    char	*pathname;
X
X    pathname = GetPathname(filename);
X    if (pathname == NULL) { 
X	return -1;
X    }
X    if (LookUpFileTable(pathname, filename, &file) != -1) {
X	if (file) {	/* load new file */
X	    SaveDisplayedFileInfo();
X	    DisplayFile(file);
X	    UpdateFileLabel(pathname);
X	    XawTextUnsetSelection(sourceWindow);
X	    XawTextSetInsertionPoint(sourceWindow, file->linepos[file->currentline]);
X	    UpdateLineLabel(file->currentline);
X	    UpdateStops(file);
X	    UpdateArrow(file);
X	    UpdateUpdown(file);
X	    UpdateBomb(file);
X	    displayedFile = file;
X	}
X    	return 0;
X    }
X    else {		/* LookUpFileTable() fails */
X    	return -1;
X    }
X}
X
Xint LoadCurrentFile()
X{
X    query_dbx("file\n");
X    return LoadFile(CurrentFile);
X}
END_OF_FILE
if test 19496 -ne `wc -c <'source.c'`; then
    echo shar: \"'source.c'\" unpacked with wrong size!
fi
# end of 'source.c'
fi
echo shar: End of archive 5 \(of 7\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 7 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
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.