summaryrefslogtreecommitdiff
path: root/commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'commands.c')
-rw-r--r--commands.c1064
1 files changed, 1064 insertions, 0 deletions
diff --git a/commands.c b/commands.c
new file mode 100644
index 0000000..69dabe2
--- /dev/null
+++ b/commands.c
@@ -0,0 +1,1064 @@
+/* $XConsortium: commands.c,v 1.33 91/10/21 14:32:18 eswu Exp $ */
+
+/*
+ * COPYRIGHT 1987
+ * DIGITAL EQUIPMENT CORPORATION
+ * MAYNARD, MASSACHUSETTS
+ * ALL RIGHTS RESERVED.
+ *
+ * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
+ * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
+ * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
+ * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
+ *
+ * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
+ * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
+ * SET FORTH ABOVE.
+ *
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Digital Equipment Corporation not be
+ * used in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ */
+/* $XFree86: xc/programs/xedit/commands.c,v 1.29 2002/11/05 06:57:05 paulo Exp $ */
+
+#include <X11/Xfuncs.h>
+#include <X11/Xos.h>
+#include "xedit.h"
+#ifdef CRAY
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <X11/Xmu/SysUtil.h>
+#include <X11/IntrinsicP.h>
+#include <X11/Xaw/TextSrcP.h>
+
+void ResetSourceChanged(xedit_flist_item*);
+static void ResetDC(Widget, XtPointer, XtPointer);
+
+static void AddDoubleClickCallback(Widget, Bool);
+static Bool ReallyDoLoad(char*, char*);
+static char *makeBackupName(String, String, unsigned);
+
+extern Widget scratch, texts[3], labels[3];
+static Boolean double_click = FALSE;
+
+#define DC_UNSAVED 1
+#define DC_LOADED 2
+#define DC_CLOBBER 3
+#define DC_KILL 4
+#define DC_SAVE 5
+static int dc_state;
+
+/* Function Name: AddDoubleClickCallback(w)
+ * Description: Adds a callback that will reset the double_click flag
+ * to false when the text is changed.
+ * Arguments: w - widget to set callback upon.
+ * state - If true add the callback, else remove it.
+ * Returns: none.
+ */
+static void
+AddDoubleClickCallback(Widget w, Bool state)
+{
+ Arg args[1];
+ static XtCallbackRec cb[] = { {NULL, NULL}, {NULL, NULL} };
+
+ if (XtIsSubclass(w, asciiSrcObjectClass)) {
+ if (state)
+ XtAddCallback(w, XtNcallback, ResetDC, NULL);
+ else
+ XtRemoveCallback(w, XtNcallback, ResetDC, NULL);
+ }
+ else {
+ if (state)
+ cb[0].callback = ResetDC;
+ else
+ cb[0].callback = NULL;
+
+ XtSetArg(args[0], XtNcallback, cb);
+ XtSetValues(w, args, ONE);
+ }
+}
+
+/* Function Name: ResetDC
+ * Description: Resets the double click flag.
+ * Arguments: w - the text widget.
+ * junk, garbage - *** NOT USED ***
+ * Returns: none.
+ */
+
+/* ARGSUSED */
+static void
+ResetDC(Widget w, XtPointer junk, XtPointer garbage)
+{
+ double_click = FALSE;
+
+ AddDoubleClickCallback(w, FALSE);
+}
+
+/*ARGSUSED*/
+void
+QuitAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ DoQuit(w, NULL, NULL);
+}
+
+/*ARGSUSED*/
+void
+DoQuit(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ unsigned i;
+ Bool source_changed = False;
+
+ if (!double_click || (dc_state && dc_state != DC_UNSAVED)) {
+ for (i = 0; i < flist.num_itens; i++)
+ if (flist.itens[i]->flags & CHANGED_BIT) {
+ source_changed = True;
+ break;
+ }
+ }
+ if(!source_changed) {
+#ifndef __UNIXOS2__
+ XeditLispCleanUp();
+#endif
+ exit(0);
+ }
+
+ XeditPrintf("Unsaved changes. Save them, or Quit again.\n");
+ Feep();
+ double_click = TRUE;
+ dc_state = DC_UNSAVED;
+ AddDoubleClickCallback(XawTextGetSource(textwindow), True);
+}
+
+static char *
+makeBackupName(String buf, String filename, unsigned len)
+{
+ if (app_resources.backupNamePrefix
+ && strlen(app_resources.backupNamePrefix)) {
+ if (strchr(app_resources.backupNamePrefix, '/'))
+ XmuSnprintf(buf, len, "%s%s%s", app_resources.backupNamePrefix,
+ filename, app_resources.backupNameSuffix);
+ else {
+ char fname[BUFSIZ];
+ char *name, ch;
+
+ strncpy(fname, filename, sizeof(fname) - 1);
+ fname[sizeof(fname) - 1] = '\0';
+ if ((name = strrchr(fname, '/')) != NULL)
+ ++name;
+ else
+ name = filename;
+ ch = *name;
+ *name = '\0';
+ ++name;
+ XmuSnprintf(buf, len, "%s%s%c%s%s",
+ fname, app_resources.backupNamePrefix, ch, name,
+ app_resources.backupNameSuffix);
+ }
+ }
+ else
+ XmuSnprintf(buf, len, "%s%s",
+ filename, app_resources.backupNameSuffix);
+
+ return (strcmp(filename, buf) ? buf : NULL);
+}
+
+#if defined(USG) && !defined(CRAY)
+int rename (from, to)
+ char *from, *to;
+{
+ (void) unlink (to);
+ if (link (from, to) == 0) {
+ unlink (from);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+#endif
+
+/*ARGSUSED*/
+void
+SaveFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ DoSave(w, NULL, NULL);
+}
+
+/*ARGSUSED*/
+void
+DoSave(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ String name = GetString(filenamewindow);
+ String filename = ResolveName(name);
+ char buf[BUFSIZ];
+ FileAccess file_access;
+ xedit_flist_item *item;
+ Boolean exists;
+ Widget source = XawTextGetSource(textwindow);
+
+ if (!filename) {
+ XeditPrintf("Save: Can't resolve pathname -- nothing saved.\n");
+ Feep();
+ return;
+ }
+ else if (*name == '\0') {
+ XeditPrintf("Save: No filename specified -- nothing saved.\n");
+ Feep();
+ return;
+ }
+ else {
+ struct stat st;
+
+ if (stat(filename, &st) == 0 && !S_ISREG(st.st_mode)) {
+ XmuSnprintf(buf, sizeof(buf),
+ "Save: file %s is not a regular file -- nothing saved.\n",
+ name);
+ XeditPrintf(buf);
+ Feep();
+ return;
+ }
+ }
+
+ item = FindTextSource(NULL, filename);
+ if (item != NULL && item->source != source) {
+ if (!double_click || (dc_state && dc_state != DC_LOADED)) {
+ XmuSnprintf(buf, sizeof(buf),
+ "Save: file %s is already loaded, "
+ "Save again to unload it -- nothing saved.\n",
+ name);
+ XeditPrintf(buf);
+ Feep();
+ double_click = TRUE;
+ dc_state = DC_LOADED;
+ AddDoubleClickCallback(XawTextGetSource(textwindow), True);
+ return;
+ }
+ KillTextSource(item);
+ item = FindTextSource(source = XawTextGetSource(textwindow), NULL);
+ double_click = FALSE;
+ dc_state = 0;
+ }
+ else if (item && !(item->flags & CHANGED_BIT)) {
+ if (!double_click || (dc_state && dc_state != DC_SAVE)) {
+ XeditPrintf("Save: No changes need to be saved, "
+ "Save again to override.\n");
+ Feep();
+ double_click = TRUE;
+ dc_state = DC_SAVE;
+ AddDoubleClickCallback(XawTextGetSource(textwindow), True);
+ return;
+ }
+ double_click = FALSE;
+ dc_state = 0;
+ }
+
+ file_access = CheckFilePermissions(filename, &exists);
+ if (!item || strcmp(item->filename, filename)) {
+ if (file_access == WRITE_OK && exists) {
+ if (!double_click || (dc_state && dc_state != DC_CLOBBER)) {
+ XmuSnprintf(buf, sizeof(buf),
+ "Save: file %s already exists, "
+ "Save again to overwrite it -- nothing saved.\n",
+ name);
+ XeditPrintf(buf);
+ Feep();
+ double_click = TRUE;
+ dc_state = DC_CLOBBER;
+ AddDoubleClickCallback(XawTextGetSource(textwindow), True);
+ return;
+ }
+ double_click = FALSE;
+ dc_state = 0;
+ }
+ if (!item)
+ item = FindTextSource(source, NULL);
+ }
+
+ if (app_resources.enableBackups && exists) {
+ char backup_file[BUFSIZ];
+
+ if (makeBackupName(backup_file, filename, sizeof(backup_file)) == NULL
+ || rename(filename, backup_file) != 0) {
+ XmuSnprintf(buf, sizeof(buf),"error backing up file: %s\n",
+ filename);
+ XeditPrintf(buf);
+ }
+ }
+
+ switch( file_access = MaybeCreateFile(filename)) {
+ case NO_READ:
+ case READ_OK:
+ XmuSnprintf(buf, sizeof(buf),
+ "File %s could not be opened for writing.\n", name);
+ Feep();
+ break;
+ case WRITE_OK:
+ if ( XawAsciiSaveAsFile(source, filename) ) {
+ int i;
+ Arg args[1];
+ char label_buf[BUFSIZ];
+
+ /* Keep file protection mode */
+ if (item && item->mode)
+ chmod(filename, item->mode);
+
+ XmuSnprintf(label_buf, sizeof(label_buf),
+ "%s Read - Write", name);
+ XtSetArg(args[0], XtNlabel, label_buf);
+ for (i = 0; i < 3; i++)
+ if (XawTextGetSource(texts[i]) == source)
+ XtSetValues(labels[i], args, 1);
+
+ XmuSnprintf(buf, sizeof(buf), "Saved file: %s\n", name);
+
+ if (item && item->source != scratch) {
+ XtSetArg(args[0], XtNlabel, filename);
+ XtSetValues(item->sme, args, 1);
+
+ XtSetArg(args[0], XtNeditType, XawtextEdit);
+ XtSetValues(item->source, args, 1);
+
+ XtFree(item->name);
+ XtFree(item->filename);
+ item->name = XtNewString(name);
+ item->filename = XtNewString(filename);
+ item->flags = EXISTS_BIT;
+ }
+ else {
+ item = flist.itens[0];
+ XtRemoveCallback(scratch, XtNcallback, SourceChanged,
+ (XtPointer)item);
+ item->source = scratch =
+ XtVaCreateWidget("textSource", international ?
+ multiSrcObjectClass : asciiSrcObjectClass,
+ topwindow,
+ XtNtype, XawAsciiFile,
+ XtNeditType, XawtextEdit,
+ NULL, NULL);
+ ResetSourceChanged(item);
+ XtAddCallback(scratch, XtNcallback, SourceChanged,
+ (XtPointer)item);
+
+ item = AddTextSource(source, name, filename, EXISTS_BIT,
+ file_access);
+ XtAddCallback(item->source, XtNcallback, SourceChanged,
+ (XtPointer)item);
+ }
+ item->flags |= EXISTS_BIT;
+ ResetSourceChanged(item);
+ }
+ else {
+ XmuSnprintf(buf, sizeof(buf), "Error saving file: %s\n", name);
+ Feep();
+ }
+ break;
+ default:
+ XmuSnprintf(buf, sizeof(buf), "%s %s",
+ "Internal function MaybeCreateFile()",
+ "returned unexpected value.\n");
+ Feep();
+ break;
+ }
+
+ XeditPrintf(buf);
+}
+
+/*ARGSUSED*/
+void
+DoLoad(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ if (ReallyDoLoad(GetString(filenamewindow), ResolveName(NULL))) {
+ SwitchDirWindow(False);
+ XtSetKeyboardFocus(topwindow, textwindow);
+ }
+}
+
+static Bool
+ReallyDoLoad(char *name, char *filename)
+{
+ Arg args[5];
+ Cardinal num_args = 0;
+ char buf[BUFSIZ];
+ xedit_flist_item *item;
+ Widget source = XawTextGetSource(textwindow);
+
+ if (!filename) {
+ XeditPrintf("Load: Can't resolve pathname.\n");
+ Feep();
+ return (False);
+ }
+ else if (*name == '\0') {
+ XeditPrintf("Load: No file specified.\n");
+ Feep();
+ }
+ if ((item = FindTextSource(NULL, filename)) != NULL) {
+ SwitchTextSource(item);
+ return (True);
+ }
+ else {
+ struct stat st;
+
+ if (stat(filename, &st) == 0 && !S_ISREG(st.st_mode)) {
+ if (S_ISDIR(st.st_mode)) {
+ char path[BUFSIZ + 1];
+
+ strncpy(path, filename, sizeof(path) - 2);
+ path[sizeof(path) - 2] = '\0';
+ if (*path) {
+ if (path[strlen(path) - 1] != '/')
+ strcat(path, "/");
+ }
+ else
+ strcpy(path, "./");
+ XtSetArg(args[0], XtNlabel, "");
+ XtSetValues(dirlabel, args, 1);
+ SwitchDirWindow(True);
+ DirWindowCB(dirwindow, path, NULL);
+ return (False);
+ }
+ }
+ }
+
+ {
+ Boolean exists;
+ int flags;
+ FileAccess file_access;
+
+ switch( file_access = CheckFilePermissions(filename, &exists) ) {
+ case NO_READ:
+ if (exists)
+ XmuSnprintf(buf, sizeof(buf), "File %s, %s", name,
+ "exists, and could not be opened for reading.\n");
+ else
+ XmuSnprintf(buf, sizeof(buf), "File %s %s %s", name,
+ "does not exist, and",
+ "the directory could not be opened for writing.\n");
+
+ XeditPrintf(buf);
+ Feep();
+ return (False);
+ case READ_OK:
+ XtSetArg(args[num_args], XtNeditType, XawtextRead); num_args++;
+ XmuSnprintf(buf, sizeof(buf), "File %s opened READ ONLY.\n",
+ name);
+ break;
+ case WRITE_OK:
+ XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
+ XmuSnprintf(buf, sizeof(buf), "File %s opened read - write.\n",
+ name);
+ break;
+ default:
+ XmuSnprintf(buf, sizeof(buf), "%s %s",
+ "Internal function MaybeCreateFile()",
+ "returned unexpected value.\n");
+ XeditPrintf(buf);
+ Feep();
+ return (False);
+ }
+
+ XeditPrintf(buf);
+
+ if (exists) {
+ flags = EXISTS_BIT;
+ XtSetArg(args[num_args], XtNstring, filename); num_args++;
+ }
+ else {
+ flags = 0;
+ XtSetArg(args[num_args], XtNstring, NULL); num_args++;
+ }
+
+ source = XtVaCreateWidget("textSource", international ?
+ multiSrcObjectClass : asciiSrcObjectClass,
+ topwindow,
+ XtNtype, XawAsciiFile,
+ XtNeditType, XawtextEdit,
+ NULL, NULL);
+ XtSetValues(source, args, num_args);
+
+ item = AddTextSource(source, name, filename, flags, file_access);
+ XtAddCallback(item->source, XtNcallback, SourceChanged,
+ (XtPointer)item);
+ if (exists && file_access == WRITE_OK) {
+ struct stat st;
+
+ if (stat(filename, &st) == 0)
+ item->mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+ SwitchTextSource(item);
+ ResetSourceChanged(item);
+ }
+
+ return (True);
+}
+
+/* Function Name: SourceChanged
+ * Description: A callback routine called when the source has changed.
+ * Arguments: w - the text source that has changed.
+ * client_data - xedit_flist_item associated with text buffer.
+ * call_data - NULL is unchanged
+ * Returns: none.
+ */
+/*ARGSUSED*/
+void
+SourceChanged(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ xedit_flist_item *item = (xedit_flist_item*)client_data;
+ Bool changed = (Bool)(long)call_data;
+
+ if (changed) {
+ if (item->flags & CHANGED_BIT)
+ return;
+ item->flags |= CHANGED_BIT;
+ }
+ else {
+ if (item->flags & CHANGED_BIT)
+ ResetSourceChanged(item);
+ return;
+ }
+
+ if (flist.pixmap) {
+ Arg args[1];
+ Cardinal num_args;
+ int i;
+
+ num_args = 0;
+ XtSetArg(args[num_args], XtNleftBitmap, flist.pixmap); ++num_args;
+ XtSetValues(item->sme, args, num_args);
+
+ for (i = 0; i < 3; i++)
+ if (XawTextGetSource(texts[i]) == item->source)
+ XtSetValues(labels[i], args, num_args);
+ }
+}
+
+/* Function Name: ResetSourceChanged.
+ * Description: Sets the source changed to FALSE, and
+ * registers a callback to set it to TRUE when
+ * the source has changed.
+ * Arguments: item - item with widget to register the callback on.
+ * Returns: none.
+ */
+
+void
+ResetSourceChanged(xedit_flist_item *item)
+{
+ Arg args[1];
+ Cardinal num_args;
+ int i;
+
+ num_args = 0;
+ XtSetArg(args[num_args], XtNleftBitmap, None); ++num_args;
+ XtSetValues(item->sme, args, num_args);
+
+ dc_state = 0;
+ double_click = FALSE;
+ for (i = 0; i < 3; i++) {
+ if (XawTextGetSource(texts[i]) == item->source)
+ XtSetValues(labels[i], args, num_args);
+ AddDoubleClickCallback(XawTextGetSource(texts[i]), False);
+ }
+
+ num_args = 0;
+ XtSetArg(args[num_args], XtNsourceChanged, False); ++num_args;
+ XtSetValues(item->source, args, num_args);
+
+ item->flags &= ~CHANGED_BIT;
+}
+
+/*ARGSUSED*/
+void
+KillFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ xedit_flist_item *item = FindTextSource(XawTextGetSource(textwindow), NULL);
+
+ if (item->source == scratch) {
+ Feep();
+ return;
+ }
+
+ if (item->flags & CHANGED_BIT) {
+ if (!double_click || (dc_state && dc_state != DC_KILL)) {
+ XeditPrintf("Kill: Unsaved changes. Kill again to override.\n");
+ Feep();
+ double_click = TRUE;
+ dc_state = DC_KILL;
+ AddDoubleClickCallback(XawTextGetSource(textwindow), True);
+ return;
+ }
+ double_click = FALSE;
+ dc_state = 0;
+ }
+ KillTextSource(item);
+}
+
+/*ARGSUSED*/
+void
+FindFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ char *string = GetString(filenamewindow);
+ char *slash = NULL;
+ XawTextBlock block;
+ XawTextPosition end = XawTextSourceScan(XawTextGetSource(filenamewindow),
+ 0, XawstAll, XawsdRight, 1, True);
+
+ if (string)
+ slash = strrchr(string, '/');
+ block.firstPos = 0;
+ block.format = FMT8BIT;
+ block.ptr = string;
+ block.length = slash ? slash - string + 1 : 0;
+
+ if (block.length != end)
+ XawTextReplace(filenamewindow, 0, end, &block);
+ XawTextSetInsertionPoint(filenamewindow, end);
+ XtSetKeyboardFocus(topwindow, filenamewindow);
+ line_edit = False;
+}
+
+/*ARGSUSED*/
+void
+LoadFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ if (line_edit)
+ LineEdit(textwindow);
+ else if (ReallyDoLoad(GetString(filenamewindow), ResolveName(NULL))) {
+ SwitchDirWindow(False);
+ XtSetKeyboardFocus(topwindow, textwindow);
+ }
+}
+
+/*ARGSUSED*/
+void
+CancelFindFile(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ Arg args[1];
+ xedit_flist_item *item;
+
+ XtSetKeyboardFocus(topwindow, textwindow);
+
+ item = FindTextSource(XawTextGetSource(textwindow), NULL);
+
+ if (item->source != scratch)
+ XtSetArg(args[0], XtNstring, item->name);
+ else
+ XtSetArg(args[0], XtNstring, NULL);
+
+ XtSetValues(filenamewindow, args, 1);
+
+ if (XtIsManaged(XtParent(dirwindow)))
+ SwitchDirWindow(False);
+
+ line_edit = False;
+}
+
+static int
+compar(_Xconst void *a, _Xconst void *b)
+{
+ return (strcmp(*(char **)a, *(char **)b));
+}
+
+/*ARGSUSED*/
+void
+FileCompletion(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ XawTextBlock block;
+ String text;
+ int length;
+ char **matches, *save, *dir_name, *file_name, match[257];
+ unsigned n_matches, len, mlen, buflen;
+ DIR *dir;
+ Bool changed, slash = False, dot = False, has_dot = False;
+#define SM_NEVER 0
+#define SM_HINT 1
+#define SM_ALWAYS 2
+ int show_matches;
+
+ text = GetString(filenamewindow);
+
+ if (!text) {
+ Feep();
+ return;
+ }
+ else if (line_edit) {
+ Feep();
+ line_edit = 0;
+ }
+
+ {
+ XawTextPosition pos = XawTextGetInsertionPoint(w);
+ char *cslash = strchr(&text[pos], '/'), *cdot = strchr(&text[pos], '.');
+
+ if (cslash != NULL || cdot != NULL) {
+ if (cslash != NULL && (cdot == NULL || cdot > cslash)) {
+ length = cslash - text;
+ slash = True;
+ }
+ else {
+ length = cdot - text;
+ has_dot = True;
+ }
+ }
+ else
+ length = strlen(text);
+ }
+
+ if (*num_params == 1 && length == strlen(text)) {
+ switch (params[0][0]) {
+ case 'n': /* Never */
+ case 'N':
+ show_matches = SM_NEVER;
+ break;
+ case 'h': /* Hint */
+ case 'H':
+ show_matches = SM_HINT;
+ break;
+ case 'a': /* Always */
+ case 'A':
+ show_matches = SM_ALWAYS;
+ break;
+ default:
+ show_matches = SM_NEVER;
+ XtAppWarning(XtWidgetToApplicationContext(w),
+ "Bad argument to file-completion, "
+ "must be Never, Hint or Always");
+ break;
+ }
+ }
+ else
+ show_matches = SM_NEVER;
+
+ matches = NULL;
+ n_matches = buflen = 0;
+ save = XtMalloc(length + 1);
+ memmove(save, text, length);
+ save[length] = '\0';
+
+ if (save[0] == '~' && save[1]) {
+ char *slash2 = strchr(save, '/');
+ int nlen;
+
+ if (slash2) {
+ struct passwd *pw;
+ char home[BUFSIZ];
+ char *name;
+ int slen = strlen(save), diff = slash2 - save;
+
+ *slash2 = '\0';
+ name = save + 1;
+ if ((nlen = strlen(name)) != 0)
+ pw = getpwnam(name);
+ else
+ pw = getpwuid(getuid());
+
+ if (pw) {
+ char fname[BUFSIZ];
+ int hlen;
+
+ strncpy(home, pw->pw_dir, sizeof(home) - 1);
+ home[sizeof(home) - 1] = '\0';
+ hlen = strlen(home);
+ strncpy(fname, slash2 + 1, sizeof(fname) - 1);
+ fname[sizeof(fname) - 1] = '\0';
+ save = XtRealloc(save, slen - diff + hlen + 2);
+ (void)memmove(&save[hlen], slash2, slen - diff + 1);
+ (void)memmove(save, home, hlen);
+ save[hlen] = '/';
+ strcpy(&save[hlen + 1], fname);
+
+ /* expand directory */
+ block.length = strlen(save);
+ block.ptr = save;
+ block.firstPos = 0;
+ block.format = FMT8BIT;
+ XawTextReplace(filenamewindow, 0, length, &block);
+ XawTextSetInsertionPoint(filenamewindow, length = block.length);
+ }
+ else
+ *slash2 = '/';
+ }
+ }
+
+ if ((file_name = strrchr(save, '/')) != NULL) {
+ *file_name = '\0';
+ ++file_name;
+ dir_name = save;
+ if (!file_name[0])
+ slash = True;
+ if (!dir_name[0])
+ dir_name = "/";
+ }
+ else {
+ dir_name = ".";
+ dot = True;
+ file_name = save;
+ }
+ len = strlen(file_name);
+
+ if ((dir = opendir(dir_name)) != NULL) {
+ char path[BUFSIZ], *pptr;
+ struct dirent *ent;
+ int isdir = 0, first = 1, bytes;
+
+ XmuSnprintf(path, sizeof(path), "%s/", dir_name);
+ pptr = path + strlen(path);
+ bytes = sizeof(path) - (pptr - path) - 1;
+
+ mlen = 0;
+ match[0] = '\0';
+ (void)readdir(dir); /* "." */
+ (void)readdir(dir); /* ".." */
+ while ((ent = readdir(dir)) != NULL) {
+ unsigned d_namlen = strlen(ent->d_name);
+
+ if (d_namlen >= len && strncmp(ent->d_name, file_name, len) == 0) {
+ char *tmp = &(ent->d_name[len]), *mat = match;
+ struct stat st;
+ Bool is_dir = FALSE;
+
+ strncpy(pptr, ent->d_name, bytes);
+ pptr[bytes] = '\0';
+ if (stat(path, &st) != 0)
+ /* Should check errno, may be a broken symbolic link
+ * a directory with r-- permission, etc */
+ continue;
+ else if (first || show_matches != SM_NEVER) {
+ is_dir = S_ISDIR(st.st_mode);
+ }
+
+ if (first) {
+ strncpy(match, tmp, sizeof(match) - 1);
+ match[sizeof(match) - 2] = '\0';
+ mlen = strlen(match);
+ first = 0;
+ isdir = is_dir;
+ }
+ else {
+ while (*tmp && *mat && *tmp++ == *mat)
+ ++mat;
+ if (mlen > mat - match) {
+ mlen = mat - match;
+ match[mlen] = '\0';
+ }
+ }
+ if (show_matches != SM_NEVER) {
+ matches = (char **)XtRealloc((char*)matches, sizeof(char**)
+ * (n_matches + 1));
+ buflen += d_namlen + 1;
+ if (is_dir) {
+ matches[n_matches] = XtMalloc(d_namlen + 2);
+ strcpy(matches[n_matches], ent->d_name);
+ strcat(matches[n_matches], "/");
+ ++buflen;
+ }
+ else
+ matches[n_matches] = XtNewString(ent->d_name);
+ }
+ else if (mlen == 0 && n_matches >= 1) {
+ ++n_matches;
+ break;
+ }
+ ++n_matches;
+ }
+ }
+
+ closedir(dir);
+ changed = mlen != 0;
+
+ if (n_matches) {
+ Bool free_matches = True, add_slash = n_matches == 1 && isdir && !slash;
+
+ if (mlen && has_dot && match[mlen - 1] == '.')
+ --mlen;
+
+ if (mlen || add_slash) {
+ XawTextPosition pos;
+
+ block.firstPos = 0;
+ block.format = FMT8BIT;
+ if (mlen) {
+ pos = length;
+ block.length = mlen;
+ block.ptr = match;
+ XawTextReplace(filenamewindow, pos, pos, &block);
+ XawTextSetInsertionPoint(filenamewindow, pos + block.length);
+ }
+ if (add_slash) {
+ XawTextPosition actual = XawTextGetInsertionPoint(w);
+
+ pos = XawTextSourceScan(XawTextGetSource(w), 0, XawstAll,
+ XawsdRight, 1, True);
+ block.length = 1;
+ block.ptr = "/";
+ XawTextReplace(filenamewindow, pos, pos, &block);
+ if (actual == pos)
+ XawTextSetInsertionPoint(filenamewindow, pos + 1);
+ }
+ }
+ else if (n_matches != 1 || isdir) {
+ if (show_matches == SM_NEVER)
+ Feep();
+ }
+
+ if (show_matches != SM_NEVER) {
+ if (show_matches == SM_ALWAYS || (!changed && n_matches != 1)) {
+ char **list = NULL, *label;
+ int n_list;
+ Arg args[2];
+
+ XtSetArg(args[0], XtNlist, &list);
+ XtSetArg(args[1], XtNnumberStrings, &n_list);
+ XtGetValues(dirwindow, args, 2);
+
+ matches = (char **)XtRealloc((char*)matches, sizeof(char**)
+ * (n_matches + 2));
+ matches[n_matches++] = XtNewString("./");
+ matches[n_matches++] = XtNewString("../");
+ qsort(matches, n_matches, sizeof(char*), compar);
+ XtSetArg(args[0], XtNlist, matches);
+ XtSetArg(args[1], XtNnumberStrings, n_matches);
+ XtSetValues(dirwindow, args, 2);
+ if (n_list > 0
+ && (n_list != 1 || list[0] != XtName(dirwindow))) {
+ while (--n_list > -1)
+ XtFree(list[n_list]);
+ XtFree((char*)list);
+ }
+
+ label = ResolveName(dir_name);
+ XtSetArg(args[0], XtNlabel, label);
+ XtSetValues(dirlabel, args, 1);
+ SwitchDirWindow(True);
+ free_matches = False;
+ }
+ }
+ if (free_matches && matches) {
+ while (--n_matches > -1)
+ XtFree(matches[n_matches]);
+ XtFree((char*)matches);
+ }
+ }
+ else
+ Feep();
+ }
+ else
+ Feep();
+
+ XtFree(save);
+}
+
+/*ARGSUSED*/
+void
+DirWindowCB(Widget w, XtPointer user_data, XtPointer call_data)
+{
+ XawListReturnStruct *file_info = (XawListReturnStruct *)call_data;
+ char *dir_name, *string, path[BUFSIZ];
+ Arg args[2];
+
+ if (file_info == NULL)
+ string = (char *)user_data;
+ else
+ string = file_info->string;
+
+ XtSetArg(args[0], XtNlabel, &dir_name);
+ XtGetValues(dirlabel, args, 1);
+ if (*dir_name == '\0') {
+ strncpy(path, string, sizeof(path) - 1);
+ path[sizeof(path) - 1] = '\0';
+ }
+ else if (strcmp(dir_name, "/") == 0)
+ XmuSnprintf(path, sizeof(path), "/%s", string);
+ else
+ XmuSnprintf(path, sizeof(path), "%s/%s", dir_name, string);
+
+ if (*string && string[strlen(string) - 1] == '/') {
+ DIR *dir;
+
+ if ((dir = opendir(path)) != NULL) {
+ struct dirent *ent;
+ struct stat st;
+ unsigned d_namlen;
+ Bool isdir;
+ char **entries = NULL, **list = NULL;
+ int n_entries = 0, n_list = 0;
+ char *label, *pptr = path + strlen(path);
+ int bytes = sizeof(path) - (pptr - path) - 1;
+
+ while ((ent = readdir(dir)) != NULL) {
+ d_namlen = strlen(ent->d_name);
+ strncpy(pptr, ent->d_name, bytes);
+ pptr[bytes] = '\0';
+ if (stat(path, &st) != 0)
+ /* Should check errno, may be a broken symbolic link
+ * a directory with r-- permission, etc */
+ continue;
+ else
+ isdir = S_ISDIR(st.st_mode);
+
+ entries = (char **)XtRealloc((char*)entries, sizeof(char*)
+ * (n_entries + 1));
+ if (isdir) {
+ entries[n_entries] = XtMalloc(d_namlen + 2);
+ strcpy(entries[n_entries], ent->d_name);
+ strcat(entries[n_entries], "/");
+ }
+ else
+ entries[n_entries] = XtNewString(ent->d_name);
+ ++n_entries;
+ }
+ closedir(dir);
+
+ XtSetArg(args[0], XtNlist, &list);
+ XtSetArg(args[1], XtNnumberStrings, &n_list);
+ XtGetValues(dirwindow, args, 2);
+
+ if (n_entries == 0) {
+ entries = (char**)XtMalloc(sizeof(char*) * 2);
+ /* Directory has read but not execute permission? */
+ entries[n_entries++] = XtNewString("./");
+ entries[n_entries++] = XtNewString("../");
+ }
+ qsort(entries, n_entries, sizeof(char*), compar);
+ XtSetArg(args[0], XtNlist, entries);
+ XtSetArg(args[1], XtNnumberStrings, n_entries);
+ XtSetValues(dirwindow, args, 2);
+ if (n_list > 0
+ && (n_list != 1 || list[0] != XtName(dirwindow))) {
+ while (--n_list > -1)
+ XtFree(list[n_list]);
+ XtFree((char*)list);
+ }
+
+ *pptr = '\0';
+ if ((label = ResolveName(path)) == NULL) {
+ Feep();
+ label = path;
+ }
+ XtSetArg(args[0], XtNlabel, label);
+ XtSetValues(dirlabel, args, 1);
+
+ strncpy(path, label, sizeof(path) - 2);
+ if (*path && path[strlen(path) - 1] != '/')
+ strcat(path, "/");
+ XtSetArg(args[0], XtNstring, path);
+ XtSetValues(filenamewindow, args, 1);
+ XtSetKeyboardFocus(topwindow, filenamewindow);
+ XawTextSetInsertionPoint(filenamewindow, strlen(path));
+ }
+ else
+ Feep();
+ }
+ else {
+ (void)ReallyDoLoad(path, path);
+ SwitchDirWindow(False);
+ XtSetKeyboardFocus(topwindow, textwindow);
+ }
+}