--- bashline.c 2017-01-23 13:28:06.955247200 -0600 +++ bashline.c 2017-01-23 13:55:07.992877600 -0600 @@ -76,6 +76,16 @@ # include "pcomplete.h" #endif +#if __CYGWIN__ +# ifdef __x86_64__ +# define IMP(x) __imp_##x +# else +# define IMP(x) _imp__##x +# endif +#else +# define IMP(x) x +#endif + /* These should agree with the defines for emacs_mode and vi_mode in rldefs.h, even though that's not a public readline header file. */ #ifndef EMACS_EDITING_MODE @@ -271,6 +281,11 @@ int no_empty_command_completion; are the only possible matches, even if FIGNORE says to. */ int force_fignore = 1; +#if __CYGWIN__ +/* If set, shorten "foo.exe" to "foo" when they are the same file. */ +int completion_strip_exe; +#endif /* __CYGWIN__ */ + /* Perform spelling correction on directory names during word completion */ int dircomplete_spelling = 0; @@ -498,11 +513,12 @@ initialize_readline () kseq[0] = CTRL('J'); kseq[1] = '\0'; func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == rl_vi_editing_mode) + extern rl_command_func_t *IMP(rl_vi_editing_mode); + if (func == rl_vi_editing_mode || func == IMP(rl_vi_editing_mode)) rl_unbind_key_in_map (CTRL('J'), emacs_meta_keymap); kseq[0] = CTRL('M'); func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == rl_vi_editing_mode) + if (func == rl_vi_editing_mode || func == IMP(rl_vi_editing_mode)) rl_unbind_key_in_map (CTRL('M'), emacs_meta_keymap); #if defined (VI_MODE) rl_unbind_key_in_map (CTRL('E'), vi_movement_keymap); @@ -521,7 +537,8 @@ initialize_readline () kseq[0] = '~'; kseq[1] = '\0'; func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tilde_expand) + extern rl_command_func_t *IMP(rl_tilde_expand); + if (func == 0 || func == rl_tilde_expand || func == IMP(rl_tilde_expand)) rl_bind_keyseq_in_map (kseq, bash_complete_username, emacs_meta_keymap); rl_bind_key_if_unbound_in_map ('~', bash_possible_username_completions, emacs_ctlx_keymap); @@ -544,7 +561,8 @@ initialize_readline () kseq[0] = TAB; kseq[1] = '\0'; func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); - if (func == 0 || func == rl_tab_insert) + extern rl_command_func_t *IMP(rl_tab_insert); + if (func == 0 || func == rl_tab_insert || func == IMP(rl_tab_insert)) rl_bind_key_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); /* Tell the completer that we want a crack first. */ @@ -2194,6 +2212,21 @@ globword: if (match && executable_completion ((searching_path ? val : cval), searching_path)) { +#if __CYGWIN__ + if (completion_strip_exe) + { + size_t val_len = strlen (val); + char *candidate; + if (val_len > 4 && !strcasecmp (&val[val_len - 4], ".exe") + && (candidate = strdup (val))) + { + candidate[val_len - 4] = '\0'; + if (same_file (val, candidate, NULL, NULL)) + temp[strlen (temp) - 4] = '\0'; + free (candidate); + } + } +#endif if (cval != val) free (cval); free (val); @@ -2929,6 +2962,17 @@ test_for_directory (name) int r; fn = bash_tilde_expand (name, 0); +#if __CYGWIN + /* stat("//server") can only be successful as a directory, but can take + seconds to time out on failure. It is much faster to assume that + "//server" is a valid name than it is to wait for a stat, even if it + gives false positives on bad names. */ + if (fn[0] == '/' && fn[1] == '/' && ! strchr (&fn[2], '/')) + { + free (fn); + return 1; + } +#endif r = file_isdir (fn); free (fn); --- builtins/read.def 2017-01-23 13:28:07.017686500 -0600 +++ builtins/read.def 2017-01-23 13:55:07.992877600 -0600 @@ -85,7 +85,6 @@ $END #ifdef __CYGWIN__ # include -# include #endif #include "../bashintl.h" @@ -530,10 +529,6 @@ read_builtin (list) fflush (stderr); } -#if defined (__CYGWIN__) && defined (O_TEXT) - setmode (0, O_TEXT); -#endif - ps2 = 0; for (print_ps2 = eof = retval = 0;;) { @@ -664,6 +659,14 @@ read_builtin (list) if (c == '\0' && delim != '\0') continue; /* skip NUL bytes in input */ +#ifdef __CYGWIN__ + { + extern igncr; + if (igncr && c == '\r' && delim != '\r') + continue; /* skip carriage return */ + } +#endif + if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL)) { saw_escape++; --- builtins/set.def 2016-06-02 19:10:10.000000000 -0500 +++ builtins/set.def 2017-01-23 13:55:07.992877600 -0600 @@ -56,6 +56,13 @@ extern int dont_save_function_defs; #if defined (READLINE) extern int no_line_editing; #endif /* READLINE */ +#ifdef __CYGWIN__ +extern int igncr; +static int set_minus_o_option_maybe (int, const char *, int); +# define INTERACTIVE_ONLY ,1 +#else +# define INTERACTIVE_ONLY +#endif $BUILTIN set $FUNCTION set_builtin @@ -92,6 +99,9 @@ Options: #if defined (HISTORY) history enable command history #endif +#ifdef __CYGWIN__ + igncr on Cygwin, ignore \r in line endings +#endif ignoreeof the shell will not exit upon reading EOF interactive-comments allow comments to appear in interactive commands @@ -192,29 +202,39 @@ const struct { int *variable; setopt_set_func_t *set_func; setopt_get_func_t *get_func; +#ifdef __CYGWIN__ + /* Cygwin users have taken to exporting SHELLOPTS for the cygwin-specific + igncr. As a result, we want to ensure SHELLOPTS parsing does not turn + on interactive options when exported from an interactive shell, but + parse in a non-interactive setting, so as not to break POSIX /bin/sh */ + int interactive_only; +#endif } o_options[] = { { "allexport", 'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, #if defined (BRACE_EXPANSION) { "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, #endif #if defined (READLINE) - { "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode }, + { "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode INTERACTIVE_ONLY }, #endif { "errexit", 'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "errtrace", 'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "functrace", 'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "hashall", 'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, #if defined (BANG_HISTORY) - { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, + { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL INTERACTIVE_ONLY }, #endif /* BANG_HISTORY */ #if defined (HISTORY) - { "history", '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL }, + { "history", '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL INTERACTIVE_ONLY }, +#endif +#ifdef __CYGWIN__ + { "igncr", '\0', &igncr, NULL, (setopt_get_func_t *)NULL }, #endif { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL }, { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "keyword", 'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, #if defined (JOB_CONTROL) - { "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, + { "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL INTERACTIVE_ONLY }, #endif { "noclobber", 'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "noexec", 'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, @@ -233,7 +253,7 @@ const struct { { "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, { "verbose", 'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, #if defined (READLINE) - { "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode }, + { "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode INTERACTIVE_ONLY }, #endif { "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL }, @@ -455,6 +475,15 @@ int set_minus_o_option (on_or_off, option_name) int on_or_off; char *option_name; +#ifdef __CYGWIN__ +{ + /* See Cygwin comments above. */ + return set_minus_o_option_maybe (on_or_off, option_name, 0); +} +static int +set_minus_o_option_maybe (int on_or_off, const char *option_name, + int avoid_interactive) +#endif /* __CYGWIN__ */ { register int i; @@ -462,6 +491,10 @@ set_minus_o_option (on_or_off, option_na { if (STREQ (option_name, o_options[i].name)) { +#ifdef __CYGWIN__ + if (o_options[i].interactive_only && avoid_interactive) + return EXECUTION_SUCCESS; +#endif if (o_options[i].letter == 0) { previous_option_value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name); @@ -588,7 +621,11 @@ parse_shellopts (value) vptr = 0; while (vname = extract_colon_unit (value, &vptr)) { +#ifdef __CYGWIN__ + set_minus_o_option_maybe (FLAG_ON, vname, !interactive_shell); +#else set_minus_o_option (FLAG_ON, vname); +#endif free (vname); } } --- builtins/shopt.def 2016-05-06 14:00:02.000000000 -0500 +++ builtins/shopt.def 2017-01-23 13:55:07.992877600 -0600 @@ -92,6 +92,10 @@ extern int glob_asciirange; extern int lastpipe_opt; extern int inherit_errexit; +#ifdef __CYGWIN__ +extern int completion_strip_exe; +#endif + #if defined (EXTENDED_GLOB) extern int extended_glob; #endif @@ -169,6 +173,9 @@ static struct { { "compat41", &shopt_compat41, set_compatibility_level }, { "compat42", &shopt_compat42, set_compatibility_level }, { "compat43", &shopt_compat43, set_compatibility_level }, +#ifdef __CYGWIN__ + { "completion_strip_exe", &completion_strip_exe, NULL }, +#endif #if defined (READLINE) { "complete_fullquote", &complete_fullquote, (shopt_set_func_t *)NULL}, { "direxpand", &dircomplete_expand, shopt_set_complete_direxpand }, --- config-top.h 2016-05-19 13:34:02.000000000 -0500 +++ config-top.h 2017-01-23 13:55:07.992877600 -0600 @@ -87,10 +87,10 @@ #define DEFAULT_BASHRC "~/.bashrc" /* System-wide .bashrc file for interactive shells. */ -/* #define SYS_BASHRC "/etc/bash.bashrc" */ +#define SYS_BASHRC "/etc/bash.bashrc" /* System-wide .bash_logout for login shells. */ -/* #define SYS_BASH_LOGOUT "/etc/bash.bash_logout" */ +#define SYS_BASH_LOGOUT "/etc/bash.bash_logout" /* Define this to make non-interactive shells begun with argv[0][0] == '-' run the startup files when not in posix mode. */ @@ -100,7 +100,7 @@ sshd and source the .bashrc if so (like the rshd behavior). This checks for the presence of SSH_CLIENT or SSH2_CLIENT in the initial environment, which can be fooled under certain not-uncommon circumstances. */ -/* #define SSH_SOURCE_BASHRC */ +#define SSH_SOURCE_BASHRC /* Define if you want the case-capitalizing operators (~[~]) and the `capcase' variable attribute (declare -c). */ --- doc/Makefile.in 2015-12-06 18:55:56.000000000 -0600 +++ doc/Makefile.in 2017-01-23 13:55:07.992877600 -0600 @@ -189,7 +189,7 @@ bashref.html: $(BASHREF_FILES) $(HSUSER) $(MAKEINFO) --html --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi bash.info: bashref.info - ${SHELL} ${INFOPOST} < $(srcdir)/bashref.info > $@ ; \ + ${SHELL} ${INFOPOST} < bashref.info > $@ ; \ bash.txt: bash.1 bash.ps: bash.1 @@ -252,9 +252,9 @@ install: info installdirs -$(INSTALL_DATA) $(srcdir)/bashbug.1 $(DESTDIR)$(man1dir)/bashbug${man1ext} -$(INSTALL_DATA) $(OTHER_DOCS) $(DESTDIR)$(docdir) # uncomment the next lines to install the builtins man page -# sed 's:bash\.1:man1/&:' $(srcdir)/builtins.1 > $${TMPDIR:-/var/tmp}/builtins.1 -# -$(INSTALL_DATA) $${TMPDIR:-/var/tmp}/builtins.1 $(DESTDIR)$(man1dir)/bash_builtins${man1ext} -# -$(RM) $${TMPDIR:-/var/tmp}/builtins.1 + sed 's:bash\.1:man1/&:' $(srcdir)/builtins.1 > $${TMPDIR:-/var/tmp}/builtins.1 + -$(INSTALL_DATA) $${TMPDIR:-/var/tmp}/builtins.1 $(DESTDIR)$(man1dir)/bash_builtins${man1ext} + -$(RM) $${TMPDIR:-/var/tmp}/builtins.1 -if test -f bash.info; then d=.; else d=$(srcdir); fi; \ $(INSTALL_DATA) $$d/bash.info $(DESTDIR)$(infodir)/bash.info # run install-info if it is present to update the info directory --- doc/bash.1 2016-08-26 08:45:17.000000000 -0500 +++ doc/bash.1 2017-01-23 13:55:08.008447700 -0600 @@ -9607,6 +9607,10 @@ filenames. This variable is set by default, which is the default bash behavior in versions through 4.2. .TP 8 +.B completion_strip_exe +If set, whenever bash sees \fIfoo.exe\fP during completion, it checks if +\fIfoo\fP is the same file and strips the suffix. +.TP 8 .B direxpand If set, .B bash --- doc/bashref.texi 2016-09-07 16:13:36.000000000 -0500 +++ doc/bashref.texi 2017-01-23 13:55:08.008447700 -0600 @@ -5123,6 +5123,10 @@ filenames. This variable is set by default, which is the default Bash behavior in versions through 4.2. +@item completion_strip_exe +If set, whenever bash sees @file{foo.exe} during completion, it checks if +@file{foo} is the same file and strips the suffix. + @item direxpand If set, Bash replaces directory names with the results of word expansion when performing --- doc/builtins.1 2012-02-21 13:32:05.000000000 -0600 +++ doc/builtins.1 2017-01-23 13:55:08.008447700 -0600 @@ -19,6 +19,6 @@ shift, shopt, source, suspend, test, tim ulimit, umask, unalias, unset, wait \- bash built-in commands, see \fBbash\fR(1) .SH BASH BUILTIN COMMANDS .nr zZ 1 -.so bash.1 +.so man1/bash.1 .SH SEE ALSO bash(1), sh(1) --- general.c 2016-08-11 10:16:56.000000000 -0500 +++ general.c 2017-01-23 13:55:08.008447700 -0600 @@ -48,6 +48,10 @@ #include +#ifdef __CYGWIN__ +# include +#endif + #if !defined (errno) extern int errno; #endif /* !errno */ @@ -718,7 +722,8 @@ make_absolute (string, dot_path) { char pathbuf[PATH_MAX + 1]; - cygwin_conv_to_full_posix_path (string, pathbuf); + cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, string, pathbuf, + sizeof pathbuf); result = savestring (pathbuf); } #else --- input.c 2015-09-24 18:49:23.000000000 -0500 +++ input.c 2017-01-23 13:55:08.008447700 -0600 @@ -44,6 +44,10 @@ #include "quit.h" #include "trap.h" +#ifdef __CYGWIN__ +int igncr; +#endif + #if !defined (errno) extern int errno; #endif /* !errno */ @@ -561,6 +565,19 @@ buffered_getchar () { CHECK_TERMSIG; +#ifdef __CYGWIN__ + /* shopt igncr discards carriage returns from the input stream. + If cr is the only character left in the buffer, recurse to pick + up the next byte; otherwise flatten the buffer. */ + if (igncr) + { + int ch; + while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) + == '\r') + ; + return ch; + } +#endif #if !defined (DJGPP) return (bufstream_getc (buffers[bash_input.location.buffered_fd])); #else --- lib/sh/pathphys.c 2013-05-28 14:33:58.000000000 -0500 +++ lib/sh/pathphys.c 2017-01-23 13:55:08.008447700 -0600 @@ -35,6 +35,7 @@ #include #include #include +#include #include "shell.h" @@ -76,6 +77,9 @@ sh_physpath (path, flags) char *path; int flags; { +#ifdef __CYGWIN__ + return realpath (path, NULL); +#endif char tbuf[PATH_MAX+1], linkbuf[PATH_MAX+1]; char *result, *p, *q, *qsave, *qbase, *workpath; int double_slash_path, linklen, nlink; @@ -214,11 +218,7 @@ error: { q = result; /* Duplicating some code here... */ -#if defined (__CYGWIN__) - qbase = (ISALPHA((unsigned char)workpath[0]) && workpath[1] == ':') ? workpath + 3 : workpath + 1; -#else qbase = workpath + 1; -#endif double_slash_path = DOUBLE_SLASH (workpath); qbase += double_slash_path; --- lib/sh/tmpfile.c 2016-08-11 10:05:58.000000000 -0500 +++ lib/sh/tmpfile.c 2017-01-23 13:55:08.008447700 -0600 @@ -101,7 +101,7 @@ get_tmpdir (flags) if (tdir && (file_iswdir (tdir) == 0 || strlen (tdir) > PATH_MAX)) tdir = 0; - if (tdir == 0) + if (tdir == 0 || !file_iswdir (tdir)) tdir = get_sys_tmpdir (); #if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX) --- mksyntax.c 2012-07-29 18:48:38.000000000 -0500 +++ mksyntax.c 2017-01-23 13:55:08.008447700 -0600 @@ -29,13 +29,13 @@ #ifdef HAVE_UNISTD_H # include +#else +extern int optind; +extern char *optarg; #endif #include "syntax.h" -extern int optind; -extern char *optarg; - #ifndef errno extern int errno; #endif --- parse.y 2016-09-11 10:31:46.000000000 -0500 +++ parse.y 2017-01-23 13:55:08.008447700 -0600 @@ -1539,14 +1539,20 @@ yy_string_get () string = bash_input.location.string; /* If the string doesn't exist, or is empty, EOF found. */ - if (string && *string) + while (string && *string) { c = *string++; bash_input.location.string = string; +#ifdef __CYGWIN__ + { + extern int igncr; + if (igncr && c == '\r') + continue; + } +#endif return (c); } - else - return (EOF); + return (EOF); } static int --- subst.c 2017-01-23 13:28:06.955247200 -0600 +++ subst.c 2017-01-23 13:55:08.008447700 -0600 @@ -43,6 +43,7 @@ #include "posixstat.h" #include "bashintl.h" +#define NEED_SH_SETLINEBUF_DECL #include "shell.h" #include "parser.h" #include "flags.h" @@ -5964,6 +5965,13 @@ read_comsub (fd, quoted, rflag) #endif continue; } +#ifdef __CYGWIN__ + { + extern int igncr; + if (igncr && c == '\r') + continue; + } +#endif /* Add the character to ISTRING, possibly after resizing it. */ RESIZE_MALLOCED_BUFFER (istring, istring_index, 2, istring_size, DEFAULT_ARRAY_SIZE); @@ -6088,6 +6096,28 @@ command_substitute (string, quoted) goto error_exit; } +#ifdef __CYGWIN__ + /* Passing a pipe through std fds can cause hangs when talking to a + non-cygwin child. Move it. */ + if (fildes[0] < 3) + { + int fd = fcntl (fildes[0], F_DUPFD, 3); + close (fildes[0]); + fildes[0] = fd; + } + if (fildes[1] < 3) + { + int fd = fcntl (fildes[1], F_DUPFD, 3); + close (fildes[1]); + fildes[1] = fd; + } + if (fildes[0] < 0 || fildes[1] < 0) + { + sys_error (_("cannot make pipe for command substitution")); + goto error_exit; + } +#endif /* __CYGWIN__ */ + old_pid = last_made_pid; #if defined (JOB_CONTROL) old_pipeline_pgrp = pipeline_pgrp; --- support/bashversion.c 2008-09-09 08:31:53.000000000 -0500 +++ support/bashversion.c 2017-01-23 13:55:08.024037200 -0600 @@ -26,6 +26,9 @@ #if defined (HAVE_UNISTD_H) # include +#else +extern int optind; +extern char *optarg; #endif #include "bashansi.h" @@ -41,9 +44,6 @@ #define LFLAG 0x0020 #define XFLAG 0x0040 -extern int optind; -extern char *optarg; - extern char *dist_version; extern int patch_level; --- support/mkversion.sh 2008-08-13 07:25:57.000000000 -0500 +++ support/mkversion.sh 2017-01-23 13:55:08.024037200 -0600 @@ -29,7 +29,7 @@ source_dir="." while [ $# -gt 0 ]; do case "$1" in -o) shift; OUTFILE=$1; shift ;; - -b) shift; inc_build=yes ;; + -b) shift; ;; # inc_build=yes ;; # hacked out for cygport -s) shift; rel_status=$1; shift ;; -p) shift; patch_level=$1; shift ;; -d) shift; dist_version=$1; shift ;; --- variables.c 2016-06-15 15:05:52.000000000 -0500 +++ variables.c 2017-01-23 13:55:08.024037200 -0600 @@ -5239,6 +5239,7 @@ sv_winsize (name) /* Update the value of HOME in the export environment so tilde expansion will work on cygwin. */ #if defined (__CYGWIN__) +void sv_home (name) char *name; {