commands.c revision 5dfecf96
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
705dfecf96Smrgextern Widget scratch, texts[3], labels[3];
715dfecf96Smrgstatic Boolean double_click = FALSE;
725dfecf96Smrg
735dfecf96Smrg#define DC_UNSAVED	1
745dfecf96Smrg#define DC_LOADED	2
755dfecf96Smrg#define DC_CLOBBER	3
765dfecf96Smrg#define DC_KILL		4
775dfecf96Smrg#define DC_SAVE		5
785dfecf96Smrgstatic int dc_state;
795dfecf96Smrg
805dfecf96Smrg/*	Function Name: AddDoubleClickCallback(w)
815dfecf96Smrg *	Description: Adds a callback that will reset the double_click flag
825dfecf96Smrg *                   to false when the text is changed.
835dfecf96Smrg *	Arguments: w - widget to set callback upon.
845dfecf96Smrg *                 state - If true add the callback, else remove it.
855dfecf96Smrg *	Returns: none.
865dfecf96Smrg */
875dfecf96Smrgstatic void
885dfecf96SmrgAddDoubleClickCallback(Widget w, Bool state)
895dfecf96Smrg{
905dfecf96Smrg  Arg args[1];
915dfecf96Smrg  static XtCallbackRec cb[] = { {NULL, NULL}, {NULL, NULL} };
925dfecf96Smrg
935dfecf96Smrg  if (XtIsSubclass(w, asciiSrcObjectClass)) {
945dfecf96Smrg      if (state)
955dfecf96Smrg	  XtAddCallback(w, XtNcallback, ResetDC, NULL);
965dfecf96Smrg      else
975dfecf96Smrg	  XtRemoveCallback(w, XtNcallback, ResetDC, NULL);
985dfecf96Smrg  }
995dfecf96Smrg  else {
1005dfecf96Smrg      if (state)
1015dfecf96Smrg	  cb[0].callback = ResetDC;
1025dfecf96Smrg      else
1035dfecf96Smrg	  cb[0].callback = NULL;
1045dfecf96Smrg
1055dfecf96Smrg      XtSetArg(args[0], XtNcallback, cb);
1065dfecf96Smrg      XtSetValues(w, args, ONE);
1075dfecf96Smrg  }
1085dfecf96Smrg}
1095dfecf96Smrg
1105dfecf96Smrg/*	Function Name: ResetDC
1115dfecf96Smrg *	Description: Resets the double click flag.
1125dfecf96Smrg *	Arguments: w - the text widget.
1135dfecf96Smrg *                 junk, garbage - *** NOT USED ***
1145dfecf96Smrg *	Returns: none.
1155dfecf96Smrg */
1165dfecf96Smrg
1175dfecf96Smrg/* ARGSUSED */
1185dfecf96Smrgstatic void
1195dfecf96SmrgResetDC(Widget w, XtPointer junk, XtPointer garbage)
1205dfecf96Smrg{
1215dfecf96Smrg  double_click = FALSE;
1225dfecf96Smrg
1235dfecf96Smrg  AddDoubleClickCallback(w, FALSE);
1245dfecf96Smrg}
1255dfecf96Smrg
1265dfecf96Smrg/*ARGSUSED*/
1275dfecf96Smrgvoid
1285dfecf96SmrgQuitAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
1295dfecf96Smrg{
1305dfecf96Smrg    DoQuit(w, NULL, NULL);
1315dfecf96Smrg}
1325dfecf96Smrg
1335dfecf96Smrg/*ARGSUSED*/
1345dfecf96Smrgvoid
1355dfecf96SmrgDoQuit(Widget w, XtPointer client_data, XtPointer call_data)
1365dfecf96Smrg{
1375dfecf96Smrg    unsigned i;
1385dfecf96Smrg    Bool source_changed = False;
1395dfecf96Smrg
1405dfecf96Smrg    if (!double_click || (dc_state && dc_state != DC_UNSAVED)) {
1415dfecf96Smrg	for (i = 0; i < flist.num_itens; i++)
1425dfecf96Smrg	    if (flist.itens[i]->flags & CHANGED_BIT) {
1435dfecf96Smrg		source_changed = True;
1445dfecf96Smrg		break;
1455dfecf96Smrg	    }
1465dfecf96Smrg    }
1475dfecf96Smrg    if(!source_changed) {
1485dfecf96Smrg#ifndef __UNIXOS2__
1495dfecf96Smrg	XeditLispCleanUp();
1505dfecf96Smrg#endif
1515dfecf96Smrg	exit(0);
1525dfecf96Smrg    }
1535dfecf96Smrg
1545dfecf96Smrg    XeditPrintf("Unsaved changes. Save them, or Quit again.\n");
1555dfecf96Smrg    Feep();
1565dfecf96Smrg    double_click = TRUE;
1575dfecf96Smrg    dc_state = DC_UNSAVED;
1585dfecf96Smrg    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
1595dfecf96Smrg}
1605dfecf96Smrg
1615dfecf96Smrgstatic char *
1625dfecf96SmrgmakeBackupName(String buf, String filename, unsigned len)
1635dfecf96Smrg{
1645dfecf96Smrg    if (app_resources.backupNamePrefix
1655dfecf96Smrg	&& strlen(app_resources.backupNamePrefix)) {
1665dfecf96Smrg	if (strchr(app_resources.backupNamePrefix, '/'))
1675dfecf96Smrg	    XmuSnprintf(buf, len, "%s%s%s", app_resources.backupNamePrefix,
1685dfecf96Smrg			filename, app_resources.backupNameSuffix);
1695dfecf96Smrg	else {
1705dfecf96Smrg	    char fname[BUFSIZ];
1715dfecf96Smrg	    char *name, ch;
1725dfecf96Smrg
1735dfecf96Smrg	    strncpy(fname, filename, sizeof(fname) - 1);
1745dfecf96Smrg	    fname[sizeof(fname) - 1] = '\0';
1755dfecf96Smrg	    if ((name = strrchr(fname, '/')) != NULL)
1765dfecf96Smrg		++name;
1775dfecf96Smrg	    else
1785dfecf96Smrg		name = filename;
1795dfecf96Smrg	    ch = *name;
1805dfecf96Smrg	    *name = '\0';
1815dfecf96Smrg	    ++name;
1825dfecf96Smrg	    XmuSnprintf(buf, len, "%s%s%c%s%s",
1835dfecf96Smrg			fname, app_resources.backupNamePrefix, ch, name,
1845dfecf96Smrg			app_resources.backupNameSuffix);
1855dfecf96Smrg	}
1865dfecf96Smrg    }
1875dfecf96Smrg    else
1885dfecf96Smrg	XmuSnprintf(buf, len, "%s%s",
1895dfecf96Smrg		    filename, app_resources.backupNameSuffix);
1905dfecf96Smrg
1915dfecf96Smrg    return (strcmp(filename, buf) ? buf : NULL);
1925dfecf96Smrg}
1935dfecf96Smrg
1945dfecf96Smrg#if defined(USG) && !defined(CRAY)
1955dfecf96Smrgint rename (from, to)
1965dfecf96Smrg    char *from, *to;
1975dfecf96Smrg{
1985dfecf96Smrg    (void) unlink (to);
1995dfecf96Smrg    if (link (from, to) == 0) {
2005dfecf96Smrg        unlink (from);
2015dfecf96Smrg        return 0;
2025dfecf96Smrg    } else {
2035dfecf96Smrg        return -1;
2045dfecf96Smrg    }
2055dfecf96Smrg}
2065dfecf96Smrg#endif
2075dfecf96Smrg
2085dfecf96Smrg/*ARGSUSED*/
2095dfecf96Smrgvoid
2105dfecf96SmrgSaveFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
2115dfecf96Smrg{
2125dfecf96Smrg    DoSave(w, NULL, NULL);
2135dfecf96Smrg}
2145dfecf96Smrg
2155dfecf96Smrg/*ARGSUSED*/
2165dfecf96Smrgvoid
2175dfecf96SmrgDoSave(Widget w, XtPointer client_data, XtPointer call_data)
2185dfecf96Smrg{
2195dfecf96Smrg    String name = GetString(filenamewindow);
2205dfecf96Smrg    String filename = ResolveName(name);
2215dfecf96Smrg    char buf[BUFSIZ];
2225dfecf96Smrg    FileAccess file_access;
2235dfecf96Smrg    xedit_flist_item *item;
2245dfecf96Smrg    Boolean exists;
2255dfecf96Smrg    Widget source = XawTextGetSource(textwindow);
2265dfecf96Smrg
2275dfecf96Smrg    if (!filename) {
2285dfecf96Smrg	XeditPrintf("Save: Can't resolve pathname -- nothing saved.\n");
2295dfecf96Smrg	Feep();
2305dfecf96Smrg	return;
2315dfecf96Smrg    }
2325dfecf96Smrg    else if (*name == '\0') {
2335dfecf96Smrg	XeditPrintf("Save: No filename specified -- nothing saved.\n");
2345dfecf96Smrg	Feep();
2355dfecf96Smrg	return;
2365dfecf96Smrg    }
2375dfecf96Smrg    else {
2385dfecf96Smrg	struct stat st;
2395dfecf96Smrg
2405dfecf96Smrg	if (stat(filename, &st) == 0 && !S_ISREG(st.st_mode)) {
2415dfecf96Smrg	    XmuSnprintf(buf, sizeof(buf),
2425dfecf96Smrg			"Save: file %s is not a regular file -- nothing saved.\n",
2435dfecf96Smrg			name);
2445dfecf96Smrg	    XeditPrintf(buf);
2455dfecf96Smrg	    Feep();
2465dfecf96Smrg	    return;
2475dfecf96Smrg	}
2485dfecf96Smrg    }
2495dfecf96Smrg
2505dfecf96Smrg    item = FindTextSource(NULL, filename);
2515dfecf96Smrg    if (item != NULL && item->source != source) {
2525dfecf96Smrg	if (!double_click || (dc_state && dc_state != DC_LOADED)) {
2535dfecf96Smrg	    XmuSnprintf(buf, sizeof(buf),
2545dfecf96Smrg			"Save: file %s is already loaded, "
2555dfecf96Smrg			"Save again to unload it -- nothing saved.\n",
2565dfecf96Smrg			name);
2575dfecf96Smrg	    XeditPrintf(buf);
2585dfecf96Smrg	    Feep();
2595dfecf96Smrg	    double_click = TRUE;
2605dfecf96Smrg	    dc_state = DC_LOADED;
2615dfecf96Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
2625dfecf96Smrg	    return;
2635dfecf96Smrg	}
2645dfecf96Smrg	KillTextSource(item);
2655dfecf96Smrg	item = FindTextSource(source = XawTextGetSource(textwindow), NULL);
2665dfecf96Smrg	double_click = FALSE;
2675dfecf96Smrg	dc_state = 0;
2685dfecf96Smrg    }
2695dfecf96Smrg    else if (item && !(item->flags & CHANGED_BIT)) {
2705dfecf96Smrg	if (!double_click || (dc_state && dc_state != DC_SAVE)) {
2715dfecf96Smrg	    XeditPrintf("Save: No changes need to be saved, "
2725dfecf96Smrg			"Save again to override.\n");
2735dfecf96Smrg	    Feep();
2745dfecf96Smrg	    double_click = TRUE;
2755dfecf96Smrg	    dc_state = DC_SAVE;
2765dfecf96Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
2775dfecf96Smrg	    return;
2785dfecf96Smrg	}
2795dfecf96Smrg	double_click = FALSE;
2805dfecf96Smrg	dc_state = 0;
2815dfecf96Smrg    }
2825dfecf96Smrg
2835dfecf96Smrg    file_access = CheckFilePermissions(filename, &exists);
2845dfecf96Smrg    if (!item || strcmp(item->filename, filename)) {
2855dfecf96Smrg	if (file_access == WRITE_OK && exists) {
2865dfecf96Smrg	    if (!double_click || (dc_state && dc_state != DC_CLOBBER)) {
2875dfecf96Smrg		XmuSnprintf(buf, sizeof(buf),
2885dfecf96Smrg			    "Save: file %s already exists, "
2895dfecf96Smrg			    "Save again to overwrite it -- nothing saved.\n",
2905dfecf96Smrg			    name);
2915dfecf96Smrg		XeditPrintf(buf);
2925dfecf96Smrg		Feep();
2935dfecf96Smrg		double_click = TRUE;
2945dfecf96Smrg		dc_state = DC_CLOBBER;
2955dfecf96Smrg		AddDoubleClickCallback(XawTextGetSource(textwindow), True);
2965dfecf96Smrg		return;
2975dfecf96Smrg	    }
2985dfecf96Smrg	    double_click = FALSE;
2995dfecf96Smrg	    dc_state = 0;
3005dfecf96Smrg	}
3015dfecf96Smrg	if (!item)
3025dfecf96Smrg	    item = FindTextSource(source, NULL);
3035dfecf96Smrg    }
3045dfecf96Smrg
3055dfecf96Smrg  if (app_resources.enableBackups && exists) {
3065dfecf96Smrg    char backup_file[BUFSIZ];
3075dfecf96Smrg
3085dfecf96Smrg    if (makeBackupName(backup_file, filename, sizeof(backup_file)) == NULL
3095dfecf96Smrg	|| rename(filename, backup_file) != 0) {
3105dfecf96Smrg	XmuSnprintf(buf, sizeof(buf),"error backing up file:  %s\n",
3115dfecf96Smrg		    filename);
3125dfecf96Smrg      XeditPrintf(buf);
3135dfecf96Smrg    }
3145dfecf96Smrg  }
3155dfecf96Smrg
3165dfecf96Smrg  switch( file_access = MaybeCreateFile(filename)) {
3175dfecf96Smrg  case NO_READ:
3185dfecf96Smrg  case READ_OK:
3195dfecf96Smrg      XmuSnprintf(buf, sizeof(buf),
3205dfecf96Smrg		  "File %s could not be opened for writing.\n", name);
3215dfecf96Smrg      Feep();
3225dfecf96Smrg      break;
3235dfecf96Smrg  case WRITE_OK:
3245dfecf96Smrg      if ( XawAsciiSaveAsFile(source, filename) ) {
3255dfecf96Smrg	  int i;
3265dfecf96Smrg	  Arg args[1];
3275dfecf96Smrg	  char label_buf[BUFSIZ];
3285dfecf96Smrg
3295dfecf96Smrg	  /* Keep file protection mode */
3305dfecf96Smrg	  if (item && item->mode)
3315dfecf96Smrg	      chmod(filename, item->mode);
3325dfecf96Smrg
3335dfecf96Smrg	  XmuSnprintf(label_buf, sizeof(label_buf),
3345dfecf96Smrg		      "%s       Read - Write", name);
3355dfecf96Smrg	  XtSetArg(args[0], XtNlabel, label_buf);
3365dfecf96Smrg	  for (i = 0; i < 3; i++)
3375dfecf96Smrg	      if (XawTextGetSource(texts[i]) == source)
3385dfecf96Smrg		  XtSetValues(labels[i], args, 1);
3395dfecf96Smrg
3405dfecf96Smrg	  XmuSnprintf(buf, sizeof(buf), "Saved file:  %s\n", name);
3415dfecf96Smrg
3425dfecf96Smrg	  if (item && item->source != scratch) {
3435dfecf96Smrg	      XtSetArg(args[0], XtNlabel, filename);
3445dfecf96Smrg	      XtSetValues(item->sme, args, 1);
3455dfecf96Smrg
3465dfecf96Smrg	      XtSetArg(args[0], XtNeditType, XawtextEdit);
3475dfecf96Smrg	      XtSetValues(item->source, args, 1);
3485dfecf96Smrg
3495dfecf96Smrg	      XtFree(item->name);
3505dfecf96Smrg	      XtFree(item->filename);
3515dfecf96Smrg	      item->name = XtNewString(name);
3525dfecf96Smrg	      item->filename = XtNewString(filename);
3535dfecf96Smrg	      item->flags = EXISTS_BIT;
3545dfecf96Smrg	  }
3555dfecf96Smrg	  else {
3565dfecf96Smrg	      item = flist.itens[0];
3575dfecf96Smrg	      XtRemoveCallback(scratch, XtNcallback, SourceChanged,
3585dfecf96Smrg			       (XtPointer)item);
3595dfecf96Smrg	      item->source = scratch =
3605dfecf96Smrg		  XtVaCreateWidget("textSource",
3615dfecf96Smrg				   multiSrcObjectClass,
3625dfecf96Smrg				   topwindow,
3635dfecf96Smrg				   XtNtype, XawAsciiFile,
3645dfecf96Smrg				   XtNeditType, XawtextEdit,
3655dfecf96Smrg				   NULL, NULL);
3665dfecf96Smrg	      ResetSourceChanged(item);
3675dfecf96Smrg	      XtAddCallback(scratch, XtNcallback, SourceChanged,
3685dfecf96Smrg			    (XtPointer)item);
3695dfecf96Smrg
3705dfecf96Smrg	      item = AddTextSource(source, name, filename, EXISTS_BIT,
3715dfecf96Smrg				   file_access);
3725dfecf96Smrg	      XtAddCallback(item->source, XtNcallback, SourceChanged,
3735dfecf96Smrg			    (XtPointer)item);
3745dfecf96Smrg	  }
3755dfecf96Smrg	  item->flags |= EXISTS_BIT;
3765dfecf96Smrg	  ResetSourceChanged(item);
3775dfecf96Smrg      }
3785dfecf96Smrg      else {
3795dfecf96Smrg	  XmuSnprintf(buf, sizeof(buf), "Error saving file:  %s\n",  name);
3805dfecf96Smrg	  Feep();
3815dfecf96Smrg      }
3825dfecf96Smrg      break;
3835dfecf96Smrg  default:
3845dfecf96Smrg      XmuSnprintf(buf, sizeof(buf), "%s %s",
3855dfecf96Smrg		  "Internal function MaybeCreateFile()",
3865dfecf96Smrg	      "returned unexpected value.\n");
3875dfecf96Smrg      Feep();
3885dfecf96Smrg      break;
3895dfecf96Smrg  }
3905dfecf96Smrg
3915dfecf96Smrg  XeditPrintf(buf);
3925dfecf96Smrg}
3935dfecf96Smrg
3945dfecf96Smrg/*ARGSUSED*/
3955dfecf96Smrgvoid
3965dfecf96SmrgDoLoad(Widget w, XtPointer client_data, XtPointer call_data)
3975dfecf96Smrg{
3985dfecf96Smrg    if (ReallyDoLoad(GetString(filenamewindow), ResolveName(NULL))) {
3995dfecf96Smrg        SwitchDirWindow(False);
4005dfecf96Smrg        XtSetKeyboardFocus(topwindow, textwindow);
4015dfecf96Smrg    }
4025dfecf96Smrg}
4035dfecf96Smrg
4045dfecf96Smrgstatic Bool
4055dfecf96SmrgReallyDoLoad(char *name, char *filename)
4065dfecf96Smrg{
4075dfecf96Smrg    Arg args[5];
4085dfecf96Smrg    Cardinal num_args = 0;
4095dfecf96Smrg    char buf[BUFSIZ];
4105dfecf96Smrg    xedit_flist_item *item;
4115dfecf96Smrg    Widget source = XawTextGetSource(textwindow);
4125dfecf96Smrg
4135dfecf96Smrg    if (!filename) {
4145dfecf96Smrg	XeditPrintf("Load: Can't resolve pathname.\n");
4155dfecf96Smrg	Feep();
4165dfecf96Smrg	return (False);
4175dfecf96Smrg    }
4185dfecf96Smrg    else if (*name == '\0') {
4195dfecf96Smrg	XeditPrintf("Load: No file specified.\n");
4205dfecf96Smrg	Feep();
4215dfecf96Smrg    }
4225dfecf96Smrg    if ((item = FindTextSource(NULL, filename)) != NULL) {
4235dfecf96Smrg	SwitchTextSource(item);
4245dfecf96Smrg	return (True);
4255dfecf96Smrg    }
4265dfecf96Smrg    else {
4275dfecf96Smrg	struct stat st;
4285dfecf96Smrg
4295dfecf96Smrg	if (stat(filename, &st) == 0 && !S_ISREG(st.st_mode)) {
4305dfecf96Smrg	    if (S_ISDIR(st.st_mode)) {
4315dfecf96Smrg		char path[BUFSIZ + 1];
4325dfecf96Smrg
4335dfecf96Smrg		strncpy(path, filename, sizeof(path) - 2);
4345dfecf96Smrg		path[sizeof(path) - 2] = '\0';
4355dfecf96Smrg		if (*path) {
4365dfecf96Smrg		    if (path[strlen(path) - 1] != '/')
4375dfecf96Smrg			strcat(path, "/");
4385dfecf96Smrg		}
4395dfecf96Smrg		else
4405dfecf96Smrg		    strcpy(path, "./");
4415dfecf96Smrg		XtSetArg(args[0], XtNlabel, "");
4425dfecf96Smrg		XtSetValues(dirlabel, args, 1);
4435dfecf96Smrg		SwitchDirWindow(True);
4445dfecf96Smrg		DirWindowCB(dirwindow, path, NULL);
4455dfecf96Smrg		return (False);
4465dfecf96Smrg	    }
4475dfecf96Smrg	}
4485dfecf96Smrg    }
4495dfecf96Smrg
4505dfecf96Smrg    {
4515dfecf96Smrg	Boolean exists;
4525dfecf96Smrg	int flags;
4535dfecf96Smrg	FileAccess file_access;
4545dfecf96Smrg
4555dfecf96Smrg	switch( file_access = CheckFilePermissions(filename, &exists) ) {
4565dfecf96Smrg	case NO_READ:
4575dfecf96Smrg	    if (exists)
4585dfecf96Smrg		XmuSnprintf(buf, sizeof(buf), "File %s, %s", name,
4595dfecf96Smrg			"exists, and could not be opened for reading.\n");
4605dfecf96Smrg	    else
4615dfecf96Smrg		XmuSnprintf(buf, sizeof(buf), "File %s %s %s",  name,
4625dfecf96Smrg			    "does not exist, and",
4635dfecf96Smrg			"the directory could not be opened for writing.\n");
4645dfecf96Smrg
4655dfecf96Smrg	    XeditPrintf(buf);
4665dfecf96Smrg	    Feep();
4675dfecf96Smrg	    return (False);
4685dfecf96Smrg	case READ_OK:
4695dfecf96Smrg	    XtSetArg(args[num_args], XtNeditType, XawtextRead); num_args++;
4705dfecf96Smrg	    XmuSnprintf(buf, sizeof(buf), "File %s opened READ ONLY.\n",
4715dfecf96Smrg			name);
4725dfecf96Smrg	    break;
4735dfecf96Smrg	case WRITE_OK:
4745dfecf96Smrg	    XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
4755dfecf96Smrg	    XmuSnprintf(buf, sizeof(buf), "File %s opened read - write.\n",
4765dfecf96Smrg			name);
4775dfecf96Smrg	    break;
4785dfecf96Smrg	default:
4795dfecf96Smrg	    XmuSnprintf(buf, sizeof(buf), "%s %s",
4805dfecf96Smrg			"Internal function MaybeCreateFile()",
4815dfecf96Smrg		    "returned unexpected value.\n");
4825dfecf96Smrg	    XeditPrintf(buf);
4835dfecf96Smrg	    Feep();
4845dfecf96Smrg	    return (False);
4855dfecf96Smrg	}
4865dfecf96Smrg
4875dfecf96Smrg	XeditPrintf(buf);
4885dfecf96Smrg
4895dfecf96Smrg	if (exists) {
4905dfecf96Smrg	    flags = EXISTS_BIT;
4915dfecf96Smrg	    XtSetArg(args[num_args], XtNstring, filename); num_args++;
4925dfecf96Smrg	}
4935dfecf96Smrg	else {
4945dfecf96Smrg	    flags = 0;
4955dfecf96Smrg	    XtSetArg(args[num_args], XtNstring, NULL); num_args++;
4965dfecf96Smrg	}
4975dfecf96Smrg
4985dfecf96Smrg	source = XtVaCreateWidget("textSource",
4995dfecf96Smrg				  multiSrcObjectClass,
5005dfecf96Smrg				  topwindow,
5015dfecf96Smrg				  XtNtype, XawAsciiFile,
5025dfecf96Smrg				  XtNeditType, XawtextEdit,
5035dfecf96Smrg				  NULL, NULL);
5045dfecf96Smrg	XtSetValues(source, args, num_args);
5055dfecf96Smrg
5065dfecf96Smrg	item = AddTextSource(source, name, filename, flags, file_access);
5075dfecf96Smrg	XtAddCallback(item->source, XtNcallback, SourceChanged,
5085dfecf96Smrg		      (XtPointer)item);
5095dfecf96Smrg	if (exists && file_access == WRITE_OK) {
5105dfecf96Smrg	    struct stat st;
5115dfecf96Smrg
5125dfecf96Smrg	    if (stat(filename, &st) == 0)
5135dfecf96Smrg		item->mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
5145dfecf96Smrg	}
5155dfecf96Smrg	SwitchTextSource(item);
5165dfecf96Smrg	ResetSourceChanged(item);
5175dfecf96Smrg    }
5185dfecf96Smrg
5195dfecf96Smrg    return (True);
5205dfecf96Smrg}
5215dfecf96Smrg
5225dfecf96Smrg#ifdef INCLUDE_XPRINT_SUPPORT
5235dfecf96Smrgstatic void
5245dfecf96SmrgprintshellDestroyXtProc(Widget w, XtPointer client_data, XtPointer callData)
5255dfecf96Smrg{
5265dfecf96Smrg    XawPrintDialogClosePrinterConnection(printdialog, False);
5275dfecf96Smrg}
5285dfecf96Smrg
5295dfecf96Smrgstatic void
5305dfecf96SmrgprintOKXtProc(Widget w, XtPointer client_data, XtPointer callData)
5315dfecf96Smrg{
5325dfecf96Smrg    XawPrintDialogCallbackStruct *pdcs = (XawPrintDialogCallbackStruct *)callData;
5335dfecf96Smrg    Cardinal                      n;
5345dfecf96Smrg    Arg                           args[2];
5355dfecf96Smrg    Widget                        textsource;
5365dfecf96Smrg
5375dfecf96Smrg    Log(("printOKXtProc: OK.\n"));
5385dfecf96Smrg
5395dfecf96Smrg    /* Get TextSource object */
5405dfecf96Smrg    n = 0;
5415dfecf96Smrg    XtSetArg(args[n], XtNtextSource, &textsource); n++;
5425dfecf96Smrg    XtGetValues(textwindow, args, n);
5435dfecf96Smrg
5445dfecf96Smrg    Assertion(textsource != NULL, (("printOKXtProc: textsource == NULL.\n")));
5455dfecf96Smrg
5465dfecf96Smrg    /* ||printJobNameBuffer| must live as long the print job prints
5475dfecf96Smrg     * because it is used for the job title AND the page headers... */
5485dfecf96Smrg    sprintf(printJobNameBuffer, "Xedit print job");
5495dfecf96Smrg
5505dfecf96Smrg    DoPrintTextSource("Xedit",
5515dfecf96Smrg                      textsource, topwindow,
5525dfecf96Smrg                      pdcs->pdpy, pdcs->pcontext, pdcs->colorspace,
5535dfecf96Smrg                      printshellDestroyXtProc,
5545dfecf96Smrg                      printJobNameBuffer,
5555dfecf96Smrg                      pdcs->printToFile?pdcs->printToFileName:NULL);
5565dfecf96Smrg
5575dfecf96Smrg    XtPopdown(printdialog_shell);
5585dfecf96Smrg}
5595dfecf96Smrg
5605dfecf96Smrgstatic void
5615dfecf96SmrgprintCancelXtProc(Widget w, XtPointer client_data, XtPointer callData)
5625dfecf96Smrg{
5635dfecf96Smrg    Log(("printCancelXtProc: cancel.\n"));
5645dfecf96Smrg    XtPopdown(printdialog_shell);
5655dfecf96Smrg
5665dfecf96Smrg    Log(("destroying print dialog shell...\n"));
5675dfecf96Smrg    XtDestroyWidget(printdialog_shell);
5685dfecf96Smrg    printdialog_shell = NULL;
5695dfecf96Smrg    printdialog       = NULL;
5705dfecf96Smrg    Log(("... done\n"));
5715dfecf96Smrg}
5725dfecf96Smrg
5735dfecf96Smrg
5745dfecf96Smrg/*ARGSUSED*/
5755dfecf96Smrgvoid
5765dfecf96SmrgPrintFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
5775dfecf96Smrg{
5785dfecf96Smrg    DoPrint(w, NULL, NULL);
5795dfecf96Smrg}
5805dfecf96Smrg
5815dfecf96Smrg/*ARGSUSED*/
5825dfecf96Smrgvoid
5835dfecf96SmrgDoPrint(Widget w, XtPointer client_data, XtPointer call_data)
5845dfecf96Smrg{
5855dfecf96Smrg  Dimension   width, height;
5865dfecf96Smrg  Position    x, y;
5875dfecf96Smrg  Widget      parent = topwindow;
5885dfecf96Smrg  Log(("print!\n"));
5895dfecf96Smrg
5905dfecf96Smrg  if (!printdialog) {
5915dfecf96Smrg    int n;
5925dfecf96Smrg    Arg args[20];
5935dfecf96Smrg
5945dfecf96Smrg    n = 0;
5955dfecf96Smrg    XtSetArg(args[n], XtNallowShellResize, True); n++;
5965dfecf96Smrg    printdialog_shell = XtCreatePopupShell("printdialogshell",
5975dfecf96Smrg                                           transientShellWidgetClass,
5985dfecf96Smrg                                           topwindow, args, n);
5995dfecf96Smrg    n = 0;
6005dfecf96Smrg    printdialog = XtCreateManagedWidget("printdialog", printDialogWidgetClass,
6015dfecf96Smrg                                        printdialog_shell, args, n);
6025dfecf96Smrg    XtAddCallback(printdialog, XawNOkCallback,     printOKXtProc,     NULL);
6035dfecf96Smrg    XtAddCallback(printdialog, XawNCancelCallback, printCancelXtProc, NULL);
6045dfecf96Smrg
6055dfecf96Smrg    XtRealizeWidget(printdialog_shell);
6065dfecf96Smrg  }
6075dfecf96Smrg
6085dfecf96Smrg  /* Center dialog */
6095dfecf96Smrg  XtVaGetValues(printdialog_shell,
6105dfecf96Smrg      XtNwidth,  &width,
6115dfecf96Smrg      XtNheight, &height,
6125dfecf96Smrg      NULL);
6135dfecf96Smrg
6145dfecf96Smrg  x = (Position)(XWidthOfScreen( XtScreen(parent)) - width)  / 2;
6155dfecf96Smrg  y = (Position)(XHeightOfScreen(XtScreen(parent)) - height) / 3;
6165dfecf96Smrg
6175dfecf96Smrg  XtVaSetValues(printdialog_shell,
6185dfecf96Smrg      XtNx, x,
6195dfecf96Smrg      XtNy, y,
6205dfecf96Smrg      NULL);
6215dfecf96Smrg
6225dfecf96Smrg  XtPopup(printdialog_shell, XtGrabNonexclusive);
6235dfecf96Smrg}
6245dfecf96Smrg#endif /* INCLUDE_XPRINT_SUPPORT */
6255dfecf96Smrg
6265dfecf96Smrg/*	Function Name: SourceChanged
6275dfecf96Smrg *	Description: A callback routine called when the source has changed.
6285dfecf96Smrg *	Arguments: w - the text source that has changed.
6295dfecf96Smrg *		   client_data - xedit_flist_item associated with text buffer.
6305dfecf96Smrg *                 call_data - NULL is unchanged
6315dfecf96Smrg *	Returns: none.
6325dfecf96Smrg */
6335dfecf96Smrg/*ARGSUSED*/
6345dfecf96Smrgvoid
6355dfecf96SmrgSourceChanged(Widget w, XtPointer client_data, XtPointer call_data)
6365dfecf96Smrg{
6375dfecf96Smrg    xedit_flist_item *item = (xedit_flist_item*)client_data;
6385dfecf96Smrg    Bool changed = (Bool)(long)call_data;
6395dfecf96Smrg
6405dfecf96Smrg    if (changed) {
6415dfecf96Smrg	if (item->flags & CHANGED_BIT)
6425dfecf96Smrg	    return;
6435dfecf96Smrg	item->flags |= CHANGED_BIT;
6445dfecf96Smrg    }
6455dfecf96Smrg    else {
6465dfecf96Smrg	if (item->flags & CHANGED_BIT)
6475dfecf96Smrg	    ResetSourceChanged(item);
6485dfecf96Smrg	return;
6495dfecf96Smrg    }
6505dfecf96Smrg
6515dfecf96Smrg    if (flist.pixmap) {
6525dfecf96Smrg	Arg args[1];
6535dfecf96Smrg	Cardinal num_args;
6545dfecf96Smrg	int i;
6555dfecf96Smrg
6565dfecf96Smrg	num_args = 0;
6575dfecf96Smrg	XtSetArg(args[num_args], XtNleftBitmap, flist.pixmap);	++num_args;
6585dfecf96Smrg	XtSetValues(item->sme, args, num_args);
6595dfecf96Smrg
6605dfecf96Smrg	for (i = 0; i < 3; i++)
6615dfecf96Smrg	    if (XawTextGetSource(texts[i]) == item->source)
6625dfecf96Smrg		XtSetValues(labels[i], args, num_args);
6635dfecf96Smrg    }
6645dfecf96Smrg}
6655dfecf96Smrg
6665dfecf96Smrg/*	Function Name: ResetSourceChanged.
6675dfecf96Smrg *	Description: Sets the source changed to FALSE, and
6685dfecf96Smrg *                   registers a callback to set it to TRUE when
6695dfecf96Smrg *                   the source has changed.
6705dfecf96Smrg *	Arguments: item - item with widget to register the callback on.
6715dfecf96Smrg *	Returns: none.
6725dfecf96Smrg */
6735dfecf96Smrg
6745dfecf96Smrgvoid
6755dfecf96SmrgResetSourceChanged(xedit_flist_item *item)
6765dfecf96Smrg{
6775dfecf96Smrg    Arg args[1];
6785dfecf96Smrg    Cardinal num_args;
6795dfecf96Smrg    int i;
6805dfecf96Smrg
6815dfecf96Smrg    num_args = 0;
6825dfecf96Smrg    XtSetArg(args[num_args], XtNleftBitmap, None);	++num_args;
6835dfecf96Smrg    XtSetValues(item->sme, args, num_args);
6845dfecf96Smrg
6855dfecf96Smrg    dc_state = 0;
6865dfecf96Smrg    double_click = FALSE;
6875dfecf96Smrg    for (i = 0; i < 3; i++) {
6885dfecf96Smrg	if (XawTextGetSource(texts[i]) == item->source)
6895dfecf96Smrg	    XtSetValues(labels[i], args, num_args);
6905dfecf96Smrg	AddDoubleClickCallback(XawTextGetSource(texts[i]), False);
6915dfecf96Smrg    }
6925dfecf96Smrg
6935dfecf96Smrg    num_args = 0;
6945dfecf96Smrg    XtSetArg(args[num_args], XtNsourceChanged, False);	++num_args;
6955dfecf96Smrg    XtSetValues(item->source, args, num_args);
6965dfecf96Smrg
6975dfecf96Smrg    item->flags &= ~CHANGED_BIT;
6985dfecf96Smrg}
6995dfecf96Smrg
7005dfecf96Smrg/*ARGSUSED*/
7015dfecf96Smrgvoid
7025dfecf96SmrgKillFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
7035dfecf96Smrg{
7045dfecf96Smrg    xedit_flist_item *item = FindTextSource(XawTextGetSource(textwindow), NULL);
7055dfecf96Smrg
7065dfecf96Smrg    if (item->source == scratch) {
7075dfecf96Smrg	Feep();
7085dfecf96Smrg	return;
7095dfecf96Smrg    }
7105dfecf96Smrg
7115dfecf96Smrg    if (item->flags & CHANGED_BIT) {
7125dfecf96Smrg	if (!double_click || (dc_state && dc_state != DC_KILL)) {
7135dfecf96Smrg	    XeditPrintf("Kill: Unsaved changes. Kill again to override.\n");
7145dfecf96Smrg	    Feep();
7155dfecf96Smrg	    double_click = TRUE;
7165dfecf96Smrg	    dc_state = DC_KILL;
7175dfecf96Smrg	    AddDoubleClickCallback(XawTextGetSource(textwindow), True);
7185dfecf96Smrg	    return;
7195dfecf96Smrg	}
7205dfecf96Smrg	double_click = FALSE;
7215dfecf96Smrg	dc_state = 0;
7225dfecf96Smrg    }
7235dfecf96Smrg    KillTextSource(item);
7245dfecf96Smrg}
7255dfecf96Smrg
7265dfecf96Smrg/*ARGSUSED*/
7275dfecf96Smrgvoid
7285dfecf96SmrgFindFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
7295dfecf96Smrg{
7305dfecf96Smrg    char *string = GetString(filenamewindow);
7315dfecf96Smrg    char *slash = NULL;
7325dfecf96Smrg    XawTextBlock block;
7335dfecf96Smrg    XawTextPosition end = XawTextSourceScan(XawTextGetSource(filenamewindow),
7345dfecf96Smrg					    0, XawstAll, XawsdRight, 1, True);
7355dfecf96Smrg
7365dfecf96Smrg    if (string)
7375dfecf96Smrg	slash = strrchr(string, '/');
7385dfecf96Smrg    block.firstPos = 0;
7395dfecf96Smrg    block.format = FMT8BIT;
7405dfecf96Smrg    block.ptr = string;
7415dfecf96Smrg    block.length = slash ? slash - string + 1 : 0;
7425dfecf96Smrg
7435dfecf96Smrg    if (block.length != end)
7445dfecf96Smrg	XawTextReplace(filenamewindow, 0, end, &block);
7455dfecf96Smrg    XawTextSetInsertionPoint(filenamewindow, end);
7465dfecf96Smrg    XtSetKeyboardFocus(topwindow, filenamewindow);
7475dfecf96Smrg    line_edit = False;
7485dfecf96Smrg}
7495dfecf96Smrg
7505dfecf96Smrg/*ARGSUSED*/
7515dfecf96Smrgvoid
7525dfecf96SmrgLoadFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
7535dfecf96Smrg{
7545dfecf96Smrg    if (line_edit)
7555dfecf96Smrg	LineEdit(textwindow);
7565dfecf96Smrg    else if (ReallyDoLoad(GetString(filenamewindow), ResolveName(NULL))) {
7575dfecf96Smrg	SwitchDirWindow(False);
7585dfecf96Smrg	XtSetKeyboardFocus(topwindow, textwindow);
7595dfecf96Smrg    }
7605dfecf96Smrg}
7615dfecf96Smrg
7625dfecf96Smrg/*ARGSUSED*/
7635dfecf96Smrgvoid
7645dfecf96SmrgCancelFindFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
7655dfecf96Smrg{
7665dfecf96Smrg    Arg args[1];
7675dfecf96Smrg    xedit_flist_item *item;
7685dfecf96Smrg
7695dfecf96Smrg    XtSetKeyboardFocus(topwindow, textwindow);
7705dfecf96Smrg
7715dfecf96Smrg    item = FindTextSource(XawTextGetSource(textwindow), NULL);
7725dfecf96Smrg
7735dfecf96Smrg    if (item->source != scratch)
7745dfecf96Smrg	XtSetArg(args[0], XtNstring, item->name);
7755dfecf96Smrg    else
7765dfecf96Smrg	XtSetArg(args[0], XtNstring, NULL);
7775dfecf96Smrg
7785dfecf96Smrg    XtSetValues(filenamewindow, args, 1);
7795dfecf96Smrg
7805dfecf96Smrg   if (XtIsManaged(XtParent(dirwindow)))
7815dfecf96Smrg	SwitchDirWindow(False);
7825dfecf96Smrg
7835dfecf96Smrg    line_edit = False;
7845dfecf96Smrg}
7855dfecf96Smrg
7865dfecf96Smrgstatic int
7875dfecf96Smrgcompar(_Xconst void *a, _Xconst void *b)
7885dfecf96Smrg{
7895dfecf96Smrg    return (strcmp(*(char **)a, *(char **)b));
7905dfecf96Smrg}
7915dfecf96Smrg
7925dfecf96Smrg/*ARGSUSED*/
7935dfecf96Smrgvoid
7945dfecf96SmrgFileCompletion(Widget w, XEvent *event, String *params, Cardinal *num_params)
7955dfecf96Smrg{
7965dfecf96Smrg    XawTextBlock block;
7975dfecf96Smrg    String text;
7985dfecf96Smrg    int length;
7995dfecf96Smrg    char **matches, *save, *dir_name, *file_name, match[257];
8005dfecf96Smrg    unsigned n_matches, len, mlen, buflen;
8015dfecf96Smrg    DIR *dir;
8025dfecf96Smrg    Bool changed, slash = False, has_dot = False;
8035dfecf96Smrg#define	SM_NEVER	0
8045dfecf96Smrg#define SM_HINT		1
8055dfecf96Smrg#define SM_ALWAYS	2
8065dfecf96Smrg    int show_matches;
8075dfecf96Smrg
8085dfecf96Smrg    text = GetString(filenamewindow);
8095dfecf96Smrg
8105dfecf96Smrg    if (!text) {
8115dfecf96Smrg	Feep();
8125dfecf96Smrg	return;
8135dfecf96Smrg    }
8145dfecf96Smrg    else if (line_edit) {
8155dfecf96Smrg	Feep();
8165dfecf96Smrg	line_edit = 0;
8175dfecf96Smrg    }
8185dfecf96Smrg
8195dfecf96Smrg    {
8205dfecf96Smrg	XawTextPosition pos = XawTextGetInsertionPoint(w);
8215dfecf96Smrg	char *cslash = strchr(&text[pos], '/'), *cdot = strchr(&text[pos], '.');
8225dfecf96Smrg
8235dfecf96Smrg	if (cslash != NULL || cdot != NULL) {
8245dfecf96Smrg	    if (cslash != NULL && (cdot == NULL || cdot > cslash)) {
8255dfecf96Smrg		length = cslash - text;
8265dfecf96Smrg		slash = True;
8275dfecf96Smrg	    }
8285dfecf96Smrg	    else {
8295dfecf96Smrg		length = cdot - text;
8305dfecf96Smrg		has_dot = True;
8315dfecf96Smrg	    }
8325dfecf96Smrg	}
8335dfecf96Smrg	else
8345dfecf96Smrg	    length = strlen(text);
8355dfecf96Smrg    }
8365dfecf96Smrg
8375dfecf96Smrg    if (*num_params == 1 && length == strlen(text)) {
8385dfecf96Smrg	switch (params[0][0]) {
8395dfecf96Smrg	case 'n':		/* Never */
8405dfecf96Smrg	case 'N':
8415dfecf96Smrg	    show_matches = SM_NEVER;
8425dfecf96Smrg	    break;
8435dfecf96Smrg	case 'h':		/* Hint */
8445dfecf96Smrg	case 'H':
8455dfecf96Smrg	    show_matches = SM_HINT;
8465dfecf96Smrg	    break;
8475dfecf96Smrg	case 'a':		/* Always */
8485dfecf96Smrg	case 'A':
8495dfecf96Smrg	    show_matches = SM_ALWAYS;
8505dfecf96Smrg	    break;
8515dfecf96Smrg	default:
8525dfecf96Smrg	    show_matches = SM_NEVER;
8535dfecf96Smrg	    XtAppWarning(XtWidgetToApplicationContext(w),
8545dfecf96Smrg			 "Bad argument to file-completion, "
8555dfecf96Smrg			 "must be Never, Hint or Always");
8565dfecf96Smrg	    break;
8575dfecf96Smrg	}
8585dfecf96Smrg    }
8595dfecf96Smrg    else
8605dfecf96Smrg	show_matches = SM_NEVER;
8615dfecf96Smrg
8625dfecf96Smrg    matches = NULL;
8635dfecf96Smrg    n_matches = buflen = 0;
8645dfecf96Smrg    save = XtMalloc(length + 1);
8655dfecf96Smrg    memmove(save, text, length);
8665dfecf96Smrg    save[length] = '\0';
8675dfecf96Smrg
8685dfecf96Smrg    if (save[0] == '~' && save[1]) {
8695dfecf96Smrg	char *slash2 = strchr(save, '/');
8705dfecf96Smrg
8715dfecf96Smrg	if (slash2) {
8725dfecf96Smrg	    struct passwd *pw;
8735dfecf96Smrg	    char home[BUFSIZ];
8745dfecf96Smrg	    char *name;
8755dfecf96Smrg	    int slen = strlen(save), diff = slash2 - save;
8765dfecf96Smrg
8775dfecf96Smrg	    *slash2 = '\0';
8785dfecf96Smrg	    name = save + 1;
8795dfecf96Smrg	    if (strlen(name) != 0)
8805dfecf96Smrg		pw = getpwnam(name);
8815dfecf96Smrg	    else
8825dfecf96Smrg		pw = getpwuid(getuid());
8835dfecf96Smrg
8845dfecf96Smrg	    if (pw) {
8855dfecf96Smrg		char fname[BUFSIZ];
8865dfecf96Smrg		int hlen;
8875dfecf96Smrg
8885dfecf96Smrg		strncpy(home, pw->pw_dir, sizeof(home) - 1);
8895dfecf96Smrg		home[sizeof(home) - 1] = '\0';
8905dfecf96Smrg		hlen = strlen(home);
8915dfecf96Smrg		strncpy(fname, slash2 + 1, sizeof(fname) - 1);
8925dfecf96Smrg		fname[sizeof(fname) - 1] = '\0';
8935dfecf96Smrg		save = XtRealloc(save, slen - diff + hlen + 2);
8945dfecf96Smrg		(void)memmove(&save[hlen], slash2, slen - diff + 1);
8955dfecf96Smrg		(void)memmove(save, home, hlen);
8965dfecf96Smrg		save[hlen] = '/';
8975dfecf96Smrg		strcpy(&save[hlen + 1], fname);
8985dfecf96Smrg
8995dfecf96Smrg		/* expand directory */
9005dfecf96Smrg		block.length = strlen(save);
9015dfecf96Smrg		block.ptr = save;
9025dfecf96Smrg		block.firstPos = 0;
9035dfecf96Smrg		block.format = FMT8BIT;
9045dfecf96Smrg		XawTextReplace(filenamewindow, 0, length, &block);
9055dfecf96Smrg		XawTextSetInsertionPoint(filenamewindow, length = block.length);
9065dfecf96Smrg	    }
9075dfecf96Smrg	    else
9085dfecf96Smrg		*slash2 = '/';
9095dfecf96Smrg	}
9105dfecf96Smrg    }
9115dfecf96Smrg
9125dfecf96Smrg    if ((file_name = strrchr(save, '/')) != NULL) {
9135dfecf96Smrg	*file_name = '\0';
9145dfecf96Smrg	++file_name;
9155dfecf96Smrg	dir_name = save;
9165dfecf96Smrg	if (!file_name[0])
9175dfecf96Smrg	    slash = True;
9185dfecf96Smrg	if (!dir_name[0])
9195dfecf96Smrg	    dir_name = "/";
9205dfecf96Smrg    }
9215dfecf96Smrg    else {
9225dfecf96Smrg	dir_name = ".";
9235dfecf96Smrg	file_name = save;
9245dfecf96Smrg    }
9255dfecf96Smrg    len = strlen(file_name);
9265dfecf96Smrg
9275dfecf96Smrg    if ((dir = opendir(dir_name)) != NULL) {
9285dfecf96Smrg	char path[BUFSIZ], *pptr;
9295dfecf96Smrg	struct dirent *ent;
9305dfecf96Smrg	int isdir = 0, first = 1, bytes;
9315dfecf96Smrg
9325dfecf96Smrg	XmuSnprintf(path, sizeof(path), "%s/", dir_name);
9335dfecf96Smrg	pptr = path + strlen(path);
9345dfecf96Smrg	bytes = sizeof(path) - (pptr - path) - 1;
9355dfecf96Smrg
9365dfecf96Smrg	mlen = 0;
9375dfecf96Smrg	match[0] = '\0';
9385dfecf96Smrg	(void)readdir(dir);	/* "." */
9395dfecf96Smrg	(void)readdir(dir);	/* ".." */
9405dfecf96Smrg	while ((ent = readdir(dir)) != NULL) {
9415dfecf96Smrg	    unsigned d_namlen = strlen(ent->d_name);
9425dfecf96Smrg
9435dfecf96Smrg	    if (d_namlen >= len && strncmp(ent->d_name, file_name, len) == 0) {
9445dfecf96Smrg		char *tmp = &(ent->d_name[len]), *mat = match;
9455dfecf96Smrg		struct stat st;
9465dfecf96Smrg		Bool is_dir = FALSE;
9475dfecf96Smrg
9485dfecf96Smrg		strncpy(pptr, ent->d_name, bytes);
9495dfecf96Smrg		pptr[bytes] = '\0';
9505dfecf96Smrg		if (stat(path, &st) != 0)
9515dfecf96Smrg		    /* Should check errno, may be a broken symbolic link
9525dfecf96Smrg		     * a directory with r-- permission, etc */
9535dfecf96Smrg		    continue;
9545dfecf96Smrg		else if (first || show_matches != SM_NEVER) {
9555dfecf96Smrg		    is_dir = S_ISDIR(st.st_mode);
9565dfecf96Smrg		}
9575dfecf96Smrg
9585dfecf96Smrg		if (first) {
9595dfecf96Smrg		    strncpy(match, tmp, sizeof(match) - 1);
9605dfecf96Smrg		    match[sizeof(match) - 2] = '\0';
9615dfecf96Smrg		    mlen = strlen(match);
9625dfecf96Smrg		    first = 0;
9635dfecf96Smrg		    isdir = is_dir;
9645dfecf96Smrg		}
9655dfecf96Smrg		else {
9665dfecf96Smrg		    while (*tmp && *mat && *tmp++ == *mat)
9675dfecf96Smrg			++mat;
9685dfecf96Smrg		    if (mlen > mat - match) {
9695dfecf96Smrg			mlen = mat - match;
9705dfecf96Smrg			match[mlen] = '\0';
9715dfecf96Smrg		    }
9725dfecf96Smrg		}
9735dfecf96Smrg		if (show_matches != SM_NEVER) {
9745dfecf96Smrg		    matches = (char **)XtRealloc((char*)matches, sizeof(char**)
9755dfecf96Smrg						 * (n_matches + 1));
9765dfecf96Smrg		    buflen += d_namlen + 1;
9775dfecf96Smrg		    if (is_dir) {
9785dfecf96Smrg			matches[n_matches] = XtMalloc(d_namlen + 2);
9795dfecf96Smrg			strcpy(matches[n_matches], ent->d_name);
9805dfecf96Smrg			strcat(matches[n_matches], "/");
9815dfecf96Smrg			++buflen;
9825dfecf96Smrg		    }
9835dfecf96Smrg		    else
9845dfecf96Smrg			matches[n_matches] = XtNewString(ent->d_name);
9855dfecf96Smrg		}
9865dfecf96Smrg		else if (mlen == 0 && n_matches >= 1) {
9875dfecf96Smrg		    ++n_matches;
9885dfecf96Smrg		    break;
9895dfecf96Smrg		}
9905dfecf96Smrg		++n_matches;
9915dfecf96Smrg	    }
9925dfecf96Smrg	}
9935dfecf96Smrg
9945dfecf96Smrg	closedir(dir);
9955dfecf96Smrg	changed = mlen != 0;
9965dfecf96Smrg
9975dfecf96Smrg	if (n_matches) {
9985dfecf96Smrg	    Bool free_matches = True, add_slash = n_matches == 1 && isdir && !slash;
9995dfecf96Smrg
10005dfecf96Smrg	    if (mlen && has_dot && match[mlen - 1] == '.')
10015dfecf96Smrg		--mlen;
10025dfecf96Smrg
10035dfecf96Smrg	    if (mlen || add_slash) {
10045dfecf96Smrg		XawTextPosition pos;
10055dfecf96Smrg
10065dfecf96Smrg		block.firstPos = 0;
10075dfecf96Smrg		block.format = FMT8BIT;
10085dfecf96Smrg		if (mlen) {
10095dfecf96Smrg		    pos = length;
10105dfecf96Smrg		    block.length = mlen;
10115dfecf96Smrg		    block.ptr = match;
10125dfecf96Smrg		    XawTextReplace(filenamewindow, pos, pos, &block);
10135dfecf96Smrg		    XawTextSetInsertionPoint(filenamewindow, pos + block.length);
10145dfecf96Smrg		}
10155dfecf96Smrg		if (add_slash) {
10165dfecf96Smrg		    XawTextPosition actual = XawTextGetInsertionPoint(w);
10175dfecf96Smrg
10185dfecf96Smrg		    pos = XawTextSourceScan(XawTextGetSource(w), 0, XawstAll,
10195dfecf96Smrg					    XawsdRight, 1, True);
10205dfecf96Smrg		    block.length = 1;
10215dfecf96Smrg		    block.ptr = "/";
10225dfecf96Smrg		    XawTextReplace(filenamewindow, pos, pos, &block);
10235dfecf96Smrg		    if (actual == pos)
10245dfecf96Smrg			XawTextSetInsertionPoint(filenamewindow, pos + 1);
10255dfecf96Smrg		}
10265dfecf96Smrg	    }
10275dfecf96Smrg	    else if (n_matches != 1 || isdir) {
10285dfecf96Smrg		if (show_matches == SM_NEVER)
10295dfecf96Smrg		    Feep();
10305dfecf96Smrg	    }
10315dfecf96Smrg
10325dfecf96Smrg	    if (show_matches != SM_NEVER) {
10335dfecf96Smrg		if (show_matches == SM_ALWAYS || (!changed && n_matches != 1)) {
10345dfecf96Smrg		    char **list = NULL, *label;
10355dfecf96Smrg		    int n_list;
10365dfecf96Smrg		    Arg args[2];
10375dfecf96Smrg
10385dfecf96Smrg		    XtSetArg(args[0], XtNlist, &list);
10395dfecf96Smrg		    XtSetArg(args[1], XtNnumberStrings, &n_list);
10405dfecf96Smrg		    XtGetValues(dirwindow, args, 2);
10415dfecf96Smrg
10425dfecf96Smrg		    matches = (char **)XtRealloc((char*)matches, sizeof(char**)
10435dfecf96Smrg						 * (n_matches + 2));
10445dfecf96Smrg		    matches[n_matches++] = XtNewString("./");
10455dfecf96Smrg		    matches[n_matches++] = XtNewString("../");
10465dfecf96Smrg		    qsort(matches, n_matches, sizeof(char*), compar);
10475dfecf96Smrg		    XtSetArg(args[0], XtNlist, matches);
10485dfecf96Smrg		    XtSetArg(args[1], XtNnumberStrings, n_matches);
10495dfecf96Smrg		    XtSetValues(dirwindow, args, 2);
10505dfecf96Smrg		    if (n_list > 0
10515dfecf96Smrg			&& (n_list != 1 || list[0] != XtName(dirwindow))) {
10525dfecf96Smrg			while (--n_list > -1)
10535dfecf96Smrg			    XtFree(list[n_list]);
10545dfecf96Smrg			XtFree((char*)list);
10555dfecf96Smrg		    }
10565dfecf96Smrg
10575dfecf96Smrg		    label = ResolveName(dir_name);
10585dfecf96Smrg		    XtSetArg(args[0], XtNlabel, label);
10595dfecf96Smrg		    XtSetValues(dirlabel, args, 1);
10605dfecf96Smrg		    SwitchDirWindow(True);
10615dfecf96Smrg		    free_matches = False;
10625dfecf96Smrg		}
10635dfecf96Smrg	    }
10645dfecf96Smrg	    if (free_matches && matches) {
10655dfecf96Smrg		while (--n_matches > -1)
10665dfecf96Smrg		    XtFree(matches[n_matches]);
10675dfecf96Smrg		XtFree((char*)matches);
10685dfecf96Smrg	    }
10695dfecf96Smrg	}
10705dfecf96Smrg	else
10715dfecf96Smrg	    Feep();
10725dfecf96Smrg    }
10735dfecf96Smrg    else
10745dfecf96Smrg	Feep();
10755dfecf96Smrg
10765dfecf96Smrg    XtFree(save);
10775dfecf96Smrg}
10785dfecf96Smrg
10795dfecf96Smrg/*ARGSUSED*/
10805dfecf96Smrgvoid
10815dfecf96SmrgDirWindowCB(Widget w, XtPointer user_data, XtPointer call_data)
10825dfecf96Smrg{
10835dfecf96Smrg    XawListReturnStruct *file_info = (XawListReturnStruct *)call_data;
10845dfecf96Smrg    char *dir_name, *string, path[BUFSIZ];
10855dfecf96Smrg    Arg args[2];
10865dfecf96Smrg
10875dfecf96Smrg    if (file_info == NULL)
10885dfecf96Smrg	string = (char *)user_data;
10895dfecf96Smrg    else
10905dfecf96Smrg	string = file_info->string;
10915dfecf96Smrg
10925dfecf96Smrg    XtSetArg(args[0], XtNlabel, &dir_name);
10935dfecf96Smrg    XtGetValues(dirlabel, args, 1);
10945dfecf96Smrg    if (*dir_name == '\0') {
10955dfecf96Smrg	strncpy(path, string, sizeof(path) - 1);
10965dfecf96Smrg	path[sizeof(path) - 1] = '\0';
10975dfecf96Smrg    }
10985dfecf96Smrg    else if (strcmp(dir_name, "/") == 0)
10995dfecf96Smrg	XmuSnprintf(path, sizeof(path), "/%s", string);
11005dfecf96Smrg    else
11015dfecf96Smrg	XmuSnprintf(path, sizeof(path), "%s/%s", dir_name, string);
11025dfecf96Smrg
11035dfecf96Smrg    if (*string && string[strlen(string) - 1] == '/') {
11045dfecf96Smrg	DIR *dir;
11055dfecf96Smrg
11065dfecf96Smrg	if ((dir = opendir(path)) != NULL) {
11075dfecf96Smrg	    struct dirent *ent;
11085dfecf96Smrg	    struct stat st;
11095dfecf96Smrg	    unsigned d_namlen;
11105dfecf96Smrg	    Bool isdir;
11115dfecf96Smrg	    char **entries = NULL, **list = NULL;
11125dfecf96Smrg	    int n_entries = 0, n_list = 0;
11135dfecf96Smrg	    char *label, *pptr = path + strlen(path);
11145dfecf96Smrg	    int bytes = sizeof(path) - (pptr - path) - 1;
11155dfecf96Smrg
11165dfecf96Smrg	    while ((ent = readdir(dir)) != NULL) {
11175dfecf96Smrg		d_namlen = strlen(ent->d_name);
11185dfecf96Smrg		strncpy(pptr, ent->d_name, bytes);
11195dfecf96Smrg		pptr[bytes] = '\0';
11205dfecf96Smrg		if (stat(path, &st) != 0)
11215dfecf96Smrg		    /* Should check errno, may be a broken symbolic link
11225dfecf96Smrg		     * a directory with r-- permission, etc */
11235dfecf96Smrg		    continue;
11245dfecf96Smrg		else
11255dfecf96Smrg		    isdir = S_ISDIR(st.st_mode);
11265dfecf96Smrg
11275dfecf96Smrg		entries = (char **)XtRealloc((char*)entries, sizeof(char*)
11285dfecf96Smrg					     * (n_entries + 1));
11295dfecf96Smrg		if (isdir) {
11305dfecf96Smrg		    entries[n_entries] = XtMalloc(d_namlen + 2);
11315dfecf96Smrg		    strcpy(entries[n_entries], ent->d_name);
11325dfecf96Smrg		    strcat(entries[n_entries], "/");
11335dfecf96Smrg		}
11345dfecf96Smrg		else
11355dfecf96Smrg		    entries[n_entries] = XtNewString(ent->d_name);
11365dfecf96Smrg		++n_entries;
11375dfecf96Smrg	    }
11385dfecf96Smrg	    closedir(dir);
11395dfecf96Smrg
11405dfecf96Smrg	    XtSetArg(args[0], XtNlist, &list);
11415dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, &n_list);
11425dfecf96Smrg	    XtGetValues(dirwindow, args, 2);
11435dfecf96Smrg
11445dfecf96Smrg	    if (n_entries == 0) {
11455dfecf96Smrg		entries = (char**)XtMalloc(sizeof(char*) * 2);
11465dfecf96Smrg		/* Directory has read but not execute permission? */
11475dfecf96Smrg		entries[n_entries++] = XtNewString("./");
11485dfecf96Smrg		entries[n_entries++] = XtNewString("../");
11495dfecf96Smrg	    }
11505dfecf96Smrg	    qsort(entries, n_entries, sizeof(char*), compar);
11515dfecf96Smrg	    XtSetArg(args[0], XtNlist, entries);
11525dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, n_entries);
11535dfecf96Smrg	    XtSetValues(dirwindow, args, 2);
11545dfecf96Smrg	    if (n_list > 0
11555dfecf96Smrg		&& (n_list != 1 || list[0] != XtName(dirwindow))) {
11565dfecf96Smrg		while (--n_list > -1)
11575dfecf96Smrg		    XtFree(list[n_list]);
11585dfecf96Smrg		XtFree((char*)list);
11595dfecf96Smrg	    }
11605dfecf96Smrg
11615dfecf96Smrg	    *pptr = '\0';
11625dfecf96Smrg	    if ((label = ResolveName(path)) == NULL) {
11635dfecf96Smrg		Feep();
11645dfecf96Smrg		label = path;
11655dfecf96Smrg	    }
11665dfecf96Smrg	    XtSetArg(args[0], XtNlabel, label);
11675dfecf96Smrg	    XtSetValues(dirlabel, args, 1);
11685dfecf96Smrg
11695dfecf96Smrg	    strncpy(path, label, sizeof(path) - 2);
11705dfecf96Smrg	    if (*path && path[strlen(path) - 1] != '/')
11715dfecf96Smrg		strcat(path, "/");
11725dfecf96Smrg	    XtSetArg(args[0], XtNstring, path);
11735dfecf96Smrg	    XtSetValues(filenamewindow, args, 1);
11745dfecf96Smrg	    XtSetKeyboardFocus(topwindow, filenamewindow);
11755dfecf96Smrg	    XawTextSetInsertionPoint(filenamewindow, strlen(path));
11765dfecf96Smrg	}
11775dfecf96Smrg	else
11785dfecf96Smrg	    Feep();
11795dfecf96Smrg    }
11805dfecf96Smrg    else {
11815dfecf96Smrg	(void)ReallyDoLoad(path, path);
11825dfecf96Smrg	SwitchDirWindow(False);
11835dfecf96Smrg	XtSetKeyboardFocus(topwindow, textwindow);
11845dfecf96Smrg    }
11855dfecf96Smrg}
1186