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