Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

464 lines
14 KiB

//+----------------------------------------------------------------------------
//
// File: processcmdln.cpp
//
// Module: CMSETUP.LIB
//
// Synopsis: Implementation of the CProcessCmdLn class.
//
// Copyright (c) 1998-1999 Microsoft Corporation
//
// Author: quintinb Created Header 08/19/99
//
//+----------------------------------------------------------------------------
#include "cmsetup.h"
#include "setupmem.h"
//+----------------------------------------------------------------------------
//
// Function: CProcessCmdLn::CProcessCmdLn
//
// Synopsis: Inits the class by copying the valid command line switches to the
// command line switch array.
//
// Arguments: UINT NumSwitches - Number of switches in the array
// UINT NumCharsInSwitch - Number of chars in each switch, counting the terminating NULL
// TCHAR pszCommandLineSwitches[][] - Array of command line switches.
//
// Returns: Nothing
//
// History: quintinb Created 7/24/98
//
//+----------------------------------------------------------------------------
CProcessCmdLn::CProcessCmdLn(UINT NumSwitches, ArgStruct* pArrayOfArgStructs,
BOOL bSkipFirstToken, BOOL bBlankCmdLnOkay)
{
m_NumSwitches = NumSwitches;
m_bSkipFirstToken = bSkipFirstToken;
m_bBlankCmdLnOkay = bBlankCmdLnOkay;
m_CommandLineSwitches = NULL;
m_CommandLineSwitches = (ArgStruct*)CmMalloc(m_NumSwitches*sizeof(ArgStruct));
if (m_CommandLineSwitches)
{
for(UINT i =0; i < NumSwitches; i++)
{
m_CommandLineSwitches[i].pszArgString =
(TCHAR*)CmMalloc(sizeof(TCHAR)*(lstrlen(pArrayOfArgStructs[i].pszArgString) + 1));
if (m_CommandLineSwitches[i].pszArgString)
{
lstrcpyn(m_CommandLineSwitches[i].pszArgString,
pArrayOfArgStructs[i].pszArgString,
(lstrlen(pArrayOfArgStructs[i].pszArgString) + 1));
m_CommandLineSwitches[i].dwFlagModifier = pArrayOfArgStructs[i].dwFlagModifier;
}
}
}
}
//+----------------------------------------------------------------------------
//
// Function: CProcessCmdLn::~CProcessCmdLn
//
// Synopsis: Cleans up after the class by deleting the dynamically allocated
// string.
//
// Arguments: None
//
// Returns: Nothing
//
// History: Created Header 7/24/98
//
//+----------------------------------------------------------------------------
CProcessCmdLn::~CProcessCmdLn()
{
if (m_CommandLineSwitches)
{
for(UINT i =0; i < m_NumSwitches; i++)
{
CmFree(m_CommandLineSwitches[i].pszArgString);
}
CmFree(m_CommandLineSwitches);
}
}
//+----------------------------------------------------------------------------
//
// Function: CProcessCmdLn::IsValidSwitch
//
// Synopsis: This function tells whether the inputed switch is a recognized
// command line switch.
//
// Arguments: LPCTSTR pszSwitch - Input switch string to be tested
//
// Returns: BOOL - Returns TRUE if the switch passed in is recognized as valid
//
// History: quintinb Created 7/13/98
//
//+----------------------------------------------------------------------------
BOOL CProcessCmdLn::IsValidSwitch(LPCTSTR pszSwitch, LPDWORD pdwFlags)
{
for (UINT i = 0; i < m_NumSwitches; i++)
{
if (m_CommandLineSwitches[i].pszArgString && (0 == lstrcmpi(m_CommandLineSwitches[i].pszArgString, pszSwitch)))
{
//
// Then we have a match
//
*pdwFlags |= m_CommandLineSwitches[i].dwFlagModifier;
return TRUE;
}
}
return FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: CProcessCmdLn::IsValidFilePath
//
// Synopsis: This file checks to see if the inputted file path is a valid filepath.
// This function depends on setfileattributes.
//
// Arguments: LPCTSTR pszFile - File to check to see if it exists.
//
// Returns: BOOL - Returns TRUE if we can set the attributes of the file inputed.
//
// History: quintinb Created 7/13/98
//
//+----------------------------------------------------------------------------
BOOL CProcessCmdLn::IsValidFilePath(LPCTSTR pszFile)
{
return SetFileAttributes(pszFile, FILE_ATTRIBUTE_NORMAL);
}
//+----------------------------------------------------------------------------
//
// Function: CProcessCmdLn::EnsureFullFilePath
//
// Synopsis: This file checks to see if a file path passed in is a full path.
// If it is not a full path then it adds the current directory path
// to the beginning (assuming that we have a filename and extension).
//
// Arguments: LPTSTR pszFile - File to check
// UINT uNumChars - Number of chars in the buffer holding pszFile
//
// Returns: BOOL - TRUE if a full file path
//
// History: quintinb Created 7/24/98
//
//+----------------------------------------------------------------------------
BOOL CProcessCmdLn::EnsureFullFilePath(LPTSTR pszFile, UINT uNumChars)
{
BOOL bReturn = FALSE;
if (SetFileAttributes(pszFile, FILE_ATTRIBUTE_NORMAL))
{
CFileNameParts InstallFileParts(pszFile);
if ((TEXT('\0') == InstallFileParts.m_Drive[0]) &&
(TEXT('\0') == InstallFileParts.m_Dir[0]) &&
(TEXT('\0') != InstallFileParts.m_FileName[0]) &&
(TEXT('\0') != InstallFileParts.m_Extension[0]))
{
//
// Then we have a filename and extension but we don't
// have a full path. Thus we want to add the current
// directory onto the filename and extension.
//
TCHAR szTemp[MAX_PATH+1];
if (GetCurrentDirectory(MAX_PATH, szTemp))
{
if (uNumChars > (UINT)(lstrlen(szTemp) + lstrlen(InstallFileParts.m_FileName) + lstrlen(InstallFileParts.m_Extension) + 2))
{
wsprintf(pszFile, TEXT("%s\\%s%s"), szTemp, InstallFileParts.m_FileName, InstallFileParts.m_Extension);
bReturn = TRUE;
}
}
}
else
{
//
// Could be a UNC path, a path with a drive letter and filename, or
// a full path with a drive and a dir
//
bReturn = TRUE;
}
}
return bReturn;
}
//+----------------------------------------------------------------------------
//
// Function: CProcessCmdLn::CheckIfValidSwitchOrPath
//
// Synopsis: Bundles code to determine if a token is a valid switch or path.
//
// Arguments: LPCTSTR pszToken - current token
// BOOL* pbFoundSwitch - pointer to the BOOL which tells if a switch has been found yet
// BOOL* pbFoundPath - pointer to the BOOL which tells if a path has been found yet
// LPTSTR pszSwitch - string to hold the switch
// LPTSTR pszPath - string to hold the path
//
// Returns: BOOL - returns TRUE if successful
//
// History: quintinb Created 8/25/98
//
//+----------------------------------------------------------------------------
BOOL CProcessCmdLn::CheckIfValidSwitchOrPath(LPCTSTR pszToken, LPDWORD pdwFlags,
BOOL* pbFoundPath, LPTSTR pszPath)
{
if (IsValidSwitch(pszToken, pdwFlags))
{
CMTRACE1(TEXT("ProcessCmdLn - ValidSwitch is %s"), pszToken);
}
else if (!(*pbFoundPath))
{
if (IsValidFilePath(pszToken))
{
*pbFoundPath = TRUE;
lstrcpy(pszPath, pszToken);
CMTRACE1(TEXT("ProcessCmdLn - ValidFilePath is %s"), pszToken);
}
else
{
//
// Maybe the path contains environment variables, try to expand them.
//
TCHAR szExpandedPath[MAX_PATH+1] = TEXT("");
CMTRACE1(TEXT("ProcessCmdLn - %s is not a valid path, expanding environment strings"), pszToken);
ExpandEnvironmentStrings(pszToken, szExpandedPath, MAX_PATH);
CMTRACE1(TEXT("ProcessCmdLn - expanded path is %s"), szExpandedPath);
if (IsValidFilePath(szExpandedPath))
{
*pbFoundPath = TRUE;
lstrcpy(pszPath, szExpandedPath);
}
else
{
//
// Still no luck, return an error
//
CMTRACE1(TEXT("ProcessCmdLn - %s is not a valid path"), szExpandedPath);
return FALSE;
}
}
}
else
{
//
// We don't know what this is, send back an error
//
CMTRACE1(TEXT("ProcessCmdLn - Invalid token is %s"), pszToken);
return FALSE;
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: CProcessCmdLn::GetCmdLineArgs
//
// Synopsis: This function looks for any combination of just a command line
// switch, just a path, or both. Handles long paths if quoted.
//
//
// Arguments: IN LPTSTR pszCmdln - the command line to parse
// OUT LPTSTR pszSwitch - Out parameter for the command line switch
// OUT LPTSTR pszPath - Out parameter for the path
//
// Returns: BOOL - Returns TRUE if it was able to parse the args
//
// History: quintinb rewrote InitArgs from cmmgr.cpp to make it
// simpler and more taylored to cmstp. 7-13-98
//
//----------------------------------------------------------------------------
BOOL CProcessCmdLn::GetCmdLineArgs(IN LPTSTR pszCmdln, OUT LPDWORD pdwFlags, OUT LPTSTR pszPath,
UINT uPathStrLimit)
{
LPTSTR pszCurr;
LPTSTR pszToken;
CMDLN_STATE state;
BOOL bFoundSwitch = FALSE;
BOOL bFoundPath = FALSE;
if ((NULL == pdwFlags) || (NULL == pszPath))
{
return FALSE;
}
//
// Init pdwFlags to Zero
//
*pdwFlags = 0;
//
// If m_bSkipFirstToken is TRUE, the we will skip the first Token. Otherwise,
// we won't.
//
BOOL bFirstToken = m_bSkipFirstToken;
state = CS_CHAR;
pszCurr = pszToken = pszCmdln;
CMTRACE1(TEXT("CProcessCmdLn::GetCmdLineArgs - Command line is %s"), pszCmdln);
do
{
switch (*pszCurr)
{
case TEXT(' '):
if (state == CS_CHAR)
{
//
// we found a token
//
*pszCurr = TEXT('\0');
if (bFirstToken)
{
//
// The first token is the name of the exe, thus throw it away
//
bFirstToken = FALSE;
CMTRACE1(TEXT("Throwing away, first token: %s"), pszToken);
}
else if(!CheckIfValidSwitchOrPath(pszToken, pdwFlags, &bFoundPath,
pszPath))
{
//
// return an error
//
return FALSE;
}
*pszCurr = TEXT(' ');
pszCurr = pszToken = CharNext(pszCurr);
state = CS_END_SPACE;
continue;
}
else if (state == CS_END_SPACE || state == CS_END_QUOTE)
{
pszToken = CharNext(pszToken);
}
break;
case TEXT('\"'):
if (state == CS_BEGIN_QUOTE)
{
//
// we found a token
//
*pszCurr = TEXT('\0');
//
// skip the opening quote
//
pszToken = CharNext(pszToken);
if (bFirstToken)
{
//
// The first token is the name of the exe, thus throw it away
//
bFirstToken = FALSE;
CMTRACE1(TEXT("Throwing away, first token: %s"), pszToken);
}
else if(!CheckIfValidSwitchOrPath(pszToken, pdwFlags, &bFoundPath,
pszPath))
{
//
// return an error
//
return FALSE;
}
*pszCurr = TEXT('\"');
pszCurr = pszToken = CharNext(pszCurr);
state = CS_END_QUOTE;
continue;
}
else
{
state = CS_BEGIN_QUOTE;
}
break;
case TEXT('\0'):
if (state != CS_END_QUOTE)
{
if (bFirstToken)
{
//
// The first token is the name of the exe, thus throw it away
//
bFirstToken = FALSE;
CMTRACE1(TEXT("Throwing away, first token: %s"), pszToken);
}
else if(!CheckIfValidSwitchOrPath(pszToken, pdwFlags, &bFoundPath,
pszPath))
{
//
// return an error
//
return FALSE;
}
}
state = CS_DONE;
break;
default:
if (state == CS_END_SPACE || state == CS_END_QUOTE)
{
state = CS_CHAR;
}
break;
}
pszCurr = CharNext(pszCurr);
} while (state != CS_DONE);
if (bFoundPath)
{
//
// Then at least we found a path (and maybe switches, maybe not)
//
return EnsureFullFilePath(pszPath, uPathStrLimit);
}
else if (0 != *pdwFlags)
{
//
// Then at least we found a switch
//
return TRUE;
}
else
{
//
// If it is okay to have a blank command line, then this is okay, otherwise it isn't.
// Note that if m_bSkipFirstToken == TRUE, then the command line might not be completely
// blank, it could contain the name of the executable for instance.
//
return m_bBlankCmdLnOkay;
}
}