This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch 8/8] Convert between Windows and Unix paths directly on command line


Index: bash-3.2/bashline.c
===================================================================
--- bash-3.2.orig/bashline.c
+++ bash-3.2/bashline.c
@@ -37,6 +37,10 @@
 #  include <netdb.h>
 #endif
 
+#if __CYGWIN__
+#  include <sys/cygwin.h>
+#endif
+
 #include <stdio.h>
 #include "chartypes.h"
 #include "bashansi.h"
@@ -342,6 +346,248 @@ enable_hostname_completion (on_or_off)
   return (old_value);
 }
 
+#if __CYGWIN__
+
+typedef enum cg_path_kind
+  {
+    CG_PATH_UNKNOWN,
+    CG_PATH_WINDOWS,
+    CG_PATH_UNIX
+  } CG_PATH_KIND;
+
+static void
+xprintwords(WORD_LIST* wl, FILE* out)
+{
+  while (wl)
+    {
+      fprintf(out, "(%d)\"%s\"", wl->word->flags, wl->word->word);
+      wl = wl->next;
+      if (wl) {
+        fprintf(out, ", ");
+      }
+    }
+}
+
+/*
+ * Guess what kind of path the given word is
+ */
+static CG_PATH_KIND
+cg_guess_path_kind (wdesc)
+     WORD_DESC *wdesc;
+{
+  char* w = wdesc->word;
+  char prev, cur, next;
+
+  /* If a filename contains a forward slash, it's probably a unix
+     path */
+  if (strchr(w, '/'))
+    return CG_PATH_UNIX;
+
+  /* Skip leading quote characters */
+  while (w[0] == '\'' || w[0] == '"')
+    ++w;
+  
+  /* UNC absolute path */
+  if (w[0] == '\\' && w[1] == '\\')
+    return CG_PATH_WINDOWS;
+
+  /* Drive-letter-relative path */
+  if (isalpha (w[0]) && w[1] == ':' && w[2] == '\\')
+    return CG_PATH_WINDOWS;
+
+  prev = '\0';
+  cur = w[0];
+  next = cur ? w[1] : '\0';
+
+  /* If a filename contains a Windows-like backslash,
+     it's probably Windows */
+  while (next)
+    {
+      if (cur == '/' && isalnum (prev) && isalnum (next))
+        return CG_PATH_WINDOWS;
+      
+      prev = cur;
+      cur = next;
+      next = *(w++);
+    }
+
+  return CG_PATH_UNKNOWN;
+}
+
+static WORD_LIST*
+cg_dwim_expand_words (wl)
+     WORD_LIST *wl;
+{
+  WORD_LIST *out = NULL;
+  WORD_LIST *it;
+
+  wl = copy_word_list (wl);
+  
+  for (it = wl; it; it = it->next)
+    {
+      char* w = it->word->word;
+      
+      /* If w has suspicious-looking backslahes, single-quote the
+         whole word. */
+      CG_PATH_KIND tkind = cg_guess_path_kind(it->word);
+      
+      if (tkind == CG_PATH_WINDOWS &&
+          w[0] != '\'' && w[0] != '"')
+        {
+          it->word->word = sh_single_quote(w);
+          free(w);
+        }
+    }
+
+  out = expand_words (wl);
+  dispose_words (wl);
+  return out;
+}
+
+static CG_PATH_KIND
+cg_guess_conv_target(wl)
+     WORD_LIST *wl;
+{
+  for (; wl; wl = wl->next)
+    {
+      switch (cg_guess_path_kind(wl->word))
+        {
+        case CG_PATH_WINDOWS:
+          return CG_PATH_UNIX;
+          
+        case CG_PATH_UNIX:
+          return CG_PATH_WINDOWS;
+
+        default:
+          ;
+        }
+    }
+  
+  return CG_PATH_UNKNOWN;
+}
+
+/* Replace text between POS_BEG and POS_END with result of converting
+   all words in DATA to TARGET and joining them with a space.
+
+   Return the length of the replacement string. */
+static int
+cg_do_conv (data, target, pos_beg, pos_end)
+     WORD_LIST *data;
+     CG_PATH_KIND target;
+     int pos_beg;
+     int pos_end;
+{
+  cygwin_conv_path_t conv_dir =
+    (target == CG_PATH_WINDOWS)
+    ? CCP_POSIX_TO_WIN_A
+    : CCP_WIN_A_TO_POSIX;
+
+  rl_begin_undo_group();
+  rl_delete_text(pos_beg, pos_end);
+  rl_point = pos_beg;
+
+  conv_dir |= CCP_RELATIVE;
+  
+  for (; data; data = data->next)
+    {
+      char *s  = cygwin_create_path(conv_dir, data->word->word);
+      char *quoted;
+      
+      if (s)
+        {
+          quoted = sh_single_quote(s);
+          rl_insert_text (quoted);
+          
+          if (data->next)
+            {
+              rl_insert_text (" ");
+            }
+        }
+      
+      free(s);
+      free(quoted);
+    }
+  
+  rl_end_undo_group();
+
+  return rl_point - pos_beg;
+}
+
+/* Let user toggle between unix and windows path representations */
+static int
+cg_dwim (count, ignore)
+    int count, ignore;
+{
+  static CG_PATH_KIND cg_conv_target;
+  static WORD_LIST *lw_data;
+  static int pos_beg;
+  static int pos_end;
+
+  if (lw_data && rl_last_func == &cg_dwim)
+    {
+      /* Reuse information from last run and just toggle the
+         conversion direction */
+      if (cg_conv_target == CG_PATH_UNIX)
+        cg_conv_target = CG_PATH_WINDOWS;
+      else
+        cg_conv_target = CG_PATH_UNIX;
+    }
+  else
+    {
+      int orig_pos;
+      char *ss = NULL;
+      WORD_LIST *lw = NULL;
+      int pos2;
+      
+      /* Slurp up words */
+      while (rl_point > 0 && whitespace (rl_line_buffer[rl_point - 1]))
+        --rl_point;
+      
+      orig_pos = rl_point;
+      
+      do {
+        bash_backward_shellword (1, -1);
+        pos2 = rl_point;
+        
+        while (pos2 < orig_pos && whitespace (rl_line_buffer[pos2]))
+          ++pos2;
+        
+        dispose_words (lw);
+        free (ss);
+        
+        ss = substring (rl_line_buffer, pos2, orig_pos);
+        lw = list_string_with_quotes (ss);
+        
+      } while(list_length (lw) < count && rl_point > 0);
+  
+      if (lw == NULL)
+        {
+          free (ss);
+          return 0;
+        }
+
+      rl_point = pos2;
+
+      pos_beg = rl_point;
+      pos_end = orig_pos;
+  
+      dispose_words (lw_data);
+      lw_data = cg_dwim_expand_words(lw);
+      
+      cg_conv_target = cg_guess_conv_target(lw_data);
+      
+      if (cg_conv_target == CG_PATH_UNKNOWN)
+        cg_conv_target = CG_PATH_WINDOWS; /* Arbitrary default */
+    }
+
+  pos_end =
+      pos_beg +
+      cg_do_conv(lw_data, cg_conv_target, pos_beg, pos_end);
+  return 0;
+}
+
+#endif /* __CYGWIN __ */
+
 /* Called once from parse.y if we are going to use readline. */
 void
 initialize_readline ()
@@ -379,6 +625,10 @@ initialize_readline ()
 #  endif
 #endif
 
+#if __CYGWIN__
+  rl_add_defun ("cygpath-dwim", cg_dwim, -1);
+#endif
+
   /* Backwards compatibility. */
   rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1);
 
@@ -439,6 +689,10 @@ initialize_readline ()
   rl_unbind_key_in_map (CTRL('E'), vi_movement_keymap);
 #endif
 
+#if __CYGWIN__
+  rl_bind_key_if_unbound_in_map (CTRL('W'), cg_dwim, emacs_ctlx_keymap);
+#endif
+
 #if defined (BRACE_COMPLETION)
   rl_bind_key_if_unbound_in_map ('{', bash_brace_completion, emacs_meta_keymap); /*}*/
 #endif /* BRACE_COMPLETION */
Index: bash-3.2/subst.c
===================================================================
--- bash-3.2.orig/subst.c
+++ bash-3.2/subst.c
@@ -2271,8 +2271,6 @@ strip_trailing_ifs_whitespace (string, s
   return string;
 }
 
-#if 0
-/* UNUSED */
 /* Split STRING into words at whitespace.  Obeys shell-style quoting with
    backslashes, single and double quotes. */
 WORD_LIST *
@@ -2324,7 +2322,6 @@ list_string_with_quotes (string)
     }
   return (REVERSE_LIST (list, WORD_LIST *));
 }
-#endif
 
 /********************************************************/
 /*							*/


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]