argv.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /VSS_Sync/wwlib/argv.cpp 11 8/29/01 10:25p Vss_sync $ */
  19. /***********************************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Library *
  24. * *
  25. * $Archive:: /VSS_Sync/wwlib/argv.cpp $*
  26. * *
  27. * $Author:: Vss_sync $*
  28. * *
  29. * $Modtime:: 8/29/01 10:24p $*
  30. * *
  31. * $Revision:: 11 $*
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * CurrentPos -- Create an instance to parse argv with. *
  36. * ArgvClass::Free -- Release data allocated. *
  37. * ArgvClass::Load_File -- Load args from a file. *
  38. * *ArgvClass::Find_Value -- Find value of argument given prefix. *
  39. * *ArgvClass::Get_Cur_Value -- Get value of current argugment. *
  40. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  41. #include "argv.h"
  42. #include <assert.h>
  43. #include <ctype.h>
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include "ffactory.h"
  48. #include "rawfile.h"
  49. int ArgvClass::Argc = 0;
  50. char *ArgvClass::Argv[MAX_ARGC];
  51. /***********************************************************************************************
  52. * CurrentPos -- Create an instance to parse argv with. *
  53. * *
  54. * INPUT: *
  55. * bool case_sensitive - Do you want to perform a case sensitive search (stricmp)? *
  56. * bool exact_size - Do you want string of same lenght (strncmp) ? *
  57. * *
  58. * OUTPUT: *
  59. * *
  60. * WARNINGS: *
  61. * *
  62. * HISTORY: *
  63. * 06/18/1999 SKB : Created. *
  64. *=============================================================================================*/
  65. ArgvClass::ArgvClass(bool case_sensitive, bool exact_size):
  66. Flags(0),
  67. LastArg(0),
  68. CurrentPos(-1)
  69. {
  70. Case_Sensitive(case_sensitive);
  71. Exact_Size(exact_size);
  72. }
  73. /***********************************************************************************************
  74. * *ArgvClass::Find_Again -- Search for a string given the flags. *
  75. * *
  76. * INPUT: *
  77. * const char *arg - String to search for. If NULL, LastArg will be used. *
  78. * *
  79. * OUTPUT: *
  80. * const char *string found (null if not found) *
  81. * *
  82. * WARNINGS: *
  83. * *
  84. * HISTORY: *
  85. * 06/17/1999 SKB : Created. *
  86. *=============================================================================================*/
  87. const char *ArgvClass::Find_Again(const char *arg)
  88. {
  89. if (arg) {
  90. LastArg = arg;
  91. } else {
  92. arg = LastArg;
  93. }
  94. // Make sure user has given us something to work with here.
  95. assert(LastArg);
  96. CurrentPos++;
  97. if (CurrentPos < Argc) {
  98. if (Is_Case_Sensitive()) {
  99. if (Is_Exact_Size()) {
  100. // Case Sensitive, Exact Size.
  101. for (; CurrentPos < Argc; CurrentPos++) {
  102. if (!strcmp(arg, Argv[CurrentPos])) {
  103. return Argv[CurrentPos];
  104. }
  105. }
  106. } else {
  107. // Case Sensitive, Match first strlen(arg).
  108. int len = strlen(arg);
  109. for (; CurrentPos < Argc; CurrentPos++) {
  110. if (!strncmp(arg, Argv[CurrentPos], len)) {
  111. return Argv[CurrentPos];
  112. }
  113. }
  114. }
  115. } else {
  116. if (Is_Exact_Size()) {
  117. // Note case sensitive, Exact Size.
  118. for (; CurrentPos < Argc; CurrentPos++) {
  119. if (!stricmp(arg, Argv[CurrentPos])) {
  120. return Argv[CurrentPos];
  121. }
  122. }
  123. } else {
  124. // Note case sensitive, Match first strlen(arg).
  125. int len = strlen(arg);
  126. for (; CurrentPos < Argc; CurrentPos++) {
  127. if (!strnicmp(arg, Argv[CurrentPos], len)) {
  128. return Argv[CurrentPos];
  129. }
  130. }
  131. }
  132. }
  133. }
  134. return NULL;
  135. }
  136. /***********************************************************************************************
  137. * ArgvClass::Init -- Setup the command line. *
  138. * *
  139. * INPUT: *
  140. * LPSTR lpCmdLine - A string of white space seperated strings. Quotes force spaces to *
  141. * be ignored. *
  142. * char *fileprefix - A prefix on an arguement telling system to load postfix file name *
  143. * as command line params. *
  144. * *
  145. * OUTPUT: *
  146. * *
  147. * WARNINGS: *
  148. * This may be called multible times with different strings. *
  149. * Once Argc reaches MAX_ARGC, no more will be added. *
  150. * *
  151. * HISTORY: *
  152. * 06/17/1999 SKB : Created. *
  153. * 07/15/2001 SKB : Put file arguements in the correct order they were included. *
  154. *=============================================================================================*/
  155. int ArgvClass::Init(char *lpCmdLine, char *fileprefix)
  156. {
  157. // Get pointer to command line.
  158. char *ptr = lpCmdLine;
  159. if (!ptr || !*ptr) {
  160. return 0;
  161. }
  162. int fp_cmp_len = (fileprefix) ? strlen(fileprefix) : 0;
  163. // Save original Argc for return.
  164. int origargc = Argc;
  165. while (*ptr) {
  166. char *eos;
  167. char save;
  168. // Keep anything within quotes as one string.
  169. if (*ptr == '"') {
  170. ptr++;
  171. eos = ptr;
  172. // Search for next " or a null.
  173. while (*eos && (*eos != '"')) {
  174. eos++;
  175. }
  176. } else if (isspace(*ptr)) {
  177. ptr++;
  178. continue;
  179. } else {
  180. eos = ptr + 1;
  181. // search for next white space or null.
  182. while (*eos && !isspace(*eos)) {
  183. eos++;
  184. }
  185. }
  186. // Null out end of string so string function work.
  187. // Save the end to restore later.
  188. save = *eos;
  189. *eos = 0;
  190. bool was_file = false;
  191. // See if we are to load a file with parameters in it.
  192. if (fp_cmp_len && !strncmp(fileprefix, ptr, fp_cmp_len)) {
  193. ptr += fp_cmp_len;
  194. if (*ptr) {
  195. was_file = Load_File(ptr);
  196. }
  197. }
  198. // If it was not the file or the load failed...then add parameter.
  199. if (!was_file) {
  200. // Copy string over and continue.
  201. Argv[Argc] = strdup(ptr);
  202. Argc++;
  203. }
  204. // If save is null, then we are at the end and we can bail out.
  205. if (!save) break;
  206. // resore whitespace.
  207. *eos = save;
  208. ptr = eos + 1;
  209. }
  210. // Return number of params read in.
  211. return(Argc - origargc);
  212. }
  213. /***********************************************************************************************
  214. * ArgvClass::Load_File -- Load args from a file. *
  215. * *
  216. * INPUT: *
  217. * const char *fname - file to load. *
  218. * *
  219. * OUTPUT: *
  220. * *
  221. * WARNINGS: *
  222. * *
  223. * HISTORY: *
  224. * 06/18/1999 SKB : Created. *
  225. *=============================================================================================*/
  226. bool ArgvClass::Load_File(const char *fname)
  227. {
  228. file_auto_ptr fileap(_TheFileFactory, fname);
  229. FILE *fp = fopen(fileap->File_Name(), "r");
  230. // [SKB: May 08 2001 @ 8:42pm] :
  231. // If file factor fails to return a valid name (i.e. can't open the file),
  232. // then see if user (namely me) specified a full path for the file and see
  233. // if we can open just fname.
  234. if (!fp)
  235. fp = fopen(fname, "r");
  236. if (fp) {
  237. while (Argc < MAX_ARGC) {
  238. const int maxstrlen = 255;
  239. char string[maxstrlen + 1];
  240. // Get next line in file.
  241. if (!fgets(string, maxstrlen - 1, fp)) {
  242. break;
  243. }
  244. // Check for comments.
  245. if ((*string != '#') && (*string != ';')) {
  246. // Make sure null terminated.
  247. string[maxstrlen - 1] = '\0';
  248. char *ptr = string + (strlen(string) - 1);
  249. while (*ptr <= ' ') {
  250. *ptr = 0;
  251. // Is it just a blank line?
  252. if (ptr == string) {
  253. break;
  254. }
  255. ptr--;
  256. }
  257. // If there is anyting in the string. (NAK: old code used to fail for 1 char options)
  258. if (strlen(string)) {
  259. Argv[Argc] = strdup(string);
  260. Argc++;
  261. }
  262. }
  263. }
  264. fclose(fp);
  265. return(true);
  266. }
  267. return(false);
  268. }
  269. /***********************************************************************************************
  270. * ArgvClass::Free -- Release data allocated. *
  271. * *
  272. * INPUT: *
  273. * *
  274. * OUTPUT: *
  275. * *
  276. * WARNINGS: *
  277. * *
  278. * HISTORY: *
  279. * 06/18/1999 SKB : Created. *
  280. *=============================================================================================*/
  281. void ArgvClass::Free()
  282. {
  283. for (int lp = 0; lp < Argc; lp++) {
  284. free(Argv[lp]);
  285. Argv[lp] = 0;
  286. }
  287. Argc = -1;
  288. }
  289. /***********************************************************************************************
  290. * *ArgvClass::Find_Value -- Find value of argument given prefix. *
  291. * *
  292. * INPUT: *
  293. * *
  294. * OUTPUT: *
  295. * *
  296. * WARNINGS: *
  297. * *
  298. * HISTORY: *
  299. * 08/23/1999 SKB : Created. *
  300. *=============================================================================================*/
  301. const char *ArgvClass::Find_Value(const char *arg)
  302. {
  303. if (arg && *arg) {
  304. const char *ptr = Find(arg);
  305. if (ptr) {
  306. return(Get_Cur_Value(strlen(arg)));
  307. }
  308. }
  309. return(NULL);
  310. }
  311. /***********************************************************************************************
  312. * *ArgvClass::Get_Cur_Value -- Get value of current argugment. *
  313. * *
  314. * INPUT: *
  315. * *
  316. * OUTPUT: *
  317. * *
  318. * WARNINGS: *
  319. * *
  320. * HISTORY: *
  321. * 08/23/1999 SKB : Created. *
  322. * 06/25/2001 SKB : add flag user can check to see if value was extracted from next location.*
  323. *=============================================================================================*/
  324. const char *ArgvClass::Get_Cur_Value(unsigned prefixlen, bool * val_in_next)
  325. {
  326. if (val_in_next) *val_in_next = false;
  327. if (CurrentPos < 0) {
  328. return NULL;
  329. }
  330. char *ptr = Argv[CurrentPos];
  331. if (strlen(ptr) < prefixlen) {
  332. return(NULL);
  333. }
  334. ptr += prefixlen;
  335. // Look for non white space (or eol).
  336. while (*ptr && !isgraph(*ptr)) {
  337. ptr++;
  338. }
  339. if (*ptr) {
  340. return ptr;
  341. }
  342. // Goto next line to handle '-P data' case on command line.
  343. ptr = Argv[CurrentPos + 1];
  344. if (!ptr) {
  345. return NULL;
  346. }
  347. while (*ptr) {
  348. if (isgraph(*ptr)) {
  349. if (val_in_next) *val_in_next = true;
  350. return ptr;
  351. }
  352. ptr++;
  353. }
  354. return (NULL);
  355. }
  356. /***********************************************************************************************
  357. * void ArgvClass::Update_Value -- Add/Replace a value *
  358. * *
  359. * INPUT: *
  360. * attrib = cmd line attrib to add/replace *
  361. * value = new value for attrib *
  362. * *
  363. * OUTPUT: *
  364. * *
  365. * WARNINGS: Not Tested! *
  366. * *
  367. * HISTORY: *
  368. * 12/13/1999 NAK : Created. *
  369. *=============================================================================================*/
  370. void ArgvClass::Update_Value(const char *attrib, const char *value)
  371. {
  372. if ((Find_Value(attrib))!=NULL)
  373. {
  374. if (((CurrentPos+1) < Argc) && (Argv[CurrentPos+1][0] != '-')) // update old value
  375. {
  376. free(Argv[CurrentPos+1]);
  377. Argv[CurrentPos+1]=strdup(value);
  378. }
  379. else // add new value
  380. {
  381. // shift vals down to make room
  382. memmove(&(Argv[CurrentPos+2]),&(Argv[CurrentPos+1]),sizeof(char *) * (MAX_ARGC-CurrentPos-2));
  383. Argv[CurrentPos+1]=strdup(value);
  384. Argc++;
  385. }
  386. }
  387. else // just add the new stuff
  388. Add_Value(attrib, value);
  389. }
  390. /***********************************************************************************************
  391. * void ArgvClass::Add_Value -- Add a value *
  392. * *
  393. * INPUT: *
  394. * attrib = thing to add *
  395. * value = new optional value *
  396. * *
  397. * OUTPUT: *
  398. * *
  399. * WARNINGS: *
  400. * *
  401. * HISTORY: *
  402. * 12/13/1999 NAK : Created. *
  403. *=============================================================================================*/
  404. void ArgvClass::Add_Value(const char *attrib, const char *value)
  405. {
  406. if (attrib)
  407. {
  408. Argv[Argc]=strdup(attrib);
  409. Argc++;
  410. if (value)
  411. {
  412. Argv[Argc]=strdup(value);
  413. Argc++;
  414. }
  415. }
  416. }
  417. /***********************************************************************************************
  418. * bool ArgvClass::Remove_Value -- Remove a value *
  419. * *
  420. * INPUT: *
  421. * attrib = thing to remove *
  422. * *
  423. * OUTPUT: *
  424. * *
  425. * WARNINGS: *
  426. * THIS CONTAINS A POTENTIAL BUG - I don't want to fix it because it might be a desired *
  427. * behavior. Given: *
  428. * Argv[0] = "-i test" "*.txt" as values in Argv, *
  429. * calling Remove_Value("-i") will remove *.txt as well. *
  430. * *
  431. * HISTORY: *
  432. * 12/13/1999 NAK : Created. *
  433. * 06/25/2001 SKB : WARNINGS message *
  434. *=============================================================================================*/
  435. bool ArgvClass::Remove_Value(const char *attrib)
  436. {
  437. int removeCount=1;
  438. if ((Find_Value(attrib))!=NULL)
  439. {
  440. free(Argv[CurrentPos]);
  441. if (((CurrentPos+1) < Argc)&&(Argv[CurrentPos+1][0]!='-')) // value for this arg
  442. {
  443. free(Argv[CurrentPos+1]);
  444. removeCount=2;
  445. }
  446. memmove(&(Argv[CurrentPos]),&(Argv[CurrentPos+removeCount]),sizeof(char *) * (MAX_ARGC-CurrentPos-removeCount));
  447. Argc-=removeCount;
  448. return(true);
  449. }
  450. return(false);
  451. }