[comp.sources.x] v04i014: xdir -- Directory Browser, Part01/02

argv@island.uu.net (Dan Heller) (06/04/89)

Submitted-by: Erik M. van der Poel <erik@sra.co.jp>
Posting-number: Volume 4, Issue 14
Archive-name: xdir/part01

[ I didn't have any problem compiling and running on my sun3/60.  It appears
  to have all the necessary sys-v dependencies.  This is a nice looking tool.
  The following is from Erik	--argv ]

This is a file name dialog/directory browser package that is handy when
an application wants the user to provide a file name. The path can be
typed at the keyboard or selected by browsing in directory listings with
the mouse.

The following features are supported:

    * file name completion

    * fast directory reading

    * linking with Xaw (Athena) and/or Xw (Hewlett-Packard) widgets

The file xdir.c is just a wrapper that demonstrates the package, and the
resulting executable can be run by typing xdir and then Return.
--
Erik M. van der Poel                  erik@sra.co.jp             (Japan)
SRA, 1-1-1 Hirakawa-cho, Chiyoda-ku   erik%sra.co.jp@uunet.uu.net  (USA)
Tokyo 102 Japan. TEL +81-3-234-2692   erik%sra.co.jp@mcvax.uucp (Europe)

-------------------------------------------------------------------------------


#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\End\Of\File\'



                  XsraSelFile File Selection Dialog Package



This directory contains the XsraSelFile file selection dialog package. This
package allows an application to obtain a filename from a user. The filename is
selected by typing in a text widget or by browsing with the mouse in directory
listings.

The following is a brief description of the available features.

* filename completion

    When the user types a filename in the Text widget, SelFile shows the
    possible completions in the directory listings. The user can hit the space
    bar to complete the filename.

* fast directory reading

    When a directory is opened, the entries are read and sorted. Then the stats
    of only the first screenful of entries are taken, and these entries are
    displayed. The stats of the other entries are taken upon demand (i.e. when
    the user wishes to see them by scrolling, etc.) or in the background. The
    Xt work procedure facility is used to do background work. The idea here is
    to give the user some feedback as soon as possible.

    "It's just an illu--sion" :-)

* Xaw and/or Xw widgets

    SelFile can be linked with Xaw (Athena) and/or Xw (Hewlett-Packard)
    widgets. However, it must be linked with the R3 or a later version of the
    Xt Intrinsics. See the Imakefile for details.

* automatic display update after directory modification

    Every now and then SelFile looks at the directories being displayed to see
    if they have been updated, and updates the display accordingly. Similarly,
    file modes are checked (but not as often).

* tilde (~) for home directories

    When the user types a tilde at the beginning of the Text widget, SelFile
    shows the home directories.

-------------------------------------------------------------------------------

This work is loosely based on (and the name comes from) an earlier X10 SelFile
by Michiharu `NinjaTerm' Ariza.

Admittedly, this X11 SelFile also looks a bit like the directory browser on the
NeXT machine.

-------------------------------------------------------------------------------

If you have any

    porting problems

    bug reports

    comments (particularly about ideas in the TODO file)

    or any other type of feedback

please send mail to

    erik@sra.co.jp
                                           OR
    erik%sra.co.jp@uunet.uu.net
                                           OR
    erik%sra.co.jp@mcvax.uucp
                                           OR
    try junet instead of co.jp
                                           OR
    Erik M. van der Poel
    Software Research Associates, Inc.
    1-1-1 Hirakawa-cho, Chiyoda-ku
    Tokyo 102 Japan. TEL +81-3-234-2692
\End\Of\File\
else
  echo "will not over write ./README"
fi
if `test ! -s ./SFinternal.h`
then
echo "writing ./SFinternal.h"
cat > ./SFinternal.h << '\End\Of\File\'
/* $Header: SFinternal.h,v 1.3 89/04/26 17:48:34 erik Exp $ */

/*
 * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  Software Research Associates
 * makes no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: Erik M. van der Poel
 *         Software Research Associates, Inc., Tokyo, Japan
 */

#include <X11/Intrinsic.h>

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
#include <Xw/Xw.h>
#include <Xw/TextEdit.h>
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
#include <X11/Text.h>
#include <X11/AsciiText.h>
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

#define SEL_FILE_CANCEL		-1
#define SEL_FILE_OK		0
#define SEL_FILE_NULL		1
#define SEL_FILE_TEXT		2

#define SF_DO_SCROLL		1
#define SF_DO_NOT_SCROLL	0

typedef struct {
	int	statDone;
	char	*real;
	char	*shown;
} SFEntry;

typedef struct {
	char	*dir;
	char	*path;
	SFEntry	*entries;
	int	nEntries;
	int	vOrigin;
	int	nChars;
	int	hOrigin;
	int	changed;
	int	beginSelection;
	int	endSelection;
	time_t	st_mtime;
} SFDir;

extern int SFstatus;

extern char SFcurrentPath[], SFstartDir[], SFcurrentDir[];

extern Widget
		selFile,
		selFileCancel,
		selFileField,
		selFileForm,
		selFileHScroll,
		selFileHScrolls[],
		selFileLists[],
		selFileOK,
		selFilePrompt,
		selFileVScrolls[];

extern Display *SFdisplay;

extern int SFcharWidth, SFcharHeight, SFcharAscent;

extern SFDir *SFdirs;

extern int SFdirEnd, SFdirPtr;

extern Pixel SFfore, SFback;

extern XSegment SFsegs[], SFcompletionSegs[];

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
extern XwTextPosition SFtextPos;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
extern XtTextPosition SFtextPos;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

extern void
	SFenterList(),
	SFleaveList(),
	SFmotionList(),
	SFbuttonPressList(),
	SFbuttonReleaseList();

extern
	SFvSliderMovedCallback(),
	SFvFloatSliderMovedCallback(),
	SFhSliderMovedCallback(),
	SFpathSliderMovedCallback(),
	SFvAreaSelectedCallback(),
	SFhAreaSelectedCallback(),
	SFpathAreaSelectedCallback();

extern int SFupperX, SFlowerY, SFupperY;

extern int SFtextX, SFtextYoffset;

extern int SFentryWidth, SFentryHeight;

extern int SFlineToTextH, SFlineToTextV;

extern int SFbesideText, SFaboveAndBelowText;

extern int SFcharsPerEntry;

extern int SFlistSize;

extern int SFcurrentInvert[];

extern int SFworkProcAdded;

extern Boolean SFworkProc();

extern XtAppContext SFapp;

extern int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
extern char SFtextBuffer[];
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

extern int SFbuttonPressed;

extern int SFcompareEntries();

extern SFdirModTimer();

extern XtIntervalId SFdirModTimerId;

extern int (*SFfunc)();
\End\Of\File\
else
  echo "will not over write ./SFinternal.h"
fi
if `test ! -s ./SelFile.c`
then
echo "writing ./SelFile.c"
cat > ./SelFile.c << '\End\Of\File\'
#ifndef lint
static char rcsid[] = "$Header: SelFile.c,v 1.7 89/05/30 14:49:17 erik Exp $";
#endif

/*
 * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  Software Research Associates
 * makes no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: Erik M. van der Poel
 *         Software Research Associates, Inc., Tokyo, Japan
 */

/*
 * Author's address:
 *
 *     erik@sra.co.jp
 *                                            OR
 *     erik%sra.co.jp@uunet.uu.net
 *                                            OR
 *     erik%sra.co.jp@mcvax.uucp
 *                                            OR
 *     try junet instead of co.jp
 *                                            OR
 *     Erik M. van der Poel
 *     Software Research Associates, Inc.
 *     1-1-1 Hirakawa-cho, Chiyoda-ku
 *     Tokyo 102 Japan. TEL +81-3-234-2692
 */

#include <stdio.h>
#include <sys/param.h>
#include <X11/cursorfont.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Composite.h>
#include <X11/Shell.h>

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
#include <Xw/Xw.h>
#include <Xw/Form.h>
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */
#include <X11/Form.h>
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)
#include <Xw/Xw.h>
#include <Xw/PButton.h>
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */
#include <X11/Command.h>
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
#include <Xw/Xw.h>
#include <Xw/ScrollBar.h>
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */
#include <X11/Scroll.h>
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT)
#include <Xw/Xw.h>
#include <Xw/SText.h>
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT) */
#include <X11/Label.h>
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT) */

#include "SFinternal.h"

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
#ifdef SEL_FILE_JAPANESE
#include <X11/XWStr.h>
#endif /* def SEL_FILE_JAPANESE */
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

#ifndef SYSV
extern char *getwd();
#endif /* ndef SYSV */

int SFstatus = SEL_FILE_NULL;

char
	SFstartDir[MAXPATHLEN],
	SFcurrentPath[MAXPATHLEN],
	SFcurrentDir[MAXPATHLEN];

Widget
	selFile,
	selFileCancel,
	selFileField,
	selFileForm,
	selFileHScroll,
	selFileHScrolls[3],
	selFileLists[3],
	selFileOK,
	selFilePrompt,
	selFileVScrolls[3];

Display *SFdisplay;

Pixel SFfore, SFback;

XSegment SFsegs[2], SFcompletionSegs[2];

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
XwTextPosition SFtextPos;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
XtTextPosition SFtextPos;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

int SFupperX, SFlowerY, SFupperY;

int SFtextX, SFtextYoffset;

int SFentryWidth, SFentryHeight;

int SFlineToTextH = 3;

int SFlineToTextV = 3;

int SFbesideText = 3;

int SFaboveAndBelowText = 2;

int SFcharsPerEntry = 15;

int SFlistSize = 10;

int SFworkProcAdded = 0;

XtAppContext SFapp;

int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
char SFtextBuffer[MAXPATHLEN];
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

XtIntervalId SFdirModTimerId;

int (*SFfunc)();

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
static char *oneLineTextEditTranslations = "\
	<Key>Return:	execute()\n\
	Ctrl<Key>M:	execute()\n\
";
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
static char *oneLineTextEditTranslations = "\
	<Key>Return:	redraw-display()\n\
	Ctrl<Key>M:	redraw-display()\n\
";
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

/* ARGSUSED */
static void
SFexposeList(w, n, event)
	Widget		w;
	int		n;
	XExposeEvent	*event;
{
	if ((event->type == NoExpose) || event->count) {
		return;
	}

	SFdrawList(n, SF_DO_NOT_SCROLL);
}

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
static void
returnCallback()
{
	SFstatus = SEL_FILE_OK;
}
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

/* ARGSUSED */
static void
SFmodVerifyCallback(w, client_data, event)
	Widget			w;
	caddr_t			client_data;
	XKeyPressedEvent	*event;
{

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
	SFstatus = SEL_FILE_TEXT;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
	char	buf[2];

	if (
		(XLookupString(event, buf, 2, NULL, NULL) == 1) &&
		((*buf) == '\r')
	) {
		SFstatus = SEL_FILE_OK;
	} else {
		SFstatus = SEL_FILE_TEXT;
	}
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

}

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
static XtCallbackRec SFmodVerify[] = {
	{ SFmodVerifyCallback, (caddr_t) NULL },
	{ NULL, (caddr_t) NULL },
};
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)
static
SFresetButton(w)
	Widget w;
{
	static Arg	arg[] = {
		{ XtNset, False }
	};

	XtSetValues(w, arg, 1);
}
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

/* ARGSUSED */
static void
SFokCallback(w)
	Widget	w;
{
	SFstatus = SEL_FILE_OK;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)
	SFresetButton(w);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

}

static XtCallbackRec SFokSelect[] = {
	{ SFokCallback, (caddr_t) NULL },
	{ NULL, (caddr_t) NULL },
};

/* ARGSUSED */
static void
SFcancelCallback(w)
	Widget	w;
{
	SFstatus = SEL_FILE_CANCEL;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)
	SFresetButton(w);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

}

static XtCallbackRec SFcancelSelect[] = {
	{ SFcancelCallback, (caddr_t) NULL },
	{ NULL, (caddr_t) NULL },
};

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
typedef struct {
	Dimension	height;
} SFfieldData, *sfFieldPtr;

static XtResource SFfieldResources[] = {
	{
		XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
		XtOffset(sfFieldPtr, height), XtRString, "1"
	},
};
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

static int
SFcreateWidgets(prompt, ok, cancel)
	u_char	*prompt;
	u_char	*ok;
	u_char	*cancel;
{
	int		i, n;
	int		listWidth, listHeight;
	int		listSpacing = 10;
	int		scrollThickness = 15;
	int		hScrollX, hScrollY;
	int		vScrollX, vScrollY;
	Cursor
			xtermCursor,

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
			sbDownArrowCursor,
			sbLeftArrowCursor,
			sbUpArrowCursor,
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

			sbRightArrowCursor,
			dotCursor;

#ifdef SEL_FILE_JAPANESE
	CStr		csl[2];
	u_char		cstr[256];
#endif /* def SEL_FILE_JAPANESE */

	Arg		arglist[20];

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
	SFfieldData	*data;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

	i = 0;
	XtSetArg(arglist[i], XtNallowShellResize, True);		i++;
	selFile = XtAppCreateShell("selFile", "SelFile",
		applicationShellWidgetClass, SFdisplay, arglist, i);

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
	selFileForm = XtCreateManagedWidget("selFileForm",
		XwformWidgetClass, selFile, (ArgList) NULL, 0);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */
	i = 0;
	XtSetArg(arglist[i], XtNdefaultDistance, 30);			i++;
	selFileForm = XtCreateManagedWidget("selFileForm",
		formWidgetClass, selFile, arglist, i);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

	i = 0;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT)

#ifdef SEL_FILE_JAPANESE

#ifdef SEL_FILE_SJIS
	(void) convSJIStoCS(prompt, cstr);
#else /* def SEL_FILE_SJIS */
	(void) convEUCtoCS(prompt, cstr);
#endif /* def SEL_FILE_SJIS */

	csl[0] = cstr;
	csl[1] = NULL;
	XtSetArg(arglist[i], XtNstrings, csl);				i++;
#else /* def SEL_FILE_JAPANESE */
	XtSetArg(arglist[i], XtNstring, prompt);			i++;
#endif /* def SEL_FILE_JAPANESE */

#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT) */
	XtSetArg(arglist[i], XtNlabel, prompt);				i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
	XtSetArg(arglist[i], XtNxOffset, 30);				i++;
	XtSetArg(arglist[i], XtNyOffset, 30);				i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

	XtSetArg(arglist[i], XtNborderWidth, 0);			i++;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT)
	selFilePrompt = XtCreateManagedWidget("selFilePrompt",
		XwstatictextWidgetClass, selFileForm, arglist, i);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT) */
	selFilePrompt = XtCreateManagedWidget("selFilePrompt",
		labelWidgetClass, selFileForm, arglist, i);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT) */

	i = 0;
	XtSetArg(arglist[i], XtNforeground, &SFfore);			i++;
	XtSetArg(arglist[i], XtNbackground, &SFback);			i++;
	XtGetValues(selFilePrompt, arglist, i);

	SFinitFont();

	SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth +
			SFbesideText;
	SFentryHeight = SFaboveAndBelowText + SFcharHeight +
			SFaboveAndBelowText;

	listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
			scrollThickness;
	listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
			SFlineToTextV + SFlistSize * SFentryHeight +
			SFlineToTextV + 1 + scrollThickness;

	SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;

	hScrollX = -1;
	hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
			SFlineToTextV + SFlistSize * SFentryHeight +
			SFlineToTextV;
	SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;

	vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
	vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
	SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
			SFlineToTextV;

	SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
	SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
			SFlineToTextV;
	SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
			SFlineToTextV + SFlistSize * SFentryHeight - 1;

	SFtextX = SFlineToTextH + SFbesideText;
	SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;

	SFsegs[0].x1 = 0;
	SFsegs[0].y1 = vScrollY;
	SFsegs[0].x2 = vScrollX - 1;
	SFsegs[0].y2 = vScrollY;
	SFsegs[1].x1 = vScrollX;
	SFsegs[1].y1 = 0;
	SFsegs[1].x2 = vScrollX;
	SFsegs[1].y2 = vScrollY - 1;

	SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
	SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
		SFlineToTextH + SFentryWidth - 1;

	i = 0;
	XtSetArg(arglist[i], XtNwidth, 3 * listWidth + 2 * listSpacing + 4);
									i++;
	XtSetArg(arglist[i], XtNborderColor, SFfore);			i++;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
	XtSetArg(arglist[i], XtNxRefWidget, selFilePrompt);		i++;
	XtSetArg(arglist[i], XtNyRefWidget, selFilePrompt);		i++;
	XtSetArg(arglist[i], XtNyAddHeight, True);			i++;
	XtSetArg(arglist[i], XtNyOffset, 10);				i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */
	XtSetArg(arglist[i], XtNfromVert, selFilePrompt);		i++;
	XtSetArg(arglist[i], XtNvertDistance, 10);			i++;
	XtSetArg(arglist[i], XtNresizable, True);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
	XtSetArg(arglist[i], XtNmodifyVerification, SFmodVerify);	i++;
	XtSetArg(arglist[i], XtNmotionVerification, SFmodVerify);	i++;
	selFileField = XtCreateManagedWidget("selFileField",
		XwtexteditWidgetClass, selFileForm, arglist, i);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
	XtSetArg(arglist[i], XtNstring, SFtextBuffer);			i++;
	XtSetArg(arglist[i], XtNlength, MAXPATHLEN);			i++;
	XtSetArg(arglist[i], XtNeditType, XttextEdit);			i++;
	XtSetArg(arglist[i], XtNtextOptions,	0		|
						editable	|
						resizeHeight	|
						wordBreak	|
						0);			i++;
	selFileField = XtCreateManagedWidget("selFileField",
		asciiStringWidgetClass, selFileForm, arglist, i);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

	XtOverrideTranslations(selFileField,
		XtParseTranslationTable(oneLineTextEditTranslations));

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)

	data = XtNew(SFfieldData);

	XtGetApplicationResources(
		selFileField,
		(caddr_t) data,
		SFfieldResources,
		XtNumber(SFfieldResources),
		(Arg *) NULL,
		0
	);

	if (data->height == 1) {

#ifdef SEL_FILE_JAPANESE
		XFontStruct	*font, *kanjiFont;
		XGCValues	values;
		XWSGC		gcSet;
#else /* def SEL_FILE_JAPANESE */
		XFontStruct	*font;
#endif /* def SEL_FILE_JAPANESE */

		int		ascent, descent;
		Dimension	top, bottom;

		i = 0;
		XtSetArg(arglist[i], XtNtopMargin, &top);		i++;
		XtSetArg(arglist[i], XtNbottomMargin, &bottom);		i++;

#ifdef SEL_FILE_JAPANESE
		XtSetArg(arglist[i], XtNfontG0, &font);			i++;
		XtSetArg(arglist[i], XtNfontG1, &kanjiFont);		i++;
#else /* def SEL_FILE_JAPANESE */
		XtSetArg(arglist[i], XtNfont, &font);			i++;
#endif /* def SEL_FILE_JAPANESE */

		XtGetValues(selFileField, arglist, i);

#ifdef SEL_FILE_JAPANESE
		gcSet = XtWSGetGCSet(selFileField, 0, &values, font, kanjiFont,
			NULL, NULL);
		XWSFontHeight(gcSet, NULL, 0, &ascent, &descent);
#else /* def SEL_FILE_JAPANESE */
		ascent = font->ascent;
		descent = font->descent;
#endif /* def SEL_FILE_JAPANESE */

		i = 0;
		XtSetArg(arglist[i], XtNheight,
			top + bottom + ascent + descent);		i++;
		XtSetValues(selFileField, arglist, i);
	}

#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

	i = 0;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
	XtSetArg(arglist[i], XtNslideOrientation, XwHORIZONTAL);	i++;
	XtSetArg(arglist[i], XtNsliderMin, 0);				i++;
	XtSetArg(arglist[i], XtNsliderExtent, 3);			i++;
	XtSetArg(arglist[i], XtNrepeatRate, 1);				i++;
	XtSetArg(arglist[i], XtNgranularity, 1);			i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */
	XtSetArg(arglist[i], XtNorientation, XtorientHorizontal);	i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

	XtSetArg(arglist[i], XtNwidth, SFpathScrollWidth);		i++;
	XtSetArg(arglist[i], XtNheight, scrollThickness);		i++;
	XtSetArg(arglist[i], XtNborderColor, SFfore);			i++;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
	XtSetArg(arglist[i], XtNxRefWidget, selFileField);		i++;
	XtSetArg(arglist[i], XtNyRefWidget, selFileField);		i++;
	XtSetArg(arglist[i], XtNyAddHeight, True);			i++;
	XtSetArg(arglist[i], XtNyOffset, 30);				i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */
	XtSetArg(arglist[i], XtNfromVert, selFileField);		i++;
	XtSetArg(arglist[i], XtNvertDistance, 30);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
	selFileHScroll = XtCreateManagedWidget("selFileHScroll",
		XwscrollbarWidgetClass, selFileForm, arglist, i);

	XtAddCallback(selFileHScroll, XtNsliderMoved,
		SFpathSliderMovedCallback, (caddr_t) NULL);
	XtAddCallback(selFileHScroll, XtNareaSelected,
		SFpathAreaSelectedCallback, (caddr_t) NULL);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */
	selFileHScroll = XtCreateManagedWidget("selFileHScroll",
		scrollbarWidgetClass, selFileForm, arglist, i);

	XtAddCallback(selFileHScroll, XtNjumpProc,
		SFpathSliderMovedCallback, (caddr_t) NULL);
	XtAddCallback(selFileHScroll, XtNscrollProc,
		SFpathAreaSelectedCallback, (caddr_t) NULL);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

	i = 0;
	XtSetArg(arglist[i], XtNwidth, listWidth);			i++;
	XtSetArg(arglist[i], XtNheight, listHeight);			i++;
	XtSetArg(arglist[i], XtNborderColor, SFfore);			i++;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
	XtSetArg(arglist[i], XtNxRefWidget, selFileHScroll);		i++;
	XtSetArg(arglist[i], XtNyRefWidget, selFileHScroll);		i++;
	XtSetArg(arglist[i], XtNyAddHeight, True);			i++;
	XtSetArg(arglist[i], XtNyOffset, 10);				i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */
	XtSetArg(arglist[i], XtNfromVert, selFileHScroll);		i++;
	XtSetArg(arglist[i], XtNvertDistance, 10);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

	selFileLists[0] = XtCreateManagedWidget("selFileList1",
		compositeWidgetClass, selFileForm, arglist, i);

	i = 0;
	XtSetArg(arglist[i], XtNwidth, listWidth);			i++;
	XtSetArg(arglist[i], XtNheight, listHeight);			i++;
	XtSetArg(arglist[i], XtNborderColor, SFfore);			i++;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
	XtSetArg(arglist[i], XtNxRefWidget, selFileLists[0]);		i++;
	XtSetArg(arglist[i], XtNyRefWidget, selFileLists[0]);		i++;
	XtSetArg(arglist[i], XtNxAddWidth, True);			i++;
	XtSetArg(arglist[i], XtNxOffset, listSpacing);			i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */
	XtSetArg(arglist[i], XtNfromHoriz, selFileLists[0]);		i++;
	XtSetArg(arglist[i], XtNfromVert, selFileHScroll);		i++;
	XtSetArg(arglist[i], XtNhorizDistance, listSpacing);		i++;
	XtSetArg(arglist[i], XtNvertDistance, 10);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

	selFileLists[1] = XtCreateManagedWidget("selFileList2",
		compositeWidgetClass, selFileForm, arglist, i);

	i = 0;
	XtSetArg(arglist[i], XtNwidth, listWidth);			i++;
	XtSetArg(arglist[i], XtNheight, listHeight);			i++;
	XtSetArg(arglist[i], XtNborderColor, SFfore);			i++;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
	XtSetArg(arglist[i], XtNxRefWidget, selFileLists[1]);		i++;
	XtSetArg(arglist[i], XtNyRefWidget, selFileLists[1]);		i++;
	XtSetArg(arglist[i], XtNxAddWidth, True);			i++;
	XtSetArg(arglist[i], XtNxOffset, listSpacing);			i++;
	XtSetArg(arglist[i], XtNxAttachRight, True);			i++;
	XtSetArg(arglist[i], XtNxAttachOffset, 30);			i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */
	XtSetArg(arglist[i], XtNfromHoriz, selFileLists[1]);		i++;
	XtSetArg(arglist[i], XtNfromVert, selFileHScroll);		i++;
	XtSetArg(arglist[i], XtNhorizDistance, listSpacing);		i++;
	XtSetArg(arglist[i], XtNvertDistance, 10);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

	selFileLists[2] = XtCreateManagedWidget("selFileList3",
		compositeWidgetClass, selFileForm, arglist, i);

	for (n = 0; n < 3; n++) {

		i = 0;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
		XtSetArg(arglist[i], XtNsliderMin, 0);			i++;
		XtSetArg(arglist[i], XtNrepeatRate, 1);			i++;
		XtSetArg(arglist[i], XtNgranularity, 1);		i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

		XtSetArg(arglist[i], XtNx, vScrollX);			i++;
		XtSetArg(arglist[i], XtNy, vScrollY);			i++;
		XtSetArg(arglist[i], XtNwidth, scrollThickness);	i++;
		XtSetArg(arglist[i], XtNheight, SFvScrollHeight);	i++;
		XtSetArg(arglist[i], XtNborderColor, SFfore);		i++;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
		selFileVScrolls[n] = XtCreateManagedWidget("selFileVScroll",
			XwscrollbarWidgetClass, selFileLists[n], arglist, i);

		XtAddCallback(selFileVScrolls[n], XtNsliderMoved,
			SFvSliderMovedCallback, (caddr_t) n);
		XtAddCallback(selFileVScrolls[n], XtNareaSelected,
			SFvAreaSelectedCallback, (caddr_t) n);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */
		selFileVScrolls[n] = XtCreateManagedWidget("selFileVScroll",
			scrollbarWidgetClass, selFileLists[n], arglist, i);

		XtAddCallback(selFileVScrolls[n], XtNjumpProc,
			SFvFloatSliderMovedCallback, (caddr_t) n);
		XtAddCallback(selFileVScrolls[n], XtNscrollProc,
			SFvAreaSelectedCallback, (caddr_t) n);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

		i = 0;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
		XtSetArg(arglist[i], XtNslideOrientation, XwHORIZONTAL);i++;
		XtSetArg(arglist[i], XtNsliderMin, 0);			i++;
		XtSetArg(arglist[i], XtNrepeatRate, 1);			i++;
		XtSetArg(arglist[i], XtNgranularity, 1);		i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */
		XtSetArg(arglist[i], XtNorientation, XtorientHorizontal);
									i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

		XtSetArg(arglist[i], XtNx, hScrollX);			i++;
		XtSetArg(arglist[i], XtNy, hScrollY);			i++;
		XtSetArg(arglist[i], XtNwidth, SFhScrollWidth);		i++;
		XtSetArg(arglist[i], XtNheight, scrollThickness);	i++;
		XtSetArg(arglist[i], XtNborderColor, SFfore);		i++;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
		selFileHScrolls[n] = XtCreateManagedWidget("selFileHScroll",
			XwscrollbarWidgetClass, selFileLists[n], arglist, i);

		XtAddCallback(selFileHScrolls[n], XtNsliderMoved,
			SFhSliderMovedCallback, (caddr_t) n);
		XtAddCallback(selFileHScrolls[n], XtNareaSelected,
			SFhAreaSelectedCallback, (caddr_t) n);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */
		selFileHScrolls[n] = XtCreateManagedWidget("selFileHScroll",
			scrollbarWidgetClass, selFileLists[n], arglist, i);

		XtAddCallback(selFileHScrolls[n], XtNjumpProc,
			SFhSliderMovedCallback, (caddr_t) n);
		XtAddCallback(selFileHScrolls[n], XtNscrollProc,
			SFhAreaSelectedCallback, (caddr_t) n);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

	}

	i = 0;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)

#ifdef SEL_FILE_JAPANESE

#ifdef SEL_FILE_SJIS
	(void) convSJIStoCS(ok, cstr);
#else /* def SEL_FILE_SJIS */
	(void) convEUCtoCS(ok, cstr);
#endif /* def SEL_FILE_SJIS */

	XtSetArg(arglist[i], XtNlabel, cstr);				i++;
#else /* def SEL_FILE_JAPANESE */
	XtSetArg(arglist[i], XtNlabel, ok);				i++;
#endif /* def SEL_FILE_JAPANESE */

	XtSetArg(arglist[i], XtNhSpace, 4);				i++;
	XtSetArg(arglist[i], XtNvSpace, 4);				i++;
	XtSetArg(arglist[i], XtNselect, SFokSelect);			i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */
	XtSetArg(arglist[i], XtNlabel, ok);				i++;
	XtSetArg(arglist[i], XtNcallback, SFokSelect);			i++;
	XtSetArg(arglist[i], XtNborderColor, SFfore);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
	XtSetArg(arglist[i], XtNxRefWidget, selFileLists[0]);		i++;
	XtSetArg(arglist[i], XtNyRefWidget, selFileLists[0]);		i++;
	XtSetArg(arglist[i], XtNyAddHeight, True);			i++;
	XtSetArg(arglist[i], XtNyOffset, 30);				i++;
	XtSetArg(arglist[i], XtNyAttachBottom, True);			i++;
	XtSetArg(arglist[i], XtNyAttachOffset, 30);			i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */
	XtSetArg(arglist[i], XtNfromVert, selFileLists[0]);		i++;
	XtSetArg(arglist[i], XtNvertDistance, 30);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)
	selFileOK = XtCreateManagedWidget("selFileOK", XwpushButtonWidgetClass,
		selFileForm, arglist, i);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */
	selFileOK = XtCreateManagedWidget("selFileOK", commandWidgetClass,
		selFileForm, arglist, i);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

	i = 0;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)

#ifdef SEL_FILE_JAPANESE

#ifdef SEL_FILE_SJIS
	(void) convSJIStoCS(cancel, cstr);
#else /* def SEL_FILE_SJIS */
	(void) convEUCtoCS(cancel, cstr);
#endif /* def SEL_FILE_SJIS */

	XtSetArg(arglist[i], XtNlabel, cstr);				i++;
#else /* def SEL_FILE_JAPANESE */
	XtSetArg(arglist[i], XtNlabel, cancel);				i++;
#endif /* def SEL_FILE_JAPANESE */

	XtSetArg(arglist[i], XtNhSpace, 4);				i++;
	XtSetArg(arglist[i], XtNvSpace, 4);				i++;
	XtSetArg(arglist[i], XtNselect, SFcancelSelect);		i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */
	XtSetArg(arglist[i], XtNlabel, cancel);				i++;
	XtSetArg(arglist[i], XtNcallback, SFcancelSelect);		i++;
	XtSetArg(arglist[i], XtNborderColor, SFfore);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM)
	XtSetArg(arglist[i], XtNxRefWidget, selFileOK);			i++;
	XtSetArg(arglist[i], XtNyRefWidget, selFileOK);			i++;
	XtSetArg(arglist[i], XtNxAddWidth, True);			i++;
	XtSetArg(arglist[i], XtNxOffset, 30);				i++;
	XtSetArg(arglist[i], XtNyAttachBottom, True);			i++;
	XtSetArg(arglist[i], XtNyAttachOffset, 30);			i++;
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */
	XtSetArg(arglist[i], XtNfromHoriz, selFileOK);			i++;
	XtSetArg(arglist[i], XtNfromVert, selFileLists[0]);		i++;
	XtSetArg(arglist[i], XtNhorizDistance, 30);			i++;
	XtSetArg(arglist[i], XtNvertDistance, 30);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWFORM) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)
	selFileCancel = XtCreateManagedWidget("selFileCancel",
		XwpushButtonWidgetClass, selFileForm, arglist, i);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */
	selFileCancel = XtCreateManagedWidget("selFileCancel",
		commandWidgetClass, selFileForm, arglist, i);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

	XtRealizeWidget(selFile);

	SFcreateGC();

	xtermCursor = XCreateFontCursor(SFdisplay, XC_xterm);

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
	sbDownArrowCursor = XCreateFontCursor(SFdisplay, XC_sb_down_arrow);
	sbLeftArrowCursor = XCreateFontCursor(SFdisplay, XC_sb_left_arrow);
	sbUpArrowCursor = XCreateFontCursor(SFdisplay, XC_sb_up_arrow);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

	sbRightArrowCursor = XCreateFontCursor(SFdisplay, XC_sb_right_arrow);
	dotCursor = XCreateFontCursor(SFdisplay, XC_dot);

	XDefineCursor(SFdisplay, XtWindow(selFileForm), xtermCursor);
	XDefineCursor(SFdisplay, XtWindow(selFileField), xtermCursor);

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
	XDefineCursor(SFdisplay, XtWindow(selFileHScroll), sbDownArrowCursor);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

	for (n = 0; n < 3; n++) {
		XDefineCursor(SFdisplay, XtWindow(selFileLists[n]),
			sbRightArrowCursor);

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR)
		XDefineCursor(SFdisplay, XtWindow(selFileVScrolls[n]),
			sbLeftArrowCursor);
		XDefineCursor(SFdisplay, XtWindow(selFileHScrolls[n]),
			sbUpArrowCursor);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSCROLLBAR) */

	}
	XDefineCursor(SFdisplay, XtWindow(selFileOK), dotCursor);
	XDefineCursor(SFdisplay, XtWindow(selFileCancel), dotCursor);

	for (n = 0; n < 3; n++) {
		XtAddEventHandler(selFileLists[n], ExposureMask, True,
			SFexposeList, (caddr_t) n);
		XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
			SFenterList, (caddr_t) n);
		XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
			SFleaveList, (caddr_t) n);
		XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
			SFmotionList, (caddr_t) n);
		XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
			SFbuttonPressList, (caddr_t) n);
		XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
			SFbuttonReleaseList, (caddr_t) n);
	}

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
	XtAddCallback(selFileField, XtNexecute, returnCallback, (caddr_t) NULL);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
	XtAddEventHandler(selFileField, KeyPressMask, False,
		SFmodVerifyCallback, (caddr_t) NULL);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

	SFapp = XtWidgetToApplicationContext(selFile);
}

SFtextChanged()
{

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
	static char	*SFtextBuffer = NULL;

#ifdef SEL_FILE_JAPANESE
	static int	alloc = 0;
	wchar_t		*wstr;
	int		len;
#endif /* def SEL_FILE_JAPANESE */

#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)

#ifdef SEL_FILE_JAPANESE
	wstr = XwTextCopyBuffer(selFileField);
	len = convWStoEUC(wstr, (unsigned char *) NULL);
	while (len + 1 > alloc) {
		alloc = 2 * (alloc + 1);
		SFtextBuffer = XtRealloc(SFtextBuffer, (unsigned) alloc);
	}
	(void) convWStoEUC(wstr, (unsigned char *) SFtextBuffer);
	XtFree((char *) wstr);
#else /* def SEL_FILE_JAPANESE */
	XtFree(SFtextBuffer);
	SFtextBuffer = (char *) XwTextCopyBuffer(selFileField);
#endif /* def SEL_FILE_JAPANESE */

#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

	if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~')) {
		(void) strcpy(SFcurrentPath, SFtextBuffer);

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
		SFtextPos = XwTextGetInsertPos(selFileField);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
		SFtextPos = XtTextGetInsertionPoint(selFileField);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

	} else {
		(void) strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT)
		SFtextPos = XwTextGetInsertPos(selFileField) +
			strlen(SFstartDir);
#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */
		SFtextPos = XtTextGetInsertionPoint(selFileField) +
			strlen(SFstartDir);
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWTEXTEDIT) */

	}

	if (!SFworkProcAdded) {
		(void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);
		SFworkProcAdded = 1;
	}

	SFupdatePath();
}

static char *
SFgetText()
{
	return strcpy(XtMalloc((unsigned) (strlen(SFcurrentPath) + 1)),
		SFcurrentPath);
}

static
SFprepareToReturn()
{
	SFstatus = SEL_FILE_NULL;
	XtRemoveGrab(selFile);
	XtUnmapWidget(selFile);
	XtRemoveTimeOut(SFdirModTimerId);
	if (SFchdir(SFstartDir)) {
		XtAppError(
			SFapp,
			"XsraSelFile: can't return to current directory"
		);
	}
}

int
XsraSelFile(display, prompt, ok, cancel, init_path, show_entry, path_return)
	Display		*display;
	unsigned char	*prompt;
	unsigned char	*ok;
	unsigned char	*cancel;
	char		*init_path;
	int		(*show_entry)();
	char		**path_return;
{
	static int	firstTime = 1;

#ifdef SEL_FILE_JAPANESE
	CStr		csl[2];
	u_char		cstr[256];
#endif /* def SEL_FILE_JAPANESE */

	int		i;
	Arg		arglist[20];
	XEvent		event;

	if ((!display) && firstTime) {
		Widget	w;
		int	argc;
		char	*argv[1];

		argc = 1;
		argv[0] = "xfoo";
		w = XtInitialize(argv[0], "XFoo", (XrmOptionDescRec *) NULL, 0,
			(Cardinal *) &argc, argv);
		display = XtDisplay(w);
	}

	if (!prompt) {
		prompt = (unsigned char *) "Pathname:";
	}

	if (!ok) {
		ok = (unsigned char *) "OK";
	}

	if (!cancel) {
		cancel = (unsigned char *) "Cancel";
	}

	if (firstTime) {
		firstTime = 0;
		SFdisplay = display;
		SFcreateWidgets(prompt, ok, cancel);
	} else {
		if (display && (SFdisplay != display)) {
			XtAppError(SFapp, "XsraSelFile: display different");
		}

		i = 0;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT)

#ifdef SEL_FILE_JAPANESE

#ifdef SEL_FILE_SJIS
		(void) convSJIStoCS(prompt, cstr);
#else /* def SEL_FILE_SJIS */
		(void) convEUCtoCS(prompt, cstr);
#endif /* def SEL_FILE_SJIS */

		csl[0] = cstr;
		csl[1] = NULL;
		XtSetArg(arglist[i], XtNstrings, csl);			i++;
#else /* def SEL_FILE_JAPANESE */
		XtSetArg(arglist[i], XtNstring, prompt);		i++;
#endif /* def SEL_FILE_JAPANESE */

#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT) */
		XtSetArg(arglist[i], XtNlabel, prompt);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWSTATICTEXT) */

		XtSetValues(selFilePrompt, arglist, i);

		i = 0;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)

#ifdef SEL_FILE_JAPANESE

#ifdef SEL_FILE_SJIS
		(void) convSJIStoCS(ok, cstr);
#else /* def SEL_FILE_SJIS */
		(void) convEUCtoCS(ok, cstr);
#endif /* def SEL_FILE_SJIS */

		XtSetArg(arglist[i], XtNlabel, cstr);			i++;
#else /* def SEL_FILE_JAPANESE */
		XtSetArg(arglist[i], XtNlabel, ok);			i++;
#endif /* def SEL_FILE_JAPANESE */

#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */
		XtSetArg(arglist[i], XtNlabel, ok);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

		XtSetValues(selFileOK, arglist, i);

		i = 0;

#if defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON)

#ifdef SEL_FILE_JAPANESE

#ifdef SEL_FILE_SJIS
		(void) convSJIStoCS(cancel, cstr);
#else /* def SEL_FILE_SJIS */
		(void) convEUCtoCS(cancel, cstr);
#endif /* def SEL_FILE_SJIS */

		XtSetArg(arglist[i], XtNlabel, cstr);			i++;
#else /* def SEL_FILE_JAPANESE */
		XtSetArg(arglist[i], XtNlabel, cancel);			i++;
#endif /* def SEL_FILE_JAPANESE */

#else /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */
		XtSetArg(arglist[i], XtNlabel, cancel);			i++;
#endif /* defined(SEL_FILE_XW) || defined(SEL_FILE_XWPUSHBUTTON) */

		XtSetValues(selFileCancel, arglist, i);

		XtMapWidget(selFile);
	}

#ifdef SYSV
	if (!getwd(SFstartDir)) {
	/* if (!getcwd(SFstartDir, MAXPATHLEN)) { */
#else /* def SYSV */
	if (!getwd(SFstartDir)) {
#endif /* def SYSV */

		XtAppError(SFapp, "XsraSelFile: can't get current directory");
	}
	(void) strcat(SFstartDir, "/");
	(void) strcpy(SFcurrentDir, SFstartDir);

	if (init_path) {
		if (init_path[0] == '/') {
			(void) strcpy(SFcurrentPath, init_path);
			if (strncmp(
				SFcurrentPath,
				SFstartDir,
				strlen(SFstartDir)
			)) {
				SFsetText(SFcurrentPath);
			} else {
				SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
			}
		} else {
			(void) strcat(strcpy(SFcurrentPath, SFstartDir),
				init_path);
			SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
		}
	} else {
		(void) strcpy(SFcurrentPath, SFstartDir);
	}

	SFfunc = show_entry;

	SFtextChanged();

	XtAddGrab(selFile, True, True);

	SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
		SFdirModTimer, (caddr_t) NULL);

	while (1) {
		XtAppNextEvent(SFapp, &event);
		XtDispatchEvent(&event);
		switch (SFstatus) {
		case SEL_FILE_TEXT:
			SFstatus = SEL_FILE_NULL;
			SFtextChanged();
			break;
		case SEL_FILE_OK:
			SFprepareToReturn();
			if (path_return) {
				*path_return = SFgetText();
			}
			return SEL_FILE_OK;
		case SEL_FILE_CANCEL:
			SFprepareToReturn();
			return SEL_FILE_CANCEL;
		case SEL_FILE_NULL:
			break;
		}
	}
}
\End\Of\File\
else
  echo "will not over write ./SelFile.c"
fi
if `test ! -s ./SelFile.man`
then
echo "writing ./SelFile.man"
cat > ./SelFile.man << '\End\Of\File\'
.\" $Header: SelFile.man,v 1.3 89/04/24 22:27:00 erik Exp $
.\"
.\" Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
.\"
.\" Permission to use, copy, modify, and distribute this software and its
.\" documentation for any purpose and without fee is hereby granted, provided
.\" that the above copyright notice appear in all copies and that both that
.\" copyright notice and this permission notice appear in supporting
.\" documentation, and that the name of Software Research Associates not be used
.\" in advertising or publicity pertaining to distribution of the software
.\" without specific, written prior permission.  Software Research Associates
.\" makes no representations about the suitability of this software for any
.\" purpose.  It is provided "as is" without express or implied warranty.
.\"
.\" SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
.\" SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
.\" IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
.\" INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
.\" PERFORMANCE OF THIS SOFTWARE.
.\"
.\" Author: Erik M. van der Poel
.\"         Software Research Associates, Inc., Tokyo, Japan
.\"
.TH XSRASELFILE 3X "April 24 1989" SRA
.SH NAME
\fIXsraSelFile\fR \- select a file
.sp
.SH SYNOPSIS
.nf
.ft B
#include <stdio.h>
#include <X11/Intrinsic.h>
.PP
.ft B
.ta +\w'unsigned char  'u
ret = XsraSelFile(display, prompt, ok, cancel, init_path, show_entry, path_return)
int	ret;
Display	*display;
unsigned char	*prompt;
unsigned char	*ok;
unsigned char	*cancel;
char	*init_path;
int	(*show_entry)();
char	**path_return;
.fi
.sp
.SH DESCRIPTION
.I XsraSelFile
allows an X11 user to select a file by typing the path or by browsing in
directory listings and selecting entries with the mouse.
.sp
The space bar can be pressed to complete filenames, and tilde is used for home
directories.
All of the usual key bindings can be used in the text widget, except for Return
and Control-M, which are equivalent to pressing the OK button.
The path can be scrolled using the large horizontal scroll bar, or by moving
the insertion cursor in the text widget.
The directory entries can be scrolled using the vertical scroll bars, or by
holding a mouse button down and moving out of the listing.
The scrolling speed varies with the distance from the listing.
.sp
The directory entries are terminated with special characters that indicate the
kind of entry, similar to the
.I \-F
option of
.IR ls (1).
.sp
The programmer's interface is simple, providing an easy way for the application
to obtain a filename from the user.
.sp
.I XsraSelFile
does not allow X events to be generated on any other widgets in the application
by adding a grab for the dialog widget while it is active.
.sp
.SH ARGUMENTS
The
.B display
argument specifies the display on which to create the new application shell
dialog widget.
If it is specified as NULL, the default display is opened by initializing the X
toolkit.
.sp
The
.B prompt
argument specifies the prompt to print near the top of the new widget.
This should be a string containing no newlines.
If the prompt is specified as NULL, the string "Pathname:" is used.
.sp
The
.B ok
argument specifies the string to print in the OK button.
If it is specified as NULL, "OK" is used.
.sp
The
.B cancel
argument specifies the string to print in the Cancel button.
If it is specified as NULL, "Cancel" is used.
.sp
The initial path may be set using
.BR init_path .
If it is specified as NULL, the initial path will be the current directory.
.sp
The
.B show_entry
argument is a pointer to a function that is called to decide whether or not to
display a particular directory entry.
If this argument is specified as NULL, all entries will be displayed.
Otherwise, the function is called with arguments as follows.
.sp
.nf
.ft I
.ta +\w'struct stat  'u
int show_entry(real_name, shown_name_return, entry_stat)
char	*real_name;
char	**shown_name_return;
struct stat	*entry_stat;
.ft R
.fi
.sp
The
.I real_name
argument is the name of the entry, and the
.I entry_stat
argument is a pointer to the stat buffer of the entry.
The contents of the real_name and entry_stat arguments should not be altered.
The
.I shown_name_return
argument is to be filled in by the function if a name other than the real name
is to be shown.
The function should return true if the entry is to be displayed.
An example of a show_entry function can be found in
.IR callback.c .
.sp
When the return key or the OK button is pressed,
.I XsraSelFile
returns, putting the full path of the selected file in
.B path_return
unless it is NULL.
.I XtMalloc
is used to make a copy of the path.
The application writer is responsible for freeing the space.
.sp
.SH RETURN VALUE
The
.B ret
return value is 0 if the user presses the return key or the OK button.
Otherwise, the user has pressed the Cancel button and a value of \-1 is
returned.
.sp
.SH COMPILATION
The XsraSelFile package can be linked with Athena (Xaw) and/or Hewlett-Packard
(Xw) widgets, by choosing the appropriate defines. See the Imakefile for
details.
.sp
.SH RESOURCES
The font to be used by
.I XsraSelFile
is specified by putting the following in a resource file:
.sp
.ft H
	selFile*font	:9x15
.ft R
.sp
(The default font is
.IR 9x15 .)
.sp
.SH ENVIRONMENT
DISPLAY \- the default host and display to use.
.sp
.SH "SEE ALSO"
X(1), xrdb(1), X Toolkit
.sp
.SH BUGS
.I XsraSelFile
must always be called with the same
.I display
argument.
.sp
When a directory is modified by a third party while the pointer is in that
directory's listing, the display will be updated and the pointer will be warped
away to prevent the user from selecting `the wrong file', which can be
considered dangerous if the application is about to delete whatever the user
selects.
.sp
.SH COPYRIGHT
Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
.sp
.SH AUTHOR
Erik M. van der Poel, Software Research Associates, Inc., Tokyo, Japan
\End\Of\File\
else
  echo "will not over write ./SelFile.man"
fi
if `test ! -s ./TODO`
then
echo "writing ./TODO"
cat > ./TODO << '\End\Of\File\'
* Variable number of lists (instead of 3), variable no. of entries, etc.
  Perhaps turn it into a widget?

* Use X selections instead of cut buffer.
  This would enable clients to obtain pathnames through selections, and the
  client would not have to link in the XsraSelFile code.

* Some clients may want to have more control over what happens in the
  XtAppNextEvent-XtDispatchEvent loop.

* Another idea is a text widget with file name completion that can be embedded
  in an application. The completions would only be popped up when the user
  wants to see them.

* Make another package for completion of not only filenames, but anything.

* launching by eg double click

* scrolling and selection through keyboard

* if file to be read, it must exist

* allow the user to specify the filename pattern e.g. *.c

* customized buttons eg vi

* directory stack option

* search (RE)

* file stat info
\End\Of\File\
else
  echo "will not over write ./TODO"
fi
if `test ! -s ./callback.c`
then
echo "writing ./callback.c"
cat > ./callback.c << '\End\Of\File\'
#ifndef lint
static char rcsid[] = "$Header: callback.c,v 1.2 89/05/29 15:06:48 erik Exp $";
#endif

/*
 * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  Software Research Associates
 * makes no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: Erik M. van der Poel
 *         Software Research Associates, Inc., Tokyo, Japan
 */

#include <stdio.h>
#include <X11/Intrinsic.h>
#include <sys/stat.h>

extern char *re_comp();

static int
match(exp, str)
	char	*exp, *str;
{
	char	*err;

	if (err = re_comp(exp)) {
		(void) fprintf(stderr, "re_comp(\"%s\"): %s\n", exp, err);
		exit(1);
	}

	return re_exec(str);
}

int
fileCheck(realFileName, shownFileName, fileStat)
	char		*realFileName;
	char		**shownFileName;
	struct stat	*fileStat;
{
	static char	shown[256];

	switch (match("^..*\.plt$", realFileName)) {
	case 0:
	case -1:
	default:
		break;
	case 1:
		if ((fileStat->st_mode & S_IFMT) == S_IFREG) {
			(void) strcpy(shown, realFileName);
			*(rindex(shown, '.')) = 0;
			*shownFileName = shown;
		}
		return 1;
	}

	switch (match("^..*\.xy$", realFileName)) {
	case 0:
	case -1:
	default:
		break;
	case 1:
		return 0;
	}

	switch (match("^..*\.z$", realFileName)) {
	case 0:
	case -1:
	default:
		break;
	case 1:
		return 0;
	}

	return 1;
}
\End\Of\File\
else
  echo "will not over write ./callback.c"
fi
if `test ! -s ./xdir.c`
then
echo "writing ./xdir.c"
cat > ./xdir.c << '\End\Of\File\'
#ifndef lint
static char rcsid[] = "$Header: xdir.c,v 1.3 89/05/29 15:07:10 erik Exp $";
#endif

/*
 * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  Software Research Associates
 * makes no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: Erik M. van der Poel
 *         Software Research Associates, Inc., Tokyo, Japan
 */

#include <stdio.h>
#include <X11/Intrinsic.h>

main(argc, argv)
	int	argc;
	char	*argv[];
{
	Widget	XDir;
	char	*path;

	XDir = XtInitialize(argv[0], "XDir", (XrmOptionDescRec *) NULL,
		(Cardinal) 0, (Cardinal *) &argc, argv);

	while (1) {
		if (XsraSelFile(
			XtDisplay(XDir),
			(unsigned char *) "Pathname to store in cut buffer:",
			(unsigned char *) "Cut",
			(unsigned char *) "Exit",
			(char *) NULL,
			(int (*)()) NULL,
			&path
		)) {
			break;
		}
		XStoreBytes(XtDisplay(XDir), path, strlen(path));
		XtFree(path);
	}

	return 0;
}
\End\Of\File\
else
  echo "will not over write ./xdir.c"
fi
echo "Finished archive 1 of 2"
exit