[PATCH]: Add support for changing drives in Cygwin
Pavel Tsekov
ptsekov at gmx.net
Thu Sep 16 11:19:17 UTC 2004
Thu, 16 Sep 2004 13:19:17 +0200hu, 16 Sep 2004 13:17:17 +0200ello,
Attached you'll find a patch which adds a change drive dialog for MC
running on Cygwin. Please, review.
Changelog:
* acinclude.m4 (MC_WITH_CHANGE_DRIVE): Define new macro.
* configure.ac: Use `MC_WITH_CHANGE_DRIVE'.
* Makefile.am (SRCS): Include drive.c and drive.h into the list.
* src/drive.c: New file.
* src/drive.h: Ditto.
* src/main.c (LeftMenu): [USE_CHANGE_DRIVE] Add new menu item.
(RightMenu): Ditto.
* src/screen.c (panel_keymap): [USE_CHANGE_DRIVE] Register new
shortcuts for Alt+F1, ALT+F2 and ALT+d.
Thanks!
Pavel Tsekov
diff -Nrup ../mc-nodrv/src/drive.c src/drive.c
--- ../mc-nodrv/src/drive.c 1970-01-01 01:00:00.000000000 +0100
+++ src/drive.c 2004-09-16 12:36:52.222032000 +0200
@@ -0,0 +1,291 @@
+/* Change drive command for the Midnight Commander
+ Copyright (C) 2003, 2004 The Free Software Foundation
+
+ Written by: 2003 Pavel Tsekov <ptsekov at gmx.net>
+
+ Based on a heavily modified version of drive.c from the PC port.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ */
+
+/* The code currently knows how to handle drives on Cygwin only, but it
+ should be pretty straight forward to add support for other platforms,
+ like Interix or UWIN, which emulate Unix on Windows. This can be done
+ by writing a new 'enum_drives' routine for the specific platform. */
+
+#include <config.h>
+#ifdef USE_CHANGE_DRIVE
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef __CYGWIN__
+#include <dirent.h> /* scandir () */
+#include <sys/cygwin.h> /* cygwin_internal () */
+#endif /* __CYGWIN__ */
+
+#include "global.h"
+#include "tty.h"
+#include "util.h"
+#include "win.h"
+#include "color.h"
+#include "dialog.h"
+#include "widget.h"
+#include "dialog.h"
+#include "dir.h"
+#include "panel.h"
+#include "main.h"
+#include "cmd.h"
+#include "wtools.h"
+#include "drive.h"
+
+struct drive_info
+{
+ char di_drive; /* drive letter */
+ char *di_mountdir; /* mount point */
+};
+
+static void
+drive_cmd (WPanel *);
+static int
+enum_drives (struct drive_info **);
+
+/* Drive dialog constants */
+/* Upper Border + 1 line + 1 Uknown + Bottom Border */
+static const int drive_dlg_base_height = 6;
+/* Left Border + Left Padding + Right Padding + Right Border */
+static const int drive_dlg_width_pad = 6;
+static const char drive_dlg_title[] = "Change Drive";
+static const char drive_dlg_help_ctx[] = "[ChDrive]";
+
+/* Drive button constants */
+static const int drive_button_base_y = 3;
+/* The values below are adjusted for BUTTON_NARROW. If for some reason
+ BUTTON_NORMAL is prefered, the value must be set to 5 - for more
+ details refer to widget.c . */
+static const int drive_button_length = 3;
+static const int drive_button_offset = 3;
+
+#ifdef __CYGWIN__
+
+static int
+select_drive_dirs (const struct dirent *d)
+{
+ if (d->d_name[1] == '\0' && isalpha (d->d_name[0]))
+ return 1;
+ return 0;
+}
+
+static int
+cygwin_enum_drives (struct drive_info **drive_list)
+{
+ int i, ret;
+ int num_drives;
+ size_t prefix_len;
+ struct dirent **d_entries;
+ struct drive_info *di;
+ char *mp;
+ char user_prefix[MAXPATHLEN + 1];
+ char system_prefix[MAXPATHLEN + 1];
+
+ num_drives = 0;
+
+ /* Find the mountpoint under which Cygwin exposes the
+ currently available drives. */
+ ret = cygwin_internal (CW_GET_CYGDRIVE_PREFIXES, (char *) &user_prefix,
+ (char *) &system_prefix);
+ if (!ret)
+ return -1;
+
+ /* The directory in 'user_prefix' contains only directory entries.
+ Each entry corresponds to a drive that is currently accessible. */
+ ret = scandir ((const char *) &user_prefix, &d_entries, select_drive_dirs,
+ alphasort);
+ if (ret < 0)
+ return -1;
+
+ num_drives = ret;
+ di = NULL;
+ if (num_drives > 0)
+ di = malloc (num_drives * sizeof (struct drive_info));
+ prefix_len = strlen (user_prefix);
+
+ for (i = 0; i < num_drives && di != NULL; i++) {
+ di[i].di_drive = d_entries[i]->d_name[0];
+ di[i].di_mountdir = mp = malloc (prefix_len + 3);
+
+ if (mp != NULL) {
+ memcpy (mp, user_prefix, prefix_len);
+ mp += prefix_len;
+ *mp++ = '/';
+ *mp++ = di[i].di_drive;
+ *mp = '\0';
+ } else {
+ /* error cleanup */
+ int j;
+ for (j = 0; j < i; j++)
+ free (di[j].di_mountdir);
+ free (di);
+ di = NULL; /* force exit */
+ }
+ }
+
+ for (i = 0; i < num_drives; i++)
+ free (d_entries[i]);
+ free (d_entries);
+
+ if (di)
+ *drive_list = di;
+
+ return (num_drives > 0 && di == NULL) ? -1 : num_drives;
+}
+
+#endif /* __CYGWIN__ */
+
+static int
+enum_drives (struct drive_info **drive_list)
+{
+#ifdef __CYGWIN__
+ return cygwin_enum_drives (drive_list);
+#else
+ return 0;
+#endif
+}
+
+static void
+drive_cmd (WPanel *panel)
+{
+ int i, j;
+ int num_drives_per_line, num_avail_drives, max_drives_per_line;
+ int num_buttons_skip;
+ int extra_padding;
+ /* Dialogbox position */
+ int x_pos, y_pos, x_width, y_height;
+ struct drive_info *drive_list, *next_drive;
+ char button_caption[sizeof("A")] = " ";
+ Dlg_head *dlg;
+
+ /* Get drive names and count */
+ if ((num_avail_drives = enum_drives (&drive_list)) == 0)
+ return;
+
+ /* Create Dialog */
+ do_refresh ();
+
+ /* Adjust the dialog position.
+
+ TODO: Move this to a separate function. */
+ extra_padding = 0;
+
+ y_height = drive_dlg_base_height;
+
+ max_drives_per_line = (panel->widget.cols - drive_dlg_width_pad) /
+ drive_button_length;
+ if (num_avail_drives > max_drives_per_line) {
+ num_drives_per_line = max_drives_per_line;
+ /* No need to add one since y_height already contains
+ the space required for one line. */
+ y_height += num_avail_drives / max_drives_per_line;
+ }
+ else {
+ num_drives_per_line = num_avail_drives;
+ }
+
+ /* Make sure that there is enough space to set the title. */
+ if (num_drives_per_line * drive_button_length + 2 /* padding */ <
+ sizeof (drive_dlg_title) - 1 + 2 /* 2 spaces around the title */) {
+ extra_padding = (sizeof (drive_dlg_title) - 1 + 2 - (num_drives_per_line * drive_button_length)) / 2;
+ x_width = drive_dlg_width_pad + sizeof (drive_dlg_title) - 1 + 2;
+ } else {
+ x_width = num_drives_per_line * drive_button_length +
+ drive_dlg_width_pad;
+ }
+ x_pos = panel->widget.x + (panel->widget.cols - x_width) / 2;
+ y_pos = panel->widget.y + (panel->widget.lines - y_height) / 2;
+
+ dlg = create_dlg (y_pos, x_pos, y_height, x_width, dialog_colors,
+ NULL, drive_dlg_help_ctx, drive_dlg_title, DLG_NONE);
+
+ /* Add a button for each drive. Note that buttons are added
+ in reverse order. */
+
+ /* A certain number of buttons that must be skipped on the
+ last line, so that at the end the buttons will look
+ nicely ordered. */
+ num_buttons_skip = num_drives_per_line -
+ num_avail_drives % max_drives_per_line;
+ next_drive = drive_list + (num_avail_drives - 1);
+ for (i = num_avail_drives / max_drives_per_line; i >= 0; i--) {
+ for (j = num_drives_per_line - num_buttons_skip - 1; j >= 0; j--) {
+ next_drive->di_drive = toupper (next_drive->di_drive);
+ button_caption[0] = next_drive->di_drive;
+ add_widget (dlg,
+ button_new (
+ drive_button_base_y + i, /* pos y */
+ j * drive_button_length + drive_button_offset + extra_padding, /* pos x */
+ B_USER + next_drive->di_drive, NARROW_BUTTON, button_caption, NULL));
+ if (next_drive == drive_list)
+ break;
+ next_drive--;
+ }
+ if (num_buttons_skip != 0)
+ num_buttons_skip = 0;
+ }
+
+ run_dlg(dlg);
+
+ /* do action */
+ if (dlg->ret_value != B_CANCEL) {
+ for (i = 0; i < num_avail_drives; i++)
+ if (drive_list[i].di_drive == dlg->ret_value - B_USER)
+ break;
+ if (do_panel_cd (panel, drive_list[i].di_mountdir, cd_exact) == 0) {
+ message (1, "Error", " Cannot change the working directory to %s: %s",
+ drive_list[i].di_mountdir, strerror (errno));
+ }
+ }
+
+ destroy_dlg (dlg);
+ repaint_screen ();
+
+ for (i = 0; i < num_avail_drives; i++)
+ free (drive_list[i].di_mountdir);
+ free (drive_list);
+
+ return;
+}
+
+inline void
+drive_cmd_left (void)
+{
+ drive_cmd (left_panel);
+}
+
+inline void
+drive_cmd_right (void)
+{
+ drive_cmd (right_panel);
+}
+
+inline void
+drive_change (WPanel *panel)
+{
+ drive_cmd (panel);
+}
+
+#endif /* USE_CHANGE_DRIVE */
diff -Nrup ../mc-nodrv/src/drive.h src/drive.h
--- ../mc-nodrv/src/drive.h 1970-01-01 01:00:00.000000000 +0100
+++ src/drive.h 2004-09-16 09:42:52.049801600 +0200
@@ -0,0 +1,25 @@
+/* Change drive command for the Midnight Commander
+ Copyright (C) 2003, 2004 The Free Software Foundation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef __DRIVE_H
+#define __DRIVE_H
+
+inline void drive_cmd_left (void);
+inline void drive_cmd_right (void);
+inline void drive_change (WPanel *panel);
+
+#endif /* __DRIVE_H */
Index: acinclude.m4
===================================================================
RCS file: /cvsroot/mc/mc/acinclude.m4,v
retrieving revision 1.61
diff -u -p -r1.61 acinclude.m4
--- acinclude.m4 28 Nov 2003 06:18:32 -0000 1.61
+++ acinclude.m4 16 Sep 2004 12:43:48 -0000
@@ -898,3 +898,30 @@ if test "$mc_cv_asm_labels" != yes; then
[Define if functions cannot be renamed by asm labels])
fi
])
+
+AC_DEFUN([MC_WITH_CHANGE_DRIVE], [
+ use_change_drive=yes
+
+ AC_ARG_WITH(change-drive,
+ [ --with-change-drive Compile with support for changing drives [[yes if the OS supports drives]]],
+ use_change_drive=$withval
+ )
+
+ if test "$use_change_drive" = yes ; then
+ AC_MSG_CHECKING([whether the OS supports drives])
+ case "$host_os" in
+ *cygwin* ) ;;
+ * ) use_change_drive=no ;;
+ esac
+ AC_MSG_RESULT([$use_change_drive])
+
+ if test "$use_change_drive" = yes ; then
+ AC_DEFINE(USE_CHANGE_DRIVE, 1, [Define if the OS supports drives])
+ AC_MSG_NOTICE([using change drive support])
+ else
+ AC_MSG_NOTICE([not using change drive support])
+ fi
+ else
+ AC_MSG_NOTICE([not using change drive support])
+ fi
+])
Index: configure.ac
===================================================================
RCS file: /cvsroot/mc/mc/configure.ac,v
retrieving revision 1.8
diff -u -p -r1.8 configure.ac
--- configure.ac 3 Sep 2004 22:37:52 -0000 1.8
+++ configure.ac 16 Sep 2004 12:43:48 -0000
@@ -510,6 +510,12 @@ else
fi
+dnl
+dnl Change drive support
+dnl
+MC_WITH_CHANGE_DRIVE
+
+
dnl Check if the OS is supported by the console saver.
cons_saver=""
case $host_os in
Index: src/Makefile.am
===================================================================
RCS file: /cvsroot/mc/mc/src/Makefile.am,v
retrieving revision 1.37
diff -u -p -r1.37 Makefile.am
--- src/Makefile.am 2 Sep 2004 15:03:48 -0000 1.37
+++ src/Makefile.am 16 Sep 2004 12:43:49 -0000
@@ -45,7 +45,7 @@ CHARSET_SRC = charsets.c charsets.h selc
SRCS = achown.c achown.h background.c background.h boxes.c boxes.h \
chmod.c chmod.h chown.c chown.h cmd.c cmd.h color.c color.h \
command.c command.h complete.c complete.h cons.handler.c \
- cons.saver.h dialog.c dialog.h dir.c dir.h \
+ cons.saver.h dialog.c dialog.h dir.c dir.h drive.c drive.h \
eregex.h execute.c execute.h ext.c ext.h file.c filegui.c \
filegui.h file.h filenot.c fileopctx.c fileopctx.h find.c \
find.h findme.c findme.h fs.h \
Index: src/main.c
===================================================================
RCS file: /cvsroot/mc/mc/src/main.c,v
retrieving revision 1.338
diff -u -p -r1.338 main.c
--- src/main.c 29 Aug 2004 23:54:47 -0000 1.338
+++ src/main.c 16 Sep 2004 12:43:51 -0000
@@ -76,6 +76,10 @@
#include "chown.h"
#include "achown.h"
+#ifdef USE_CHANGE_DRIVE
+#include "drive.h"
+#endif /* USE_CHANGE_DRIVE */
+
#ifdef WITH_SMBFS
#include "../vfs/smbfs.h" /* smbfs_set_debug() */
#endif
@@ -812,6 +816,9 @@ static menu_entry LeftMenu[] = {
#endif
#endif
{' ', "", ' ', 0},
+#ifdef USE_CHANGE_DRIVE
+ {' ', N_("Drive... M-F1"), ALT(KEY_F(1)), drive_cmd_left},
+#endif /* USE_CHANGE_DRIVE */
{' ', N_("&Rescan C-r"), 'R', reread_cmd}
};
@@ -836,6 +843,9 @@ static menu_entry RightMenu[] = {
#endif
#endif
{' ', "", ' ', 0},
+#ifdef USE_CHANGE_DRIVE
+ {' ', N_("&Drive... M-F2"), ALT(KEY_F(2)), drive_cmd_right},
+#endif /* USE_CHANGE_DRIVE */
{' ', N_("&Rescan C-r"), 'R', reread_cmd}
};
Index: src/screen.c
===================================================================
RCS file: /cvsroot/mc/mc/src/screen.c,v
retrieving revision 1.194
diff -u -p -r1.194 screen.c
--- src/screen.c 31 Aug 2004 23:34:18 -0000 1.194
+++ src/screen.c 16 Sep 2004 12:43:52 -0000
@@ -48,6 +48,10 @@
#define WANT_WIDGETS
#include "main.h" /* the_menubar */
+#ifdef USE_CHANGE_DRIVE
+#include "drive.h"
+#endif /* USE_CHANGE_DRIVE */
+
#define ELEMENTS(arr) ( sizeof(arr) / sizeof((arr)[0]) )
#define J_LEFT 1
@@ -2085,6 +2089,12 @@ static const panel_key_map panel_keymap
{ ALT('r'), goto_middle_file }, /* M-r like emacs */
{ ALT('j'), goto_bottom_file },
+#ifdef USE_CHANGE_DRIVE
+ { ALT(KEY_F(1)), drive_cmd_left },
+ { ALT(KEY_F(2)), drive_cmd_right },
+ { ALT('d'), drive_change },
+#endif /* USE_CHANGE_DRIVE */
+
/* Emacs-like bindings */
{ XCTRL('v'), next_page }, /* C-v like emacs */
{ ALT('v'), prev_page }, /* M-v like emacs */
More information about the mc-devel
mailing list