[comp.sources.x] v02i069: a browser, Part01/03

mikew@wyse.wyse.com (Mike Wexler) (01/04/89)

Submitted-by: Schlichter.Wbst@Xerox.COM (Hans Schlichter)
Posting-number: Volume 2, Issue 69
Archive-name: xbrowser/part01

#! /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 1 (of 3)."
# Contents:  README commands.c search.c util.c xbrowser.man
# Wrapped by mikew@wyse on Tue Jan  3 12:03:47 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1181 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XXbrowser provides a graphical interface to browse directories, 
Xselect files from directory listings and invoke commands on them,
Xsuch as invoking the editor on these files,
Xsearch files for specified patterns, move, copy or delete files.
X
XXbrowser was developed for X11 R3. It runs on Sun workstations
Xunder Sun OS 3.2, 3.5 and 4.0. I did not test it on any
Xother workstation type. Portability was not a major concern
Xduring development. I only wanted to learn X11 and the X11 Toolkit.
XTherefore I used both regular expression packages of SUN OS
X(regexp and regex) which might not be available on other Unix versions.
X
XI tested xbrowser with the following window managers: wm, rtl, uwm and
Xtwm. A special warning if you use twm: your .twmrc must set 
XNoTitleFocus otherwise the dialog boxes and the text windows do not work
Xcorrectly. I believe there is a bug in twm.
X
XAnother warning:
XIf you specify a geometry resource for xbrowser
Xin your .Xdefaults file, the dialog boxes will have initially these geometry
Xsizes (you might have very strange shaped command buttons). Geometry values
Xspecified on the command line which called xbrowser 
Xdo not affect the dialog box geometry.
X
END_OF_FILE
if test 1181 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'commands.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'commands.c'\"
else
echo shar: Extracting \"'commands.c'\" \(18919 characters\)
sed "s/^X//" >'commands.c' <<'END_OF_FILE'
X/* Systems Sciences Laboratory, Webster Research Center */
X
Xstatic char *PROGRAM_information[] =
X{
X    "Copyright (c) 1988 Xerox Corporation.  All rights reserved.",
X    "$Header$",
X    "$Locker$"
X}
X;
X
X/*
X * Copyright protection claimed includes all forms and matters of copyrightable
X * material and information now allowed by statutory or judicial lay or
X * herinafter granted, including without limitation, material generated from
X * the software programs which are displayed on the screen such as icons,
X * screen display looks, etc.
X */
X
X
X#include "xfilebrowser.h"
X#include <ctype.h>
X#include <sys/file.h>
X
Xextern char *getenv();
Xextern char *re_comp();
X
Xtypedef enum { JHSXEDIT, EMACS, VI, XEDIT, XMORE, ED_UNKNOWN } edittype;
Xtypedef enum { DELETE, MOVE, COPY } requesttype;
X
Xstatic DialogData dialogdata;
Xstatic unsigned int cmdsize = 1024;
X
X
XDoQuit()
X{
X	XtUnmapWidget(toplevel);
X	XCloseDisplay(curdisplay);
X	exit(0);
X}
X
X/* ARGSUSED */
Xsetup_pattern(source, pattern)
Xchar *source, *pattern;
X{
X	register char *p = source;
X	register char *q = pattern;
X	
X	*q = '^'; q++;
X	while (*p != '\0') {
X	   if (*p == '.') { *q = '\\'; q++; *q = '.'; }
X	   else if (*p == '$') *q = '.';
X	   else if (*p == '*') { *q = '.'; q++; *q = '*'; }
X	   else *q = *p; 
X
X	   q++; p++;
X	}
X	*q = '$'; q++; *q = '\0';
X}
X
X/* ARGSUSED */
XDoList(w, client_data, call_data)
XWidget w;
Xcaddr_t client_data, call_data;
X{
X	int i;
X	char *error;
X	char tmppattern[64], curpattern[255];
X	XtTextPosition pos1, pos2;
X	short dir;
X	struct stat buf;
X
X	switch ((int)call_data) {
X	   case 2: dir = -1; break;
X	   case 3: 
X		if (!check_option()) display_listoptions(w); 
X		return;
X
X	   case 0:
X	   case 1: 
X	   default: dir = (short)call_data; break;
X	}
X
X	XtTextGetSelectionPos(listwidget, &pos1, &pos2);
X	if (pos1 != pos2 && numfiles != 0 && 
X		( (i = select_file(pos1, pos2)) != -1)) {
X	   if (stat((*files[i]).d_name, &buf) == -1) {
X 		disp_message("\nList: cannot check file stats");
X 	   	return;
X 	   }
X 	   if (buf.st_mode & S_IFDIR) 
X 	   	sprintf(curpattern, "%s/%s", (*files[i]).d_name, filepattern);
X 	   else {
X 	   	disp_message(
X	   "\nList: selected file %s is not a directory\nuse current pattern",
X 	   		(*files[i]).d_name);
X		if (! strcmp(filepattern, oldpattern)) return;
X 	   	else strcpy(curpattern, filepattern);
X	   }
X	}
X	else strcpy(curpattern, filepattern);
X
X	if (strcmp(curpattern, oldpattern)) {
X		/* old pattern and new pattern differ */
X	   if (get_dirpat(curpattern, curdirectory, oldpattern) == -1) {
X	   	disp_message("\nList: access to directory?");
X	   	return;
X	   }
X	}
X	
X	setup_pattern(oldpattern, tmppattern);
X	if (error = re_comp(tmppattern)) {
X	   disp_message("\nList: search pattern %s?", error);
X	   return;
X	}
X
X	clear_widget(grepwidget, grepsource);
X	clear_widget(listwidget, listsource);
X	free_direct(&files, &numfiles);
X	free_hitfiles();
X
X	if (prepare_list(curdirectory, dir, &files, &numfiles, 
X			(char *)NULL) != -1) {
X	   if (!(chdir(curdirectory))) {
X	   	strcpy(filepattern, oldpattern);
X	   	setup_dirlabel(curdirectory, oldpattern);
X	   }
X	   else disp_message("\nList: problems in changing to %s",
X			 curdirectory);
X	   display_files(0);
X	}
X	else clear_widget(listwidget, listsource);
X
X	setup_iconname();
X
X	return;
X}
X
X
X/***************************
X* 	Edit Routines 
X****************************/
X
X/* ARGSUSED */
Xedittype check_editor(s)
Xchar *s;
X{
X	char *p, *q;
X	int len;
X	edittype result;
X	
X	p = s; result = ED_UNKNOWN;
X	while ( p != NULL) {
X	   if ( (q = index(p, ' ')) != NULL) len = q - p;
X	   else len = strlen(p);
X
X	   if (! strncmp(p, "jhsxedit", len)) { result = JHSXEDIT; break; }
X	   else if (! strncmp(p, "xedit", len)) { result = XEDIT; break; }
X	   else if (! strncmp(p, "emacs", len)) { result = EMACS; break; }
X	   else if (! strncmp(p, "vi", len)) { result = VI; break; }
X	   else if (! strncmp(p, "xmore", len)) { result = XMORE; break; }
X
X	   if (q != NULL) {
X		q++;
X	   	while (*q == ' ') q++;
X	   	p = q;
X	   }
X	   else break;
X	}
X	
X	return result;
X}
X
X/* ARGSUSED */
Xinvoke_editor(file, toline, edit)
Xchar *file;
Xint toline;
XBoolean edit;
X{
X	int cc;
X	char command[255];
X	char *editor = NULL, *curviewer;
X	struct stat buf;
X	edittype edit_view;
X	static char xviewer[] = "xmore";
X	static char xeditor[] = "xedit";
X	
X	if (stat(file, &buf) == -1) {
X 	   disp_message("\nEdit: cannot check file stats");
X 	   return;
X 	}
X
X 	if ( (buf.st_mode & S_IFMT) == S_IFREG ) {
X	   if (!edit) {
X		edit_view = XMORE;
X		curviewer = &xviewer[0];
X	   }
X	   else {
X 	   	if ( (editor = getenv("XEDITOR")) != NULL) {
X		   edit_view = check_editor(editor);
X		   curviewer = editor;
X		}
X		else {
X		   edit_view = XEDIT;
X		   curviewer = &xeditor[0];
X		}
X	   }
X
X   	   if (toline != 0) {
X 	   	switch(edit_view) {
X 	   	   case JHSXEDIT:
X 	   	   case EMACS:
X 	   	   case VI:
X 	   	   	sprintf(command, "%s -display %s +%d %s&", 
X			   curviewer, DisplayString(curdisplay), toline, file);
X 	   	   	break;
X 	   	   default:
X 	   	   	sprintf(command, "%s -display %s %s&",
X 	   	   	   	curviewer, DisplayString(curdisplay), file);
X 	   	   	break;
X		}
X 	   }
X	   else sprintf(command, "%s -display %s %s&", 
X			    curviewer, DisplayString(curdisplay), file);
X	   cc = system(command);
X	}
X	else disp_message("\nEdit: %s not regular file!", file);	
X}
X
XDoEdit(w, client_data, call_data)
XWidget w;
Xcaddr_t client_data, call_data;
X{
X	XtTextPosition pos1, pos2;
X	int i;
X
X	if ( (int)call_data == 3 ) return;
X	XtTextGetSelectionPos(listwidget, &pos1, &pos2);
X	if (pos1 == pos2 || numfiles == 0) {
X 	   disp_message("\nEdit: no file selected");
X 	   return;
X 	}
X
X	if ( (i = select_file(pos1, pos2)) == -1) {
X 	   disp_message("\nEdit: file selection?");
X 	   return;
X 	}
X
X	switch ( (int)call_data ) {
X	case 1:	invoke_editor(files[i]->d_name, 0, False); break;
X	case 2:	invoke_editor(files[i]->d_name, 0, True); break;
X	}
X
X	return;
X}
X
X
X/***************************
X* 	Grep/GrepEdit Routines 
X****************************/
X
XDoGrepEdit(w, client_data, call_data)
XWidget w;
Xcaddr_t client_data, call_data;
X{
X	XtTextPosition pos1, pos2;
X	int i, linenr;
X
X	if ( (int)call_data == 3 ) return;
X
X	XtTextGetSelectionPos(grepwidget, &pos1, &pos2);
X	if (pos1 == pos2 || numhitfiles == 0) {
X 	   disp_message("\nEdit: no file selected");
X 	   return;
X 	}
X
X	if ( (i = select_searchfile(pos1, pos2, &linenr)) == -1) {
X 	   disp_message("\nEdit: file selection?");
X 	   return;
X 	}
X	switch ( (int)call_data ) {
X	case 1:	invoke_editor(hitfiles[i]->name, linenr, False); break;
X	case 2:	invoke_editor(hitfiles[i]->name, linenr, True); break;
X	}
X
X	return;
X}
X
X
XDoGrep(w, client_data, call_data)
XWidget w;
Xcaddr_t client_data, call_data;
X{
X	XtTextPosition pos1, pos2, fstart, fend;
X	Boolean stopwhenfound = False;
X
X	switch ((int)call_data) {
X	   case 3: 
X		if (!check_search()) display_searchoptions(w); 
X		return;
X
X	   case 2:	stopwhenfound = True; break;
X	   case 1:	break;
X	   default:	return;
X	}
X
X	if (numfiles == 0) {
X	   disp_message("\nGrep: no files listed");
X	   return;
X	}
X	
X	if (strlen(searchpattern) == 0) {
X	   disp_message("\nGrep: search pattern?");
X	   return;
X	}
X	if (index(searchpattern, '\n') != NULL) {
X	   disp_message("\nGrep: search pattern contains newline");
X	   return;
X	}
X
X	clear_widget(grepwidget, grepsource);
X	free_hitfiles();
X
X	XtTextGetSelectionPos(listwidget, &pos1, &pos2);
X	if (pos1 == pos2 ||
X		select_files(pos1, pos2, &fstart, &fend) == -1) 
X	   { fstart = 0; fend = numfiles -1; }
X
X	examine_files(fstart, fend, stopwhenfound);
X}
X
X
X/***************************
X* 	Shell Routines 
X****************************/
X
X/* ARGSUSED */
Xint execute_cmdline(command, saveout, savediag)
Xchar *command;
XBoolean saveout, savediag;
X{
X	int cc, i;
X	int cmdindex = 0;
X	struct stat statbuf;
X	FILE *fin;
X	char tmpfile[16];
X	char buf[128];
X	char *cmd = command;
X
X	if (saveout || savediag) {
X	   cmdindex = strlen(cmd);
X	   sprintf(tmpfile, "/tmp/xbXXXXXX");
X	   if (mktemp(tmpfile) == NULL) {
X	   	disp_message("\ncannot create log file");
X	   	return(-1);
X	   }
X
X	   strcat(cmd, (savediag) ? " 2>" : " 1>");
X	   strcat(cmd, tmpfile);
X	   if (savediag && saveout) strcat(cmd, " 1>&2");
X	}
X	else *tmpfile = '\0';
X
X	cc = system(cmd);
X	if (cc != 0)
X	   disp_message(
X		"\nexit status is %d\ncheck command or targetfile",
X		 cc);
X
X	if (*tmpfile != '\0' && stat(tmpfile, &statbuf) == 0) {
X   	   if (statbuf.st_size > 0) {
X	   	  if (statbuf.st_size < 127) {
X	   	      fin = fopen(tmpfile, "r");
X	   	      i = fread(buf, 1, 127, fin);
X	   	      fclose(fin);
X	   	      buf[i] = '\0';
X	   	      disp_message("\n%s", buf);
X		  }
X		  else {
X		      command[cmdindex] = '\0'; 
X			/* delete tmpfile name from command */
X		      log_popup(command, tmpfile);
X	   	   }
X	   }
X	   unlink(tmpfile);
X	}
X	
X	XtTextUnsetSelection(listwidget);
X	return(cc);
X}
X
X
Xshellcancel(clientdata)
XDialogData *clientdata;
X{
X	return;
X}
X
X/* ARGSUSED */
Xshellok(clientdata)
XDialogData *clientdata;
X{
X	char *answer = clientdata->answer;
X	char *tilde, *expand, *begquote, *endquote;
X
X	if ( (tilde = index(answer, '~')) != NULL) {
X		/* check if tilde is between single quotes; then do not
X		expand tilde */
X	   if ( ((begquote = index(answer, '\'')) == NULL) ||
X	   	((endquote = index(begquote+1, '\'')) == NULL) ||
X	   	(tilde < begquote || tilde > endquote)) {
X
X	   	if ( (expand = expand_tilde(tilde)) == NULL) {
X	   	   disp_message("\ncannot expand ~");
X	   	   return;
X		}
X	   	strcpy(tilde, expand);	/* replaces tilde by the actual
X				path name */
X	   	XtFree(expand);
X	   }
X	}
X
X	execute_cmdline(answer, clientdata->out, clientdata->diag);
X	return;
X}
X
X/* ARGSUSED */
XDoShell(w, client_data, call_data)
XWidget w;
Xcaddr_t client_data, call_data;
X{
X	char command[64];
X	char label[32];
X	char *defvalue;
X	XtTextPosition pos1, pos2, fstart, fend;
X	int i, len = 0;
X
X	switch ((int)call_data) {
X	   case 2: 	sprintf(command, "xterm -display %s &",
X	   			DisplayString(curdisplay));
X			system(command);
X			break;
X	   case 1: 
X			if (check_prompt() == -1) return;
X				/* there is already a prompt window */	
X			XtTextGetSelectionPos(listwidget, &pos1, &pos2);
X			if (pos1 != pos2 && 
X			   select_files(pos1, pos2, &fstart, &fend) != -1) {
X			   if ( (fend - fstart + 1) == numfiles) {
X				defvalue = XtMalloc(255);
X				strcpy(defvalue, oldpattern);
X			   }
X			   else {
X	   		   	for (i = fstart; i <= fend; i++)
X	   		   	   len += files[i]->d_namlen;
X			   	defvalue = XtCalloc(len + (fend - fstart) + 64);
X			   	for (i = fstart; i <= fend; i++) {
X			   	   strcat(defvalue, " ");
X			   	   strcat(defvalue, files[i]->d_name);
X			   	}
X			   }
X			}
X			else defvalue = XtCalloc(255, 1);
X
X			dialogdata.w = w;
X			dialogdata.start = 0;
X			dialogdata.end = 0;
X			dialogdata.current = 0;
X			dialogdata.yes = shellok;
X			dialogdata.no = NULL;
X			dialogdata.cancel = shellcancel;
X			sprintf(label, "which shell command to execute?");
X			create_toggleprompt(&dialogdata, label, defvalue);
X			XtFree(defvalue);
X			break;
X	   case 3: 
X	   default:	break;
X	}
X	return;
X}
X
X
X
X/***************************
X* 	Copy Routines 
X****************************/
X
X/* ARGSUSED */
Xcopyok(clientdata)
XDialogData *clientdata;
X{
X	int fstart = clientdata->start;
X	int fend = clientdata->end;
X	int i;
X	char *s = clientdata->answer;
X	char *name;
X
X	strcpy(cmdline, "cp ");
X	for (i = fstart; i <= fend; i++) {
X	   strcat(cmdline, "'");
X	   strcat(cmdline, files[i]->d_name);
X	   strcat(cmdline, "' ");
X	}
X	if (*s == '~') {
X	   if ( (name = expand_tilde(s)) == NULL) {
X	   	disp_message("\nCopy: cannot expand target name");
X	   	return;
X	   }
X	}
X	else name = s;
X	strcat(cmdline, name);
X
X	if (execute_cmdline(cmdline, FALSE, TRUE) == 0) {
X	   if (fstart == fend) 
X		DoList(clientdata->w, (caddr_t)clientdata, (caddr_t)0);
X
X		/* copied file may be in the same directory; if values
X		are different assume files were copied into different
X		directory */
X	}
X	return;
X}
X
Xcopycancel(clientdata)
XDialogData *clientdata;
X{
X	return;
X}
X
X/* ARGSUSED */
XDoCopy(w, client_data, call_data)
XWidget w;
Xcaddr_t client_data, call_data;
X{
X	XtTextPosition pos1, pos2, fstart, fend;
X	char label[32];
X	char defvalue[255];
X
X	if (check_prompt() == -1) return;
X				/* there is already a prompt window */
X	if (numfiles == 0) {
X	   disp_message("\nCopy: no files listed");
X	   return;
X	}
X
X	XtTextGetSelectionPos(listwidget, &pos1, &pos2);
X	if (pos1 == pos2 || select_files(pos1, pos2, &fstart, &fend) == -1) {
X	   disp_message("\nCopy: no file selected");
X	   return;
X	}
X
X	dialogdata.w = w;
X	dialogdata.start = fstart;
X	dialogdata.end = fend;
X	dialogdata.current = fend;
X	dialogdata.yes = copyok;
X	dialogdata.no = NULL;
X	dialogdata.cancel = copycancel;
X
X	if (fstart == fend) {
X	   sprintf(label, "copy selected file to?");
X	   sprintf(defvalue, "%s", files[fstart]->d_name);
X	}
X	else {
X	   sprintf(label, "copy selected files to directory?");
X	   defvalue[0] = '\0';
X	}
X	create_prompt(&dialogdata, label, defvalue);
X	return;
X}
X
X
X/***************************
X* 	Move Routines 
X****************************/
X
X/* ARGSUSED */
Xmoveok(clientdata)
XDialogData *clientdata;
X{
X	int fstart = clientdata->start;
X	int fend = clientdata->end;
X	int i;
X	char *s = clientdata->answer;
X	char *name;
X
X	strcpy(cmdline, "mv ");
X	for (i = fstart; i <= fend; i++) {
X	   strcat(cmdline, "'");
X	   strcat(cmdline, files[i]->d_name);
X	   strcat(cmdline, "' ");
X	}
X	if (*s == '~') {
X	   if ( (name = expand_tilde(s)) == NULL) {
X	   	disp_message("\nMove: cannot expand target name");
X	   	return;
X	   }
X	}
X	else name = s;
X	strcat(cmdline, name);
X
X	if (execute_cmdline(cmdline, FALSE, TRUE) == 0) {
X	   DoList(clientdata->w, (caddr_t)clientdata, (caddr_t)0);
X	}
X	return;
X}
X
Xmovecancel(clientdata)
XDialogData *clientdata;
X{
X	return;
X}
X
X/* ARGSUSED */
XDoRename(w, client_data, call_data)
XWidget w;
Xcaddr_t client_data, call_data;
X{
X	XtTextPosition pos1, pos2, fstart, fend;
X	char label[32];
X	char defvalue[255];
X
X	if (check_prompt() == -1) return;
X				/* there is already a prompt window */
X	if (numfiles == 0) {
X	   disp_message("\nMove: no files listed");
X	   return;
X	}
X
X	XtTextGetSelectionPos(listwidget, &pos1, &pos2);
X	if (pos1 == pos2 || select_files(pos1, pos2, &fstart, &fend) == -1) {
X	   disp_message("\nMove: no file selected");
X	   return;
X	}
X
X	dialogdata.w = w;
X	dialogdata.start = fstart;
X	dialogdata.end = fend;
X	dialogdata.current = fend;
X	dialogdata.yes = moveok;
X	dialogdata.no = NULL;
X	dialogdata.cancel = movecancel;
X
X	if (fstart == fend) {
X	   sprintf(label, "move selected file to?");
X	   sprintf(defvalue, "%s", files[fstart]->d_name);
X	}
X	else {
X	   sprintf(label, "move selected files to directory?");
X	   defvalue[0] = '\0';
X	}
X
X	create_prompt(&dialogdata, label, defvalue);
X	return;
X}
X
X
X/***************************
X* 	Delete Routines 
X****************************/
X
X/* ARGSUSED */
Xupdate_list(fstart, fend, sort)
Xint fstart, fend;
Xshort sort;
X{
X	int i;
X	int next = fstart;
X	int position = files[fstart]->d_pos1;
X
X	for (i = fstart; i <= fend; i++) {
X	   if (files[i]->d_marked == 0) {
X	   	if (next < i) files[next] = files[i];
X	   	next++;
X	   }
X	   else if (! access(files[i]->d_name, F_OK) ) {
X		disp_message("\nfile %s not removed", files[i]->d_name);
X		if (next < i) files[next] = files[i];
X	   	next++;
X	   }
X	   else XtFree(files[i]);
X	}
X	
X	if (next == i) return; /* no files were deleted */
X
X	for (i = fend + 1; i < numfiles; i++) 
X	   files[next++] = files[i];
X	numfiles = next;
X	if (sort) ;/* then sort files again */
X	display_files(position);
X}
X
X/* ARGSUSED */
Xconfirm(data, cur, op)
XDialogData *data;
Xint cur;
Xrequesttype op;
X{
X	struct stat buf;
X	char label[255];
X
X	data->current = cur;
X	switch (op) {
X	case DELETE:
X		if (files[cur]->d_type == 'd')
X			sprintf(label, "delete directory %s and its content?",
X		   		files[cur]->d_name);
X		else if (files[cur]->d_type == 'l') {
X		   if (stat(files[cur]->d_name, &buf) == -1) {
X			sprintf(label, 
X				"cannot check status of %s; delete anyway?",
X		   		files[cur]->d_name);
X		   }
X		}
X		else 	sprintf(label, "delete file %s",
X		   		files[cur]->d_name);
X		break;
X
X	default: return;
X	}
X	create_confirm(data, label);
X}
X
X
X/* ARGSUSED */
Xdeleteyes(clientdata)
XDialogData *clientdata;
X{
X	int cur = clientdata->current;
X	struct afile *fp;
X
X	fp = files[cur];
X	if ( (strlen(cmdline) + strlen(fp->d_name) + 1) >= cmdsize) {
X	   cmdsize += 1024;
X	   XtRealloc(cmdsize, cmdsize);
X	}
X	strcat(cmdline, " '");
X	strcat(cmdline, fp->d_name);
X	strcat(cmdline, "'");
X	fp->d_marked = 1;	/* file is marked for deletion */
X
X	if (cur < clientdata->end) {
X	   confirm(clientdata, cur+1, DELETE);
X	}
X	else {
X	   if (execute_cmdline(cmdline, FALSE, TRUE) == 0)
X	   	update_list(clientdata->start, clientdata->end, 0);
X	}
X	return;
X}
X
X/* ARGSUSED */
Xdeleteno(clientdata)
XDialogData *clientdata;
X{
X	int cur = clientdata->current;
X	short found = 0;
X	int i;
X
X	if (cur < clientdata->end) {
X	   confirm(clientdata, cur+1, DELETE);
X	}
X	else {
X		/* check if there is any file to delete */
X	   for (i = clientdata->start; i <= clientdata->end; i++) {
X	   	if (files[i]->d_marked != 0) {
X	   	   found = 1;
X	   	   break;
X		}
X	   }
X	   if (!found) return;
X	   if (execute_cmdline(cmdline, FALSE, TRUE) == 0)
X	   	update_list(clientdata->start, clientdata->end, 0);
X	}
X
X	return;
X}
X
X/* ARGSUSED */
Xdeletecancel(clientdata)
XDialogData *clientdata;
X{
X	int i;
X
X	for (i = clientdata->start; i <= clientdata->end; i++) 
X	   files[i]->d_marked = 0;
X	return;
X}
X
X
X/* ARGSUSED */
XDoDelete(w, client_data, call_data)
XWidget w;
Xcaddr_t client_data, call_data;
X{
X	XtTextPosition pos1, pos2, fstart, fend;
X
X	if (check_confirm() == -1) return;
X				/* there is already a prompt window */
X	if (numfiles == 0) {
X	   disp_message("\nDelete: no files listed");
X	   return;
X	}
X
X	XtTextGetSelectionPos(listwidget, &pos1, &pos2);
X	if (pos1 == pos2 || select_files(pos1, pos2, &fstart, &fend) == -1) {
X	   disp_message("\nDelete: no file selected");
X	   return;
X	}
X
X	dialogdata.w = w;
X	dialogdata.yes = deleteyes;
X	dialogdata.no = deleteno;
X	dialogdata.cancel = deletecancel;
X	dialogdata.start = fstart;
X	dialogdata.end = fend;
X	strcpy(cmdline, "rm -rf");
X
X	confirm(&dialogdata, fstart, DELETE);
X	return;
X}
X
X
X/*******************************
X* 	Parent Directory Routines 
X********************************/
X
XDoParent(w, client_data, call_data)
XWidget w;
Xcaddr_t client_data, call_data;
X{
X	char *p;
X
X	if ( (int)call_data == 3) return;
X			/* right button was pressed; no action is
X			taken */
X
X	if ( (p = rindex(curdirectory, '/')) == NULL)
X	   disp_message("\nParent: cannot select parent directory");
X	else {
X	   if ( (p - curdirectory) == 0) p[1] = '\0'; 
X			/* already at the beginning */
X	   else p[0] = '\0';
X	   if (!(chdir(curdirectory))) 
X		setup_dirlabel(curdirectory, filepattern);
X	   else disp_message("\nParent: problems in changing to %s",
X			curdirectory);
X	}
X
X	XtTextUnsetSelection(listwidget);
X
X	switch ((int)call_data) {
X	   case 2: 
X		clear_widget(listwidget, listsource); break;
X
X	   case 1: 
X	   default: 
X		XtTextUnsetSelection(listwidget);
X		DoList(w, client_data, (caddr_t)0); break;
X	}
X
X	return;
X}
END_OF_FILE
if test 18919 -ne `wc -c <'commands.c'`; then
    echo shar: \"'commands.c'\" unpacked with wrong size!
fi
# end of 'commands.c'
fi
if test -f 'search.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'search.c'\"
else
echo shar: Extracting \"'search.c'\" \(12704 characters\)
sed "s/^X//" >'search.c' <<'END_OF_FILE'
X/* Systems Sciences Laboratory, Webster Research Center */
X
Xstatic char *PROGRAM_information[] =
X{
X    "Copyright (c) 1988 Xerox Corporation.  All rights reserved.",
X    "$Header$",
X    "$Locker$"
X}
X;
X
X/*
X * Copyright protection claimed includes all forms and matters of copyrightable
X * material and information now allowed by statutory or judicial lay or
X * herinafter granted, including without limitation, material generated from
X * the software programs which are displayed on the screen such as icons,
X * screen display looks, etc.
X */
Xstatic int errornum;
Xstatic int hitfilesize;
X
X#define MAXDISPLAY 256
X#define BLKSIZE 8192
X#define ESIZE 1024
X
X#define INIT   register char *sp = instring;
X#define GETC() (*sp++)
X#define PEEKC()     (*sp)
X#define UNGETC(c)   (--sp)
X#define RETURN(c)   return;
X#define ERROR(c)    { errornum = c; return; }
X
X#include <regexp.h>
X#include <sys/file.h>
X#include <ctype.h>
X#include "xfilebrowser.h"
X
X
Xstatic short recursion = 1;
X		/* 1 no recursive search of directories
X		   2 search one level of directories
X		   3 search all levels of directories */
X
Xstatic Widget searchshell = NULL;
Xstatic Widget searchoption;	/* option for sorting files */
Xstatic Widget optioncaller;
Xstatic Widget caseoption;	/* togglewidget selecting case sensitive */
X
Xstatic short disp_option = 0;
X
Xstatic Boolean filefound = False;
Xstatic char *searchbuf;
Xstatic int blksize;
Xstatic Boolean recursive = False;
Xstatic XtState ignore_case = XtToggleOff;	/* is grep case insensitive */
X
X
Xextern char *re_comp();
X
X
X
X
X/*************************************
X**	build options dialog for search
X**************************************/
X
Xcheck_search()
X{
X	return disp_option;
X}
X
Xstatic void DoApply()
X{
X	recursion = XtOptionGetSelection(searchoption);
X
X	ignore_case = GetToggle(caseoption);
X
X	disp_option = 0;
X	change_sensitive(optioncaller, TRUE);
X	XtPopdown(searchshell);
X}
X
Xstatic void DoCancel()
X{
X	XtState toggle;
X
X	/* reset the option dialog window */
X	if ( !(recursion == XtOptionGetSelection(searchoption)) ) 
X		/* sorting was modified by user */
X	   XtOptionSetSelection(searchoption, recursion);
X
X	SetToggle(caseoption, ignore_case);
X
X	disp_option = 0;
X	change_sensitive(optioncaller, TRUE);
X	XtPopdown(searchshell);
X}
X
Xbuild_searchoptions()
X{
X	Arg popargs[1];
X	Widget listpane, listrow1, listrow2;
X
X	static Arg paneargs[] = {
X	   { XtNallowResize, (XtArgVal)True },
X	};
X
X	static Arg toggleargs[] = {
X	   { XtNstate, (XtArgVal)XtToggleOff },
X	};
X	
X	static Arg optionargs[] = { 
X	   { XtNlabel, (XtArgVal)NULL },
X	   { XtNorientation,(XtArgVal)XtorientVertical },
X	   { XtNfromHoriz, (XtArgVal) NULL },
X	   { XtNfromVert, (XtArgVal) NULL },
X	   { XtNleft, (XtArgVal) XtChainLeft },
X	   { XtNright, (XtArgVal) XtChainLeft },
X	   { XtNtop, (XtArgVal) XtChainTop },
X	   { XtNbottom, (XtArgVal) XtChainTop }
X
X	};
X
X	XtSetArg( popargs[0], XtNborderWidth, 2 );
X	
X	searchshell = XtCreatePopupShell("searchshell",
X	   		overrideShellWidgetClass,
X			toplevel, popargs, XtNumber(popargs));
X
X	listpane = XtCreateManagedWidget( "vpaned", vPanedWidgetClass, 
X			searchshell, paneargs , XtNumber(paneargs) );
X	listrow1 = XtCreateManagedWidget("row1", boxWidgetClass, 
X			listpane, NULL,0);
X	listrow2 = XtCreateManagedWidget("row2", boxWidgetClass, 
X			listpane, NULL,0);
X	makeCommandButton(listrow1, "Apply", DoApply);
X	makeCommandButton(listrow1, "Cancel", DoCancel);
X
X		/* define option menu for searching directories */
X	optionargs[0].value = (XtArgVal)"Select Search Option:";
X	searchoption = XtCreateManagedWidget("searching", optionWidgetClass, 
X		listrow2, optionargs, XtNumber(optionargs));
X	XtOptionAddOption(searchoption, "skip directories", TRUE);
X	XtOptionAddOption(searchoption, "search next-level directory", FALSE);
X	XtOptionAddOption(searchoption, "search all directories", FALSE);
X
X		/* define toggle for selecting case sensitivity */
X	caseoption = XtCreateManagedWidget("case insensitive search",
X		toggleWidgetClass,
X		listrow2, toggleargs, XtNumber(toggleargs));
X
X	XtSetMappedWhenManaged(searchshell, FALSE);
X	XtRealizeWidget(searchshell);
X}
X
X
Xdisplay_searchoptions(caller)
XWidget caller;
X{
X	if (searchshell == NULL) {
X	   build_searchoptions();
X	   optioncaller = caller;
X	}
X
X	disp_option = 1;
X	move_popup(searchshell, caller);
X	change_sensitive(caller, FALSE);
X	XtMapWidget(searchshell);
X	XtPopup(searchshell, XtGrabNonexclusive);
X}
X
X/**********************************************
X**	build data file structure for grep files
X***********************************************/
X
Xfree_hitfiles()
X{
X	register int i;
X	register LineElement *p, *tmp;
X
X	if (hitfiles != (SearchElement **)NULL) {
X	   for (i = 0; i < numhitfiles; i++) {
X		p = hitfiles[i]->lines;
X		while (p != (LineElement *)NULL) {
X		   tmp = p->next;
X		   XtFree(p);
X		   p = tmp;
X		}
X		XtFree(hitfiles[i]);
X	   }
X	   numhitfiles = 0;
X	}
X}
X
XLineElement *add_line(pos1, pos2, line, next)
XXtTextPosition pos1, pos2;
Xint line;
XLineElement *next;
X{
X	register LineElement *p;
X
X	p = (LineElement *)XtMalloc(sizeof(LineElement));
X	p->pa = pos1;
X	p->pe = pos2;
X	p->linenumber = line;
X	p->next = next;
X	return p;	
X}
X
Xadd_file(fname, pos1, pos2, linenr)
Xchar *fname;
XXtTextPosition pos1, pos2;
Xint linenr;
X{
X	SearchElement *selem;
X	if (numhitfiles == hitfilesize) {
X	   hitfilesize += (numfiles > 64) ? (2 * numfiles): 128;
X	   if (hitfiles != (SearchElement **)NULL)
X	   	hitfiles = (SearchElement **)XtRealloc(hitfiles, 
X	   		hitfilesize * sizeof(SearchElement *));
X	   else 
X		hitfiles = 
X		(SearchElement **)XtMalloc(hitfilesize*sizeof(SearchElement *));
X	}
X
X	if ( numhitfiles <= 0 || 
X			strcmp(fname, hitfiles[numhitfiles-1]->name) ) {
X	   selem = (SearchElement *)XtMalloc(sizeof(SearchElement));
X	   selem->pos1 = pos1;
X	   selem->pos2 = pos2;
X	   selem->lines = add_line(pos1, pos2, linenr, (LineElement *)NULL);
X	   strcpy(selem->name, fname);
X	   hitfiles[numhitfiles] = (SearchElement *)selem;
X
X	   numhitfiles++;
X	}
X	else {
X	   hitfiles[numhitfiles-1]->lines = 
X	   	add_line(pos1, pos2, linenr, hitfiles[numhitfiles-1]->lines);
X	   hitfiles[numhitfiles-1]->pos2 = pos2;
X	}
X}
X
Xdisp_searchline(file, line, linenr)
Xchar *file, *line;
Xint linenr;
X{
X	XtTextBlock text;
X	XtTextPosition pos;
X
X	text.length = strlen(line);
X	text.ptr = line;
X	text.firstPos = 0;
X	allowedit = 1;
X
X	pos = (*grepsource->Scan)(grepsource, 0, XtstAll, XtsdRight, 1, 0);
X
X	XtTextReplace(grepwidget, pos, pos, &text);
X	allowedit = 0;
X	add_file(file, pos, (pos + text.length + 1), linenr);
X}
X
Xdet_surround(file, start, end, linenr)
Xchar *file, *start, *end;
Xint linenr;
X{
X	int i, len;
X	char tmpline[MAXDISPLAY + 1];
X
X	sprintf(tmpline, "%s: ", file);
X	len = MAXDISPLAY - strlen(tmpline) - 2;
X	if ( (end - start) < len ) 
X	   strcat(tmpline, start);
X	else if ( (i = loc2 - start) < len) {
X	   strncat(tmpline, start, i);
X	   tmpline[i] = '\0';
X	}
X	else {
X	   strncat(tmpline, loc1, len);
X	   tmpline[MAXDISPLAY - 2] = '\0';
X	}
X	strcat(tmpline, "\n");
X	disp_searchline(file, tmpline, linenr);
X	filefound = True;
X}
X
Xint check_textfile(p)
Xchar *p;
X{
X	switch (*(int *)p) {
X	case 0177555:
X	case 0177545:
X	case 070707:	return(-1);
X	}
X	switch (*(short *)(p+2)) {
X	case 0407: 
X	case 0413:	return(-1);
X	}
X
X	if (strncmp(p, "Interpress", 10) == 0) return(-1);
X	else if (strncmp(p, "\037\036", 2) == 0) return(-1);
X	else if (strncmp(p, "\377\037", 2) == 0) return(-1);
X	else if (strncmp(p, "\037\235", 2) == 0) return(-1);
X	return(0);
X}
X
Xint search_file(filelist, index, expbuf, stop)
Xstruct afile **filelist;
Xint index;
Xchar *expbuf;
XBoolean stop;
X{
X	int fp, first = 1;
X	int count = 0, i, j;
X	int linenr = 0;
X	char *p;
X	char *q, *h;
X	char *linebuf;
X	struct stat statbuf;
X
X	char *filename = filelist[index]->d_name;
X
X		/* check file type */
X	switch (filelist[index]->d_type) {
X	case 'b':
X	case 'c':
X	case 's':	return(-1);
X	case 'd':	/* handle directories */
X	   {
X		struct afile **dirfiles;
X		int numdirfiles, i;
X		
X		if ( (recursion == 1) ||
X			(recursion == 2 && recursive) ) return(-1);
X		recursive = True;
X		setup_filepattern("*");
X		if (prepare_list(filename, 0, &dirfiles, &numdirfiles,
X				filename))
X		   return(-1);
X		setup_filepattern(filepattern);
X
X		for (i = 0; (i < numdirfiles && (!stop || !filefound) ); i++)
X		   search_file(dirfiles, i, expbuf, stop);
X		free_direct(&dirfiles, &numdirfiles);
X		recursive = False;
X		return(0);
X	   }
X	default:	break;
X	}
X		/* check if file pattern matches */
X	if (! re_exec(filename)) return(-1);	
X	if ( (fp = open(filename, O_RDONLY)) < 0) {
X	   disp_message("\nSearch: cannot open file %s", filename);
X	   return(-1);
X	}
X	if (fstat(fp, &statbuf) == -1) { close(fp); return(-1); }
X	else if ( !(statbuf.st_mode & S_IFREG )) {
X	   disp_message("\nSearch: %s not regular file!", filename);
X	   close(fp);
X	   return(-1);
X	}
X
X	if (searchbuf == NULL) {
X	   if (statbuf.st_blksize > 0)
X		blksize = statbuf.st_blksize;
X	   else	blksize = BLKSIZE;
X	   searchbuf = (char *)XtMalloc(blksize+ (2*MAXDISPLAY));
X	}
X	p = searchbuf;
X	while ( (i = read(fp, p, blksize)) > 0) {
X	   	   if (first) {
X	   	/* check if file can be scanned */
X		if (check_textfile(p) == -1) {
X		   disp_message("\nSearch: %s does not contain text!",
X			 filename);
X		   close(fp);
X	   	   return(-1);
X		}
X		first = 0;
X	   }
X
X	   if (count == 0) {
X		while (*p == '\n') { i--; p++; linenr++; }
X		if (i == 0) continue; else count = i;
X	   }
X	   else count += i;
XNEXT:
X	   linebuf = p;  p++;  j = 1;
X	   while ( (j < min(MAXDISPLAY, count)) && *p != '\n' )
X		{ p++; j++; }
X	   if ( j < MAXDISPLAY && *p != '\n' ) {
X		q = searchbuf; h = linebuf; j = 1;
X		while (j++ <= count) *q++ = *h++;
X		linebuf = searchbuf;
X		p = linebuf + count;
X		continue;
X	   }
X
X	   if (*p == '\n') linenr++;
X	   *p = '\0'; 
X	   if (step(linebuf, expbuf)) 
X		det_surround(filename, linebuf, p, linenr);
X	   count -= j + 1;
X	   if (count == 0) { p = searchbuf; continue; }
X	   else {
X		p++;
X	   	while (*p == '\n' && count > 0) { p++; count--; linenr++; }
X	   }
X	   if (count > 0) goto NEXT; else { p = searchbuf; continue; }
X	}
X
X	if (count > 0) {
X	    *(p+1) = '\0';
X	    if (step(linebuf, expbuf)) 
X		det_surround(filename, linebuf, p, linenr);
X	}
X	close(fp);
X	return(0);
X}
X
Xint examine_files(fstart, fend, stop)
Xint fstart, fend;
XBoolean stop;
X{
X	int i;
X	char expbuf[ESIZE+1];
X	char *greppattern;
X	char *setup_search();
X
X	greppattern = setup_search(searchpattern);
X	errornum = 0;
X	compile(greppattern, expbuf, &expbuf[ESIZE], '\0');
X	XtFree(greppattern);
X	if (errornum != 0) {
X	   switch (errornum) {
X	   case 50: 
X		disp_message("\nSearch: Regular expression overflow");
X		break;
X	   case 49:
X		disp_message("\nSearch: [ ] imbalance");
X		break;
X	   case 46:
X		disp_message("\nSearch: First number exceeds second in \\{ \\}");
X		break;
X	   case 45:
X		disp_message("\nSearch: } expected after \\");
X		break;
X	   case 44:
X		disp_message("\nSearch: More than 2 numbers given in \\{ \\}");
X		break;
X	   case 43:
X		disp_message("\nSearch: Too many \\(");
X		break;
X	   case 42:
X		disp_message("\nSearch: \\( \\) imbalance");
X		break;
X	   case 36:
X		disp_message("\nSearch: Illegal or missing delimiter");
X		break;
X
X	   default:
X		disp_message("\nSearch: search pattern failure %d", errornum);
X	   }
X	   return(-1);
X	}
X
X	setup_filepattern(filepattern);
X	filefound = False;
X	for (i = fstart; (i <= fend && (!stop || !filefound) ); i++)
X	   search_file(files, i, expbuf, stop);
X	return(0);
X}
X
X/**********************************************
X**	search utility routines
X***********************************************/
X
Xint setup_filepattern(pattern)
Xchar *pattern;
X{
X	char tmppattern[64];
X	char *error;
X
X	setup_pattern(pattern, tmppattern);
X	if (error = re_comp(tmppattern)) {
X	   disp_message("\nsearch pattern for files %s?", error);
X	   return(-1);
X	}
X	return(0);
X}
X
Xchar *setup_search(s)
Xchar *s;
X{
X	char *target, *src = s, *dest;
X	char c;
X
X	if (ignore_case == XtToggleOff) {
X	   target = XtMalloc(strlen(s) + 1);
X	   strcpy(target, s);
X	}
X	else {
X		/* allocate maximum memory */
X	   target = XtMalloc(4 * strlen(s) + 1);
X	   dest = target;
X
X	   while (c = *src++) {
X	   	if (isalpha(c)) {
X	   	   *dest++ = '[';
X	   	   *dest++ = c;
X	   	   *dest++ = ',';
X
X	   	   if (islower(c)) 	*dest++ = toupper(c); 
X		   else 		*dest++ = tolower(c); 
X
X		   *dest++ = ']';
X	   	}
X	   	else *dest++ = c;
X	   }
X	   *dest = '\0';
X	}
X	return(target);
X}
X
Xint select_searchfile(start, end, line)
Xint start, end;
Xint *line;
X{
X	int i = 0;
X	register LineElement *p;
X
X	while (i < numhitfiles && hitfiles[i]->pos1 <= start) i++; 
X	if ( (hitfiles[i-1]->pos2 + 1) < end) { *line = 0; return(-1); }
X	else {
X	   p = hitfiles[i-1]->lines;
X	   while (p != (LineElement *)NULL && (p->pa > start) ) p = p->next;
X
X	   if (p == (LineElement *)NULL) 
X	   	*line = 0; 
X	   else *line = p->linenumber;
X
X	   return(i-1);
X	}
X}
END_OF_FILE
if test 12704 -ne `wc -c <'search.c'`; then
    echo shar: \"'search.c'\" unpacked with wrong size!
fi
# end of 'search.c'
fi
if test -f 'util.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'util.c'\"
else
echo shar: Extracting \"'util.c'\" \(4542 characters\)
sed "s/^X//" >'util.c' <<'END_OF_FILE'
X/* Systems Sciences Laboratory, Webster Research Center */
X
Xstatic char *PROGRAM_information[] =
X{
X    "Copyright (c) 1988 Xerox Corporation.  All rights reserved.",
X    "$Header$",
X    "$Locker$"
X}
X;
X
X/*
X * Copyright protection claimed includes all forms and matters of copyrightable
X * material and information now allowed by statutory or judicial lay or
X * herinafter granted, including without limitation, material generated from
X * the software programs which are displayed on the screen such as icons,
X * screen display looks, etc.
X */
X
X
X#include "xfilebrowser.h"
X#include <ctype.h>
X
Xextern char *get_userdir();
X
X/* ARGSUSED */
Xdisp_message(fmt, arg1, arg2, arg3, arg4)
X  char *fmt;
X{
X	char buf[1024];
X	int maxlength = 1024;
X	XtTextBlock text;
X	XtTextPosition pos, start;
X
X	sprintf(buf, fmt, arg1, arg2, arg3, arg4);
X	text.length = strlen(buf);
X	text.ptr = buf;
X	text.firstPos = 0;
X	allowedit = 1;
X
X	pos = (*messsource->Scan)(messsource, 0, XtstAll, XtsdRight,1,0);
X
X	if ( (pos + text.length) > maxlength)  start = 0;
X	else start = pos;
X	XtTextReplace( messwidget, start, pos, &text);
X	XtTextSetInsertionPoint(messwidget, start + text.length);
X
X	allowedit = 0;
X	/* Feep(); */
X}
X
X
X/* ARGSUSED */
XWidget makeCommandButton(box, name, function)
X  Window box;
X  char *name;
X  XtCallbackProc function;
X{
X  static XtCallbackRec callbackList[] = { {NULL, NULL}, {NULL, NULL} };
X  static Arg arg[] = { {XtNcallback,(XtArgVal)callbackList} };
X
X	callbackList[0].callback = function;
X	return (XtCreateManagedWidget(name, commandWidgetClass, box, arg, 1));
X}
X
X/* ARGSUSED */
XWidget makeStringBox(parentBox, string, length)
X  Widget parentBox;
X  char *string;
X{
X  Arg args[5];
X  Widget StringW;
X  int numargs;
X    numargs = 0;
X    MakeArg(XtNeditType, (XtArgVal)XttextEdit );
X    MakeArg(XtNtextOptions, (XtArgVal)( resizeWidth)); 
X    MakeArg(XtNstring,(XtArgVal)string);     
X    MakeArg(XtNwidth,  (XtArgVal)length);
X    MakeArg(XtNlength, (XtArgVal)1000);
X    StringW = XtCreateManagedWidget("stringthing", asciiStringWidgetClass, 
X					parentBox, args, numargs);
X    return(StringW);  
X}
X
X/* ARGSUSED */
Xclear_widget(w, wsrc)
XWidget w;
XXtTextSource wsrc;
X{
X	XtTextBlock text;
X	XtTextPosition end;
X	
X	allowedit = 1;
X	text.length = 0;
X	text.ptr = "";
X	text.firstPos = 0;
X
X	end = (*wsrc->Scan)(wsrc, 0, XtstAll, XtsdRight, 1, 0);
X
X	XtTextReplace(w, 0, end, &text);
X	XtTextUnsetSelection(w);
X	XtTextSetInsertionPoint(w, 0);
X	allowedit = 0;
X}
X
X
Xint setup_dirlabel(dir, pattern)
Xchar *dir, *pattern;
X{
X	Arg dirargs[1];
X	XtTextSource src;
X	XtTextBlock text, block;
X	XtTextPosition end;
X
X		/* setup the new pattern in the fpatwindow widget */	
X	allowedit = 1;
X	text.length = strlen(pattern);
X	text.ptr = pattern;
X	text.firstPos = 0;
X
X	src = XtTextGetSource(fpatwindow);
X	(void)(*src->Read)(src, 0, &block, 254);
X
X	end = block.length;
X	XtTextReplace(fpatwindow, 0, end, &text);
X	allowedit = 0;
X
X		/* setup the new directory label in dirwidget */
X	XtSetArg(dirargs[0], XtNlabel, dir);
X	XtSetValues(dirwidget, dirargs, XtNumber(dirargs));
X}
X
X
Xsetup_iconname()
X{
X	Arg topargs[1];
X	char *p;
X	char pattern[32];
X
X	if ( ((p = rindex(curdirectory, '/')) == NULL) || (strlen(p) == 1))
X		XtSetArg(topargs[0], XtNiconName, (XtArgVal)"xbrowser");
X	else {
X	   sprintf(pattern, "../%s", p+1);
X	   XtSetArg(topargs[0], XtNiconName, (XtArgVal)pattern);
X	}
X	XtSetValues(toplevel, topargs, XtNumber(topargs));
X}
X
X/* ARGSUSED */
Xint getsize(w, width, height)
XWidget w;
XDimension *width, *height;
X{
X    static Dimension twidth, theight;
X    
X	static Arg args[] = {
X	  {XtNwidth, (XtArgVal)&twidth},
X          {XtNheight, (XtArgVal)&theight},
X        };
X
X	XtGetValues(w, args, (Cardinal)2);
X    *width = twidth;
X    *height = theight;
X}
X
X/* ARGSUSED */
Xint getpos(w, posx, posy)
XWidget w;
XPosition *posx, *posy;
X{
X    static  Position tposx, tposy;
X    
X	static Arg args[] = { 
X	   {XtNy, (XtArgVal)&tposy},
X           {XtNx, (XtArgVal)&tposx},
X        };
X
X	XtGetValues(w, args, (Cardinal)2);
X    *posx = tposx;
X    *posy = tposy;
X}
X
X/* ARGSUSED */
Xchar *expand_tilde(s)
Xchar *s;
X{
X	char *home, *getenv();
X	char *p, *fullname;
X	int i;
X	char user[12];
X
X	if (s[0] == '~' && (s[1] == '\0' || s[1] == '/') ) {
X	   home = getenv("HOME");
X	   p = s + 1;
X	}
X	else if (s[0] == '~' && isalnum(s[1])) {
X	   p = s + 1;
X	   i = 0;
X	   while (*p != '/' && *p != '\0')   user[i++] = *p++; 
X	   user[i] = '\0'; 
X
X	   if ( (home = get_userdir(user)) == NULL) return((char *)NULL);
X	}
X
X	fullname = XtMalloc(strlen(home) + strlen(p));
X	sprintf(fullname, "%s%s", home, p);
X	return fullname;
X}
X
END_OF_FILE
if test 4542 -ne `wc -c <'util.c'`; then
    echo shar: \"'util.c'\" unpacked with wrong size!
fi
# end of 'util.c'
fi
if test -f 'xbrowser.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbrowser.man'\"
else
echo shar: Extracting \"'xbrowser.man'\" \(13458 characters\)
sed "s/^X//" >'xbrowser.man' <<'END_OF_FILE'
X.TH XBROWSER 1 "25 October 1988" "X Version 11"
X.SH NAME
Xxbrowser - simple directory and file browser for X
X.SH SYNTAX
X\fBxbrowser\fP [ \fI-toolkitoption\fP ...] [ directory ]
X.SH OPTIONS
X.I Xbrowser
Xaccepts all of the standard X Toolkit command line options,
X(such as geometry, etc.) plus:
X.TP 8
X.I directory
XSpecifies the startup directory for subsequent searches within 
X.I xbrowser.
XIf no directory is specified, the current working directory is
Xchosen as the startup directory.
X.SH DESCRIPTION
X.I Xbrowser
Xprovides a graphical interface to browse directories, select files from
Xdirectory listings and invoke commands on them, such as invoking
Xthe editor on these files,
Xsearch files for specified patterns, move, copy or delete
Xfiles. The application provides
Xa window consisting of the following areas:
X.IP "Commands Menu" 8
XSpecifies commands for browsing directories and invoking the editor
Xon selected files (possible commands are \fBQuit\fP, \fBList\fP,
X\fBEdit\fP, \fBParent\fP, \fBShell\fP, \fBCopy\fP, \fBMove\fP,
X\fBDelete\fP).
X.IP "File Pattern Box"
XDefines the file name pattern for searching directories.
XIt accepts the same
Xnotation as 
X.I ls
X(except for environment variables which are currently not supported).
XThe characters *, $ and ~ are expanded as defined by C-Shell. 
XThe current working directory and
Xthe pattern defined by the File Pattern Box are combined to define the
Xsearch directory and the search pattern for files. For example,
X"net/src/*.c" searches in the directory "<current directory>/net/src"
Xfor all files whose name end with ".c". After each search the 
Xfile pattern box is updated: only the file pattern is displayed,
Xthe directory portion is extracted. The search directory becomes the
Xcurrent working directory of
X.I xbrowser.
X.IP "Directory Label"
XDisplays the current working directory of
X.I xbrowser.
XIf the file pattern does not specify an absolute path name, the current
Xdirectory is prepended to define the search directory.
X.IP "Message Window"
XDisplays
X.I xbrowser
Xmessages, such as error messages or messages returned by shell programs
Xwhich were invoked via the Shell command.
X.IP "File Window"
XDisplays a list of files which are members of the current directory used by
X.I xbrowser.
XThe files listed in this window depend on the pattern defined by the
XFile Pattern Box. Each line of the File Window displays the characteristics
Xof one file (the window does not use word wrap; the toolkit 
Xshould display a
Xhorizontal scrollbar for the text widget but the current version
Xdoes not implement it correctly).
X
XThe meaning of the characteristics is exactly the same as for the
X.I ls
Xcommand. 
X.I xbrowser
Xdisplays the file type, the access rights, the number of links, the
Xowner, the file size in bytes, the last modification date and the 
Xfile name. This window allows the user only to select one or
Xseveral lines; individual characters cannot be selected. 
X
XA single click
Xof the left mouse button selects one line. The selection of files
Xmay be extended by
Xusing the right mouse button. The selected files can be 
Xde-selected by hitting a character generating key (no modifier keys)
Xof the keyboard or by clicking the middle button of the mouse.
XA double click on a line is a shortcut for selecting a file and invoking
Xexplicitly the commands \fBList\fP or \fBView/Edit\fP. If the double-clicked
Xfile is a directory the \fBList\fP command is executed; otherwise the command
X\fBView/Edit\fP is executed (if the resource \fBViewEdit\fP is set to "true"
X.I xbrowser
Xinvokes the desired editor rather than 
X.I xmore). 
X.IP "Search Commands"
XLists the commands to search text files for specified patterns
X(possible commands are 
X\fBEdit\fP and  \fBGrep\fP).
X.IP "Grep Window"
XDisplays lines of text files which match the current search pattern. Each
Xline consists of the file name, followed by a colon and a space, followed
Xby the matching line (restricted to 256 characters).
XThis window allows the user only to select one or
Xseveral lines; individual characters cannot be selected.
X
XA double click on a line is a shortcut for selecting a file and invoking
Xexplicitly the command \fBView/Edit\fP
X(if the resource \fBViewEdit\fP is set to "true"
X.I xbrowser
Xinvokes the desired editor rather than 
X.I xmore). 
X.SH COMMANDS
X.IP "Quit" 8
XExits
X.I xbrowser.
XWindows created via the Edit or Shell
Xcommand buttons (
X.I xterm
Xwindows) are not deleted.
XHowever, all dialog boxes and dialog windows are destroyed.
X.IP "List"
XSearches directories to list all files which match the pattern
Xdefined in the File Pattern Box. If a directory is selected in
Xthe File Window, it is assumed to be the current search directory. If 
Xthe file selected in the File Window is not a directory, an error message
Xis returned. If no file is selected or the selected file is not a
Xdirectory,
X.I xbrowser
Xcombines the current working directory with the string specified in the
XFile Pattern Box to determine the current search directory and 
Xfile pattern. After the 
X.I List
Xcommand is performed successfully, the current directory of 
X.I xbrowser
Xis updated (see Directory Label).
X
XPressing the left mouse button sorts the files in the ascending order
Xof the current sorting option (e.g. starting from A to z in case of
Xfile names). If the middle button is
Xpressed
X.I xbrowser
Xapplies the current sorting option, but in reverse order.
XIf the right button is pressed, an option menu is displayed for
Xchoosing the current sorting option, the option to display owner or group
Xassociated with the file,
Xand the option to print files starting with a dot or not. The files may
Xbe sorted by file name, file size or date (in ascending or descending
Xorder depending if the left or the middle button is pressed). If an option
Xis selected it is displayed in reverse video.
X.IP View/Edit
XInvokes the viewer or the editor on the file selected in the File Window. Only one
Xfile may be selected at a time. Clicking the left mouse button runs
Xthe 
X.I xmore
Xapplication and loads the selected file. The file cannot be edited.
XClicking the middle mouse button invokes the preferred editor on
Xthe selected file. This commands checks the
Xenvironment variable XEDITOR to determine the preferred editor. If
Xthe environment variable is not set, 
X.I xedit
Xis invoked. 
X
XFor each viewer or editor instance a new process and a new X window is
Xcreated. If the favourite text editor is
X.I vi
Xthe environment variable XEDITOR must be set to "xterm -e vi" (which
Xassures the creation of a new X window). 
XThe cursor
Xis always positioned at the beginning of the file.
X
XThe Search Commands also include an View/Edit command (left button for
Xviewer;
Xmiddle button for editor). It
Xworks on selections in the Grep Window rather than selections in the
XFile Window. If the preferred viewer/editor supports line number selection
Xfrom the command line, such as
X.I jhsxedit,
X.I emacs
Xor
X.I vi,
Xthen the cursor of the viewer/editor is positioned at that line of the file 
Xwhich corresponds to the  grep match displayed
Xin the grep window. Otherwise the cursor is positioned at the beginning
Xof the file.
X.I xmore
Xand
X.I xedit
Xdo not support line positioning.
X
XFor both View/Edit commands
Xthe created windows are not deleted when the user quits
X.I xbrowser.
XThe user must close all windows
Xseparately.
X.IP Parent
XClears the File and Grep Window, and changes the current directory
Xof
X.I xbrowser
Xto the parent of the current directory. If the left mouse button is
Xpressed, the current file pattern is
Xapplied to list the files of the new current directory using the last sorting option. If the middle button is pressed, the new current
Xdirectory is \fBnot\fP listed. Pressing the right mouse button
Xperforms no action; the current directory stays unchanged.
X.IP Shell
XProvides the option to execute shell programs or to create
Xnew xterm windows. 
X
XIf the left mouse button is pressed, 
X.I xbrowser
Xdisplayes a dialog box in which the user may type a shell command (note
Xthe execution uses
X.I sh
Xrather then
X.I csh;
Xcertain special characters, such as ~ are not valid for
X.I sh).
XIf the user selected one or several files in the File Window, their
Xnames are displayed in the dialog box. The dialog window also displays
X2 options: 
X.B Return Ouput
Xand
X.B Return Diagnostics.
XIn the first case the standard output generated by the shell command
Xis displayed in the Message window (if the
Xinformation consists only of a few lines) or in a separate popup window; in the second case the standard error information is returned to the user. 
XBoth buttons are
Xtoggles and the user may enable/disable them. If an option is
Xselected, it is displayed in reverse video. 
XIf the user disables both options, messages are displayed in the 
X.I xterm
Xstartup window. The user must 
Xquit the popup window, before he/she may invoke new commands in
X.I xbrowser.
X
XIf the middle button is pressed a new
X.I xterm
Xwindow is created inheriting the current working directory
Xof
X.I xbrowser.
XIf the user quits
X.I xbrowser, xterm
Xwindows are not deleted. They must be closed separately.
X.IP Copy
XCopies files selected in the File Window. The user is 
Xprompted in a dialog box to specify the target file or target
Xdirectory. The File Window is updated.
X.IP Move
XMoves files selected in the File Window. The user is 
Xprompted in a dialog box to specify the target file or target
Xdirectory. The File Window is updated.
X.IP Delete
XDeletes files selected in the File Window. For each file the user
Xis prompted in a dialog box, if he/she wants to delete this file
X(yes button) or skip this file (no button) or cancel the delete
Xoperation (cancel button). If the user selects the cancel button
Xduring the interaction, the Delete command is aborted and no file
Xis deleted (even if the user answered yes to previous prompts).
XThe actual deletion occurs after the user answered all prompts with
Xyes or no.
X.IP Grep
XSearches files to find lines 
Xwhich match the pattern defined in the string box after the 
X.I Grep 
Xcommand. The files searched is determined by the 
Xpattern in the File Pattern Box, the files selected in the File Window
Xand selections in the dialog box associated with
X.I Grep
X(the dialog box is invoked by pressing the right mouse button; see below).
XAll files selected in the File Window which
Xsatisfy the file pattern in the File Pattern Box are searched.
XIf no file is selected in the File Window, all files which satisfy
Xthe file pattern are
Xsearched. The search pattern for
X.I Grep
Xis a regular expression as defined by the
X.I grep
Xshell command.
X.I xbrowser
Xattempts to determine the file type (executable, text, etc). Only
Xtext files are searched. This allows the user to extend the file
Xselection across non-text files (e.g., select all .c and .o files
Xin a directory; but .o files are not searched).
X
XClicking the left mouse button
Xcontinues until all files which match the file pattern are searched.
XClicking the middle
Xbutton stops searching at the first file which contains a match
Xfor the string to be searched.
X
XClicking the right button displays a dialog window which allows the
Xuser to specify the search behavior in case
X.I Grep
Xencounters a directory. The user may skip all directories
X(this is the default)
Xthat means only files selected in the File Window are searched.
XThe user may select the option
X"search next-level directory" which specifies that all directories
Xwhich are selected in the File Window are searched, i.e. files in
Xthese directories
Xwhose file names satisfy the pattern in the File Pattern Box. The last
Xoption allows the user to recursively search all directories which
Xare encountered.
X.I Grep
Xfor this option may take a long time (depending on the size of the
Xunderlying directory structure).
XThe file pattern in the File Pattern Box is only 
Xinterpreted for the files which are actually searched for
Xthe string pattern. It is not a selection criteria for directory
Xnames.
X
XThe dialog window for
X.I Grep
Xalso supports a toggle for case-sensitive or case insensitive search.
XThe default setting is case-sensitive.
X.SH X DEFAULTS
X.I xbrowser
Xsupports the following resource which may be set in the .Xdefaults file:
X.IP "ViewEdit"
Xspecifies the tool to be invoked after the user double-clicks a text file
Xof the File Window or the Grep Window. If the resource is set to "false"
X.I xbrowser
Xinvokes
X.I xmore
Xon the double-clicked file (the default setting of ViewEdit is false).
XOtherwise
X.I xbrowser
Xinvokes the user desired editor on the double-clicked file.
X.SH FILES
X~/.XtActions, ~/.Xdefaults
X.br
X/usr/lib/X11/.XtActions
X.SH SEE ALSO
XX(1), xedit(1), ls(1), grep(1), sh(1), csh(1), jhsxedit(1);
X.SH BUGS
XBeware of using the geometry resource in your .Xdefaults file for
X.I xbrowser.
XThe
Xtoolkit obviously interprets these values not only for the toplevel
Xwindows but also for the popup windows (dialog boxes). I tried
Xto overwrite the values, but it does not work consistently. If 
Xyou specify a geometry resource for
X.I xbrowser
Xin your .Xdefaults file, the dialog boxes will have initially these geometry
Xsizes (you might have very strange shaped command buttons). Geometry values
Xspecified on the command line which called 
X.I xbrowser 
Xdo not affect the dialog
Xbox geometry.
X
XIf you use the window manager twm, your .twmrc must set 
X.I NoTitleFocus
Xotherwise the dialog boxes and the text windows do not work
Xcorrectly. There is a bug in twm.
X.SH RESTRICTIONS
X.SH COPYRIGHT
XCopyright 1988, Xerox Corporation.
X.SH AUTHOR
XHans Schlichter, Xerox Corporation.
END_OF_FILE
if test 13458 -ne `wc -c <'xbrowser.man'`; then
    echo shar: \"'xbrowser.man'\" unpacked with wrong size!
fi
# end of 'xbrowser.man'
fi
echo shar: End of archive 1 \(of 3\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 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
-- 
Mike Wexler(wyse!mikew)    Phone: (408)433-1000 x1330
Moderator of comp.sources.x