[alt.sources] Xbrowser part 01/01

andy@comp.lancs.ac.uk (Andy Colebourne) (03/22/91)

Xbrowser is a file and directory browser for X-Windows.  It needs Motif 1.1.

Luv 'n' Hugs,

Andy
xx

------------------------cut here------------------------------------

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	COPYRIGHT
#	Makefile
#	README
#	TODO
#	xbrowser.1
#	xbrowser.buttons
#	xbrowser.c
#	xbrowser.magic
# This archive created: Fri Mar 22 13:54:16 1991
export PATH; PATH=/bin:$PATH
if test -f 'COPYRIGHT'
then
	echo shar: will not over-write existing file "'COPYRIGHT'"
else
sed 's/^X//' << \SHAR_EOF > 'COPYRIGHT'
XCopyright (c) 1991 Andy Colebourne and the University of Lancaster
X
XPermission to use, copy, modify, distribute, and sell this software
Xand its documentation for any purpose is hereby granted without fee,
Xprovided that the above copyright notice appear in all copies and that
Xboth that copyright notice and this permission notice appear in
Xsupporting documentation, and that the names of Andy Colebourne and
Xthe University of Lancaster not be used in advertising or publicity 
Xpertaining to distribution of the software without specific, written prior
Xpermission.  Andy Colebourne and the University of Lancaster make no 
Xrepresentations about the suitability of this software for any purpose.
XIt is provided "as is" without express or implied warranty.
X
XAndy Colebourne and the University of Lancaster DISCLAIMS ALL WARRANTIES
XWITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF 
XMERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Andy Colebourne and the
XUniversity of Lancaster BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
XDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 
XPROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
XACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 
XTHIS SOFTWARE.
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
XLIBS = -lXm -lXt -lX11
X
Xxbrowser:	xbrowser.c
X	cc -D_NO_PROTO -o xbrowser xbrowser.c $(LIBS)
SHAR_EOF
chmod +x 'Makefile'
fi # end of overwriting check
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XThis is xbrowser, a user-configurable file and directory browser for X-Windows.
XIt compiles with Motif 1.1
X
XSend me something nice if you like this program.
X
XAndy Colebourne
XDept. of Computing
XLancaster University
XBailrigg
XLA1 4YW
X
XAndy@uk.ac.lancs.comp
SHAR_EOF
fi # end of overwriting check
if test -f 'TODO'
then
	echo shar: will not over-write existing file "'TODO'"
else
sed 's/^X//' << \SHAR_EOF > 'TODO'
XThings to do to version 1.0 of xbrowser (in no particular order)
X
X1. Add a separate wildcard text widget next to the directory_path text widget.  This
Xcould hold "*.c" and only those files matching that wildcard in the directory would be
Xdisplayed.
X
X2. Redirect stdout etc. to a scrolling text window.  (I've no idea how to do this!)
X
X3. Check the magic number of a file (as unix file command does) and execute a
Xcommand on the file when it is double clicked on.
X
X
XIf you write any code for any of the above please send it to me so it can be added
Xand released!  Also mail me if you have any new ideas for improving xbrowser.
X
Xandy@uk.ac.lancs.comp
SHAR_EOF
fi # end of overwriting check
if test -f 'xbrowser.1'
then
	echo shar: will not over-write existing file "'xbrowser.1'"
else
sed 's/^X//' << \SHAR_EOF > 'xbrowser.1'
X.TH xbrowser 1 "22 March 1991"
X.SH NAME
Xxbrowser \- X11 directory and file browser
X.SH SYNOPSIS
X.B xbrowser [-debug]
X.LP
X
X.SH DESCRIPTION
X
XXbrowser displays two directory listing windows and allows the user to
Xtraverse the directory structure by double-clicking on directory names.
XFiles
Xor directories can be marked by a single-click, and operations performed on
Xthem.  Buttons can be 
Xdefined which, when pressed, execute specified commands on the selected files.
XA double click on a file can be used to perform a specified operation,
Xdetermined by the file name or suffix.
X
XTwo directory windows, the source and destination directories, are shown.  Each
Xwindow can display different directories, with the path of the current
Xdirectory
Xshown in a text widget above it.  A new path may be entered
Xin here and the directory will be re-read when return is pressed.  At the
Xbottom of each directory window are four buttons:
X
X.I 	All
Xselect all files and directories.
X
X.I 	Clear
Xdeselects all files and directories.
X
X.I 	Files
Xselects only files.
X
X.I 	Invert
Xinverts all.
X
X.SH OPTIONS
X\-debug    Displays the button and magic file information (and any errors) as
Xthe files are read.
X
X.SH BUTTONS
XThere are four buttons which always appear, QUIT, VIEW, HEX VIEW and RENAME.
X
X.I QUIT
Xexits xbrowser,
X
X.I VIEW
Xdisplays selected text files in a window,
X
X.I HEX VIEW
Xdisplays selected files as hex codes in a window.
X
X.I RENAME
Xallows selected files and directories to be renamed. 
X
XOther buttons are defined in a file called 
X.I xbrowser.buttons
Xwhich is either in the directory in which xbrowser is started or the directory
Xspecified by the environment variable
X.I XBROWSER.
XIt is read automatically when xbrowser is run.
X
XEach line in the button file specifies:
X 1. the button label,
X 2. the context in which the command is used,
X 3. a re-read flag, and
X 4. a command:
X
XA '#' at the start of a line indicates that the line is a comment.
X
X.SS Button Label
XThe label is the text that will appear on the button; it may not contain spaces.
X
X.SS Button Context
XThe button context determines the relationship between the command and the
Xitems selected in the directory viewers.  Some commands may be performed on
Xmany files at once, for example 'compress,' whereas others only make sense with
Xone file, for example xedit.  The former would use a button context of 'all,'
Xand the latter would use 'each.'  The difference is that a new xedit is run for
Xeach selected file in the latter case.  The available button contexts are listed below:
X
X.I all
X\- execute the command once with all the marked files as
Xthe parameter.  The command will be run in the directory of the marked files.
X(One '%s' should be present in the command string).
X
X.I allpath
X\- the command is executed once and full pathnames are used for each
Xfile.  (One '%s' should be present in the command string)
X
X.I each
X\- execute the command once for each file marked.  (One '%s' should be present in the command string)
X
X.I command
X\- execute the command.  The current working directory will be set to the path
Xof the last file clicked on before the command is executed. No parameters are
Xsubstituted (no '%s' should be present in the command string).
X
X.I sourcedest
X\- two strings are placed into the command string: first, all the
Xfiles selected on the left, and secondly, the current right-directory name.  The single
Xcommand is then executed. (Two '%s' should be present in the command string.)
X
XThe reason for the distinction between 'all' and 'allpath' is because the two
Xdirectory viewers may be opened on different directories.  With 'all', the
Xcommand is run from the directory of the left hand viewer for files selected on
Xthe left, and another command run from the directory of the right hand viewer for
Xthose files selected on the right.  If running two separate commands is inappropriate,
Xthen 'allpath' should be used; it executes the command only once, with the full pathnames
Xgiven for each file.  This is useful, for example, with the 'diff' command, where it must
Xbe run only once, even if the two files lie in different directories.
X
X.SS Re-read Flag
XThe re-read flag is either a 'y' or an 'n'.
XIt indicates whether the directory viewer should be re-read after the command has
Xbeen executed.  This is essential after a command that may change the contents of
Xa directory, (for example 'mkdir' or 'make') to keep the viewer up to date.
X
X.SS Button Command
XThe rest of the line is taken to be the command that will be executed when the button is
Xpressed.  Up to two '%s' may be present (depending on the context used).  These
Xwill be substituted, when the button is pressed, by one or more highlighted
Xfilenames.
X
XNote that the button command may finish with an '&' symbol, in which case the command
Xwill be run in the background; you may continue to use the browser whilst it executes.
XIn this case though, the re-read flag may not have the desired effect, as the directory
Xwill be re-read after the command has started, not after it has finished.
X
XAn additional parameter may be requested from the user before a command is executed by
Xinserting a '^' character, as in the following example:
X
XMkDir    command    y    mkdir ^MkDir@Enter directory name^
X
XWhen the MkDir button is pressed, a dialogue box is presented to the user.  Its title
Xis the string appearing between the first '^' and the '@' (i.e. 'MkDir'), and its prompt
Xis the rest of the text up to the second '^'.  A text widget is provided, along with 'OK'
Xand 'Cancel' buttons.  Pressing the 'OK' button reads the text that the user has entered
Xinto the text widget, substitutes that in the command string in place of all text between
Xthe '^' symbols, and finally executes the new command.  This allows any command to accept
Xan extra parameter string from the user before execution.
X
X.SS Examples
X
XCOMPRESS    all    y    compress %s
X
XThis creates a button labelled with the string
X.I COMPRESS.
XWhen it is pressed, the
X.I compress
Xcommand is executed on all of the items that are selected in the
Xdirectory windows.  The directory viewer will be re-read after the
Xcommand has executed.  Any output from the command will appear in the
Xwindow from where the browser was started, and any input required will be
Xtaken from the same window.
X
XMAIL    allpath    n    cat %s | mail ^Mail@Enter username^
X
XThis creates a button labelled with the string
X.I MAIL.
XWhen it is pressed, the full pathnames of all selected files are substituted
Xfor the '%s' and a dialogue entitled 'Mail' is brought up prompting the user for
Xa username.  Pressing 'OK' places the username after the 'mail' command, and
Xfinally the command string is executed.
X
X.SS EXAMPLE BUTTONS
X.nf
XXTERM		command		n	xterm & 
XCOPY		sourcedest	y	cp -ri %s %s 
XXV		all		n	xv %s &
XVI		each		n	xterm -e vi %s & 
XDIFF		allpath		n	diff %s | xmless &
X.fi
X
X.SH DOUBLE-CLICKING
XDouble-clicking on a directory name (indicated by a '/' after its name) will
Xchange the directory window to view that directory. 
XA double-click on an executable file (indicated by an '*' after its name) will
Xrun it.  Double clicking on a file will
Xinitiate a search through a list (called the
X.I magic list)
Xto see if there is a match with that file.  A match causes a corresponding
Xcommand to be executed.
X
X.SH MAGIC FILE
XThis magic list is read from 
X.I xbrowser.magic
Xwhen xbrowser is run.  It should be
Xpresent either in the current directory or the directory specified by the
Xenvironment variable
X.I XBROWSER.
X
XEach line in the magic file specifies:
X 1. The magic classification
X 2. A match string
X 3. Re-read flag
X 4. A command
X
X.SS Magic Classification
XThe
X.I magic class
Xis either the string
X.I file
Xor
X.I suffix.
XIt specifies whether
Xthe match-string should be used to look for a whole filename or just the suffix.
X
X.SS Match String
XThe
X.I match string
Xspecifies the filename or suffix to be used when matching.
X
X.SS Re-read flag
XThe re-read flag is either a 'y' or an 'n'.
XIt indicates whether the directory viewer should be re-read after the command has
Xbeen executed.
X
X.SS Command
XThe
X.I command
Xis executed after a match has been found.  If the command string is
X.I *view,
Xthe xbrowser internal function is used to show the file.
XSimilarly,
X.I *hex
Xwill use the xbrowser internal hex view function.
XOtherwise,
Xthe command is executed in the same manner as Button File command strings (see above).
X
X.SS Example Magic Definitions
X.nf
Xfile	.Xdefaults	n	csh -c "xedit %s" &
Xfile	README		n	*view
Xsuffix	.au		n	/usr/demo/SOUND/play -v 20 %s &
Xsuffix	.tar		n	tar tvf %s | xmless &
Xsuffix	.gif		n	xloadimage %s &
X.fi
X
X.SH HINTS AND TIPS
X
X.SS Command Strings
X
XCommand string may contain multiple commands separated by pipes or semi-colons in
Xthe usual manner.  They may also be run in the background by appending an '&'.  To
Xrun multiple commands in the background, enclose them in parentheses '(' and ')'
Xbefore appending the '&'.
X
XCommands are executed via the Bourne shell.  This means that csh users will not be able
Xto use their aliases.  To overcome this problem precede the command by 'csh - c'
X
XX-Window users may run commands in xterm windows using command strings of the form of the
Xfollowing example, which runs 'vi' on selected files.
X.nf
Xxterm -e vi %s
X.fi
X
X.SH X-RESOURCES
XThe number of items visible in each list can be altered by putting the following
Xin the .Xdefaults file:
X
XXbrowser*sidelist.visibleItemCount: <int>
X
X(Where <int> is the number of visible lines in each list)
X
XThe window which is used for VIEW has the resourcename "textwindow".  The size
Xcan be changed.  e.g.
X.nf
XXbrowser*textwindow.rows:		20
XXbrowser*textwindow.columns:		80
X.fi
X
XThe strip of buttons along the bottom of the main window can be made to
Xposition the buttons in rows and columns:
X
XFor two rows of buttons:
X
XXbrowser*buttonstrip.packing:		PACK_COLUMN
XXbrowser*buttonstrip.numColumns:	2
X
X.SH FILES
X.nf
X$XBROWSER/xbrowser.buttons
X$XBROWSER/xbrowser.magic
Xxbrowser.buttons
Xxbrowser.magic
X$HOME/.Xdefaults
X.fi
X
X.SH SEE ALSO
Xxmless
X
X.SH BUGS
XThere probably are some!
X
X.SH AUTHOR
XAndy Colebourne
SHAR_EOF
fi # end of overwriting check
if test -f 'xbrowser.buttons'
then
	echo shar: will not over-write existing file "'xbrowser.buttons'"
else
sed 's/^X//' << \SHAR_EOF > 'xbrowser.buttons'
X# Buttonname	context	    rereaddir?	command string
X# 
XCopy		sourcedest	y	cp -ri %s %s
XMove		sourcedest	y	mv -i %s %s
XDelete		all		y	rm -ir %s
XMakeDir		command		y	mkdir ^Make Directory@Enter new dir name:^
XXV		all		n	xv %s &
XXedit		each		n	csh -c "xedit %s "&
XMore		each		n	xterm -e more %s /dev/null & 
X#VI		each		n	xterm -e vi %s & 
XXterm		command		n	xterm &
XFile		all		n	file %s
XWordCount	all		n	wc %s
XDiff		allpath		n	diff %s | xmless &
XPlay		each		n	cat %s >/dev/audio
XMan		each		n	nroff -man %s | xmless &
XCompress	all		y	compress %s 
XUncompress	all		y	uncompress %s
Xgrep		allpath		n	grep ^Grep@Enter search string:^ %s | xmless &
XCommand		allpath		y	csh -c "^Command@Enter command for selected files:^ %s"		
XChmod		allpath		y	chmod ^Chmod@Enter protections for files^ %s
XPrint		allpath         n      	lpr ^Printout@Enter options:^ %s &
SHAR_EOF
chmod +x 'xbrowser.buttons'
fi # end of overwriting check
if test -f 'xbrowser.c'
then
	echo shar: will not over-write existing file "'xbrowser.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xbrowser.c'
X/** XBrowser V1.0 by Andy Colebourne **/
X
X/** Some of this code is not very tidy!  I may clean it up one day. **/
X/** if you find any bugs, please mail me with the details (and fixes?) **/
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <sys/param.h>
X#include <dirent.h>
X
X#include <X11/Intrinsic.h>
X#include <Xm/Xm.h>
X#include <Xm/Label.h>
X#include <Xm/RowColumn.h>
X#include <Xm/Text.h>
X#include <Xm/List.h>
X#include <Xm/PushB.h>
X#include <Xm/Form.h>
X#include <Xm/Frame.h>
X#include <Xm/SelectioB.h>
X#include <Xm/DialogS.h>
X
X#define VERSIONSTRING "XBrowser Version 1.0"
X#define MAGIC_FILE "xbrowser.magic"
X#define BUTTONS_FILE "xbrowser.buttons"
X
XString fallback_resources[] = {
X    "*title*fontList:			*-times-bold-r-*-*-*-140-*" ,
X    "*textwindow.rows:			24",
X    "*textwindow.columns:		80",
X    "*sidelist.visibleItemCount:	12",
X    NULL,
X};
X
X
X#define DIRSIZE 1000
X#define STRING(A) strcpy(malloc(strlen(A)+1),A);
X#define MFILE 0
X#define MSUFFIX 1
X#define LEFT 0
X#define RIGHT 1
X
Xchar leftcd[MAXPATHLEN];
Xchar rightcd[MAXPATHLEN];
XWidget toplevel, leftinfolabel, rightinfolabel;
Xchar *astring;
XBoolean debug;
XBoolean readaftercommand;
X
X
Xstruct Entry
X{
X    char *name;
X    off_t size;
X    Boolean dir;
X    int mode;
X    char *path;
X    char *fullname;
X};
X
X
Xstruct Magic
X{
X    int mtype;
X    char *mname;
X    char *mstring;
X    Boolean mreread;
X
X};
X
X
Xstruct Button
X{
X    int context;
X    char *command;
X    Boolean reread;
X};
X
X
X#define BALL 0
X#define BEACH 1
X#define BCOMMAND 2
X#define BSOURCEDEST 3
X#define BALLPATH 4
X
Xstruct Button *buttonlist[255];
Xint num_buttons;
X
Xstruct Magic *magiclist[255];
Xint num_magic;
X
Xstruct Entry *leftptrs[DIRSIZE];
Xstruct Entry *rightptrs[DIRSIZE];
Xint leftlistnum, rightlistnum;
XWidget leftlist, rightlist ,leftlabel, rightlabel, leftdirtext, rightdirtext;
Xint rename_popups;
Xchar *command_string;
Xlong int size;
Xchar *xbrowserpath;
X
Xint compare(ptr1, ptr2)
Xvoid *ptr1, *ptr2;
X{
X    return( strcmp( ((struct Entry *)*(struct Entry **)ptr1)->name, ((struct Entry *)*(struct Entry **)ptr2)->name ));
X}
X
X
Xvoid set_label(w, str)
XWidget w;
Xchar *str;
X{
Xint ac;
XArg al[2];
XXmString label_label;
X
X    ac = 0;
X    label_label = XmStringCreateLtoR(str, XmSTRING_DEFAULT_CHARSET);
X    XtSetArg(al[ac], XmNlabelType, XmSTRING); ac++;
X    XtSetArg(al[ac], XmNlabelString, label_label); ac++;
X    XtSetValues(w, al, ac);
X    XmUpdateDisplay(w);
X}
X
Xvoid displayerror(t, side)
Xchar *t;
Xint side;
X{
X
X    if (side == LEFT)
X        set_label(leftinfolabel, t);
X    else
X        set_label(rightinfolabel, t);
X
X}
X
Xvoid add_size(ptr)
Xstruct Entry *ptr;
X{
X    size = size + ptr->size;
X}
X
X
X
Xvoid display_info(side)
Xint side;
X{
Xint *sellist;
Xint numsel, n;
Xchar line[255];
X
X    numsel = 0;
X    size = 0;
X    if (side == LEFT)
X        {
X        numsel = foreachleft(add_size);
X        sprintf(line, "%d selected, %d bytes", numsel, size);
X        set_label(leftinfolabel, line);
X        }
X    else
X        {
X        numsel = foreachright(add_size);
X        sprintf(line, "%d selected, %d bytes", numsel, size);
X        set_label(rightinfolabel, line);
X        }
X
X}
X
Xint dir_list(list, dir, ptrs)
X/* ** read a dir from 'dir' string and set the list contents in widget 'list **/
XWidget list;
Xchar *dir; 
Xstruct Entry *ptrs[];
X{
XArg al[10];
Xint ac;
XDIR *dirl;
Xstruct dirent *dent;
XXmString item_array[DIRSIZE];
Xint items,loop, side, n;
Xstruct stat buf;
Xchar info_line[255];
Xchar p[10];
Xmode_t mode;
X
X    if (list == leftlist)
X        side = LEFT;
X    else
X        side = RIGHT;
X
X    dirl = opendir(dir);
X    if (dirl == NULL)
X        {
X        displayerror("can't open dir", side);
X        return(0);
X        }
X
X    if (side == LEFT)
X        {
X        for (n=0; n < leftlistnum; n++)
X             free(ptrs[n]);
X        }
X    else 
X        {
X        for (n=0; n < rightlistnum; n++)
X             free(ptrs[n]);
X        }
X    items = 0;
X    for ( dent = readdir(dirl); dent != NULL ; dent = readdir(dirl) )
X        {
X        char path[MAXNAMLEN];
X
X        sprintf(path, "%s/%s", dir, dent->d_name);
X        stat(path, &buf);
X
X        ptrs[items] = (struct Entry *)malloc(sizeof(struct Entry));
X        ptrs[items]->dir = S_ISDIR(buf.st_mode);
X        ptrs[items]->size = buf.st_size;
X        ptrs[items]->mode = buf.st_mode;
X        ptrs[items]->name = STRING(dent->d_name);
X        ptrs[items]->path = STRING(dir);
X        ptrs[items]->fullname = XtMalloc(strlen(dir)+strlen(dent->d_name)+2);
X        sprintf(ptrs[items]->fullname, "%s/%s", dir, dent->d_name);
X        items++;
X        }
X
X    closedir(dirl);
X
X    qsort(ptrs, items, sizeof(struct Entry *), compare);
X
X    for (loop=0; loop < items; loop++)
X        {
X        char t;
X
X        t = ' ';
X        if (ptrs[loop]->dir)
X            t='/';
X        else
X        if (ptrs[loop]->mode & S_IXUSR)
X            t = '*';
X    mode = ptrs[loop]->mode;
X    strcpy(p, "----------");
X    if (ptrs[loop]->dir)
X        p[0] = 'd';
X    if (mode & S_IRUSR)
X        p[1] = 'r';
X    if (mode & S_IWUSR)
X        p[2] = 'w';
X    if (mode & S_IXUSR)
X        p[3] = 'x';
X    if (mode & S_IRGRP)
X        p[4] = 'r';
X    if (mode & S_IWGRP)
X        p[5] = 'w';
X    if (mode & S_IXGRP)
X        p[6] = 'x';
X    if (mode & S_IROTH)
X        p[7] = 'r';
X    if (mode & S_IWOTH)
X        p[8] = 'w';
X    if (mode & S_IXOTH)
X        p[9] = 'x';
X
X        sprintf(info_line, " %s %8d %s%c", p, ptrs[loop]->size, ptrs[loop]->name, t);
X        item_array[loop] = (XmString)XmStringCreateLtoR(info_line, XmSTRING_DEFAULT_CHARSET);
X        }
X
X    ac = 0;
X    XtSetArg(al[ac], XmNitems, (XtArgVal)item_array); ac++;
X    XtSetArg(al[ac], XmNitemCount, (XtArgVal)items); ac++;
X    XtSetValues(list, al, ac);
X    XmListDeselectAllItems(list);
X    displayerror("OK.", side);
X    return(items);
X}
X
Xvoid read_left()
X{
X    set_label(leftinfolabel, "Reading directory...");
X    leftlistnum = dir_list(leftlist, leftcd, leftptrs);
X}
X
Xvoid read_right()
X{
X    set_label(rightinfolabel, "Reading directory...");
X    rightlistnum = dir_list(rightlist, rightcd, rightptrs);
X}
X
Xvoid do_left()
X{
X    getwd(leftcd);
X    XmTextSetString(leftdirtext, leftcd);
X    read_left();
X}
X
Xvoid do_right()
X{
X    getwd(rightcd);
X    XmTextSetString(rightdirtext, rightcd);
X    read_right();
X}
X
Xvoid init()
X{
X    do_left();
X    do_right();
X}
X
X
X
Xvoid newleftdir()
X{
X    strcpy(leftcd, XmTextGetString(leftdirtext));
X    read_left();
X}
X
Xvoid newrightdir()
X{
X    strcpy(rightcd, XmTextGetString(rightdirtext));
X    read_right();
X}
X
X
X
Xvoid sys(com)
Xchar *com;
X{
X    fprintf(stdout, "%s\n", com);
X    system(com);
X    if (readaftercommand)
X        {
X        read_left();
X        read_right();
X        }
X
X}
X
X     
X
X
X
Xvoid killpop(w, c1, c2)
XWidget w;
X{
X    XtUnmanageChild(w);
X    XtDestroyWidget(w);
X}
X
X
Xstatic XtCallbackRec call_kill[] = { {(XtCallbackProc)killpop, (caddr_t)NULL},
X                            { (XtCallbackProc)NULL, (caddr_t)NULL} };
X
X
X
Xvoid string_popup(title, info, initstr, callback, entry)
Xchar *title, *info, *initstr;
XXtCallbackProc callback;
Xstruct Entry *entry;
X{
XWidget pop, stringtext, outer, rc, label;
XArg al[10];
Xint ac;
XFILE *fp = NULL;
XWidget okbutton, cancelbutton, cancelallbutton;
X
X
X    ac = 0;
X    XtSetArg(al[ac], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);  ac++;
X    XtSetArg(al[ac], XmNselectionLabelString, XmStringCreate(info, XmSTRING_DEFAULT_CHARSET) ); ac++;
X    XtSetArg(al[ac], XmNtextString, XmStringCreate(initstr, XmSTRING_DEFAULT_CHARSET) ); ac++;
X    pop = XmCreatePromptDialog(toplevel, "stringpopup", al, ac);
X    outer = XtParent(pop);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNunmapCallback, call_kill);  ac++;
X    XtSetValues(outer, al, ac);
X
X    stringtext = XmSelectionBoxGetChild(pop, XmDIALOG_TEXT );
X
X    okbutton = XmSelectionBoxGetChild(pop, XmDIALOG_OK_BUTTON);
X    cancelbutton = XmSelectionBoxGetChild(pop, XmDIALOG_CANCEL_BUTTON);
X
X    XtUnmanageChild(XmSelectionBoxGetChild(pop, XmDIALOG_HELP_BUTTON) );
X
X    XtAddCallback(pop, XmNokCallback, callback, (XtPointer)entry);
X    XtAddCallback(pop, XmNcancelCallback, callback, (XtPointer)entry);
X
X    XtUnmanageChild(XmSelectionBoxGetChild(pop, XmDIALOG_SEPARATOR ) );
X
X    ac = 0;
X    XtSetArg (al[ac], XmNtitle, title); ac++;
X    XtSetValues(outer, al, ac);
X
X    XtManageChild(pop);
X}
X
X
Xvoid view_window(str, title)
Xchar *str;
Xchar *title;
X{
XWidget pop, textwindow, outer;
XArg al[10];
Xint ac;
X    ac = 0;
X    XtSetArg(al[ac], XmNokLabelString, XmStringCreate("Close", XmSTRING_DEFAULT_CHARSET) ); ac++;
X    pop = XmCreatePromptDialog(toplevel, "textpopup", al, ac);
X    outer = XtParent(pop);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNunmapCallback, call_kill);  ac++;
X    XtSetValues(outer, al, ac);
X
X    XtUnmanageChild(XmSelectionBoxGetChild(pop, XmDIALOG_SELECTION_LABEL) );
X    XtUnmanageChild(XmSelectionBoxGetChild(pop, XmDIALOG_TEXT ) );
X    XtUnmanageChild(XmSelectionBoxGetChild(pop, XmDIALOG_SEPARATOR ) );
X    XtUnmanageChild(XmSelectionBoxGetChild(pop, XmDIALOG_APPLY_BUTTON) );
X    XtUnmanageChild(XmSelectionBoxGetChild(pop, XmDIALOG_CANCEL_BUTTON) );
X    XtUnmanageChild(XmSelectionBoxGetChild(pop, XmDIALOG_HELP_BUTTON) );
X
X
X    ac = 0;
X
X    XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
X    XtSetArg(al[ac], XmNscrollLeftSide, TRUE); ac++;
X    textwindow = XmCreateScrolledText(pop, "textwindow", al, ac);
X    XtManageChild(textwindow);
X
X    ac = 0;
X    XtSetArg (al[ac], XmNtitle, title); ac++;
X    XtSetValues(outer, al, ac);
X
X    XmTextSetString(textwindow, str);
X    XmUpdateDisplay(textwindow);
X    XtManageChild(pop);
X}
X
X
Xvoid text_popup(filename)
Xchar *filename;
X{
X
XFILE *fp = NULL;
Xint file_length;
Xchar * file_string;
Xstruct stat statbuf;
X
X
X    /** load the file **/
X
X    if ((fp = fopen(filename, "r")) == NULL)
X        {
X        char line[255];
X
X            sprintf(line, "can't open file %s for viewing\n", filename);
X            fprintf(stderr, line);
X            return;
X        }
X
X    
X    if (stat(filename, &statbuf) == 0)
X        file_length = statbuf.st_size;
X    file_string = (char *) XtMalloc((unsigned)file_length+1);
X    file_string[file_length]='\0';
X    fread(file_string, sizeof(char), file_length, fp);
X    if (fclose(fp) != NULL)
X        fprintf(stdout, "%s\n", "Warning: unable to close file.");
X
X    view_window(file_string, filename);
X    XtFree(file_string);
X
X
X}
X
X
Xchar *dumporama(file)
Xchar* file;
X{
X    struct stat statbuf;
X    char ch,str[17];
X    char line[80];
X    char hex[4];
X    char* massivebuf;
X    char* massiveptr;
X    int i,count=0,offset=(-16);
X    int fd;
X    int wanted;
X
X    str[16]='\0';
X    if ((fd=open(file,O_RDONLY,0))==-1) {
X        fprintf(stderr,"cannot open %s\n",file);
X        return(NULL);
X    }
X    if (fstat(fd,&statbuf))
X    {
X        fprintf(stderr,"cannot stat file\n");
X        return(NULL);
X    }
X    wanted=(statbuf.st_size)*75+1;
X    massiveptr=massivebuf=(char*)malloc(wanted);
X    if (!massivebuf)
X    {
X        fprintf(stderr,"cannot malloc %d bytes\n",wanted);
X        return(NULL);
X    }
X    sprintf(line,"%6X: ",offset+=16);
X    while (read(fd,&ch,1)>0)
X    {
X        ch=(int)ch&0xff;
X        str[count++]=((ch>31 && ch<127)?ch:'.');
X        sprintf(hex,"%2.2X ",(int) ch&0xff);
X        strcat(line,hex);
X        if (count==16)
X        {
X            count=0;
X            strcat(line,": ");
X            strcat(line,str);
X            sprintf(massiveptr,"%s\n",line);
X            massiveptr+=strlen(line)+1;
X            sprintf(line,"%6X: ",offset+=16);
X        }
X    }
X    sprintf(massiveptr,"%s",line);
X    massiveptr+=strlen(line);
X    close(fd);
X    if (count>0) for (i=count;i<16;i++)
X    {
X        sprintf(massiveptr,(i!=15)?"-- ":"-- : ");
X        massiveptr+=(i!=15)?3:5;
X    }
X    i=count;
X    while (count>0)
X    {
X        sprintf(massiveptr,count==0?"%c\n":"%c",str[i-count--]);
X        massiveptr+=count==0?2:1;
X    }
X    return(massivebuf);
X}
X
X
X
Xvoid hex_popup(filename)
Xchar *filename;
X{
Xchar *string;
X
X    string = dumporama(filename);
X    if (string != NULL)
X        {
X        view_window(string, filename);
X        free(string);
X        }
X}
X
XexecuteCB(w, c1, calldata)
XWidget w;
Xcaddr_t c1;
Xcaddr_t calldata;
X{
Xchar *param;
XXmSelectionBoxCallbackStruct *call;
Xchar *line;
Xchar *command = (char*)c1;
X
X    call = (XmSelectionBoxCallbackStruct *)calldata;
X    if (call->reason != XmCR_CANCEL)
X        {
X        XmStringGetLtoR(call->value, XmSTRING_DEFAULT_CHARSET, &param);
X        line = XtMalloc(strlen(command) + strlen(param) + 1);
X        sprintf(line, command, param);
X        sys(line);
X        XtFree(line);
X        }
X}
X
Xvoid execute(command)
Xchar *command;
X{
Xint len = strlen(command);
Xchar *newcmd = malloc(len+1);
Xchar *promptstring = malloc(len+1);
Xchar *titlestring = malloc(len+1);
Xint newptr = 0;
Xint callbackused;
Xint tit = 0;
Xint pit = 0;
Xint n;
XBoolean popupneeded = FALSE;
X
X    for (n=0; n< len; n++)
X        {
X        if (command[n] == '^')
X            {
X            popupneeded = TRUE;
X            while (command[++n] != '@')
X                titlestring[tit++] = command[n];
X            titlestring[tit] = '\0';
X            while (command[++n] != '^')
X                promptstring[pit++] = command[n];
X            promptstring[pit] = '\0';
X            n++;
X            newcmd[newptr++] = '%';
X            newcmd[newptr++] = 's';
X            }
X         newcmd[newptr++] = command[n];
X         }
X     newcmd[newptr] =  '\0';
X
X     if (popupneeded)
X         string_popup(titlestring, promptstring, "", executeCB, newcmd);
X     else
X         sys(command);
X}
X
Xvoid renameCB(w, c1, calldata)
XWidget w;
Xcaddr_t c1;
Xcaddr_t calldata;
X{
Xchar *newname;
XXmSelectionBoxCallbackStruct *call;
Xchar newpath[255];
Xstruct Entry *e;
X
X    e=(struct Entry *)c1;
X
X    call = (XmSelectionBoxCallbackStruct *)calldata;
X
X    if (call->reason != XmCR_CANCEL)
X        {
X        XmStringGetLtoR(call->value, XmSTRING_DEFAULT_CHARSET, &newname);
X        sprintf(newpath, "%s/%s", e->path, newname);
X        if (rename(e->fullname, newpath) !=0)
X            fprintf(stderr, "Error: rename %s %s failed.\n", e->fullname, newpath); 
X        }
X
X    rename_popups--;
X    if (rename_popups == 0) /** reread the dir after all the popups have gone **/
X        {
X        read_left();
X        read_right();
X        } 
X
X}
X
Xint foreachleft(func)
Xint (*func)();
X{
Xint *sellist;
Xint numsel, n;
X
X    if (XmListGetSelectedPos(leftlist, &sellist, &numsel) )
X        for (n = 0; n < numsel; n++)
X            (*func)(leftptrs[sellist[n]-1]);
X    else
X        numsel = 0;
X    return(numsel);
X}
X
Xint foreachright(func)
Xint (*func)();
X{
Xint *sellist;
Xint numsel, n;
X
X    if (XmListGetSelectedPos(rightlist, &sellist, &numsel) )
X        for (n = 0; n < numsel; n++)
X            (*func)(rightptrs[sellist[n]-1]);
X    else
X        numsel = 0;
X    return(numsel);
X
X}
X
Xint foreachselected(func)
Xint (*func)();
X{
X    return(foreachleft(func) + foreachright(func));
X}
X
X
Xint rename_one_file(ent)
Xstruct Entry *ent;
X{
Xchar *tstr;
Xstatic char text[]="Enter new name for : ";
X
X    printf("rename %s\n", ent->name);
X    tstr = XtMalloc(strlen(text) + strlen(ent->fullname) +2);
X    sprintf(tstr, "%s%s", text, ent->fullname );
X    string_popup("Rename", tstr, ent->name, (XtCallbackProc)renameCB, ent);
X    rename_popups++;
X    XtFree(tstr);
X}
X
X
Xvoid ren(w, c1, c2)
X/** rename the selected files **/
XWidget w;
Xcaddr_t c1, c2;
X{
X    rename_popups = 0;
X    foreachselected(rename_one_file);
X}
X
X
Xvoid view_one_file(ptr)
Xstruct Entry *ptr;
X{
X     text_popup(ptr->fullname);
X}
X
X
Xvoid view(w, c1, c2)
X/** view the selected files **/
XWidget w;
Xcaddr_t c1;
Xcaddr_t c2;
X{
X    foreachselected(view_one_file);
X}
X
Xvoid hex_view_one_file(ptr)
Xstruct Entry *ptr;
X{
X     hex_popup(ptr->fullname);
X}
X
Xvoid hex_view(w, c1, c2)
X/** view the selected files **/
XWidget w;
Xcaddr_t c1;
Xcaddr_t c2;
X{
X    foreachselected(hex_view_one_file);
X}
X
X
Xvoid do_each_one(ptr)
Xstruct Entry *ptr;
X{
Xchar line[255];
X
X    sprintf(line, command_string, ptr->fullname);
X    execute(line);
X}
X
X
Xvoid do_each(command, rereaddir)
X/** execute the command for each file that is selected **/
Xchar *command;
XBoolean rereaddir;
X{
Xint *sellist;   
Xint numsel, n;
Xchar line[255], path[255];
X
X    command_string = command;
X    readaftercommand = rereaddir;
X    foreachselected(do_each_one);
X}
X
Xvoid do_sourcedest(command, rereaddir)
Xchar *command;
XBoolean rereaddir;
X{
Xchar *string;
Xint *sellist;   
Xint numsel, n, len;
Xchar *tptr, *fname;
Xchar *line;
X
X    string = NULL;
X    chdir(leftcd);
X    readaftercommand = rereaddir;
X
X    if (XmListGetSelectedPos(leftlist, &sellist, &numsel) )
X    {
X    for (n = 0; n < numsel; n++)
X        {
X        fname = leftptrs[sellist[n]-1]->name;
X        len = strlen(fname);
X        if (strcmp(fname, "..") && strcmp(fname, "."))
X            {
X            if (string == NULL)
X                {
X                string = XtMalloc(len+2);
X                sprintf(string, "%s ", fname);
X                }
X            else
X                {
X                tptr = XtMalloc(strlen(string)+len+2);
X                sprintf(tptr, "%s ", string);
X                strcat(tptr, fname);
X                XtFree(string);
X                string = tptr;
X                }
X            }
X        }
X    printf("source dest = \"%s\"\n", string);
X    line = XtMalloc(strlen(string)+strlen(command)+strlen(rightcd));
X    sprintf(line,command, string, rightcd);
X    execute(line);
X    XtFree(line);
X    XtFree(string);
X
X/**    if (rereaddir)
X        {
X        newleftdir();
X        newrightdir();
X        }
X**/
X    display_info(LEFT);
X    display_info(RIGHT);
X
X    }
X
X
X}
X
Xvoid assemble_str(ptr)
Xstruct Entry *ptr;
X{
Xchar *nstr;
Xchar *t;
X
X    if (astring == NULL)
X        astring = strcpy(XtMalloc(strlen(ptr->fullname)+1),ptr->fullname); 
X
X    else
X
X        {
X        nstr = XtMalloc(strlen(ptr->fullname) + 2);
X        sprintf(nstr, " %s", ptr->fullname);
X        t = XtMalloc(strlen(nstr) + strlen(astring) + 1);
X        strcpy(t, astring);
X        strcat(t, nstr);
X        XtFree(astring);
X        astring = t;
X        XtFree(nstr);
X        }
X}
X
X        
X
Xvoid do_allpath(command, rereaddir)
X/** execute a single command with each file that is selected **/
Xchar *command;
XBoolean rereaddir;
X{
Xchar *s;
X
X    if (astring != NULL)
X        {
X        XtFree(astring);
X        astring = NULL;
X        }
X    readaftercommand = rereaddir;
X    if (foreachselected(assemble_str))
X        {
X        s = XtMalloc(strlen(command) + strlen(astring) + 2);
X        sprintf(s, command, astring);
X        execute(s);
X        XtFree(s);
X        }
X}
X
X
Xvoid do_all(command, rereaddir)
X/** execute a single command with each file that is selected **/
Xchar *command;
XBoolean rereaddir;
X{
X
Xint *sellist;   
Xint numsel;
Xchar *line;
Xint len, n;
Xchar *string, *fname;
Xchar *tptr, path[255];
Xchar fullname[255];
X
X    string = NULL;
X    chdir(leftcd);
X
X    readaftercommand = rereaddir;
X
X    if (XmListGetSelectedPos(leftlist, &sellist, &numsel) )
X    {
X    for (n = 0; n < numsel; n++)
X        {
X        fname = leftptrs[sellist[n]-1]->name;
X        sprintf(fullname, "%s/%s", path, fname);
X        len = strlen(fname);
X        if (string == NULL)
X            {
X            string = XtMalloc(len);
X            sprintf(string, "%s", fname);
X            }
X        else
X            {
X            tptr = XtMalloc(strlen(string)+len+2);
X            sprintf(tptr, "%s ", string);
X            strcat(tptr, fname);
X            XtFree(string);
X            string = tptr;
X            }
X        }
X    }
X
X    
X    if (XmListGetSelectedPos(rightlist, &sellist, &numsel) )
X    {
X    if (strcmp(leftcd, rightcd))
X        {
X        if (string!=NULL)	/** execute the command if there is one **/
X            {
X            line = XtMalloc(strlen(string) + strlen(command) + 2);
X            sprintf(line, command, string);
X            execute(line);
X            }
X        chdir(rightcd);
X        *path = '\0';
X        XtFree(string);
X        string = NULL;
X        }
X
X
X    strcpy(path, rightcd);
X
X    for (n = 0; n < numsel; n++)
X        {
X        fname = rightptrs[sellist[n]-1]->name;
X        if (!(*path!='\0'))
X            sprintf(fullname, "%s/%s", path, fname);
X        else
X            sprintf(fullname, "%s", fname);
X
X        len = strlen(fullname);
X        if (string == NULL)
X            {
X            string = XtMalloc(len+2);
X            sprintf(string, " %s", fullname);	/** this space should not be in the string! */
X            }
X        else
X            {
X            tptr = XtMalloc(strlen(string)+len+2);
X            sprintf(tptr, "%s ", string);
X            strcat(tptr, fullname);
X            XtFree(string);
X            string = tptr;
X            }
X        }
X    }
X
X    if (string == NULL)
X        return;
X
X    line = XtMalloc(strlen(string) + strlen(command) + 2);
X    sprintf(line, command, string);
X    execute(line);
X    XtFree(line);
X
X    XtFree(string);
X
X}
X
Xvoid prog_button(w, c1, c2)
X/** a user defined button has been pressed **/
XWidget w;
Xcaddr_t c1;
Xcaddr_t c2;
X{
Xint b, context;
Xchar *str;
XBoolean reread;
X
X    b = (int)c1;
X    context = buttonlist[b]->context;
X    str = buttonlist[b]->command;
X    reread = buttonlist[b]->reread;
X    
X    switch (context)
X        {
X        case BCOMMAND: 	readaftercommand = reread; execute(str); break;
X        case BEACH:	do_each(str, reread); break;
X        case BALL: 	do_all(str, reread); break;
X        case BALLPATH: 	do_allpath(str, reread); break;
X        case BSOURCEDEST: do_sourcedest(str, reread); break;
X        }
X}
X
Xvoid do_magic_file(m, name)
Xint m;
Xchar *name;
X{
Xchar command[255];
X
X    if (*magiclist[m]->mstring == '*')
X        {
X        if (!strcmp(magiclist[m]->mstring, "*view") )
X            text_popup(name);
X        if (!strcmp(magiclist[m]->mstring, "*hex") )
X            hex_popup(name);
X        }
X    else
X        {
X        readaftercommand = magiclist[m]->mreread;
X        sprintf(command, magiclist[m]->mstring, name);
X        execute(command);
X        }
X}
X 
Xvoid selection(w, side, c2)
X/** a list item was selected by a single click **/
XWidget w;
Xcaddr_t side;
Xcaddr_t c2;
X{
Xint s;
X    s = (int)side;
X    display_info(s);
X    if (side ==LEFT)
X        chdir(leftcd);
X    else
X        chdir(rightcd);
X}
X       
X
Xvoid dc_selection(w, side, c2)
XWidget w;
Xcaddr_t side;
Xcaddr_t c2;
X{
X/** a list item was selected by a double click **/
Xint pos;
XXmListCallbackStruct *cb =  (XmListCallbackStruct *)c2;
Xchar *fname, *path, *fullname;
Xint n, fmode;
XBoolean fdir;
X
X    pos = (cb->item_position) - 1;
X
X    if ((int)side == LEFT)
X        {
X        fname = leftptrs[pos]->name;
X        fdir = leftptrs[pos]->dir;
X        fmode = leftptrs[pos]->mode;
X        fullname = leftptrs[pos]->fullname;
X        path = leftcd;
X        }
X    else
X        {
X        fname = rightptrs[pos]->name;
X        fdir = rightptrs[pos]->dir;
X        fmode = rightptrs[pos]->mode;
X        fullname = rightptrs[pos]->fullname;
X        path = rightcd;
X        }
X
X    /** if the file is a dir then attempt to change **/
X    if (fdir)
X        {
X        if (chdir(fullname) != 0)
X            displayerror("can't change dir!\n", (int)side );
X        else
X            {
X            if ((int)side == RIGHT)
X                do_right();
X            else
X                do_left();
X            }
X        }
X    else
X    {
X    for (n=0; n<num_magic; n++)
X        {
X        if ((magiclist[n]->mtype == MFILE) && (!strcmp(fname, magiclist[n]->mname)) )
X            do_magic_file(n, fullname);    
X        }
X
X    for (n=0; n<num_magic; n++)
X        {
X        char *cf;
X        cf = fname + strlen(fname)-strlen(magiclist[n]->mname);
X
X        if ((magiclist[n]->mtype == MSUFFIX) && (!strcmp(cf, magiclist[n]->mname)) )
X            do_magic_file(n, fullname);    
X        }
X
X    if (fmode & S_IXUSR) /**execute it if it has execute permission **/
X        {
X        char *line;
X
X            line = XtMalloc(strlen(fullname)+3);
X            sprintf(line, "%s &", fullname);
X            execute(line);
X            XtFree(line);
X        }
X
X    }
X}
X
Xvoid get_magic()
X{
XFILE *mfile;    
Xchar mtype[255], mname[255], mreread[255], mstring[255];
Xint mline;
Xchar *m;
Xchar magic_path[255];
X
X
X    sprintf(magic_path, "%s/%s", xbrowserpath, MAGIC_FILE);
X
X    num_magic = 0;
X    mline = 0;
X    if (!(mfile = fopen(magic_path, "r")))
X        {
X        fprintf(stderr, "can't open magic file %s.\n", magic_path);
X        return;   
X        }
X
X    while (1)
X        {
X        if (fscanf(mfile, "%s%s%s %[ ]" , mtype, mname, mreread) == -1)
X            break;
X        if (fgets(mstring, 255, mfile) == NULL)
X            {
X            fprintf(stderr, "error in magic file line:%d\n",mline);
X            break;
X            }
X        else
X            mstring[strlen(mstring)-1] = '\0';  /** clear return chr **/
X
X        if (mtype[0] != '#') 
X            {
X            if (debug)
X                fprintf(stdout, "mclass = %s \t mstring = %s \t\t mcommand = %s\n",mtype, mname, mstring);
X            magiclist[num_magic] = (struct Magic *)malloc(sizeof(struct Magic));
X            if (!strcmp("file", mtype))
X                magiclist[num_magic]->mtype = MFILE; 
X            else
X            if (!strcmp("suffix", mtype))
X                magiclist[num_magic]->mtype = MSUFFIX; 
X            else
X                fprintf(stderr, "unknown magic type line:%d\n", mline);
X            
X            magiclist[num_magic]->mname = STRING(mname);
X            magiclist[num_magic]->mstring = STRING(mstring);
X            if (*mreread == 'y' || *mreread == 'Y')
X                magiclist[num_magic]->mreread = TRUE;
X            else
X            if (*mreread == 'n' || *mreread == 'N')
X                magiclist[num_magic]->mreread = FALSE;
X            else
X                fprintf(stderr, "error in magic file (rereaddir) line:%d\n",mline);
X
X            num_magic++;
X            }
X
X        mline++;
X        }
X    fclose(mfile);
X    if (debug)
X        fprintf(stdout, "\n\nMagic file read, %d lines, %d magic classes\n\n\n", mline+1, num_magic);
X}
X
X
Xvoid get_buttons(parent)
XWidget parent;
X{
XFILE *mfile;    
Xchar mcontext[255], mname[255], mreread[255], mstring[255], button_label[255];
Xint mline;
XWidget w;
XBoolean make_button;
XArg al[10];
Xint ac;
Xchar button_path[255];
X
X    num_buttons = 0;
X    mline = 0;
X    sprintf(button_path, "%s/%s", xbrowserpath, BUTTONS_FILE);
X
X    if (!(mfile = fopen(button_path, "r")))
X        {
X        fprintf(stderr, "can't open buttons file %s.\n", button_path);
X        return;   
X        }
X
X    while (1)
X        {
X        if (fscanf(mfile, "%s %s%s %[ ]" , mname, mcontext, mreread) == -1)
X            break;
X        if (fgets(mstring, 255, mfile) == NULL)
X            {
X            fprintf(stderr, "error in button file line:%d\n",mline);
X            break;
X            }
X        else
X            mstring[strlen(mstring)-1] = '\0';  /** clear return chr **/
X
X        if (mname[0] != '#') 
X            {
X            make_button = TRUE;
X            if (debug)
X                fprintf(stdout, "bname = %s \t bcontext = %s \t bstring = %s\n",mname, mcontext, mstring);
X            buttonlist[num_buttons] = (struct Button *)malloc(sizeof(struct Button));
X            if (!strcmp("all", mcontext))
X                buttonlist[num_buttons]->context = BALL; 
X            else
X            if (!strcmp("allpath", mcontext))
X                buttonlist[num_buttons]->context = BALLPATH; 
X            else
X            if (!strcmp("each", mcontext))
X                buttonlist[num_buttons]->context = BEACH; 
X            else
X            if (!strcmp("command", mcontext))
X                buttonlist[num_buttons]->context = BCOMMAND;
X            else
X            if (!strcmp("sourcedest", mcontext))
X                buttonlist[num_buttons]->context = BSOURCEDEST;
X            else
X                {
X                fprintf(stderr, "unknown button context line:%d\n", mline);
X                make_button = FALSE;
X                }
X
X            if (*mreread == 'y' || *mreread == 'Y')
X                buttonlist[num_buttons]->reread = TRUE;
X            else
X            if (*mreread == 'n' || *mreread == 'N')
X                buttonlist[num_buttons]->reread = FALSE;
X            else
X                {
X                fprintf(stderr, "error in buttons file (rereaddir) line:%d\n",mline);
X                make_button = FALSE;
X                }
X
X            if (make_button)
X                {
X                buttonlist[num_buttons]->command = STRING(mstring);
X                ac = 0;
X                XtSetArg(al[ac], XmNlabelString, XmStringCreate(mname, XmSTRING_DEFAULT_CHARSET) ); ac++;
X                w = XtCreateManagedWidget("button", xmPushButtonWidgetClass, parent, al, ac);
X                XtAddCallback(w, XmNactivateCallback, prog_button, (XtPointer)num_buttons);
X                num_buttons++;
X                }
X            }
X
X        mline++;
X        }
X    fclose(mfile);
X
X    if (debug)
X        fprintf(stdout, "\n\nButton file read, %d lines, %d buttons\n\n\n", mline+1, num_buttons);
X}
X
Xvoid quit(w, c1, c2)
XWidget w;
Xcaddr_t c1;
Xcaddr_t c2;
X{
X    fprintf(stdout, "Bye!\n");
X    exit(0);
X}
X
Xvoid select_all(w, side, c2)
XWidget w;
Xcaddr_t side;
Xcaddr_t c2;
X{
XWidget list;
Xint n, maxi;
X
X    if ( (int)side == LEFT)
X        {
X        maxi = leftlistnum;
X        list = leftlist;
X        }
X    else
X        {
X        list = rightlist;
X        maxi = rightlistnum;
X        }
X    XmListDeselectAllItems(list);
X    for (n = 1; n <=maxi; n++)
X        XmListSelectPos(list, n, FALSE);
X    display_info((int)side);
X}
X
Xvoid select_files(w, side, c2)
XWidget w;
Xcaddr_t side;
Xcaddr_t c2;
X{
XWidget list;
Xint n, maxi;
Xstruct Entry *(*ptrs);
X
X    if ( (int)side == LEFT)
X        {
X        maxi = leftlistnum;
X        list = leftlist;
X        ptrs = leftptrs;
X        }
X    else
X        {
X        list = rightlist;
X        maxi = rightlistnum;
X        ptrs = rightptrs;
X        }
X    XmListDeselectAllItems(list);
X    for (n = 1; n <=maxi; n++)
X        if (!ptrs[n-1]->dir)
X            XmListSelectPos(list, n, FALSE);
X    display_info((int)side);
X}
X
Xvoid invert_all(w, side, c2)
XWidget w;
Xcaddr_t side;
Xcaddr_t c2;
X{
XWidget list;
Xint n, maxi;
X
X    if ( (int)side == LEFT)
X        {
X        maxi = leftlistnum;
X        list = leftlist;
X        }
X    else
X        {
X        list = rightlist;
X        maxi = rightlistnum;
X        }
X
X    for (n = 1; n <=maxi; n++)
X        XmListSelectPos(list, n, FALSE);
X    display_info((int)side);
X}
X
Xvoid clear_all(w, side, c2)
XWidget w;
Xcaddr_t side;
Xcaddr_t c2;
X{
XWidget list;
X
X    if ( (int)side == LEFT)
X        list = leftlist;
X    else
X        list = rightlist;
X    XmListDeselectAllItems(list);
X    display_info((int)side);
X}
X
X
Xvoid newdir(w, side, c2)
XWidget w;
Xcaddr_t side;
Xcaddr_t c2;
X{
Xint s;
X    s = (int)side;
X    if (side == LEFT)
X        newleftdir();
X    else 
X        newrightdir();
X
X}
X
X
XWidget make_side(side, title, parentform, dirtext, list, label)
Xint side;
Xchar *title;
XWidget parentform;
XWidget *dirtext;
XWidget *list;
XWidget *label;
X{
XWidget sidef, sideform, sidelabel, sidedirtext, sidelist, siderc, w;
XArg al[10];
Xint ac;
X
X    ac = 0;
X    XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
X    sidef = XtCreateManagedWidget("sideform", xmFormWidgetClass, parentform, al, ac);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
X    sideform = XtCreateManagedWidget("sideform", xmFormWidgetClass, sidef, al, ac);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
X    sidelabel = XtCreateManagedWidget(title, xmLabelWidgetClass, sideform, al, ac);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
X    XtSetArg(al[ac], XmNtopWidget, sidelabel); ac++;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
X    sidedirtext = XtCreateManagedWidget("sidedir", xmTextWidgetClass, sideform, al, ac);
X    XtAddCallback(sidedirtext, XmNactivateCallback, (XtCallbackProc)newdir, (XtPointer)side);
X
X
X    ac = 0;
X    XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
X    XtSetArg(al[ac], XmNtopWidget, sidedirtext); ac++;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNselectionPolicy, XmMULTIPLE_SELECT); ac++;
X
X    sidelist = XmCreateScrolledList(sideform, "sidelist", al, ac);
X    XtAddCallback(sidelist, XmNmultipleSelectionCallback, selection, (XtPointer)side);
X    XtAddCallback(sidelist, XmNdefaultActionCallback, dc_selection, (XtPointer)side);
X    XtManageChild(sidelist);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNentryAlignment, XmALIGNMENT_CENTER); ac++;
X    XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
X    XtSetArg(al[ac], XmNpacking, XmPACK_COLUMN); ac++;
X    siderc = XtCreateManagedWidget("siderc", xmRowColumnWidgetClass, sidef, al, ac);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
X    XtSetArg(al[ac], XmNbottomWidget, siderc); ac++;
X    XtSetValues(sideform, al, ac);
X
X
X    ac = 0;
X    w = XtCreateManagedWidget("All", xmPushButtonWidgetClass, siderc, al, ac);
X    XtAddCallback(w, XmNactivateCallback, select_all, (XtPointer)side);
X    w = XtCreateManagedWidget("Clear", xmPushButtonWidgetClass, siderc, al, ac);
X    XtAddCallback(w, XmNactivateCallback, clear_all, (XtPointer)side);
X    w = XtCreateManagedWidget("Files", xmPushButtonWidgetClass, siderc, al, ac);
X    XtAddCallback(w, XmNactivateCallback, select_files, (XtPointer)side);
X    w = XtCreateManagedWidget("Invert", xmPushButtonWidgetClass, siderc, al, ac);
X    XtAddCallback(w, XmNactivateCallback, invert_all, (XtPointer)side);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNmarginLeft, 10); ac++;
X    XtSetArg(al[ac], XmNmarginHeight, 4); ac++;
X    XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
X    sidelabel = XtCreateManagedWidget("sidelabel", xmLabelWidgetClass, sidef, al, ac);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
X    XtSetArg(al[ac], XmNbottomWidget, sidelabel); ac++;
X    XtSetValues(siderc, al, ac);
X
X    *dirtext = sidedirtext;
X    *list = sidelist;
X    *label = sidelabel;
X
X    return(sidef);
X}
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
XWidget topform, topformframe, w, mainform, mainlabel;
XWidget leftform, rightform, buttonrc, buttonrcframe;
XXtAppContext app_con;
X
X
XArg al[10];
Xint ac;
X
X    toplevel = XtAppInitialize(&app_con, "Xbrowser", NULL, 0,
X			       &argc, argv, fallback_resources, NULL, 0);
X
X    if ( (argc == 2) && (!strcmp(argv[1], "-debug") ) )
X        debug = TRUE;
X    else
X        debug = FALSE;
X
X    if (debug)
X        printf("xbrowser path = %s\n", getenv("XBROWSER") );
X    xbrowserpath = getenv("XBROWSER");
X    if (xbrowserpath == NULL)
X        xbrowserpath = STRING(".");
X    get_magic();
X
X    ac = 0;
X    mainform = XtCreateManagedWidget("mainform", xmFormWidgetClass, toplevel, al, ac);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNmarginHeight, 5); ac++;
X    XtSetArg(al[ac], XmNlabelString,
X        XmStringCreate(VERSIONSTRING, XmSTRING_DEFAULT_CHARSET)); ac++;
X    mainlabel = XtCreateManagedWidget("title", xmLabelWidgetClass, mainform, al, ac);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
X    XtSetArg(al[ac], XmNtopWidget, mainlabel); ac++;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNshadowType, XmSHADOW_OUT); ac++;
X    topformframe = XtCreateManagedWidget("topformframe", xmFrameWidgetClass, mainform, al, ac);
X
X    ac = 0;
X    topform = XtCreateManagedWidget("topform", xmFormWidgetClass, topformframe, al, ac);
X
X    leftform = make_side(LEFT, "Source:", topform, &leftdirtext, &leftlist, &leftinfolabel);
X    rightform = make_side(RIGHT, "Destination:", topform, &rightdirtext, &rightlist, &rightinfolabel);
X
X    /** button strip frame**/
X    ac = 0;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
X    XtSetArg(al[ac], XmNshadowType, XmSHADOW_OUT); ac++;
X    buttonrcframe = XtCreateManagedWidget("buttonstripframe", xmFrameWidgetClass, topform, al, ac);
X
X    /** button strip **/
X    ac = 0;
X    XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
X    XtSetArg(al[ac], XmNentryAlignment, XmALIGNMENT_CENTER); ac++;
X    buttonrc = XtCreateManagedWidget("buttonstrip", xmRowColumnWidgetClass, buttonrcframe, al, ac);
X
X    ac = 0;
X    w = XtCreateManagedWidget("QUIT", xmPushButtonWidgetClass, buttonrc, al, ac);
X    XtAddCallback(w, XmNactivateCallback, quit, NULL);
X    w = XtCreateManagedWidget("VIEW", xmPushButtonWidgetClass, buttonrc, al, ac);
X    XtAddCallback(w, XmNactivateCallback, view, NULL);
X    w = XtCreateManagedWidget("HEX-VIEW", xmPushButtonWidgetClass, buttonrc, al, ac);
X    XtAddCallback(w, XmNactivateCallback, hex_view, NULL);
X    w = XtCreateManagedWidget("RENAME", xmPushButtonWidgetClass, buttonrc, al, ac);
X    XtAddCallback(w, XmNactivateCallback, ren, NULL);
X
X    get_buttons(buttonrc);
X
X    /** attach to button strip **/
X    ac = 0;
X    XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
X    XtSetArg(al[ac], XmNbottomWidget, buttonrcframe); ac++;
X    XtSetValues(rightform, al, ac);
X    XtSetValues(leftform, al, ac);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNrightAttachment, XmATTACH_POSITION); ac++;
X    XtSetArg(al[ac], XmNrightPosition, 50); ac++;
X    XtSetValues(leftform, al, ac);
X
X    ac = 0;
X    XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
X    XtSetArg(al[ac], XmNleftWidget, leftform); ac++;
X    XtSetArg(al[ac], XmNleftOffset, 10); ac++;
X    XtSetValues(rightform, al, ac);
X
X    init();
X
X    XtRealizeWidget(toplevel);
X    XtAppMainLoop(app_con);
X}
SHAR_EOF
fi # end of overwriting check
if test -f 'xbrowser.magic'
then
	echo shar: will not over-write existing file "'xbrowser.magic'"
else
sed 's/^X//' << \SHAR_EOF > 'xbrowser.magic'
X#class	match-string	rereaddir?	command
Xfile 	.Xdefaults		n	csh -c "xedit %s" &
Xfile	xbrowser.magic		n	csh -c "xedit %s" &
Xfile	xbrowser.buttons	n	csh -c "xedit %s" &
Xfile	Makefile		y	make
Xfile	README			n	*view
Xfile	readme			n	*view
Xfile	ReadMe			n	*view
X
Xsuffix	.gif			n	xv %s &
Xsuffix	rc			n	xedit %s &
Xsuffix	.lzh			n	lharc -l %s &
Xsuffix	.c			n	*view
Xsuffix	.au			n	/usr/demo/SOUND/play -v 20 %s &
Xsuffix  .xbm			n	xv %s &
Xsuffix	.tar			n	tar tvf %s | xmless &
Xsuffix	.man			n	nroff -man %s | xmless &
SHAR_EOF
chmod +x 'xbrowser.magic'
fi # end of overwriting check
#	End of shell archive
exit 0