//+---------------------------------------------------------------------------- // // 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; } }