Support POSIX shells under MinGW Fixes CLOWNFISH-100.
Project: http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/commit/c5387af3 Tree: http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/tree/c5387af3 Diff: http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/diff/c5387af3 Branch: refs/heads/master Commit: c5387af383d317dcd887f9e07769c589039e099c Parents: 7f2cb31 Author: Nick Wellnhofer <wellnho...@aevum.de> Authored: Wed Jun 1 20:57:27 2016 +0200 Committer: Nick Wellnhofer <wellnho...@aevum.de> Committed: Thu Jun 2 00:04:18 2016 +0200 ---------------------------------------------------------------------- src/Charmonizer/Core/OperatingSystem.c | 126 ++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-charmonizer/blob/c5387af3/src/Charmonizer/Core/OperatingSystem.c ---------------------------------------------------------------------- diff --git a/src/Charmonizer/Core/OperatingSystem.c b/src/Charmonizer/Core/OperatingSystem.c index cd5bfeb..47a66af 100644 --- a/src/Charmonizer/Core/OperatingSystem.c +++ b/src/Charmonizer/Core/OperatingSystem.c @@ -35,7 +35,11 @@ static struct { char dir_sep[2]; char local_command_start[3]; int shell_type; -} chaz_OS = { "", "", "", "", 0 }; + int run_sh_via_cmd_exe; +} chaz_OS = { "", "", "", "", 0, 0 }; + +static int +chaz_OS_run_sh_via_cmd_exe(const char *command); void chaz_OS_init(void) { @@ -58,11 +62,27 @@ chaz_OS_init(void) { if (chaz_Util_verbosity) { printf("Detected cmd.exe shell\n"); } - chaz_OS.shell_type = CHAZ_OS_CMD_EXE; - strcpy(chaz_OS.dir_sep, "\\"); - strcpy(chaz_OS.dev_null, "nul"); - /* Empty string should work, too. */ - strcpy(chaz_OS.local_command_start, ".\\"); + + /* Try to see whether running commands via the `sh` command works. + * Run the `find` command to check whether we're in a somewhat POSIX + * compatible environment. */ + free(output); + chaz_OS.run_sh_via_cmd_exe = 1; + output = chaz_OS_run_and_capture("find . -prune", &output_len); + + if (output_len >= 2 + && output[0] == '.' + && isspace((unsigned char)output[1]) + ) { + if (chaz_Util_verbosity) { + printf("Detected POSIX shell via cmd.exe\n"); + } + chaz_OS.shell_type = CHAZ_OS_POSIX; + } + else { + chaz_OS.shell_type = CHAZ_OS_CMD_EXE; + chaz_OS.run_sh_via_cmd_exe = 0; + } } else if (output_len >= 7 && memcmp(output, "foo^bar", 7) == 0) { /* Escape character is backslash. */ @@ -70,6 +90,15 @@ chaz_OS_init(void) { printf("Detected POSIX shell\n"); } chaz_OS.shell_type = CHAZ_OS_POSIX; + } + + if (chaz_OS.shell_type == CHAZ_OS_CMD_EXE) { + strcpy(chaz_OS.dir_sep, "\\"); + strcpy(chaz_OS.dev_null, "nul"); + /* Empty string should work, too. */ + strcpy(chaz_OS.local_command_start, ".\\"); + } + else if (chaz_OS.shell_type == CHAZ_OS_POSIX) { strcpy(chaz_OS.dir_sep, "/"); strcpy(chaz_OS.dev_null, "/dev/null"); strcpy(chaz_OS.local_command_start, "./"); @@ -177,11 +206,94 @@ chaz_OS_run_redirected(const char *command, const char *path) { else { chaz_Util_die("Don't know the shell type"); } - retval = system(quiet_command); + if (chaz_OS.run_sh_via_cmd_exe) { + retval = chaz_OS_run_sh_via_cmd_exe(quiet_command); + } + else { + retval = system(quiet_command); + } free(quiet_command); return retval; } +static int +chaz_OS_run_sh_via_cmd_exe(const char *command) { + size_t i; + size_t size; + char *sh_command; + char *p; + int retval; + + /* Compute size. */ + + size = sizeof("sh -c \"\""); + + for (i = 0; command[i] != '\0'; i++) { + char c = command[i]; + + switch (c) { + case '"': + case '\\': + size += 2; + break; + + case '%': + case '!': + size += 3; + break; + + default: + size += 1; + break; + } + } + + /* Build sh command. */ + + sh_command = (char*)malloc(size); + p = sh_command; + memcpy(p, "sh -c \"", 7); + p += 7; + + /* Escape special characters. */ + + for (i = 0; command[i] != '\0'; i++) { + char c = command[i]; + + switch (c) { + case '"': + case '\\': + /* Escape double quote and backslash. */ + *p++ = '\\'; + *p++ = c; + break; + + case '%': + case '!': + /* Break out of double quotes for percent sign and + * exclamation mark. This prevents variable expansion. */ + *p++ = '"'; + *p++ = c; + *p++ = '"'; + break; + + default: + *p++ = c; + break; + } + } + + /* Finish and run sh command. */ + + *p++ = '"'; + *p++ = '\0'; + + retval = system(sh_command); + + free(sh_command); + return retval; +} + char* chaz_OS_run_and_capture(const char *command, size_t *output_len) { char *output;