PageRenderTime 74ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/src/c4group/c4group_cmdl.cpp

https://bitbucket.org/randrian/openclonk2
C++ | 580 lines | 410 code | 46 blank | 124 comment | 109 complexity | 37a974817288293658177809e031863a MD5 | raw file
Possible License(s): WTFPL, 0BSD, LGPL-2.1, CC-BY-3.0
  1. /*
  2. * OpenClonk, http://www.openclonk.org
  3. *
  4. * Copyright (c) 2002, 2006, 2008 Sven Eberhardt
  5. * Copyright (c) 2003-2004, 2007 Matthes Bender
  6. * Copyright (c) 2004, 2007-2008 Peter Wortmann
  7. * Copyright (c) 2005 G?nther Brammer
  8. * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
  9. *
  10. * Portions might be copyrighted by other authors who have contributed
  11. * to OpenClonk.
  12. *
  13. * Permission to use, copy, modify, and/or distribute this software for any
  14. * purpose with or without fee is hereby granted, provided that the above
  15. * copyright notice and this permission notice appear in all copies.
  16. * See isc_license.txt for full license and disclaimer.
  17. *
  18. * "Clonk" is a registered trademark of Matthes Bender.
  19. * See clonk_trademark_license.txt for full license.
  20. */
  21. /* C4Group command line executable */
  22. // Version 1.0 November 1997
  23. // 1.1 November 1997
  24. // 1.2 February 1998
  25. // 1.3 March 1998
  26. // 1.4 April 1998
  27. // 1.5 May 1998
  28. // 1.6 November 1998
  29. // 1.7 December 1998
  30. // 1.8 February 1999
  31. // 1.9 May 1999
  32. // 2.0 June 1999
  33. // 2.6 March 2001
  34. // 2.7 June 2001
  35. // 2.8 June 2002
  36. // 4.95.0 November 2003
  37. // 4.95.4 July 2005 PORT/HEAD mixmax
  38. #include <C4Include.h>
  39. #include <C4ConfigShareware.h>
  40. #include <StdRegistry.h>
  41. #include <C4Group.h>
  42. #include <C4Version.h>
  43. #include <C4Update.h>
  44. #include <shellapi.h>
  45. #include <conio.h>
  46. int globalArgC;
  47. char **globalArgV;
  48. int iFirstCommand = -1;
  49. bool fQuiet = false;
  50. bool fRecursive = false;
  51. bool fRegisterShell = false;
  52. bool fUnregisterShell = false;
  53. bool fPromptAtEnd = false;
  54. char strExecuteAtEnd[_MAX_PATH + 1] = "";
  55. int iResult = 0;
  56. C4ConfigShareware Config;
  57. C4Config *GetCfg() { return &Config; }
  58. CDDrawCfg DDrawCfg; // to satisfy the linker
  59. #ifdef _WIN32
  60. #ifdef _DEBUG
  61. int dbg_printf(const char *strMessage, ...)
  62. {
  63. va_list args; va_start(args, strMessage);
  64. // Compose formatted message
  65. StdStrBuf Buf;
  66. Buf.FormatV(strMessage, args);
  67. // Log
  68. OutputDebugString(Buf.getData());
  69. return printf(Buf.getData());
  70. }
  71. #define printf dbg_printf
  72. #endif
  73. #endif
  74. bool ProcessGroup(const char *szFilename)
  75. {
  76. C4Group hGroup;
  77. int iArg;
  78. bool fDeleteGroup = false;
  79. hGroup.SetStdOutput(true);
  80. int argc = globalArgC;
  81. char **argv = globalArgV;
  82. // Current filename
  83. if (!fQuiet)
  84. printf("Group: %s\n",szFilename);
  85. // Open group file
  86. if (hGroup.Open(szFilename, true && Config.Registered()))
  87. {
  88. // No commands: display contents
  89. if (iFirstCommand<0)
  90. {
  91. if (Config.Registered())
  92. hGroup.View("*");
  93. }
  94. // Process commands
  95. else
  96. for (iArg=iFirstCommand; iArg<argc; iArg++)
  97. {
  98. // This argument is a command
  99. if (argv[iArg][0]=='-')
  100. {
  101. // Block unregistered commands
  102. if (!Config.Registered() && (SCharPos(argv[iArg][1], "yw") < 0))
  103. {
  104. printf("Command -%c not allowed in unregistered version: %s\n", argv[iArg][1], Config.GetRegistrationError());
  105. continue;
  106. }
  107. // Handle commands
  108. switch (argv[iArg][1])
  109. {
  110. // Add
  111. case 'a':
  112. if ((iArg+1>=argc) || (argv[iArg+1][0]=='-'))
  113. printf("Missing argument for add command\n");
  114. else
  115. {
  116. if ((argv[iArg][2]=='s') || (argv[iArg][2] && (argv[iArg][3]=='s')) )
  117. {
  118. if ((iArg+2>=argc) || (argv[iArg+2][0]=='-'))
  119. printf("Missing argument for add as command\n");
  120. else
  121. { hGroup.Add(argv[iArg+1],argv[iArg+2]); iArg+=2; }
  122. }
  123. else
  124. #ifdef _WIN32
  125. { hGroup.Add(argv[iArg+1]); iArg++; }
  126. #else
  127. { hGroup.Add(argv[iArg+1], argv[iArg+1]); iArg++; }
  128. #endif
  129. }
  130. break;
  131. // Move
  132. case 'm':
  133. if ((iArg+1>=argc) || (argv[iArg+1][0]=='-'))
  134. printf("Missing argument for move command\n");
  135. else
  136. #ifdef _WIN32
  137. { hGroup.Move(argv[iArg+1]); iArg++; }
  138. #else
  139. { hGroup.Move(argv[iArg+1], argv[iArg+1]); iArg++; }
  140. #endif
  141. break;
  142. // Extract
  143. case 'e':
  144. if ((iArg+1>=argc) || (argv[iArg+1][0]=='-'))
  145. printf("Missing argument for extract command\n");
  146. else
  147. {
  148. if ((argv[iArg][2]=='t') || (argv[iArg][2] && (argv[iArg][3]=='s')) )
  149. {
  150. if ((iArg+2>=argc) || (argv[iArg+2][0]=='-'))
  151. printf("Missing argument for extract as command\n");
  152. else
  153. { hGroup.Extract(argv[iArg+1],argv[iArg+2]); iArg+=2; }
  154. }
  155. else
  156. { hGroup.Extract(argv[iArg+1]); iArg++; }
  157. }
  158. break;
  159. // Delete
  160. case 'd':
  161. if ((iArg+1>=argc) || (argv[iArg+1][0]=='-'))
  162. printf("Missing argument for delete command\n");
  163. else
  164. { hGroup.Delete(argv[iArg+1], fRecursive); iArg++; }
  165. break;
  166. // Sort
  167. case 's':
  168. // First sort parameter overrides default Clonk sort list
  169. C4Group_SetSortList(NULL);
  170. // Missing argument
  171. if ((iArg+1>=argc) || (argv[iArg+1][0]=='-'))
  172. printf("Missing argument for sort command\n");
  173. // Sort, advance to next argument
  174. else
  175. { hGroup.Sort(argv[iArg+1]); iArg++; }
  176. break;
  177. // Rename
  178. case 'r':
  179. if ((iArg+2>=argc) || (argv[iArg+1][0]=='-') || (argv[iArg+2][0]=='-'))
  180. printf("Missing argument(s) for rename command\n");
  181. else
  182. { hGroup.Rename(argv[iArg+1],argv[iArg+2]); iArg+=2; }
  183. break;
  184. // View
  185. case 'v':
  186. if ((iArg+1>=argc) || (argv[iArg+1][0]=='-'))
  187. { hGroup.View("*"); }
  188. else
  189. { hGroup.View(argv[iArg+1]); iArg++; }
  190. break;
  191. // Make original
  192. case 'o':
  193. hGroup.MakeOriginal(true);
  194. break;
  195. // Pack
  196. case 'p':
  197. printf("Packing...\n");
  198. // Close
  199. if (!hGroup.Close()) printf("Closing failed: %s\n",hGroup.GetError());
  200. // Pack
  201. else if (!C4Group_PackDirectory(szFilename)) printf("Pack failed\n");
  202. // Reopen
  203. else if (!hGroup.Open(szFilename)) printf("Reopen failed: %s\n",hGroup.GetError());
  204. break;
  205. // Unpack
  206. case 'u':
  207. printf("Unpacking...\n");
  208. // Close
  209. if (!hGroup.Close()) printf("Closing failed: %s\n",hGroup.GetError());
  210. // Unpack
  211. else if (!C4Group_UnpackDirectory(szFilename)) printf("Unpack failed\n");
  212. // Reopen
  213. else if (!hGroup.Open(szFilename)) printf("Reopen failed: %s\n",hGroup.GetError());
  214. break;
  215. // Unpack
  216. case 'x':
  217. printf("Exploding...\n");
  218. // Close
  219. if (!hGroup.Close()) printf("Closing failed: %s\n",hGroup.GetError());
  220. // Explode
  221. else if (!C4Group_ExplodeDirectory(szFilename)) printf("Unpack failed\n");
  222. // Reopen
  223. else if (!hGroup.Open(szFilename)) printf("Reopen failed: %s\n",hGroup.GetError());
  224. break;
  225. // Print maker
  226. case 'k':
  227. printf("%s\n",hGroup.GetMaker());
  228. break;
  229. // Generate update
  230. case 'g':
  231. if ((iArg + 3 >= argc) || (argv[iArg+1][0] == '-') || (argv[iArg+2][0] == '-') || (argv[iArg+3][0] == '-'))
  232. printf("Update generation failed: too few arguments\n");
  233. else
  234. {
  235. C4UpdatePackage Upd;
  236. // Close
  237. if (!hGroup.Close()) printf("Closing failed: %s\n",hGroup.GetError());
  238. // generate
  239. else if(!Upd.MakeUpdate(argv[iArg+1], argv[iArg+2], szFilename, argv[iArg+3]))
  240. printf("Update generation failed.\n");
  241. // Reopen
  242. else if (!hGroup.Open(szFilename)) printf("Reopen failed: %s\n",hGroup.GetError());
  243. iArg+=3;
  244. }
  245. break;
  246. // Apply update
  247. case 'y':
  248. printf("Applying update...\n");
  249. if (C4Group_ApplyUpdate(hGroup))
  250. { if (argv[iArg][2]=='d') fDeleteGroup = true; }
  251. else
  252. printf("Update failed.\n");
  253. break;
  254. // Optimize update generation target
  255. case 'z':
  256. if ((iArg + 1 >= argc) || (argv[iArg+1][0] == '-'))
  257. printf("Missing parameter for optimization\n");
  258. else
  259. {
  260. printf("Optimizing %s...\n", argv[iArg+1]);
  261. if(!C4UpdatePackage::Optimize(&hGroup, argv[iArg+1]))
  262. printf("Optimization failed.\n");
  263. iArg++;
  264. }
  265. break;
  266. #ifdef _DEBUG
  267. // Print internals
  268. case 'q':
  269. hGroup.PrintInternals();
  270. break;
  271. #endif
  272. // Wait
  273. case 'w':
  274. if ((iArg+1>=argc) || (argv[iArg+1][0]=='-'))
  275. printf("Missing argument for wait command\n");
  276. else
  277. {
  278. int iMilliseconds = 0;
  279. sscanf(argv[iArg+1], "%d", &iMilliseconds);
  280. // Wait for specified time
  281. if (iMilliseconds > 0)
  282. {
  283. printf("Waiting...\n");
  284. Sleep(iMilliseconds);
  285. }
  286. // Wait for specified process to end
  287. else
  288. {
  289. printf("Waiting for %s to end", argv[iArg+1]);
  290. for (int i = 0; FindWindow(NULL, argv[iArg+1]) && (i < 5); i++)
  291. {
  292. Sleep(1000);
  293. printf(".");
  294. }
  295. printf("\n");
  296. }
  297. iArg++;
  298. }
  299. break;
  300. // Undefined
  301. default:
  302. printf("Unknown command: %s\n",argv[iArg]);
  303. break;
  304. }
  305. }
  306. else
  307. {
  308. printf("Invalid parameter %s\n",argv[iArg]);
  309. }
  310. }
  311. // Error: output status
  312. if (!SEqual(hGroup.GetError(),"No Error"))
  313. printf("Status: %s\n",hGroup.GetError());
  314. // Close group file
  315. if (!hGroup.Close())
  316. printf("Closing: %s\n",hGroup.GetError());
  317. // Delete group file if desired (i.e. after apply update)
  318. if (fDeleteGroup)
  319. {
  320. printf("Deleting %s...\n", GetFilename(szFilename));
  321. EraseItem(szFilename);
  322. }
  323. }
  324. // Couldn't open group
  325. else
  326. {
  327. printf("Status: %s\n",hGroup.GetError());
  328. }
  329. // Done
  330. return true;
  331. }
  332. int RegisterShellExtensions()
  333. {
  334. #ifdef _WIN32
  335. char strModule[2048];
  336. char strCommand[2048];
  337. char strClass[128];
  338. GetModuleFileName(NULL, strModule, 2048);
  339. // Groups
  340. const char *strClasses = "Clonk4.Definition;Clonk4.Folder;Clonk4.Group;Clonk4.Player;Clonk4.Scenario;Clonk4.Update;Clonk4.Weblink;Clonk4.Object";
  341. for (int i = 0; SCopySegment(strClasses, i, strClass); i++)
  342. {
  343. // Unpack
  344. sprintf(strCommand, "\"%s\" \"%%1\" \"-u\"", strModule);
  345. if (!SetRegShell(strClass, "MakeFolder", "C4Group Unpack", strCommand)) return 0;
  346. // Explode
  347. sprintf(strCommand, "\"%s\" \"%%1\" \"-x\"", strModule);
  348. if (!SetRegShell(strClass, "ExplodeFolder", "C4Group Explode", strCommand)) return 0;
  349. }
  350. // Directories
  351. const char *strClasses2 = "Directory";
  352. for (int i = 0; SCopySegment(strClasses2, i, strClass); i++)
  353. {
  354. // Pack
  355. sprintf(strCommand, "\"%s\" \"%%1\" \"-p\"", strModule);
  356. if (!SetRegShell(strClass, "MakeGroupFile", "C4Group Pack", strCommand)) return 0;
  357. }
  358. // Done
  359. #endif
  360. return 1;
  361. }
  362. int UnregisterShellExtensions()
  363. {
  364. #ifdef _WIN32
  365. char strModule[2048];
  366. char strClass[128];
  367. GetModuleFileName(NULL, strModule, 2048);
  368. // Groups
  369. const char *strClasses = "Clonk4.Definition;Clonk4.Folder;Clonk4.Group;Clonk4.Player;Clonk4.Scenario;Clonk4.Update;Clonk4.Weblink";
  370. for (int i = 0; SCopySegment(strClasses, i, strClass); i++)
  371. {
  372. // Unpack
  373. if (!RemoveRegShell(strClass, "MakeFolder")) return 0;
  374. // Explode
  375. if (!RemoveRegShell(strClass, "ExplodeFolder")) return 0;
  376. }
  377. // Directories
  378. const char *strClasses2 = "Directory";
  379. for (int i = 0; SCopySegment(strClasses2, i, strClass); i++)
  380. {
  381. // Pack
  382. if (!RemoveRegShell(strClass, "MakeGroupFile")) return 0;
  383. }
  384. // Done
  385. #endif
  386. return 1;
  387. }
  388. bool Log(const char *msg)
  389. {
  390. if (!fQuiet)
  391. printf("%s\n", msg);
  392. return 1;
  393. }
  394. bool LogFatal(const char *msg) { return Log(msg); }
  395. bool LogF(const char *strMessage, ...)
  396. {
  397. va_list args; va_start(args, strMessage);
  398. // Compose formatted message
  399. StdStrBuf Buf;
  400. Buf.FormatV(strMessage, args);
  401. // Log
  402. return Log(Buf.getData());
  403. }
  404. void StdCompilerWarnCallback(void *pData, const char *szPosition, const char *szError)
  405. {
  406. const char *szName = reinterpret_cast<const char *>(pData);
  407. if(!szPosition || !*szPosition)
  408. LogF("WARNING: %s: %s", szName, szError);
  409. else
  410. LogF("WARNING: %s (%s): %s", szName, szPosition, szError);
  411. }
  412. int main(int argc, char *argv[])
  413. {
  414. // Scan options (scan including first parameter - this means the group filename cannot start with a '/'...)
  415. for (int i = 1; i < argc; i++)
  416. {
  417. // Option encountered
  418. if (argv[i][0]=='/')
  419. switch (argv[i][1])
  420. {
  421. // Quiet mode
  422. case 'q': fQuiet = true; break;
  423. // Recursive mode
  424. case 'r': fRecursive = true; break;
  425. // Register shell
  426. case 'i': fRegisterShell = true; break;
  427. // Unregister shell
  428. case 'u': fUnregisterShell = true; break;
  429. // Prompt at end
  430. case 'p': fPromptAtEnd = true; break;
  431. // Execute at end
  432. case 'x': SCopy(argv[i] + 3, strExecuteAtEnd, _MAX_PATH); break;
  433. // Unknown
  434. default: printf("Unknown option %s\n",argv[i]); break;
  435. }
  436. // Command encountered: no more options expected
  437. if (argv[i][0]=='-')
  438. {
  439. iFirstCommand = i;
  440. break;
  441. }
  442. }
  443. // Program info
  444. if (!fQuiet)
  445. printf("RedWolf Design C4Group %s\n", C4VERSION);
  446. // Registration check
  447. Config.Init();
  448. bool fWasQuiet = fQuiet; fQuiet = true; // prevent premature logging of registration error
  449. Config.Load(false);
  450. fQuiet = fWasQuiet;
  451. // Init C4Group
  452. C4Group_SetMaker(Config.General.Name); // This makes no sense if unregistered but it is assumed that no groups can be written if unregistered
  453. C4Group_SetTempPath(Config.General.TempPath);
  454. C4Group_SetSortList(C4CFN_FLS);
  455. // Display current working directory
  456. if (!fQuiet)
  457. {
  458. char strWorkingDirectory[_MAX_PATH+1] = "";
  459. GetCurrentDirectory(_MAX_PATH, strWorkingDirectory);
  460. printf("Location: %s\n", strWorkingDirectory);
  461. }
  462. // Store command line parameters
  463. globalArgC = argc;
  464. globalArgV = argv;
  465. // Register shell
  466. if (fRegisterShell)
  467. if (RegisterShellExtensions())
  468. printf("Shell extensions registered.\n");
  469. else
  470. printf("Error registering shell extensions. You might need administrator rights.\n");
  471. // Unregister shell
  472. if (fUnregisterShell)
  473. if (UnregisterShellExtensions())
  474. printf("Shell extensions removed.\n");
  475. else
  476. printf("Error removing shell extensions.\n");
  477. // At least one parameter (filename, not option or command): process file(s)
  478. if ((argc>1) && (argv[1][0] != '/') && (argv[1][0] != '-')) // ...remember filenames cannot start with a forward slash because of options format
  479. {
  480. // Wildcard in filename: use file search
  481. if (SCharCount('*',argv[1]))
  482. ForEachFile(argv[1], &ProcessGroup);
  483. // Only one file
  484. else
  485. ProcessGroup(argv[1]);
  486. }
  487. // Too few parameters: output help (if we didn't register stuff)
  488. else
  489. if (!fRegisterShell && !fUnregisterShell)
  490. {
  491. printf("\n");
  492. printf("Usage: c4group group [options] command(s)\n\n");
  493. printf("Commands: -a[s] Add [as] -m Move -e[t] Extract [to]\n");
  494. printf(" -v View -d Delete -r Rename -s Sort\n");
  495. printf(" -p Pack -u Unpack -x Explode\n");
  496. printf(" -k Print maker\n");
  497. printf(" -g [source] [target] [title] Make update\n");
  498. printf(" -y[d] Apply update [and delete group file]\n");
  499. printf(" -z Optimize a group to be similar (smaller update)\n");
  500. printf("\n");
  501. printf("Options: /q Quiet /r Recursive /p Prompt at end\n");
  502. printf(" /i Register shell /u Unregister shell\n");
  503. printf(" /x:<command> Execute shell command when done\n");
  504. printf("\n");
  505. printf("Examples: c4group pack.c4g -a myfile.dat -v *.dat\n");
  506. printf(" c4group pack.c4g -as myfile.dat myfile.bin\n");
  507. printf(" c4group pack.c4g -et *.dat \\data\\mydatfiles\\\n");
  508. printf(" c4group pack.c4g -et myfile.dat myfile.bak\n");
  509. printf(" c4group pack.c4g -s \"*.bin|*.dat\"\n");
  510. printf(" c4group pack.c4g -x\n");
  511. printf(" c4group pack.c4g /q -k\n");
  512. printf(" c4group update.c4u -g ver1.c4f ver2.c4f New_Version\n");
  513. printf(" c4group ver1.c4f -z ver2.c4f\n");
  514. printf(" c4group /i\n");
  515. }
  516. // Prompt at end
  517. if (fPromptAtEnd)
  518. {
  519. printf("\nDone. Press any key to continue.\n");
  520. _getch();
  521. }
  522. // Execute when done
  523. if (strExecuteAtEnd[0])
  524. {
  525. printf("Executing: %s\n", strExecuteAtEnd);
  526. STARTUPINFO startInfo;
  527. ZeroMem(&startInfo, sizeof(startInfo));
  528. startInfo.cb = sizeof(startInfo);
  529. PROCESS_INFORMATION procInfo;
  530. CreateProcess(strExecuteAtEnd, NULL, NULL, NULL, false, 0, NULL, NULL, &startInfo, &procInfo);
  531. }
  532. // Done
  533. return iResult;
  534. }