X-Recipient: archive-cygwin AT delorie DOT com X-SWARE-Spam-Status: No, hits=-1.5 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: sourceware.org Message-Id: <20101102205043.339395100@gmail.com> User-Agent: quilt/0.48-1 Date: Tue, 02 Nov 2010 13:49:03 -0700 From: dan DOT colascione AT gmail DOT com To: cygwin AT cygwin DOT com Subject: [patch 8/8] Convert between Windows and Unix paths directly on command line References: <20101102204855 DOT 153395100 AT gmail DOT com> Content-Disposition: inline; filename=cygwin-commands X-IsSubscribed: yes Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com Index: bash-3.2/bashline.c =================================================================== --- bash-3.2.orig/bashline.c +++ bash-3.2/bashline.c @@ -37,6 +37,10 @@ # include #endif +#if __CYGWIN__ +# include +#endif + #include #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