Windows2003-3790/termsrv/admtools/utilsub/parse.c
2020-09-30 16:53:55 +02:00

626 lines
22 KiB
C

// Copyright (c) 1998-1999 Microsoft Corporation
/*****************************************************************************
*
* PARSE.C
*
* This module contains the code to implement generic parsing routines
* for utilities. There are several parsing routines included here.
*
* External Entry Points: (defined in utilsub.h)
*
* ParseCommandLineW()
* IsTokenPresentW()
* SetTokenPresentW()
* SetTokenNotPresentW()
*
*
****************************************************************************/
/* Get the standard C includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <winstaw.h>
#include <utilsub.h>
#include <expand.h>
// Verify that these are used internally, and do not rep. OS flags
// usage appears in parse.c and expand.c only
//
#define READ_ONLY 0x0001 /* file is read only */
#define HIDDEN 0x0002 /* file is hidden */
#define SYSTEM 0x0004 /* file is a system file */
#define VOLUME 0x0008 /* file is a volume label */
#define SUBDIR 0x0010 /* file is a subdirectory */
#define ARCHIVE 0x0020 /* file has archive bit on */
/*=============================================================================
== Local Functions Defined
============================================================================*/
static USHORT StoreArgument(PTOKMAPW, WCHAR *);
/*=============================================================================
== External Functions Used
============================================================================*/
/*=============================================================================
== Local Variables Used
============================================================================*/
ARGS arg_data;
/*=============================================================================
== Global Variables Used
============================================================================*/
VOID
SetBoolean(
PTOKMAPW TokenMap,
BOOL Value
)
{
//
// Folks pass in a variety of types and sizes as "boolean". Carefully
// perform the write based on the size of the token map: first clear the
// entire field, then (if Value != FALSE) set the only the first byte to
// TRUE.
//
ZeroMemory( TokenMap->tmAddr, TokenMap->tmDLen );
if (Value != FALSE) {
*((PCHAR)TokenMap->tmAddr) = TRUE;
}
}
/*****************************************************************************
*
* ParseCommandLineW (UNICODE version)
*
* This is the main function of the ParseCommandLine function. If the
* caller is passing argv from the main() function the caller is
* is responsible for pointing to argv[1], unless he wants this function
* to parse the program name (argv[0]).
*
* If the user wishes to parse an admin file it is necessary to massage
* the data into a form compatible with the command line arguements
* passed to a main() function before calling ParseCommandLine().
*
* ENTRY:
* argc - count of the command line arguments.
* argv - vector of strings containing the
* ptm - pointer to begining of the token map array
* flag - USHORT set of flags (see utilsub.h for flag descriptions).
*
* EXIT:
* Normal: ********** NOTE***********
* PARSE_FLAG_NO_ERROR * All errors returned *
* * from this function are *
* Error: * BIT flags and must be *
* PARSE_FLAG_NO_PARMS * converted by caller to *
* PARSE_FLAG_INVALID_PARM * OS/2+ ERRORS!!!! *
* PARSE_FLAG_TOO_MANY_PARMS ********** NOTE***********
* PARSE_FLAG_MISSING_REQ_FIELD
* ALGORITHM:
*
****************************************************************************/
USHORT WINAPI
ParseCommandLineW( INT argc,
WCHAR **argv,
PTOKMAPW ptm,
USHORT flag )
{
BOOL everyonespos = FALSE;
WCHAR *pChar;
USHORT rc, argi, found;
size_t tokenlen, arglen;
PTOKMAPW ptmtmp, nextpositional;
PFILELIST pFileList;
rc = PARSE_FLAG_NO_ERROR;
/*--------------------------------------------------------------------------
-- If there are no parameters inform the caller of this fact.
--------------------------------------------------------------------------*/
if(argc == 0) {
rc |= PARSE_FLAG_NO_PARMS;
return(rc);
}
/*--------------------------------------------------------------------------
-- Find the first positional parameter in the token map array, if any.
-- Also set the valid memory locations to '\0'.
--------------------------------------------------------------------------*/
nextpositional = NULL;
for(ptmtmp=ptm; ptmtmp->tmToken != NULL; ptmtmp++) {
if(ptmtmp->tmDLen && !(flag & PCL_FLAG_NO_CLEAR_MEMORY)) {
pChar = (WCHAR *) ptmtmp->tmAddr;
/*
* Clear the 'string' form fields for tmDLen*sizeof(WCHAR) bytes;
* all other forms to tmDLen bytes.
*/
if ( (ptmtmp->tmForm == TMFORM_S_STRING) ||
(ptmtmp->tmForm == TMFORM_DATE) ||
(ptmtmp->tmForm == TMFORM_PHONE) ||
(ptmtmp->tmForm == TMFORM_STRING) ||
(ptmtmp->tmForm == TMFORM_X_STRING) )
memset(pChar, L'\0', (ptmtmp->tmDLen*sizeof(WCHAR)));
else
memset(pChar, L'\0', ptmtmp->tmDLen);
}
if(ptmtmp->tmToken[0] != L'/' && ptmtmp->tmToken[0] != L'-' && nextpositional == NULL) {
nextpositional = ptmtmp;
}
}
/*--------------------------------------------------------------------------
-- Scan the argument array looking for /x or -x switches or positional
-- parameters. If a switch is found look it up in the token map array
-- and if found see if it has a trailing parameter of the format:
-- -x:foo || /x:foo || -x foo || /x foo
-- when found set the found flag and if there is a trailing parameter
-- store it at the location the user requested.
--
-- If it is not found in the token map array return the proper error
-- unless the user requests us to ignore it (PCL_FLAG_IGNORE_INVALID).
--
-- If it is a positional parameter enter it into the token map array if
-- there is room for it (i.e. nextpositional != NULL), if there is no
-- room for it then return the proper error.
--------------------------------------------------------------------------*/
for(argi=0; argi<argc;) {
if(everyonespos) {
if( (wcslen(nextpositional->tmAddr) + wcslen(argv[argi]) + 1) > nextpositional->tmDLen) {
rc |= PARSE_FLAG_TOO_MANY_PARMS;
return(rc);
}
wcscat((WCHAR *) nextpositional->tmAddr, L" ");
wcscat((WCHAR *) nextpositional->tmAddr, argv[argi]);
argi++;
}
else if(argv[argi][0] == L'/' || /* argument is a switch (/x or -x) */
argv[argi][0] == L'-') {
found = FALSE;
for(ptmtmp=ptm; ptmtmp->tmToken != NULL; ptmtmp++) {
/*-----------------------------------------------------------------
-- The string is found if a few requirements are met:
-- 1) The first N-1 characters are the same, where N is
-- the length of the string in the token map array.
-- We ignore the first character (could be '-' or '/').
-- 2) If the strings are not the same length, then the only
-- valid character after /x can be ':', this is only true
-- if the switch has a trailing parameter.
----------------------------------------------------------------*/
tokenlen = wcslen(ptmtmp->tmToken); /* get token length */
arglen = wcslen(argv[argi]); /* get argument length */
if(!(_wcsnicmp(&(ptmtmp->tmToken[1]), &(argv[argi][1]), tokenlen-1))) {
if(tokenlen != arglen) { /* not same length */
if(ptmtmp->tmForm != TMFORM_VOID && /* if trailing parm is */
argv[argi][tokenlen] == L':') {/* delemited with a ':' */
if(ptmtmp->tmFlag & TMFLAG_PRESENT) { /* seen already */
rc |= PARSE_FLAG_DUPLICATE_FIELD;
}
found = TRUE; /* then report it found. */
break;
}
}
else { /* all character same and */
if(ptmtmp->tmFlag & TMFLAG_PRESENT) { /* seen already */
rc |= PARSE_FLAG_DUPLICATE_FIELD;
}
found = TRUE; /* strings are the same */
break; /* len report it found. */
}
}
}
/* switch not found in token map array and not requested to ignore */
if(found != TRUE && !(flag & PCL_FLAG_IGNORE_INVALID)) {
rc |= PARSE_FLAG_INVALID_PARM;
if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
return(rc);
}
++argi;
}
else if (!found) {
++argi;
}
else { /* switch was found in token map array */
if(ptmtmp->tmForm == TMFORM_VOID) { /* no trailing parameter, done */
ptmtmp->tmFlag |= TMFLAG_PRESENT;
++argi;
}
else if(ptmtmp->tmForm == TMFORM_BOOLEAN) { /* need confirmation */
ptmtmp->tmFlag |= TMFLAG_PRESENT;
SetBoolean(ptmtmp, TRUE);
++argi;
}
else { /* has a trailing parameter */
if(argv[argi][tokenlen] == L':') { /* all in one switch (i.e. /x:foo) */
if(StoreArgument(ptmtmp, &(argv[argi][tokenlen+1]))) {
ptmtmp->tmFlag |= TMFLAG_PRESENT;
if(flag & PCL_FLAG_RET_ON_FIRST_SUCCESS) {
return(rc);
}
}
else {
rc |= PARSE_FLAG_INVALID_PARM;
if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
return(rc);
}
}
++argi; /* bump up to next argument */
}
else { /* two argument switch (i.e. /x foo) */
if ((++argi >= argc) ||
(argv[argi][0] == L'/') ||
(argv[argi][0] == L'-')) { /* bump up to trailing parm */
switch ( ptmtmp->tmForm ) {
case TMFORM_S_STRING:
case TMFORM_STRING:
ptmtmp->tmFlag |= TMFLAG_PRESENT;
pChar = (WCHAR *) ptmtmp->tmAddr;
pChar[0] = (WCHAR)NULL;
break;
default:
rc |= PARSE_FLAG_INVALID_PARM;
if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
return(rc);
}
break;
}
}
else if(StoreArgument(ptmtmp, argv[argi])) {
ptmtmp->tmFlag |= TMFLAG_PRESENT;
if(flag & PCL_FLAG_RET_ON_FIRST_SUCCESS) {
return(rc);
}
++argi; /* bump up to next argument */
}
else {
rc |= PARSE_FLAG_INVALID_PARM;
if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
return(rc);
}
++argi; /* bump up to next argument */
}
}
}
}
} /* endif - is switch */
else { /* argument is a positional parmater*/
if(nextpositional == NULL) { /* if there are no positional left */
rc |= PARSE_FLAG_TOO_MANY_PARMS;
if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
return(rc);
}
}
else { /* set positional in token array **/
/*
* Is the current PTM the start of TMFORM_FILES?
*/
if (nextpositional->tmForm == TMFORM_FILES) {
nextpositional->tmFlag |= TMFLAG_PRESENT;
args_init(&arg_data, MAX_ARG_ALLOC);
do {
/*
* If no match was found then return the current id.
*/
// if (!expand_path(argv[argi], (HIDDEN|SYSTEM), &arg_data)) {
// arg_data.argc--;
// arg_data.argvp--;
// }
expand_path(argv[argi], (HIDDEN|SYSTEM), &arg_data);
} while (++argi<argc);
pFileList = (PFILELIST) nextpositional->tmAddr;
pFileList->argc = arg_data.argc;
pFileList->argv = &arg_data.argv[0];
return (rc);
}
else if(StoreArgument(nextpositional, argv[argi])) {
nextpositional->tmFlag |= TMFLAG_PRESENT;
if(flag & PCL_FLAG_RET_ON_FIRST_SUCCESS) {
return(rc);
}
/*--------------------------------------------------------------
-- if this is an X_STRING then every thing from now on is
-- going to be a concatenated string
--------------------------------------------------------------*/
if(nextpositional->tmForm == TMFORM_X_STRING) {
everyonespos = TRUE;
}
else {
for(++nextpositional; nextpositional->tmToken!=NULL; nextpositional++) {
if(nextpositional->tmToken[0] != L'/' && nextpositional->tmToken[0] != L'-') {
break;
}
}
if(nextpositional->tmToken == NULL) { /* ran out of PP */
nextpositional = NULL;
}
}
}
else { /* invalid PP */
rc |= PARSE_FLAG_INVALID_PARM;
if(!(flag & PCL_FLAG_CONTINUE_ON_ERROR)) {
return(rc);
}
}
}
argi++;
}
}
for(ptmtmp=ptm; ptmtmp->tmToken!=NULL; ptmtmp++) {
if(ptmtmp->tmFlag & TMFLAG_REQUIRED && !(ptmtmp->tmFlag & TMFLAG_PRESENT)) {
rc |= PARSE_FLAG_MISSING_REQ_FIELD;
break;
}
}
return(rc);
} // end ParseCommandLineW
/*****************************************************************************
*
* IsTokenPresentW (UNICODE version)
*
* Determines if a specified command line token (in given TOKMAPW array)
* was present on the command line.
*
* ENTRY:
* ptm (input)
* Points to 0-terminated TOKMAPW array to scan.
* pToken (input)
* The token to scan for.
*
* EXIT:
* TRUE if the specified token was present on the command line;
* FALSE otherwise.
*
****************************************************************************/
BOOLEAN WINAPI
IsTokenPresentW( PTOKMAPW ptm,
PWCHAR pToken )
{
int i;
for ( i = 0; ptm[i].tmToken; i++ ) {
if ( !wcscmp( ptm[i].tmToken, pToken ) )
return( (ptm[i].tmFlag & TMFLAG_PRESENT) ? TRUE : FALSE );
}
return(FALSE);
} // end IsTokenPresentW
/*****************************************************************************
*
* SetTokenPresentW (UNICODE version)
*
* Forces a specified command line token (in given TOKMAPW array)
* to be flagged as 'present' on the command line.
*
* ENTRY:
* ptm (input)
* Points to 0-terminated TOKMAPW array to scan.
* pToken (input)
* The token to scan for and set flags.
*
* EXIT:
* TRUE if the specified token was found in the TOKMAPW array
* (TMFLAG_PRESENT flag is set). FALSE otherwise.
*
****************************************************************************/
BOOLEAN WINAPI
SetTokenPresentW( PTOKMAPW ptm,
PWCHAR pToken )
{
int i;
for ( i = 0; ptm[i].tmToken; i++ ) {
if ( !wcscmp( ptm[i].tmToken, pToken ) ) {
ptm[i].tmFlag |= TMFLAG_PRESENT;
return(TRUE);
}
}
return(FALSE);
} // end SetTokenPresentW
/*****************************************************************************
*
* SetTokenNotPresentW (UNICODE version)
*
* Forces a specified command line token (in given TOKMAPW array)
* to be flagged as 'not present' on the command line.
*
* ENTRY:
* ptm (input)
* Points to 0-terminated TOKMAPW array to scan.
* pToken (input)
* The token to scan for and set flags.
*
* EXIT:
* TRUE if the specified token was found in the TOKMAPW array
* (TMFLAG_PRESENT flag is reset). FALSE otherwise.
*
****************************************************************************/
BOOLEAN WINAPI
SetTokenNotPresentW( PTOKMAPW ptm,
PWCHAR pToken )
{
int i;
for ( i = 0; ptm[i].tmToken; i++ ) {
if ( !wcscmp( ptm[i].tmToken, pToken ) ) {
ptm[i].tmFlag &= ~TMFLAG_PRESENT;
return(TRUE);
}
}
return(FALSE);
} // end SetTokenNotPresentW
/*****************************************************************************
*
* StoreArgument:
*
* ENTRY:
* ptm - a pointer to an entry in the token array map
* s - the argument to be entered into the current token array map entry.
*
* EXIT:
* Normal:
* TRUE
*
* Error:
* FALSE
*
* ALGORITHM:
*
****************************************************************************/
USHORT
StoreArgument( PTOKMAPW ptm,
WCHAR *s )
{
char *pByte;
WCHAR *pChar;
SHORT *pShort;
USHORT *pUShort;
LONG *pLong;
ULONG *pULong;
WCHAR *pEnd = s; //pointer to end of conversion
/*
* If the string is empty, allow it for real 'strings'!
*/
if( !wcslen(s) ) {
switch ( ptm->tmForm ) {
case TMFORM_S_STRING:
case TMFORM_STRING:
pChar = (WCHAR *) ptm->tmAddr;
pChar[0] = (WCHAR)NULL;
return( TRUE );
}
return( FALSE );
}
/*
* Fail if there is no room to store result.
*/
if ( ptm->tmDLen == 0) {
return(FALSE);
}
switch(ptm->tmForm) {
case TMFORM_BOOLEAN:
SetBoolean(ptm, TRUE);
break;
case TMFORM_BYTE:
pByte = (BYTE *) ptm->tmAddr;
*pByte = (BYTE) wcstol(s, &pEnd, 10);
if (pEnd == s)
{
return FALSE;
}
break;
case TMFORM_CHAR:
pChar = (WCHAR *) ptm->tmAddr;
*pChar = s[0];
break;
case TMFORM_S_STRING:
if (*s == L'\\') {
++s;
}
case TMFORM_DATE:
case TMFORM_PHONE:
case TMFORM_STRING:
case TMFORM_X_STRING:
//Added by a-skuzin
//case when we need parameter to start with '-' or '/' and use "\-" or"\/"
if(s[0]==L'\\' && (s[1]==L'-' || s[1]==L'/' || s[1]==L'\\') ) {
++s;
}
//end of "added by a-skuzin"
pChar = (WCHAR *) ptm->tmAddr;
wcsncpy(pChar, s, ptm->tmDLen);
break;
case TMFORM_SHORT:
pShort = (SHORT *) ptm->tmAddr;
*pShort = (SHORT) wcstol(s, &pEnd, 10);
if (pEnd == s)
{
return FALSE;
}
break;
case TMFORM_USHORT:
if ( s[0] == L'-') { /* no negative numbers! */
return( FALSE );
}
pUShort = (USHORT *) ptm->tmAddr;
*pUShort = (USHORT) wcstol(s, &pEnd, 10);
if (pEnd == s)
{
return FALSE;
}
break;
case TMFORM_LONG:
pLong = (LONG *) ptm->tmAddr;
*pLong = wcstol(s, &pEnd, 10);
if (pEnd == s)
{
return FALSE;
}
break;
case TMFORM_SERIAL:
case TMFORM_ULONG:
if ( s[0] == L'-') { /* no negative numbers! */
return (FALSE);
}
pULong = (ULONG *) ptm->tmAddr;
*pULong = (ULONG) wcstol(s, &pEnd, 10);
if (pEnd == s)
{
return FALSE;
}
break;
case TMFORM_HEX:
if ( s[0] == L'-') { /* no negative numbers! */
return( FALSE );
}
pUShort = (USHORT *) ptm->tmAddr;
*pUShort = (USHORT) wcstoul(s,NULL,16);
break;
case TMFORM_LONGHEX:
if ( s[0] == L'-') { /* no negative numbers! */
return( FALSE );
}
pULong = (ULONG *) ptm->tmAddr;
*pULong = wcstoul(s,NULL,16);
break;
default: /* if invalid format return FALSE */
return(FALSE);
break;
}
return(TRUE);
}