X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkfilesel.c;h=d3a1904364c362fddf9f7e60517ce09792ea8622;hb=e57b1afa2b4c91bcfecef26e4bff5280bd3563de;hp=2001e2d937391591021e6d0de0096f04ba64fb85;hpb=9ad922290cc7495298099a4b97029942b0ce34c3;p=~andy%2Fgtk diff --git a/gtk/gtkfilesel.c b/gtk/gtkfilesel.c index 2001e2d93..d3a190436 100644 --- a/gtk/gtkfilesel.c +++ b/gtk/gtkfilesel.c @@ -12,19 +12,39 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. */ + +/* + * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + #include #include #include +#ifdef HAVE_SYS_PARAM_H #include +#endif +#ifdef HAVE_DIRENT_H #include +#endif #include +#ifdef HAVE_UNISTD_H #include +#endif #include #include +#ifdef HAVE_PWD_H #include +#endif + #include "fnmatch.h" #include "gdk/gdkkeysyms.h" @@ -32,6 +52,7 @@ #include "gtkentry.h" #include "gtkfilesel.h" #include "gtkhbox.h" +#include "gtkhbbox.h" #include "gtklabel.h" #include "gtklist.h" #include "gtklistitem.h" @@ -44,6 +65,23 @@ #include "gtkoptionmenu.h" #include "gtkclist.h" #include "gtkdialog.h" +#include "gtkintl.h" + +#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) +#define STRICT +#include + +#ifdef G_OS_WIN32 +#include +#include +#define mkdir(p,m) _mkdir(p) +#ifndef S_ISDIR +#define S_ISDIR(mode) ((mode)&_S_IFDIR) +#endif + +#endif /* G_OS_WIN32 */ + +#endif /* G_OS_WIN32 || G_WITH_CYGWIN */ #define DIR_LIST_WIDTH 180 #define DIR_LIST_HEIGHT 180 @@ -92,10 +130,9 @@ struct _CompletionDirSent { ino_t inode; time_t mtime; + dev_t device; gint entry_count; - gchar *name_buffer; /* memory segment containing names of all entries */ - struct _CompletionDirEntry *entries; }; @@ -121,7 +158,7 @@ struct _CompletionDir */ struct _CompletionDirEntry { - gint is_dir; + gboolean is_dir; gchar *entry_name; }; @@ -138,7 +175,7 @@ struct _PossibleCompletion */ gchar *text; gint is_a_completion; - gint is_directory; + gboolean is_directory; /* Private fields */ @@ -151,11 +188,10 @@ struct _CompletionState gchar *updated_text; gint updated_text_len; gint updated_text_alloc; - gint re_complete; + gboolean re_complete; gchar *user_dir_name_buffer; gint user_directories_len; - gchar *user_home_dir; gchar *last_completion_text; @@ -200,7 +236,7 @@ static gint cmpl_is_a_completion (PossibleCompletion*); /* True if the completion is a directory */ -static gint cmpl_is_directory (PossibleCompletion*); +static gboolean cmpl_is_directory (PossibleCompletion*); /* Obtains the next completion, or NULL */ @@ -218,7 +254,7 @@ static gchar* cmpl_updated_text (CompletionState* cmpl_state) /* After updating, to see if the completion was a directory, call * this. If it was, you should consider re-calling completion_matches. */ -static gint cmpl_updated_dir (CompletionState* cmpl_state); +static gboolean cmpl_updated_dir (CompletionState* cmpl_state); /* Current location: if using file completion, return the current * directory, from which file completion begins. More specifically, @@ -242,13 +278,22 @@ static gchar* cmpl_completion_fullname (gchar*, CompletionState* cm static CompletionDir* open_ref_dir (gchar* text_to_complete, gchar** remaining_text, CompletionState* cmpl_state); +#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) +static gboolean check_dir (gchar *dir_name, + struct stat *result, + gboolean *stat_subdirs); +#endif static CompletionDir* open_dir (gchar* dir_name, CompletionState* cmpl_state); +#ifdef HAVE_PWD_H static CompletionDir* open_user_dir (gchar* text_to_complete, CompletionState *cmpl_state); +#endif static CompletionDir* open_relative_dir (gchar* dir_name, CompletionDir* dir, CompletionState *cmpl_state); -static CompletionDirSent* open_new_dir (gchar* dir_name, struct stat* sbuf); +static CompletionDirSent* open_new_dir (gchar* dir_name, + struct stat* sbuf, + gboolean stat_subdirs); static gint correct_dir_fullname (CompletionDir* cmpl_dir); static gint correct_parent (CompletionDir* cmpl_dir, struct stat *sbuf); @@ -269,9 +314,11 @@ static CompletionDir* find_completion_dir(gchar* text_to_complete, CompletionState* cmpl_state); static PossibleCompletion* append_completion_text(gchar* text, CompletionState* cmpl_state); +#ifdef HAVE_PWD_H static gint get_pwdb(CompletionState* cmpl_state); -static gint first_diff_index(gchar* pat, gchar* text); static gint compare_user_dir(const void* a, const void* b); +#endif +static gint first_diff_index(gchar* pat, gchar* text); static gint compare_cmpl_dir(const void* a, const void* b); static void update_cmpl(PossibleCompletion* poss, CompletionState* cmpl_state); @@ -286,27 +333,15 @@ static gint gtk_file_selection_key_press (GtkWidget *widget, static void gtk_file_selection_file_button (GtkWidget *widget, gint row, gint column, - gint button, + GdkEventButton *bevent, gpointer user_data); -static void gtk_file_selection_file_button_double (GtkWidget *widget, - gint row, - gint column, - gint button, - gpointer user_data); - static void gtk_file_selection_dir_button (GtkWidget *widget, gint row, gint column, - gint button, + GdkEventButton *bevent, gpointer data); -static void gtk_file_selection_dir_button_double (GtkWidget *widget, - gint row, - gint column, - gint button, - gpointer data); - static void gtk_file_selection_populate (GtkFileSelection *fs, gchar *rel_path, gint try_complete); @@ -326,25 +361,91 @@ static GtkWindowClass *parent_class = NULL; /* Saves errno when something cmpl does fails. */ static gint cmpl_errno; -guint -gtk_file_selection_get_type () +#ifdef G_WITH_CYGWIN +/* + * Take the path currently in the file selection + * entry field and translate as necessary from + * a WIN32 style to CYGWIN32 style path. For + * instance translate: + * x:\somepath\file.jpg + * to: + * //x/somepath/file.jpg + * + * Replace the path in the selection text field. + * Return a boolean value concerning whether a + * translation had to be made. + */ +int +translate_win32_path(GtkFileSelection *filesel) +{ + int updated = 0; + gchar *path; + + /* + * Retrieve the current path + */ + path = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); + + /* + * Translate only if this looks like a DOS-ish + * path... First handle any drive letters. + */ + if (isalpha(path[0]) && (path[1] == ':')) { + /* + * This part kind of stinks... It isn't possible + * to know if there is enough space in the current + * string for the extra character required in this + * conversion. Assume that there isn't enough space + * and use the set function on the text field to + * set the newly created string. + */ + gchar *newPath; + + newPath = g_malloc(strlen(path) + 2); + sprintf(newPath, "//%c/%s", path[0], (path + 3)); + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), newPath); + + path = newPath; + updated = 1; + } + + /* + * Now, replace backslashes with forward slashes + * if necessary. + */ + if (strchr(path, '\\')) { + int index; + for (index = 0; path[index] != '\0'; index++) + if (path[index] == '\\') + path[index] = '/'; + + updated = 1; + } + + return updated; +} +#endif + +GtkType +gtk_file_selection_get_type (void) { - static guint file_selection_type = 0; + static GtkType file_selection_type = 0; if (!file_selection_type) { - GtkTypeInfo filesel_info = + static const GtkTypeInfo filesel_info = { "GtkFileSelection", sizeof (GtkFileSelection), sizeof (GtkFileSelectionClass), (GtkClassInitFunc) gtk_file_selection_class_init, (GtkObjectInitFunc) gtk_file_selection_init, - (GtkArgSetFunc) NULL, - (GtkArgGetFunc) NULL, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, }; - file_selection_type = gtk_type_unique (gtk_window_get_type (), &filesel_info); + file_selection_type = gtk_type_unique (GTK_TYPE_WINDOW, &filesel_info); } return file_selection_type; @@ -357,7 +458,7 @@ gtk_file_selection_class_init (GtkFileSelectionClass *class) object_class = (GtkObjectClass*) class; - parent_class = gtk_type_class (gtk_window_get_type ()); + parent_class = gtk_type_class (GTK_TYPE_WINDOW); object_class->destroy = gtk_file_selection_destroy; } @@ -368,56 +469,31 @@ gtk_file_selection_init (GtkFileSelection *filesel) GtkWidget *entry_vbox; GtkWidget *label; GtkWidget *list_hbox; - GtkWidget *action_area; + GtkWidget *confirm_area; GtkWidget *pulldown_hbox; - GtkWidget *button_hbox; - GtkWidget *button; - char *dir_title [] = { "Directories", }; - char *file_title [] = { "Files", }; + GtkWidget *scrolled_win; + + char *dir_title [2]; + char *file_title [2]; filesel->cmpl_state = cmpl_init_state (); - + /* The dialog-sized vertical box */ filesel->main_vbox = gtk_vbox_new (FALSE, 10); - gtk_container_border_width (GTK_CONTAINER (filesel), 10); + gtk_container_set_border_width (GTK_CONTAINER (filesel), 10); gtk_container_add (GTK_CONTAINER (filesel), filesel->main_vbox); gtk_widget_show (filesel->main_vbox); /* The horizontal box containing create, rename etc. buttons */ - button_hbox = gtk_hbox_new (TRUE, 0); - gtk_box_pack_start (GTK_BOX (filesel->main_vbox), button_hbox, + filesel->button_area = gtk_hbutton_box_new (); + gtk_button_box_set_layout(GTK_BUTTON_BOX(filesel->button_area), GTK_BUTTONBOX_START); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(filesel->button_area), 0); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->button_area, FALSE, FALSE, 0); - gtk_widget_show (button_hbox); - - /* delete, create directory, and rename */ - button = gtk_button_new_with_label ("Create Dir"); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) gtk_file_selection_create_dir, - (gpointer) filesel); - gtk_box_pack_start (GTK_BOX (button_hbox), button, TRUE, TRUE, 0); - gtk_widget_show (button); - - button = gtk_button_new_with_label ("Delete File"); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) gtk_file_selection_delete_file, - (gpointer) filesel); - gtk_box_pack_start (GTK_BOX (button_hbox), button, TRUE, TRUE, 0); - gtk_widget_show (button); - - button = gtk_button_new_with_label ("Rename File"); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) gtk_file_selection_rename_file, - (gpointer) filesel); - gtk_box_pack_start (GTK_BOX (button_hbox), button, TRUE, TRUE, 0); - gtk_widget_show (button); - - /* The Help button */ - filesel->help_button = gtk_button_new_with_label ("Help"); - gtk_box_pack_start (GTK_BOX (button_hbox), filesel->help_button, - TRUE, TRUE, 5); - gtk_widget_show (filesel->help_button); - + gtk_widget_show (filesel->button_area); + gtk_file_selection_show_fileop_buttons(filesel); + /* hbox for pulldown menu */ pulldown_hbox = gtk_hbox_new (TRUE, 5); gtk_box_pack_start (GTK_BOX (filesel->main_vbox), pulldown_hbox, FALSE, FALSE, 0); @@ -435,51 +511,67 @@ gtk_file_selection_init (GtkFileSelection *filesel) gtk_widget_show (list_hbox); /* The directories clist */ - filesel->dir_list = gtk_clist_new_with_titles (1, dir_title); + dir_title[0] = _("Directories"); + dir_title[1] = NULL; + filesel->dir_list = gtk_clist_new_with_titles (1, (gchar**) dir_title); gtk_widget_set_usize (filesel->dir_list, DIR_LIST_WIDTH, DIR_LIST_HEIGHT); gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "select_row", (GtkSignalFunc) gtk_file_selection_dir_button, (gpointer) filesel); - gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "mouse_double_click", - (GtkSignalFunc) gtk_file_selection_dir_button_double, - (gpointer) filesel); - gtk_clist_set_policy (GTK_CLIST (filesel->dir_list), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC); gtk_clist_column_titles_passive (GTK_CLIST (filesel->dir_list)); - gtk_container_border_width (GTK_CONTAINER (filesel->dir_list), 5); - gtk_box_pack_start (GTK_BOX (list_hbox), filesel->dir_list, TRUE, TRUE, 0); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->dir_list); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_container_set_border_width (GTK_CONTAINER (scrolled_win), 5); + gtk_box_pack_start (GTK_BOX (list_hbox), scrolled_win, TRUE, TRUE, 0); gtk_widget_show (filesel->dir_list); + gtk_widget_show (scrolled_win); /* The files clist */ - filesel->file_list = gtk_clist_new_with_titles (1, file_title); + file_title[0] = _("Files"); + file_title[1] = NULL; + filesel->file_list = gtk_clist_new_with_titles (1, (gchar**) file_title); gtk_widget_set_usize (filesel->file_list, FILE_LIST_WIDTH, FILE_LIST_HEIGHT); gtk_signal_connect (GTK_OBJECT (filesel->file_list), "select_row", (GtkSignalFunc) gtk_file_selection_file_button, (gpointer) filesel); - gtk_signal_connect (GTK_OBJECT (filesel->file_list), "mouse_double_click", - (GtkSignalFunc) gtk_file_selection_file_button_double, - (gpointer) filesel); - gtk_clist_set_policy (GTK_CLIST (filesel->file_list), GTK_POLICY_ALWAYS, GTK_POLICY_AUTOMATIC); gtk_clist_column_titles_passive (GTK_CLIST (filesel->file_list)); - gtk_container_border_width (GTK_CONTAINER (filesel->file_list), 5); - gtk_box_pack_start (GTK_BOX (list_hbox), filesel->file_list, TRUE, TRUE, 0); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (scrolled_win), filesel->file_list); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_container_set_border_width (GTK_CONTAINER (scrolled_win), 5); + gtk_box_pack_start (GTK_BOX (list_hbox), scrolled_win, TRUE, TRUE, 0); gtk_widget_show (filesel->file_list); + gtk_widget_show (scrolled_win); - /* The action area */ - action_area = gtk_hbox_new (TRUE, 10); - gtk_box_pack_end (GTK_BOX (filesel->main_vbox), action_area, FALSE, FALSE, 0); - gtk_widget_show (action_area); + /* action area for packing buttons into. */ + filesel->action_area = gtk_hbox_new (TRUE, 0); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->action_area, + FALSE, FALSE, 0); + gtk_widget_show (filesel->action_area); + + /* The OK/Cancel button area */ + confirm_area = gtk_hbutton_box_new (); + gtk_button_box_set_layout(GTK_BUTTON_BOX(confirm_area), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(confirm_area), 5); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), confirm_area, FALSE, FALSE, 0); + gtk_widget_show (confirm_area); /* The OK button */ - filesel->ok_button = gtk_button_new_with_label ("OK"); + filesel->ok_button = gtk_button_new_with_label (_("OK")); GTK_WIDGET_SET_FLAGS (filesel->ok_button, GTK_CAN_DEFAULT); - gtk_box_pack_start (GTK_BOX (action_area), filesel->ok_button, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (confirm_area), filesel->ok_button, TRUE, TRUE, 0); gtk_widget_grab_default (filesel->ok_button); gtk_widget_show (filesel->ok_button); /* The Cancel button */ - filesel->cancel_button = gtk_button_new_with_label ("Cancel"); + filesel->cancel_button = gtk_button_new_with_label (_("Cancel")); GTK_WIDGET_SET_FLAGS (filesel->cancel_button, GTK_CAN_DEFAULT); - gtk_box_pack_start (GTK_BOX (action_area), filesel->cancel_button, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (confirm_area), filesel->cancel_button, TRUE, TRUE, 0); gtk_widget_show (filesel->cancel_button); /* The selection entry widget */ @@ -508,9 +600,9 @@ gtk_file_selection_init (GtkFileSelection *filesel) { gchar err_buf[256]; - sprintf (err_buf, "Directory unreadable: %s", cmpl_strerror (cmpl_errno)); + sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno)); - gtk_label_set (GTK_LABEL (filesel->selection_text), err_buf); + gtk_label_set_text (GTK_LABEL (filesel->selection_text), err_buf); } else { @@ -525,37 +617,104 @@ gtk_file_selection_new (const gchar *title) { GtkFileSelection *filesel; - filesel = gtk_type_new (gtk_file_selection_get_type ()); + filesel = gtk_type_new (GTK_TYPE_FILE_SELECTION); gtk_window_set_title (GTK_WINDOW (filesel), title); return GTK_WIDGET (filesel); } +void +gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + /* delete, create directory, and rename */ + if (!filesel->fileop_c_dir) + { + filesel->fileop_c_dir = gtk_button_new_with_label (_("Create Dir")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_c_dir), "clicked", + (GtkSignalFunc) gtk_file_selection_create_dir, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_c_dir, TRUE, TRUE, 0); + gtk_widget_show (filesel->fileop_c_dir); + } + + if (!filesel->fileop_del_file) + { + filesel->fileop_del_file = gtk_button_new_with_label (_("Delete File")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_del_file), "clicked", + (GtkSignalFunc) gtk_file_selection_delete_file, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_del_file, TRUE, TRUE, 0); + gtk_widget_show (filesel->fileop_del_file); + } + + if (!filesel->fileop_ren_file) + { + filesel->fileop_ren_file = gtk_button_new_with_label (_("Rename File")); + gtk_signal_connect (GTK_OBJECT (filesel->fileop_ren_file), "clicked", + (GtkSignalFunc) gtk_file_selection_rename_file, + (gpointer) filesel); + gtk_box_pack_start (GTK_BOX (filesel->button_area), + filesel->fileop_ren_file, TRUE, TRUE, 0); + gtk_widget_show (filesel->fileop_ren_file); + } + + gtk_widget_queue_resize(GTK_WIDGET(filesel)); +} + +void +gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + + if (filesel->fileop_ren_file) + { + gtk_widget_destroy (filesel->fileop_ren_file); + filesel->fileop_ren_file = NULL; + } + + if (filesel->fileop_del_file) + { + gtk_widget_destroy (filesel->fileop_del_file); + filesel->fileop_del_file = NULL; + } + + if (filesel->fileop_c_dir) + { + gtk_widget_destroy (filesel->fileop_c_dir); + filesel->fileop_c_dir = NULL; + } +} + + + void gtk_file_selection_set_filename (GtkFileSelection *filesel, const gchar *filename) { - char buf[MAXPATHLEN]; + gchar *buf; const char *name, *last_slash; g_return_if_fail (filesel != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); g_return_if_fail (filename != NULL); - last_slash = strrchr (filename, '/'); + last_slash = strrchr (filename, G_DIR_SEPARATOR); if (!last_slash) { - buf[0] = 0; + buf = g_strdup (""); name = filename; } else { - gint len = MIN (MAXPATHLEN - 1, last_slash - filename + 1); - - strncpy (buf, filename, len); - buf[len] = 0; - + buf = g_strdup (filename); + buf[last_slash - filename + 1] = 0; name = last_slash + 1; } @@ -563,6 +722,7 @@ gtk_file_selection_set_filename (GtkFileSelection *filesel, if (filesel->selection_entry) gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), name); + g_free (buf); } gchar* @@ -575,16 +735,32 @@ gtk_file_selection_get_filename (GtkFileSelection *filesel) g_return_val_if_fail (filesel != NULL, nothing); g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), nothing); +#ifdef G_WITH_CYGWIN + translate_win32_path(filesel); +#endif text = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); if (text) { filename = cmpl_completion_fullname (text, filesel->cmpl_state); - return filename; + return g_filename_from_utf8 (filename); } return nothing; } +void +gtk_file_selection_complete (GtkFileSelection *filesel, + const gchar *pattern) +{ + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + g_return_if_fail (pattern != NULL); + + if (filesel->selection_entry) + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), pattern); + gtk_file_selection_populate (filesel, (gchar*) pattern, TRUE); +} + static void gtk_file_selection_destroy (GtkObject *object) { @@ -607,6 +783,7 @@ gtk_file_selection_destroy (GtkObject *object) { callback_arg = list->data; g_free (callback_arg->directory); + g_free (callback_arg); list = list->next; } g_list_free (filesel->history_list); @@ -623,7 +800,7 @@ gtk_file_selection_destroy (GtkObject *object) /* Begin file operations callbacks */ static void -gtk_file_selection_fileop_error (gchar *error_message) +gtk_file_selection_fileop_error (GtkFileSelection *fs, gchar *error_message) { GtkWidget *label; GtkWidget *vbox; @@ -639,11 +816,16 @@ gtk_file_selection_fileop_error (gchar *error_message) (GtkSignalFunc) gtk_file_selection_fileop_destroy, (gpointer) fs); */ - gtk_window_set_title (GTK_WINDOW (dialog), "Error"); - gtk_window_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Error")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + /* If file dialog is grabbed, make this dialog modal too */ + /* When error dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + vbox = gtk_vbox_new(FALSE, 0); - gtk_container_border_width(GTK_CONTAINER(vbox), 8); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, FALSE, FALSE, 0); gtk_widget_show(vbox); @@ -657,7 +839,7 @@ gtk_file_selection_fileop_error (gchar *error_message) g_free (error_message); /* close button */ - button = gtk_button_new_with_label ("Close"); + button = gtk_button_new_with_label (_("Close")); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (gpointer) dialog); @@ -699,12 +881,12 @@ gtk_file_selection_create_dir_confirmed (GtkWidget *widget, gpointer data) cmpl_state = (CompletionState*) fs->cmpl_state; path = cmpl_reference_position (cmpl_state); - full_path = g_strconcat (path, "/", dirname, NULL); + full_path = g_strconcat (path, G_DIR_SEPARATOR_S, dirname, NULL); if ( (mkdir (full_path, 0755) < 0) ) { buf = g_strconcat ("Error creating directory \"", dirname, "\": ", g_strerror(errno), NULL); - gtk_file_selection_fileop_error (buf); + gtk_file_selection_fileop_error (fs, buf); } g_free (full_path); @@ -732,17 +914,21 @@ gtk_file_selection_create_dir (GtkWidget *widget, gpointer data) gtk_signal_connect (GTK_OBJECT (dialog), "destroy", (GtkSignalFunc) gtk_file_selection_fileop_destroy, (gpointer) fs); - gtk_window_set_title (GTK_WINDOW (dialog), "Create Directory"); - gtk_window_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); - gtk_widget_show (dialog); - + gtk_window_set_title (GTK_WINDOW (dialog), _("Create Directory")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); + vbox = gtk_vbox_new(FALSE, 0); - gtk_container_border_width(GTK_CONTAINER(vbox), 8); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, FALSE, FALSE, 0); gtk_widget_show(vbox); - label = gtk_label_new("Directory name:"); + label = gtk_label_new(_("Directory name:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); gtk_widget_show(label); @@ -755,7 +941,7 @@ gtk_file_selection_create_dir (GtkWidget *widget, gpointer data) gtk_widget_show (fs->fileop_entry); /* buttons */ - button = gtk_button_new_with_label ("Create"); + button = gtk_button_new_with_label (_("Create")); gtk_signal_connect (GTK_OBJECT (button), "clicked", (GtkSignalFunc) gtk_file_selection_create_dir_confirmed, (gpointer) fs); @@ -764,7 +950,7 @@ gtk_file_selection_create_dir (GtkWidget *widget, gpointer data) GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_show(button); - button = gtk_button_new_with_label ("Cancel"); + button = gtk_button_new_with_label (_("Cancel")); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (gpointer) dialog); @@ -773,6 +959,8 @@ gtk_file_selection_create_dir (GtkWidget *widget, gpointer data) GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_grab_default(button); gtk_widget_show (button); + + gtk_widget_show (dialog); } static void @@ -790,12 +978,12 @@ gtk_file_selection_delete_file_confirmed (GtkWidget *widget, gpointer data) cmpl_state = (CompletionState*) fs->cmpl_state; path = cmpl_reference_position (cmpl_state); - full_path = g_strconcat (path, "/", fs->fileop_file, NULL); + full_path = g_strconcat (path, G_DIR_SEPARATOR_S, fs->fileop_file, NULL); if ( (unlink (full_path) < 0) ) { buf = g_strconcat ("Error deleting file \"", fs->fileop_file, "\": ", g_strerror(errno), NULL); - gtk_file_selection_fileop_error (buf); + gtk_file_selection_fileop_error (fs, buf); } g_free (full_path); @@ -820,6 +1008,10 @@ gtk_file_selection_delete_file (GtkWidget *widget, gpointer data) if (fs->fileop_dialog) return; +#ifdef G_WITH_CYGWIN + translate_win32_path(fs); +#endif + filename = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); if (strlen(filename) < 1) return; @@ -831,11 +1023,16 @@ gtk_file_selection_delete_file (GtkWidget *widget, gpointer data) gtk_signal_connect (GTK_OBJECT (dialog), "destroy", (GtkSignalFunc) gtk_file_selection_fileop_destroy, (gpointer) fs); - gtk_window_set_title (GTK_WINDOW (dialog), "Delete File"); - gtk_window_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + gtk_window_set_title (GTK_WINDOW (dialog), _("Delete File")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog is closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); vbox = gtk_vbox_new(FALSE, 0); - gtk_container_border_width(GTK_CONTAINER(vbox), 8); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, FALSE, FALSE, 0); gtk_widget_show(vbox); @@ -848,7 +1045,7 @@ gtk_file_selection_delete_file (GtkWidget *widget, gpointer data) g_free(buf); /* buttons */ - button = gtk_button_new_with_label ("Delete"); + button = gtk_button_new_with_label (_("Delete")); gtk_signal_connect (GTK_OBJECT (button), "clicked", (GtkSignalFunc) gtk_file_selection_delete_file_confirmed, (gpointer) fs); @@ -857,7 +1054,7 @@ gtk_file_selection_delete_file (GtkWidget *widget, gpointer data) GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_show(button); - button = gtk_button_new_with_label ("Cancel"); + button = gtk_button_new_with_label (_("Cancel")); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (gpointer) dialog); @@ -868,6 +1065,7 @@ gtk_file_selection_delete_file (GtkWidget *widget, gpointer data) gtk_widget_show (button); gtk_widget_show (dialog); + } static void @@ -888,14 +1086,14 @@ gtk_file_selection_rename_file_confirmed (GtkWidget *widget, gpointer data) cmpl_state = (CompletionState*) fs->cmpl_state; path = cmpl_reference_position (cmpl_state); - new_filename = g_strconcat (path, "/", file, NULL); - old_filename = g_strconcat (path, "/", fs->fileop_file, NULL); + new_filename = g_strconcat (path, G_DIR_SEPARATOR_S, file, NULL); + old_filename = g_strconcat (path, G_DIR_SEPARATOR_S, fs->fileop_file, NULL); if ( (rename (old_filename, new_filename)) < 0) { buf = g_strconcat ("Error renaming file \"", file, "\": ", g_strerror(errno), NULL); - gtk_file_selection_fileop_error (buf); + gtk_file_selection_fileop_error (fs, buf); } g_free (new_filename); g_free (old_filename); @@ -929,12 +1127,16 @@ gtk_file_selection_rename_file (GtkWidget *widget, gpointer data) gtk_signal_connect (GTK_OBJECT (dialog), "destroy", (GtkSignalFunc) gtk_file_selection_fileop_destroy, (gpointer) fs); - gtk_window_set_title (GTK_WINDOW (dialog), "Rename File"); - gtk_window_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); - gtk_widget_show (dialog); + gtk_window_set_title (GTK_WINDOW (dialog), _("Rename File")); + gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); + + /* If file dialog is grabbed, grab option dialog */ + /* When option dialog closed, file dialog will be grabbed again */ + if (GTK_WINDOW(fs)->modal) + gtk_window_set_modal (GTK_WINDOW(dialog), TRUE); vbox = gtk_vbox_new(FALSE, 0); - gtk_container_border_width(GTK_CONTAINER(vbox), 8); + gtk_container_set_border_width (GTK_CONTAINER(vbox), 8); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, FALSE, FALSE, 0); gtk_widget_show(vbox); @@ -954,11 +1156,11 @@ gtk_file_selection_rename_file (GtkWidget *widget, gpointer data) gtk_widget_show (fs->fileop_entry); gtk_entry_set_text (GTK_ENTRY (fs->fileop_entry), fs->fileop_file); - gtk_entry_select_region (GTK_ENTRY (fs->fileop_entry), - 0, strlen (fs->fileop_file)); + gtk_editable_select_region (GTK_EDITABLE (fs->fileop_entry), + 0, strlen (fs->fileop_file)); /* buttons */ - button = gtk_button_new_with_label ("Rename"); + button = gtk_button_new_with_label (_("Rename")); gtk_signal_connect (GTK_OBJECT (button), "clicked", (GtkSignalFunc) gtk_file_selection_rename_file_confirmed, (gpointer) fs); @@ -967,7 +1169,7 @@ gtk_file_selection_rename_file (GtkWidget *widget, gpointer data) GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_show(button); - button = gtk_button_new_with_label ("Cancel"); + button = gtk_button_new_with_label (_("Cancel")); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", (GtkSignalFunc) gtk_widget_destroy, (gpointer) dialog); @@ -976,6 +1178,8 @@ gtk_file_selection_rename_file (GtkWidget *widget, gpointer data) GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_grab_default(button); gtk_widget_show (button); + + gtk_widget_show (dialog); } @@ -992,12 +1196,20 @@ gtk_file_selection_key_press (GtkWidget *widget, if (event->keyval == GDK_Tab) { - gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); - fs = GTK_FILE_SELECTION (user_data); +#ifdef G_WITH_CYGWIN + translate_win32_path(fs); +#endif text = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + + text = g_strdup (text); + gtk_file_selection_populate (fs, text, TRUE); + g_free (text); + + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + return TRUE; } @@ -1038,7 +1250,6 @@ gtk_file_selection_update_history_menu (GtkFileSelection *fs, GtkWidget *menu_item; GList *list; gchar *current_dir; - gchar *directory; gint dir_len; gint i; @@ -1053,6 +1264,7 @@ gtk_file_selection_update_history_menu (GtkFileSelection *fs, while (list) { callback_arg = list->data; g_free (callback_arg->directory); + g_free (callback_arg); list = list->next; } g_list_free (fs->history_list); @@ -1071,13 +1283,16 @@ gtk_file_selection_update_history_menu (GtkFileSelection *fs, { /* the i == dir_len is to catch the full path for the first * entry. */ - if ( (current_dir[i] == '/') || (i == dir_len)) + if ( (current_dir[i] == G_DIR_SEPARATOR) || (i == dir_len)) { /* another small hack to catch the full path */ if (i != dir_len) current_dir[i + 1] = '\0'; +#ifdef G_WITH_CYGWIN + if (!strcmp(current_dir, "//")) + continue; +#endif menu_item = gtk_menu_item_new_with_label (current_dir); - directory = g_strdup (current_dir); callback_arg = g_new (HistoryCallbackArg, 1); callback_arg->menu_item = menu_item; @@ -1088,7 +1303,7 @@ gtk_file_selection_update_history_menu (GtkFileSelection *fs, if (dir_len == i) { callback_arg->directory = g_strdup (""); } else { - callback_arg->directory = directory; + callback_arg->directory = g_strdup (current_dir); } fs->history_list = g_list_append (fs->history_list, callback_arg); @@ -1106,95 +1321,140 @@ gtk_file_selection_update_history_menu (GtkFileSelection *fs, g_free (current_dir); } - - static void gtk_file_selection_file_button (GtkWidget *widget, - gint row, - gint column, - gint button, - gpointer user_data) + gint row, + gint column, + GdkEventButton *bevent, + gpointer user_data) { GtkFileSelection *fs = NULL; - gchar *filename; + gchar *filename, *temp = NULL; g_return_if_fail (GTK_IS_CLIST (widget)); fs = user_data; g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); - - filename = gtk_clist_get_row_data (GTK_CLIST (fs->file_list), row); - if (filename) - gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); -} - -static void -gtk_file_selection_file_button_double (GtkWidget *widget, - gint row, - gint column, - gint button, - gpointer user_data) -{ - GtkFileSelection *fs = NULL; - gchar *filename; - - g_return_if_fail (GTK_IS_CLIST (widget)); - - fs = user_data; - g_return_if_fail (fs != NULL); - g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + gtk_clist_get_text (GTK_CLIST (fs->file_list), row, 0, &temp); + filename = g_strdup (temp); + +#ifdef G_WITH_CYGWIN + /* Check to see if the selection was a drive selector */ + if (isalpha(filename[0]) && (filename[1] == ':')) { + /* It is... map it to a CYGWIN32 drive */ + char temp_filename[10]; + + sprintf(temp_filename, "//%c/", tolower(filename[0])); + g_free(filename); + filename = g_strdup(temp_filename); + } +#endif /* G_WITH_CYGWIN */ - filename = gtk_clist_get_row_data (GTK_CLIST (fs->file_list), row); - if (filename) - gtk_button_clicked (GTK_BUTTON (fs->ok_button)); + { + if (bevent) + switch (bevent->type) + { + case GDK_2BUTTON_PRESS: + gtk_button_clicked (GTK_BUTTON (fs->ok_button)); + break; + + default: + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + + g_free (filename); + } } static void gtk_file_selection_dir_button (GtkWidget *widget, gint row, gint column, - gint button, + GdkEventButton *bevent, gpointer user_data) { GtkFileSelection *fs = NULL; - gchar *filename; - + gchar *filename, *temp = NULL; + g_return_if_fail (GTK_IS_CLIST (widget)); fs = GTK_FILE_SELECTION (user_data); g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); - filename = gtk_clist_get_row_data (GTK_CLIST (fs->dir_list), row); - + gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp); + filename = g_strdup (temp); + if (filename) - gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + { + if (bevent) + switch (bevent->type) + { + case GDK_2BUTTON_PRESS: + gtk_file_selection_populate (fs, filename, FALSE); + break; + + default: + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + break; + } + else + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + + g_free (filename); + } } +#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) + static void -gtk_file_selection_dir_button_double (GtkWidget *widget, - gint row, - gint column, - gint button, - gpointer user_data) +win32_gtk_add_drives_to_dir_list(GtkWidget *the_dir_list) { - GtkFileSelection *fs = NULL; - gchar *filename; - - g_return_if_fail (GTK_IS_CLIST (widget)); + gchar *text[2], *textPtr; + gchar buffer[128]; + char volumeNameBuf[128]; + char formatBuffer[128]; + gint row; - fs = GTK_FILE_SELECTION (user_data); - g_return_if_fail (fs != NULL); - g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + text[1] = NULL; - filename = gtk_clist_get_row_data (GTK_CLIST (fs->dir_list), row); - - if (filename) - gtk_file_selection_populate (fs, filename, FALSE); + /* Get the Drives string */ + GetLogicalDriveStrings(sizeof(buffer), buffer); + + /* Add the drives as necessary */ + textPtr = buffer; + while (*textPtr != '\0') { + /* Get the volume information for this drive */ + if ((tolower(textPtr[0]) != 'a') && (tolower(textPtr[0]) != 'b')) + { + /* Ignore floppies (?) */ + DWORD maxComponentLength, flags; + + GetVolumeInformation(textPtr, + volumeNameBuf, sizeof(volumeNameBuf), + NULL, &maxComponentLength, + &flags, NULL, 0); + /* Build the actual displayable string */ + + sprintf(formatBuffer, "%c:\\", toupper(textPtr[0])); +#if 0 /* HB: removed to allow drive change AND directory update with one click */ + if (strlen(volumeNameBuf) > 0) + sprintf(formatBuffer, "%s (%s)", formatBuffer, volumeNameBuf); +#endif + /* Add to the list */ + text[0] = formatBuffer; + row = gtk_clist_append (GTK_CLIST (the_dir_list), text); + } + textPtr += (strlen(textPtr) + 1); + } } +#endif static void gtk_file_selection_populate (GtkFileSelection *fs, @@ -1211,6 +1471,8 @@ gtk_file_selection_populate (GtkFileSelection *fs, gint did_recurse = FALSE; gint possible_count = 0; gint selection_index = -1; + gint file_list_width; + gint dir_list_width; g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); @@ -1234,13 +1496,17 @@ gtk_file_selection_populate (GtkFileSelection *fs, /* Set the dir_list to include ./ and ../ */ text[1] = NULL; - text[0] = "./"; + text[0] = "." G_DIR_SEPARATOR_S; row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); - gtk_clist_set_row_data (GTK_CLIST (fs->dir_list), row, "./"); - text[0] = "../"; + text[0] = ".." G_DIR_SEPARATOR_S; row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); - gtk_clist_set_row_data (GTK_CLIST (fs->dir_list), row, "../"); + + /*reset the max widths of the lists*/ + dir_list_width = gdk_string_width(fs->dir_list->style->font,".." G_DIR_SEPARATOR_S); + gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0,dir_list_width); + file_list_width = 1; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0,file_list_width); while (poss) { @@ -1248,31 +1514,48 @@ gtk_file_selection_populate (GtkFileSelection *fs, { possible_count += 1; - filename = g_strdup (cmpl_this_completion (poss)); + filename = cmpl_this_completion (poss); text[0] = filename; if (cmpl_is_directory (poss)) { - if (strcmp (filename, "./") != 0 && - strcmp (filename, "../") != 0) + if (strcmp (filename, "." G_DIR_SEPARATOR_S) != 0 && + strcmp (filename, ".." G_DIR_SEPARATOR_S) != 0) { + int width = gdk_string_width(fs->dir_list->style->font, + filename); row = gtk_clist_append (GTK_CLIST (fs->dir_list), text); - gtk_clist_set_row_data (GTK_CLIST (fs->dir_list), row, - filename); + if(width > dir_list_width) + { + dir_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->dir_list),0, + width); + } } } else { + int width = gdk_string_width(fs->file_list->style->font, + filename); row = gtk_clist_append (GTK_CLIST (fs->file_list), text); - gtk_clist_set_row_data (GTK_CLIST (fs->file_list), row, - filename); + if(width > file_list_width) + { + file_list_width = width; + gtk_clist_set_column_width(GTK_CLIST(fs->file_list),0, + width); + } } } poss = cmpl_next_completion (cmpl_state); } +#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) + /* For Windows, add drives as potential selections */ + win32_gtk_add_drives_to_dir_list (fs->dir_list); +#endif + gtk_clist_thaw (GTK_CLIST (fs->dir_list)); gtk_clist_thaw (GTK_CLIST (fs->file_list)); @@ -1329,12 +1612,11 @@ gtk_file_selection_populate (GtkFileSelection *fs, if (fs->selection_entry) { - sel_text = g_new (char, strlen (cmpl_reference_position (cmpl_state)) + - sizeof ("Selection: ")); - strcpy (sel_text, "Selection: "); - strcat (sel_text, cmpl_reference_position (cmpl_state)); + sel_text = g_strconcat (_("Selection: "), + cmpl_reference_position (cmpl_state), + NULL); - gtk_label_set (GTK_LABEL (fs->selection_text), sel_text); + gtk_label_set_text (GTK_LABEL (fs->selection_text), sel_text); g_free (sel_text); } @@ -1351,12 +1633,12 @@ gtk_file_selection_abort (GtkFileSelection *fs) { gchar err_buf[256]; - sprintf (err_buf, "Directory unreadable: %s", cmpl_strerror (cmpl_errno)); + sprintf (err_buf, _("Directory unreadable: %s"), cmpl_strerror (cmpl_errno)); /* BEEP gdk_beep(); */ if (fs->selection_entry) - gtk_label_set (GTK_LABEL (fs->selection_text), err_buf); + gtk_label_set_text (GTK_LABEL (fs->selection_text), err_buf); } /**********************************************************************/ @@ -1371,7 +1653,7 @@ cmpl_updated_text (CompletionState* cmpl_state) return cmpl_state->updated_text; } -static gint +static gboolean cmpl_updated_dir (CompletionState* cmpl_state) { return cmpl_state->re_complete; @@ -1392,10 +1674,17 @@ cmpl_last_valid_char (CompletionState* cmpl_state) static gchar* cmpl_completion_fullname (gchar* text, CompletionState* cmpl_state) { - if (text[0] == '/') + static char nothing[2] = ""; + + if (!cmpl_state_okay (cmpl_state)) + { + return nothing; + } + else if (g_path_is_absolute (text)) { strcpy (cmpl_state->updated_text, text); } +#ifdef HAVE_PWD_H else if (text[0] == '~') { CompletionDir* dir; @@ -1414,16 +1703,18 @@ cmpl_completion_fullname (gchar* text, CompletionState* cmpl_state) strcpy (cmpl_state->updated_text, dir->fullname); - slash = strchr (text, '/'); + slash = strchr (text, G_DIR_SEPARATOR); if (slash) strcat (cmpl_state->updated_text, slash); } } +#endif else { strcpy (cmpl_state->updated_text, cmpl_state->reference_dir->fullname); - strcat (cmpl_state->updated_text, "/"); + if (cmpl_state->updated_text[strlen (cmpl_state->updated_text) - 1] != G_DIR_SEPARATOR) + strcat (cmpl_state->updated_text, G_DIR_SEPARATOR_S); strcat (cmpl_state->updated_text, text); } @@ -1438,7 +1729,7 @@ cmpl_this_completion (PossibleCompletion* pc) return pc->text; } -static gint +static gboolean cmpl_is_directory (PossibleCompletion* pc) { return pc->is_directory; @@ -1457,27 +1748,18 @@ cmpl_is_a_completion (PossibleCompletion* pc) static CompletionState* cmpl_init_state (void) { - gchar getcwd_buf[2*MAXPATHLEN]; + gchar *getcwd_buf; CompletionState *new_state; new_state = g_new (CompletionState, 1); - if (!getcwd (getcwd_buf, MAXPATHLEN)) - { - cmpl_errno = errno; - return NULL; - } + getcwd_buf = g_get_current_dir (); + +tryagain: new_state->reference_dir = NULL; new_state->completion_dir = NULL; new_state->active_completion_dir = NULL; - - if ((new_state->user_home_dir = getenv("HOME")) != NULL) - { - /* if this fails, get_pwdb will fill it in. */ - new_state->user_home_dir = g_strdup(new_state->user_home_dir); - } - new_state->directory_storage = NULL; new_state->directory_sent_storage = NULL; new_state->last_valid_char = 0; @@ -1491,8 +1773,13 @@ cmpl_init_state (void) new_state->reference_dir = open_dir (getcwd_buf, new_state); if (!new_state->reference_dir) - return NULL; + { + /* Directories changing from underneath us, grumble */ + strcpy (getcwd_buf, G_DIR_SEPARATOR_S); + goto tryagain; + } + g_free (getcwd_buf); return new_state; } @@ -1550,7 +1837,9 @@ free_dir(CompletionDir* dir) static void free_dir_sent(CompletionDirSent* sent) { - g_free(sent->name_buffer); + gint i; + for (i = 0; i < sent->entry_count; i++) + g_free(sent->entries[i].entry_name); g_free(sent->entries); g_free(sent); } @@ -1597,7 +1886,7 @@ cmpl_completion_matches (gchar* text_to_complete, prune_memory_usage(cmpl_state); - g_assert(text_to_complete); + g_assert (text_to_complete != NULL); cmpl_state->user_completion_index = -1; cmpl_state->last_completion_text = text_to_complete; @@ -1607,28 +1896,29 @@ cmpl_completion_matches (gchar* text_to_complete, cmpl_state->updated_text[0] = 0; cmpl_state->re_complete = FALSE; - first_slash = strchr(text_to_complete, '/'); +#ifdef HAVE_PWD_H + first_slash = strchr (text_to_complete, G_DIR_SEPARATOR); - if(text_to_complete[0] == '~' && !first_slash) + if (text_to_complete[0] == '~' && !first_slash) { /* Text starts with ~ and there is no slash, show all the * home directory completions. */ - poss = attempt_homedir_completion(text_to_complete, cmpl_state); + poss = attempt_homedir_completion (text_to_complete, cmpl_state); update_cmpl(poss, cmpl_state); return poss; } - +#endif cmpl_state->reference_dir = - open_ref_dir(text_to_complete, remaining_text, cmpl_state); + open_ref_dir (text_to_complete, remaining_text, cmpl_state); if(!cmpl_state->reference_dir) return NULL; cmpl_state->completion_dir = - find_completion_dir(*remaining_text, remaining_text, cmpl_state); + find_completion_dir (*remaining_text, remaining_text, cmpl_state); cmpl_state->last_valid_char = *remaining_text - text_to_complete; @@ -1657,10 +1947,14 @@ cmpl_next_completion (CompletionState* cmpl_state) cmpl_state->the_completion.text[0] = 0; +#ifdef HAVE_PWD_H if(cmpl_state->user_completion_index >= 0) poss = attempt_homedir_completion(cmpl_state->last_completion_text, cmpl_state); else poss = attempt_file_completion(cmpl_state); +#else + poss = attempt_file_completion(cmpl_state); +#endif update_cmpl(poss, cmpl_state); @@ -1680,15 +1974,39 @@ open_ref_dir(gchar* text_to_complete, gchar* first_slash; CompletionDir *new_dir; - first_slash = strchr(text_to_complete, '/'); + first_slash = strchr(text_to_complete, G_DIR_SEPARATOR); - if (text_to_complete[0] == '/' || !cmpl_state->reference_dir) +#ifdef G_WITH_CYGWIN + if (text_to_complete[0] == '/' && text_to_complete[1] == '/') { - new_dir = open_dir("/", cmpl_state); + char root_dir[5]; + sprintf(root_dir, "//%c", text_to_complete[2]); - if(new_dir) - *remaining_text = text_to_complete + 1; + new_dir = open_dir(root_dir, cmpl_state); + + if (new_dir) { + *remaining_text = text_to_complete + 4; + } } +#else + if (FALSE) + ; +#endif + else if (g_path_is_absolute (text_to_complete) || !cmpl_state->reference_dir) + { + char *root; + int rootlen; + + rootlen = g_path_skip_root (text_to_complete) - text_to_complete; + root = g_malloc (rootlen + 1); + memcpy (root, text_to_complete, rootlen); + root[rootlen] = '\0'; + new_dir = open_dir (root, cmpl_state); + if (new_dir) + *remaining_text = g_path_skip_root (text_to_complete); + g_free (root); + } +#ifdef HAVE_PWD_H else if (text_to_complete[0] == '~') { new_dir = open_user_dir(text_to_complete, cmpl_state); @@ -1705,6 +2023,7 @@ open_ref_dir(gchar* text_to_complete, return NULL; } } +#endif else { *remaining_text = text_to_complete; @@ -1721,6 +2040,8 @@ open_ref_dir(gchar* text_to_complete, return new_dir; } +#ifdef HAVE_PWD_H + /* open a directory by user name */ static CompletionDir* open_user_dir(gchar* text_to_complete, @@ -1731,7 +2052,7 @@ open_user_dir(gchar* text_to_complete, g_assert(text_to_complete && text_to_complete[0] == '~'); - first_slash = strchr(text_to_complete, '/'); + first_slash = strchr(text_to_complete, G_DIR_SEPARATOR); if (first_slash) cmp_len = first_slash - text_to_complete - 1; @@ -1741,10 +2062,12 @@ open_user_dir(gchar* text_to_complete, if(!cmp_len) { /* ~/ */ - if (!cmpl_state->user_home_dir && - !get_pwdb(cmpl_state)) + gchar *homedir = g_get_home_dir (); + + if (homedir) + return open_dir(homedir, cmpl_state); + else return NULL; - return open_dir(cmpl_state->user_home_dir, cmpl_state); } else { @@ -1765,65 +2088,57 @@ open_user_dir(gchar* text_to_complete, } } +#endif + /* open a directory relative the the current relative directory */ static CompletionDir* open_relative_dir(gchar* dir_name, CompletionDir* dir, CompletionState *cmpl_state) { - gchar path_buf[2*MAXPATHLEN]; + CompletionDir *result; + GString *path; - if(dir->fullname_len + strlen(dir_name) + 2 >= MAXPATHLEN) - { - cmpl_errno = CMPL_ERRNO_TOO_LONG; - return NULL; - } + path = g_string_sized_new (dir->fullname_len + strlen (dir_name) + 10); + g_string_assign (path, dir->fullname); - strcpy(path_buf, dir->fullname); + if(dir->fullname_len > 1 + && path->str[dir->fullname_len - 1] != G_DIR_SEPARATOR) + g_string_append_c (path, G_DIR_SEPARATOR); + g_string_append (path, dir_name); - if(dir->fullname_len > 1) - { - path_buf[dir->fullname_len] = '/'; - strcpy(path_buf + dir->fullname_len + 1, dir_name); - } - else - { - strcpy(path_buf + dir->fullname_len, dir_name); - } + result = open_dir(path->str, cmpl_state); + + g_string_free (path, TRUE); - return open_dir(path_buf, cmpl_state); + return result; } /* after the cache lookup fails, really open a new directory */ static CompletionDirSent* -open_new_dir(gchar* dir_name, struct stat* sbuf) +open_new_dir(gchar* dir_name, struct stat* sbuf, gboolean stat_subdirs) { CompletionDirSent* sent; DIR* directory; gchar *buffer_ptr; struct dirent *dirent_ptr; - gint buffer_size = 0; gint entry_count = 0; gint i; struct stat ent_sbuf; - char path_buf[MAXPATHLEN*2]; - gint path_buf_len; + GString *path; + gchar *xdir, *xname; + int entry_len; sent = g_new(CompletionDirSent, 1); sent->mtime = sbuf->st_mtime; sent->inode = sbuf->st_ino; + sent->device = sbuf->st_dev; - path_buf_len = strlen(dir_name); + path = g_string_sized_new (2*MAXPATHLEN + 10); - if (path_buf_len > MAXPATHLEN) - { - cmpl_errno = CMPL_ERRNO_TOO_LONG; - return NULL; - } - - strcpy(path_buf, dir_name); - - directory = opendir(dir_name); + xdir = g_filename_from_utf8 (dir_name); + directory = opendir(xdir); + g_free (xdir); if(!directory) { @@ -1833,24 +2148,12 @@ open_new_dir(gchar* dir_name, struct stat* sbuf) while((dirent_ptr = readdir(directory)) != NULL) { - int entry_len = strlen(dirent_ptr->d_name); - buffer_size += entry_len + 1; - entry_count += 1; - - if(path_buf_len + entry_len + 2 >= MAXPATHLEN) - { - cmpl_errno = CMPL_ERRNO_TOO_LONG; - closedir(directory); - return NULL; - } + entry_count++; } - sent->name_buffer = g_new(gchar, buffer_size); sent->entries = g_new(CompletionDirEntry, entry_count); sent->entry_count = entry_count; - buffer_ptr = sent->name_buffer; - rewinddir(directory); for(i = 0; i < entry_count; i += 1) @@ -1864,23 +2167,29 @@ open_new_dir(gchar* dir_name, struct stat* sbuf) return NULL; } - strcpy(buffer_ptr, dirent_ptr->d_name); - sent->entries[i].entry_name = buffer_ptr; - buffer_ptr += strlen(dirent_ptr->d_name); - *buffer_ptr = 0; - buffer_ptr += 1; + sent->entries[i].entry_name = g_filename_to_utf8 (dirent_ptr->d_name); - path_buf[path_buf_len] = '/'; - strcpy(path_buf + path_buf_len + 1, dirent_ptr->d_name); + g_string_assign (path, dir_name); + if (path->str[path->len-1] != G_DIR_SEPARATOR) + { + g_string_append_c (path, G_DIR_SEPARATOR); + } + g_string_append (path, dirent_ptr->d_name); - if(stat(path_buf, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) - sent->entries[i].is_dir = 1; + if (stat_subdirs) + { + if(stat(path->str, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) + sent->entries[i].is_dir = TRUE; + else + /* stat may fail, and we don't mind, since it could be a + * dangling symlink. */ + sent->entries[i].is_dir = FALSE; + } else - /* stat may fail, and we don't mind, since it could be a - * dangling symlink. */ - sent->entries[i].is_dir = 0; + sent->entries[i].is_dir = 1; } + g_string_free (path, TRUE); qsort(sent->entries, sent->entry_count, sizeof(CompletionDirEntry), compare_cmpl_dir); closedir(directory); @@ -1888,19 +2197,75 @@ open_new_dir(gchar* dir_name, struct stat* sbuf) return sent; } +#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) + +static gboolean +check_dir(gchar *dir_name, struct stat *result, gboolean *stat_subdirs) +{ + /* A list of directories that we know only contain other directories. + * Trying to stat every file in these directories would be very + * expensive. + */ + + static struct { + gchar *name; + gboolean present; + struct stat statbuf; + } no_stat_dirs[] = { + { "/afs", FALSE, { 0 } }, + { "/net", FALSE, { 0 } } + }; + + static const gint n_no_stat_dirs = sizeof(no_stat_dirs) / sizeof(no_stat_dirs[0]); + static gboolean initialized = FALSE; + + gint i; + + if (!initialized) + { + initialized = TRUE; + for (i = 0; i < n_no_stat_dirs; i++) + { + if (stat (no_stat_dirs[i].name, &no_stat_dirs[i].statbuf) == 0) + no_stat_dirs[i].present = TRUE; + } + } + + if(stat(dir_name, result) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + *stat_subdirs = TRUE; + for (i=0; ist_dev) && + (no_stat_dirs[i].statbuf.st_ino == result->st_ino)) + { + *stat_subdirs = FALSE; + break; + } + } + + return TRUE; +} + +#endif + /* open a directory by absolute pathname */ static CompletionDir* open_dir(gchar* dir_name, CompletionState* cmpl_state) { struct stat sbuf; + gboolean stat_subdirs; CompletionDirSent *sent; GList* cdsl; - if(stat(dir_name, &sbuf) < 0) - { - cmpl_errno = errno; - return NULL; - } +#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) + if (!check_dir (dir_name, &sbuf, &stat_subdirs)) + return NULL; cdsl = cmpl_state->directory_sent_storage; @@ -1909,13 +2274,17 @@ open_dir(gchar* dir_name, CompletionState* cmpl_state) sent = cdsl->data; if(sent->inode == sbuf.st_ino && - sent->mtime == sbuf.st_mtime) + sent->mtime == sbuf.st_mtime && + sent->device == sbuf.st_dev) return attach_dir(sent, dir_name, cmpl_state); cdsl = cdsl->next; } +#else + stat_subdirs = TRUE; +#endif - sent = open_new_dir(dir_name, &sbuf); + sent = open_new_dir(dir_name, &sbuf, stat_subdirs); if (sent) { cmpl_state->directory_sent_storage = @@ -1948,27 +2317,42 @@ static gint correct_dir_fullname(CompletionDir* cmpl_dir) { gint length = strlen(cmpl_dir->fullname); + gchar *first_slash = strchr(cmpl_dir->fullname, G_DIR_SEPARATOR); struct stat sbuf; - if (strcmp(cmpl_dir->fullname + length - 2, "/.") == 0) + /* Does it end with /. (\.) ? */ + if (length >= 2 && + strcmp(cmpl_dir->fullname + length - 2, G_DIR_SEPARATOR_S ".") == 0) { - if (length == 2) + /* Is it just the root directory (on a drive) ? */ + if (cmpl_dir->fullname + length - 2 == first_slash) { - strcpy(cmpl_dir->fullname, "/"); - cmpl_dir->fullname_len = 1; + cmpl_dir->fullname[length - 1] = 0; + cmpl_dir->fullname_len = length - 1; return TRUE; - } else { + } + else + { cmpl_dir->fullname[length - 2] = 0; } } - else if (strcmp(cmpl_dir->fullname + length - 3, "/./") == 0) + + /* Ends with /./ (\.\)? */ + else if (length >= 3 && + strcmp(cmpl_dir->fullname + length - 3, + G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S) == 0) cmpl_dir->fullname[length - 2] = 0; - else if (strcmp(cmpl_dir->fullname + length - 3, "/..") == 0) + + /* Ends with /.. (\..) ? */ + else if (length >= 3 && + strcmp(cmpl_dir->fullname + length - 3, + G_DIR_SEPARATOR_S "..") == 0) { - if(length == 3) + /* Is it just /.. (X:\..)? */ + if(cmpl_dir->fullname + length - 3 == first_slash) { - strcpy(cmpl_dir->fullname, "/"); - cmpl_dir->fullname_len = 1; + cmpl_dir->fullname[length - 2] = 0; + cmpl_dir->fullname_len = length - 2; return TRUE; } @@ -1978,17 +2362,22 @@ correct_dir_fullname(CompletionDir* cmpl_dir) return FALSE; } - cmpl_dir->fullname[length - 2] = 0; + cmpl_dir->fullname[length - 3] = 0; if(!correct_parent(cmpl_dir, &sbuf)) return FALSE; } - else if (strcmp(cmpl_dir->fullname + length - 4, "/../") == 0) + + /* Ends with /../ (\..\)? */ + else if (length >= 4 && + strcmp(cmpl_dir->fullname + length - 4, + G_DIR_SEPARATOR_S ".." G_DIR_SEPARATOR_S) == 0) { - if(length == 4) + /* Is it just /../ (X:\..\)? */ + if(cmpl_dir->fullname + length - 4 == first_slash) { - strcpy(cmpl_dir->fullname, "/"); - cmpl_dir->fullname_len = 1; + cmpl_dir->fullname[length - 3] = 0; + cmpl_dir->fullname_len = length - 3; return TRUE; } @@ -1998,7 +2387,7 @@ correct_dir_fullname(CompletionDir* cmpl_dir) return FALSE; } - cmpl_dir->fullname[length - 3] = 0; + cmpl_dir->fullname[length - 4] = 0; if(!correct_parent(cmpl_dir, &sbuf)) return FALSE; @@ -2014,15 +2403,21 @@ correct_parent(CompletionDir* cmpl_dir, struct stat *sbuf) { struct stat parbuf; gchar *last_slash; + gchar *first_slash; gchar *new_name; gchar c = 0; - last_slash = strrchr(cmpl_dir->fullname, '/'); - + last_slash = strrchr(cmpl_dir->fullname, G_DIR_SEPARATOR); g_assert(last_slash); + first_slash = strchr(cmpl_dir->fullname, G_DIR_SEPARATOR); - if(last_slash != cmpl_dir->fullname) - { /* last_slash[0] = 0; */ } + /* Clever (?) way to check for top-level directory that works also on + * Win32, where there is a drive letter and colon prefixed... + */ + if (last_slash != first_slash) + { + last_slash[0] = 0; + } else { c = last_slash[1]; @@ -2032,17 +2427,20 @@ correct_parent(CompletionDir* cmpl_dir, struct stat *sbuf) if (stat(cmpl_dir->fullname, &parbuf) < 0) { cmpl_errno = errno; + if (!c) + last_slash[0] = G_DIR_SEPARATOR; return FALSE; } +#ifndef G_OS_WIN32 /* No inode numbers on Win32 */ if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev) /* it wasn't a link */ return TRUE; if(c) last_slash[1] = c; - /* else - last_slash[0] = '/'; */ + else + last_slash[0] = G_DIR_SEPARATOR; /* it was a link, have to figure it out the hard way */ @@ -2054,21 +2452,20 @@ correct_parent(CompletionDir* cmpl_dir, struct stat *sbuf) g_free(cmpl_dir->fullname); cmpl_dir->fullname = new_name; +#endif return TRUE; } +#ifndef G_OS_WIN32 + static gchar* find_parent_dir_fullname(gchar* dirname) { - gchar buffer[MAXPATHLEN]; - gchar buffer2[MAXPATHLEN]; + gchar *orig_dir; + gchar *result; - if(!getcwd(buffer, MAXPATHLEN)) - { - cmpl_errno = errno; - return NULL; - } + orig_dir = g_get_current_dir (); if(chdir(dirname) != 0 || chdir("..") != 0) { @@ -2076,27 +2473,26 @@ find_parent_dir_fullname(gchar* dirname) return NULL; } - if(!getcwd(buffer2, MAXPATHLEN)) - { - chdir(buffer); - cmpl_errno = errno; - - return NULL; - } + result = g_get_current_dir (); - if(chdir(buffer) != 0) + if(chdir(orig_dir) != 0) { cmpl_errno = errno; return NULL; } - return g_strdup(buffer2); + g_free (orig_dir); + return result; } +#endif + /**********************************************************************/ /* Completion Operations */ /**********************************************************************/ +#ifdef HAVE_PWD_H + static PossibleCompletion* attempt_homedir_completion(gchar* text_to_complete, CompletionState *cmpl_state) @@ -2128,7 +2524,7 @@ attempt_homedir_completion(gchar* text_to_complete, } cmpl_state->the_completion.is_a_completion = 1; - cmpl_state->the_completion.is_directory = 1; + cmpl_state->the_completion.is_directory = TRUE; append_completion_text("~", cmpl_state); @@ -2136,7 +2532,7 @@ attempt_homedir_completion(gchar* text_to_complete, user_directories[cmpl_state->user_completion_index].login, cmpl_state); - return append_completion_text("/", cmpl_state); + return append_completion_text(G_DIR_SEPARATOR_S, cmpl_state); } if(text_to_complete[1] || @@ -2149,12 +2545,20 @@ attempt_homedir_completion(gchar* text_to_complete, { cmpl_state->user_completion_index += 1; cmpl_state->the_completion.is_a_completion = 1; - cmpl_state->the_completion.is_directory = 1; + cmpl_state->the_completion.is_directory = TRUE; - return append_completion_text("~/", cmpl_state); + return append_completion_text("~" G_DIR_SEPARATOR_S, cmpl_state); } } +#endif + +#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) +#define FOLD(c) (tolower(c)) +#else +#define FOLD(c) (c) +#endif + /* returns the index (>= 0) of the first differing character, * PATTERN_MATCH if the completion matches */ static gint @@ -2162,7 +2566,7 @@ first_diff_index(gchar* pat, gchar* text) { gint diff = 0; - while(*pat && *text && *text == *pat) + while(*pat && *text && FOLD(*text) == FOLD(*pat)) { pat += 1; text += 1; @@ -2211,15 +2615,16 @@ find_completion_dir(gchar* text_to_complete, gchar** remaining_text, CompletionState* cmpl_state) { - gchar* first_slash = strchr(text_to_complete, '/'); + gchar* first_slash = strchr(text_to_complete, G_DIR_SEPARATOR); CompletionDir* dir = cmpl_state->reference_dir; + CompletionDir* next; *remaining_text = text_to_complete; while(first_slash) { gint len = first_slash - *remaining_text; gint found = 0; - gint found_index = -1; + gchar *found_name = NULL; /* Quiet gcc */ gint i; gchar* pat_buf = g_new (gchar, len + 1); @@ -2240,40 +2645,37 @@ find_completion_dir(gchar* text_to_complete, else { found = 1; - found_index = i; + found_name = dir->sent->entries[i].entry_name; } } } - if(found) + if (!found) { - CompletionDir* next = open_relative_dir(dir->sent->entries[found_index].entry_name, - dir, cmpl_state); - - if(!next) - { - g_free (pat_buf); - return NULL; - } - - next->cmpl_parent = dir; - - dir = next; - - if(!correct_dir_fullname(dir)) - { - g_free(pat_buf); - return NULL; - } - - *remaining_text = first_slash + 1; - first_slash = strchr(*remaining_text, '/'); + /* Perhaps we are trying to open an automount directory */ + found_name = pat_buf; } - else + + next = open_relative_dir(found_name, dir, cmpl_state); + + if(!next) { g_free (pat_buf); return NULL; } + + next->cmpl_parent = dir; + + dir = next; + + if(!correct_dir_fullname(dir)) + { + g_free(pat_buf); + return NULL; + } + + *remaining_text = first_slash + 1; + first_slash = strchr(*remaining_text, G_DIR_SEPARATOR); g_free (pat_buf); } @@ -2354,7 +2756,7 @@ attempt_file_completion(CompletionState *cmpl_state) g_assert(dir->cmpl_text); - first_slash = strchr(dir->cmpl_text, '/'); + first_slash = strchr(dir->cmpl_text, G_DIR_SEPARATOR); if(first_slash) { @@ -2370,7 +2772,12 @@ attempt_file_completion(CompletionState *cmpl_state) pat_buf = g_new (gchar, len + 2); strcpy(pat_buf, dir->cmpl_text); - strcpy(pat_buf + len, "*"); + /* Don't append a * if the user entered one herself. + * This way one can complete *.h and don't get matches + * on any .help files, for instance. + */ + if (strchr(pat_buf, '*') == NULL) + strcpy(pat_buf + len, "*"); } if(first_slash) @@ -2420,7 +2827,7 @@ attempt_file_completion(CompletionState *cmpl_state) append_completion_text(dir->fullname + strlen(cmpl_state->completion_dir->fullname) + 1, cmpl_state); - append_completion_text("/", cmpl_state); + append_completion_text(G_DIR_SEPARATOR_S, cmpl_state); } append_completion_text(dir->sent->entries[dir->cmpl_index].entry_name, cmpl_state); @@ -2431,19 +2838,20 @@ attempt_file_completion(CompletionState *cmpl_state) cmpl_state->the_completion.is_directory = dir->sent->entries[dir->cmpl_index].is_dir; if(dir->sent->entries[dir->cmpl_index].is_dir) - append_completion_text("/", cmpl_state); + append_completion_text(G_DIR_SEPARATOR_S, cmpl_state); g_free (pat_buf); return &cmpl_state->the_completion; } } +#ifdef HAVE_PWD_H static gint get_pwdb(CompletionState* cmpl_state) { struct passwd *pwd_ptr; - gchar* buf_ptr, *home_dir = NULL; + gchar* buf_ptr; gint len = 0, i, count = 0; if(cmpl_state->user_dir_name_buffer) @@ -2458,23 +2866,6 @@ get_pwdb(CompletionState* cmpl_state) count += 1; } - if (!cmpl_state->user_home_dir) - { - /* the loser doesn't have $HOME set */ - setpwent (); - - pwd_ptr = getpwuid(getuid()); - if(!pwd_ptr) - { - cmpl_errno = errno; - goto error; - } - home_dir = pwd_ptr->pw_dir; - - len += strlen(home_dir); - len += 1; - } - setpwent (); cmpl_state->user_dir_name_buffer = g_new(gchar, len); @@ -2483,14 +2874,6 @@ get_pwdb(CompletionState* cmpl_state) buf_ptr = cmpl_state->user_dir_name_buffer; - if (!cmpl_state->user_home_dir) - { - strcpy(buf_ptr, home_dir); - cmpl_state->user_home_dir = buf_ptr; - buf_ptr += strlen(buf_ptr); - buf_ptr += 1; - } - for(i = 0; i < count; i += 1) { pwd_ptr = getpwent(); @@ -2539,11 +2922,18 @@ compare_user_dir(const void* a, const void* b) (((CompletionUserDir*)b))->login); } +#endif + static gint compare_cmpl_dir(const void* a, const void* b) { +#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN) return strcmp((((CompletionDirEntry*)a))->entry_name, (((CompletionDirEntry*)b))->entry_name); +#else + return g_strcasecmp((((CompletionDirEntry*)a))->entry_name, + (((CompletionDirEntry*)b))->entry_name); +#endif } static gint