367 lines
8.7 KiB
C
367 lines
8.7 KiB
C
|
// Copyright (c) 1998-1999 Microsoft Corporation
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* SETARGVW.C (UNICODE argc, argv routines)
|
||
|
*
|
||
|
* argc / argv routines
|
||
|
*
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
/*
|
||
|
* Include files
|
||
|
*/
|
||
|
#include <windows.h>
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
/*
|
||
|
* UNICODE ARGS structure and other stuff (private).
|
||
|
*/
|
||
|
#include "setargvw.h"
|
||
|
|
||
|
/*
|
||
|
* Local function prototypes.
|
||
|
*/
|
||
|
void args_init( ARGS * );
|
||
|
int add_arg_to_list( WCHAR *, ARGS * );
|
||
|
int args_trunc( ARGS * );
|
||
|
|
||
|
/*
|
||
|
* setargvW()
|
||
|
*
|
||
|
* Forms a standard C-runtime argc, argv parsed command line.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* szModuleName (input)
|
||
|
* Optional Windows module name. If not NULL, will be added as first
|
||
|
* parsed argument (argv[0], argc=1).
|
||
|
* szCmdLine (input)
|
||
|
* Points to command line to parse into argc, argv
|
||
|
* argc (output)
|
||
|
* Points to int to save argument count into on exit.
|
||
|
* argv (output)
|
||
|
* Points to (WCHAR **) to save argv array into on exit.
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* ERROR_SUCCESS if ok; ERROR_xxx code if not ok.
|
||
|
*
|
||
|
* A typical use of this routine is by a Windows UI application to
|
||
|
* convert a command line into the C argc & argv variables prior to calling
|
||
|
* the utilsub.lib ParseCommandLine() function. Therefore, a companion
|
||
|
* routine, freeargv(), allows for alloc'd memory to be freed by the caller
|
||
|
* after use, if desired.
|
||
|
*
|
||
|
*/
|
||
|
int WINAPI
|
||
|
setargvW( LPWSTR szModuleName,
|
||
|
LPWSTR szCmdLine,
|
||
|
int *argc,
|
||
|
WCHAR ***argv )
|
||
|
{
|
||
|
int rc;
|
||
|
WCHAR *cp;
|
||
|
WCHAR FAR *cfp = szCmdLine;
|
||
|
WCHAR ch, fname[_MAX_PATH];
|
||
|
ARGS arg_data;
|
||
|
|
||
|
/*
|
||
|
* Initialize arg_data
|
||
|
*/
|
||
|
args_init( &arg_data );
|
||
|
|
||
|
/*
|
||
|
* If present, add module name as argv[0].
|
||
|
*/
|
||
|
if ( szModuleName ) {
|
||
|
if ( (rc = add_arg_to_list( szModuleName, &arg_data )) != ERROR_SUCCESS )
|
||
|
goto setargv_error;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Skip leading blanks/tabs of remaining args
|
||
|
*/
|
||
|
cp = fname;
|
||
|
/* skip consecutive blanks and/or tabs */
|
||
|
while ( (ch = *cfp) == L' ' || ch == L'\t' )
|
||
|
cfp++;
|
||
|
|
||
|
/*
|
||
|
* Process remainder of command line
|
||
|
*/
|
||
|
while ( ch = *cfp++ ) {
|
||
|
|
||
|
/*
|
||
|
* Process quoted strings.
|
||
|
*/
|
||
|
if ( ch == '"' ) {
|
||
|
while ( (ch = *cfp++) && ch != '"' )
|
||
|
*cp++ = ch;
|
||
|
if ( ch == '\0' )
|
||
|
cfp--;
|
||
|
|
||
|
/*
|
||
|
* If we find a delimeter, process the pathname we just scanned.
|
||
|
*/
|
||
|
} else if ( ch == ' ' || ch == '\t') {
|
||
|
*cp = '\0';
|
||
|
if ( (rc = add_arg_to_list( fname, &arg_data )) != ERROR_SUCCESS )
|
||
|
goto setargv_error;
|
||
|
|
||
|
cp = fname;
|
||
|
/* skip consecutive blanks and/or tabs */
|
||
|
while ( (ch = *cfp) == ' ' || ch == '\t')
|
||
|
cfp++;
|
||
|
|
||
|
/*
|
||
|
* All other chars, just copy to internal buffer.
|
||
|
*/
|
||
|
} else {
|
||
|
*cp++ = ch;
|
||
|
}
|
||
|
}
|
||
|
if ( cp != fname ) {
|
||
|
*cp = '\0';
|
||
|
if ( (rc = add_arg_to_list( fname, &arg_data )) != ERROR_SUCCESS )
|
||
|
goto setargv_error;
|
||
|
}
|
||
|
|
||
|
if ( (rc = args_trunc( &arg_data )) != ERROR_SUCCESS )
|
||
|
goto setargv_error;
|
||
|
|
||
|
/*
|
||
|
* Initialize global variables __argc and __argv
|
||
|
*/
|
||
|
*argc = arg_data.argc;
|
||
|
*argv = arg_data.argv;
|
||
|
|
||
|
return(ERROR_SUCCESS);
|
||
|
|
||
|
//--------------
|
||
|
// Error return
|
||
|
//--------------
|
||
|
setargv_error:
|
||
|
return(rc);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* freeargvW()
|
||
|
*
|
||
|
* Frees up the memory alloc'd for argv strings and argv
|
||
|
* array itself.
|
||
|
*
|
||
|
* ENTER:
|
||
|
* argv = argv array as created by this setargv() routine.
|
||
|
*
|
||
|
*/
|
||
|
void WINAPI
|
||
|
freeargvW( WCHAR **argv )
|
||
|
{
|
||
|
free(*argv);
|
||
|
free(argv);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* args_init()
|
||
|
*
|
||
|
* Initialize the ARGS struct passed as an argument.
|
||
|
*
|
||
|
* ENTER:
|
||
|
* argp = pointer to ARGS struct
|
||
|
*
|
||
|
*/
|
||
|
static void
|
||
|
args_init( ARGS *argp )
|
||
|
{
|
||
|
|
||
|
argp->argc = 0;
|
||
|
argp->argv = NULL;
|
||
|
argp->argvlen = 0;
|
||
|
argp->argvp = NULL;
|
||
|
argp->buflen = 0;
|
||
|
argp->buf = argp->bufptr = argp->bufend = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* add_arg_to_list()
|
||
|
*
|
||
|
* This routine adds the specified argument string to the argv array,
|
||
|
* and increments the argv pointer and argc counter.
|
||
|
* If necessary, memory for the argument string is allocated.
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* ERROR_SUCCESS if ok; ERROR_NOT_ENOUGH_MEMORY if not.
|
||
|
*
|
||
|
*/
|
||
|
static int
|
||
|
add_arg_to_list( WCHAR *arg_string,
|
||
|
ARGS *argp )
|
||
|
{
|
||
|
int len;
|
||
|
|
||
|
#ifdef notdef
|
||
|
wprintf( L"add_arg_to_list: arg_string=%s:, argc=%d, argvp=%x",
|
||
|
arg_string, argp->argc, argp->argvp );
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Verify we have an argv array buffer.
|
||
|
* If we have one but it is full, expand the array.
|
||
|
* If we can't alloc/realloc the array, return an error.
|
||
|
*/
|
||
|
if ( !argp->argv ) {
|
||
|
argp->argvlen = MIN_ARG_ALLOC;
|
||
|
argp->argc = 0;
|
||
|
argp->argv = malloc( argp->argvlen * sizeof( WCHAR *) );
|
||
|
argp->argvp = argp->argv;
|
||
|
} else if ( argp->argc + 1 >= argp->argvlen ) {
|
||
|
argp->argvlen += MIN_ARG_ALLOC;
|
||
|
argp->argv = realloc( argp->argv, argp->argvlen * sizeof(WCHAR *) );
|
||
|
argp->argvp = argp->argv + argp->argc;
|
||
|
}
|
||
|
if ( !argp->argv ) {
|
||
|
#ifdef notdef
|
||
|
wprintf( L"add_arg_to_list: failed to (re)alloc argv buf\n" );
|
||
|
#endif
|
||
|
goto add_arg_to_list_error;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Verify we have a string buffer to store the argument string.
|
||
|
* If we have one but there is not room for the new arg, expand the
|
||
|
* buffer. If we can't alloc/realloc the buffer, return an error.
|
||
|
*/
|
||
|
len = wcslen( arg_string ) + 1;
|
||
|
if ( !argp->buf ) {
|
||
|
argp->buflen = MIN_BUF_ALLOC;
|
||
|
while ( argp->buflen < len )
|
||
|
argp->buflen += MIN_BUF_ALLOC;
|
||
|
argp->buf = malloc( argp->buflen );
|
||
|
argp->bufptr = argp->buf;
|
||
|
argp->bufend = argp->buf + argp->buflen - 1;
|
||
|
|
||
|
} else if ( argp->bufptr + len > argp->bufend ) {
|
||
|
WCHAR *old_buf;
|
||
|
int buf_offset = (int)(argp->bufptr - argp->buf);
|
||
|
while ( argp->buflen < buf_offset + len )
|
||
|
argp->buflen += MIN_BUF_ALLOC;
|
||
|
old_buf = argp->buf;
|
||
|
argp->buf = realloc( argp->buf, argp->buflen );
|
||
|
argp->bufend = argp->buf + argp->buflen - 1;
|
||
|
argp->bufptr = argp->buf + buf_offset;
|
||
|
|
||
|
/*
|
||
|
* If the argument string buffer moved, then we need to relocate the
|
||
|
* argv pointers in the argv array to point to the new string locations.
|
||
|
*/
|
||
|
if ( argp->buf != old_buf ) {
|
||
|
WCHAR *buf_ptr, **argv_ptr;
|
||
|
argv_ptr = argp->argv;
|
||
|
buf_ptr = argp->buf;
|
||
|
|
||
|
while ( buf_ptr != argp->bufptr ) {
|
||
|
*argv_ptr++ = buf_ptr;
|
||
|
buf_ptr += wcslen( buf_ptr ) + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ( !argp->buf ) {
|
||
|
#ifdef notdef
|
||
|
wprintf( L"add_arg_to_list: failed to (re)alloc string buf\n" );
|
||
|
#endif
|
||
|
goto add_arg_to_list_error;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Add the new argument to the buffer and the argv array.
|
||
|
* Increment the arg count, the argv pointer, and the buffer pointer.
|
||
|
*/
|
||
|
wcscpy( argp->bufptr, arg_string );
|
||
|
*(argp->argvp) = argp->bufptr;
|
||
|
argp->bufptr += len;
|
||
|
++argp->argc;
|
||
|
++argp->argvp;
|
||
|
*(argp->argvp) = NULL;
|
||
|
return(ERROR_SUCCESS);
|
||
|
|
||
|
//--------------
|
||
|
// Error return
|
||
|
//--------------
|
||
|
add_arg_to_list_error:
|
||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* args_trunc()
|
||
|
*
|
||
|
* Truncate the memory used by the ARGS struct
|
||
|
* so that unused memory is freed.
|
||
|
*
|
||
|
* ENTER:
|
||
|
* argp = pointer to ARGS struct
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* ERROR_SUCCESS if ok; ERROR_NOT_ENOUGH_MEMORY code if not ok.
|
||
|
*
|
||
|
*/
|
||
|
static int
|
||
|
args_trunc( ARGS *argp )
|
||
|
{
|
||
|
WCHAR *old_buf;
|
||
|
|
||
|
/*
|
||
|
* call realloc to shrink size of argv array, set argvlen = argc
|
||
|
* to indicate no more room in argv array.
|
||
|
*/
|
||
|
argp->argvlen = argp->argc + 1;
|
||
|
argp->argv = realloc( argp->argv, argp->argvlen * sizeof(WCHAR *) );
|
||
|
if ( !argp->argv )
|
||
|
goto args_trunc_error;
|
||
|
argp->argvp = argp->argv + argp->argc;
|
||
|
|
||
|
/*
|
||
|
* call realloc to shrink size of argument string buffer, set bufend
|
||
|
* pointer to end of buffer to indicate buf is full.
|
||
|
*/
|
||
|
old_buf = argp->buf;
|
||
|
argp->buflen = (int)(argp->bufptr - argp->buf);
|
||
|
argp->buf = realloc( argp->buf, argp->buflen );
|
||
|
if ( !argp->buf )
|
||
|
goto args_trunc_error;
|
||
|
argp->bufptr = argp->buf + argp->buflen;
|
||
|
argp->bufend = argp->buf + argp->buflen - 1;
|
||
|
|
||
|
/*
|
||
|
* If the argument string buffer moved, then we need to relocate the
|
||
|
* argv pointers in the argv array to point to the new string locations.
|
||
|
*/
|
||
|
if ( old_buf != argp->buf ) {
|
||
|
WCHAR *buf_ptr, **argv_ptr;
|
||
|
|
||
|
argv_ptr = argp->argv;
|
||
|
buf_ptr = argp->buf;
|
||
|
while ( buf_ptr != argp->bufptr ) {
|
||
|
*argv_ptr++ = buf_ptr;
|
||
|
buf_ptr += wcslen( buf_ptr ) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(ERROR_SUCCESS);
|
||
|
|
||
|
//--------------
|
||
|
// Error return
|
||
|
//--------------
|
||
|
args_trunc_error:
|
||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|