Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/***
2
*stdargv.c - standard & wildcard _setargv routine
3
*
4
*       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
5
*
6
*Purpose:
7
*       processes program command line, with or without wildcard expansion
8
*
9
*******************************************************************************/
10
 
11
 
12
#include <cruntime.h>
13
#include <internal.h>
14
#include <rterr.h>
15
#include <stdlib.h>
16
#if defined (WILDCARD) || defined (_WIN32)
17
#include <dos.h>
18
#include <oscalls.h>
19
#endif  /* defined (WILDCARD) || defined (_WIN32) */
20
#ifdef _MBCS
21
#include <mbctype.h>
22
#endif  /* _MBCS */
23
#include <tchar.h>
24
#include <dbgint.h>
25
 
26
#define NULCHAR    _T('\0')
27
#define SPACECHAR  _T(' ')
28
#define TABCHAR    _T('\t')
29
#define DQUOTECHAR _T('\"')
30
#define SLASHCHAR  _T('\\')
31
 
32
/*
33
 * Flag to ensure multibyte ctype table is only initialized once
34
 */
35
extern int __mbctype_initialized;
36
 
37
#ifdef WPRFLAG
38
static void __cdecl wparse_cmdline(wchar_t *cmdstart, wchar_t **argv, wchar_t *args,
39
        int *numargs, int *numchars);
40
#else  /* WPRFLAG */
41
static void __cdecl parse_cmdline(char *cmdstart, char **argv, char *args,
42
        int *numargs, int *numchars);
43
#endif  /* WPRFLAG */
44
 
45
/***
46
*_setargv, __setargv - set up "argc" and "argv" for C programs
47
*
48
*Purpose:
49
*       Read the command line and create the argv array for C
50
*       programs.
51
*
52
*Entry:
53
*       Arguments are retrieved from the program command line,
54
*       pointed to by _acmdln.
55
*
56
*Exit:
57
*       "argv" points to a null-terminated list of pointers to ASCIZ
58
*       strings, each of which is an argument from the command line.
59
*       "argc" is the number of arguments.  The strings are copied from
60
*       the environment segment into space allocated on the heap/stack.
61
*       The list of pointers is also located on the heap or stack.
62
*       _pgmptr points to the program name.
63
*
64
*Exceptions:
65
*       Terminates with out of memory error if no memory to allocate.
66
*
67
*******************************************************************************/
68
 
69
#ifdef WILDCARD
70
 
71
#ifdef WPRFLAG
72
void __cdecl __wsetargv (
73
#else  /* WPRFLAG */
74
void __cdecl __setargv (
75
#endif  /* WPRFLAG */
76
 
77
#else  /* WILDCARD */
78
 
79
#ifdef WPRFLAG
80
void __cdecl _wsetargv (
81
#else  /* WPRFLAG */
82
void __cdecl _setargv (
83
#endif  /* WPRFLAG */
84
 
85
#endif  /* WILDCARD */
86
    void
87
    )
88
{
89
        _TSCHAR *p;
90
        _TSCHAR *cmdstart;                  /* start of command line to parse */
91
        int numargs, numchars;
92
 
93
        static _TSCHAR _pgmname[ MAX_PATH ];
94
 
95
#if !defined (CRTDLL) && defined (_MBCS)
96
        /* If necessary, initialize the multibyte ctype table. */
97
        if ( __mbctype_initialized == 0 )
98
            __initmbctable();
99
#endif  /* !defined (CRTDLL) && defined (_MBCS) */
100
 
101
        /* Get the program name pointer from Win32 Base */
102
 
103
        GetModuleFileName( NULL, _pgmname, sizeof( _pgmname ) / sizeof(_TSCHAR));
104
#ifdef WPRFLAG
105
        _wpgmptr = _pgmname;
106
#else  /* WPRFLAG */
107
        _pgmptr = _pgmname;
108
#endif  /* WPRFLAG */
109
 
110
        /* if there's no command line at all (won't happen from cmd.exe, but
111
           possibly another program), then we use _pgmptr as the command line
112
           to parse, so that argv[0] is initialized to the program name */
113
 
114
#ifdef WPRFLAG
115
        cmdstart = (*_wcmdln == NULCHAR) ? _wpgmptr : _wcmdln;
116
#else  /* WPRFLAG */
117
        cmdstart = (*_acmdln == NULCHAR) ? _pgmptr : _acmdln;
118
#endif  /* WPRFLAG */
119
 
120
        /* first find out how much space is needed to store args */
121
#ifdef WPRFLAG
122
        wparse_cmdline(cmdstart, NULL, NULL, &numargs, &numchars);
123
#else  /* WPRFLAG */
124
        parse_cmdline(cmdstart, NULL, NULL, &numargs, &numchars);
125
#endif  /* WPRFLAG */
126
 
127
        /* allocate space for argv[] vector and strings */
128
        p = _malloc_crt(numargs * sizeof(_TSCHAR *) + numchars * sizeof(_TSCHAR));
129
        if (p == NULL)
130
            _amsg_exit(_RT_SPACEARG);
131
 
132
        /* store args and argv ptrs in just allocated block */
133
 
134
#ifdef WPRFLAG
135
        wparse_cmdline(cmdstart, (wchar_t **)p, (wchar_t *)(((char *)p) + numargs * sizeof(wchar_t *)), &numargs, &numchars);
136
#else  /* WPRFLAG */
137
        parse_cmdline(cmdstart, (char **)p, p + numargs * sizeof(char *), &numargs, &numchars);
138
#endif  /* WPRFLAG */
139
 
140
        /* set argv and argc */
141
        __argc = numargs - 1;
142
#ifdef WPRFLAG
143
        __wargv = (wchar_t **)p;
144
#else  /* WPRFLAG */
145
        __argv = (char **)p;
146
#endif  /* WPRFLAG */
147
 
148
#ifdef WILDCARD
149
 
150
        /* call _[w]cwild to expand wildcards in arg vector */
151
#ifdef WPRFLAG
152
        if (_wcwild())
153
#else  /* WPRFLAG */
154
        if (_cwild())
155
#endif  /* WPRFLAG */
156
            _amsg_exit(_RT_SPACEARG);   /* out of space */
157
 
158
#endif  /* WILDCARD */
159
}
160
 
161
 
162
/***
163
*static void parse_cmdline(cmdstart, argv, args, numargs, numchars)
164
*
165
*Purpose:
166
*       Parses the command line and sets up the argv[] array.
167
*       On entry, cmdstart should point to the command line,
168
*       argv should point to memory for the argv array, args
169
*       points to memory to place the text of the arguments.
170
*       If these are NULL, then no storing (only coujting)
171
*       is done.  On exit, *numargs has the number of
172
*       arguments (plus one for a final NULL argument),
173
*       and *numchars has the number of bytes used in the buffer
174
*       pointed to by args.
175
*
176
*Entry:
177
*       _TSCHAR *cmdstart - pointer to command line of the form
178
*           <progname><nul><args><nul>
179
*       _TSCHAR **argv - where to build argv array; NULL means don't
180
*                       build array
181
*       _TSCHAR *args - where to place argument text; NULL means don't
182
*                       store text
183
*
184
*Exit:
185
*       no return value
186
*       int *numargs - returns number of argv entries created
187
*       int *numchars - number of characters used in args buffer
188
*
189
*Exceptions:
190
*
191
*******************************************************************************/
192
 
193
#ifdef WPRFLAG
194
static void __cdecl wparse_cmdline (
195
#else  /* WPRFLAG */
196
static void __cdecl parse_cmdline (
197
#endif  /* WPRFLAG */
198
    _TSCHAR *cmdstart,
199
    _TSCHAR **argv,
200
    _TSCHAR *args,
201
    int *numargs,
202
    int *numchars
203
    )
204
{
205
        _TSCHAR *p;
206
        _TUCHAR c;
207
        int inquote;                    /* 1 = inside quotes */
208
        int copychar;                   /* 1 = copy char to *args */
209
        unsigned numslash;              /* num of backslashes seen */
210
 
211
        *numchars = 0;
212
        *numargs = 1;                   /* the program name at least */
213
 
214
        /* first scan the program name, copy it, and count the bytes */
215
        p = cmdstart;
216
        if (argv)
217
            *argv++ = args;
218
 
219
#ifdef WILDCARD
220
        /* To handle later wild card expansion, we prefix each entry by
221
        it's first character before quote handling.  This is done
222
        so _[w]cwild() knows whether to expand an entry or not. */
223
        if (args)
224
            *args++ = *p;
225
        ++*numchars;
226
 
227
#endif  /* WILDCARD */
228
 
229
        /* A quoted program name is handled here. The handling is much
230
           simpler than for other arguments. Basically, whatever lies
231
           between the leading double-quote and next one, or a terminal null
232
           character is simply accepted. Fancier handling is not required
233
           because the program name must be a legal NTFS/HPFS file name.
234
           Note that the double-quote characters are not copied, nor do they
235
           contribute to numchars. */
236
        if ( *p == DQUOTECHAR ) {
237
            /* scan from just past the first double-quote through the next
238
               double-quote, or up to a null, whichever comes first */
239
            while ( (*(++p) != DQUOTECHAR) && (*p != NULCHAR) ) {
240
 
241
#ifdef _MBCS
242
                if (_ismbblead(*p)) {
243
                    ++*numchars;
244
                    if ( args )
245
                        *args++ = *p++;
246
                }
247
#endif  /* _MBCS */
248
                ++*numchars;
249
                if ( args )
250
                    *args++ = *p;
251
            }
252
            /* append the terminating null */
253
            ++*numchars;
254
            if ( args )
255
                *args++ = NULCHAR;
256
 
257
            /* if we stopped on a double-quote (usual case), skip over it */
258
            if ( *p == DQUOTECHAR )
259
                p++;
260
        }
261
        else {
262
            /* Not a quoted program name */
263
            do {
264
                ++*numchars;
265
                if (args)
266
                    *args++ = *p;
267
 
268
                c = (_TUCHAR) *p++;
269
#ifdef _MBCS
270
                if (_ismbblead(c)) {
271
                    ++*numchars;
272
                    if (args)
273
                        *args++ = *p;   /* copy 2nd byte too */
274
                    p++;  /* skip over trail byte */
275
                }
276
#endif  /* _MBCS */
277
 
278
            } while ( c != SPACECHAR && c != NULCHAR && c != TABCHAR );
279
 
280
            if ( c == NULCHAR ) {
281
                p--;
282
            } else {
283
                if (args)
284
                    *(args-1) = NULCHAR;
285
            }
286
        }
287
 
288
        inquote = 0;
289
 
290
        /* loop on each argument */
291
        for(;;) {
292
 
293
            if ( *p ) {
294
                while (*p == SPACECHAR || *p == TABCHAR)
295
                    ++p;
296
            }
297
 
298
            if (*p == NULCHAR)
299
                break;              /* end of args */
300
 
301
            /* scan an argument */
302
            if (argv)
303
                *argv++ = args;     /* store ptr to arg */
304
            ++*numargs;
305
 
306
#ifdef WILDCARD
307
        /* To handle later wild card expansion, we prefix each entry by
308
        it's first character before quote handling.  This is done
309
        so _[w]cwild() knows whether to expand an entry or not. */
310
        if (args)
311
            *args++ = *p;
312
        ++*numchars;
313
 
314
#endif  /* WILDCARD */
315
 
316
        /* loop through scanning one argument */
317
        for (;;) {
318
            copychar = 1;
319
            /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
320
               2N+1 backslashes + " ==> N backslashes + literal "
321
               N backslashes ==> N backslashes */
322
            numslash = 0;
323
            while (*p == SLASHCHAR) {
324
                /* count number of backslashes for use below */
325
                ++p;
326
                ++numslash;
327
            }
328
            if (*p == DQUOTECHAR) {
329
                /* if 2N backslashes before, start/end quote, otherwise
330
                    copy literally */
331
                if (numslash % 2 == 0) {
332
                    if (inquote) {
333
                        if (p[1] == DQUOTECHAR)
334
                            p++;    /* Double quote inside quoted string */
335
                        else        /* skip first quote char and copy second */
336
                            copychar = 0;
337
                    } else
338
                        copychar = 0;       /* don't copy quote */
339
 
340
                    inquote = !inquote;
341
                }
342
                numslash /= 2;          /* divide numslash by two */
343
            }
344
 
345
            /* copy slashes */
346
            while (numslash--) {
347
                if (args)
348
                    *args++ = SLASHCHAR;
349
                ++*numchars;
350
            }
351
 
352
            /* if at end of arg, break loop */
353
            if (*p == NULCHAR || (!inquote && (*p == SPACECHAR || *p == TABCHAR)))
354
                break;
355
 
356
            /* copy character into argument */
357
#ifdef _MBCS
358
            if (copychar) {
359
                if (args) {
360
                    if (_ismbblead(*p)) {
361
                        *args++ = *p++;
362
                        ++*numchars;
363
                    }
364
                    *args++ = *p;
365
                } else {
366
                    if (_ismbblead(*p)) {
367
                        ++p;
368
                        ++*numchars;
369
                    }
370
                }
371
                ++*numchars;
372
            }
373
            ++p;
374
#else  /* _MBCS */
375
            if (copychar) {
376
                if (args)
377
                    *args++ = *p;
378
                ++*numchars;
379
            }
380
            ++p;
381
#endif  /* _MBCS */
382
            }
383
 
384
            /* null-terminate the argument */
385
 
386
            if (args)
387
                *args++ = NULCHAR;          /* terminate string */
388
            ++*numchars;
389
        }
390
 
391
        /* We put one last argument in -- a null ptr */
392
        if (argv)
393
            *argv++ = NULL;
394
        ++*numargs;
395
}
396
 
397