Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

459 lines
11 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2001.
//
// File: cmdkey: command.cpp
//
// Contents: Command line parsing functions
//
// Classes:
//
// Functions:
//
// History: 07-09-01 georgema Created
//
//----------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "command.h"
#include "switches.h"
#ifdef CLPARSER
WCHAR szsz[500];
#define ODS(x) OutputDebugString(x)
#endif
static BOOL *pf = NULL;
static INT iMaxCommand = -1;
static INT iFirstCommand = -1;
static WCHAR *pModel = NULL;
static WCHAR **pprgc = NULL;
static WCHAR *pCmdline = NULL;
static INT cSwitches = 0;
static BOOL fExtra = FALSE;
static WCHAR rgcAll[] = {L"abcdefghijklmnopqrstuvwxyz?0123456789"};
#define ccAll (sizeof(rgcAll) / sizeof(WCHAR))
// -------------------------------------------------------------------------
//
// Command Parser exports
//
// -------------------------------------------------------------------------
// Get access to the command switches model and the count of valid switches
// Create variables for use by the parser
BOOL CLInit(void)
{
return CLInit((INT) ccAll,rgcAll);
}
BOOL CLInit(INT ccSwitches, WCHAR *prgc)
{
if (NULL == prgc) return FALSE;
if (0 >= ccSwitches) return FALSE;
// note that GetCommandLine() does not return any cr/lf at the end of the string, just NULL.
pCmdline = GetCommandLineW();
#ifdef CLPARSER
swprintf(szsz,L"CMDKEY: Command line :%s\n",pCmdline);
ODS(szsz);
#endif
pModel = prgc;
cSwitches = ccSwitches;
// accept a count of switches, generate the appropriate
// intermediate variables for the parser
pprgc = (WCHAR **) malloc(sizeof(WCHAR*) * (cSwitches + 1));
if (NULL == pprgc) return FALSE;
pf = (BOOL *) malloc(sizeof(BOOL) * (cSwitches + 1));
if (NULL == pf) return FALSE;
for (INT i=0;i<cSwitches;i++)
{
pprgc[i] = NULL;
pf[i] = FALSE;
}
return TRUE;
}
// Scan for switches, detecting extraneous ones, and setting the switchpresent flag
// and the switch argument data pointer as appropriate.
//
// Parsing will return failed in the case of finding a duplicate of a switch already
// encountered. In many cases, that can lead to ambiguity. This should be pretty
// uncommon, and will always result from bad input from the user.
BOOL CLParse(void)
{
BOOL fOK = TRUE;
WCHAR *pc = pCmdline;
WCHAR *pa = NULL;
WCHAR c = 0;
INT i = 0;
WCHAR last = 0x0;
#ifdef CLPARSER
WCHAR sz[] = {L" "};
#endif
#ifdef CLPARSER
ODS(L"CMDKEY: Scanning for all switches : ");
#endif
while (0 != (c = *pc++))
{
// char found on command line
if ((c == '/') || (c == '-'))
{
if (last != ' ')
{
// Only valid switchchar if preceded by a space
//last = c;
continue;
}
c = *pc; // fetch next character
if (0 == c) break; // break on end of line
#ifdef CLPARSER
sz[0] = c;
ODS(sz);
#endif
for (i=0; i<cSwitches;i++)
{
c |= 0x20; // force to lower case
if (c == pModel[i]) break; // break the for for char OK
}
if ( i!= cSwitches )
{
if (pf[i])
{
#ifdef CLPARSER
ODS(L"(duplicate!)");
#endif
fOK = FALSE;
break; // fatal parse error - dup switch
}
pf[i] = TRUE;
if (iFirstCommand < 0)
{
if (i <= iMaxCommand)
{
iFirstCommand = i;
#ifdef CLPARSER
ODS(L"!");
#endif
}
}
pa = FetchSwitchString(pc);
if (NULL != pa)
{
pprgc[i] = pa;
#ifdef CLPARSER
swprintf(szsz,L"(%s)",pa);
ODS(szsz);
#endif
}
}
#ifdef PICKY
else
{
// once you find an extraneous switch, cease looking
#ifdef CLPARSER
ODS(L" (*bad*)");
#endif
fExtra = TRUE;
break; // get out of while
}
#endif // PICKY
#ifdef CLPARSER
ODS(L" ");
#endif
}
last = c;
}
#ifdef CLPARSER
ODS(L"\n");
#endif
return fOK;
}
INT
CLSetMaxPrincipalSwitch(INT i)
{
INT iOld = iMaxCommand;
iMaxCommand = i;
return iOld;
}
INT
CLGetPrincipalSwitch(void)
{
return iFirstCommand;
}
// Return TRUE if extraneous switches found
BOOL CLExtra(void)
{
return fExtra;
}
// Return TRUE if the indexed switch was found
BOOL CLFlag(INT i)
{
if (i > cSwitches) return FALSE;
if (i < 0) return FALSE;
return pf[i];
}
// Returns a pointer to a copy of the switch argument data, or NULL if the switch had no data following
WCHAR *CLPtr(INT i)
{
if (i > cSwitches) return NULL;
if (i < 0) return NULL;
return pprgc[i];
}
// Free allocated parser variables
void CLUnInit(void)
{
for (INT i=0;i<cSwitches;i++)
{
if (pprgc[i] != NULL) free((void *) pprgc[i]);
}
if (pprgc) free((void *)pprgc);
if (pf) free((void *)pf);
}
// -------------------------------------------------------------------------
//
// Switch Parsing group
//
// -------------------------------------------------------------------------
// Fetch switch argument after finding switch. Ret ptr to
// first non-whitespace char, place null after last non-whitespace
// char. In the case of quotes, return ptr to 1st char after quote
// and place null over last quote.
//
// Note that whitespace seems to be specifically 0x20. Tabs do not seem to be
// returned from command lines
//
// Place two pointers, one at the beginning, one at the end, work from
// there.
//
// Caller should use the value and then free the string.
WCHAR *FetchSwitchString(WCHAR *origin)
{
WCHAR *p1;
WCHAR *p2;
WCHAR c;
WCHAR l = 0;
BOOL fQ = FALSE;
INT_PTR iLen;
WCHAR *pBuf;
if (NULL == origin) return NULL;
p1 = origin;
// walk to end of switchstring itself
while (1 )
{
c = *p1;
if (c == 0) return NULL; // eol before arg found
// skip to end of switch token
if (c == ':') break; // end of switch
if (c == 0x20) break; // end of switch
if (c == '/') return NULL; // next switch before arg found
if (c == '-') return NULL;
p1++;
l = c;
}
p1++;
// walk to beginning of the switch argument
// eat spaces, step over begin quotes
while (1 )
{
c = *p1;
if (c == '"')
{
fQ = TRUE;
p1++;
l = c;
break;
}
else if (c == 0) return NULL; // did not find an arg
else if (c == '/') return NULL;
else if (c == '-') return NULL;
else if (c > 0x20) break;
p1++;
l = c;
}
// p1 now pointed to root char of switch arg itself
// fQ set if in a quoted string
// Find the end of the arg string
// If a quoted string, only a quote or EOL ends it
// else ended by EOL, switchchar or quote
p2 = p1;
while (1)
{
c = *p2;
if (fQ)
{
if (c == 0) break;
if (c == '"') break;
}
else
{
if (c == 0) break;
// Encountering the next switch terminates the string only if the
// switch char is preceded by a space (valid switchchar)
if (l == ' ')
{
if (c == '/') break;
if (c == '-') break;
}
// disallow embedded quotes
if (c == '"') return NULL;
}
p2++;
l = c;
}
p2--; // ptr to last valid char in arg string
// now back up until you hit the first printable character, IFF the tail ptr is not already
// coincident with the head ptr. In that case, the string length is 1
while (p2 > p1)
{
c = *p2;
if (c > 0x20) break;
p2--;
}
iLen = p2 - p1;
pBuf = (WCHAR *) malloc(iLen * sizeof(WCHAR) + 2 * sizeof(WCHAR));
if (pBuf)
{
memset(pBuf,0,iLen * sizeof(WCHAR) + 2 * sizeof(WCHAR));
wcsncpy(pBuf,p1,iLen + 1);
}
return pBuf;
}
// Return a count of tokens on the command line. The executable name by itself makes 1, so the
// return value is never zero.
int
CLTokens(void)
{
BOOL fQ = FALSE;
WCHAR *p1 = pCmdline;
int i = 0;
WCHAR c;
// walk to beginning of the switch argument
while (1)
{
while (1 )
{
c = *p1;
// handle in and out of quote mode
if (fQ)
if (c == '"')
{
fQ = FALSE; // empty quotation
p1++;
break;
}
if (c == '"')
{
fQ = TRUE;
}
// exit at end of string only
else if (c == 0) return ++i; // did not find an arg
// space between tokens
else if (c <= 0x20)
if (!fQ) break;
// normal character - just keep walking
p1++;
}
++i;
// skip over whitespace
while (1)
{
c = *p1;
if (c > 0x20) break;
if (c == 0) return i;
p1++;
}
}
}
WCHAR
*CLFirstString(WCHAR *pc)
{
WCHAR *pd = pc;
if (NULL == pc) return NULL;
if (*(pc) == 0) return NULL;
while (*(++pc) > 0x20) continue;
*pc = 0;
return pd;
}
WCHAR
*CLLastString(WCHAR *pc)
{
WCHAR c;
WCHAR *pd = pc;
if (NULL == pc) return NULL;
if (NULL == *pc) return NULL;
while (*(++pc) != 0) continue;
while (pc > pd)
{
c = *(--pc);
if (0 == c) return NULL;
if (0x20 >= c) break;
}
if (pc == pd) return NULL;
return ++pc;
}
// -------------------------------------------------------------------------
//
// Security and Utility Group
//
// -------------------------------------------------------------------------
void StompCommandLine(INT argc, char **argv)
{
//return;
INT cc;
WCHAR *pL = GetCommandLineW();
if (pL)
{
cc = wcslen(pL);
if (cc)
{
SecureZeroMemory(pL,cc * sizeof(WCHAR));
}
}
// remove c runtime copy contents, as well
for (INT i=0 ; i < argc ; i++)
{
cc = strlen( argv[i]);
if (cc)
{
SecureZeroMemory(pL,cc * sizeof(char));
}
}
}