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.

464 lines
15 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: processcmdln.cpp
  4. //
  5. // Module: CMSETUP.LIB
  6. //
  7. // Synopsis: Implementation of the CProcessCmdLn class.
  8. //
  9. // Copyright (c) 1998-1999 Microsoft Corporation
  10. //
  11. // Author: quintinb Created Header 08/19/99
  12. //
  13. //+----------------------------------------------------------------------------
  14. #include "cmsetup.h"
  15. #include "setupmem.h"
  16. //+----------------------------------------------------------------------------
  17. //
  18. // Function: CProcessCmdLn::CProcessCmdLn
  19. //
  20. // Synopsis: Inits the class by copying the valid command line switches to the
  21. // command line switch array.
  22. //
  23. // Arguments: UINT NumSwitches - Number of switches in the array
  24. // UINT NumCharsInSwitch - Number of chars in each switch, counting the terminating NULL
  25. // TCHAR pszCommandLineSwitches[][] - Array of command line switches.
  26. //
  27. // Returns: Nothing
  28. //
  29. // History: quintinb Created 7/24/98
  30. //
  31. //+----------------------------------------------------------------------------
  32. CProcessCmdLn::CProcessCmdLn(UINT NumSwitches, ArgStruct* pArrayOfArgStructs,
  33. BOOL bSkipFirstToken, BOOL bBlankCmdLnOkay)
  34. {
  35. m_NumSwitches = NumSwitches;
  36. m_bSkipFirstToken = bSkipFirstToken;
  37. m_bBlankCmdLnOkay = bBlankCmdLnOkay;
  38. m_CommandLineSwitches = NULL;
  39. m_CommandLineSwitches = (ArgStruct*)CmMalloc(m_NumSwitches*sizeof(ArgStruct));
  40. if (m_CommandLineSwitches)
  41. {
  42. for(UINT i =0; i < NumSwitches; i++)
  43. {
  44. m_CommandLineSwitches[i].pszArgString =
  45. (TCHAR*)CmMalloc(sizeof(TCHAR)*(lstrlen(pArrayOfArgStructs[i].pszArgString) + 1));
  46. if (m_CommandLineSwitches[i].pszArgString)
  47. {
  48. lstrcpyn(m_CommandLineSwitches[i].pszArgString,
  49. pArrayOfArgStructs[i].pszArgString,
  50. (lstrlen(pArrayOfArgStructs[i].pszArgString) + 1));
  51. m_CommandLineSwitches[i].dwFlagModifier = pArrayOfArgStructs[i].dwFlagModifier;
  52. }
  53. }
  54. }
  55. }
  56. //+----------------------------------------------------------------------------
  57. //
  58. // Function: CProcessCmdLn::~CProcessCmdLn
  59. //
  60. // Synopsis: Cleans up after the class by deleting the dynamically allocated
  61. // string.
  62. //
  63. // Arguments: None
  64. //
  65. // Returns: Nothing
  66. //
  67. // History: Created Header 7/24/98
  68. //
  69. //+----------------------------------------------------------------------------
  70. CProcessCmdLn::~CProcessCmdLn()
  71. {
  72. if (m_CommandLineSwitches)
  73. {
  74. for(UINT i =0; i < m_NumSwitches; i++)
  75. {
  76. CmFree(m_CommandLineSwitches[i].pszArgString);
  77. }
  78. CmFree(m_CommandLineSwitches);
  79. }
  80. }
  81. //+----------------------------------------------------------------------------
  82. //
  83. // Function: CProcessCmdLn::IsValidSwitch
  84. //
  85. // Synopsis: This function tells whether the inputed switch is a recognized
  86. // command line switch.
  87. //
  88. // Arguments: LPCTSTR pszSwitch - Input switch string to be tested
  89. //
  90. // Returns: BOOL - Returns TRUE if the switch passed in is recognized as valid
  91. //
  92. // History: quintinb Created 7/13/98
  93. //
  94. //+----------------------------------------------------------------------------
  95. BOOL CProcessCmdLn::IsValidSwitch(LPCTSTR pszSwitch, LPDWORD pdwFlags)
  96. {
  97. for (UINT i = 0; i < m_NumSwitches; i++)
  98. {
  99. if (m_CommandLineSwitches[i].pszArgString && (0 == lstrcmpi(m_CommandLineSwitches[i].pszArgString, pszSwitch)))
  100. {
  101. //
  102. // Then we have a match
  103. //
  104. *pdwFlags |= m_CommandLineSwitches[i].dwFlagModifier;
  105. return TRUE;
  106. }
  107. }
  108. return FALSE;
  109. }
  110. //+----------------------------------------------------------------------------
  111. //
  112. // Function: CProcessCmdLn::IsValidFilePath
  113. //
  114. // Synopsis: This file checks to see if the inputted file path is a valid filepath.
  115. // This function depends on setfileattributes.
  116. //
  117. // Arguments: LPCTSTR pszFile - File to check to see if it exists.
  118. //
  119. // Returns: BOOL - Returns TRUE if we can set the attributes of the file inputed.
  120. //
  121. // History: quintinb Created 7/13/98
  122. //
  123. //+----------------------------------------------------------------------------
  124. BOOL CProcessCmdLn::IsValidFilePath(LPCTSTR pszFile)
  125. {
  126. return SetFileAttributes(pszFile, FILE_ATTRIBUTE_NORMAL);
  127. }
  128. //+----------------------------------------------------------------------------
  129. //
  130. // Function: CProcessCmdLn::EnsureFullFilePath
  131. //
  132. // Synopsis: This file checks to see if a file path passed in is a full path.
  133. // If it is not a full path then it adds the current directory path
  134. // to the beginning (assuming that we have a filename and extension).
  135. //
  136. // Arguments: LPTSTR pszFile - File to check
  137. // UINT uNumChars - Number of chars in the buffer holding pszFile
  138. //
  139. // Returns: BOOL - TRUE if a full file path
  140. //
  141. // History: quintinb Created 7/24/98
  142. //
  143. //+----------------------------------------------------------------------------
  144. BOOL CProcessCmdLn::EnsureFullFilePath(LPTSTR pszFile, UINT uNumChars)
  145. {
  146. BOOL bReturn = FALSE;
  147. if (SetFileAttributes(pszFile, FILE_ATTRIBUTE_NORMAL))
  148. {
  149. CFileNameParts InstallFileParts(pszFile);
  150. if ((TEXT('\0') == InstallFileParts.m_Drive[0]) &&
  151. (TEXT('\0') == InstallFileParts.m_Dir[0]) &&
  152. (TEXT('\0') != InstallFileParts.m_FileName[0]) &&
  153. (TEXT('\0') != InstallFileParts.m_Extension[0]))
  154. {
  155. //
  156. // Then we have a filename and extension but we don't
  157. // have a full path. Thus we want to add the current
  158. // directory onto the filename and extension.
  159. //
  160. TCHAR szTemp[MAX_PATH+1];
  161. if (GetCurrentDirectory(MAX_PATH, szTemp))
  162. {
  163. if (uNumChars > (UINT)(lstrlen(szTemp) + lstrlen(InstallFileParts.m_FileName) + lstrlen(InstallFileParts.m_Extension) + 2))
  164. {
  165. wsprintf(pszFile, TEXT("%s\\%s%s"), szTemp, InstallFileParts.m_FileName, InstallFileParts.m_Extension);
  166. bReturn = TRUE;
  167. }
  168. }
  169. }
  170. else
  171. {
  172. //
  173. // Could be a UNC path, a path with a drive letter and filename, or
  174. // a full path with a drive and a dir
  175. //
  176. bReturn = TRUE;
  177. }
  178. }
  179. return bReturn;
  180. }
  181. //+----------------------------------------------------------------------------
  182. //
  183. // Function: CProcessCmdLn::CheckIfValidSwitchOrPath
  184. //
  185. // Synopsis: Bundles code to determine if a token is a valid switch or path.
  186. //
  187. // Arguments: LPCTSTR pszToken - current token
  188. // BOOL* pbFoundSwitch - pointer to the BOOL which tells if a switch has been found yet
  189. // BOOL* pbFoundPath - pointer to the BOOL which tells if a path has been found yet
  190. // LPTSTR pszSwitch - string to hold the switch
  191. // LPTSTR pszPath - string to hold the path
  192. //
  193. // Returns: BOOL - returns TRUE if successful
  194. //
  195. // History: quintinb Created 8/25/98
  196. //
  197. //+----------------------------------------------------------------------------
  198. BOOL CProcessCmdLn::CheckIfValidSwitchOrPath(LPCTSTR pszToken, LPDWORD pdwFlags,
  199. BOOL* pbFoundPath, LPTSTR pszPath)
  200. {
  201. if (IsValidSwitch(pszToken, pdwFlags))
  202. {
  203. CMTRACE1(TEXT("ProcessCmdLn - ValidSwitch is %s"), pszToken);
  204. }
  205. else if (!(*pbFoundPath))
  206. {
  207. if (IsValidFilePath(pszToken))
  208. {
  209. *pbFoundPath = TRUE;
  210. lstrcpy(pszPath, pszToken);
  211. CMTRACE1(TEXT("ProcessCmdLn - ValidFilePath is %s"), pszToken);
  212. }
  213. else
  214. {
  215. //
  216. // Maybe the path contains environment variables, try to expand them.
  217. //
  218. TCHAR szExpandedPath[MAX_PATH+1] = TEXT("");
  219. CMTRACE1(TEXT("ProcessCmdLn - %s is not a valid path, expanding environment strings"), pszToken);
  220. ExpandEnvironmentStrings(pszToken, szExpandedPath, MAX_PATH);
  221. CMTRACE1(TEXT("ProcessCmdLn - expanded path is %s"), szExpandedPath);
  222. if (IsValidFilePath(szExpandedPath))
  223. {
  224. *pbFoundPath = TRUE;
  225. lstrcpy(pszPath, szExpandedPath);
  226. }
  227. else
  228. {
  229. //
  230. // Still no luck, return an error
  231. //
  232. CMTRACE1(TEXT("ProcessCmdLn - %s is not a valid path"), szExpandedPath);
  233. return FALSE;
  234. }
  235. }
  236. }
  237. else
  238. {
  239. //
  240. // We don't know what this is, send back an error
  241. //
  242. CMTRACE1(TEXT("ProcessCmdLn - Invalid token is %s"), pszToken);
  243. return FALSE;
  244. }
  245. return TRUE;
  246. }
  247. //+----------------------------------------------------------------------------
  248. //
  249. // Function: CProcessCmdLn::GetCmdLineArgs
  250. //
  251. // Synopsis: This function looks for any combination of just a command line
  252. // switch, just a path, or both. Handles long paths if quoted.
  253. //
  254. //
  255. // Arguments: IN LPTSTR pszCmdln - the command line to parse
  256. // OUT LPTSTR pszSwitch - Out parameter for the command line switch
  257. // OUT LPTSTR pszPath - Out parameter for the path
  258. //
  259. // Returns: BOOL - Returns TRUE if it was able to parse the args
  260. //
  261. // History: quintinb rewrote InitArgs from cmmgr.cpp to make it
  262. // simpler and more taylored to cmstp. 7-13-98
  263. //
  264. //----------------------------------------------------------------------------
  265. BOOL CProcessCmdLn::GetCmdLineArgs(IN LPTSTR pszCmdln, OUT LPDWORD pdwFlags, OUT LPTSTR pszPath,
  266. UINT uPathStrLimit)
  267. {
  268. LPTSTR pszCurr;
  269. LPTSTR pszToken;
  270. CMDLN_STATE state;
  271. BOOL bFoundSwitch = FALSE;
  272. BOOL bFoundPath = FALSE;
  273. if ((NULL == pdwFlags) || (NULL == pszPath))
  274. {
  275. return FALSE;
  276. }
  277. //
  278. // Init pdwFlags to Zero
  279. //
  280. *pdwFlags = 0;
  281. //
  282. // If m_bSkipFirstToken is TRUE, the we will skip the first Token. Otherwise,
  283. // we won't.
  284. //
  285. BOOL bFirstToken = m_bSkipFirstToken;
  286. state = CS_CHAR;
  287. pszCurr = pszToken = pszCmdln;
  288. CMTRACE1(TEXT("CProcessCmdLn::GetCmdLineArgs - Command line is %s"), pszCmdln);
  289. do
  290. {
  291. switch (*pszCurr)
  292. {
  293. case TEXT(' '):
  294. if (state == CS_CHAR)
  295. {
  296. //
  297. // we found a token
  298. //
  299. *pszCurr = TEXT('\0');
  300. if (bFirstToken)
  301. {
  302. //
  303. // The first token is the name of the exe, thus throw it away
  304. //
  305. bFirstToken = FALSE;
  306. CMTRACE1(TEXT("Throwing away, first token: %s"), pszToken);
  307. }
  308. else if(!CheckIfValidSwitchOrPath(pszToken, pdwFlags, &bFoundPath,
  309. pszPath))
  310. {
  311. //
  312. // return an error
  313. //
  314. return FALSE;
  315. }
  316. *pszCurr = TEXT(' ');
  317. pszCurr = pszToken = CharNext(pszCurr);
  318. state = CS_END_SPACE;
  319. continue;
  320. }
  321. else if (state == CS_END_SPACE || state == CS_END_QUOTE)
  322. {
  323. pszToken = CharNext(pszToken);
  324. }
  325. break;
  326. case TEXT('\"'):
  327. if (state == CS_BEGIN_QUOTE)
  328. {
  329. //
  330. // we found a token
  331. //
  332. *pszCurr = TEXT('\0');
  333. //
  334. // skip the opening quote
  335. //
  336. pszToken = CharNext(pszToken);
  337. if (bFirstToken)
  338. {
  339. //
  340. // The first token is the name of the exe, thus throw it away
  341. //
  342. bFirstToken = FALSE;
  343. CMTRACE1(TEXT("Throwing away, first token: %s"), pszToken);
  344. }
  345. else if(!CheckIfValidSwitchOrPath(pszToken, pdwFlags, &bFoundPath,
  346. pszPath))
  347. {
  348. //
  349. // return an error
  350. //
  351. return FALSE;
  352. }
  353. *pszCurr = TEXT('\"');
  354. pszCurr = pszToken = CharNext(pszCurr);
  355. state = CS_END_QUOTE;
  356. continue;
  357. }
  358. else
  359. {
  360. state = CS_BEGIN_QUOTE;
  361. }
  362. break;
  363. case TEXT('\0'):
  364. if (state != CS_END_QUOTE)
  365. {
  366. if (bFirstToken)
  367. {
  368. //
  369. // The first token is the name of the exe, thus throw it away
  370. //
  371. bFirstToken = FALSE;
  372. CMTRACE1(TEXT("Throwing away, first token: %s"), pszToken);
  373. }
  374. else if(!CheckIfValidSwitchOrPath(pszToken, pdwFlags, &bFoundPath,
  375. pszPath))
  376. {
  377. //
  378. // return an error
  379. //
  380. return FALSE;
  381. }
  382. }
  383. state = CS_DONE;
  384. break;
  385. default:
  386. if (state == CS_END_SPACE || state == CS_END_QUOTE)
  387. {
  388. state = CS_CHAR;
  389. }
  390. break;
  391. }
  392. pszCurr = CharNext(pszCurr);
  393. } while (state != CS_DONE);
  394. if (bFoundPath)
  395. {
  396. //
  397. // Then at least we found a path (and maybe switches, maybe not)
  398. //
  399. return EnsureFullFilePath(pszPath, uPathStrLimit);
  400. }
  401. else if (0 != *pdwFlags)
  402. {
  403. //
  404. // Then at least we found a switch
  405. //
  406. return TRUE;
  407. }
  408. else
  409. {
  410. //
  411. // If it is okay to have a blank command line, then this is okay, otherwise it isn't.
  412. // Note that if m_bSkipFirstToken == TRUE, then the command line might not be completely
  413. // blank, it could contain the name of the executable for instance.
  414. //
  415. return m_bBlankCmdLnOkay;
  416. }
  417. }