windows-nt/Source/XPSP1/NT/termsrv/admtools/utilsub/setargvw.c
2020-09-26 16:20:57 +08:00

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);
}