OSDN Git Service

Correct C++ compilation anomaly with hypotf() in cmath header.
[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
39 #define WIN32_LEAN_AND_MEAN
40 #include <windows.h>
41
42 /* Access to a standard 'main'-like argument count and list.
43  */
44 extern int     _argc;
45 extern char ** _argv;
46 extern int     _CRT_glob;
47
48 #define ARGV_INLINE  static __inline__ __attribute__((__always_inline__))
49
50 #define ARGV_ESCAPE     __CRT_GLOB_ESCAPE_CHAR__
51 #define ARGV_SQUOTE     __CRT_GLOB_USE_SINGLE_QUOTE__
52 #define ARGV_NOGROUP    __CRT_GLOB_BRACKET_GROUPS__
53
54 ARGV_INLINE
55 char *backslash( int count, char *buf )
56 {
57   /* Helper used by the MinGW replacement command line globbing handler,
58    * to provide appropriate handling of backslashes while preparing the
59    * command line arguments for globbing.
60    */
61   while( count-- )
62     *buf++ = '\\';
63   return buf;
64 }
65
66 ARGV_INLINE
67 char *unquote( int quote, int altquote, int escape, int *state, char *buf )
68 {
69   /* Helper used by the MinGW replacement command line globbing handler,
70    * to provide a single level of reduction for balanced quotation marks,
71    * while preparing the command line arguments for globbing.
72    */
73   buf = backslash( escape >> 1, buf );
74   if( (escape & 1) || (*state == altquote) )
75     /*
76      * In this case, the quotation mark is to be interpreted as a literal,
77      * and is NOT a candidate for reduction...
78      */
79     *buf++ = quote;
80   else
81     /* ...while this is the more usual case, of a quotation mark used to
82      * delimit a single argument; it must be reduced.
83      */
84     *state ^= quote;
85   return buf;
86 }
87
88 ARGV_INLINE
89 void __mingw32_setargv( const char *cmdline )
90 {
91   /* Implementation of the MinGW replacement command line interpreter.
92    */
93   char cmdbuf[1 + strlen( cmdline ) << 1];
94   int c, gotarg = 0, quoted = 0, bracket = 0, bslash = 0;
95   char *argptr = cmdbuf; const char *cmdptr = cmdline;
96   glob_t gl_argv;
97
98   /* Capture any non-default globbing options, which the user may have
99    * specified via a custom setting for _CRT_glob.
100    */
101   int gl_opts = GLOB_NOCHECK;
102   if( _CRT_glob & __CRT_GLOB_CASE_SENSITIVE__ )
103     gl_opts |= GLOB_CASEMATCH;
104
105   /* We explicitly DO NOT use the GLOB_DOOFFS capability; ensure that
106    * the associated field, in the glob_t structure, is initialized to
107    * correctly reflect this.
108    */
109   gl_argv.gl_offs = 0;
110
111   /* Scan the command line, and prepare it for globbing.
112    */
113   while( c = *cmdptr++ )
114   {
115     /* Got a character to process...
116      */
117     switch( c )
118     {
119       /* Specific characters, which serve as globbing tokens,
120        * need special handling.
121        */
122       case '\\':
123         /* We don't (yet) know if this is a literal backslash,
124          * (directory separator), or an escape for a following
125          * quote character; just note its presence, until we
126          * have looked far enough ahead to decide.
127          */
128         ++bslash;
129         break;
130
131       case '[':
132         /* POSIX defines this as a globbing token, (introducing
133          * a character group); we don't support this by default,
134          * so defeat it, unless the extended behaviour has been
135          * requested by the user.
136          */
137         bracket = (_CRT_glob & ARGV_NOGROUP) ? 0 : ARGV_NOGROUP;
138
139       case '*':
140       case '?':
141         /* These standard globbing tokens...
142          */
143       case ARGV_ESCAPE:
144         /* ...and the escape character itself, need to be escaped
145          * when they appear in any context in which they should be
146          * interpreted literally, rather than globbed.
147          */
148         argptr = backslash( bslash, argptr );
149         if( quoted || (bracket == ARGV_NOGROUP) || (c == ARGV_ESCAPE) )
150           *argptr++ = ARGV_ESCAPE;
151         bracket = bslash = 0;
152         *argptr++ = c;
153         break;
154
155       case '"':
156         /* The double quote always acts as an argument quoting
157          * character, (unless escaped); handle it accordingly.
158          */
159         argptr = unquote( c, '\'', bslash, &quoted, argptr );
160         gotarg = 1; bslash = 0;
161         break;
162
163       case '\'':
164         /* POSIX also defines the single quote as a quoting
165          * character, but MS-Windows does not; we offer this
166          * extended handling...
167          */
168         if( _CRT_glob & ARGV_SQUOTE )
169         {
170           /* ...only when the user has explicitly enabled the
171            * POSIX compatible extended quoting option.
172            */
173           argptr = unquote( c, '"', bslash, &quoted, argptr );
174           gotarg = 1; bslash = 0;
175           break;
176         }
177
178       default:
179         /* With one exception, any other character is handled
180          * literally, after flushing out any pending backslashes.
181          */
182         argptr = backslash( bslash, argptr );
183         if( (quoted == 0) && isspace( c ) )
184         {
185           /* The one exception is any white space character,
186            * when it is not contained within quotes; this acts
187            * as an argument separator, (or is simply discarded
188            * if there is no argument already collected)...
189            */
190           if( gotarg || (argptr > cmdbuf) )
191           {
192             /* ...so, when there is a argument pending, we may
193              * now add it to the globbed argument vector.
194              */
195             *argptr = '\0';
196             __mingw_glob( argptr = cmdbuf, gl_opts, NULL, &gl_argv );
197             gl_opts |= GLOB_APPEND;
198             gotarg = 0;
199           }
200         }
201         else
202           /* In every other case, we simply collect the current
203            * literal character into the next pending argument.
204            */
205           *argptr++ = c;
206
207         /* Irrespective of how we handled the current character,
208          * we can be certain that there are no pending backslashes
209          * by the time we get to here.
210          */
211         bslash = 0;
212     }
213   }
214   /* Finally, when we've run out of command line characters to process,
215    * flush out any final pending backslashes, ...
216    */
217   argptr = backslash( bslash, argptr );
218   if( gotarg || (argptr > cmdbuf) )
219   {
220     /* ...and add any final pending argument to the globbed vector.
221      */
222     *argptr = '\0';
223     __mingw_glob( argptr = cmdbuf, gl_opts, NULL, &gl_argv );
224   }
225   /* ...and store the resultant globbed vector into the "argc" and "argv"
226    * variables to be passed to main(); note that this allows us to safely
227    * discard our working glob_t structure, but we MUST NOT globfree() it,
228    * as that would destroy the content of "argv".
229    */
230   _argc = gl_argv.gl_pathc;
231   _argv = gl_argv.gl_pathv;
232 }
233
234 extern void _mingw32_init_mainargs( void );
235
236 void _setargv()
237 {
238   /* Initialize the _argc, _argv and environ variables.
239    */
240   if( (_CRT_glob & __CRT_GLOB_USE_MINGW__) == 0 )
241   {
242     /* This is the old start-up mechanism, implemented via a callback
243      * into the CRT initialization module, in which we use a start-up
244      * hook provided by Microsoft's runtime library to initialize the
245      * argument and environment vectors.
246      */
247     _mingw32_init_mainargs();
248   }
249   else
250   { /* Here, we implement a new, more POSIX compatible mechanism,
251      * for initializing the argument vector; note that we delegate
252      * to the previously defined inline function, which avoids the
253      * broken globbing behaviour of some more recent versions of
254      * MSVCRT.DLL
255      */
256     __mingw32_setargv( GetCommandLine() );
257   }
258 }
259
260 /* $RCSfile$: end of file */