Counter Strike : Global Offensive Source Code
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.

488 lines
11 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ====
  2. //
  3. // Purpose: Handles running the OS commands for map compilation.
  4. //
  5. //=============================================================================
  6. #include "stdafx.h"
  7. #include <afxtempl.h>
  8. #include "GameConfig.h"
  9. #include "RunCommands.h"
  10. #include "Options.h"
  11. #include <process.h>
  12. #include <io.h>
  13. #include <direct.h>
  14. #include "GlobalFunctions.h"
  15. #include "hammer.h"
  16. #include "mapdoc.h"
  17. #include "gridnav.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include <tier0/memdbgon.h>
  20. static bool s_bRunsCommands = false;
  21. bool IsRunningCommands() { return s_bRunsCommands; }
  22. static char *pszDocPath, *pszDocName, *pszDocExt;
  23. // --------------------------------------------------------------------------------------------------------------- //
  24. // This class queues the list of commands to execute, then sends them to hammer_run_map_launcher.exe
  25. // --------------------------------------------------------------------------------------------------------------- //
  26. class CCommandExecuter
  27. {
  28. public:
  29. CCommandExecuter( bool bWaitForKeypress );
  30. ~CCommandExecuter();
  31. void AddCommandVA( const char *pStr, ... );
  32. void AddCommandWithArgList( char **ppParms );
  33. void EncodeCommand( const char *pCommand, CString &out );
  34. void Launch();
  35. private:
  36. // Each command is the full command line with each argument in quotes.
  37. CUtlVector<CString*> m_Commands;
  38. bool m_bWaitForKeypress;
  39. };
  40. CCommandExecuter::CCommandExecuter( bool bWaitForKeypress )
  41. {
  42. m_bWaitForKeypress = bWaitForKeypress;
  43. }
  44. CCommandExecuter::~CCommandExecuter()
  45. {
  46. m_Commands.PurgeAndDeleteElements();
  47. }
  48. void CCommandExecuter::AddCommandVA( const char *pStr, ... )
  49. {
  50. char fullStr[8192];
  51. va_list marker;
  52. va_start( marker, pStr );
  53. V_vsnprintf( fullStr, sizeof( fullStr ), pStr, marker );
  54. va_end( marker );
  55. CString *pFullStr = new CString;
  56. *pFullStr = fullStr;
  57. m_Commands.AddToTail( pFullStr );
  58. }
  59. void CCommandExecuter::AddCommandWithArgList( char **ppParms )
  60. {
  61. CString *pFullStr = new CString;
  62. CString &str = *pFullStr;
  63. while ( *ppParms )
  64. {
  65. str += *ppParms;
  66. str += " ";
  67. ++ppParms;
  68. }
  69. m_Commands.AddToTail( pFullStr );
  70. }
  71. void CCommandExecuter::EncodeCommand( const char *pCommand, CString &out )
  72. {
  73. // 'a' - 'p'
  74. int len = V_strlen( pCommand );
  75. char *pTempStr = new char[ len*2 + 1 ];
  76. for ( int i=0; i < len; i++ )
  77. {
  78. pTempStr[i*2+0] = 'a' + (((unsigned char)pCommand[i] >> 0) & 0xF);
  79. pTempStr[i*2+1] = 'a' + (((unsigned char)pCommand[i] >> 4) & 0xF);
  80. }
  81. pTempStr[len*2] = 0;
  82. out = pTempStr;
  83. delete [] pTempStr;
  84. }
  85. void CCommandExecuter::Launch()
  86. {
  87. char szFilename[MAX_PATH];
  88. GetModuleFileName( NULL, szFilename, sizeof( szFilename ) );
  89. V_StripLastDir( szFilename, sizeof( szFilename ) );
  90. V_AppendSlash( szFilename, sizeof( szFilename ) );
  91. if ( APP()->IsFoundryMode() )
  92. {
  93. V_strncat( szFilename, "bin", sizeof( szFilename ) );
  94. V_AppendSlash( szFilename, sizeof( szFilename ) );
  95. }
  96. // Make a master string of all the args.
  97. CString fullCommand = szFilename;
  98. fullCommand += "hammer_run_map_launcher.exe ";
  99. if ( m_bWaitForKeypress )
  100. fullCommand += "-WaitForKeypress ";
  101. for ( int i=0; i < m_Commands.Count(); i++ )
  102. {
  103. // We encode the commands here into a string without spaces and quotes so hammer_run_map_launcher can pick it up
  104. // exactly as we have it here.
  105. CString encodedCommand;
  106. EncodeCommand( *m_Commands[i], encodedCommand );
  107. fullCommand += encodedCommand;
  108. fullCommand += " ";
  109. }
  110. PROCESS_INFORMATION pi;
  111. STARTUPINFO si;
  112. memset( &si, 0, sizeof( si ) );
  113. si.cb = sizeof( si );
  114. CreateProcess(
  115. NULL,
  116. (char*)(const char*)fullCommand,
  117. NULL,
  118. NULL,
  119. FALSE,
  120. CREATE_NEW_CONSOLE,
  121. NULL,
  122. NULL,
  123. &si,
  124. &pi );
  125. }
  126. void FixGameVars(char *pszSrc, char *pszDst, BOOL bUseQuotes)
  127. {
  128. // run through the parms list and substitute $variable strings for
  129. // the real thing
  130. char *pSrc = pszSrc, *pDst = pszDst;
  131. BOOL bInQuote = FALSE;
  132. while(pSrc[0])
  133. {
  134. if(pSrc[0] == '$') // found a parm
  135. {
  136. if(pSrc[1] == '$') // nope, it's a single symbol
  137. {
  138. *pDst++ = '$';
  139. ++pSrc;
  140. }
  141. else
  142. {
  143. // figure out which parm it is ..
  144. ++pSrc;
  145. if (!bInQuote && bUseQuotes)
  146. {
  147. // not in quote, and subbing a variable.. start quote
  148. *pDst++ = '\"';
  149. bInQuote = TRUE;
  150. }
  151. if(!strnicmp(pSrc, "file", 4))
  152. {
  153. pSrc += 4;
  154. strcpy(pDst, pszDocName);
  155. pDst += strlen(pDst);
  156. }
  157. else if(!strnicmp(pSrc, "ext", 3))
  158. {
  159. pSrc += 3;
  160. strcpy(pDst, pszDocExt);
  161. pDst += strlen(pDst);
  162. }
  163. else if(!strnicmp(pSrc, "path", 4))
  164. {
  165. pSrc += 4;
  166. strcpy(pDst, pszDocPath);
  167. pDst += strlen(pDst);
  168. }
  169. else if(!strnicmp(pSrc, "exedir", 6))
  170. {
  171. pSrc += 6;
  172. strcpy(pDst, g_pGameConfig->m_szGameExeDir);
  173. pDst += strlen(pDst);
  174. }
  175. else if(!strnicmp(pSrc, "bspdir", 6))
  176. {
  177. pSrc += 6;
  178. strcpy(pDst, g_pGameConfig->szBSPDir);
  179. pDst += strlen(pDst);
  180. }
  181. else if(!strnicmp(pSrc, "bsp_exe", 7))
  182. {
  183. pSrc += 7;
  184. strcpy(pDst, g_pGameConfig->szBSP);
  185. pDst += strlen(pDst);
  186. }
  187. else if(!strnicmp(pSrc, "vis_exe", 7))
  188. {
  189. pSrc += 7;
  190. strcpy(pDst, g_pGameConfig->szVIS);
  191. pDst += strlen(pDst);
  192. }
  193. else if(!strnicmp(pSrc, "light_exe", 9))
  194. {
  195. pSrc += 9;
  196. strcpy(pDst, g_pGameConfig->szLIGHT);
  197. pDst += strlen(pDst);
  198. }
  199. else if(!strnicmp(pSrc, "game_exe", 8))
  200. {
  201. pSrc += 8;
  202. strcpy(pDst, g_pGameConfig->szExecutable);
  203. pDst += strlen(pDst);
  204. }
  205. else if (!strnicmp(pSrc, "gamedir", 7))
  206. {
  207. pSrc += 7;
  208. strcpy(pDst, g_pGameConfig->m_szModDir);
  209. pDst += strlen(pDst);
  210. }
  211. }
  212. }
  213. else
  214. {
  215. if(*pSrc == ' ' && bInQuote)
  216. {
  217. bInQuote = FALSE;
  218. *pDst++ = '\"'; // close quotes
  219. }
  220. // just copy the char into the destination buffer
  221. *pDst++ = *pSrc++;
  222. }
  223. }
  224. if(bInQuote)
  225. {
  226. bInQuote = FALSE;
  227. *pDst++ = '\"'; // close quotes
  228. }
  229. pDst[0] = 0;
  230. }
  231. static void RemoveQuotes(char *pBuf)
  232. {
  233. if(pBuf[0] == '\"')
  234. strcpy(pBuf, pBuf+1);
  235. if(pBuf[strlen(pBuf)-1] == '\"')
  236. pBuf[strlen(pBuf)-1] = 0;
  237. }
  238. LPCTSTR GetErrorString()
  239. {
  240. static char szBuf[200];
  241. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
  242. szBuf, 200, NULL);
  243. char *p = strchr(szBuf, '\r'); // get rid of \r\n
  244. if(p) p[0] = 0;
  245. return szBuf;
  246. }
  247. bool RunCommands(CCommandArray& Commands, LPCTSTR pszOrigDocName, bool bWaitForKeypress)
  248. {
  249. s_bRunsCommands = true;
  250. char szCurDir[MAX_PATH];
  251. _getcwd(szCurDir, MAX_PATH);
  252. // cut up document name into file and extension components.
  253. // create two sets of buffers - one set with the long filename
  254. // and one set with the 8.3 format.
  255. char szDocLongPath[MAX_PATH] = {0}, szDocLongName[MAX_PATH] = {0},
  256. szDocLongExt[MAX_PATH] = {0};
  257. char szDocShortPath[MAX_PATH] = {0}, szDocShortName[MAX_PATH] = {0},
  258. szDocShortExt[MAX_PATH] = {0};
  259. GetFullPathName(pszOrigDocName, MAX_PATH, szDocLongPath, NULL);
  260. GetShortPathName(pszOrigDocName, szDocShortPath, MAX_PATH);
  261. // split them up
  262. char *p = strrchr(szDocLongPath, '.');
  263. if(p && strrchr(szDocLongPath, '\\') < p && strrchr(szDocLongPath, '/') < p)
  264. {
  265. // got the extension
  266. strcpy(szDocLongExt, p+1);
  267. p[0] = 0;
  268. }
  269. p = strrchr(szDocLongPath, '\\');
  270. if(!p)
  271. p = strrchr(szDocLongPath, '/');
  272. if(p)
  273. {
  274. // got the filepart
  275. strcpy(szDocLongName, p+1);
  276. p[0] = 0;
  277. }
  278. // split the short part up
  279. p = strrchr(szDocShortPath, '.');
  280. if(p && strrchr(szDocShortPath, '\\') < p && strrchr(szDocShortPath, '/') < p)
  281. {
  282. // got the extension
  283. strcpy(szDocShortExt, p+1);
  284. p[0] = 0;
  285. }
  286. p = strrchr(szDocShortPath, '\\');
  287. if(!p)
  288. p = strrchr(szDocShortPath, '/');
  289. if(p)
  290. {
  291. // got the filepart
  292. strcpy(szDocShortName, p+1);
  293. p[0] = 0;
  294. }
  295. CCommandExecuter commandExecuter( bWaitForKeypress );
  296. int iSize = Commands.GetSize(), i = 0;
  297. char *ppParms[32];
  298. while(iSize--)
  299. {
  300. CCOMMAND &cmd = Commands[i++];
  301. // anything there?
  302. if((!cmd.szRun[0] && !cmd.iSpecialCmd) || !cmd.bEnable)
  303. continue;
  304. // set name pointers for long filenames
  305. pszDocExt = szDocLongExt;
  306. pszDocName = szDocLongName;
  307. pszDocPath = szDocLongPath;
  308. char szNewParms[MAX_PATH*5], szNewRun[MAX_PATH*5];
  309. FixGameVars(cmd.szRun, szNewRun, TRUE);
  310. FixGameVars(cmd.szParms, szNewParms, TRUE);
  311. // create a parameter list (not always required)
  312. char *p = szNewParms;
  313. ppParms[0] = szNewRun;
  314. int iArg = 1;
  315. BOOL bDone = FALSE;
  316. while(p[0])
  317. {
  318. ppParms[iArg++] = p;
  319. while(p[0])
  320. {
  321. if(p[0] == ' ')
  322. {
  323. // found a space-separator
  324. p[0] = 0;
  325. p++;
  326. // skip remaining white space
  327. while (*p == ' ')
  328. p++;
  329. break;
  330. }
  331. // found the beginning of a quoted parameters
  332. if(p[0] == '\"')
  333. {
  334. while(1)
  335. {
  336. p++;
  337. if(p[0] == '\"')
  338. {
  339. // found the end
  340. if(p[1] == 0)
  341. bDone = TRUE;
  342. p[1] = 0; // kick its ass
  343. p += 2;
  344. // skip remaining white space
  345. while (*p == ' ')
  346. p++;
  347. break;
  348. }
  349. }
  350. break;
  351. }
  352. // else advance p
  353. ++p;
  354. }
  355. if(!p[0] || bDone)
  356. break; // done.
  357. }
  358. ppParms[iArg] = NULL;
  359. if(cmd.iSpecialCmd)
  360. {
  361. if(cmd.iSpecialCmd == CCCopyFile && iArg == 3)
  362. {
  363. RemoveQuotes(ppParms[1]);
  364. RemoveQuotes(ppParms[2]);
  365. // don't copy if we're already there
  366. if (stricmp(ppParms[1], ppParms[2]) != 0 )
  367. {
  368. commandExecuter.AddCommandVA( "copy \"%s\" \"%s\"", ppParms[1], ppParms[2] );
  369. }
  370. }
  371. else if(cmd.iSpecialCmd == CCDelFile && iArg == 2)
  372. {
  373. RemoveQuotes(ppParms[1]);
  374. commandExecuter.AddCommandVA( "del \"%s\"", ppParms[1] );
  375. }
  376. else if(cmd.iSpecialCmd == CCRenameFile && iArg == 3)
  377. {
  378. RemoveQuotes(ppParms[1]);
  379. RemoveQuotes(ppParms[2]);
  380. commandExecuter.AddCommandVA( "ren \"%s\" \"%s\"", ppParms[1], ppParms[2] );
  381. }
  382. else if(cmd.iSpecialCmd == CCChangeDir && iArg == 2)
  383. {
  384. RemoveQuotes(ppParms[1]);
  385. commandExecuter.AddCommandVA( "cd \"%s\"", ppParms[1] );
  386. }
  387. else if(cmd.iSpecialCmd == CCGenerateGridNav && iArg == 2 )
  388. {
  389. CMapDoc* pMapDoc = CMapDoc::GetActiveMapDoc();
  390. if ( pMapDoc )
  391. {
  392. CGridNav* pGridNav = pMapDoc->GetGridNav();
  393. if ( pGridNav && pGridNav->IsEnabled() )
  394. {
  395. RemoveQuotes(ppParms[1]);
  396. pGridNav->GenerateGridNavFile( ppParms[1] );
  397. }
  398. }
  399. }
  400. }
  401. else
  402. {
  403. // Change to the game exe folder before spawning the engine.
  404. // This is necessary for Steam to find the correct Steam DLL (it
  405. // uses the current working directory to search).
  406. char szDir[MAX_PATH];
  407. V_strncpy( szDir, szNewRun, sizeof(szDir) );
  408. RemoveQuotes( szDir );
  409. V_StripFilename( szDir );
  410. commandExecuter.AddCommandVA( "cd \"%s\"", szDir );
  411. commandExecuter.AddCommandWithArgList( ppParms );
  412. }
  413. }
  414. commandExecuter.Launch();
  415. s_bRunsCommands = false;
  416. return TRUE;
  417. }