/***************************************************************************/
/***************************************************************************/
/* */
/* (c) 1995-1999. The Regents of the University of California. All */
/* rights reserved. */
/* */
/* This work was produced at the University of California, Lawrence */
/* Livermore National Laboratory (UC LLNL) under contract no. */
/* W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy */
/* (DOE) and The Regents of the University of California (University) */
/* for the operation of UC LLNL. Copyright is reserved to the */
/* University for purposes of controlled dissemination, */
/* commercialization through formal licensing, or other disposition */
/* under terms of Contract 48; DOE policies, regulations and orders; */
/* and U.S. statutes. The rights of the Federal Government are */
/* reserved under Contract 48 subject to the restrictions agreed upon */
/* by the DOE and University. */
/* */
/* */
/* DISCLAIMER */
/* */
/* This software was prepared as an account of work sponsored by an */
/* agency of the United States Government. Neither the United States */
/* Government nor the University of California nor any of their */
/* employees, makes any warranty, express or implied, or assumes any */
/* liability or responsibility for the accuracy, completeness, or */
/* usefulness of any information, apparatus, product, or process */
/* disclosed, or represents that its specific commercial products, */
/* process, or service by trade name, trademark, manufacturer, or */
/* otherwise, does not necessarily constitute or imply its */
/* endorsement, recommendation, or favoring by the United States */
/* Government or the University of California. The views and opinions */
/* of the authors expressed herein do not necessarily state or reflect */
/* those of the United States Government or the University of */
/* California, and shall not be used for advertising or product */
/* endorsement purposes. */
/* */
/* Permission to use, copy, modify and distribute this software and its */
/* documentation for any non-commercial purpose, without fee, is */
/* hereby granted, provided that the above copyright notice and this */
/* permission notice appear in all copies of the software and */
/* supporting documentation, and that all UC LLNL identification in */
/* the user interface remain unchanged. The title to copyright LLNL */
/* XDIR shall at all times remain with The Regents of the University */
/* of California and users agree to preserve same. Users seeking the */
/* right to make derivative works with LLNL XDIR for commercial */
/* purposes may obtain a license from the Lawrence Livermore National */
/* Laboratory's Technology Transfer Office, P.O. Box 808, L-795, */
/* Livermore, CA 94550. */
/* */
/***************************************************************************/
/***************************************************************************/
#include <Xm/SelectioB.h>
#include <Xm/TextF.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/Frame.h>
#include <Xm/ToggleBG.h>
#include <Xm/RowColumn.h>
#include <Xm/Scale.h>
#include "xdir.h"
#include "list.h"
#include "str.h"
struct dirwin_link {
struct dirwin_link *next;
struct dirwin_st *dirwin;
};
int search_complete = True;
static struct {
char *pattern;
int match_case;
int max_depth;
int range;
int level;
int host;
struct dirwin_link *dirwin_head;
struct entry_link *entry_head[MAXSEARCHDEPTH];
struct entry_link *current_entry;
char *full_path[MAXSEARCHDEPTH];
char *true_full_path[MAXSEARCHDEPTH];
struct dirwin_st *cmd_dirwin;
char *hostname;
char *username;
} sc;
static struct {
char *pattern;
int match_case;
int max_depth;
int range;
} prev_dialog_values;
static int saved_prev_dialog_values = False;
static struct {
Widget w_dialog;
Widget w_form;
Widget w_textLabel;
Widget w_text;
Widget w_depth;
Widget w_matchRadioBoxFrame;
Widget w_matchRadioBox;
Widget w_matchCaseToggle;
Widget w_searchRadioBoxFrame;
Widget w_searchRadioBox;
Widget w_searchThisDirToggle;
Widget w_searchThisHostToggle;
Widget w_searchAllHostsToggle;
} search;
static char *search_help[] = {
"This dialog allows you to initiate a recursive search of directory",
"windows for entry names that match a specified pattern. ",
"The pattern to be matched can contain the usual wildcard",
"characters ('*', '?', '[', and ']'). The toggle item",
"\"Match Case\" controls whether case (upper or lower)",
"should be considered when looking for a match. The",
"\"Maximum Search Depth\" slider is used to specify the",
"maximum number of directory levels the search command",
"will explore. Choose one of the toggle items,",
"\"Search this directory\", \"Search all displayed",
"directories of this host\", or \"Search all displayed",
"directories of all hosts\", to specify which directory",
"windows to begin the search from.\n",
"\n",
"When the OK button is pressed, a dialog appears to",
"monitor the progress of the search. This dialog contains",
"a button that can be used to abort the search.\n",
"\n",
"If a match is found in a directory that is already",
"displayed, the entry is selected, scrolled into view, and",
"its directory window is brought to the front. If a match",
"is found in a directory that is not already displayed,",
"there are two cases: If the search was initiated from a",
"directory window with tunneling mode on, the entry's",
"directory is displayed in that directory window;",
"otherwise a new window is created to display the entry's",
"directory.\n",
"\n",
"Use SEARCH AGAIN (in the OPS menu) to continue the search",
"once an entry has been found.\n",
"\n",
"Use general preferences",
"INITIAL SEARCH DEPTH, INITIAL SEARCH CASE MATCH, and",
"INITIAL SEARCH RANGE to change the dialog's default",
"values.",
NULL
};
static char *msg1 = "Match found: \"%s\" in directory \"%s\".\n\nUnable to display directory.\n\nWill continue search.";
static char *msg2 = "Unable to perform search. Can't get directory list.";
extern XtAppContext app;
extern int beep_when_ops_done;
extern struct dirwin_st *dirwin_head;
extern int initial_match_case;
extern int initial_max_search_depth;
extern int initial_search_range;
extern struct st_host_info hinfo[];
extern Display *display;
void cb_search_ok();
void cb_search_cancel();
void cb_search_help();
void cb_map_dialog();
void create_search_dialog();
void clean_up_sc();
void clear_search_flags();
void save_search_dialog_values();
void init_search_dialog_values();
void sort_dirwins();
int cb_search_entries();
struct entry_info *name_to_entry();
char *merge_paths();
/*
* cb_search - Callback that pops up Search dialog.
*/
void
cb_search(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
char *pattern;
int temp;
/* Start operation */
if (!start_op(True))
return;
/* Clear error flag */
raise_okflag();
/* Create "Search" dialog */
create_search_dialog(dirwin);
/* Initialize settings in search dialog */
init_search_dialog_values();
/* Pop up dialog */
XtVaSetValues(search.w_dialog, XmNuserData, dirwin, NULL);
XtManageChild(search.w_dialog);
traverse_to_widget(search.w_text);
/* If pattern is already entered, select it */
pattern = XmTextFieldGetString(search.w_text);
XmTextFieldSetSelection(search.w_text, (XmTextPosition)0,
(XmTextPosition)strlen(pattern), CurrentTime);
XtFree(pattern);
/* Kludge to make level initially visible with some versions of Motif */
force_update(search.w_dialog);
XmScaleGetValue(search.w_depth, &temp);
XmScaleSetValue(search.w_depth, 1);
XmScaleSetValue(search.w_depth, temp);
}
/*
* create_search_dialog - Create dialog for searching. "dirwin" is the
* directory window to center the Search dialog over.
*/
void
create_search_dialog(dirwin)
struct dirwin_st *dirwin;
{
int i;
Arg args[5];
Widget widget;
/* Create prompt dialog for searching */
i = 0;
XtSetArg(args[i], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); i++;
XtSetArg(args[i], XmNdefaultPosition, False); i++;
XtSetArg(args[i], XmNautoUnmanage, False); i++;
search.w_dialog = XmCreatePromptDialog(dirwin->w_shell, "search", args, i);
XtAddCallback(search.w_dialog, XmNokCallback, cb_search_ok,
(XtPointer)NULL);
XtAddCallback(search.w_dialog, XmNcancelCallback, cb_search_cancel,
(XtPointer)NULL);
XtAddCallback(search.w_dialog, XmNhelpCallback, cb_search_help,
(XtPointer)NULL);
XtAddCallback(search.w_dialog, XmNmapCallback, cb_map_dialog,
(XtPointer)XtWindow(dirwin->w_shell));
/* Don't show prompt dialog's selection label and text */
widget = XmSelectionBoxGetChild(search.w_dialog, XmDIALOG_SELECTION_LABEL);
XtUnmanageChild(widget);
widget = XmSelectionBoxGetChild(search.w_dialog, XmDIALOG_TEXT);
XtUnmanageChild(widget);
/* Add callback for the WM_DELETE_WINDOW protocol */
add_wm_delete_window_cb(search.w_dialog, cb_search_cancel, NULL, False);
/* Create form for control area */
search.w_form = XtVaCreateWidget(
"form",
xmFormWidgetClass,
search.w_dialog,
NULL
);
/* Create label for search expression */
search.w_textLabel = XtVaCreateManagedWidget(
"textLabel",
xmLabelWidgetClass,
search.w_form,
XmNalignment, XmALIGNMENT_BEGINNING,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL
);
/* Create textfield for search expression */
search.w_text = XtVaCreateManagedWidget(
"text",
xmTextFieldWidgetClass,
search.w_form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, search.w_textLabel,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL
);
/* Create radio box frame for match criteria */
search.w_matchRadioBoxFrame = XtVaCreateManagedWidget(
"matchRadioBoxFrame",
xmFrameWidgetClass,
search.w_form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, search.w_text,
XmNtopOffset, 15,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL
);
/* Create radio box for match criteria */
i = 0;
XtSetArg(args[i], XmNorientation, XmVERTICAL); i++;
XtSetArg(args[i], XmNspacing, 0); i++;
XtSetArg(args[i], XmNradioBehavior, False); i++;
search.w_matchRadioBox = XmCreateRadioBox(search.w_matchRadioBoxFrame,
"matchRadioBox", args, i);
/* Create "Match Case" toggle */
search.w_matchCaseToggle = XtVaCreateManagedWidget(
"matchCaseToggle",
xmToggleButtonGadgetClass,
search.w_matchRadioBox,
XmNindicatorType, XmN_OF_MANY,
XmNmarginHeight, 0,
NULL
);
XtManageChild(search.w_matchRadioBox);
/* Create scale for setting/displaying maximum search depth */
search.w_depth = XtVaCreateManagedWidget(
"depth",
xmScaleWidgetClass,
search.w_form,
XmNshowValue, True,
XmNorientation, XmHORIZONTAL,
XmNminimum, 1,
XmNmaximum, MAXSEARCHDEPTH,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, search.w_matchRadioBoxFrame,
XmNtopOffset, 15,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL
);
/* Create radio box frame for search range */
search.w_searchRadioBoxFrame = XtVaCreateManagedWidget(
"searchRadioBoxFrame",
xmFrameWidgetClass,
search.w_form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, search.w_depth,
XmNtopOffset, 15,
XmNbottomOffset, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL
);
/* Create radio box for search range */
i = 0;
XtSetArg(args[i], XmNorientation, XmVERTICAL); i++;
XtSetArg(args[i], XmNspacing, 0); i++;
search.w_searchRadioBox = XmCreateRadioBox(search.w_searchRadioBoxFrame,
"searchRadioBox", args, i);
/* Create "Search this directory" toggle */
search.w_searchThisDirToggle = XtVaCreateManagedWidget(
"searchThisDirToggle",
xmToggleButtonGadgetClass,
search.w_searchRadioBox,
XmNindicatorType, XmONE_OF_MANY,
XmNmarginHeight, 0,
NULL
);
/* Create "Search all open directories for this host" toggle */
search.w_searchThisHostToggle = XtVaCreateManagedWidget(
"searchThisHostToggle",
xmToggleButtonGadgetClass,
search.w_searchRadioBox,
XmNindicatorType, XmONE_OF_MANY,
XmNmarginHeight, 0,
NULL
);
/* Create "Search all open directories for all hosts" toggle */
search.w_searchAllHostsToggle = XtVaCreateManagedWidget(
"searchAllHostsToggle",
xmToggleButtonGadgetClass,
search.w_searchRadioBox,
XmNindicatorType, XmONE_OF_MANY,
XmNmarginHeight, 0,
NULL
);
XtManageChild(search.w_searchRadioBox);
/* Initialize search range toggles */
switch (initial_search_range) {
case SEARCH_THIS_DIR:
XmToggleButtonGadgetSetState(search.w_searchThisDirToggle, True, False);
break;
case SEARCH_THIS_HOST:
XmToggleButtonGadgetSetState(search.w_searchThisHostToggle, True,False);
break;
case SEARCH_ALL_HOSTS:
XmToggleButtonGadgetSetState(search.w_searchAllHostsToggle, True,False);
}
XtManageChild(search.w_form);
}
/*
* cb_search_ok - This callback initializes the search.
*/
void
cb_search_ok(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct dirwin_st *dirwin;
struct entry_link *head;
struct dirwin_link *dptr;
struct dirwin_st *dwin;
char *expression;
char *raw_expression;
int i;
int len;
struct sl_struct *list;
int retval;
Widget w;
/* If previous search can be continued, clear state variables */
if (!search_complete) {
clean_up_sc();
search_complete = True;
}
/* Clear dirwin search flags */
clear_search_flags();
/* Get directory display */
XtVaGetValues(search.w_dialog, XmNuserData, &dirwin, NULL);
/* Get pattern to search for */
raw_expression = XmTextFieldGetString(search.w_text);
expression = strtok(raw_expression, " ");
if (expression == NULL) {
XtFree(raw_expression);
warn("No search pattern given.", XtParent(search.w_dialog));
w = XmSelectionBoxGetChild(search.w_dialog, XmDIALOG_OK_BUTTON);
XtUnmanageChild(w);
XtManageChild(w);
traverse_to_widget(search.w_text);
return;
}
/* Match case? */
sc.match_case = XmToggleButtonGadgetGetState(search.w_matchCaseToggle);
/* Get search depth */
XtVaGetValues(search.w_depth, XmNvalue, &sc.max_depth, NULL);
/* Determine range of search */
if (XmToggleButtonGadgetGetState(search.w_searchThisDirToggle))
sc.range = SEARCH_THIS_DIR;
else if (XmToggleButtonGadgetGetState(search.w_searchThisHostToggle))
sc.range = SEARCH_THIS_HOST;
else
sc.range = SEARCH_ALL_HOSTS;
/* Make operation interruptable */
show_stop_button(dirwin);
/* This might take some time */
use_busy_cursor();
/* Get rid of Search Dialog */
save_search_dialog_values();
XtUnmanageChild(search.w_dialog);
XtDestroyWidget(XtParent(search.w_dialog));
/* Form list of directory windows to search */
sc.dirwin_head = NULL;
switch (sc.range) {
case SEARCH_THIS_DIR:
dptr = XtNew(struct dirwin_link);
dptr->dirwin = dirwin;
dptr->next = sc.dirwin_head;
sc.dirwin_head = dptr;
break;
case SEARCH_THIS_HOST:
dwin = dirwin_head;
while (dwin) {
if (dwin->host == dirwin->host) {
dptr = XtNew(struct dirwin_link);
dptr->dirwin = dwin;
dptr->next = sc.dirwin_head;
sc.dirwin_head = dptr;
}
dwin = dwin->next;
}
break;
case SEARCH_ALL_HOSTS:
dwin = dirwin_head;
while (dwin) {
dptr = XtNew(struct dirwin_link);
dptr->dirwin = dwin;
dptr->next = sc.dirwin_head;
sc.dirwin_head = dptr;
dwin = dwin->next;
}
}
/* Establish the order the dirwins are to be searched */
sort_dirwins(&sc.dirwin_head);
/* Finish setting up search control block */
sc.cmd_dirwin = dirwin;
sc.level = 0;
dwin = sc.dirwin_head->dirwin;
sc.host = dwin->host;
show_search_monitor(dirwin, expression, dwin->host, dwin->dirname);
if (sc.host != LOCAL) {
retval = check_connection(sc.host, sc.cmd_dirwin);
if (retval < 0) {
restore_prev_cursor();
switch (retval) {
case -6:
record_abort("Search");
break;
case -1:
record_and_alert(
"Unable to perform search. Can't get directory list.",
sc.cmd_dirwin->w_shell);
}
hide_search_monitor();
XtFree(raw_expression);
while (sc.dirwin_head) {
dptr = sc.dirwin_head;
sc.dirwin_head = sc.dirwin_head->next;
XtFree((char *)dptr);
}
hide_stop_button();
end_op();
return;
}
}
retval = get_dirlist(sc.host, dwin->dirname, TABULAR, True, False, False,
&list);
if (retval < 0) {
restore_prev_cursor();
switch (retval) {
case -6:
record_abort("Search");
break;
case -3:
restore_lost_connection(sc.host, sc.cmd_dirwin);
case -1:
record_and_alert(
"Unable to perform search. Can't get directory list.",
sc.cmd_dirwin->w_shell);
}
hide_search_monitor();
XtFree(raw_expression);
while (sc.dirwin_head) {
dptr = sc.dirwin_head;
sc.dirwin_head = sc.dirwin_head->next;
XtFree((char *)dptr);
}
hide_stop_button();
end_op();
return;
}
head = NULL;
for (i=list->nentries-1; i>=0; i--)
add_to_linked_list(&head, list->entries[i]);
release_array_list(list);
sc.entry_head[0] = head;
sc.current_entry = head;
sc.full_path[0] = XtNewString(dwin->dirname);
sc.true_full_path[0] = XtNewString(dwin->dirname);
sc.pattern = XtNewString(expression);
XtFree(raw_expression);
sc.hostname = XtNewString(hinfo[dwin->host].hostname);
sc.username = XtNewString(hinfo[dwin->host].username);
/* Handle ignore/match case */
if (!sc.match_case) {
len = strlen(sc.pattern);
for (i=0; i<len; i++)
sc.pattern[i] = tolower(sc.pattern[i]);
}
/* Perform search */
search_complete = False;
XtAppAddWorkProc(app, (XtWorkProc)cb_search_entries, NULL);
}
/*
* cb_search_again - Callback that searches selected entries starting
* from where the search last let off.
*/
void
cb_search_again(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
int i;
/* Start operation */
if (!start_op(True))
return;
/* Sanity check */
if (search_complete)
fatal_error("Programming bug in cb_search_again()");
/* Clear error flag */
raise_okflag();
/* Remember directory display that initiated continued search */
sc.cmd_dirwin = dirwin;
/* Make operation interruptable */
show_stop_button(dirwin);
/* This might take some time */
use_busy_cursor();
/* If tunnelling on, clear dirwin search flags */
if (dirwin->tunneling_mode)
clear_search_flags();
/* Make sure that search is not continued in dir of disconnected host */
if (!hinfo[sc.host].in_use ||
strcmp(sc.hostname, hinfo[sc.host].hostname) ||
strcmp(sc.username, hinfo[sc.host].username)) {
for(i=0; i<=sc.level; i++) {
release_linked_list(&sc.entry_head[i]);
XtFree(sc.full_path[i]);
XtFree(sc.true_full_path[i]);
}
sc.level = 0;
}
/* Perform search */
XtAppAddWorkProc(app, (XtWorkProc)cb_search_entries, NULL);
}
/*
* cb_search_help - Callback to display help info for Search dialog.
*/
void
cb_search_help(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
help_dialog(widget, True, "Search", search_help);
}
/*
* cb_search_entries - Work procedure for executing search request.
* State information is kept in "sc", the search
* control block data structure. A post-order
* search is performed.
*/
cb_search_entries()
{
struct entry_link *ptr;
struct sl_struct *list;
int retval;
int len;
int i;
char *full_entry_path;
char *entry;
int match_not_found = False;
struct entry_link *head;
struct dirwin_st *dirwin;
struct dirwin_link *dptr;
struct dirwin_st *dwin;
char *msg;
/* Did user push abort button? */
if (stop())
goto abort;
/* Is there more to search? */
if (sc.entry_head[sc.level] == NULL) {
XtFree(sc.full_path[sc.level]);
sc.full_path[sc.level] = NULL;
XtFree(sc.true_full_path[sc.level]);
sc.true_full_path[sc.level] = NULL;
if (sc.level == 0) {
dptr = sc.dirwin_head;
sc.dirwin_head = sc.dirwin_head->next;
XtFree((char *)dptr);
if (sc.dirwin_head) {
dirwin = sc.dirwin_head->dirwin;
dwin = dirwin_head;
while (dwin && (dwin != dirwin))
dwin = dwin->next;
if (!dwin)
return False;
sc.host = dirwin->host;
show_search_monitor(sc.cmd_dirwin, sc.pattern, sc.host,
dirwin->dirname);
if (sc.host != LOCAL) {
retval = check_connection(sc.host, sc.cmd_dirwin);
switch (retval) {
case -6:
goto abort;
case -3:
goto bad;
case -1:
record_and_alert(msg2, sc.cmd_dirwin->w_shell);
goto bad;
}
}
retval = get_dirlist(sc.host, dirwin->dirname, TABULAR, True,
False, False, &list);
switch (retval) {
case -6:
goto abort;
case -3:
goto lost;
case -1:
goto advance;
}
head = NULL;
for (i=list->nentries-1; i>=0; i--)
add_to_linked_list( &head, list->entries[i]);
release_array_list(list);
sc.entry_head[0] = head;
sc.current_entry = head;
sc.full_path[0] = XtNewString(dirwin->dirname);
sc.true_full_path[0] = XtNewString(dirwin->dirname);
XtFree(sc.hostname);
sc.hostname =XtNewString(hinfo[dirwin->host].hostname);
XtFree(sc.username);
sc.username =XtNewString(hinfo[dirwin->host].username);
return False;
} else {
match_not_found = True;
goto done;
}
} else {
sc.level--;
ptr = sc.entry_head[sc.level];
sc.entry_head[sc.level] = ptr->next;
XtFree(ptr->entry);
XtFree((char *)ptr);
return False;
}
}
/* If on first sweep of this directory, test entry for match */
if (sc.current_entry) {
entry = XtNewString(sc.current_entry->entry);
if (!sc.match_case) {
len = strlen(entry);
for (i=0; i<len; i++)
entry[i] = tolower(entry[i]);
}
if (match(entry, sc.pattern)) {
hide_search_monitor();
XtFree(entry);
retval = display_found_entry(sc.host, sc.true_full_path[sc.level],
sc.current_entry->entry);
switch (retval) {
case 0:
sc.current_entry = sc.current_entry->next;
goto found;
case -2:
msg = XtMalloc(strlen(msg1)+strlen(sc.true_full_path[sc.level])
+strlen(sc.current_entry->entry)+1);
sprintf(msg, msg1, sc.current_entry->entry,
sc.true_full_path[sc.level]);
record_and_alert(msg, sc.cmd_dirwin->w_shell);
XtFree(msg);
case -1:
sc.current_entry = sc.current_entry->next;
return False;
case -3:
goto lost;
case -6:
goto abort;
}
} else {
sc.current_entry = sc.current_entry->next;
XtFree(entry);
return False;
}
}
/* Limit search depth to user-specified value */
if (sc.level == sc.max_depth-1)
goto advance;
/* On second sweep. Construct full path for entry */
full_entry_path = merge_paths(hinfo[sc.host].system, sc.full_path[sc.level],
sc.entry_head[sc.level]->entry);
/* Test for directory by trying to cd to it */
if (sc.host == LOCAL) {
if (local_cd(full_entry_path, False) != 0) {
XtFree(full_entry_path);
goto advance;
}
} else {
if (sc.host != LOCAL) {
retval = check_connection(sc.host, sc.cmd_dirwin);
if (retval < 0) {
XtFree(full_entry_path);
switch (retval) {
case -6:
goto abort;
case -3:
goto bad;
case -1:
record_and_alert(msg2, sc.cmd_dirwin->w_shell);
goto bad;
}
}
}
switch (remote_cd(sc.host, full_entry_path, False)) {
case -6:
XtFree(full_entry_path);
goto abort;
case -3:
XtFree(full_entry_path);
goto lost;
case -1:
XtFree(full_entry_path);
goto advance;
}
}
/* It is a directory. Try to list it */
switch (get_dirlist(sc.host, full_entry_path, TABULAR, True, False, False,
&list)) {
case -6:
XtFree(full_entry_path);
goto abort;
case -3:
XtFree(full_entry_path);
goto lost;
case -1:
XtFree(full_entry_path);
goto advance;
}
/* Add directory list to new level */
sc.level++;
sc.entry_head[sc.level] = NULL;
for (i=list->nentries-1; i>=0; i--)
add_to_linked_list(&sc.entry_head[sc.level], list->entries[i]);
release_array_list(list);
sc.current_entry = sc.entry_head[sc.level];
sc.full_path[sc.level] = full_entry_path;
retval = determine_true_path(sc.host, sc.full_path[sc.level], True, False,
False, &sc.true_full_path[sc.level]);
switch (retval) {
case -6:
goto abort;
case -3:
goto lost;
case -1:
record_and_alert("Unable to perform search. Can't get directory name.",
sc.cmd_dirwin->w_shell);
goto done;
}
show_search_monitor(sc.cmd_dirwin, sc.pattern, sc.host,
sc.full_path[sc.level]);
return False;
advance:
ptr = sc.entry_head[sc.level];
sc.entry_head[sc.level] = ptr->next;
XtFree(ptr->entry);
XtFree((char *)ptr);
return False;
done:
clean_up_sc();
search_complete = True;
hide_search_monitor();
found:
if (beep_when_ops_done)
beep();
restore_prev_cursor();
if (match_not_found)
info_dialog("Match not found.", sc.cmd_dirwin->w_shell);
goto final;
abort:
search_complete = True;
hide_search_monitor();
clean_up_sc();
record_abort("Search");
if (beep_when_ops_done)
beep();
restore_prev_cursor();
goto final;
bad:
search_complete = True;
clean_up_sc();
hide_search_monitor();
if (beep_when_ops_done)
beep();
restore_prev_cursor();
goto final;
lost:
search_complete = True;
clean_up_sc();
clear_selected_entries();
hide_search_monitor();
restore_prev_cursor();
restore_lost_connection(sc.host, sc.cmd_dirwin);
use_busy_cursor();
if (beep_when_ops_done)
beep();
restore_prev_cursor();
final:
/* Miscellaneous cleanup */
update_dir_controls();
/* Signal end of operation */
hide_stop_button();
end_op();
return True;
}
/*
* clean_up_sc - Cleans up the search control block data
* structure. This routine should be called
* before servicing a new search request.
*/
void
clean_up_sc()
{
int i;
struct dirwin_link *dptr;
struct dirwin_link *head;
XtFree(sc.pattern);
XtFree(sc.hostname);
XtFree(sc.username);
for(i=0; i<=sc.level; i++) {
release_linked_list(&sc.entry_head[i]);
XtFree(sc.full_path[i]);
XtFree(sc.true_full_path[i]);
}
head = sc.dirwin_head;
while (head) {
dptr = head;
head = head->next;
XtFree((char *)dptr);
}
}
/*
* clear_search_flags - Clear the flag "temp_for_search" from the dirwin.
* This is the flag that indicates that a directory
* display was created to display a found entry, and
* that it should be deleted if the search is continued.
*/
void
clear_search_flags()
{
struct dirwin_st *dirwin = dirwin_head;
while(dirwin) {
dirwin->temp_for_search = False;
dirwin = dirwin->next;
}
}
/*
* destroy_search_dirwin - Destroy any directory display popped up to
* display a found entry.
*/
void
destroy_search_dirwin()
{
struct dirwin_st *dirwin = dirwin_head;
while(dirwin) {
if (dirwin->temp_for_search) {
close_directory_window(dirwin);
return;
}
dirwin = dirwin->next;
}
}
/*
* display_found_entry - Display and select the indicated entry in the
* specified directory. If directory is not already
* displayed then (1) if tunnelling is on, display
* directory in current dirwin, or (2) if tunnelling
* is off, create new dirwin for directory (and flag
* dirwin for deletion if search is continued).
* Returns 0 if successful, -1 if entry not in
* directory, -2 if unable to display directory,
* -6 if stop button pressed, and -3 if connection
* broken.
*/
display_found_entry(host, directory, entry)
int host;
char *directory;
char *entry;
{
struct entry_info *temp_einfo;
struct entry_info *einfo;
struct dirwin_st *dirwin;
int using_tunnelling;
int retval;
/* Make sure that directory is displayed and that entry is in it */
if (is_dir_displayed(host, directory, &dirwin, &temp_einfo)) {
if (!dirwin->temp_for_search)
destroy_search_dirwin();
if ((einfo = name_to_entry(host, directory, entry)))
XMapRaised(display, XtWindow(dirwin->w_shell));
else {
if ((entry[0] == '.') && !dirwin->dotfiles_mode) {
dirwin->dotfiles_mode = True;
cb_dotfiles_button_expose(dirwin->w_dotFilesButton,
(XtPointer)dirwin, (XtPointer)NULL);
}
switch (display_dir(host, dirwin, directory, True, True,
dirwin->cache_mode, False)) {
case -6:
return -6;
case -1:
return -2;
case -3:
return -3;
}
if (!(einfo = name_to_entry(host, directory, entry)))
return -1;
}
} else {
using_tunnelling = sc.cmd_dirwin->tunneling_mode;
retval = display_dir(host, sc.cmd_dirwin, directory, True, True,
sc.cmd_dirwin->cache_mode, False);
switch (retval) {
case -1:
return -2;
case -3:
case -6:
return retval;
}
destroy_search_dirwin();
if (!is_dir_displayed(host, directory, &dirwin, &temp_einfo))
fatal_error("Bug in display_found_entry()");
dirwin->temp_for_search = True;
if (!(einfo = name_to_entry(host, directory, entry))) {
if (!using_tunnelling) {
close_directory_window(dirwin);
return -1;
}
}
}
/* Make sure that entry is visible */
scroll_entry_into_view(einfo);
/* Select entry */
clear_selected_entries();
toggle_entry(einfo);
return 0;
}
/*
* name_to_entry - Return the entry in the specified directory with name
* "entry". Returns NULL if entry not in directory or if
* directory not displayed.
*/
struct entry_info *
name_to_entry(host, directory, entry)
int host;
char *directory;
char *entry;
{
struct dirwin_st *dirwin;
struct entry_info *einfo;
int start_index;
int i;
int level;
/* Is directory being displayed? */
if (!is_dir_displayed(host, directory, &dirwin, &einfo))
return NULL;
/* Look for entry */
if (einfo) {
start_index = einfo->indx+1;
level = einfo->level+1;
} else {
start_index = 0;
level = 0;
}
for (i=start_index; i<dirwin->nentries; i++)
if (dirwin->entries[i].level < level)
return NULL;
else if ((dirwin->entries[i].level == level)
&& (strcmp(dirwin->entries[i].name, entry) == 0))
return &(dirwin->entries[i]);
return NULL;
}
/*
* dircmp - Compares full-path directory names, dir1 and dir2. Returns
* -1 is dir1 has fewer links than dir2, 1 is dir1 has more links
* than dir2, and 0 if dir1 has the same number of links as dir2.
*/
dircmp(dir1, dir2)
char *dir1;
char *dir2;
{
int nlinks1 = 0;
int nlinks2 = 0;
char *ptr;
int len;
/* Determine number of links in dir1 */
ptr = dir1;
while (ptr) {
if (*ptr == '/')
nlinks1++;
ptr++;
}
len = strlen(dir1);
if (len > 0 && dir1[len-1] != '/')
nlinks1++;
/* Determine number of links in dir2 */
ptr = dir2;
while (ptr) {
if (*ptr == '/')
nlinks2++;
ptr++;
}
len = strlen(dir2);
if (len > 0 && dir2[len-1] != '/')
nlinks2++;
/* Compare */
if (nlinks1 < nlinks2)
return -1;
else if (nlinks1 > nlinks2)
return 1;
else
return 0;
}
/*
* cb_search_cancel - Callback to handle Search Dialog "Cancel" button.
*/
void
cb_search_cancel(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
/* Get rid of Search Dialog */
save_search_dialog_values();
XtDestroyWidget(XtParent(search.w_dialog));
/* End operation */
end_op();
}
/*
* save_search_dialog_values - Remember current search dialog settings
* for next time search dialog is popped up.
*/
void
save_search_dialog_values()
{
if (saved_prev_dialog_values)
XtFree(prev_dialog_values.pattern);
prev_dialog_values.pattern = XmTextFieldGetString(search.w_text);
prev_dialog_values.match_case =
XmToggleButtonGadgetGetState(search.w_matchCaseToggle);
XtVaGetValues(search.w_depth, XmNvalue,
&prev_dialog_values.max_depth, NULL);
if (XmToggleButtonGadgetGetState(search.w_searchThisDirToggle))
prev_dialog_values.range = SEARCH_THIS_DIR;
else if (XmToggleButtonGadgetGetState(search.w_searchThisHostToggle))
prev_dialog_values.range = SEARCH_THIS_HOST;
else
prev_dialog_values.range = SEARCH_ALL_HOSTS;
saved_prev_dialog_values = True;
}
/*
* init_search_dialog_values - Initialize the search dialog with values
* saved from the last time the dialog was
* popped up. If this is the first time the
* dialog is popped up, use values from the
* user preferences to initialize the settings.
*/
void
init_search_dialog_values()
{
XmToggleButtonGadgetSetState(search.w_searchThisDirToggle, False, True);
XmToggleButtonGadgetSetState(search.w_searchThisHostToggle, False, True);
XmToggleButtonGadgetSetState(search.w_searchAllHostsToggle, False, True);
if (saved_prev_dialog_values) {
XmTextFieldSetString(search.w_text, prev_dialog_values.pattern);
XtVaSetValues(search.w_depth, XmNvalue,
prev_dialog_values.max_depth, NULL);
XmToggleButtonGadgetSetState(search.w_matchCaseToggle,
prev_dialog_values.match_case, True);
switch (prev_dialog_values.range) {
case SEARCH_THIS_DIR:
XmToggleButtonGadgetSetState(search.w_searchThisDirToggle, True,
True);
break;
case SEARCH_THIS_HOST:
XmToggleButtonGadgetSetState(search.w_searchThisHostToggle, True,
True);
break;
case SEARCH_ALL_HOSTS:
XmToggleButtonGadgetSetState(search.w_searchAllHostsToggle, True,
True);
}
} else {
XmTextFieldSetString(search.w_text, "");
XtVaSetValues(search.w_depth, XmNvalue, initial_max_search_depth, NULL);
XmToggleButtonGadgetSetState(search.w_matchCaseToggle,
initial_match_case, True);
switch (initial_search_range) {
case SEARCH_THIS_DIR:
XmToggleButtonGadgetSetState(search.w_searchThisDirToggle, True,
True);
break;
case SEARCH_THIS_HOST:
XmToggleButtonGadgetSetState(search.w_searchThisHostToggle, True,
True);
break;
case SEARCH_ALL_HOSTS:
XmToggleButtonGadgetSetState(search.w_searchAllHostsToggle, True,
True);
}
}
}
/*
* sort_dirwins - Sort a linked list of directory windows by host name,
* user name, and directory path.
*/
void
sort_dirwins(head)
struct dirwin_link **head;
{
struct dirwin_link *dptr;
struct dirwin_st **dirwins;
int ndirwins = 0;
int n;
int i;
int j;
/* Count the number of entries in the linked list */
dptr = *head;
while (dptr) {
ndirwins++;
dptr = dptr->next;
}
/* Allocate array of pointers to dirwins */
dirwins =
(struct dirwin_st **)XtMalloc(sizeof(struct dirwin_st *)*ndirwins);
/* Use straight insertion sort to place dirwins into array in order */
n = 0;
dptr = *head;
while (dptr) {
for (i=0; i<n; i++)
if (dirwin_cmp(dptr->dirwin, dirwins[i]) < 0)
break;
for (j=n-1; j>=i; j--)
dirwins[j+1] = dirwins[j];
dirwins[i] = dptr->dirwin;
n++;
dptr = dptr->next;
}
/* Free input linked list */
while (*head) {
dptr = (*head)->next;
XtFree((char*)*head);
*head = dptr;
}
/* Build sorted linked list */
for (i=ndirwins-1; i>=0; i--) {
dptr = XtNew(struct dirwin_link);
dptr->dirwin = dirwins[i];
dptr->next = *head;
*head = dptr;
}
XtFree((char *)dirwins);
}
/*
* dirwin_cmp - Compare directory windows "dirwin1" and "dirwin2" by host
* name, user name, and then directory path. Returns negative
* value if "dirwin1" is less than "dirwin2", 0 if "dirwin1"
* equals "dirwin2", and positive value if "dirwin1" is
* greater than "dirwin2".
*/
dirwin_cmp(dirwin1, dirwin2)
struct dirwin_st *dirwin1;
struct dirwin_st *dirwin2;
{
int retval;
char *username1;
char *username2;
/* Compare host names */
retval = strcmp(hinfo[dirwin1->host].hostname,
hinfo[dirwin2->host].hostname);
if (retval)
return retval;
/* Compare user names */
if (dirwin1->host == LOCAL)
username1 = XtNewString("Local");
else
username1 = XtNewString(hinfo[dirwin1->host].username);
if (dirwin2->host == LOCAL)
username2 = XtNewString("Local");
else
username2 = XtNewString(hinfo[dirwin2->host].username);
retval = strcmp(username1, username2);
XtFree(username1);
XtFree(username2);
if (retval)
return retval;
/* Compare directory paths */
return strcmp(dirwin1->dirname, dirwin2->dirname);
}
syntax highlighted by Code2HTML, v. 0.9.1