/***************************************************************************/ /***************************************************************************/ /* */ /* (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. */ /* */ /***************************************************************************/ /***************************************************************************/ #ifdef NEXT #include #else #include #endif #include #include #include #include #include #include "xdir.h" #include "list.h" #include "str.h" #include "history.h" static int volume = 0; static char *msg1 = "Operation aborted.\n\nThis directory window might be out of date.\n\nClick on sun icon in toolbar to refresh."; static char *msg2 = "Operation aborted.\n\nSource and sink directory windows might be out of date.\n\nClick on sun icon in toolbar to refresh a directory window."; char *entry_to_rel_path(); extern Display *display; extern Window root_window; extern int screen; extern int need_to_save_prefs; extern int diagnostics; extern struct dirwin_st *dirwin_head; extern struct st_host_info hinfo[]; extern int use_last_dir; /* * add_wm_delete_window_cb - Add callback for the WM_DELETE_WINDOW protocol * for the shell that is the ancestor of widget. * Set "unmap" to True if the window manager should * unmap the window. */ void add_wm_delete_window_cb(widget, callback, client_data, unmap) Widget widget; XtCallbackProc callback; XtPointer client_data; int unmap; { Atom WM_DELETE_WINDOW; Widget shell; /* First find the dialog's shell widget */ for (shell = widget; !XtIsShell(shell); shell = XtParent(shell)); /* Don't want toolkit to handle Close action */ if (unmap) XtVaSetValues(shell, XmNdeleteResponse, XmUNMAP, NULL); else XtVaSetValues(shell, XmNdeleteResponse, XmDO_NOTHING, NULL); /* Install the WM_DELETE_WINDOW atom */ WM_DELETE_WINDOW = XmInternAtom(display, "WM_DELETE_WINDOW", False); /* Add callback for the WM_DELETE_WINDOW protocol */ XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, callback, client_data); } /* * beep - Emit a beep. */ void beep() { XBell(display, volume); } /* * vertical_sb - Returns the vertical scrollbar of the list widget "w_list". */ Widget vertical_sb(widget) Widget widget; { Widget w_vertical_sb; XtVaGetValues(widget, XmNverticalScrollBar, &w_vertical_sb, NULL); return w_vertical_sb; } /* * quit - Quit application. w_parent is the widget to center the error * and question dialogs over. */ void quit(w_parent) Widget w_parent; { /* See if preferences need to be saved */ if (need_to_save_prefs && question_dialog( "Do you want to save the user preferences?", w_parent) && save_prefs()) { warn("Unable to save user preferences.", w_parent); } /* Get rid of any remaining temporary view directories */ delete_all_viewer_dirs(); if (save_history(w_parent) < 0) warn("Unable to save history.", w_parent); exit(0); } /* * cb_quit - Callback to quit application. */ void cb_quit(widget, client_data, call_data) Widget widget; XtPointer client_data; XtPointer call_data; { struct dirwin_st *dirwin = (struct dirwin_st *)client_data; /* Start operation */ if (!start_op(False)) return; if (question_dialog("Do you really want to terminate Xdir?", dirwin->w_shell)) quit(dirwin->w_shell); /* End operation */ end_op(); } /* * determine_true_path - Returns the actual path of the directory "path" * in "true_path" (which might differ from "path" * because of aliases). Set print_error_msg to * True if error messages are to be written to * the log. Set "cfetch_ok" to True if it is ok * to fetch the true path from the cache. Set * "cstore_ok" to True if it is ok to use the * true path to update the cache. The caller is * responsible for freeing "true_path" with XtFree(). * Returns 0 if successful, -3 for broken connection, * -6 for stop button pressed, and -1 for other * errors. "path" must be a full path. */ determine_true_path(host, path, print_error_msg, cstore_ok, cfetch_ok, true_path) int host; char *path; int print_error_msg; int cstore_ok; int cfetch_ok; char **true_path; { int retval; /* Can the directory mapping cache be used? */ if (cfetch_ok && (host != LOCAL)) { if (fetch_truepath_from_cache(host, path, true_path)) return 0; } /* Get true path */ if (host == LOCAL) { if (local_cd(path, print_error_msg) < 0) return -1; if (local_pwd(true_path) != 0) fatal_error("Unable to get local working directory"); } else { if ((retval = remote_cd(host, path, print_error_msg)) < 0) return retval; if ((retval = remote_pwd(host, true_path)) < 0) return retval; if (cstore_ok) add_truepath_to_cache(host, path, *true_path); } return 0; } /* * report_client_timeout - Write notice to diagnostics log that the * "host" has timed out. */ void report_client_timeout(host) int host; { char *msg; if (diagnostics >= VERBOSE) { msg = XtMalloc(strlen(hinfo[host].hostname)+100); sprintf(msg, "Timed out waiting for remote host %s to respond.\n", hinfo[host].hostname); write_log(msg); XtFree(msg); } } /* * get_host - Return array index to free host structure. Character string * Fields are initialized to zeros and NULLs. Returns -1 if * maximum number of hosts exceeded. */ get_host() { int host; /* Use first free structure */ for (host=1; hostdirwin; struct entry_link *ptr; if (einfo->expanded) { for (i=einfo->indx+1; inentries; i++) if (dirwin->entries[i].level <= einfo->level) break; else if (dirwin->entries[i].level == einfo->level+1) { postorder_selected_items(&dirwin->entries[i], head, tail); } } if (einfo->state == SELECTED) { ptr = XtNew(struct entry_link); ptr->entry = entry_to_rel_path(einfo); ptr->next = NULL; if (*head == NULL) { *head = ptr; *tail = ptr; } else { (*tail)->next = ptr; *tail = ptr; } } } /* * cb_disconnect - Callback to disconnect host. */ void cb_disconnect(widget, client_data, call_data) Widget widget; XtPointer client_data; XtPointer call_data; { struct dirwin_st *dirwin = (struct dirwin_st *)client_data; struct dirwin_st *dwin; struct dirwin_st *next; int host; static char *msg = "Disconnecting from this host will terminate Xdir. Continue disconnecting?"; /* Start operation */ if (!start_op(False)) return; /* Clear error flag */ raise_okflag(); /* Will disconnecting host cause application to terminate? */ dwin = dirwin_head; while (dwin && (dwin->host == dirwin->host)) dwin = dwin->next; if (dwin == NULL) { if (question_dialog(msg, dirwin->w_shell)) quit(dirwin->w_shell); else { end_op(); return; } } /* Close all directory windows associated with host */ host = dirwin->host; dwin = dirwin_head; while (dwin) { next = dwin->next; if (dwin->host == host) close_directory_window(dwin); dwin = next; } /* End operation */ end_op(); } /* * cb_map_dialog - Map the dialog (indicated by "widget") over the window * specified by "client_data". */ void cb_map_dialog(widget, client_data, call_data) Widget widget; XtPointer client_data; XtPointer call_data; { Window window = (Window)client_data; Window child; XWindowAttributes xwa; Dimension w; Dimension h; int x; int y; /* Get dialog's dimensions */ XtVaGetValues(widget, XmNwidth, &w, XmNheight, &h, NULL); /* Get bottom window's geometry */ if (!XGetWindowAttributes(display, window, &xwa)) fatal_error("Bug in cb_map_dialog()"); XTranslateCoordinates(display, window, root_window, 0, 0, &x, &y, &child); /* Center dialog above bottom window */ XtVaSetValues(widget, XmNx, x+(int)(xwa.width-w)/2, XmNy, y+(int)(xwa.height-h)/2, NULL); } /* * create_unique_name - Create a unique file name by, if necessary, * prefixing name with "." followed by a integer * that ranges from 1 to 99. If successful, a * pointer to the new name is returned. The * memory is in a static buffer local to this * routine. If unsuccessful, NULL is returned. * "file_path" should be the full path name of * the file. */ char * create_unique_name(file_path) char *file_path; { static char new_path[MAXPATHLEN+1]; int i; /* First see if supplied name is unique */ if (access(file_path, 0) < 0) { if (errno == ENOENT) { strcpy(new_path, file_path); return new_path; } else return NULL; } /* Try concatenating a "." followed by an integer */ for (i=1; i<100; i++) { sprintf(new_path, "%s.%d", file_path, i); if (access(new_path, 0) < 0) { if (errno == ENOENT) return new_path; else return NULL; } } /* Ran out of suffices */ return NULL; } /* * can_create_sinkfile - Returns True if a writable file specifed by * "snk_path" can be created; else returns False. */ can_create_sinkfile(snk_path) char *snk_path; { char *snk_dir; parse_path(SYS_UNIX, snk_path, &snk_dir, NULL); if (access(snk_path, W_OK) < 0) if (errno == ENOENT) { /* File does not exist */ if (access(snk_dir, W_OK) < 0) { report_perror(snk_path); XtFree(snk_dir); return False; } } else if (errno == EACCES) { /* Permission denied */ if (access(snk_dir, W_OK) < 0) { report_perror(snk_path); XtFree(snk_dir); return False; } if (chmod(snk_path, 0600) < 0) { report_perror(snk_path); XtFree(snk_dir); return False; } } else { report_perror(snk_path); XtFree(snk_dir); return False; } XtFree(snk_dir); return True; } /* * cb_iconify_all - Callback to iconify all top-level windows. */ void cb_iconify_all(widget, client_data, call_data) Widget widget; XtPointer client_data; XtPointer call_data; { /* Start operation */ if (!start_op(False)) return; /* Iconify all the windows */ iconify_diag_window(); iconify_lprefs_window(); iconify_vprefs_window(); iconify_fprefs_window(); iconify_gprefs_window(); iconify_directory_windows(); iconify_file_viewer_windows(); /* End operation */ end_op(); } /* * cb_deiconify_all - Callback to de-iconify all top-level windows. */ void cb_deiconify_all(widget, client_data, call_data) Widget widget; XtPointer client_data; XtPointer call_data; { /* Start operation */ if (!start_op(False)) return; /* Deiconify all the windows */ deiconify_diag_window(); deiconify_lprefs_window(); deiconify_vprefs_window(); deiconify_fprefs_window(); deiconify_gprefs_window(); deiconify_directory_windows(); deiconify_file_viewer_windows(); /* End the operation */ end_op(); } /* * cvt_to_lower - Convert string to lower case. */ void cvt_to_lower(str) char *str; { int i; for (i=strlen(str); i>=0; i--) str[i] = tolower(str[i]); } /* * cvt_to_upper - Convert string to upper case. */ void cvt_to_upper(str) char *str; { int i; for (i=strlen(str); i>=0; i--) str[i] = toupper(str[i]); } /* * add_commas - Converts "value" to a string, with each group of digits * delimited with a comma (e.g., long integer 1234567 is * converted to the string "1,234,567". Call XtFree() to * free returned string. */ char * add_commas(value) long value; { char buf[25]; char *number; int negative = False; int ndigits; int ncommas; int nlead; int i; int j; /* Easier to work with positive integer */ if (value < 0) { negative = True; value = -value; } /* Convert integer to string and add commas */ sprintf(buf, "%ld", value); ndigits = strlen(buf); ncommas = (ndigits-1)/3; if (negative) { number = XtMalloc(ndigits+ncommas+2); number[0] = '-'; j = 1; } else { number = XtMalloc(ndigits+ncommas+1); j = 0; } nlead = ndigits-((ndigits-1)/3)*3; for (i=0; inentries > 0) { retval = determine_true_path(host, list->entries[0], False, False, False, path); release_array_list(list); if (retval != -1) return retval; } else release_array_list(list); } /* Default to home directory */ *path = XtNewString(hinfo[host].homedir); return 0; } /* * cmp_long_vms_entries - Compares two long VMS entries (basically the * first blank-delimited tokens in "string1" and * "string2". Returns negative value if "string1" * is less than "string2, 0 if "string1" equals * string2, and positive value if "string1" is * greater than "string2". */ cmp_long_vms_entries(string1, string2) char *string1; char *string2; { char str1[MAXPATHLEN+1]; char str2[MAXPATHLEN+1]; /* Make copies of strings because strtok() modifies input string */ strcpy(str1, string1); strcpy(str2, string2); /* Strip off entry names */ if (!strtok(str1, " \t") || !strtok(str2, " \t")) fatal_error("Bug in cmp_long_vms_entries()"); /* Make comparison */ return strcmp(str1, str2); } /* * cmp_symbol_entries - Compares two strings, starting with the second * character of each string. Returns negative * value if "string1" is less than "string2, * 0 if "string1" equals "string2", and positive * value if "string1" is greater than "string2". */ cmp_symbol_entries(string1, string2) char *string1; char *string2; { return strcmp(string1+1, string2+1); } /* * sort_symbol_entries - Sort the "n" strings pointed to by the array of * character pointers "s". If a string ends with * '@', '*', '=', or '/', ignore the last character * when comparing two strings. */ void sort_symbol_entries(s, n) char *s[]; int n; { int i; int len; char *p; char ch; /* Move special character to first position in string, else use space */ for (i=0; itv_sec = time1->tv_sec+time2->tv_sec; total_time->tv_usec = time1->tv_usec+time2->tv_usec; carry_secs = total_time->tv_usec/1000000; total_time->tv_usec = total_time->tv_usec-1000000*carry_secs; total_time->tv_sec += carry_secs; } /* * cmp_timevals - Returns negative value if "time1" is less than "time2", * 0 if "time1" equals "time2", and positive value if * "time1" is greater than "time2". All times are * represented using the standard timeval structure. */ cmp_timevals(time1, time2) struct timeval *time1; struct timeval *time2; { if (time1->tv_sec > time2->tv_sec) return 1; else if (time1->tv_sec < time2->tv_sec) return -1; else if (time1->tv_usec > time2->tv_usec) return 1; else if (time1->tv_usec < time2->tv_usec) return -1; else return 0; } /* * dirwin_out_of_date_alert - Alert the user that the directory window might * out of date because of the aborted operation. * The alert dialog is placed over the directory * window specified by "dirwin". */ void dirwin_out_of_date_alert(dirwin) struct dirwin_st *dirwin; { info_dialog(msg1, dirwin->w_shell); } /* * dirwins_out_of_date_alert - Alert the user that the directory windows might * out of date because of the aborted operation. * The alert dialog is placed over the directory * window specified by "dirwin". */ void dirwins_out_of_date_alert(dirwin) struct dirwin_st *dirwin; { info_dialog(msg2, dirwin->w_shell); } /* * set_textfield - Set the textfield widget "widget" to the character * string "string". If the textfield already has this * value, this routine is a no-op (to prevent the widget * from blinking). */ void set_textfield(widget, string) Widget widget; char *string; { char *old_string; old_string = XmTextFieldGetString(widget); if (strcmp(string, old_string)) XmTextFieldSetString(widget, string); XtFree(old_string); }