465 lines
14 KiB
C++
465 lines
14 KiB
C++
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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;
|
||
|
}
|
||
|
}
|