OSDN Git Service

Merge further W32API updates from Cygwin CVS.
[mingw/mingw-org-wsl.git] / mingwrt / setargv.c
1 /*
2  * setargv.c
3  *
4  * Implements runtime initialization code to populate the argument
5  * vector, which will subsequently be passed to the main() function;
6  * provides a _setargv() hook, similar to that described on MSDN.
7  *
8  * $Id$
9  *
10  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
11  * Copyright (C) 2014, MinGW.org Project
12  *
13  * ---------------------------------------------------------------------------
14  *
15  * Permission is hereby granted, free of charge, to any person obtaining a
16  * copy of this software and associated documentation files (the "Software"),
17  * to deal in the Software without restriction, including without limitation
18  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19  * and/or sell copies of the Software, and to permit persons to whom the
20  * Software is furnished to do so, subject to the following conditions:
21  *
22  * The above copyright notice and this permission notice shall be included
23  * in all copies or substantial portions of the Software.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
28  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31  * DEALINGS IN THE SOFTWARE.
32  *
33  * ---------------------------------------------------------------------------
34  *
35  */
36 #include <glob.h>
37 #include <string.h>
38 #include <ctype.h>
39
40 #define WIN32_LEAN_AND_MEAN
41 #include <windows.h>
42
43 /* Access to a standard 'main'-like argument count and list.
44  */
45 extern int     _argc;
46 extern char ** _argv;
47 extern int     _CRT_glob;
48
49 #define ARGV_INLINE  static __inline__ __attribute__((__always_inline__))
50
51 #define ARGV_ESCAPE     __CRT_GLOB_ESCAPE_CHAR__
52 #define ARGV_SQUOTE     __CRT_GLOB_USE_SINGLE_QUOTE__
53 #define ARGV_NOGROUP    __CRT_GLOB_BRACKET_GROUPS__
54
55 ARGV_INLINE
56 char *backslash( int count, char *buf )
57 {
58   /* Helper used by the MinGW replacement command line globbing handler,
59    * to provide appropriate handling of backslashes while preparing the
60    * command line arguments for globbing.
61    */
62   while( count-- )
63     *buf++ = '\\';
64   return buf;
65 }
66
67 ARGV_INLINE
68 char *unquote( int quote, int altquote, int escape, int *state, char *buf )
69 {
70   /* Helper used by the MinGW replacement command line globbing handler,
71    * to provide a single level of reduction for balanced quotation marks,
72    * while preparing the command line arguments for globbing.
73    */
74   buf = backslash( escape >> 1, buf );
75   if( (escape & 1) || (*state == altquote) )
76     /*
77      * In this case, the quotation mark is to be interpreted as a literal,
78      * and is NOT a candidate for reduction...
79      */
80     *buf++ = quote;
81   else
82     /* ...while this is the more usual case, of a quotation mark used to
83      * delimit a single argument; it must be reduced.
84      */
85     *state ^= quote;
86   return buf;
87 }
88
89 ARGV_INLINE
90 void __mingw32_setargv( const char *cmdline )
91 {
92   /* Implementation of the MinGW replacement command line interpreter.
93    */
94   char cmdbuf[1 + strlen( cmdline ) << 1];
95   int c, gotarg = 0, quoted = 0, bracket = 0, bslash = 0;
96   char *argptr = cmdbuf; const char *cmdptr = cmdline;
97   glob_t gl_argv;
98
99   /* Capture any non-default globbing options, which the user may have
100    * specified via a custom setting for _CRT_glob.
101    */
102   int gl_opts = GLOB_NOCHECK;
103   if( _CRT_glob & __CRT_GLOB_CASE_SENSITIVE__ )
104     gl_opts |= GLOB_CASEMATCH;
105
106   /* We explicitly DO NOT use the GLOB_DOOFFS capability; ensure that
107    * the associated field, in the glob_t structure, is initialized to
108    * correctly reflect this.
109    */
110   gl_argv.gl_offs = 0;
111
112   /* Scan the command line, and prepare it for globbing.
113    */
114   while( c = *cmdptr++ )
115   {
116     /* Got a character to process...
117      */
118     switch( c )
119     {
120       /* Specific characters, which serve as globbing tokens,
121        * need special handling.
122        */
123       case '\\':
124         /* We don't (yet) know if this is a literal backslash,
125          * (directory separator), or an escape for a following
126          * quote character; just note its presence, until we
127          * have looked far enough ahead to decide.
128          */
129         ++bslash;
130         break;
131
132       case '[':
133         /* POSIX defines this as a globbing token, (introducing
134          * a character group); we don't support this by default,
135          * so defeat it, unless the extended behaviour has been
136          * requested by the user.
137          */
138         bracket = (_CRT_glob & ARGV_NOGROUP) ? 0 : ARGV_NOGROUP;
139
140       case '*':
141       case '?':
142         /* These standard globbing tokens...
143          */
144       case ARGV_ESCAPE:
145         /* ...and the escape character itself, need to be escaped
146          * when they appear in any context in which they should be
147          * interpreted literally, rather than globbed.
148          */
149         argptr = backslash( bslash, argptr );
150         if( quoted || (bracket == ARGV_NOGROUP) || (c == ARGV_ESCAPE) )
151           *argptr++ = ARGV_ESCAPE;
152         bracket = bslash = 0;
153         *argptr++ = c;
154         break;
155
156       case '"':
157         /* The double quote always acts as an argument quoting
158          * character, (unless escaped); handle it accordingly.
159          */
160         argptr = unquote( c, '\'', bslash, &quoted, argptr );
161         gotarg = 1; bslash = 0;
162         break;
163
164       case '\'':
165         /* POSIX also defines the single quote as a quoting
166          * character, but MS-Windows does not; we offer this
167          * extended handling...
168          */
169         if( _CRT_glob & ARGV_SQUOTE )
170         {
171           /* ...only when the user has explicitly enabled the
172            * POSIX compatible extended quoting option.
173            */
174           argptr = unquote( c, '"', bslash, &quoted, argptr );
175           gotarg = 1; bslash = 0;
176           break;
177         }
178
179       default:
180         /* With one exception, any other character is handled
181          * literally, after flushing out any pending backslashes.
182          */
183         argptr = backslash( bslash, argptr );
184         if( (quoted == 0) && isspace( c ) )
185         {
186           /* The one exception is any white space character,
187            * when it is not contained within quotes; this acts
188            * as an argument separator, (or is simply discarded
189            * if there is no argument already collected)...
190            */
191           if( gotarg || (argptr > cmdbuf) )
192           {
193             /* ...so, when there is a argument pending, we may
194              * now add it to the globbed argument vector.
195              */
196             *argptr = '\0';
197             __mingw_glob( argptr = cmdbuf, gl_opts, NULL, &gl_argv );
198             gl_opts |= GLOB_APPEND;
199             gotarg = 0;
200           }
201         }
202         else
203           /* In every other case, we simply collect the current
204            * literal character into the next pending argument.
205            */
206           *argptr++ = c;
207
208         /* Irrespective of how we handled the current character,
209          * we can be certain that there are no pending backslashes
210          * by the time we get to here.
211          */
212         bslash = 0;
213     }
214   }
215   /* Finally, when we've run out of command line characters to process,
216    * flush out any final pending backslashes, ...
217    */
218   argptr = backslash( bslash, argptr );
219   if( gotarg || (argptr > cmdbuf) )
220   {
221     /* ...and add any final pending argument to the globbed vector.
222      */
223     *argptr = '\0';
224     __mingw_glob( argptr = cmdbuf, gl_opts, NULL, &gl_argv );
225   }
226   /* ...and store the resultant globbed vector into the "argc" and "argv"
227    * variables to be passed to main(); note that this allows us to safely
228    * discard our working glob_t structure, but we MUST NOT globfree() it,
229    * as that would destroy the content of "argv".
230    */
231   _argc = gl_argv.gl_pathc;
232   _argv = gl_argv.gl_pathv;
233 }
234
235 extern void _mingw32_init_mainargs( void );
236
237 void _setargv()
238 {
239   /* Initialize the _argc, _argv and environ variables.
240    */
241   if( (_CRT_glob & __CRT_GLOB_USE_MINGW__) == 0 )
242   {
243     /* This is the old start-up mechanism, implemented via a callback
244      * into the CRT initialization module, in which we use a start-up
245      * hook provided by Microsoft's runtime library to initialize the
246      * argument and environment vectors.
247      */
248     _mingw32_init_mainargs();
249   }
250   else
251   { /* Here, we implement a new, more POSIX compatible mechanism,
252      * for initializing the argument vector; note that we delegate
253      * to the previously defined inline function, which avoids the
254      * broken globbing behaviour of some more recent versions of
255      * MSVCRT.DLL
256      */
257     __mingw32_setargv( GetCommandLine() );
258   }
259 }
260
261 /* $RCSfile$: end of file */