OSDN Git Service

Implement new command line argument globbing strategy.
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Sat, 8 Nov 2014 11:10:32 +0000 (11:10 +0000)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Sat, 8 Nov 2014 11:10:32 +0000 (11:10 +0000)
mingwrt/CRTglob.c
mingwrt/ChangeLog
mingwrt/Makefile.in
mingwrt/crt1.c
mingwrt/include/_mingw.h
mingwrt/init.c [deleted file]
mingwrt/setargv.c [new file with mode: 0644]

index a4f5fe0..b9c54d4 100644 (file)
@@ -1,16 +1,30 @@
 /*
  * CRTglob.c
- * This file has no copyright assigned and is placed in the Public Domain.
- * This file is a part of the mingw-runtime package.
- * No warranty is given; refer to the file DISCLAIMER within the package.
  *
- * Include this object file to set _CRT_glob to a state that will
- * turn on command line globbing by default.  NOTE: _CRT_glob has a default
- * state of on.  Specify CRT_noglob.o to turn off globbing by default.
+ * This file is a part of the mingw-runtime package; it has no copyright
+ * assigned and is placed in the Public Domain. No warranty is given; refer
+ * to the file DISCLAIMER within the package.
  *
- * To use this object include the object file in your link command:
- * gcc -o foo.exe foo.o CRTglob.o
+ * Link with this object file to set _CRT_glob to a state that will turn
+ * on command line globbing by default, preferring the MinGW algorithm to
+ * Microsoft's, but without enabling any of its additional features, as
+ * described in include/_mingw.h.
+ *
+ * NOTE: this file is linked by default, via libmingw32.a, if _CRT_glob
+ * is not defined elsewhere in explicitly linked object files.  To turn
+ * globbing off, you may link explicitly with CRT_noglob.o, or you may
+ * define _CRT_glob with a value of zero, as a global variable in one of
+ * your own source files, (typically, the one which defines your main()
+ * function).  To enable any of the additional globbing features described
+ * in include/_mingw.h, you should define _CRT_glob yourself, initializing
+ * it to the value formed by logical OR of __CRT_GLOB_USE_MINGW__ with the
+ * additional feature descriptors you wish to enable, while to select
+ * Microsoft's globbing algorithm in preference to MinGW's, you should
+ * initialize _CRT_glob = __CRT_glob = __CRT_GLOB_USE_MSVCRT__
  *
  */
+#include <_mingw.h>
+
+int _CRT_glob = __CRT_GLOB_USE_MINGW__;
 
-int _CRT_glob = -1;
+/* $RCSfile$: end of file */
index 9f1c22e..26cc709 100644 (file)
@@ -1,3 +1,36 @@
+2014-11-08  Keith Marshall  <keithmarshall@users.sourceforge.net>
+
+       Implement new command line argument globbing strategy.
+
+       * include/_mingw.h: Backport feature defines from master...
+       (__CRT_GLOB_USE_MINGW__, __CRT_GLOB_USE_MSVCRT__): New manifest
+       constants; define them.  They select the preferred globbing algorithm.
+       [_CRT_glob & __CRT_GLOB_USE_MINGW__] (__CRT_GLOB_USE_SINGLE_QUOTE__)
+       (__CRT_GLOB_BRACKET_GROUPS__, __CRT_GLOB_CASE_SENSITIVE__): New option
+       bit-map constants; define them.  When added to __CRT_GLOB_USE_MINGW__,
+       they enable optional additional features supported by this algorithm.
+       (__CRT_GLOB_ESCAPE_CHAR__): New manifest constant; define it.
+
+       * CRTglob.c (_CRT_glob): Change default to __CRT_GLOB_USE_MINGW__.
+
+       * Makefile.in (libmingw32.a): Add setargv.$OBJEXT, furnished by...
+       * setargv.c: ...new file; it implements the initialization mechanism
+       for the __CRT_GLOB_USE_MINGW__ globbing algorithm, when invoked by...
+       (_setargv) [_CRT_glob & __CRT_GLOB_USE_MINGW__]: ...this new function;
+       it invokes the algorithm via an API similar to that described by MSDN,
+       while continuing to support our original _CRT_glob interpretation.
+       (_setargv) [! _CRT_glob & __CRT_GLOB_USE_MINGW__]: Invoke Microsoft
+       algorithm, via the MSDN-alike API, by calling back to...
+
+       * crt1.c (_mingw32_init_mainargs): ...this original function, now
+       relocated to here, as a publicly addressable function; formerly...
+       (__mingw_CRTStartup): ...called directly from here, we now redirect
+       the call through _setargv(), whence it may be called indirectly.
+
+       * init.c: Redundant file; delete it.  It originally provided...
+       (_mingw32_init_mainargs): ...this, now relocated as noted above, with
+       original static attribute removed, to allow global addressing.
+
 2014-11-07  Keith Marshall  <keithmarshall@users.sourceforge.net>
 
        Backport glob implementation from master to legacy.
index 01f48d5..3cdb394 100644 (file)
@@ -363,9 +363,9 @@ $(addsuffix .def,$(all_moldname)): %.def: ${mingwrt_srcdir}/moldname.def.in
        $(CC) -C -E -P -D__FILENAME__=$@ -xc-header $< > $@
 
 all-mingwrt-libs install-mingwrt-libs: libmingw32.a libmingwex.a
-libmingw32.a: $(addsuffix .$(OBJEXT), CRTinit CRTfmode CRTglob \
-  cpu_features CRT_fp10 txtmode main dllmain gccmain crtst tlsmcrt \
-  tlsmthread tlssup tlsthrd pseudo-reloc pseudo-reloc-list)
+libmingw32.a: $(addsuffix .$(OBJEXT), CRTinit CRTglob setargv \
+  CRTfmode cpu_features CRT_fp10 txtmode main dllmain gccmain crtst \
+  tlsmcrt tlsmthread tlssup tlsthrd pseudo-reloc pseudo-reloc-list)
 
 libmingw32.a libmingwex.a libm.a libmingwthrd.a libgmon.a:
        $(AR) $(ARFLAGS) $@ $?
index 8e24d00..8730606 100644 (file)
@@ -10,7 +10,8 @@
  */
 
 /* Hide the declaration of _fmode with dllimport attribute in stdlib.h to
-   avoid problems with older GCC. */
+ * avoid problems with older GCC.
+ */
 #define __IN_MINGW_RUNTIME
 #include <stdlib.h>
 #include <stdio.h>
 #include <windows.h>
 #include <signal.h>
 
-/* NOTE: The code for initializing the _argv, _argc, and environ variables
- *       has been moved to a separate .c file which is included in both
- *       crt1.c and dllcrt1.c. This means changes in the code don't have to
- *       be manually synchronized, but it does lead to this not-generally-
- *       a-good-idea use of include. */
-#include "init.c"
 #include "cpu_features.h"
 
 extern void __main ();
 extern void _pei386_runtime_relocator (void);
 
+/* Main program entry point, and argument initialization hook.
+ */
 extern int main (int, char **, char **);
 
-/* TLS initialization hook.  */
-extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
+int    _argc = 0;
+char **_argv = NULL;
 
-/*
- * Must have the correct app type for MSVCRT.
+/* NOTE: Thanks to Pedro A. Aranda Gutiirrez <paag@tid.es> for pointing
+ * this out: the GetMainArgs() function, (provided by CRTDLL.DDL, as an
+ * argument initialization hook), takes a fourth argument (an int), which
+ * controls the globbing of the command line; if it is non-zero the command
+ * line will be globbed (e.g. *.* will be expanded to a list, separated by
+ * spaces, of all files in the startup directory).
+ *
+ * We determine how globbing should be performed, by inspection of the two
+ * least significant bits of the global int variable _CRT_glob, (defined in
+ * the mingw32 library, with a default value of 2).  If this pair of bits
+ * represent a value of 2 or more, the new MinGW globbing algorithm, (as
+ * implemented by function _setargv() in setargv.c), will be applied; for
+ * values of one or zero, _setargv() will delegate the globbing function to
+ * the _mingw32_init_mainargs() callback function implemented below, and so
+ * invoking the Microsoft GetMainArgs() algorithm, with its fourth argument
+ * set to one or zero, to match the least significant bit of _CRT_glob.
+ *
+ * The mingw32 library default value of 2 for _CRT_glob enables command line
+ * globbing using the MinGW algorithm.  If you prefer to adopt the Microsoft
+ * algorithm, you should define _CRT_glob as a global variable, by including
+ * a line in one of your own source code files, like this:
+ *
+ *    int _CRT_glob = 1;
+ *
+ * Alternatively, if you prefer to disable globbing, and do all command line
+ * processing yourself, (and so evade possible bogons in the Microsoft or in
+ * the MinGW globbing code), include a similar line in one of your own source
+ * code files, defining _CRT_glob with a value of zero, like this:
+ *
+ *    int _CRT_glob = 0;
+ */
+extern int _CRT_glob;
+
+#ifdef __MSVCRT__
+/* In MSVCRT.DLL, Microsoft's initialization hook is called __getmainargs(),
+ * and it expects a further structure argument, (which we don't use, but pass
+ * it as a dummy, with a declared size of zero in its first and only field).
  */
+typedef struct { int newmode; } _startupinfo;
+extern void __getmainargs( int *, char ***, char ***, int, _startupinfo * );
 
+#else
+/* In CRTDLL.DLL, the initialization hook is called __GetMainArgs().
+ */
+extern void __GetMainArgs( int *, char ***, char ***, int );
+#endif
+
+void _mingw32_init_mainargs()
+{
+  /* This is the old start-up mechanism, in which we use a start-up
+   * hook provided by Microsoft's runtime library to initialize the
+   * argument and environment vectors.
+   *
+   * Note that the preferred method for accessing the environment
+   * vector is via a direct pointer retrieved from the runtime DLL,
+   * using a system call declared in stdlib.h; thus, we don't need
+   * to preserve the pointer returned by the start-up hook, so we
+   * may simply capture it locally, and subsequently discard it.
+   */
+  char **dummy_envp;
+
+# define _CRT_GLOB_OPT  _CRT_glob & __CRT_GLOB_USE_MSVCRT__
+# ifdef __MSVCRT__
+    /* The MSVCRT.DLL start-up hook requires this invocation
+     * protocol...
+     */
+    _startupinfo start_info = { 0 };
+    __getmainargs( &_argc, &_argv, &dummy_envp, _CRT_GLOB_OPT, &start_info );
+
+# else
+    /* ...while a somewhat simpler protocol is applicable, in
+     * the case of the CRTDLL.DLL version.
+     */
+    __GetMainArgs( &_argc, &_argv, &dummy_envp, _CRT_GLOB_OPT );
+# endif
+}
+
+/* TLS initialization hook.
+ */
+extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
+
+/* Must have the correct app type for MSVCRT.
+ */
 #ifdef __MSVCRT__
-#define __UNKNOWN_APP    0
-#define __CONSOLE_APP    1
-#define __GUI_APP        2
+# define __UNKNOWN_APP    0
+# define __CONSOLE_APP    1
+# define __GUI_APP        2
+
 __MINGW_IMPORT void __set_app_type(int);
+
 #endif /* __MSVCRT__ */
 
-/*  Global _fmode for this .exe, not the one in msvcrt.dll,
-    The default is set in txtmode.o in libmingw32.a */
-/* Override the dllimport'd declarations in stdlib.h */
+/* Global _fmode for this .exe, (not the one in msvcrt.dll).
+ *
+ * The default is set in txtmode.o in libmingw32.a
+ * Override the dllimport'd declarations in stdlib.h
+ */
 #undef _fmode
 extern int _fmode;
 #ifdef __MSVCRT__
@@ -66,42 +146,35 @@ extern int _CRT_fmode;
 static void
 _mingw32_init_fmode (void)
 {
-  /* Don't set the std file mode if the user hasn't set any value for it. */
+  /* Don't set the std file mode if the user hasn't set any value for it.
+   */
   if (_CRT_fmode)
-    {
-      _fmode = _CRT_fmode;
-
-      /*
-       * This overrides the default file mode settings for stdin,
-       * stdout and stderr. At first I thought you would have to
-       * test with isatty, but it seems that the DOS console at
-       * least is smart enough to handle _O_BINARY stdout and
-       * still display correctly.
-       */
-      if (stdin)
-       {
-         _setmode (_fileno (stdin), _CRT_fmode);
-       }
-      if (stdout)
-       {
-         _setmode (_fileno (stdout), _CRT_fmode);
-       }
-      if (stderr)
-       {
-         _setmode (_fileno (stderr), _CRT_fmode);
-       }
-    }
-
-    /*  Now sync  the dll _fmode to the  one for this .exe.  */
-#ifdef __MSVCRT__
+  {
+    _fmode = _CRT_fmode;
+
+    /* This overrides the default file mode settings for stdin,
+     * stdout and stderr. At first I thought you would have to
+     * test with isatty, but it seems that the DOS console at
+     * least is smart enough to handle _O_BINARY stdout and
+     * still display correctly.
+     */
+    if (stdin) _setmode (_fileno (stdin), _CRT_fmode);
+    if (stdout) _setmode (_fileno (stdout), _CRT_fmode);
+    if (stderr) _setmode (_fileno (stderr), _CRT_fmode);
+  }
+
+  /* Now sync the dll _fmode to the one for this .exe.
+   */
+# ifdef __MSVCRT__
     *__p__fmode() = _fmode;
-#else
+# else
     *_imp___fmode_dll = _fmode;
-#endif
+# endif
 }
 
-/* This function will be called when a trap occurs. Thanks to Jacob
-   Navia for his contribution. */
+/* This function will be called when a trap occurs.  Thanks to
+ * Jacob Navia for this contribution.
+ */
 static CALLBACK long
 _gnu_exception_handler (EXCEPTION_POINTERS * exception_data)
 {
@@ -181,50 +254,48 @@ _gnu_exception_handler (EXCEPTION_POINTERS * exception_data)
   return action;
 }
 
-/*
- * The function mainCRTStartup is the entry point for all console programs.
+/* The function mainCRTStartup is the entry point for all console programs.
  */
 static void  __MINGW_ATTRIB_NORETURN
 __mingw_CRTStartup (void)
 {
   int nRet;
 
-  /* Initialize TLS callback.  */
+  /* Initialize TLS callback.
+   */
   if (__dyn_tls_init_callback != NULL)
     __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL);
 
-  /*
-   * Set up the top-level exception handler so that signal handling
+  /* Set up the top-level exception handler so that signal handling
    * works as expected. The mapping between ANSI/POSIX signals and
-   * Win32 SE is not 1-to-1, so caveat emptore.
+   * Win32 SE is not 1-to-1, so caveat emptor.
    *
    */
   SetUnhandledExceptionFilter (_gnu_exception_handler);
 
-  /*
-   * Initialize floating point unit.
+  /* Initialize floating point unit.
    */
   __cpu_features_init ();      /* Do we have SSE, etc.*/
   _fpreset ();                 /* Supplied by the runtime library. */
 
-  /*
-   * Set up __argc, __argv and _environ.
+  /* Set up __argc, __argv and _environ.
    */
-  _mingw32_init_mainargs ();
+  _setargv ();
 
-  /*
-   * Sets the default file mode.
+  /* Sets the default file mode.
    * If _CRT_fmode is set, also set mode for stdin, stdout
    * and stderr, as well
    * NOTE: DLLs don't do this because that would be rude!
    */
   _mingw32_init_fmode ();
 
-   /* Adust references to dllimported data that have non-zero offsets.  */
+  /* Adust references to dllimported data that have non-zero offsets.
+   */
   _pei386_runtime_relocator ();
 
   /* Align the stack to 16 bytes for the sake of SSE ops in main
-     or in functions inlined into main.  */
+   * or in functions inlined into main.
+   */
   asm  __volatile__  ("andl $-16, %%esp" : : : "%esp");
 
    /* From libgcc.a, __main calls global class constructors via
@@ -235,16 +306,14 @@ __mingw_CRTStartup (void)
       which has its own __do_global_ctors.  */
     __main ();
 
-  /*
-   * Call the main function. If the user does not supply one
+  /* Call the main function. If the user does not supply one
    * the one in the 'libmingw32.a' library will be linked in, and
    * that one calls WinMain. See main.c in the 'lib' dir
    * for more details.
    */
   nRet = main (_argc, _argv, environ);
 
-  /*
-   * Perform exit processing for the C library. This means
+  /* Perform exit processing for the C library. This means
    * flushing output and calling 'atexit' registered functions.
    */
   _cexit ();
index eb51458..cbaf9d0 100644 (file)
 #endif
 #endif
 
-/* These are defined by the user (or the compiler)
-   to specify how identifiers are imported from a DLL.
-
-   __DECLSPEC_SUPPORTED            Defined if dllimport attribute is supported.
-   __MINGW_IMPORT                  The attribute definition to specify imported
-                                   variables/functions.
-   _CRTIMP                         As above.  For MS compatibility.
-   __MINGW32_VERSION               Runtime version.
-   __MINGW32_MAJOR_VERSION         Runtime major version.
-   __MINGW32_MINOR_VERSION         Runtime minor version.
-   __MINGW32_BUILD_DATE            Runtime build date.
-
-   Macros to enable MinGW features which deviate from standard MSVC
-   compatible behaviour; these may be specified directly in user code,
-   activated implicitly, (e.g. by specifying _POSIX_C_SOURCE or such),
-   or by inclusion in __MINGW_FEATURES__:
-
-   __USE_MINGW_ANSI_STDIO          Select a more ANSI C99 compatible
-                                   implementation of printf() and friends.
+/* The following are defined by the user (or by the compiler), to specify how
+ * identifiers are imported from a DLL.  All headers should include this first,
+ * and then use __DECLSPEC_SUPPORTED to choose between the old ``__imp__name''
+ * style or the __MINGW_IMPORT style for declarations.
+ *
+ * __DECLSPEC_SUPPORTED            Defined if dllimport attribute is supported.
+ * __MINGW_IMPORT                  The attribute definition to specify imported
+ *                                 variables/functions.
+ * _CRTIMP                         As above.  For MS compatibility.
+ * __MINGW32_VERSION               Runtime version.
+ * __MINGW32_MAJOR_VERSION         Runtime major version.
+ * __MINGW32_MINOR_VERSION         Runtime minor version.
+ * __MINGW32_BUILD_DATE            Runtime build date.
+ *
+ * Macros to enable MinGW features which deviate from standard MSVC
+ * compatible behaviour; these may be specified directly in user code,
+ * activated implicitly, (e.g. by specifying _POSIX_C_SOURCE or such),
+ * or by inclusion in __MINGW_FEATURES__:
+ *
+ * __USE_MINGW_ANSI_STDIO          Select a more ANSI C99 compatible
+ *                                 implementation of printf() and friends.
+ *
+ * Other macros:
+ *
+ * __int64                         define to be long long.  Using a typedef
+ *                                 doesn't work for "unsigned __int64"
+ *
+ *
+ * Manifest definitions for flags to control globbing of the command line
+ * during application start up, (before main() is called).  The first pair,
+ * when assigned as bit flags within _CRT_glob, select the globbing algorithm
+ * to be used; (the MINGW algorithm overrides MSCVRT, if both are specified).
+ * Prior to mingwrt-3.21, only the MSVCRT option was supported; this choice
+ * may produce different results, depending on which particular version of
+ * MSVCRT.DLL is in use; (in recent versions, it seems to have become
+ * definitively broken, when globbing within double quotes).
+ */
+#define __CRT_GLOB_USE_MSVCRT__        0x0001
 
-   Other macros:
+/* From mingwrt-3.21 onward, this should be the preferred choice; it will
+ * produce consistent results, regardless of the MSVCRT.DLL version in use.
+ */
+#define __CRT_GLOB_USE_MINGW__         0x0002
 
-   __int64                         define to be long long.  Using a typedef
-                                   doesn't work for "unsigned __int64"
+/* When the __CRT_GLOB_USE_MINGW__ flag is set, within _CRT_glob, the
+ * following additional options are also available; they are not enabled
+ * by default, but the user may elect to enable any combination of them,
+ * by setting _CRT_glob to the boolean sum (i.e. logical OR combination)
+ * of __CRT_GLOB_USE_MINGW__ and the desired options.
+ *
+ *    __CRT_GLOB_USE_SINGLE_QUOTE__    allows use of single (apostrophe)
+ *                                     quoting characters, analogously to
+ *                                     POSIX usage, as an alternative to
+ *                                     double quotes, for collection of
+ *                                     arguments separated by white space
+ *                                     into a single logical argument.
+ *
+ *    __CRT_GLOB_BRACKET_GROUPS__      enable interpretation of bracketed
+ *                                     character groups as POSIX compatible
+ *                                     globbing patterns, matching any one
+ *                                     character which is either included
+ *                                     in, or excluded from the group.
+ *
+ *    __CRT_GLOB_CASE_SENSITIVE__      enable case sensitive matching for
+ *                                     globbing patterns; this is default
+ *                                     behaviour for POSIX, but because of
+ *                                     the case insensitive nature of the
+ *                                     MS-Windows file system, it is more
+ *                                     appropriate to use case insensitive
+ *                                     globbing as the MinGW default.
+ *
+ */
+#define __CRT_GLOB_USE_SINGLE_QUOTE__  0x0010
+#define __CRT_GLOB_BRACKET_GROUPS__    0x0020
+#define __CRT_GLOB_CASE_SENSITIVE__    0x0040
 
-   All headers should include this first, and then use __DECLSPEC_SUPPORTED
-   to choose between the old ``__imp__name'' style or __MINGW_IMPORT
-   style declarations.  */
+/* The MinGW globbing algorithm uses the ASCII DEL control code as a marker
+ * for globbing characters which were embedded within quoted arguments; (the
+ * quotes are stripped away BEFORE the argument is globbed; the globbing code
+ * treats the marked character as immutable, and strips out the DEL markers,
+ * before storing the resultant argument).  The DEL code is mapped to this
+ * function here; DO NOT change it, without rebuilding the runtime.
+ */
+#define __CRT_GLOB_ESCAPE_CHAR__       (char)(127)
 
 
 /* Manifest definitions identifying the flag bits, controlling activation
diff --git a/mingwrt/init.c b/mingwrt/init.c
deleted file mode 100644 (file)
index b7af07c..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * init.c
- * This file has no copyright assigned and is placed in the Public Domain.
- * This file is a part of the mingw-runtime package.
- * No warranty is given; refer to the file DISCLAIMER within the package.
- *
- * Code to initialize standard file handles and command line arguments.
- * This file is #included in both crt1.c and dllcrt1.c.
- *
- */
-
-/*
- * Access to a standard 'main'-like argument count and list. Also included
- * is a table of environment variables.
- */
-int _argc = 0;
-char **_argv = 0;
-
-/* NOTE: Thanks to Pedro A. Aranda Gutiirrez <paag@tid.es> for pointing
- * this out to me. GetMainArgs (used below) takes a fourth argument
- * which is an int that controls the globbing of the command line. If
- * _CRT_glob is non-zero the command line will be globbed (e.g. *.*
- * expanded to be all files in the startup directory). In the mingw32
- * library a _CRT_glob variable is defined as being -1, enabling
- * this command line globbing by default. To turn it off and do all
- * command line processing yourself (and possibly escape bogons in
- * MS's globbing code) include a line in one of your source modules
- * defining _CRT_glob and setting it to zero, like this:
- *  int _CRT_glob = 0;
- */
-extern int _CRT_glob;
-
-#ifdef __MSVCRT__
-typedef struct {
-  int newmode;
-} _startupinfo;
-extern void __getmainargs (int *, char ***, char ***, int, _startupinfo *);
-#else
-extern void __GetMainArgs (int *, char ***, char ***, int);
-#endif
-
-/*
- * Initialize the _argc, _argv and environ variables.
- */
-static void
-_mingw32_init_mainargs ()
-{
-  /* The environ variable is provided directly in stdlib.h through
-   * a dll function call. */
-  char **dummy_environ;
-#ifdef __MSVCRT__
-  _startupinfo start_info;
-  start_info.newmode = 0;
-#endif
-
-  /*
-   * Microsoft's runtime provides a function for doing just that.
-   */
-#ifdef __MSVCRT__
-  (void) __getmainargs (&_argc, &_argv, &dummy_environ, _CRT_glob,
-                        &start_info);
-#else
-  /* CRTDLL version */
-  (void) __GetMainArgs (&_argc, &_argv, &dummy_environ, _CRT_glob);
-#endif
-}
-
diff --git a/mingwrt/setargv.c b/mingwrt/setargv.c
new file mode 100644 (file)
index 0000000..3e823e8
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * setargv.c
+ *
+ * Implements runtime initialization code to populate the argument
+ * vector, which will subsequently be passed to the main() function;
+ * provides a _setargv() hook, similar to that described on MSDN.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2014, MinGW.org Project
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ */
+#include <glob.h>
+#include <string.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/* Access to a standard 'main'-like argument count and list.
+ */
+extern int     _argc;
+extern char ** _argv;
+extern int     _CRT_glob;
+
+#define ARGV_INLINE  static __inline__ __attribute__((__always_inline__))
+
+#define ARGV_ESCAPE     __CRT_GLOB_ESCAPE_CHAR__
+#define ARGV_SQUOTE     __CRT_GLOB_USE_SINGLE_QUOTE__
+#define ARGV_NOGROUP    __CRT_GLOB_BRACKET_GROUPS__
+
+ARGV_INLINE
+char *backslash( int count, char *buf )
+{
+  /* Helper used by the MinGW replacement command line globbing handler,
+   * to provide appropriate handling of backslashes while preparing the
+   * command line arguments for globbing.
+   */
+  while( count-- )
+    *buf++ = '\\';
+  return buf;
+}
+
+ARGV_INLINE
+char *unquote( int quote, int altquote, int escape, int *state, char *buf )
+{
+  /* Helper used by the MinGW replacement command line globbing handler,
+   * to provide a single level of reduction for balanced quotation marks,
+   * while preparing the command line arguments for globbing.
+   */
+  buf = backslash( escape >> 1, buf );
+  if( (escape & 1) || (*state == altquote) )
+    /*
+     * In this case, the quotation mark is to be interpreted as a literal,
+     * and is NOT a candidate for reduction...
+     */
+    *buf++ = quote;
+  else
+    /* ...while this is the more usual case, of a quotation mark used to
+     * delimit a single argument; it must be reduced.
+     */
+    *state ^= quote;
+  return buf;
+}
+
+ARGV_INLINE
+void __mingw32_setargv( const char *cmdline )
+{
+  /* Implementation of the MinGW replacement command line interpreter.
+   */
+  char cmdbuf[1 + strlen( cmdline ) << 1];
+  int c, gotarg = 0, quoted = 0, bracket = 0, bslash = 0;
+  char *argptr = cmdbuf; const char *cmdptr = cmdline;
+  glob_t gl_argv;
+
+  /* Capture any non-default globbing options, which the user may have
+   * specified via a custom setting for _CRT_glob.
+   */
+  int gl_opts = GLOB_NOCHECK;
+  if( _CRT_glob & __CRT_GLOB_CASE_SENSITIVE__ )
+    gl_opts |= GLOB_CASEMATCH;
+
+  /* We explicitly DO NOT use the GLOB_DOOFFS capability; ensure that
+   * the associated field, in the glob_t structure, is initialized to
+   * correctly reflect this.
+   */
+  gl_argv.gl_offs = 0;
+
+  /* Scan the command line, and prepare it for globbing.
+   */
+  while( c = *cmdptr++ )
+  {
+    /* Got a character to process...
+     */
+    switch( c )
+    {
+      /* Specific characters, which serve as globbing tokens,
+       * need special handling.
+       */
+      case '\\':
+       /* We don't (yet) know if this is a literal backslash,
+        * (directory separator), or an escape for a following
+        * quote character; just note its presence, until we
+        * have looked far enough ahead to decide.
+        */
+       ++bslash;
+       break;
+
+      case '[':
+       /* POSIX defines this as a globbing token, (introducing
+        * a character group); we don't support this by default,
+        * so defeat it, unless the extended behaviour has been
+        * requested by the user.
+        */
+       bracket = (_CRT_glob & ARGV_NOGROUP) ? 0 : ARGV_NOGROUP;
+
+      case '*':
+      case '?':
+       /* These standard globbing tokens...
+        */
+      case ARGV_ESCAPE:
+       /* ...and the escape character itself, need to be escaped
+        * when they appear in any context in which they should be
+        * interpreted literally, rather than globbed.
+        */
+       argptr = backslash( bslash, argptr );
+       if( quoted || (bracket == ARGV_NOGROUP) || (c == ARGV_ESCAPE) )
+         *argptr++ = ARGV_ESCAPE;
+       bracket = bslash = 0;
+       *argptr++ = c;
+       break;
+
+      case '"':
+       /* The double quote always acts as an argument quoting
+        * character, (unless escaped); handle it accordingly.
+        */
+       argptr = unquote( c, '\'', bslash, &quoted, argptr );
+       gotarg = 1; bslash = 0;
+       break;
+
+      case '\'':
+       /* POSIX also defines the single quote as a quoting
+        * character, but MS-Windows does not; we offer this
+        * extended handling...
+        */
+       if( _CRT_glob & ARGV_SQUOTE )
+       {
+         /* ...only when the user has explicitly enabled the
+          * POSIX compatible extended quoting option.
+          */
+         argptr = unquote( c, '"', bslash, &quoted, argptr );
+         gotarg = 1; bslash = 0;
+         break;
+       }
+
+      default:
+       /* With one exception, any other character is handled
+        * literally, after flushing out any pending backslashes.
+        */
+       argptr = backslash( bslash, argptr );
+       if( (quoted == 0) && isspace( c ) )
+       {
+         /* The one exception is any white space character,
+          * when it is not contained within quotes; this acts
+          * as an argument separator, (or is simply discarded
+          * if there is no argument already collected)...
+          */
+         if( gotarg || (argptr > cmdbuf) )
+         {
+           /* ...so, when there is a argument pending, we may
+            * now add it to the globbed argument vector.
+            */
+           *argptr = '\0';
+           __mingw_glob( argptr = cmdbuf, gl_opts, NULL, &gl_argv );
+           gl_opts |= GLOB_APPEND;
+           gotarg = 0;
+         }
+       }
+       else
+         /* In every other case, we simply collect the current
+          * literal character into the next pending argument.
+          */
+         *argptr++ = c;
+
+       /* Irrespective of how we handled the current character,
+        * we can be certain that there are no pending backslashes
+        * by the time we get to here.
+        */
+       bslash = 0;
+    }
+  }
+  /* Finally, when we've run out of command line characters to process,
+   * flush out any final pending backslashes, ...
+   */
+  argptr = backslash( bslash, argptr );
+  if( gotarg || (argptr > cmdbuf) )
+  {
+    /* ...and add any final pending argument to the globbed vector.
+     */
+    *argptr = '\0';
+    __mingw_glob( argptr = cmdbuf, gl_opts, NULL, &gl_argv );
+  }
+  /* ...and store the resultant globbed vector into the "argc" and "argv"
+   * variables to be passed to main(); note that this allows us to safely
+   * discard our working glob_t structure, but we MUST NOT globfree() it,
+   * as that would destroy the content of "argv".
+   */
+  _argc = gl_argv.gl_pathc;
+  _argv = gl_argv.gl_pathv;
+}
+
+extern void _mingw32_init_mainargs( void );
+
+void _setargv()
+{
+  /* Initialize the _argc, _argv and environ variables.
+   */
+  if( (_CRT_glob & __CRT_GLOB_USE_MINGW__) == 0 )
+  {
+    /* This is the old start-up mechanism, implemented via a callback
+     * into the CRT initialization module, in which we use a start-up
+     * hook provided by Microsoft's runtime library to initialize the
+     * argument and environment vectors.
+     */
+    _mingw32_init_mainargs();
+  }
+  else
+  { /* Here, we implement a new, more POSIX compatible mechanism,
+     * for initializing the argument vector; note that we delegate
+     * to the previously defined inline function, which avoids the
+     * broken globbing behaviour of some more recent versions of
+     * MSVCRT.DLL
+     */
+    __mingw32_setargv( GetCommandLine() );
+  }
+}
+
+/* $RCSfile$: end of file */