[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