From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2203 invoked by alias); 22 Aug 2015 07:45:06 -0000 Mailing-List: contact cygwin-apps-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: cygwin-apps-cvs-owner@sourceware.org Received: (qmail 2184 invoked by uid 10076); 22 Aug 2015 07:45:05 -0000 Date: Sat, 22 Aug 2015 07:45:00 -0000 Message-ID: <20150822074505.2133.qmail@sourceware.org> From: gratz@sourceware.org To: cygwin-apps-cvs@sourceware.org Subject: [run] branch master, updated. 1e1c404112e13d34f16dfaeff7343f1daafc731b X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 10feb81b4461d434e9f13c03e182a9a0a8f41273 X-Git-Newrev: 1e1c404112e13d34f16dfaeff7343f1daafc731b X-SW-Source: 2015-q3/txt/msg00009.txt.bz2 https://sourceware.org/git/gitweb.cgi?p=cygwin-run.git;h=1e1c404112e13d34f16dfaeff7343f1daafc731b commit 1e1c404112e13d34f16dfaeff7343f1daafc731b Author: Achim Gratz Date: Sat Aug 22 09:39:53 2015 +0200 release 1.3.4 https://sourceware.org/git/gitweb.cgi?p=cygwin-run.git;h=4470ca51d0e12d44124b71c8c1cf479d6bf0e663 commit 4470ca51d0e12d44124b71c8c1cf479d6bf0e663 Author: Achim Gratz Date: Thu Aug 13 21:23:45 2015 +0200 When quoting, do not simply skip empty arguments https://sourceware.org/git/gitweb.cgi?p=cygwin-run.git;h=adb8378775705fcc99aa29e5a8b6970349d37656 commit adb8378775705fcc99aa29e5a8b6970349d37656 Author: Achim Gratz Date: Thu Aug 13 21:08:57 2015 +0200 Hoist char* t out of loop and initialize NULL * src/run.c (file_exists_multi): Hoist char* t out of loop and initialize NULL. Remove redundant truncation of fullname. https://sourceware.org/git/gitweb.cgi?p=cygwin-run.git;h=2fb8fd2461111d66d4efbb8bd6b1e022f0006cd5 commit 2fb8fd2461111d66d4efbb8bd6b1e022f0006cd5 Author: Achim Gratz Date: Thu Aug 13 21:04:54 2015 +0200 Replace stricmp with strcasecmp throughout * src/run.c (xemacs_special): Replace stricmp with strcasecmp throughout. * src/util.c (run2_ends_with): Ditto. Whitespace cleanup in ChangeLog. https://sourceware.org/git/gitweb.cgi?p=cygwin-run.git;h=a28455a88187d1c22f97db1627e530c8d082b680 commit a28455a88187d1c22f97db1627e530c8d082b680 Author: Achim Gratz Date: Thu Aug 13 21:01:41 2015 +0200 Implement -wait/--wait and -quote/--quote as valid long options * src/run.c (parse_args): Implement -wait/--wait and -quote/--quote as valid long options, we prefer the double-dash variant. * src/run.1.in: All long options are preferedly using leading double dashes. Document the fact that single slashes work on two of them for backwards compatibility. https://sourceware.org/git/gitweb.cgi?p=cygwin-run.git;h=8d6f51656f17fe0a9b54df0919ac2826b35fa0de commit 8d6f51656f17fe0a9b54df0919ac2826b35fa0de Author: Achim Gratz Date: Sat Sep 6 15:29:15 2014 +0200 add "-quote" option and refactor quoting to use run2_quote_strdup https://sourceware.org/git/gitweb.cgi?p=cygwin-run.git;h=8716ae80067a6bbde2a50da58a42d0f3c22c325e commit 8716ae80067a6bbde2a50da58a42d0f3c22c325e Author: Achim Gratz Date: Sat Sep 6 14:19:48 2014 +0200 refactor options removal during argument parsing https://sourceware.org/git/gitweb.cgi?p=cygwin-run.git;h=79a45ad1c625dae7f32f792169d9412ee9772976 commit 79a45ad1c625dae7f32f792169d9412ee9772976 Author: Achim Gratz Date: Sat Sep 6 13:58:20 2014 +0200 revert indiscriminate argument quoting since some programs don't expect quoted options https://sourceware.org/git/gitweb.cgi?p=cygwin-run.git;h=9dcabef66716f47b8853596144a805e352de5886 commit 9dcabef66716f47b8853596144a805e352de5886 Author: Achim Gratz Date: Mon Jun 9 20:02:12 2014 +0200 quote args and account for NULL argv list terminator, correct some occurences of error to errorMsg Diff: --- ChangeLog | 73 +++++++++++++++++++++++++--- configure.ac | 10 ++-- src/run.1.in | 26 ++++++++-- src/run.c | 153 ++++++++++++++++++++------------------------------------- src/util.c | 37 +++++++++++++- src/util.h | 1 + 6 files changed, 184 insertions(+), 116 deletions(-) diff --git a/ChangeLog b/ChangeLog index a6f55ca..5d69344 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,62 @@ +2015-08-22 Achim Gratz + + * configure.ac: Bump version number. Add strcasecmp to + AC_CHECK_FUNCS. + +2015-08-13 Achim Gratz + + * src/util.c (run2_quote_strdup): When quoting, do not simply skip + empty arguments but return '""'. + +2015-08-13 Achim Gratz + + * src/run.c (file_exists_multi): Hoist char* t out of loop and + initialize NULL. Remove redundant truncation of fullname. + +2015-08-13 Achim Gratz + + * src/run.c (xemacs_special): Replace stricmp with strcasecmp throughout. + * src/util.c (run2_ends_with): Ditto. + +2015-08-13 Achim Gratz + + * src/run.c (parse_args): Implement -wait/--wait and + -quote/--quote as valid long options, we prefer the double-dash + variant. + * src/run.1.in: All long options are preferedly using leading + double dashes. Document the fact that single slashes work on two + of them for backwards compatibility. + +2014-09-06 Achim Gratz + + * configure.ac: Bump version number. Correct some type, header + and function checks. + * src/run.c: Add "-quote" option. Use run2_quote_strdup function + to (maybe) quote the input string. + * src/util.c: New function run2_quote_strdup. If the quote + argument is false, then just copy the input string via + run2_strdup. Otherwise, check if the input string needs quoting. + If yes, then surround the string with double quotes and quote all + embedded double quotes and backslahses with a backslash. + * src/util.h: New function run2_quote_strdup. + +2014-09-06 Achim Gratz + + * src/run.c: Revert indiscriminate argument quoting. This also + quotes options and apparently some programs process options before + quote removal. + +2014-06-09 Achim Gratz + + * configure.ac: Bump version number. + * src/run.c: Correct some calls to error, obviously these were + meant to call errorMsg. + +2013-11-30 Max Polk + + * src/run.c: account for NULL argv list terminator. Surround + arguments with double quotes in case of space in original arg. + 2013-07-24 Charles Wilson Release 1.3.0. Massive refactoring. @@ -51,7 +110,7 @@ Support cygwin64, mingw64 * configure.ac: Detect cygwin64 and mingw64. Detect - signature of _spawnv() and spawnv(). Update to + signature of _spawnv() and spawnv(). Update to recent autotools. * src/Makefile.am: Use correct entrypoint for 64bit platforms. @@ -210,7 +269,7 @@ * build-aux/.cvsignore: New. * m4/.cvsignore: New. -2006-05-22 Charles Wilson +2006-05-22 Charles Wilson Release 1.1.10 @@ -317,7 +376,7 @@ release are still present, because they were added right back in run-1.1.5... - Finally, ALL of these changes, from this point down to + Finally, ALL of these changes, from this point down to the release of version 1.1.4 below, are one single checkin in the repository, because we no longer have access to the development repository of the time. @@ -342,7 +401,7 @@ 2004-10-06 Alexander Gottwald * run.c: Added ability to expand PATH variable with - -p parameter + -p parameter 2004-03-11 @@ -379,7 +438,7 @@ Version 1.1.2 - 5-Dec-98 (NOT RELEASED) are called on paths/pathlists that are already in posix format they return garbage in B19. So don't call them when you don't have to. - - CYGWIN: added #defines to enable building under both B19 and + - CYGWIN: added #defines to enable building under both B19 and B20 without modifying the source code. UNTESTED under B20. Version 1.1.1 - 30-Nov-98 (NOT RELEASED) @@ -392,12 +451,12 @@ Version 1.1.0 - 18-Nov-98 (NOT RELEASED) -------------------------- - added ability to search PATH for the target - added ability to specify explicit path information for - the target, which removed requirement that run.exe and + the target, which removed requirement that run.exe and the target be in the same directory - added "simple" mode of operation, where run.exe is renamed to runXXXXXX.exe, to run target XXXXXX - SHOWSTOPPER: cygwin version gets confused if '\\' character - appears in the argument list + appears in the argument list Version 1.0.0 - 29-Sept-98 -------------------------- diff --git a/configure.ac b/configure.ac index 15e0cb7..96cb8d1 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. dnl Auto* initialization AC_PREREQ([2.69]) -AC_INIT([run], [1.3.0], [cygwin@cygwin.com]) +AC_INIT([run], [1.3.4], [cygwin@cygwin.com]) AC_CONFIG_SRCDIR(src/run.c) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) @@ -87,19 +87,21 @@ AM_PROG_AR AC_PROG_INSTALL # checks for header files -AC_CHECK_HEADERS([locale.h malloc.h stdlib.h math.h string.h assert.h pwd.h]) +AC_CHECK_HEADERS([float.h locale.h malloc.h stdlib.h string.h assert.h pwd.h unistd.h]) AC_CHECK_HEADERS([getopt.h sys/cygwin.h windows.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T # Checks for library functions. +AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_FUNC_MALLOC +AC_FUNC_REALLOC AC_FUNC_STRTOD AC_FUNC_VPRINTF -AC_CHECK_FUNC([setenv]) -AC_CHECK_FUNCS([clock_gettime floor setlocale strdup setenv]) +AC_CHECK_FUNCS([getcwd memset putenv setenv setlocale strcasecmp strchr strcspn strdup strerror strrchr strtol]) AC_CHECK_FUNC([getopt_long], [], [replace_getopt=yes]) AM_CONDITIONAL([REPLACE_GETOPT], [test "$replace_getopt" = yes]) if test "$replace_getopt" = yes; then diff --git a/src/run.1.in b/src/run.1.in index ebe9c3b..28b4c7d 100644 --- a/src/run.1.in +++ b/src/run.1.in @@ -1,13 +1,13 @@ -.TH RUN 1 November\ 2005 Version\ @VERSION@ run\ @VERSION@ +.TH RUN 1 September\ 2014 Version\ @VERSION@ run\ @VERSION@ .SH NAME run - start programs with hidden console window .SH SYNOPSIS .B run -[ -p path ] command [ -wait ] arguments +[ -p path ] command [ --wait ] [ --quote ] arguments .B runcommand -[ -p path ] [ -wait ] arguments +[ -p path ] [ --wait ] [ --quote ] arguments .SH DESCRIPTION Windows programs are either GUI programs or console programs. When started @@ -26,17 +26,35 @@ you can add to the PATH environment variable. Issuing -.B -wait +.B --wait as first program argument will make .I run wait for program completition, otherwise it returns immediately. +The +.B --quote +option enables automatic quoting of arguments with embedded +whitespace, double quotes or backslashes for consumption by the +standard Microsoft startup code or compatible implementations. If you +do not use this option, +.I run +assumes that the arguments are already correctly quoted for the +consumer and simply concatenates them separated by single spaces. + The second variant is for creating wrappers. If the executable is named .B runcommand (eg runemacs), .I run will try to start the program (eg emacs). +.SH NOTES + +For backwards compatibility, the long options +.B -wait +and +.B -quote +can be issued with a single leading dash. + .SH EXAMPLES run -p /usr/X11R6/bin xterm diff --git a/src/run.c b/src/run.c index ca3a75c..0064844 100644 --- a/src/run.c +++ b/src/run.c @@ -84,6 +84,7 @@ int opt_loglevel = RUN2_DEFAULT_LOG_SILENT_LEVEL; int opt_loglevel = RUN2_DEFAULT_LOG_LEVEL; #endif int opt_wait = 0; +int opt_quote = 0; int argv_is_malloc = 0; static void @@ -93,6 +94,7 @@ dumpOpts(void) debugMsg(1, "opt_nogui : %d", opt_nogui); debugMsg(1, "opt_notty : %d", opt_notty); debugMsg(1, "opt_wait : %d", opt_wait); + debugMsg(1, "opt_quote : %d", opt_quote); } char buffer[1024]; @@ -150,11 +152,13 @@ WinMain (HINSTANCE hSelf, HINSTANCE hPrev, LPSTR cmdline, int nShow) return 1; } - /* protect embedded spaces in bufArg0 */ - strcpy(fullCmdLine, "\""); - strcat(fullCmdLine, bufArg0); - strcat(fullCmdLine, "\" "); - strcat(fullCmdLine, cmdline); + { + /* quote special chars in bufArg0 */ + char * quoteArg0 = run2_quote_strdup (bufArg0, 1); + strcat(fullCmdLine, quoteArg0); + strcat(fullCmdLine, cmdline); + free (quoteArg0); + } free (bufArg0); debugMsg(1, "new cmdline = %s", fullCmdLine); @@ -252,7 +256,8 @@ realMain(int argc, char* argv[]) newargv = run2_dupargv (argv); /* discard newargv[0] and shift up */ free (newargv[0]); - for (newargc = 1; newargc < argc; newargc++) + /* Account for NULL array terminator */ + for (newargc = 1; newargc <= argc; newargc++) newargv[newargc-1] = newargv[newargc]; newargc = argc - 1; @@ -391,13 +396,13 @@ xemacs_special(char* exec) char tmp[MAX_PATH + FILENAME_MAX + 100]; strcpy(exec2,exec); /* this depends on short-circuit evaluation */ - if ( ((p = strrchr(exec2,'\\')) && stricmp(p,"\\xemacs") == 0) || - ((p = strrchr(exec2,'/')) && stricmp(p,"/xemacs") == 0) || - ((p = strrchr(exec2,'\\')) && stricmp(p,"\\xemacs.exe") == 0) || - ((p = strrchr(exec2,'/')) && stricmp(p,"/xemacs.exe") == 0) ) + if ( ((p = strrchr(exec2,'\\')) && strcasecmp(p,"\\xemacs") == 0) || + ((p = strrchr(exec2,'/')) && strcasecmp(p,"/xemacs") == 0) || + ((p = strrchr(exec2,'\\')) && strcasecmp(p,"\\xemacs.exe") == 0) || + ((p = strrchr(exec2,'/')) && strcasecmp(p,"/xemacs.exe") == 0) ) { - if ( ((p2 = strrchr(p, '\\')) && stricmp(p2, "\\bin") == 0) || - ((p2 = strrchr(p, '/')) && stricmp(p2, "/bin") == 0) ) + if ( ((p2 = strrchr(p, '\\')) && strcasecmp(p2, "\\bin") == 0) || + ((p2 = strrchr(p, '/')) && strcasecmp(p2, "/bin") == 0) ) { *p2 = '\0'; #if defined(__CYGWIN__) @@ -413,6 +418,16 @@ xemacs_special(char* exec) } } +static void +remove_args(int *argc, char* argv[], int i) +{ + int j; + /* remove argv[i] from argv array */ + if (argv_is_malloc) free (argv[i]); + for (j = i+1; j < *argc; j++) + argv[i++] = argv[j]; + argv[--*argc] = NULL; +} static int parse_args(int *argc, char* argv[]) { @@ -448,90 +463,40 @@ parse_args(int *argc, char* argv[]) } add_path (next); - /* remove -p and it argument from argv */ - if (argv_is_malloc) - { - free (argv[i]); - free (argv[i+1]); - } - for (j = i; j < *argc-2; j++) - argv[j] = argv[j+2]; - argv[*argc-1] = '\0'; - *argc -= 2; - - /* - * since argv[i] now points to a new argument, - * reset i for the next pass - */ - i--; + /* remove -p and its argument from argv */ + remove_args(argc, argv, i); + remove_args(argc, argv, i--); } - else if (strcmp(argv[i],"-wait") == 0) + else if ((strcmp(argv[i],"--wait") == 0) || + (strcmp(argv[i],"-wait") == 0)) { opt_wait = 1; - /* remove argv[i] from argv array */ - if (argv_is_malloc) free (argv[i]); - for (j = i; j < *argc-1; j++) - argv[j] = argv[j+1]; - argv[*argc-1] = NULL; - *argc -= 1; - - /* - * since argv[i] now points to a new argument, - * reset i for the next pass - */ - i--; + remove_args(argc, argv, i--); + } + else if ((strcmp(argv[i],"--quote") == 0) || + (strcmp(argv[i],"-quote") == 0)) + { + opt_quote = 1; + remove_args(argc, argv, i--); } #if (ENABLE_GUI == 1) else if (strcmp(argv[i],"--run-nogui") == 0) { opt_nogui = 1; - /* remove argv[i] from argv array */ - if (argv_is_malloc) free (argv[i]); - for (j = i; j < *argc-1; j++) - argv[j] = argv[j+1]; - argv[*argc-1] = NULL; - *argc -= 1; - - /* - * since argv[i] now points to a new argument, - * reset i for the next pass - */ - i--; + remove_args(argc, argv, i--); } #endif #if (ENABLE_TTY == 1) else if (strcmp(argv[i],"--run-notty") == 0) { opt_notty = 1; - /* remove argv[i] from argv array */ - if (argv_is_malloc) free (argv[i]); - for (j = i; j < *argc-1; j++) - argv[j] = argv[j+1]; - argv[*argc-1] = NULL; - *argc -= 1; - - /* - * since argv[i] now points to a new argument, - * reset i for the next pass - */ - i--; + remove_args(argc, argv, i--); } #endif else if (strcmp(argv[i],"--run-verbose") == 0) { opt_loglevel = RUN2_DEFAULT_LOG_VERBOSE_LEVEL; - /* remove argv[i] from argv array */ - if (argv_is_malloc) free (argv[i]); - for (j = i; j < *argc-1; j++) - argv[j] = argv[j+1]; - argv[*argc-1] = NULL; - *argc -= 1; - - /* - * since argv[i] now points to a new argument, - * reset i for the next pass - */ - i--; + remove_args(argc, argv, i--); } else if (strncmp(argv[i],"--run-debug=", 12) == 0) { @@ -551,18 +516,7 @@ parse_args(int *argc, char* argv[]) { opt_loglevel = RUN2_LOG_DEBUG; } - /* remove argv[i] from argv array */ - if (argv_is_malloc) free (argv[i]); - for (j = i; j < *argc-1; j++) - argv[j] = argv[j+1]; - argv[*argc-1] = NULL; - *argc -= 1; - - /* - * since argv[i] now points to a new argument, - * reset i for the next pass - */ - i--; + remove_args(argc, argv, i--); } } return 0; @@ -576,15 +530,17 @@ build_cmdline(char* new_cmdline, char* exec, int argc, char* argv[]) char_cnt = strlen(exec); for (i = 1; i < argc; i++) - char_cnt += strlen(argv[i]); + char_cnt += strlen(argv[i]); if (char_cnt > MAX_ARGS*MAX_PATH) /* then we ran out of room */ run2_error(EXIT_FAILURE, 0, "command line too long -\n%s",new_cmdline); strcpy(new_cmdline,exec); for (i = 1; i < argc; i++) { - strcat(new_cmdline," "); - strcat(new_cmdline,argv[i]); + char* quoteArgvi = run2_quote_strdup (argv[i], opt_quote); + strcat(new_cmdline, " "); + strcat(new_cmdline, quoteArgvi); + free (quoteArgvi); } } @@ -870,22 +826,22 @@ add_path_cygwin(const char *str) if (lasterror == ERROR_ENVVAR_NOT_FOUND) { if (!SetEnvironmentVariable("PATH", wstr)) - error("SetEnvironmentVariable failed: 0x%x", GetLastError()); + errorMsg("SetEnvironmentVariable failed: 0x%x", GetLastError()); } - error("GetEnvironmentVariable failed: 0x%x", lasterror); + errorMsg("GetEnvironmentVariable failed: 0x%x", lasterror); } buffer = malloc(envsize + slen + 2); if (buffer == NULL) - error("internal error - out of memory"); + errorMsg("internal error - out of memory"); if (!GetEnvironmentVariable("PATH", buffer, envsize)) - error("GetEnvironmentVariable failed: 0x%x", GetLastError()); + errorMsg("GetEnvironmentVariable failed: 0x%x", GetLastError()); strcat(buffer, ";"); strcat(buffer, wstr); if (!SetEnvironmentVariable("PATH", buffer)) - error("SetEnvironmentVariable failed: 0x%x", GetLastError()); + errorMsg("SetEnvironmentVariable failed: 0x%x", GetLastError()); free(buffer); } @@ -919,10 +875,10 @@ file_exists_multi(char* fullname, const char* path, char tryName[MAX_PATH + FILENAME_MAX]; int i = 0; int retval = FALSE; + char* t = NULL; fullname[0] = '\0'; for (i = 0; i < extcnt; i++) { - char* t; strcpy(tryName,name_noext); strcat(tryName,exts[i]); if ((run2_fileExists(&t, path, tryName) == TRUE) && t && *t) @@ -937,7 +893,6 @@ file_exists_multi(char* fullname, const char* path, free(t); t = NULL; } - fullname[0] = '\0'; } return retval; } diff --git a/src/util.c b/src/util.c index 31249c0..acfc4a5 100755 --- a/src/util.c +++ b/src/util.c @@ -125,7 +125,7 @@ run2_ends_with(const char* s1, const char* s2) len1 = strlen(s1); len2 = strlen(s2); if (len1 - len2 >= 0) - if (stricmp(&(s1[len1-len2]),s2) == 0) + if (strcasecmp(&(s1[len1-len2]),s2) == 0) retval = 1; return retval; } @@ -136,7 +136,7 @@ run2_strip_exe(char* s) size_t slen = strlen(s); if ((slen > 4) && /* long enough to have .exe extension */ /* second part not evaluated (short circuit) if exec_arg too short */ - (stricmp(&(s[slen-4]),".exe") == 0)) + (strcasecmp(&(s[slen-4]),".exe") == 0)) s[slen-4] = '\0'; } @@ -523,6 +523,39 @@ run2_strdup (const char *s) return d; } +char* +run2_quote_strdup (const char *s, int quote) +{ + size_t len = strlen (s); + if (len == 0) + return "\"\""; + if (quote && (len > strcspn (s, " \t\v\"\\"))) + { + size_t i, j = 0; + char * d = (char *) run2_malloc (2*len + 3); + d[j++] = '"'; + for (i=0; i