commands.c revision f765521f
15dfecf96Smrg/* $XConsortium: commands.c,v 1.33 91/10/21 14:32:18 eswu Exp $ */
25dfecf96Smrg
35dfecf96Smrg/*
45dfecf96Smrg *			  COPYRIGHT 1987
55dfecf96Smrg *		   DIGITAL EQUIPMENT CORPORATION
65dfecf96Smrg *		       MAYNARD, MASSACHUSETTS
75dfecf96Smrg *			ALL RIGHTS RESERVED.
85dfecf96Smrg *
95dfecf96Smrg * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
105dfecf96Smrg * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
115dfecf96Smrg * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
125dfecf96Smrg * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
135dfecf96Smrg *
145dfecf96Smrg * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
155dfecf96Smrg * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
165dfecf96Smrg * SET FORTH ABOVE.
175dfecf96Smrg *
185dfecf96Smrg *
195dfecf96Smrg * Permission to use, copy, modify, and distribute this software and its
205dfecf96Smrg * documentation for any purpose and without fee is hereby granted, provided
215dfecf96Smrg * that the above copyright notice appear in all copies and that both that
225dfecf96Smrg * copyright notice and this permission notice appear in supporting
235dfecf96Smrg * documentation, and that the name of Digital Equipment Corporation not be
245dfecf96Smrg * used in advertising or publicity pertaining to distribution of the software
255dfecf96Smrg * without specific, written prior permission.
265dfecf96Smrg */
275dfecf96Smrg/* $XFree86: xc/programs/xedit/commands.c,v 1.29tsi Exp $ */
285dfecf96Smrg
295dfecf96Smrg#include <X11/Xfuncs.h>
305dfecf96Smrg#include <X11/Xos.h>
315dfecf96Smrg#include "xedit.h"
325dfecf96Smrg#include <stdlib.h>
335dfecf96Smrg#include <stdio.h>
345dfecf96Smrg#include <limits.h>
355dfecf96Smrg#include <string.h>
365dfecf96Smrg#include <dirent.h>
375dfecf96Smrg#include <pwd.h>
385dfecf96Smrg#include <sys/stat.h>
395dfecf96Smrg#include <X11/Xmu/SysUtil.h>
405dfecf96Smrg#include <X11/IntrinsicP.h>
415dfecf96Smrg#include <X11/Xaw/TextSrcP.h>
425dfecf96Smrg
435dfecf96Smrg/* Turn a NULL pointer string into an empty string */
445dfecf96Smrg#define NULLSTR(x) (((x)!=NULL)?(x):(""))
455dfecf96Smrg
465dfecf96Smrg#define Error(x) { printf x ; exit(EXIT_FAILURE); }
475dfecf96Smrg#define Assertion(expr, msg) { if (!(expr)) { Error msg } }
485dfecf96Smrg#define Log(x)   { if (True) printf x; }
495dfecf96Smrg
505dfecf96Smrgvoid ResetSourceChanged(xedit_flist_item*);
515dfecf96Smrgstatic void ResetDC(Widget, XtPointer, XtPointer);
525dfecf96Smrg
535dfecf96Smrgstatic void AddDoubleClickCallback(Widget, Bool);
545dfecf96Smrgstatic Bool ReallyDoLoad(char*, char*);
555dfecf96Smrgstatic char *makeBackupName(String, String, unsigned);
565dfecf96Smrg
57f14f4646Smrg/*
58f14f4646Smrg * External
59f14f4646Smrg */
60f14f4646Smrgextern void _XawTextShowPosition(TextWidget);
61f14f4646Smrg
625dfecf96Smrgextern Widget scratch, texts[3], labels[3];
635dfecf96Smrg
64f14f4646Smrg#define DC_UNSAVED	(1 << 0)
65f14f4646Smrg#define DC_LOADED	(1 << 1)
66f14f4646Smrg#define DC_CLOBBER	(1 << 2)
67f14f4646Smrg#define DC_KILL		(1 << 3)
68f14f4646Smrg#define DC_SAVE		(1 << 4)
69f14f4646Smrg#define DC_NEWER	(1 << 5)
705dfecf96Smrgstatic int dc_state;
715dfecf96Smrg
725dfecf96Smrgstatic void
735dfecf96SmrgAddDoubleClickCallback(Widget w, Bool state)
745dfecf96Smrg{
75f14f4646Smrg    if (state)
76f14f4646Smrg	XtAddCallback(w, XtNcallback, ResetDC, NULL);
77f14f4646Smrg    else
78f14f4646Smrg	XtRemoveCallback(w, XtNcallback, ResetDC, NULL);
795dfecf96Smrg}
805dfecf96Smrg
815dfecf96Smrg/*	Function Name: ResetDC
825dfecf96Smrg *	Description: Resets the double click flag.
835dfecf96Smrg *	Arguments: w - the text widget.
845dfecf96Smrg *                 junk, garbage - *** NOT USED ***
855dfecf96Smrg *	Returns: none.
865dfecf96Smrg */
875dfecf96Smrg
885dfecf96Smrg/* ARGSUSED */
895dfecf96Smrgstatic void
905dfecf96SmrgResetDC(Widget w, XtPointer junk, XtPointer garbage)
915dfecf96Smrg{
92f14f4646Smrg    AddDoubleClickCallback(w, FALSE);
935dfecf96Smrg}
945dfecf96Smrg
955dfecf96Smrg/*ARGSUSED*/
965dfecf96Smrgvoid
975dfecf96SmrgQuitAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
985dfecf96Smrg{
995dfecf96Smrg    DoQuit(w, NULL, NULL);
1005dfecf96Smrg}
1015dfecf96Smrg
1025dfecf96Smrg/*ARGSUSED*/
1035dfecf96Smrgvoid
1045dfecf96SmrgDoQuit(Widget w, XtPointer client_data, XtPointer call_data)
1055dfecf96Smrg{
1065dfecf96Smrg    unsigned i;
1075dfecf96Smrg    Bool source_changed = False;
1085dfecf96Smrg
109f14f4646Smrg    if (!(dc_state & DC_UNSAVED)) {
1105dfecf96Smrg	for (i = 0; i < flist.num_itens; i++)
1115dfecf96Smrg	    if (flist.itens[i]->flags & CHANGED_BIT) {
1125dfecf96Smrg		source_changed = True;
1135dfecf96Smrg		break;
1145dfecf96Smrg	    }
1155dfecf96Smrg    }
116f14f4646Smrg    if (!source_changed) {
1175dfecf96Smrg#ifndef __UNIXOS2__
1185dfecf96Smrg	XeditLispCleanUp();
1195dfecf96Smrg#endif
1205dfecf96Smrg	exit(0);
1215dfecf96Smrg    }
1225dfecf96Smrg
1235dfecf96Smrg    XeditPrintf("Unsaved changes. Save them, or Quit again.\n");
1245dfecf96Smrg    Feep();
125f14f4646Smrg    dc_state |= DC_UNSAVED;
1265dfecf96Smrg    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
1275dfecf96Smrg}
1285dfecf96Smrg
1295dfecf96Smrgstatic char *
1305dfecf96SmrgmakeBackupName(String buf, String filename, unsigned len)
1315dfecf96Smrg{
1325dfecf96Smrg    if (app_resources.backupNamePrefix
1335dfecf96Smrg	&& strlen(app_resources.backupNamePrefix)) {
1345dfecf96Smrg	if (strchr(app_resources.backupNamePrefix, '/'))
1355dfecf96Smrg	    XmuSnprintf(buf, len, "%s%s%s", app_resources.backupNamePrefix,
1365dfecf96Smrg			filename, app_resources.backupNameSuffix);
1375dfecf96Smrg	else {
1385dfecf96Smrg	    char fname[BUFSIZ];
1395dfecf96Smrg	    char *name, ch;
1405dfecf96Smrg
1415dfecf96Smrg	    strncpy(fname, filename, sizeof(fname) - 1);
1425dfecf96Smrg	    fname[sizeof(fname) - 1] = '\0';
1435dfecf96Smrg	    if ((name = strrchr(fname, '/')) != NULL)
1445dfecf96Smrg		++name;
1455dfecf96Smrg	    else
1465dfecf96Smrg		name = filename;
1475dfecf96Smrg	    ch = *name;
1485dfecf96Smrg	    *name = '\0';
1495dfecf96Smrg	    ++name;
1505dfecf96Smrg	    XmuSnprintf(buf, len, "%s%s%c%s%s",
1515dfecf96Smrg			fname, app_resources.backupNamePrefix, ch, name,
1525dfecf96Smrg			app_resources.backupNameSuffix);
1535dfecf96Smrg	}
1545dfecf96Smrg    }
1555dfecf96Smrg    else
1565dfecf96Smrg	XmuSnprintf(buf, len, "%s%s",
1575dfecf96Smrg		    filename, app_resources.backupNameSuffix);
1585dfecf96Smrg
1595dfecf96Smrg    return (strcmp(filename, buf) ? buf : NULL);
1605dfecf96Smrg}
1615dfecf96Smrg
1625dfecf96Smrg/*ARGSUSED*/
1635dfecf96Smrgvoid
1645dfecf96SmrgSaveFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
1655dfecf96Smrg{
166f14f4646Smrg    if (line_edit) {
167f14f4646Smrg	/* Don't try to save buffer with regex string.
168f14f4646Smrg	 * Call CancelFindFile() to leave line_edit mode.
169f14f4646Smrg	 */
170f14f4646Smrg	XeditPrintf("Save: Leaving line edit mode -- nothing saved.\n");
171f14f4646Smrg	CancelFindFile(w, event, params, num_params);
172f14f4646Smrg	Feep();
173f14f4646Smrg    }
174f14f4646Smrg    else
175f14f4646Smrg	DoSave(w, NULL, NULL);
1765dfecf96Smrg}
1775dfecf96Smrg
1785dfecf96Smrg/*ARGSUSED*/
1795dfecf96Smrgvoid
1805dfecf96SmrgDoSave(Widget w, XtPointer client_data, XtPointer call_data)
1815dfecf96Smrg{
1825dfecf96Smrg    String name = GetString(filenamewindow);
1835dfecf96Smrg    String filename = ResolveName(name);
1845dfecf96Smrg    FileAccess file_access;
1855dfecf96Smrg    xedit_flist_item *item;
1865dfecf96Smrg    Boolean exists;
1875dfecf96Smrg    Widget source = XawTextGetSource(textwindow);
188f14f4646Smrg    char buffer[BUFSIZ];
189f14f4646Smrg    struct stat st;
190f765521fSmrg    static const char *nothing_saved = " -- nothing saved.\n";
1915dfecf96Smrg
1925dfecf96Smrg    if (!filename) {
193f14f4646Smrg	XmuSnprintf(buffer, sizeof(buffer), "%s%s",
194f14f4646Smrg		    "Save: Can't resolve pathname",  nothing_saved);
195f14f4646Smrg	goto error;
1965dfecf96Smrg    }
1975dfecf96Smrg    else if (*name == '\0') {
198f14f4646Smrg	XmuSnprintf(buffer, sizeof(buffer), "%s%s",
199f14f4646Smrg		    "Save: No filename specified", nothing_saved);
200f14f4646Smrg	goto error;
2015dfecf96Smrg    }
2025dfecf96Smrg
2035dfecf96Smrg    item = FindTextSource(NULL, filename);
2045dfecf96Smrg    if (item != NULL && item->source != source) {
205f14f4646Smrg	if (!(dc_state & DC_LOADED)) {
206f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s%s%s",
207f14f4646Smrg			"Save: file ", name, " is already loaded, "
208f14f4646Smrg			"Save again to unload it", nothing_saved);
2095dfecf96Smrg	    Feep();
210f14f4646Smrg	    dc_state |= DC_LOADED;
2115dfecf96Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
212f14f4646Smrg	    goto error;
213f14f4646Smrg	}
214f14f4646Smrg	else {
215f14f4646Smrg	    KillTextSource(item);
216f14f4646Smrg	    item = FindTextSource(source = XawTextGetSource(textwindow), NULL);
217f14f4646Smrg	    dc_state &= ~DC_LOADED;
2185dfecf96Smrg	}
2195dfecf96Smrg    }
2205dfecf96Smrg    else if (item && !(item->flags & CHANGED_BIT)) {
221f14f4646Smrg	if (!(dc_state & DC_SAVE)) {
222f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s",
223f14f4646Smrg			"Save: No changes need to be saved, "
224f14f4646Smrg			"save again to override", nothing_saved);
2255dfecf96Smrg	    Feep();
226f14f4646Smrg	    dc_state |= DC_SAVE;
2275dfecf96Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
228f14f4646Smrg	    goto error;
2295dfecf96Smrg	}
230f14f4646Smrg	else
231f14f4646Smrg	    dc_state &= ~DC_SAVE;
2325dfecf96Smrg    }
2335dfecf96Smrg
2345dfecf96Smrg    file_access = CheckFilePermissions(filename, &exists);
235f14f4646Smrg    if (exists) {
236f14f4646Smrg	if (stat(filename, &st) != 0) {
237f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s%s",
238f14f4646Smrg			"Save: cannot stat ", name, nothing_saved);
239f14f4646Smrg	    goto error;
240f14f4646Smrg	}
241f14f4646Smrg	else if (!S_ISREG(st.st_mode)) {
242f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s%s%s",
243f14f4646Smrg			"Save: file ", name, "is not a regular file",
244f14f4646Smrg			nothing_saved);
245f14f4646Smrg	    goto error;
246f14f4646Smrg	}
247f14f4646Smrg    }
248f14f4646Smrg
2495dfecf96Smrg    if (!item || strcmp(item->filename, filename)) {
2505dfecf96Smrg	if (file_access == WRITE_OK && exists) {
251f14f4646Smrg	    if (!(dc_state & DC_CLOBBER)) {
252f14f4646Smrg		XmuSnprintf(buffer, sizeof(buffer), "%s%s%s%s",
253f14f4646Smrg			    "Save: file ", name, " already exists, "
254f14f4646Smrg			    "save again to override", nothing_saved);
2555dfecf96Smrg		Feep();
256f14f4646Smrg		dc_state |= DC_CLOBBER;
2575dfecf96Smrg		AddDoubleClickCallback(XawTextGetSource(textwindow), True);
258f14f4646Smrg		goto error;
2595dfecf96Smrg	    }
260f14f4646Smrg	    else
261f14f4646Smrg		dc_state &= ~DC_CLOBBER;
2625dfecf96Smrg	}
2635dfecf96Smrg	if (!item)
2645dfecf96Smrg	    item = FindTextSource(source, NULL);
2655dfecf96Smrg    }
2665dfecf96Smrg
267f14f4646Smrg    if (item && item->mtime && exists && item->mtime < st.st_mtime) {
268f14f4646Smrg	if (!(dc_state & DC_NEWER)) {
269f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s",
270f14f4646Smrg			"Save: Newer file exists, "
271f14f4646Smrg			"save again to override", nothing_saved);
272f14f4646Smrg	    Feep();
273f14f4646Smrg	    dc_state |= DC_NEWER;
274f14f4646Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
275f14f4646Smrg	    goto error;
276f14f4646Smrg	}
277f14f4646Smrg	else
278f14f4646Smrg	    dc_state &= DC_NEWER;
279f14f4646Smrg    }
280f14f4646Smrg
281f14f4646Smrg    if (app_resources.enableBackups && exists) {
282f14f4646Smrg	char backup_file[BUFSIZ];
283f14f4646Smrg
284f14f4646Smrg	if (makeBackupName(backup_file, filename, sizeof(backup_file)) == NULL
285f14f4646Smrg	    || rename(filename, backup_file) != 0) {
286f14f4646Smrg	    XeditPrintf("Error backing up file: %s\n", filename);
287f14f4646Smrg	}
288f14f4646Smrg    }
289f14f4646Smrg
290f14f4646Smrg    switch (file_access = MaybeCreateFile(filename)) {
291f14f4646Smrg	case NO_READ:
292f14f4646Smrg	case READ_OK:
293f14f4646Smrg	    XeditPrintf("File %s could not be opened for writing.\n", name);
294f14f4646Smrg	    Feep();
295f14f4646Smrg	    break;
296f14f4646Smrg	case WRITE_OK:
297f14f4646Smrg	    if (XawAsciiSaveAsFile(source, filename)) {
298f14f4646Smrg		int i;
299f14f4646Smrg		Arg args[1];
300f14f4646Smrg
301f14f4646Smrg		XmuSnprintf(buffer, sizeof(buffer),
302f14f4646Smrg			    "%s       Read - Write", name);
303f14f4646Smrg		XtSetArg(args[0], XtNlabel, buffer);
304f14f4646Smrg		for (i = 0; i < 3; i++)
305f14f4646Smrg		    if (XawTextGetSource(texts[i]) == source)
306f14f4646Smrg			XtSetValues(labels[i], args, 1);
307f14f4646Smrg
308f14f4646Smrg		XeditPrintf("Saved file: %s\n", name);
309f14f4646Smrg
310f14f4646Smrg		if (item && item->source != scratch) {
311f14f4646Smrg		    XtSetArg(args[0], XtNlabel, filename);
312f14f4646Smrg		    XtSetValues(item->sme, args, 1);
313f14f4646Smrg
314f14f4646Smrg		    XtSetArg(args[0], XtNeditType, XawtextEdit);
315f14f4646Smrg		    XtSetValues(item->source, args, 1);
316f14f4646Smrg
317f14f4646Smrg		    XtFree(item->name);
318f14f4646Smrg		    XtFree(item->filename);
319f14f4646Smrg		    item->name = XtNewString(name);
320f14f4646Smrg		    item->filename = XtNewString(filename);
321f14f4646Smrg		    item->flags = EXISTS_BIT;
322f14f4646Smrg		}
323f14f4646Smrg		else {
324f14f4646Smrg		    item = flist.itens[0];
325f14f4646Smrg		    XtRemoveCallback(scratch, XtNcallback, SourceChanged,
326f14f4646Smrg				     (XtPointer)item);
327f14f4646Smrg		    item->source = scratch =
328f14f4646Smrg		    XtVaCreateWidget("textSource", international ?
329f14f4646Smrg				     multiSrcObjectClass :
330f14f4646Smrg				     asciiSrcObjectClass,
331f14f4646Smrg				     topwindow,
332f14f4646Smrg				     XtNtype, XawAsciiFile,
333f14f4646Smrg				     XtNeditType, XawtextEdit,
334f14f4646Smrg				     NULL, NULL);
335f14f4646Smrg		    ResetSourceChanged(item);
336f14f4646Smrg		    XtAddCallback(scratch, XtNcallback, SourceChanged,
337f14f4646Smrg				  (XtPointer)item);
338f14f4646Smrg
339f14f4646Smrg		    item = AddTextSource(source, name, filename, EXISTS_BIT,
340f14f4646Smrg					 file_access);
341f14f4646Smrg		    XtAddCallback(item->source, XtNcallback, SourceChanged,
342f14f4646Smrg				  (XtPointer)item);
343f14f4646Smrg		}
344f14f4646Smrg
345f14f4646Smrg		/* Keep file protection mode */
346f14f4646Smrg		if (item->mode)
347f14f4646Smrg		    chmod(filename, item->mode);
348f14f4646Smrg
349f14f4646Smrg		/* Remember time of last modification */
350f14f4646Smrg		if (stat(filename, &st) == 0)
351f14f4646Smrg		    item->mtime = st.st_mtime;
352f14f4646Smrg
353f14f4646Smrg		item->flags |= EXISTS_BIT;
354f14f4646Smrg		ResetSourceChanged(item);
355f14f4646Smrg	    }
356f14f4646Smrg	    else {
357f14f4646Smrg		XeditPrintf("Error saving file: %s\n",  name);
358f14f4646Smrg		Feep();
359f14f4646Smrg	    }
360f14f4646Smrg	    break;
361f14f4646Smrg	default:
362f14f4646Smrg	    Feep();
363f14f4646Smrg	    break;
3645dfecf96Smrg    }
3655dfecf96Smrg
366f14f4646Smrg    return;
367f14f4646Smrgerror:
368f14f4646Smrg    XeditPrintf("%s", buffer);
369f14f4646Smrg    Feep();
3705dfecf96Smrg}
3715dfecf96Smrg
3725dfecf96Smrg/*ARGSUSED*/
3735dfecf96Smrgvoid
3745dfecf96SmrgDoLoad(Widget w, XtPointer client_data, XtPointer call_data)
3755dfecf96Smrg{
3765dfecf96Smrg    if (ReallyDoLoad(GetString(filenamewindow), ResolveName(NULL))) {
3775dfecf96Smrg        SwitchDirWindow(False);
3785dfecf96Smrg        XtSetKeyboardFocus(topwindow, textwindow);
3795dfecf96Smrg    }
3805dfecf96Smrg}
3815dfecf96Smrg
382f14f4646SmrgBool
383f14f4646SmrgLoadFileInTextwindow(char *name, char *resolved_name)
384f14f4646Smrg{
385f14f4646Smrg    return (ReallyDoLoad(name, resolved_name));
386f14f4646Smrg}
387f14f4646Smrg
3885dfecf96Smrgstatic Bool
3895dfecf96SmrgReallyDoLoad(char *name, char *filename)
3905dfecf96Smrg{
3915dfecf96Smrg    Arg args[5];
3925dfecf96Smrg    Cardinal num_args = 0;
3935dfecf96Smrg    xedit_flist_item *item;
3945dfecf96Smrg    Widget source = XawTextGetSource(textwindow);
3955dfecf96Smrg
3965dfecf96Smrg    if (!filename) {
3975dfecf96Smrg	XeditPrintf("Load: Can't resolve pathname.\n");
3985dfecf96Smrg	Feep();
3995dfecf96Smrg	return (False);
4005dfecf96Smrg    }
4015dfecf96Smrg    else if (*name == '\0') {
4025dfecf96Smrg	XeditPrintf("Load: No file specified.\n");
4035dfecf96Smrg	Feep();
4045dfecf96Smrg    }
4055dfecf96Smrg    if ((item = FindTextSource(NULL, filename)) != NULL) {
4065dfecf96Smrg	SwitchTextSource(item);
4075dfecf96Smrg	return (True);
4085dfecf96Smrg    }
4095dfecf96Smrg    else {
4105dfecf96Smrg	struct stat st;
4115dfecf96Smrg
4125dfecf96Smrg	if (stat(filename, &st) == 0 && !S_ISREG(st.st_mode)) {
4135dfecf96Smrg	    if (S_ISDIR(st.st_mode)) {
4145dfecf96Smrg		char path[BUFSIZ + 1];
4155dfecf96Smrg
4165dfecf96Smrg		strncpy(path, filename, sizeof(path) - 2);
4175dfecf96Smrg		path[sizeof(path) - 2] = '\0';
4185dfecf96Smrg		if (*path) {
4195dfecf96Smrg		    if (path[strlen(path) - 1] != '/')
4205dfecf96Smrg			strcat(path, "/");
4215dfecf96Smrg		}
4225dfecf96Smrg		else
4235dfecf96Smrg		    strcpy(path, "./");
4245dfecf96Smrg		XtSetArg(args[0], XtNlabel, "");
4255dfecf96Smrg		XtSetValues(dirlabel, args, 1);
4265dfecf96Smrg		SwitchDirWindow(True);
4275dfecf96Smrg		DirWindowCB(dirwindow, path, NULL);
4285dfecf96Smrg		return (False);
4295dfecf96Smrg	    }
4305dfecf96Smrg	}
4315dfecf96Smrg    }
4325dfecf96Smrg
4335dfecf96Smrg    {
4345dfecf96Smrg	Boolean exists;
4355dfecf96Smrg	int flags;
4365dfecf96Smrg	FileAccess file_access;
4375dfecf96Smrg
4385dfecf96Smrg	switch( file_access = CheckFilePermissions(filename, &exists) ) {
4395dfecf96Smrg	case NO_READ:
4405dfecf96Smrg	    if (exists)
441f14f4646Smrg		XeditPrintf("File %s, %s", name,
442f14f4646Smrg			    "exists, and could not be opened for reading.\n");
4435dfecf96Smrg	    else
444f14f4646Smrg		XeditPrintf("File %s %s %s",  name,
4455dfecf96Smrg			    "does not exist, and",
446f14f4646Smrg			    "the directory could not be opened for writing.\n");
4475dfecf96Smrg
4485dfecf96Smrg	    Feep();
4495dfecf96Smrg	    return (False);
4505dfecf96Smrg	case READ_OK:
4515dfecf96Smrg	    XtSetArg(args[num_args], XtNeditType, XawtextRead); num_args++;
452f14f4646Smrg	    XeditPrintf("File %s opened READ ONLY.\n", name);
4535dfecf96Smrg	    break;
4545dfecf96Smrg	case WRITE_OK:
4555dfecf96Smrg	    XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
456f14f4646Smrg	    XeditPrintf("File %s opened read - write.\n", name);
4575dfecf96Smrg	    break;
4585dfecf96Smrg	default:
4595dfecf96Smrg	    Feep();
4605dfecf96Smrg	    return (False);
4615dfecf96Smrg	}
4625dfecf96Smrg
4635dfecf96Smrg	if (exists) {
4645dfecf96Smrg	    flags = EXISTS_BIT;
4655dfecf96Smrg	    XtSetArg(args[num_args], XtNstring, filename); num_args++;
4665dfecf96Smrg	}
4675dfecf96Smrg	else {
4685dfecf96Smrg	    flags = 0;
4695dfecf96Smrg	    XtSetArg(args[num_args], XtNstring, NULL); num_args++;
4705dfecf96Smrg	}
4715dfecf96Smrg
472f14f4646Smrg	source = XtVaCreateWidget("textSource", international ?
473f14f4646Smrg				  multiSrcObjectClass :
474f14f4646Smrg				  asciiSrcObjectClass,
4755dfecf96Smrg				  topwindow,
4765dfecf96Smrg				  XtNtype, XawAsciiFile,
4775dfecf96Smrg				  XtNeditType, XawtextEdit,
4785dfecf96Smrg				  NULL, NULL);
4795dfecf96Smrg	XtSetValues(source, args, num_args);
4805dfecf96Smrg
4815dfecf96Smrg	item = AddTextSource(source, name, filename, flags, file_access);
4825dfecf96Smrg	XtAddCallback(item->source, XtNcallback, SourceChanged,
4835dfecf96Smrg		      (XtPointer)item);
4845dfecf96Smrg	if (exists && file_access == WRITE_OK) {
4855dfecf96Smrg	    struct stat st;
4865dfecf96Smrg
487f14f4646Smrg	    if (stat(item->filename, &st) == 0) {
4885dfecf96Smrg		item->mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
489f14f4646Smrg		item->mtime = st.st_mtime;
490f14f4646Smrg	    }
4915dfecf96Smrg	}
4925dfecf96Smrg	SwitchTextSource(item);
4935dfecf96Smrg	ResetSourceChanged(item);
4945dfecf96Smrg    }
4955dfecf96Smrg
4965dfecf96Smrg    return (True);
4975dfecf96Smrg}
4985dfecf96Smrg
4995dfecf96Smrg/*	Function Name: SourceChanged
5005dfecf96Smrg *	Description: A callback routine called when the source has changed.
5015dfecf96Smrg *	Arguments: w - the text source that has changed.
5025dfecf96Smrg *		   client_data - xedit_flist_item associated with text buffer.
5035dfecf96Smrg *                 call_data - NULL is unchanged
5045dfecf96Smrg *	Returns: none.
5055dfecf96Smrg */
5065dfecf96Smrg/*ARGSUSED*/
5075dfecf96Smrgvoid
5085dfecf96SmrgSourceChanged(Widget w, XtPointer client_data, XtPointer call_data)
5095dfecf96Smrg{
5105dfecf96Smrg    xedit_flist_item *item = (xedit_flist_item*)client_data;
5115dfecf96Smrg    Bool changed = (Bool)(long)call_data;
5125dfecf96Smrg
5135dfecf96Smrg    if (changed) {
5145dfecf96Smrg	if (item->flags & CHANGED_BIT)
5155dfecf96Smrg	    return;
5165dfecf96Smrg	item->flags |= CHANGED_BIT;
5175dfecf96Smrg    }
5185dfecf96Smrg    else {
5195dfecf96Smrg	if (item->flags & CHANGED_BIT)
5205dfecf96Smrg	    ResetSourceChanged(item);
5215dfecf96Smrg	return;
5225dfecf96Smrg    }
5235dfecf96Smrg
5245dfecf96Smrg    if (flist.pixmap) {
5255dfecf96Smrg	Arg args[1];
5265dfecf96Smrg	Cardinal num_args;
5275dfecf96Smrg	int i;
5285dfecf96Smrg
5295dfecf96Smrg	num_args = 0;
5305dfecf96Smrg	XtSetArg(args[num_args], XtNleftBitmap, flist.pixmap);	++num_args;
5315dfecf96Smrg	XtSetValues(item->sme, args, num_args);
5325dfecf96Smrg
5335dfecf96Smrg	for (i = 0; i < 3; i++)
5345dfecf96Smrg	    if (XawTextGetSource(texts[i]) == item->source)
5355dfecf96Smrg		XtSetValues(labels[i], args, num_args);
5365dfecf96Smrg    }
5375dfecf96Smrg}
5385dfecf96Smrg
5395dfecf96Smrg/*	Function Name: ResetSourceChanged.
5405dfecf96Smrg *	Description: Sets the source changed to FALSE, and
5415dfecf96Smrg *                   registers a callback to set it to TRUE when
5425dfecf96Smrg *                   the source has changed.
5435dfecf96Smrg *	Arguments: item - item with widget to register the callback on.
5445dfecf96Smrg *	Returns: none.
5455dfecf96Smrg */
5465dfecf96Smrg
5475dfecf96Smrgvoid
5485dfecf96SmrgResetSourceChanged(xedit_flist_item *item)
5495dfecf96Smrg{
5505dfecf96Smrg    Arg args[1];
5515dfecf96Smrg    Cardinal num_args;
5525dfecf96Smrg    int i;
5535dfecf96Smrg
5545dfecf96Smrg    num_args = 0;
5555dfecf96Smrg    XtSetArg(args[num_args], XtNleftBitmap, None);	++num_args;
5565dfecf96Smrg    XtSetValues(item->sme, args, num_args);
5575dfecf96Smrg
5585dfecf96Smrg    dc_state = 0;
5595dfecf96Smrg    for (i = 0; i < 3; i++) {
5605dfecf96Smrg	if (XawTextGetSource(texts[i]) == item->source)
5615dfecf96Smrg	    XtSetValues(labels[i], args, num_args);
5625dfecf96Smrg	AddDoubleClickCallback(XawTextGetSource(texts[i]), False);
5635dfecf96Smrg    }
5645dfecf96Smrg
5655dfecf96Smrg    num_args = 0;
5665dfecf96Smrg    XtSetArg(args[num_args], XtNsourceChanged, False);	++num_args;
5675dfecf96Smrg    XtSetValues(item->source, args, num_args);
5685dfecf96Smrg
5695dfecf96Smrg    item->flags &= ~CHANGED_BIT;
5705dfecf96Smrg}
5715dfecf96Smrg
5725dfecf96Smrg/*ARGSUSED*/
5735dfecf96Smrgvoid
5745dfecf96SmrgKillFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
5755dfecf96Smrg{
5765dfecf96Smrg    xedit_flist_item *item = FindTextSource(XawTextGetSource(textwindow), NULL);
5775dfecf96Smrg
5785dfecf96Smrg    if (item->source == scratch) {
5795dfecf96Smrg	Feep();
5805dfecf96Smrg	return;
5815dfecf96Smrg    }
5825dfecf96Smrg
5835dfecf96Smrg    if (item->flags & CHANGED_BIT) {
584f14f4646Smrg	if (!(dc_state & DC_KILL)) {
5855dfecf96Smrg	    XeditPrintf("Kill: Unsaved changes. Kill again to override.\n");
5865dfecf96Smrg	    Feep();
587f14f4646Smrg	    dc_state |= DC_KILL;
5885dfecf96Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
5895dfecf96Smrg	    return;
5905dfecf96Smrg	}
591f14f4646Smrg	dc_state &= ~DC_KILL;
5925dfecf96Smrg    }
5935dfecf96Smrg    KillTextSource(item);
5945dfecf96Smrg}
5955dfecf96Smrg
5965dfecf96Smrg/*ARGSUSED*/
5975dfecf96Smrgvoid
5985dfecf96SmrgFindFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
5995dfecf96Smrg{
600f14f4646Smrg    char *string;
601f14f4646Smrg    char *slash;
6025dfecf96Smrg    XawTextBlock block;
6035dfecf96Smrg    XawTextPosition end = XawTextSourceScan(XawTextGetSource(filenamewindow),
6045dfecf96Smrg					    0, XawstAll, XawsdRight, 1, True);
6055dfecf96Smrg
606c05e22d7Smrg    slash = NULL;
607f14f4646Smrg    if (!line_edit) {
608f14f4646Smrg	string = GetString(filenamewindow);
609f14f4646Smrg	if (string)
610f14f4646Smrg	    slash = strrchr(string, '/');
611f14f4646Smrg    }
612f14f4646Smrg    else {
613f14f4646Smrg	string = "";
614f14f4646Smrg	line_edit = False;
615f14f4646Smrg    }
616f14f4646Smrg
6175dfecf96Smrg    block.firstPos = 0;
6185dfecf96Smrg    block.format = FMT8BIT;
6195dfecf96Smrg    block.ptr = string;
6205dfecf96Smrg    block.length = slash ? slash - string + 1 : 0;
6215dfecf96Smrg
6225dfecf96Smrg    if (block.length != end)
6235dfecf96Smrg	XawTextReplace(filenamewindow, 0, end, &block);
6245dfecf96Smrg    XawTextSetInsertionPoint(filenamewindow, end);
6255dfecf96Smrg    XtSetKeyboardFocus(topwindow, filenamewindow);
6265dfecf96Smrg}
6275dfecf96Smrg
6285dfecf96Smrg/*ARGSUSED*/
6295dfecf96Smrgvoid
6305dfecf96SmrgLoadFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
6315dfecf96Smrg{
6325dfecf96Smrg    if (line_edit)
6335dfecf96Smrg	LineEdit(textwindow);
6345dfecf96Smrg    else if (ReallyDoLoad(GetString(filenamewindow), ResolveName(NULL))) {
6355dfecf96Smrg	SwitchDirWindow(False);
6365dfecf96Smrg	XtSetKeyboardFocus(topwindow, textwindow);
6375dfecf96Smrg    }
6385dfecf96Smrg}
6395dfecf96Smrg
6405dfecf96Smrg/*ARGSUSED*/
6415dfecf96Smrgvoid
6425dfecf96SmrgCancelFindFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
6435dfecf96Smrg{
6445dfecf96Smrg    Arg args[1];
6455dfecf96Smrg    xedit_flist_item *item;
6465dfecf96Smrg
6475dfecf96Smrg    XtSetKeyboardFocus(topwindow, textwindow);
6485dfecf96Smrg
6495dfecf96Smrg    item = FindTextSource(XawTextGetSource(textwindow), NULL);
6505dfecf96Smrg
6515dfecf96Smrg    if (item->source != scratch)
6525dfecf96Smrg	XtSetArg(args[0], XtNstring, item->name);
6535dfecf96Smrg    else
6545dfecf96Smrg	XtSetArg(args[0], XtNstring, NULL);
6555dfecf96Smrg
6565dfecf96Smrg    XtSetValues(filenamewindow, args, 1);
657f14f4646Smrg    /* XXX This probably should be done by the TextWidget, i.e. notice
658f14f4646Smrg     * if the cursor became inivisible due to an horizontal scroll */
659f14f4646Smrg    _XawTextShowPosition((TextWidget)filenamewindow);
6605dfecf96Smrg
6615dfecf96Smrg   if (XtIsManaged(XtParent(dirwindow)))
6625dfecf96Smrg	SwitchDirWindow(False);
6635dfecf96Smrg
6645dfecf96Smrg    line_edit = False;
6655dfecf96Smrg}
6665dfecf96Smrg
6675dfecf96Smrgstatic int
6685dfecf96Smrgcompar(_Xconst void *a, _Xconst void *b)
6695dfecf96Smrg{
6705dfecf96Smrg    return (strcmp(*(char **)a, *(char **)b));
6715dfecf96Smrg}
6725dfecf96Smrg
6735dfecf96Smrg/*ARGSUSED*/
6745dfecf96Smrgvoid
6755dfecf96SmrgFileCompletion(Widget w, XEvent *event, String *params, Cardinal *num_params)
6765dfecf96Smrg{
6775dfecf96Smrg    XawTextBlock block;
6785dfecf96Smrg    String text;
6795dfecf96Smrg    int length;
6805dfecf96Smrg    char **matches, *save, *dir_name, *file_name, match[257];
6815dfecf96Smrg    unsigned n_matches, len, mlen, buflen;
6825dfecf96Smrg    DIR *dir;
6835dfecf96Smrg    Bool changed, slash = False, has_dot = False;
6845dfecf96Smrg#define	SM_NEVER	0
6855dfecf96Smrg#define SM_HINT		1
6865dfecf96Smrg#define SM_ALWAYS	2
6875dfecf96Smrg    int show_matches;
6885dfecf96Smrg
6895dfecf96Smrg    text = GetString(filenamewindow);
6905dfecf96Smrg
6915dfecf96Smrg    if (!text) {
6925dfecf96Smrg	Feep();
6935dfecf96Smrg	return;
6945dfecf96Smrg    }
6955dfecf96Smrg    else if (line_edit) {
6965dfecf96Smrg	Feep();
6975dfecf96Smrg	line_edit = 0;
6985dfecf96Smrg    }
6995dfecf96Smrg
7005dfecf96Smrg    {
7015dfecf96Smrg	XawTextPosition pos = XawTextGetInsertionPoint(w);
7025dfecf96Smrg	char *cslash = strchr(&text[pos], '/'), *cdot = strchr(&text[pos], '.');
7035dfecf96Smrg
7045dfecf96Smrg	if (cslash != NULL || cdot != NULL) {
7055dfecf96Smrg	    if (cslash != NULL && (cdot == NULL || cdot > cslash)) {
7065dfecf96Smrg		length = cslash - text;
7075dfecf96Smrg		slash = True;
7085dfecf96Smrg	    }
7095dfecf96Smrg	    else {
7105dfecf96Smrg		length = cdot - text;
7115dfecf96Smrg		has_dot = True;
7125dfecf96Smrg	    }
7135dfecf96Smrg	}
7145dfecf96Smrg	else
7155dfecf96Smrg	    length = strlen(text);
7165dfecf96Smrg    }
7175dfecf96Smrg
7185dfecf96Smrg    if (*num_params == 1 && length == strlen(text)) {
7195dfecf96Smrg	switch (params[0][0]) {
7205dfecf96Smrg	case 'n':		/* Never */
7215dfecf96Smrg	case 'N':
7225dfecf96Smrg	    show_matches = SM_NEVER;
7235dfecf96Smrg	    break;
7245dfecf96Smrg	case 'h':		/* Hint */
7255dfecf96Smrg	case 'H':
7265dfecf96Smrg	    show_matches = SM_HINT;
7275dfecf96Smrg	    break;
7285dfecf96Smrg	case 'a':		/* Always */
7295dfecf96Smrg	case 'A':
7305dfecf96Smrg	    show_matches = SM_ALWAYS;
7315dfecf96Smrg	    break;
7325dfecf96Smrg	default:
7335dfecf96Smrg	    show_matches = SM_NEVER;
7345dfecf96Smrg	    XtAppWarning(XtWidgetToApplicationContext(w),
7355dfecf96Smrg			 "Bad argument to file-completion, "
7365dfecf96Smrg			 "must be Never, Hint or Always");
7375dfecf96Smrg	    break;
7385dfecf96Smrg	}
7395dfecf96Smrg    }
7405dfecf96Smrg    else
7415dfecf96Smrg	show_matches = SM_NEVER;
7425dfecf96Smrg
7435dfecf96Smrg    matches = NULL;
7445dfecf96Smrg    n_matches = buflen = 0;
7455dfecf96Smrg    save = XtMalloc(length + 1);
7465dfecf96Smrg    memmove(save, text, length);
7475dfecf96Smrg    save[length] = '\0';
7485dfecf96Smrg
7495dfecf96Smrg    if (save[0] == '~' && save[1]) {
7505dfecf96Smrg	char *slash2 = strchr(save, '/');
7515dfecf96Smrg
7525dfecf96Smrg	if (slash2) {
7535dfecf96Smrg	    struct passwd *pw;
7545dfecf96Smrg	    char home[BUFSIZ];
7555dfecf96Smrg	    char *name;
7565dfecf96Smrg	    int slen = strlen(save), diff = slash2 - save;
7575dfecf96Smrg
7585dfecf96Smrg	    *slash2 = '\0';
7595dfecf96Smrg	    name = save + 1;
7605dfecf96Smrg	    if (strlen(name) != 0)
7615dfecf96Smrg		pw = getpwnam(name);
7625dfecf96Smrg	    else
7635dfecf96Smrg		pw = getpwuid(getuid());
7645dfecf96Smrg
7655dfecf96Smrg	    if (pw) {
7665dfecf96Smrg		char fname[BUFSIZ];
7675dfecf96Smrg		int hlen;
7685dfecf96Smrg
7695dfecf96Smrg		strncpy(home, pw->pw_dir, sizeof(home) - 1);
7705dfecf96Smrg		home[sizeof(home) - 1] = '\0';
7715dfecf96Smrg		hlen = strlen(home);
7725dfecf96Smrg		strncpy(fname, slash2 + 1, sizeof(fname) - 1);
7735dfecf96Smrg		fname[sizeof(fname) - 1] = '\0';
7745dfecf96Smrg		save = XtRealloc(save, slen - diff + hlen + 2);
7755dfecf96Smrg		(void)memmove(save, home, hlen);
7765dfecf96Smrg		save[hlen] = '/';
7775dfecf96Smrg		strcpy(&save[hlen + 1], fname);
7785dfecf96Smrg
7795dfecf96Smrg		/* expand directory */
7805dfecf96Smrg		block.length = strlen(save);
7815dfecf96Smrg		block.ptr = save;
7825dfecf96Smrg		block.firstPos = 0;
7835dfecf96Smrg		block.format = FMT8BIT;
7845dfecf96Smrg		XawTextReplace(filenamewindow, 0, length, &block);
7855dfecf96Smrg		XawTextSetInsertionPoint(filenamewindow, length = block.length);
7865dfecf96Smrg	    }
7875dfecf96Smrg	    else
7885dfecf96Smrg		*slash2 = '/';
7895dfecf96Smrg	}
7905dfecf96Smrg    }
7915dfecf96Smrg
7925dfecf96Smrg    if ((file_name = strrchr(save, '/')) != NULL) {
7935dfecf96Smrg	*file_name = '\0';
7945dfecf96Smrg	++file_name;
7955dfecf96Smrg	dir_name = save;
7965dfecf96Smrg	if (!file_name[0])
7975dfecf96Smrg	    slash = True;
7985dfecf96Smrg	if (!dir_name[0])
7995dfecf96Smrg	    dir_name = "/";
8005dfecf96Smrg    }
8015dfecf96Smrg    else {
8025dfecf96Smrg	dir_name = ".";
8035dfecf96Smrg	file_name = save;
8045dfecf96Smrg    }
8055dfecf96Smrg    len = strlen(file_name);
8065dfecf96Smrg
8075dfecf96Smrg    if ((dir = opendir(dir_name)) != NULL) {
8085dfecf96Smrg	char path[BUFSIZ], *pptr;
8095dfecf96Smrg	struct dirent *ent;
8105dfecf96Smrg	int isdir = 0, first = 1, bytes;
8115dfecf96Smrg
8125dfecf96Smrg	XmuSnprintf(path, sizeof(path), "%s/", dir_name);
8135dfecf96Smrg	pptr = path + strlen(path);
8145dfecf96Smrg	bytes = sizeof(path) - (pptr - path) - 1;
8155dfecf96Smrg
8165dfecf96Smrg	mlen = 0;
8175dfecf96Smrg	match[0] = '\0';
8185dfecf96Smrg	while ((ent = readdir(dir)) != NULL) {
8195dfecf96Smrg	    unsigned d_namlen = strlen(ent->d_name);
8205dfecf96Smrg
821f14f4646Smrg	    if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
822f14f4646Smrg		continue;
8235dfecf96Smrg	    if (d_namlen >= len && strncmp(ent->d_name, file_name, len) == 0) {
8245dfecf96Smrg		char *tmp = &(ent->d_name[len]), *mat = match;
8255dfecf96Smrg		struct stat st;
8265dfecf96Smrg		Bool is_dir = FALSE;
8275dfecf96Smrg
8285dfecf96Smrg		strncpy(pptr, ent->d_name, bytes);
8295dfecf96Smrg		pptr[bytes] = '\0';
8305dfecf96Smrg		if (stat(path, &st) != 0)
8315dfecf96Smrg		    /* Should check errno, may be a broken symbolic link
8325dfecf96Smrg		     * a directory with r-- permission, etc */
8335dfecf96Smrg		    continue;
8345dfecf96Smrg		else if (first || show_matches != SM_NEVER) {
8355dfecf96Smrg		    is_dir = S_ISDIR(st.st_mode);
8365dfecf96Smrg		}
8375dfecf96Smrg
8385dfecf96Smrg		if (first) {
8395dfecf96Smrg		    strncpy(match, tmp, sizeof(match) - 1);
8405dfecf96Smrg		    match[sizeof(match) - 2] = '\0';
8415dfecf96Smrg		    mlen = strlen(match);
8425dfecf96Smrg		    first = 0;
8435dfecf96Smrg		    isdir = is_dir;
8445dfecf96Smrg		}
8455dfecf96Smrg		else {
8465dfecf96Smrg		    while (*tmp && *mat && *tmp++ == *mat)
8475dfecf96Smrg			++mat;
8485dfecf96Smrg		    if (mlen > mat - match) {
8495dfecf96Smrg			mlen = mat - match;
8505dfecf96Smrg			match[mlen] = '\0';
8515dfecf96Smrg		    }
8525dfecf96Smrg		}
8535dfecf96Smrg		if (show_matches != SM_NEVER) {
8545dfecf96Smrg		    matches = (char **)XtRealloc((char*)matches, sizeof(char**)
8555dfecf96Smrg						 * (n_matches + 1));
8565dfecf96Smrg		    buflen += d_namlen + 1;
8575dfecf96Smrg		    if (is_dir) {
8585dfecf96Smrg			matches[n_matches] = XtMalloc(d_namlen + 2);
8595dfecf96Smrg			strcpy(matches[n_matches], ent->d_name);
8605dfecf96Smrg			strcat(matches[n_matches], "/");
8615dfecf96Smrg			++buflen;
8625dfecf96Smrg		    }
8635dfecf96Smrg		    else
8645dfecf96Smrg			matches[n_matches] = XtNewString(ent->d_name);
8655dfecf96Smrg		}
8665dfecf96Smrg		else if (mlen == 0 && n_matches >= 1) {
8675dfecf96Smrg		    ++n_matches;
8685dfecf96Smrg		    break;
8695dfecf96Smrg		}
8705dfecf96Smrg		++n_matches;
8715dfecf96Smrg	    }
8725dfecf96Smrg	}
8735dfecf96Smrg
8745dfecf96Smrg	closedir(dir);
8755dfecf96Smrg	changed = mlen != 0;
8765dfecf96Smrg
877f14f4646Smrg	if (first || n_matches) {
8785dfecf96Smrg	    Bool free_matches = True, add_slash = n_matches == 1 && isdir && !slash;
8795dfecf96Smrg
8805dfecf96Smrg	    if (mlen && has_dot && match[mlen - 1] == '.')
8815dfecf96Smrg		--mlen;
8825dfecf96Smrg
8835dfecf96Smrg	    if (mlen || add_slash) {
8845dfecf96Smrg		XawTextPosition pos;
8855dfecf96Smrg
8865dfecf96Smrg		block.firstPos = 0;
8875dfecf96Smrg		block.format = FMT8BIT;
8885dfecf96Smrg		if (mlen) {
8895dfecf96Smrg		    pos = length;
8905dfecf96Smrg		    block.length = mlen;
8915dfecf96Smrg		    block.ptr = match;
8925dfecf96Smrg		    XawTextReplace(filenamewindow, pos, pos, &block);
8935dfecf96Smrg		    XawTextSetInsertionPoint(filenamewindow, pos + block.length);
8945dfecf96Smrg		}
8955dfecf96Smrg		if (add_slash) {
8965dfecf96Smrg		    XawTextPosition actual = XawTextGetInsertionPoint(w);
8975dfecf96Smrg
8985dfecf96Smrg		    pos = XawTextSourceScan(XawTextGetSource(w), 0, XawstAll,
8995dfecf96Smrg					    XawsdRight, 1, True);
9005dfecf96Smrg		    block.length = 1;
9015dfecf96Smrg		    block.ptr = "/";
9025dfecf96Smrg		    XawTextReplace(filenamewindow, pos, pos, &block);
9035dfecf96Smrg		    if (actual == pos)
9045dfecf96Smrg			XawTextSetInsertionPoint(filenamewindow, pos + 1);
9055dfecf96Smrg		}
9065dfecf96Smrg	    }
9075dfecf96Smrg	    else if (n_matches != 1 || isdir) {
9085dfecf96Smrg		if (show_matches == SM_NEVER)
9095dfecf96Smrg		    Feep();
9105dfecf96Smrg	    }
9115dfecf96Smrg
9125dfecf96Smrg	    if (show_matches != SM_NEVER) {
9135dfecf96Smrg		if (show_matches == SM_ALWAYS || (!changed && n_matches != 1)) {
9145dfecf96Smrg		    char **list = NULL, *label;
9155dfecf96Smrg		    int n_list;
9165dfecf96Smrg		    Arg args[2];
9175dfecf96Smrg
9185dfecf96Smrg		    XtSetArg(args[0], XtNlist, &list);
9195dfecf96Smrg		    XtSetArg(args[1], XtNnumberStrings, &n_list);
9205dfecf96Smrg		    XtGetValues(dirwindow, args, 2);
9215dfecf96Smrg
9225dfecf96Smrg		    matches = (char **)XtRealloc((char*)matches, sizeof(char**)
9235dfecf96Smrg						 * (n_matches + 2));
9245dfecf96Smrg		    matches[n_matches++] = XtNewString("./");
9255dfecf96Smrg		    matches[n_matches++] = XtNewString("../");
9265dfecf96Smrg		    qsort(matches, n_matches, sizeof(char*), compar);
9275dfecf96Smrg		    XtSetArg(args[0], XtNlist, matches);
9285dfecf96Smrg		    XtSetArg(args[1], XtNnumberStrings, n_matches);
9295dfecf96Smrg		    XtSetValues(dirwindow, args, 2);
9305dfecf96Smrg		    if (n_list > 0
9315dfecf96Smrg			&& (n_list != 1 || list[0] != XtName(dirwindow))) {
9325dfecf96Smrg			while (--n_list > -1)
9335dfecf96Smrg			    XtFree(list[n_list]);
9345dfecf96Smrg			XtFree((char*)list);
9355dfecf96Smrg		    }
9365dfecf96Smrg
9375dfecf96Smrg		    label = ResolveName(dir_name);
9385dfecf96Smrg		    XtSetArg(args[0], XtNlabel, label);
9395dfecf96Smrg		    XtSetValues(dirlabel, args, 1);
9405dfecf96Smrg		    SwitchDirWindow(True);
9415dfecf96Smrg		    free_matches = False;
9425dfecf96Smrg		}
9435dfecf96Smrg	    }
9445dfecf96Smrg	    if (free_matches && matches) {
9455dfecf96Smrg		while (--n_matches > -1)
9465dfecf96Smrg		    XtFree(matches[n_matches]);
9475dfecf96Smrg		XtFree((char*)matches);
9485dfecf96Smrg	    }
9495dfecf96Smrg	}
9505dfecf96Smrg	else
9515dfecf96Smrg	    Feep();
9525dfecf96Smrg    }
9535dfecf96Smrg    else
9545dfecf96Smrg	Feep();
9555dfecf96Smrg
9565dfecf96Smrg    XtFree(save);
9575dfecf96Smrg}
9585dfecf96Smrg
9595dfecf96Smrg/*ARGSUSED*/
9605dfecf96Smrgvoid
9615dfecf96SmrgDirWindowCB(Widget w, XtPointer user_data, XtPointer call_data)
9625dfecf96Smrg{
9635dfecf96Smrg    XawListReturnStruct *file_info = (XawListReturnStruct *)call_data;
9645dfecf96Smrg    char *dir_name, *string, path[BUFSIZ];
9655dfecf96Smrg    Arg args[2];
9665dfecf96Smrg
9675dfecf96Smrg    if (file_info == NULL)
9685dfecf96Smrg	string = (char *)user_data;
9695dfecf96Smrg    else
9705dfecf96Smrg	string = file_info->string;
9715dfecf96Smrg
9725dfecf96Smrg    XtSetArg(args[0], XtNlabel, &dir_name);
9735dfecf96Smrg    XtGetValues(dirlabel, args, 1);
9745dfecf96Smrg    if (*dir_name == '\0') {
9755dfecf96Smrg	strncpy(path, string, sizeof(path) - 1);
9765dfecf96Smrg	path[sizeof(path) - 1] = '\0';
9775dfecf96Smrg    }
9785dfecf96Smrg    else if (strcmp(dir_name, "/") == 0)
9795dfecf96Smrg	XmuSnprintf(path, sizeof(path), "/%s", string);
9805dfecf96Smrg    else
9815dfecf96Smrg	XmuSnprintf(path, sizeof(path), "%s/%s", dir_name, string);
9825dfecf96Smrg
9835dfecf96Smrg    if (*string && string[strlen(string) - 1] == '/') {
9845dfecf96Smrg	DIR *dir;
9855dfecf96Smrg
9865dfecf96Smrg	if ((dir = opendir(path)) != NULL) {
9875dfecf96Smrg	    struct dirent *ent;
9885dfecf96Smrg	    struct stat st;
9895dfecf96Smrg	    unsigned d_namlen;
9905dfecf96Smrg	    Bool isdir;
9915dfecf96Smrg	    char **entries = NULL, **list = NULL;
9925dfecf96Smrg	    int n_entries = 0, n_list = 0;
9935dfecf96Smrg	    char *label, *pptr = path + strlen(path);
9945dfecf96Smrg	    int bytes = sizeof(path) - (pptr - path) - 1;
9955dfecf96Smrg
9965dfecf96Smrg	    while ((ent = readdir(dir)) != NULL) {
9975dfecf96Smrg		d_namlen = strlen(ent->d_name);
9985dfecf96Smrg		strncpy(pptr, ent->d_name, bytes);
9995dfecf96Smrg		pptr[bytes] = '\0';
10005dfecf96Smrg		if (stat(path, &st) != 0)
10015dfecf96Smrg		    /* Should check errno, may be a broken symbolic link
10025dfecf96Smrg		     * a directory with r-- permission, etc */
10035dfecf96Smrg		    continue;
10045dfecf96Smrg		else
10055dfecf96Smrg		    isdir = S_ISDIR(st.st_mode);
10065dfecf96Smrg
10075dfecf96Smrg		entries = (char **)XtRealloc((char*)entries, sizeof(char*)
10085dfecf96Smrg					     * (n_entries + 1));
10095dfecf96Smrg		if (isdir) {
10105dfecf96Smrg		    entries[n_entries] = XtMalloc(d_namlen + 2);
10115dfecf96Smrg		    strcpy(entries[n_entries], ent->d_name);
10125dfecf96Smrg		    strcat(entries[n_entries], "/");
10135dfecf96Smrg		}
10145dfecf96Smrg		else
10155dfecf96Smrg		    entries[n_entries] = XtNewString(ent->d_name);
10165dfecf96Smrg		++n_entries;
10175dfecf96Smrg	    }
10185dfecf96Smrg	    closedir(dir);
10195dfecf96Smrg
10205dfecf96Smrg	    XtSetArg(args[0], XtNlist, &list);
10215dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, &n_list);
10225dfecf96Smrg	    XtGetValues(dirwindow, args, 2);
10235dfecf96Smrg
10245dfecf96Smrg	    if (n_entries == 0) {
10255dfecf96Smrg		entries = (char**)XtMalloc(sizeof(char*) * 2);
10265dfecf96Smrg		/* Directory has read but not execute permission? */
10275dfecf96Smrg		entries[n_entries++] = XtNewString("./");
10285dfecf96Smrg		entries[n_entries++] = XtNewString("../");
10295dfecf96Smrg	    }
10305dfecf96Smrg	    qsort(entries, n_entries, sizeof(char*), compar);
10315dfecf96Smrg	    XtSetArg(args[0], XtNlist, entries);
10325dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, n_entries);
10335dfecf96Smrg	    XtSetValues(dirwindow, args, 2);
10345dfecf96Smrg	    if (n_list > 0
10355dfecf96Smrg		&& (n_list != 1 || list[0] != XtName(dirwindow))) {
10365dfecf96Smrg		while (--n_list > -1)
10375dfecf96Smrg		    XtFree(list[n_list]);
10385dfecf96Smrg		XtFree((char*)list);
10395dfecf96Smrg	    }
10405dfecf96Smrg
10415dfecf96Smrg	    *pptr = '\0';
10425dfecf96Smrg	    if ((label = ResolveName(path)) == NULL) {
10435dfecf96Smrg		Feep();
10445dfecf96Smrg		label = path;
10455dfecf96Smrg	    }
10465dfecf96Smrg	    XtSetArg(args[0], XtNlabel, label);
10475dfecf96Smrg	    XtSetValues(dirlabel, args, 1);
10485dfecf96Smrg
10495dfecf96Smrg	    strncpy(path, label, sizeof(path) - 2);
10505dfecf96Smrg	    if (*path && path[strlen(path) - 1] != '/')
10515dfecf96Smrg		strcat(path, "/");
10525dfecf96Smrg	    XtSetArg(args[0], XtNstring, path);
10535dfecf96Smrg	    XtSetValues(filenamewindow, args, 1);
10545dfecf96Smrg	    XtSetKeyboardFocus(topwindow, filenamewindow);
10555dfecf96Smrg	    XawTextSetInsertionPoint(filenamewindow, strlen(path));
10565dfecf96Smrg	}
10575dfecf96Smrg	else
10585dfecf96Smrg	    Feep();
10595dfecf96Smrg    }
10605dfecf96Smrg    else {
1061c05e22d7Smrg	(void)ReallyDoLoad(path, ResolveName(path));
10625dfecf96Smrg	SwitchDirWindow(False);
10635dfecf96Smrg	XtSetKeyboardFocus(topwindow, textwindow);
10645dfecf96Smrg    }
10655dfecf96Smrg}
1066