commands.c revision f14f4646
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#ifdef INCLUDE_XPRINT_SUPPORT
335dfecf96Smrg#include "printdialog.h"
345dfecf96Smrg#include "print.h"
355dfecf96Smrg#endif /* INCLUDE_XPRINT_SUPPORT */
365dfecf96Smrg#ifdef CRAY
375dfecf96Smrg#include <unistd.h>
385dfecf96Smrg#endif
395dfecf96Smrg#include <stdlib.h>
405dfecf96Smrg#include <stdio.h>
415dfecf96Smrg#include <limits.h>
425dfecf96Smrg#include <string.h>
435dfecf96Smrg#include <dirent.h>
445dfecf96Smrg#include <pwd.h>
455dfecf96Smrg#include <sys/stat.h>
465dfecf96Smrg#include <X11/Xmu/SysUtil.h>
475dfecf96Smrg#include <X11/IntrinsicP.h>
485dfecf96Smrg#include <X11/Xaw/TextSrcP.h>
495dfecf96Smrg
505dfecf96Smrg/* Turn a NULL pointer string into an empty string */
515dfecf96Smrg#define NULLSTR(x) (((x)!=NULL)?(x):(""))
525dfecf96Smrg
535dfecf96Smrg#define Error(x) { printf x ; exit(EXIT_FAILURE); }
545dfecf96Smrg#define Assertion(expr, msg) { if (!(expr)) { Error msg } }
555dfecf96Smrg#define Log(x)   { if (True) printf x; }
565dfecf96Smrg
575dfecf96Smrg#ifdef INCLUDE_XPRINT_SUPPORT
585dfecf96Smrgstatic Widget printdialog_shell = NULL;
595dfecf96Smrgstatic Widget printdialog       = NULL;
605dfecf96Smrgstatic char   printJobNameBuffer[PATH_MAX+256];
615dfecf96Smrg#endif /* INCLUDE_XPRINT_SUPPORT */
625dfecf96Smrg
635dfecf96Smrgvoid ResetSourceChanged(xedit_flist_item*);
645dfecf96Smrgstatic void ResetDC(Widget, XtPointer, XtPointer);
655dfecf96Smrg
665dfecf96Smrgstatic void AddDoubleClickCallback(Widget, Bool);
675dfecf96Smrgstatic Bool ReallyDoLoad(char*, char*);
685dfecf96Smrgstatic char *makeBackupName(String, String, unsigned);
695dfecf96Smrg
70f14f4646Smrg/*
71f14f4646Smrg * External
72f14f4646Smrg */
73f14f4646Smrgextern void _XawTextShowPosition(TextWidget);
74f14f4646Smrg
755dfecf96Smrgextern Widget scratch, texts[3], labels[3];
765dfecf96Smrg
77f14f4646Smrg#define DC_UNSAVED	(1 << 0)
78f14f4646Smrg#define DC_LOADED	(1 << 1)
79f14f4646Smrg#define DC_CLOBBER	(1 << 2)
80f14f4646Smrg#define DC_KILL		(1 << 3)
81f14f4646Smrg#define DC_SAVE		(1 << 4)
82f14f4646Smrg#define DC_NEWER	(1 << 5)
835dfecf96Smrgstatic int dc_state;
845dfecf96Smrg
855dfecf96Smrgstatic void
865dfecf96SmrgAddDoubleClickCallback(Widget w, Bool state)
875dfecf96Smrg{
88f14f4646Smrg    if (state)
89f14f4646Smrg	XtAddCallback(w, XtNcallback, ResetDC, NULL);
90f14f4646Smrg    else
91f14f4646Smrg	XtRemoveCallback(w, XtNcallback, ResetDC, NULL);
925dfecf96Smrg}
935dfecf96Smrg
945dfecf96Smrg/*	Function Name: ResetDC
955dfecf96Smrg *	Description: Resets the double click flag.
965dfecf96Smrg *	Arguments: w - the text widget.
975dfecf96Smrg *                 junk, garbage - *** NOT USED ***
985dfecf96Smrg *	Returns: none.
995dfecf96Smrg */
1005dfecf96Smrg
1015dfecf96Smrg/* ARGSUSED */
1025dfecf96Smrgstatic void
1035dfecf96SmrgResetDC(Widget w, XtPointer junk, XtPointer garbage)
1045dfecf96Smrg{
105f14f4646Smrg    AddDoubleClickCallback(w, FALSE);
1065dfecf96Smrg}
1075dfecf96Smrg
1085dfecf96Smrg/*ARGSUSED*/
1095dfecf96Smrgvoid
1105dfecf96SmrgQuitAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
1115dfecf96Smrg{
1125dfecf96Smrg    DoQuit(w, NULL, NULL);
1135dfecf96Smrg}
1145dfecf96Smrg
1155dfecf96Smrg/*ARGSUSED*/
1165dfecf96Smrgvoid
1175dfecf96SmrgDoQuit(Widget w, XtPointer client_data, XtPointer call_data)
1185dfecf96Smrg{
1195dfecf96Smrg    unsigned i;
1205dfecf96Smrg    Bool source_changed = False;
1215dfecf96Smrg
122f14f4646Smrg    if (!(dc_state & DC_UNSAVED)) {
1235dfecf96Smrg	for (i = 0; i < flist.num_itens; i++)
1245dfecf96Smrg	    if (flist.itens[i]->flags & CHANGED_BIT) {
1255dfecf96Smrg		source_changed = True;
1265dfecf96Smrg		break;
1275dfecf96Smrg	    }
1285dfecf96Smrg    }
129f14f4646Smrg    if (!source_changed) {
1305dfecf96Smrg#ifndef __UNIXOS2__
1315dfecf96Smrg	XeditLispCleanUp();
1325dfecf96Smrg#endif
1335dfecf96Smrg	exit(0);
1345dfecf96Smrg    }
1355dfecf96Smrg
1365dfecf96Smrg    XeditPrintf("Unsaved changes. Save them, or Quit again.\n");
1375dfecf96Smrg    Feep();
138f14f4646Smrg    dc_state |= DC_UNSAVED;
1395dfecf96Smrg    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
1405dfecf96Smrg}
1415dfecf96Smrg
1425dfecf96Smrgstatic char *
1435dfecf96SmrgmakeBackupName(String buf, String filename, unsigned len)
1445dfecf96Smrg{
1455dfecf96Smrg    if (app_resources.backupNamePrefix
1465dfecf96Smrg	&& strlen(app_resources.backupNamePrefix)) {
1475dfecf96Smrg	if (strchr(app_resources.backupNamePrefix, '/'))
1485dfecf96Smrg	    XmuSnprintf(buf, len, "%s%s%s", app_resources.backupNamePrefix,
1495dfecf96Smrg			filename, app_resources.backupNameSuffix);
1505dfecf96Smrg	else {
1515dfecf96Smrg	    char fname[BUFSIZ];
1525dfecf96Smrg	    char *name, ch;
1535dfecf96Smrg
1545dfecf96Smrg	    strncpy(fname, filename, sizeof(fname) - 1);
1555dfecf96Smrg	    fname[sizeof(fname) - 1] = '\0';
1565dfecf96Smrg	    if ((name = strrchr(fname, '/')) != NULL)
1575dfecf96Smrg		++name;
1585dfecf96Smrg	    else
1595dfecf96Smrg		name = filename;
1605dfecf96Smrg	    ch = *name;
1615dfecf96Smrg	    *name = '\0';
1625dfecf96Smrg	    ++name;
1635dfecf96Smrg	    XmuSnprintf(buf, len, "%s%s%c%s%s",
1645dfecf96Smrg			fname, app_resources.backupNamePrefix, ch, name,
1655dfecf96Smrg			app_resources.backupNameSuffix);
1665dfecf96Smrg	}
1675dfecf96Smrg    }
1685dfecf96Smrg    else
1695dfecf96Smrg	XmuSnprintf(buf, len, "%s%s",
1705dfecf96Smrg		    filename, app_resources.backupNameSuffix);
1715dfecf96Smrg
1725dfecf96Smrg    return (strcmp(filename, buf) ? buf : NULL);
1735dfecf96Smrg}
1745dfecf96Smrg
1755dfecf96Smrg#if defined(USG) && !defined(CRAY)
1765dfecf96Smrgint rename (from, to)
1775dfecf96Smrg    char *from, *to;
1785dfecf96Smrg{
1795dfecf96Smrg    (void) unlink (to);
1805dfecf96Smrg    if (link (from, to) == 0) {
1815dfecf96Smrg        unlink (from);
1825dfecf96Smrg        return 0;
1835dfecf96Smrg    } else {
1845dfecf96Smrg        return -1;
1855dfecf96Smrg    }
1865dfecf96Smrg}
1875dfecf96Smrg#endif
1885dfecf96Smrg
1895dfecf96Smrg/*ARGSUSED*/
1905dfecf96Smrgvoid
1915dfecf96SmrgSaveFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
1925dfecf96Smrg{
193f14f4646Smrg    if (line_edit) {
194f14f4646Smrg	/* Don't try to save buffer with regex string.
195f14f4646Smrg	 * Call CancelFindFile() to leave line_edit mode.
196f14f4646Smrg	 */
197f14f4646Smrg	XeditPrintf("Save: Leaving line edit mode -- nothing saved.\n");
198f14f4646Smrg	CancelFindFile(w, event, params, num_params);
199f14f4646Smrg	Feep();
200f14f4646Smrg    }
201f14f4646Smrg    else
202f14f4646Smrg	DoSave(w, NULL, NULL);
2035dfecf96Smrg}
2045dfecf96Smrg
2055dfecf96Smrg/*ARGSUSED*/
2065dfecf96Smrgvoid
2075dfecf96SmrgDoSave(Widget w, XtPointer client_data, XtPointer call_data)
2085dfecf96Smrg{
2095dfecf96Smrg    String name = GetString(filenamewindow);
2105dfecf96Smrg    String filename = ResolveName(name);
2115dfecf96Smrg    FileAccess file_access;
2125dfecf96Smrg    xedit_flist_item *item;
2135dfecf96Smrg    Boolean exists;
2145dfecf96Smrg    Widget source = XawTextGetSource(textwindow);
215f14f4646Smrg    char buffer[BUFSIZ];
216f14f4646Smrg    struct stat st;
217f14f4646Smrg    static char *nothing_saved = " -- nothing saved.\n";
2185dfecf96Smrg
2195dfecf96Smrg    if (!filename) {
220f14f4646Smrg	XmuSnprintf(buffer, sizeof(buffer), "%s%s",
221f14f4646Smrg		    "Save: Can't resolve pathname",  nothing_saved);
222f14f4646Smrg	goto error;
2235dfecf96Smrg    }
2245dfecf96Smrg    else if (*name == '\0') {
225f14f4646Smrg	XmuSnprintf(buffer, sizeof(buffer), "%s%s",
226f14f4646Smrg		    "Save: No filename specified", nothing_saved);
227f14f4646Smrg	goto error;
2285dfecf96Smrg    }
2295dfecf96Smrg
2305dfecf96Smrg    item = FindTextSource(NULL, filename);
2315dfecf96Smrg    if (item != NULL && item->source != source) {
232f14f4646Smrg	if (!(dc_state & DC_LOADED)) {
233f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s%s%s",
234f14f4646Smrg			"Save: file ", name, " is already loaded, "
235f14f4646Smrg			"Save again to unload it", nothing_saved);
2365dfecf96Smrg	    Feep();
237f14f4646Smrg	    dc_state |= DC_LOADED;
2385dfecf96Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
239f14f4646Smrg	    goto error;
240f14f4646Smrg	}
241f14f4646Smrg	else {
242f14f4646Smrg	    KillTextSource(item);
243f14f4646Smrg	    item = FindTextSource(source = XawTextGetSource(textwindow), NULL);
244f14f4646Smrg	    dc_state &= ~DC_LOADED;
2455dfecf96Smrg	}
2465dfecf96Smrg    }
2475dfecf96Smrg    else if (item && !(item->flags & CHANGED_BIT)) {
248f14f4646Smrg	if (!(dc_state & DC_SAVE)) {
249f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s",
250f14f4646Smrg			"Save: No changes need to be saved, "
251f14f4646Smrg			"save again to override", nothing_saved);
2525dfecf96Smrg	    Feep();
253f14f4646Smrg	    dc_state |= DC_SAVE;
2545dfecf96Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
255f14f4646Smrg	    goto error;
2565dfecf96Smrg	}
257f14f4646Smrg	else
258f14f4646Smrg	    dc_state &= ~DC_SAVE;
2595dfecf96Smrg    }
2605dfecf96Smrg
2615dfecf96Smrg    file_access = CheckFilePermissions(filename, &exists);
262f14f4646Smrg    if (exists) {
263f14f4646Smrg	if (stat(filename, &st) != 0) {
264f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s%s",
265f14f4646Smrg			"Save: cannot stat ", name, nothing_saved);
266f14f4646Smrg	    goto error;
267f14f4646Smrg	}
268f14f4646Smrg	else if (!S_ISREG(st.st_mode)) {
269f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s%s%s",
270f14f4646Smrg			"Save: file ", name, "is not a regular file",
271f14f4646Smrg			nothing_saved);
272f14f4646Smrg	    goto error;
273f14f4646Smrg	}
274f14f4646Smrg    }
275f14f4646Smrg
2765dfecf96Smrg    if (!item || strcmp(item->filename, filename)) {
2775dfecf96Smrg	if (file_access == WRITE_OK && exists) {
278f14f4646Smrg	    if (!(dc_state & DC_CLOBBER)) {
279f14f4646Smrg		XmuSnprintf(buffer, sizeof(buffer), "%s%s%s%s",
280f14f4646Smrg			    "Save: file ", name, " already exists, "
281f14f4646Smrg			    "save again to override", nothing_saved);
2825dfecf96Smrg		Feep();
283f14f4646Smrg		dc_state |= DC_CLOBBER;
2845dfecf96Smrg		AddDoubleClickCallback(XawTextGetSource(textwindow), True);
285f14f4646Smrg		goto error;
2865dfecf96Smrg	    }
287f14f4646Smrg	    else
288f14f4646Smrg		dc_state &= ~DC_CLOBBER;
2895dfecf96Smrg	}
2905dfecf96Smrg	if (!item)
2915dfecf96Smrg	    item = FindTextSource(source, NULL);
2925dfecf96Smrg    }
2935dfecf96Smrg
294f14f4646Smrg    if (item && item->mtime && exists && item->mtime < st.st_mtime) {
295f14f4646Smrg	if (!(dc_state & DC_NEWER)) {
296f14f4646Smrg	    XmuSnprintf(buffer, sizeof(buffer), "%s%s",
297f14f4646Smrg			"Save: Newer file exists, "
298f14f4646Smrg			"save again to override", nothing_saved);
299f14f4646Smrg	    Feep();
300f14f4646Smrg	    dc_state |= DC_NEWER;
301f14f4646Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
302f14f4646Smrg	    goto error;
303f14f4646Smrg	}
304f14f4646Smrg	else
305f14f4646Smrg	    dc_state &= DC_NEWER;
306f14f4646Smrg    }
307f14f4646Smrg
308f14f4646Smrg    if (app_resources.enableBackups && exists) {
309f14f4646Smrg	char backup_file[BUFSIZ];
310f14f4646Smrg
311f14f4646Smrg	if (makeBackupName(backup_file, filename, sizeof(backup_file)) == NULL
312f14f4646Smrg	    || rename(filename, backup_file) != 0) {
313f14f4646Smrg	    XeditPrintf("Error backing up file: %s\n", filename);
314f14f4646Smrg	}
315f14f4646Smrg    }
316f14f4646Smrg
317f14f4646Smrg    switch (file_access = MaybeCreateFile(filename)) {
318f14f4646Smrg	case NO_READ:
319f14f4646Smrg	case READ_OK:
320f14f4646Smrg	    XeditPrintf("File %s could not be opened for writing.\n", name);
321f14f4646Smrg	    Feep();
322f14f4646Smrg	    break;
323f14f4646Smrg	case WRITE_OK:
324f14f4646Smrg	    if (XawAsciiSaveAsFile(source, filename)) {
325f14f4646Smrg		int i;
326f14f4646Smrg		Arg args[1];
327f14f4646Smrg
328f14f4646Smrg		XmuSnprintf(buffer, sizeof(buffer),
329f14f4646Smrg			    "%s       Read - Write", name);
330f14f4646Smrg		XtSetArg(args[0], XtNlabel, buffer);
331f14f4646Smrg		for (i = 0; i < 3; i++)
332f14f4646Smrg		    if (XawTextGetSource(texts[i]) == source)
333f14f4646Smrg			XtSetValues(labels[i], args, 1);
334f14f4646Smrg
335f14f4646Smrg		XeditPrintf("Saved file: %s\n", name);
336f14f4646Smrg
337f14f4646Smrg		if (item && item->source != scratch) {
338f14f4646Smrg		    XtSetArg(args[0], XtNlabel, filename);
339f14f4646Smrg		    XtSetValues(item->sme, args, 1);
340f14f4646Smrg
341f14f4646Smrg		    XtSetArg(args[0], XtNeditType, XawtextEdit);
342f14f4646Smrg		    XtSetValues(item->source, args, 1);
343f14f4646Smrg
344f14f4646Smrg		    XtFree(item->name);
345f14f4646Smrg		    XtFree(item->filename);
346f14f4646Smrg		    item->name = XtNewString(name);
347f14f4646Smrg		    item->filename = XtNewString(filename);
348f14f4646Smrg		    item->flags = EXISTS_BIT;
349f14f4646Smrg		}
350f14f4646Smrg		else {
351f14f4646Smrg		    item = flist.itens[0];
352f14f4646Smrg		    XtRemoveCallback(scratch, XtNcallback, SourceChanged,
353f14f4646Smrg				     (XtPointer)item);
354f14f4646Smrg		    item->source = scratch =
355f14f4646Smrg		    XtVaCreateWidget("textSource", international ?
356f14f4646Smrg				     multiSrcObjectClass :
357f14f4646Smrg				     asciiSrcObjectClass,
358f14f4646Smrg				     topwindow,
359f14f4646Smrg				     XtNtype, XawAsciiFile,
360f14f4646Smrg				     XtNeditType, XawtextEdit,
361f14f4646Smrg				     NULL, NULL);
362f14f4646Smrg		    ResetSourceChanged(item);
363f14f4646Smrg		    XtAddCallback(scratch, XtNcallback, SourceChanged,
364f14f4646Smrg				  (XtPointer)item);
365f14f4646Smrg
366f14f4646Smrg		    item = AddTextSource(source, name, filename, EXISTS_BIT,
367f14f4646Smrg					 file_access);
368f14f4646Smrg		    XtAddCallback(item->source, XtNcallback, SourceChanged,
369f14f4646Smrg				  (XtPointer)item);
370f14f4646Smrg		}
371f14f4646Smrg
372f14f4646Smrg		/* Keep file protection mode */
373f14f4646Smrg		if (item->mode)
374f14f4646Smrg		    chmod(filename, item->mode);
375f14f4646Smrg
376f14f4646Smrg		/* Remember time of last modification */
377f14f4646Smrg		if (stat(filename, &st) == 0)
378f14f4646Smrg		    item->mtime = st.st_mtime;
379f14f4646Smrg
380f14f4646Smrg		item->flags |= EXISTS_BIT;
381f14f4646Smrg		ResetSourceChanged(item);
382f14f4646Smrg	    }
383f14f4646Smrg	    else {
384f14f4646Smrg		XeditPrintf("Error saving file: %s\n",  name);
385f14f4646Smrg		Feep();
386f14f4646Smrg	    }
387f14f4646Smrg	    break;
388f14f4646Smrg	default:
389f14f4646Smrg	    Feep();
390f14f4646Smrg	    break;
3915dfecf96Smrg    }
3925dfecf96Smrg
393f14f4646Smrg    return;
394f14f4646Smrgerror:
395f14f4646Smrg    XeditPrintf("%s", buffer);
396f14f4646Smrg    Feep();
3975dfecf96Smrg}
3985dfecf96Smrg
3995dfecf96Smrg/*ARGSUSED*/
4005dfecf96Smrgvoid
4015dfecf96SmrgDoLoad(Widget w, XtPointer client_data, XtPointer call_data)
4025dfecf96Smrg{
4035dfecf96Smrg    if (ReallyDoLoad(GetString(filenamewindow), ResolveName(NULL))) {
4045dfecf96Smrg        SwitchDirWindow(False);
4055dfecf96Smrg        XtSetKeyboardFocus(topwindow, textwindow);
4065dfecf96Smrg    }
4075dfecf96Smrg}
4085dfecf96Smrg
409f14f4646SmrgBool
410f14f4646SmrgLoadFileInTextwindow(char *name, char *resolved_name)
411f14f4646Smrg{
412f14f4646Smrg    return (ReallyDoLoad(name, resolved_name));
413f14f4646Smrg}
414f14f4646Smrg
4155dfecf96Smrgstatic Bool
4165dfecf96SmrgReallyDoLoad(char *name, char *filename)
4175dfecf96Smrg{
4185dfecf96Smrg    Arg args[5];
4195dfecf96Smrg    Cardinal num_args = 0;
4205dfecf96Smrg    xedit_flist_item *item;
4215dfecf96Smrg    Widget source = XawTextGetSource(textwindow);
4225dfecf96Smrg
4235dfecf96Smrg    if (!filename) {
4245dfecf96Smrg	XeditPrintf("Load: Can't resolve pathname.\n");
4255dfecf96Smrg	Feep();
4265dfecf96Smrg	return (False);
4275dfecf96Smrg    }
4285dfecf96Smrg    else if (*name == '\0') {
4295dfecf96Smrg	XeditPrintf("Load: No file specified.\n");
4305dfecf96Smrg	Feep();
4315dfecf96Smrg    }
4325dfecf96Smrg    if ((item = FindTextSource(NULL, filename)) != NULL) {
4335dfecf96Smrg	SwitchTextSource(item);
4345dfecf96Smrg	return (True);
4355dfecf96Smrg    }
4365dfecf96Smrg    else {
4375dfecf96Smrg	struct stat st;
4385dfecf96Smrg
4395dfecf96Smrg	if (stat(filename, &st) == 0 && !S_ISREG(st.st_mode)) {
4405dfecf96Smrg	    if (S_ISDIR(st.st_mode)) {
4415dfecf96Smrg		char path[BUFSIZ + 1];
4425dfecf96Smrg
4435dfecf96Smrg		strncpy(path, filename, sizeof(path) - 2);
4445dfecf96Smrg		path[sizeof(path) - 2] = '\0';
4455dfecf96Smrg		if (*path) {
4465dfecf96Smrg		    if (path[strlen(path) - 1] != '/')
4475dfecf96Smrg			strcat(path, "/");
4485dfecf96Smrg		}
4495dfecf96Smrg		else
4505dfecf96Smrg		    strcpy(path, "./");
4515dfecf96Smrg		XtSetArg(args[0], XtNlabel, "");
4525dfecf96Smrg		XtSetValues(dirlabel, args, 1);
4535dfecf96Smrg		SwitchDirWindow(True);
4545dfecf96Smrg		DirWindowCB(dirwindow, path, NULL);
4555dfecf96Smrg		return (False);
4565dfecf96Smrg	    }
4575dfecf96Smrg	}
4585dfecf96Smrg    }
4595dfecf96Smrg
4605dfecf96Smrg    {
4615dfecf96Smrg	Boolean exists;
4625dfecf96Smrg	int flags;
4635dfecf96Smrg	FileAccess file_access;
4645dfecf96Smrg
4655dfecf96Smrg	switch( file_access = CheckFilePermissions(filename, &exists) ) {
4665dfecf96Smrg	case NO_READ:
4675dfecf96Smrg	    if (exists)
468f14f4646Smrg		XeditPrintf("File %s, %s", name,
469f14f4646Smrg			    "exists, and could not be opened for reading.\n");
4705dfecf96Smrg	    else
471f14f4646Smrg		XeditPrintf("File %s %s %s",  name,
4725dfecf96Smrg			    "does not exist, and",
473f14f4646Smrg			    "the directory could not be opened for writing.\n");
4745dfecf96Smrg
4755dfecf96Smrg	    Feep();
4765dfecf96Smrg	    return (False);
4775dfecf96Smrg	case READ_OK:
4785dfecf96Smrg	    XtSetArg(args[num_args], XtNeditType, XawtextRead); num_args++;
479f14f4646Smrg	    XeditPrintf("File %s opened READ ONLY.\n", name);
4805dfecf96Smrg	    break;
4815dfecf96Smrg	case WRITE_OK:
4825dfecf96Smrg	    XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
483f14f4646Smrg	    XeditPrintf("File %s opened read - write.\n", name);
4845dfecf96Smrg	    break;
4855dfecf96Smrg	default:
4865dfecf96Smrg	    Feep();
4875dfecf96Smrg	    return (False);
4885dfecf96Smrg	}
4895dfecf96Smrg
4905dfecf96Smrg	if (exists) {
4915dfecf96Smrg	    flags = EXISTS_BIT;
4925dfecf96Smrg	    XtSetArg(args[num_args], XtNstring, filename); num_args++;
4935dfecf96Smrg	}
4945dfecf96Smrg	else {
4955dfecf96Smrg	    flags = 0;
4965dfecf96Smrg	    XtSetArg(args[num_args], XtNstring, NULL); num_args++;
4975dfecf96Smrg	}
4985dfecf96Smrg
499f14f4646Smrg	source = XtVaCreateWidget("textSource", international ?
500f14f4646Smrg				  multiSrcObjectClass :
501f14f4646Smrg				  asciiSrcObjectClass,
5025dfecf96Smrg				  topwindow,
5035dfecf96Smrg				  XtNtype, XawAsciiFile,
5045dfecf96Smrg				  XtNeditType, XawtextEdit,
5055dfecf96Smrg				  NULL, NULL);
5065dfecf96Smrg	XtSetValues(source, args, num_args);
5075dfecf96Smrg
5085dfecf96Smrg	item = AddTextSource(source, name, filename, flags, file_access);
5095dfecf96Smrg	XtAddCallback(item->source, XtNcallback, SourceChanged,
5105dfecf96Smrg		      (XtPointer)item);
5115dfecf96Smrg	if (exists && file_access == WRITE_OK) {
5125dfecf96Smrg	    struct stat st;
5135dfecf96Smrg
514f14f4646Smrg	    if (stat(item->filename, &st) == 0) {
5155dfecf96Smrg		item->mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
516f14f4646Smrg		item->mtime = st.st_mtime;
517f14f4646Smrg	    }
5185dfecf96Smrg	}
5195dfecf96Smrg	SwitchTextSource(item);
5205dfecf96Smrg	ResetSourceChanged(item);
5215dfecf96Smrg    }
5225dfecf96Smrg
5235dfecf96Smrg    return (True);
5245dfecf96Smrg}
5255dfecf96Smrg
5265dfecf96Smrg#ifdef INCLUDE_XPRINT_SUPPORT
5275dfecf96Smrgstatic void
5285dfecf96SmrgprintshellDestroyXtProc(Widget w, XtPointer client_data, XtPointer callData)
5295dfecf96Smrg{
5305dfecf96Smrg    XawPrintDialogClosePrinterConnection(printdialog, False);
5315dfecf96Smrg}
5325dfecf96Smrg
5335dfecf96Smrgstatic void
5345dfecf96SmrgprintOKXtProc(Widget w, XtPointer client_data, XtPointer callData)
5355dfecf96Smrg{
5365dfecf96Smrg    XawPrintDialogCallbackStruct *pdcs = (XawPrintDialogCallbackStruct *)callData;
5375dfecf96Smrg    Cardinal                      n;
5385dfecf96Smrg    Arg                           args[2];
5395dfecf96Smrg    Widget                        textsource;
5405dfecf96Smrg
5415dfecf96Smrg    Log(("printOKXtProc: OK.\n"));
5425dfecf96Smrg
5435dfecf96Smrg    /* Get TextSource object */
5445dfecf96Smrg    n = 0;
5455dfecf96Smrg    XtSetArg(args[n], XtNtextSource, &textsource); n++;
5465dfecf96Smrg    XtGetValues(textwindow, args, n);
5475dfecf96Smrg
5485dfecf96Smrg    Assertion(textsource != NULL, (("printOKXtProc: textsource == NULL.\n")));
5495dfecf96Smrg
5505dfecf96Smrg    /* ||printJobNameBuffer| must live as long the print job prints
5515dfecf96Smrg     * because it is used for the job title AND the page headers... */
5525dfecf96Smrg    sprintf(printJobNameBuffer, "Xedit print job");
5535dfecf96Smrg
5545dfecf96Smrg    DoPrintTextSource("Xedit",
5555dfecf96Smrg                      textsource, topwindow,
5565dfecf96Smrg                      pdcs->pdpy, pdcs->pcontext, pdcs->colorspace,
5575dfecf96Smrg                      printshellDestroyXtProc,
5585dfecf96Smrg                      printJobNameBuffer,
5595dfecf96Smrg                      pdcs->printToFile?pdcs->printToFileName:NULL);
5605dfecf96Smrg
5615dfecf96Smrg    XtPopdown(printdialog_shell);
5625dfecf96Smrg}
5635dfecf96Smrg
5645dfecf96Smrgstatic void
5655dfecf96SmrgprintCancelXtProc(Widget w, XtPointer client_data, XtPointer callData)
5665dfecf96Smrg{
5675dfecf96Smrg    Log(("printCancelXtProc: cancel.\n"));
5685dfecf96Smrg    XtPopdown(printdialog_shell);
5695dfecf96Smrg
5705dfecf96Smrg    Log(("destroying print dialog shell...\n"));
5715dfecf96Smrg    XtDestroyWidget(printdialog_shell);
5725dfecf96Smrg    printdialog_shell = NULL;
5735dfecf96Smrg    printdialog       = NULL;
5745dfecf96Smrg    Log(("... done\n"));
5755dfecf96Smrg}
5765dfecf96Smrg
5775dfecf96Smrg
5785dfecf96Smrg/*ARGSUSED*/
5795dfecf96Smrgvoid
5805dfecf96SmrgPrintFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
5815dfecf96Smrg{
5825dfecf96Smrg    DoPrint(w, NULL, NULL);
5835dfecf96Smrg}
5845dfecf96Smrg
5855dfecf96Smrg/*ARGSUSED*/
5865dfecf96Smrgvoid
5875dfecf96SmrgDoPrint(Widget w, XtPointer client_data, XtPointer call_data)
5885dfecf96Smrg{
5895dfecf96Smrg  Dimension   width, height;
5905dfecf96Smrg  Position    x, y;
5915dfecf96Smrg  Widget      parent = topwindow;
5925dfecf96Smrg  Log(("print!\n"));
5935dfecf96Smrg
5945dfecf96Smrg  if (!printdialog) {
5955dfecf96Smrg    int n;
5965dfecf96Smrg    Arg args[20];
5975dfecf96Smrg
5985dfecf96Smrg    n = 0;
5995dfecf96Smrg    XtSetArg(args[n], XtNallowShellResize, True); n++;
6005dfecf96Smrg    printdialog_shell = XtCreatePopupShell("printdialogshell",
6015dfecf96Smrg                                           transientShellWidgetClass,
6025dfecf96Smrg                                           topwindow, args, n);
6035dfecf96Smrg    n = 0;
6045dfecf96Smrg    printdialog = XtCreateManagedWidget("printdialog", printDialogWidgetClass,
6055dfecf96Smrg                                        printdialog_shell, args, n);
6065dfecf96Smrg    XtAddCallback(printdialog, XawNOkCallback,     printOKXtProc,     NULL);
6075dfecf96Smrg    XtAddCallback(printdialog, XawNCancelCallback, printCancelXtProc, NULL);
6085dfecf96Smrg
6095dfecf96Smrg    XtRealizeWidget(printdialog_shell);
6105dfecf96Smrg  }
6115dfecf96Smrg
6125dfecf96Smrg  /* Center dialog */
6135dfecf96Smrg  XtVaGetValues(printdialog_shell,
6145dfecf96Smrg      XtNwidth,  &width,
6155dfecf96Smrg      XtNheight, &height,
6165dfecf96Smrg      NULL);
6175dfecf96Smrg
6185dfecf96Smrg  x = (Position)(XWidthOfScreen( XtScreen(parent)) - width)  / 2;
6195dfecf96Smrg  y = (Position)(XHeightOfScreen(XtScreen(parent)) - height) / 3;
6205dfecf96Smrg
6215dfecf96Smrg  XtVaSetValues(printdialog_shell,
6225dfecf96Smrg      XtNx, x,
6235dfecf96Smrg      XtNy, y,
6245dfecf96Smrg      NULL);
6255dfecf96Smrg
6265dfecf96Smrg  XtPopup(printdialog_shell, XtGrabNonexclusive);
6275dfecf96Smrg}
6285dfecf96Smrg#endif /* INCLUDE_XPRINT_SUPPORT */
6295dfecf96Smrg
6305dfecf96Smrg/*	Function Name: SourceChanged
6315dfecf96Smrg *	Description: A callback routine called when the source has changed.
6325dfecf96Smrg *	Arguments: w - the text source that has changed.
6335dfecf96Smrg *		   client_data - xedit_flist_item associated with text buffer.
6345dfecf96Smrg *                 call_data - NULL is unchanged
6355dfecf96Smrg *	Returns: none.
6365dfecf96Smrg */
6375dfecf96Smrg/*ARGSUSED*/
6385dfecf96Smrgvoid
6395dfecf96SmrgSourceChanged(Widget w, XtPointer client_data, XtPointer call_data)
6405dfecf96Smrg{
6415dfecf96Smrg    xedit_flist_item *item = (xedit_flist_item*)client_data;
6425dfecf96Smrg    Bool changed = (Bool)(long)call_data;
6435dfecf96Smrg
6445dfecf96Smrg    if (changed) {
6455dfecf96Smrg	if (item->flags & CHANGED_BIT)
6465dfecf96Smrg	    return;
6475dfecf96Smrg	item->flags |= CHANGED_BIT;
6485dfecf96Smrg    }
6495dfecf96Smrg    else {
6505dfecf96Smrg	if (item->flags & CHANGED_BIT)
6515dfecf96Smrg	    ResetSourceChanged(item);
6525dfecf96Smrg	return;
6535dfecf96Smrg    }
6545dfecf96Smrg
6555dfecf96Smrg    if (flist.pixmap) {
6565dfecf96Smrg	Arg args[1];
6575dfecf96Smrg	Cardinal num_args;
6585dfecf96Smrg	int i;
6595dfecf96Smrg
6605dfecf96Smrg	num_args = 0;
6615dfecf96Smrg	XtSetArg(args[num_args], XtNleftBitmap, flist.pixmap);	++num_args;
6625dfecf96Smrg	XtSetValues(item->sme, args, num_args);
6635dfecf96Smrg
6645dfecf96Smrg	for (i = 0; i < 3; i++)
6655dfecf96Smrg	    if (XawTextGetSource(texts[i]) == item->source)
6665dfecf96Smrg		XtSetValues(labels[i], args, num_args);
6675dfecf96Smrg    }
6685dfecf96Smrg}
6695dfecf96Smrg
6705dfecf96Smrg/*	Function Name: ResetSourceChanged.
6715dfecf96Smrg *	Description: Sets the source changed to FALSE, and
6725dfecf96Smrg *                   registers a callback to set it to TRUE when
6735dfecf96Smrg *                   the source has changed.
6745dfecf96Smrg *	Arguments: item - item with widget to register the callback on.
6755dfecf96Smrg *	Returns: none.
6765dfecf96Smrg */
6775dfecf96Smrg
6785dfecf96Smrgvoid
6795dfecf96SmrgResetSourceChanged(xedit_flist_item *item)
6805dfecf96Smrg{
6815dfecf96Smrg    Arg args[1];
6825dfecf96Smrg    Cardinal num_args;
6835dfecf96Smrg    int i;
6845dfecf96Smrg
6855dfecf96Smrg    num_args = 0;
6865dfecf96Smrg    XtSetArg(args[num_args], XtNleftBitmap, None);	++num_args;
6875dfecf96Smrg    XtSetValues(item->sme, args, num_args);
6885dfecf96Smrg
6895dfecf96Smrg    dc_state = 0;
6905dfecf96Smrg    for (i = 0; i < 3; i++) {
6915dfecf96Smrg	if (XawTextGetSource(texts[i]) == item->source)
6925dfecf96Smrg	    XtSetValues(labels[i], args, num_args);
6935dfecf96Smrg	AddDoubleClickCallback(XawTextGetSource(texts[i]), False);
6945dfecf96Smrg    }
6955dfecf96Smrg
6965dfecf96Smrg    num_args = 0;
6975dfecf96Smrg    XtSetArg(args[num_args], XtNsourceChanged, False);	++num_args;
6985dfecf96Smrg    XtSetValues(item->source, args, num_args);
6995dfecf96Smrg
7005dfecf96Smrg    item->flags &= ~CHANGED_BIT;
7015dfecf96Smrg}
7025dfecf96Smrg
7035dfecf96Smrg/*ARGSUSED*/
7045dfecf96Smrgvoid
7055dfecf96SmrgKillFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
7065dfecf96Smrg{
7075dfecf96Smrg    xedit_flist_item *item = FindTextSource(XawTextGetSource(textwindow), NULL);
7085dfecf96Smrg
7095dfecf96Smrg    if (item->source == scratch) {
7105dfecf96Smrg	Feep();
7115dfecf96Smrg	return;
7125dfecf96Smrg    }
7135dfecf96Smrg
7145dfecf96Smrg    if (item->flags & CHANGED_BIT) {
715f14f4646Smrg	if (!(dc_state & DC_KILL)) {
7165dfecf96Smrg	    XeditPrintf("Kill: Unsaved changes. Kill again to override.\n");
7175dfecf96Smrg	    Feep();
718f14f4646Smrg	    dc_state |= DC_KILL;
7195dfecf96Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
7205dfecf96Smrg	    return;
7215dfecf96Smrg	}
722f14f4646Smrg	dc_state &= ~DC_KILL;
7235dfecf96Smrg    }
7245dfecf96Smrg    KillTextSource(item);
7255dfecf96Smrg}
7265dfecf96Smrg
7275dfecf96Smrg/*ARGSUSED*/
7285dfecf96Smrgvoid
7295dfecf96SmrgFindFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
7305dfecf96Smrg{
731f14f4646Smrg    char *string;
732f14f4646Smrg    char *slash;
7335dfecf96Smrg    XawTextBlock block;
7345dfecf96Smrg    XawTextPosition end = XawTextSourceScan(XawTextGetSource(filenamewindow),
7355dfecf96Smrg					    0, XawstAll, XawsdRight, 1, True);
7365dfecf96Smrg
737f14f4646Smrg    if (!line_edit) {
738f14f4646Smrg	string = GetString(filenamewindow);
739f14f4646Smrg	if (string)
740f14f4646Smrg	    slash = strrchr(string, '/');
741f14f4646Smrg    }
742f14f4646Smrg    else {
743f14f4646Smrg	string = "";
744f14f4646Smrg	slash = NULL;
745f14f4646Smrg	line_edit = False;
746f14f4646Smrg    }
747f14f4646Smrg
7485dfecf96Smrg    block.firstPos = 0;
7495dfecf96Smrg    block.format = FMT8BIT;
7505dfecf96Smrg    block.ptr = string;
7515dfecf96Smrg    block.length = slash ? slash - string + 1 : 0;
7525dfecf96Smrg
7535dfecf96Smrg    if (block.length != end)
7545dfecf96Smrg	XawTextReplace(filenamewindow, 0, end, &block);
7555dfecf96Smrg    XawTextSetInsertionPoint(filenamewindow, end);
7565dfecf96Smrg    XtSetKeyboardFocus(topwindow, filenamewindow);
7575dfecf96Smrg}
7585dfecf96Smrg
7595dfecf96Smrg/*ARGSUSED*/
7605dfecf96Smrgvoid
7615dfecf96SmrgLoadFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
7625dfecf96Smrg{
7635dfecf96Smrg    if (line_edit)
7645dfecf96Smrg	LineEdit(textwindow);
7655dfecf96Smrg    else if (ReallyDoLoad(GetString(filenamewindow), ResolveName(NULL))) {
7665dfecf96Smrg	SwitchDirWindow(False);
7675dfecf96Smrg	XtSetKeyboardFocus(topwindow, textwindow);
7685dfecf96Smrg    }
7695dfecf96Smrg}
7705dfecf96Smrg
7715dfecf96Smrg/*ARGSUSED*/
7725dfecf96Smrgvoid
7735dfecf96SmrgCancelFindFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
7745dfecf96Smrg{
7755dfecf96Smrg    Arg args[1];
7765dfecf96Smrg    xedit_flist_item *item;
7775dfecf96Smrg
7785dfecf96Smrg    XtSetKeyboardFocus(topwindow, textwindow);
7795dfecf96Smrg
7805dfecf96Smrg    item = FindTextSource(XawTextGetSource(textwindow), NULL);
7815dfecf96Smrg
7825dfecf96Smrg    if (item->source != scratch)
7835dfecf96Smrg	XtSetArg(args[0], XtNstring, item->name);
7845dfecf96Smrg    else
7855dfecf96Smrg	XtSetArg(args[0], XtNstring, NULL);
7865dfecf96Smrg
7875dfecf96Smrg    XtSetValues(filenamewindow, args, 1);
788f14f4646Smrg    /* XXX This probably should be done by the TextWidget, i.e. notice
789f14f4646Smrg     * if the cursor became inivisible due to an horizontal scroll */
790f14f4646Smrg    _XawTextShowPosition((TextWidget)filenamewindow);
7915dfecf96Smrg
7925dfecf96Smrg   if (XtIsManaged(XtParent(dirwindow)))
7935dfecf96Smrg	SwitchDirWindow(False);
7945dfecf96Smrg
7955dfecf96Smrg    line_edit = False;
7965dfecf96Smrg}
7975dfecf96Smrg
7985dfecf96Smrgstatic int
7995dfecf96Smrgcompar(_Xconst void *a, _Xconst void *b)
8005dfecf96Smrg{
8015dfecf96Smrg    return (strcmp(*(char **)a, *(char **)b));
8025dfecf96Smrg}
8035dfecf96Smrg
8045dfecf96Smrg/*ARGSUSED*/
8055dfecf96Smrgvoid
8065dfecf96SmrgFileCompletion(Widget w, XEvent *event, String *params, Cardinal *num_params)
8075dfecf96Smrg{
8085dfecf96Smrg    XawTextBlock block;
8095dfecf96Smrg    String text;
8105dfecf96Smrg    int length;
8115dfecf96Smrg    char **matches, *save, *dir_name, *file_name, match[257];
8125dfecf96Smrg    unsigned n_matches, len, mlen, buflen;
8135dfecf96Smrg    DIR *dir;
8145dfecf96Smrg    Bool changed, slash = False, has_dot = False;
8155dfecf96Smrg#define	SM_NEVER	0
8165dfecf96Smrg#define SM_HINT		1
8175dfecf96Smrg#define SM_ALWAYS	2
8185dfecf96Smrg    int show_matches;
8195dfecf96Smrg
8205dfecf96Smrg    text = GetString(filenamewindow);
8215dfecf96Smrg
8225dfecf96Smrg    if (!text) {
8235dfecf96Smrg	Feep();
8245dfecf96Smrg	return;
8255dfecf96Smrg    }
8265dfecf96Smrg    else if (line_edit) {
8275dfecf96Smrg	Feep();
8285dfecf96Smrg	line_edit = 0;
8295dfecf96Smrg    }
8305dfecf96Smrg
8315dfecf96Smrg    {
8325dfecf96Smrg	XawTextPosition pos = XawTextGetInsertionPoint(w);
8335dfecf96Smrg	char *cslash = strchr(&text[pos], '/'), *cdot = strchr(&text[pos], '.');
8345dfecf96Smrg
8355dfecf96Smrg	if (cslash != NULL || cdot != NULL) {
8365dfecf96Smrg	    if (cslash != NULL && (cdot == NULL || cdot > cslash)) {
8375dfecf96Smrg		length = cslash - text;
8385dfecf96Smrg		slash = True;
8395dfecf96Smrg	    }
8405dfecf96Smrg	    else {
8415dfecf96Smrg		length = cdot - text;
8425dfecf96Smrg		has_dot = True;
8435dfecf96Smrg	    }
8445dfecf96Smrg	}
8455dfecf96Smrg	else
8465dfecf96Smrg	    length = strlen(text);
8475dfecf96Smrg    }
8485dfecf96Smrg
8495dfecf96Smrg    if (*num_params == 1 && length == strlen(text)) {
8505dfecf96Smrg	switch (params[0][0]) {
8515dfecf96Smrg	case 'n':		/* Never */
8525dfecf96Smrg	case 'N':
8535dfecf96Smrg	    show_matches = SM_NEVER;
8545dfecf96Smrg	    break;
8555dfecf96Smrg	case 'h':		/* Hint */
8565dfecf96Smrg	case 'H':
8575dfecf96Smrg	    show_matches = SM_HINT;
8585dfecf96Smrg	    break;
8595dfecf96Smrg	case 'a':		/* Always */
8605dfecf96Smrg	case 'A':
8615dfecf96Smrg	    show_matches = SM_ALWAYS;
8625dfecf96Smrg	    break;
8635dfecf96Smrg	default:
8645dfecf96Smrg	    show_matches = SM_NEVER;
8655dfecf96Smrg	    XtAppWarning(XtWidgetToApplicationContext(w),
8665dfecf96Smrg			 "Bad argument to file-completion, "
8675dfecf96Smrg			 "must be Never, Hint or Always");
8685dfecf96Smrg	    break;
8695dfecf96Smrg	}
8705dfecf96Smrg    }
8715dfecf96Smrg    else
8725dfecf96Smrg	show_matches = SM_NEVER;
8735dfecf96Smrg
8745dfecf96Smrg    matches = NULL;
8755dfecf96Smrg    n_matches = buflen = 0;
8765dfecf96Smrg    save = XtMalloc(length + 1);
8775dfecf96Smrg    memmove(save, text, length);
8785dfecf96Smrg    save[length] = '\0';
8795dfecf96Smrg
8805dfecf96Smrg    if (save[0] == '~' && save[1]) {
8815dfecf96Smrg	char *slash2 = strchr(save, '/');
8825dfecf96Smrg
8835dfecf96Smrg	if (slash2) {
8845dfecf96Smrg	    struct passwd *pw;
8855dfecf96Smrg	    char home[BUFSIZ];
8865dfecf96Smrg	    char *name;
8875dfecf96Smrg	    int slen = strlen(save), diff = slash2 - save;
8885dfecf96Smrg
8895dfecf96Smrg	    *slash2 = '\0';
8905dfecf96Smrg	    name = save + 1;
8915dfecf96Smrg	    if (strlen(name) != 0)
8925dfecf96Smrg		pw = getpwnam(name);
8935dfecf96Smrg	    else
8945dfecf96Smrg		pw = getpwuid(getuid());
8955dfecf96Smrg
8965dfecf96Smrg	    if (pw) {
8975dfecf96Smrg		char fname[BUFSIZ];
8985dfecf96Smrg		int hlen;
8995dfecf96Smrg
9005dfecf96Smrg		strncpy(home, pw->pw_dir, sizeof(home) - 1);
9015dfecf96Smrg		home[sizeof(home) - 1] = '\0';
9025dfecf96Smrg		hlen = strlen(home);
9035dfecf96Smrg		strncpy(fname, slash2 + 1, sizeof(fname) - 1);
9045dfecf96Smrg		fname[sizeof(fname) - 1] = '\0';
9055dfecf96Smrg		save = XtRealloc(save, slen - diff + hlen + 2);
9065dfecf96Smrg		(void)memmove(save, home, hlen);
9075dfecf96Smrg		save[hlen] = '/';
9085dfecf96Smrg		strcpy(&save[hlen + 1], fname);
9095dfecf96Smrg
9105dfecf96Smrg		/* expand directory */
9115dfecf96Smrg		block.length = strlen(save);
9125dfecf96Smrg		block.ptr = save;
9135dfecf96Smrg		block.firstPos = 0;
9145dfecf96Smrg		block.format = FMT8BIT;
9155dfecf96Smrg		XawTextReplace(filenamewindow, 0, length, &block);
9165dfecf96Smrg		XawTextSetInsertionPoint(filenamewindow, length = block.length);
9175dfecf96Smrg	    }
9185dfecf96Smrg	    else
9195dfecf96Smrg		*slash2 = '/';
9205dfecf96Smrg	}
9215dfecf96Smrg    }
9225dfecf96Smrg
9235dfecf96Smrg    if ((file_name = strrchr(save, '/')) != NULL) {
9245dfecf96Smrg	*file_name = '\0';
9255dfecf96Smrg	++file_name;
9265dfecf96Smrg	dir_name = save;
9275dfecf96Smrg	if (!file_name[0])
9285dfecf96Smrg	    slash = True;
9295dfecf96Smrg	if (!dir_name[0])
9305dfecf96Smrg	    dir_name = "/";
9315dfecf96Smrg    }
9325dfecf96Smrg    else {
9335dfecf96Smrg	dir_name = ".";
9345dfecf96Smrg	file_name = save;
9355dfecf96Smrg    }
9365dfecf96Smrg    len = strlen(file_name);
9375dfecf96Smrg
9385dfecf96Smrg    if ((dir = opendir(dir_name)) != NULL) {
9395dfecf96Smrg	char path[BUFSIZ], *pptr;
9405dfecf96Smrg	struct dirent *ent;
9415dfecf96Smrg	int isdir = 0, first = 1, bytes;
9425dfecf96Smrg
9435dfecf96Smrg	XmuSnprintf(path, sizeof(path), "%s/", dir_name);
9445dfecf96Smrg	pptr = path + strlen(path);
9455dfecf96Smrg	bytes = sizeof(path) - (pptr - path) - 1;
9465dfecf96Smrg
9475dfecf96Smrg	mlen = 0;
9485dfecf96Smrg	match[0] = '\0';
9495dfecf96Smrg	while ((ent = readdir(dir)) != NULL) {
9505dfecf96Smrg	    unsigned d_namlen = strlen(ent->d_name);
9515dfecf96Smrg
952f14f4646Smrg	    if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
953f14f4646Smrg		continue;
9545dfecf96Smrg	    if (d_namlen >= len && strncmp(ent->d_name, file_name, len) == 0) {
9555dfecf96Smrg		char *tmp = &(ent->d_name[len]), *mat = match;
9565dfecf96Smrg		struct stat st;
9575dfecf96Smrg		Bool is_dir = FALSE;
9585dfecf96Smrg
9595dfecf96Smrg		strncpy(pptr, ent->d_name, bytes);
9605dfecf96Smrg		pptr[bytes] = '\0';
9615dfecf96Smrg		if (stat(path, &st) != 0)
9625dfecf96Smrg		    /* Should check errno, may be a broken symbolic link
9635dfecf96Smrg		     * a directory with r-- permission, etc */
9645dfecf96Smrg		    continue;
9655dfecf96Smrg		else if (first || show_matches != SM_NEVER) {
9665dfecf96Smrg		    is_dir = S_ISDIR(st.st_mode);
9675dfecf96Smrg		}
9685dfecf96Smrg
9695dfecf96Smrg		if (first) {
9705dfecf96Smrg		    strncpy(match, tmp, sizeof(match) - 1);
9715dfecf96Smrg		    match[sizeof(match) - 2] = '\0';
9725dfecf96Smrg		    mlen = strlen(match);
9735dfecf96Smrg		    first = 0;
9745dfecf96Smrg		    isdir = is_dir;
9755dfecf96Smrg		}
9765dfecf96Smrg		else {
9775dfecf96Smrg		    while (*tmp && *mat && *tmp++ == *mat)
9785dfecf96Smrg			++mat;
9795dfecf96Smrg		    if (mlen > mat - match) {
9805dfecf96Smrg			mlen = mat - match;
9815dfecf96Smrg			match[mlen] = '\0';
9825dfecf96Smrg		    }
9835dfecf96Smrg		}
9845dfecf96Smrg		if (show_matches != SM_NEVER) {
9855dfecf96Smrg		    matches = (char **)XtRealloc((char*)matches, sizeof(char**)
9865dfecf96Smrg						 * (n_matches + 1));
9875dfecf96Smrg		    buflen += d_namlen + 1;
9885dfecf96Smrg		    if (is_dir) {
9895dfecf96Smrg			matches[n_matches] = XtMalloc(d_namlen + 2);
9905dfecf96Smrg			strcpy(matches[n_matches], ent->d_name);
9915dfecf96Smrg			strcat(matches[n_matches], "/");
9925dfecf96Smrg			++buflen;
9935dfecf96Smrg		    }
9945dfecf96Smrg		    else
9955dfecf96Smrg			matches[n_matches] = XtNewString(ent->d_name);
9965dfecf96Smrg		}
9975dfecf96Smrg		else if (mlen == 0 && n_matches >= 1) {
9985dfecf96Smrg		    ++n_matches;
9995dfecf96Smrg		    break;
10005dfecf96Smrg		}
10015dfecf96Smrg		++n_matches;
10025dfecf96Smrg	    }
10035dfecf96Smrg	}
10045dfecf96Smrg
10055dfecf96Smrg	closedir(dir);
10065dfecf96Smrg	changed = mlen != 0;
10075dfecf96Smrg
1008f14f4646Smrg	if (first || n_matches) {
10095dfecf96Smrg	    Bool free_matches = True, add_slash = n_matches == 1 && isdir && !slash;
10105dfecf96Smrg
10115dfecf96Smrg	    if (mlen && has_dot && match[mlen - 1] == '.')
10125dfecf96Smrg		--mlen;
10135dfecf96Smrg
10145dfecf96Smrg	    if (mlen || add_slash) {
10155dfecf96Smrg		XawTextPosition pos;
10165dfecf96Smrg
10175dfecf96Smrg		block.firstPos = 0;
10185dfecf96Smrg		block.format = FMT8BIT;
10195dfecf96Smrg		if (mlen) {
10205dfecf96Smrg		    pos = length;
10215dfecf96Smrg		    block.length = mlen;
10225dfecf96Smrg		    block.ptr = match;
10235dfecf96Smrg		    XawTextReplace(filenamewindow, pos, pos, &block);
10245dfecf96Smrg		    XawTextSetInsertionPoint(filenamewindow, pos + block.length);
10255dfecf96Smrg		}
10265dfecf96Smrg		if (add_slash) {
10275dfecf96Smrg		    XawTextPosition actual = XawTextGetInsertionPoint(w);
10285dfecf96Smrg
10295dfecf96Smrg		    pos = XawTextSourceScan(XawTextGetSource(w), 0, XawstAll,
10305dfecf96Smrg					    XawsdRight, 1, True);
10315dfecf96Smrg		    block.length = 1;
10325dfecf96Smrg		    block.ptr = "/";
10335dfecf96Smrg		    XawTextReplace(filenamewindow, pos, pos, &block);
10345dfecf96Smrg		    if (actual == pos)
10355dfecf96Smrg			XawTextSetInsertionPoint(filenamewindow, pos + 1);
10365dfecf96Smrg		}
10375dfecf96Smrg	    }
10385dfecf96Smrg	    else if (n_matches != 1 || isdir) {
10395dfecf96Smrg		if (show_matches == SM_NEVER)
10405dfecf96Smrg		    Feep();
10415dfecf96Smrg	    }
10425dfecf96Smrg
10435dfecf96Smrg	    if (show_matches != SM_NEVER) {
10445dfecf96Smrg		if (show_matches == SM_ALWAYS || (!changed && n_matches != 1)) {
10455dfecf96Smrg		    char **list = NULL, *label;
10465dfecf96Smrg		    int n_list;
10475dfecf96Smrg		    Arg args[2];
10485dfecf96Smrg
10495dfecf96Smrg		    XtSetArg(args[0], XtNlist, &list);
10505dfecf96Smrg		    XtSetArg(args[1], XtNnumberStrings, &n_list);
10515dfecf96Smrg		    XtGetValues(dirwindow, args, 2);
10525dfecf96Smrg
10535dfecf96Smrg		    matches = (char **)XtRealloc((char*)matches, sizeof(char**)
10545dfecf96Smrg						 * (n_matches + 2));
10555dfecf96Smrg		    matches[n_matches++] = XtNewString("./");
10565dfecf96Smrg		    matches[n_matches++] = XtNewString("../");
10575dfecf96Smrg		    qsort(matches, n_matches, sizeof(char*), compar);
10585dfecf96Smrg		    XtSetArg(args[0], XtNlist, matches);
10595dfecf96Smrg		    XtSetArg(args[1], XtNnumberStrings, n_matches);
10605dfecf96Smrg		    XtSetValues(dirwindow, args, 2);
10615dfecf96Smrg		    if (n_list > 0
10625dfecf96Smrg			&& (n_list != 1 || list[0] != XtName(dirwindow))) {
10635dfecf96Smrg			while (--n_list > -1)
10645dfecf96Smrg			    XtFree(list[n_list]);
10655dfecf96Smrg			XtFree((char*)list);
10665dfecf96Smrg		    }
10675dfecf96Smrg
10685dfecf96Smrg		    label = ResolveName(dir_name);
10695dfecf96Smrg		    XtSetArg(args[0], XtNlabel, label);
10705dfecf96Smrg		    XtSetValues(dirlabel, args, 1);
10715dfecf96Smrg		    SwitchDirWindow(True);
10725dfecf96Smrg		    free_matches = False;
10735dfecf96Smrg		}
10745dfecf96Smrg	    }
10755dfecf96Smrg	    if (free_matches && matches) {
10765dfecf96Smrg		while (--n_matches > -1)
10775dfecf96Smrg		    XtFree(matches[n_matches]);
10785dfecf96Smrg		XtFree((char*)matches);
10795dfecf96Smrg	    }
10805dfecf96Smrg	}
10815dfecf96Smrg	else
10825dfecf96Smrg	    Feep();
10835dfecf96Smrg    }
10845dfecf96Smrg    else
10855dfecf96Smrg	Feep();
10865dfecf96Smrg
10875dfecf96Smrg    XtFree(save);
10885dfecf96Smrg}
10895dfecf96Smrg
10905dfecf96Smrg/*ARGSUSED*/
10915dfecf96Smrgvoid
10925dfecf96SmrgDirWindowCB(Widget w, XtPointer user_data, XtPointer call_data)
10935dfecf96Smrg{
10945dfecf96Smrg    XawListReturnStruct *file_info = (XawListReturnStruct *)call_data;
10955dfecf96Smrg    char *dir_name, *string, path[BUFSIZ];
10965dfecf96Smrg    Arg args[2];
10975dfecf96Smrg
10985dfecf96Smrg    if (file_info == NULL)
10995dfecf96Smrg	string = (char *)user_data;
11005dfecf96Smrg    else
11015dfecf96Smrg	string = file_info->string;
11025dfecf96Smrg
11035dfecf96Smrg    XtSetArg(args[0], XtNlabel, &dir_name);
11045dfecf96Smrg    XtGetValues(dirlabel, args, 1);
11055dfecf96Smrg    if (*dir_name == '\0') {
11065dfecf96Smrg	strncpy(path, string, sizeof(path) - 1);
11075dfecf96Smrg	path[sizeof(path) - 1] = '\0';
11085dfecf96Smrg    }
11095dfecf96Smrg    else if (strcmp(dir_name, "/") == 0)
11105dfecf96Smrg	XmuSnprintf(path, sizeof(path), "/%s", string);
11115dfecf96Smrg    else
11125dfecf96Smrg	XmuSnprintf(path, sizeof(path), "%s/%s", dir_name, string);
11135dfecf96Smrg
11145dfecf96Smrg    if (*string && string[strlen(string) - 1] == '/') {
11155dfecf96Smrg	DIR *dir;
11165dfecf96Smrg
11175dfecf96Smrg	if ((dir = opendir(path)) != NULL) {
11185dfecf96Smrg	    struct dirent *ent;
11195dfecf96Smrg	    struct stat st;
11205dfecf96Smrg	    unsigned d_namlen;
11215dfecf96Smrg	    Bool isdir;
11225dfecf96Smrg	    char **entries = NULL, **list = NULL;
11235dfecf96Smrg	    int n_entries = 0, n_list = 0;
11245dfecf96Smrg	    char *label, *pptr = path + strlen(path);
11255dfecf96Smrg	    int bytes = sizeof(path) - (pptr - path) - 1;
11265dfecf96Smrg
11275dfecf96Smrg	    while ((ent = readdir(dir)) != NULL) {
11285dfecf96Smrg		d_namlen = strlen(ent->d_name);
11295dfecf96Smrg		strncpy(pptr, ent->d_name, bytes);
11305dfecf96Smrg		pptr[bytes] = '\0';
11315dfecf96Smrg		if (stat(path, &st) != 0)
11325dfecf96Smrg		    /* Should check errno, may be a broken symbolic link
11335dfecf96Smrg		     * a directory with r-- permission, etc */
11345dfecf96Smrg		    continue;
11355dfecf96Smrg		else
11365dfecf96Smrg		    isdir = S_ISDIR(st.st_mode);
11375dfecf96Smrg
11385dfecf96Smrg		entries = (char **)XtRealloc((char*)entries, sizeof(char*)
11395dfecf96Smrg					     * (n_entries + 1));
11405dfecf96Smrg		if (isdir) {
11415dfecf96Smrg		    entries[n_entries] = XtMalloc(d_namlen + 2);
11425dfecf96Smrg		    strcpy(entries[n_entries], ent->d_name);
11435dfecf96Smrg		    strcat(entries[n_entries], "/");
11445dfecf96Smrg		}
11455dfecf96Smrg		else
11465dfecf96Smrg		    entries[n_entries] = XtNewString(ent->d_name);
11475dfecf96Smrg		++n_entries;
11485dfecf96Smrg	    }
11495dfecf96Smrg	    closedir(dir);
11505dfecf96Smrg
11515dfecf96Smrg	    XtSetArg(args[0], XtNlist, &list);
11525dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, &n_list);
11535dfecf96Smrg	    XtGetValues(dirwindow, args, 2);
11545dfecf96Smrg
11555dfecf96Smrg	    if (n_entries == 0) {
11565dfecf96Smrg		entries = (char**)XtMalloc(sizeof(char*) * 2);
11575dfecf96Smrg		/* Directory has read but not execute permission? */
11585dfecf96Smrg		entries[n_entries++] = XtNewString("./");
11595dfecf96Smrg		entries[n_entries++] = XtNewString("../");
11605dfecf96Smrg	    }
11615dfecf96Smrg	    qsort(entries, n_entries, sizeof(char*), compar);
11625dfecf96Smrg	    XtSetArg(args[0], XtNlist, entries);
11635dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, n_entries);
11645dfecf96Smrg	    XtSetValues(dirwindow, args, 2);
11655dfecf96Smrg	    if (n_list > 0
11665dfecf96Smrg		&& (n_list != 1 || list[0] != XtName(dirwindow))) {
11675dfecf96Smrg		while (--n_list > -1)
11685dfecf96Smrg		    XtFree(list[n_list]);
11695dfecf96Smrg		XtFree((char*)list);
11705dfecf96Smrg	    }
11715dfecf96Smrg
11725dfecf96Smrg	    *pptr = '\0';
11735dfecf96Smrg	    if ((label = ResolveName(path)) == NULL) {
11745dfecf96Smrg		Feep();
11755dfecf96Smrg		label = path;
11765dfecf96Smrg	    }
11775dfecf96Smrg	    XtSetArg(args[0], XtNlabel, label);
11785dfecf96Smrg	    XtSetValues(dirlabel, args, 1);
11795dfecf96Smrg
11805dfecf96Smrg	    strncpy(path, label, sizeof(path) - 2);
11815dfecf96Smrg	    if (*path && path[strlen(path) - 1] != '/')
11825dfecf96Smrg		strcat(path, "/");
11835dfecf96Smrg	    XtSetArg(args[0], XtNstring, path);
11845dfecf96Smrg	    XtSetValues(filenamewindow, args, 1);
11855dfecf96Smrg	    XtSetKeyboardFocus(topwindow, filenamewindow);
11865dfecf96Smrg	    XawTextSetInsertionPoint(filenamewindow, strlen(path));
11875dfecf96Smrg	}
11885dfecf96Smrg	else
11895dfecf96Smrg	    Feep();
11905dfecf96Smrg    }
11915dfecf96Smrg    else {
11925dfecf96Smrg	(void)ReallyDoLoad(path, path);
11935dfecf96Smrg	SwitchDirWindow(False);
11945dfecf96Smrg	XtSetKeyboardFocus(topwindow, textwindow);
11955dfecf96Smrg    }
11965dfecf96Smrg}
1197