diff options
Diffstat (limited to 'commands.c')
-rw-r--r-- | commands.c | 1064 |
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); + } +} |