summaryrefslogtreecommitdiffstats
path: root/private/crt32/startup/stdargv.c
blob: e75e98b7759f0d96909993551aa36014d93be47c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
/***
*stdargv.c - standard & wildcard _setargv routine
*
*	Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
*
*Purpose:
*	processes program command line, with or without wildcard expansion
*
*Revision History:
*	06-27-89  PHG	module created, based on asm version
*	04-09-90  GJF	Added #include <cruntime.h>. Made calling types
*			explicit (_CALLTYPE1 or _CALLTYPE4). Also, fixed the
*			copyright.
*	06-04-90  GJF	Changed error message interface.
*	08-31-90  GJF	Removed 32 from API names.
*	09-25-90  GJF	Merged tree version with local version (8-31 change
*			with 6-4 change).
*	10-08-90  GJF	New-style function declarators.
*       12-04-90  SRW   Changed to include <oscalls.h> instead of <doscalls.h>
*       12-06-90  SRW   Added _CRUISER_ and _WIN32 conditionals.
*       01-25-91  SRW   Include oscalls.h if _WIN32_ OR WILDCARD defined
*       01-25-91  SRW   Changed Win32 Process Startup [_WIN32_]
*	01-25-91  MHL	Fixed bug in Win32 Process Startup [_WIN32_]
*	01-28-91  GJF	Fixed call to DOSFINDFIRST (removed last arg).
*       01-31-91  MHL   Changed to call GetModuleFileName instead of NtCurrentPeb() [_WIN32_]
*	02-18-91  SRW	Fixed command line parsing bug [_WIN32_]
*	03-11-91  GJF	Fixed check of FindFirstFile return [_WIN32_].
*	03-12-91  SRW	Add FindClose call to _find [_WIN32_]
*	04-16-91  SRW	Fixed quote parsing logic for arguments.
*	03-31-92  DJM	POSIX support.
*	05-12-92  DJM	ifndefed for POSIX.
*	06-02-92  SKS	Add #include <dos.h> for CRTDLL definition of _pgmptr
*	04-19-93  GJF	Change test in the do-while loop in parse_cmdline to
*			NOT terminate on chars with high bit set.
*	05-14-93  GJF	Added support for quoted program names.
*	05-28-93  KRS	Added MBCS support under _MBCS switches.
*	06-04-93  KRS	Added more MBCS logic.
*
*******************************************************************************/

#ifndef _POSIX_

#include <cruntime.h>
#include <internal.h>
#include <rterr.h>
#include <stdlib.h>
#if defined(WILDCARD) || defined(_WIN32_)
#include <dos.h>
#include <oscalls.h>
#endif
#ifdef _MBCS
#include <mbctype.h>
#endif

static void _CRTAPI3 parse_cmdline(char *cmdstart, char **argv, char *args,
	int *numargs, int *numbytes);

/***
*_setargv, __setargv - set up "argc" and "argv" for C programs
*
*Purpose:
*	Read the command line and create the argv array for C
*	programs.
*
*Entry:
*	Arguments are retrieved from the program command line,
*	pointed to by _acmdln.
*
*Exit:
*	"argv" points to a null-terminated list of pointers to ASCIZ
*	strings, each of which is an argument from the command line.
*	"argc" is the number of arguments.  The strings are copied from
*	the environment segment into space allocated on the heap/stack.
*	The list of pointers is also located on the heap or stack.
*	_pgmptr points to the program name.
*
*Exceptions:
*	Terminates with out of memory error if no memory to allocate.
*
*******************************************************************************/

#ifdef WILDCARD
void _CRTAPI1 __setargv (
#else
void _CRTAPI1 _setargv (
#endif
    void
    )
{
    char *p;
    char *cmdstart;		    /* start of command line to parse */
    int numargs, numbytes;

#ifdef	_CRUISER_

    /* OS/2 sets up memory like this:
    <nul><full path of program><nul><prog name as typed><nul><arguments><nul>
				     ^
				     _acmdline
    */

    /* first we set _pgmptr to point to the full name of program */
    p = _acmdln - 1;
    while (*(p-1) != '\0')
	--p;
    _pgmptr = p;

#else	/* ndef _CRUISER_ */

#if defined(_WIN32_)
    static char _pgmname[ MAX_PATH ];

    /* Get the program name pointer from Win32 Base */

    GetModuleFileName( NULL, _pgmname, sizeof( _pgmname ));
    _pgmptr = _pgmname;

#else	/* ndef _WIN32_ */

#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!

#endif	/* _WIN32_ */

#endif	/* _CRUISER_ */

    /* if there's no command line at all (won't happen from cmd.exe, but
       possibly another program), then we use _pgmptr as the command line
       to parse, so that argv[0] is initialized to the program name */
    cmdstart = (*_acmdln == '\0') ? _pgmptr : _acmdln;

    /* first find out how much space is needed to store args */
    parse_cmdline(cmdstart, NULL, NULL, &numargs, &numbytes);

    /* allocate space for argv[] vector and strings */
    p = malloc(numargs * sizeof(char *) + numbytes);
    if (p == NULL)
	_amsg_exit(_RT_SPACEARG);

    /* store args and argv ptrs in just allocated block */
    parse_cmdline(cmdstart, (char **)p, p + numargs * sizeof(char *), &numargs, &numbytes);

    /* set argv and argc */
    __argc = numargs - 1;
    __argv = (char **)p;
#ifdef WILDCARD
    /* call _cwild to expand wildcards in arg vector */
    if (_cwild())
	_amsg_exit(_RT_SPACEARG);	/* out of space */
#endif
}


/***
*static void parse_cmdline(cmdstart, argv, args, numargs, numbytes)
*
*Purpose:
*	Parses the command line and sets up the argv[] array.
*	On entry, cmdstart should point to the command line,
*	argv should point to memory for the argv array, args
*	points to memory to place the text of the arguments.
*	If these are NULL, then no storing (only coujting)
*	is done.  On exit, *numargs has the number of
*	arguments (plus one for a final NULL argument),
*	and *numbytes has the number of bytes used in the buffer
*	pointed to by args.
*
*Entry:
*	char *cmdstart - pointer to command line of the form
*	    <progname><nul><args><nul>
*	char **argv - where to build argv array; NULL means don't
*			build array
*	char *args - where to place argument text; NULL means don't
*			store text
*
*Exit:
*	no return value
*	int *numargs - returns number of argv entries created
*	int *numbytes - number of bytes used in args buffer
*
*Exceptions:
*
*******************************************************************************/

static void _CRTAPI3 parse_cmdline (
    char *cmdstart,
    char **argv,
    char *args,
    int *numargs,
    int *numbytes
    )
{
    char *p;
    unsigned char c;
    int inquote;		    /* 1 = inside quotes */
    int copychar;		    /* 1 = copy char to *args */
    unsigned numslash;		    /* num of backslashes seen */

    *numbytes = 0;
    *numargs = 1;	    /* the program name at least */

    /* first scan the program name, copy it, and count the bytes */
    p = cmdstart;
    if (argv)
	*argv++ = args;
#ifdef WILDCARD
    /* To handle later wild card expansion, we prefix each entry by
       it's first character before quote handling.  This is done
       so _cwild() knows whether to expand an entry or not. */
    if (args)
	*args++ = *p;
    ++*numbytes;

#endif	/* WILDCARD */
    /* A quoted program name is handled here. The handling is much
       simpler than for other arguments. Basically, whatever lies
       between the leading double-quote and next one, or a terminal null
       character is simply accepted. Fancier handling is not required
       because the program name must be a legal NTFS/HPFS file name.
       Note that the double-quote characters are not copied, nor do they
       contribute to numbytes. */
    if ( *p == '\"' ) {
	/* scan from just past the first double-quote through the next
	   double-quote, or up to a null, whichever comes first */
	while ( (*(++p) != '\"') && (*p != '\0') ) {
	
#ifdef _MBCS
	    if (_ismbblead(*p)) {
		*numbytes += 2;
		if ( args ) {
		    *args++ = *p++;
		    *args++ = *p;
		}
	    }
	    else {
#endif
	    ++*numbytes;
	    if ( args )
		*args++ = *p;
#ifdef _MBCS
	    }
#endif
	}
	/* append the terminating null */
	++*numbytes;
	if ( args )
	    *args++ = '\0';

	/* if we stopped on a double-quote (usual case), skip over it */
	if ( *p == '\"' )
	    p++;
    }
    else {
	/* Not a quoted program name */
	do {
	    ++*numbytes;
	    if (args)
		*args++ = *p;
#ifdef	_CRUISER_

	} while (*p++ != '\0');

#else	/* ndef _CRUISER_ */

#ifdef _WIN32_

	    c = (unsigned char) *p++;
#ifdef _MBCS
	    if (_ismbblead(c)) {
		++*numbytes;
		if (args)
		    *args++ = *p;	/* copy 2nd byte too */
		p++;  /* skip over trail byte */
	    }
#endif

	} while ( c > ' ' );

	if ( c == '\0' ) {
	    p--;
	} else {
	    if (args)
		*(args-1) = '\0';
	}
    }
#else	/* ndef _WIN32_ */

#error ERROR - ONLY CRUISER, OR WIN32 TARGET SUPPORTED!

#endif	/* _WIN32_ */

#endif	/* _CRUISER_ */

    inquote = 0;

    /* loop on each argument */
    for(;;) {

#ifdef	_CRUISER_
	/* skip blanks */
	while (*p == ' ' || *p == '\t')
	    ++p;

#else	/* ndef _CRUISER_ */

#ifdef _WIN32_
        if ( *p ) {
	    while (*p == ' ' || *p == '\t')
	        ++p;
        }
#else	/* ndef _WIN32_ */

#error ERROR - ONLY CRUISER, OR WIN32 TARGET SUPPORTED!

#endif	/* _WIN32_ */

#endif	/* _CRUISER_ */

	if (*p == '\0')
	    break;		    /* end of args */

	/* scan an argument */
	if (argv)
	    *argv++ = args;	    /* store ptr to arg */
	++*numargs;

#ifdef WILDCARD
	/* To handle later wild card expansion, we prefix each entry by
	   it's first character before quote handling.  This is done
	   so _cwild() knows whether to expand an entry or not. */
	if (args)
	    *args++ = *p;
	++*numbytes;

#endif	/* WILDCARD */

	/* loop through scanning one argument */
	for (;;) {
            copychar = 1;
	    /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
		      2N+1 backslashes + " ==> N backslashes + literal "
		      N backslashes ==> N backslashes */
	    numslash = 0;
	    while (*p == '\\') {
		/* count number of backslashes for use below */
		++p;
		++numslash;
	    }
	    if (*p == '\"') {
		/* if 2N backslashes before, start/end quote, otherwise
		   copy literally */
		if (numslash % 2 == 0) {
                    if (inquote)
                        if (p[1] == '\"')
                            p++;    /* Double quote inside quoted string */
                        else        /* skip first quote char and copy second */
                            copychar = 0;
                    else
                        copychar = 0;       /* don't copy quote */

		    inquote = !inquote;
		}
		numslash /= 2;		/* divide numslash by two */
	    }

	    /* copy slashes */
	    while (numslash--) {
		if (args)
		    *args++ = '\\';
		++*numbytes;
	    }

	    /* if at end of arg, break loop */
	    if (*p == '\0' || (!inquote && (*p == ' ' || *p == '\t')))
		break;

	    /* copy character into argument */
#ifdef _MBCS
            if (copychar) {
                if (args) {
                    if (_ismbblead(*p)) {
                        *args++ = *p++;
                        ++*numbytes;
                    }
                    *args++ = *p;
                } else {
                    if (_ismbblead(*p)) {
                        ++p;
                        ++*numbytes;
                    }
                }   
                ++*numbytes;
            }
            ++p;
#else 
            if (copychar) {
	        if (args)
	        	*args++ = *p;
	        ++*numbytes;
            }
            ++p;
#endif 
	}

	/* null-terminate the argument */

	if (args)
	    *args++ = '\0';	    /* terminate string */
	++*numbytes;
    }

    /* We put one last argument in -- a null ptr */
    if (argv)
	*argv++ = NULL;
    ++*numargs;
}


#ifdef WILDCARD
/***
*_find(pattern) - find matching filename
*
*Purpose:
*	if argument is non-null, do a DOSFINDFIRST on that pattern
*	otherwise do a DOSFINDNEXT call.  Return matching filename
*	or NULL if no more matches.
*
*Entry:
*	pattern = pointer to pattern or NULL
*	    (NULL means find next matching filename)
*
*Exit:
*	returns pointer to matching file name
*	    or NULL if no more matches.
*
*Exceptions:
*
*******************************************************************************/

char * _CRTAPI1 _find (
    char *pattern
    )
{
    char *retval;

#ifdef	_CRUISER_
    static FILEFINDBUF findbuf;
    HDIR findhandle = HDIR_SYSTEM;
    ULONG findcount = 1;
    int rc;

    if (pattern)
	rc = DOSFINDFIRST(pattern, &findhandle, FILE_NORMAL | FILE_DIRECTORY,
			    &findbuf, sizeof(findbuf), &findcount, 1L);
    else
	rc = DOSFINDNEXT(findhandle, &findbuf, sizeof(findbuf), &findcount);

    retval = rc ? NULL : findbuf.achName;

#else	/* ndef _CRUISER_ */

#ifdef _WIN32_

    static HANDLE _WildFindHandle;
    static LPWIN32_FIND_DATA findbuf;

    if (pattern) {
        if (findbuf == NULL)
            findbuf = (LPWIN32_FIND_DATA)malloc(MAX_PATH + sizeof(*findbuf));

        if (_WildFindHandle != NULL) {
            (void)FindClose( _WildFindHandle );
            _WildFindHandle = NULL;
        }

        _WildFindHandle = FindFirstFile( (LPSTR)pattern, findbuf );
	if (_WildFindHandle == (HANDLE)0xffffffff)
            return NULL;
    }
    else
        if (!FindNextFile( _WildFindHandle, findbuf )) {
            (void)FindClose( _WildFindHandle );
            _WildFindHandle = NULL;
            return NULL;
        }

    retval = findbuf->cFileName;

#else	/* ndef _WIN32_ */

#error ERROR - ONLY CRUISER, OR WIN32 TARGET SUPPORTED!

#endif	/* _WIN32_ */

#endif	/* _CRUISER_ */

    return retval;
}

#endif /* WILDCARD */

#endif /* ndef _POSIX_ */