mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 15:41:39 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
510
Code/wwlib/argv.cpp
Normal file
510
Code/wwlib/argv.cpp
Normal file
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
** Command & Conquer Renegade(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* $Header: /VSS_Sync/wwlib/argv.cpp 11 8/29/01 10:25p Vss_sync $ */
|
||||
/***********************************************************************************************
|
||||
*** 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 ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Library *
|
||||
* *
|
||||
* $Archive:: /VSS_Sync/wwlib/argv.cpp $*
|
||||
* *
|
||||
* $Author:: Vss_sync $*
|
||||
* *
|
||||
* $Modtime:: 8/29/01 10:24p $*
|
||||
* *
|
||||
* $Revision:: 11 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* CurrentPos -- Create an instance to parse argv with. *
|
||||
* ArgvClass::Free -- Release data allocated. *
|
||||
* ArgvClass::Load_File -- Load args from a file. *
|
||||
* *ArgvClass::Find_Value -- Find value of argument given prefix. *
|
||||
* *ArgvClass::Get_Cur_Value -- Get value of current argugment. *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
#include "argv.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ffactory.h"
|
||||
#include "rawfile.h"
|
||||
int ArgvClass::Argc = 0;
|
||||
char *ArgvClass::Argv[MAX_ARGC];
|
||||
|
||||
/***********************************************************************************************
|
||||
* CurrentPos -- Create an instance to parse argv with. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* bool case_sensitive - Do you want to perform a case sensitive search (stricmp)? *
|
||||
* bool exact_size - Do you want string of same lenght (strncmp) ? *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/18/1999 SKB : Created. *
|
||||
*=============================================================================================*/
|
||||
ArgvClass::ArgvClass(bool case_sensitive, bool exact_size):
|
||||
Flags(0),
|
||||
LastArg(0),
|
||||
CurrentPos(-1)
|
||||
{
|
||||
Case_Sensitive(case_sensitive);
|
||||
Exact_Size(exact_size);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* *ArgvClass::Find_Again -- Search for a string given the flags. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* const char *arg - String to search for. If NULL, LastArg will be used. *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* const char *string found (null if not found) *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/17/1999 SKB : Created. *
|
||||
*=============================================================================================*/
|
||||
const char *ArgvClass::Find_Again(const char *arg)
|
||||
{
|
||||
if (arg) {
|
||||
LastArg = arg;
|
||||
} else {
|
||||
arg = LastArg;
|
||||
}
|
||||
|
||||
// Make sure user has given us something to work with here.
|
||||
assert(LastArg);
|
||||
|
||||
CurrentPos++;
|
||||
if (CurrentPos < Argc) {
|
||||
if (Is_Case_Sensitive()) {
|
||||
if (Is_Exact_Size()) {
|
||||
// Case Sensitive, Exact Size.
|
||||
for (; CurrentPos < Argc; CurrentPos++) {
|
||||
if (!strcmp(arg, Argv[CurrentPos])) {
|
||||
return Argv[CurrentPos];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Case Sensitive, Match first strlen(arg).
|
||||
int len = strlen(arg);
|
||||
for (; CurrentPos < Argc; CurrentPos++) {
|
||||
if (!strncmp(arg, Argv[CurrentPos], len)) {
|
||||
return Argv[CurrentPos];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Is_Exact_Size()) {
|
||||
// Note case sensitive, Exact Size.
|
||||
for (; CurrentPos < Argc; CurrentPos++) {
|
||||
if (!stricmp(arg, Argv[CurrentPos])) {
|
||||
return Argv[CurrentPos];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Note case sensitive, Match first strlen(arg).
|
||||
int len = strlen(arg);
|
||||
for (; CurrentPos < Argc; CurrentPos++) {
|
||||
if (!strnicmp(arg, Argv[CurrentPos], len)) {
|
||||
return Argv[CurrentPos];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* ArgvClass::Init -- Setup the command line. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* LPSTR lpCmdLine - A string of white space seperated strings. Quotes force spaces to *
|
||||
* be ignored. *
|
||||
* char *fileprefix - A prefix on an arguement telling system to load postfix file name *
|
||||
* as command line params. *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* This may be called multible times with different strings. *
|
||||
* Once Argc reaches MAX_ARGC, no more will be added. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/17/1999 SKB : Created. *
|
||||
* 07/15/2001 SKB : Put file arguements in the correct order they were included. *
|
||||
*=============================================================================================*/
|
||||
int ArgvClass::Init(char *lpCmdLine, char *fileprefix)
|
||||
{
|
||||
// Get pointer to command line.
|
||||
char *ptr = lpCmdLine;
|
||||
if (!ptr || !*ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fp_cmp_len = (fileprefix) ? strlen(fileprefix) : 0;
|
||||
|
||||
// Save original Argc for return.
|
||||
int origargc = Argc;
|
||||
|
||||
while (*ptr) {
|
||||
char *eos;
|
||||
char save;
|
||||
|
||||
// Keep anything within quotes as one string.
|
||||
if (*ptr == '"') {
|
||||
ptr++;
|
||||
eos = ptr;
|
||||
// Search for next " or a null.
|
||||
while (*eos && (*eos != '"')) {
|
||||
eos++;
|
||||
}
|
||||
} else if (isspace(*ptr)) {
|
||||
ptr++;
|
||||
continue;
|
||||
} else {
|
||||
eos = ptr + 1;
|
||||
// search for next white space or null.
|
||||
while (*eos && !isspace(*eos)) {
|
||||
eos++;
|
||||
}
|
||||
}
|
||||
|
||||
// Null out end of string so string function work.
|
||||
// Save the end to restore later.
|
||||
save = *eos;
|
||||
*eos = 0;
|
||||
|
||||
bool was_file = false;
|
||||
|
||||
// See if we are to load a file with parameters in it.
|
||||
if (fp_cmp_len && !strncmp(fileprefix, ptr, fp_cmp_len)) {
|
||||
ptr += fp_cmp_len;
|
||||
if (*ptr) {
|
||||
was_file = Load_File(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// If it was not the file or the load failed...then add parameter.
|
||||
if (!was_file) {
|
||||
// Copy string over and continue.
|
||||
Argv[Argc] = strdup(ptr);
|
||||
Argc++;
|
||||
}
|
||||
|
||||
// If save is null, then we are at the end and we can bail out.
|
||||
if (!save) break;
|
||||
|
||||
// resore whitespace.
|
||||
*eos = save;
|
||||
ptr = eos + 1;
|
||||
}
|
||||
|
||||
// Return number of params read in.
|
||||
return(Argc - origargc);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* ArgvClass::Load_File -- Load args from a file. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* const char *fname - file to load. *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/18/1999 SKB : Created. *
|
||||
*=============================================================================================*/
|
||||
bool ArgvClass::Load_File(const char *fname)
|
||||
{
|
||||
file_auto_ptr fileap(_TheFileFactory, fname);
|
||||
|
||||
FILE *fp = fopen(fileap->File_Name(), "r");
|
||||
|
||||
// [SKB: May 08 2001 @ 8:42pm] :
|
||||
// If file factor fails to return a valid name (i.e. can't open the file),
|
||||
// then see if user (namely me) specified a full path for the file and see
|
||||
// if we can open just fname.
|
||||
if (!fp)
|
||||
fp = fopen(fname, "r");
|
||||
|
||||
if (fp) {
|
||||
while (Argc < MAX_ARGC) {
|
||||
const int maxstrlen = 255;
|
||||
char string[maxstrlen + 1];
|
||||
|
||||
// Get next line in file.
|
||||
if (!fgets(string, maxstrlen - 1, fp)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for comments.
|
||||
if ((*string != '#') && (*string != ';')) {
|
||||
// Make sure null terminated.
|
||||
string[maxstrlen - 1] = '\0';
|
||||
|
||||
char *ptr = string + (strlen(string) - 1);
|
||||
while (*ptr <= ' ') {
|
||||
*ptr = 0;
|
||||
|
||||
// Is it just a blank line?
|
||||
if (ptr == string) {
|
||||
break;
|
||||
}
|
||||
ptr--;
|
||||
}
|
||||
|
||||
// If there is anyting in the string. (NAK: old code used to fail for 1 char options)
|
||||
if (strlen(string)) {
|
||||
Argv[Argc] = strdup(string);
|
||||
Argc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* ArgvClass::Free -- Release data allocated. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/18/1999 SKB : Created. *
|
||||
*=============================================================================================*/
|
||||
void ArgvClass::Free()
|
||||
{
|
||||
for (int lp = 0; lp < Argc; lp++) {
|
||||
free(Argv[lp]);
|
||||
Argv[lp] = 0;
|
||||
}
|
||||
Argc = -1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* *ArgvClass::Find_Value -- Find value of argument given prefix. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/23/1999 SKB : Created. *
|
||||
*=============================================================================================*/
|
||||
const char *ArgvClass::Find_Value(const char *arg)
|
||||
{
|
||||
if (arg && *arg) {
|
||||
const char *ptr = Find(arg);
|
||||
if (ptr) {
|
||||
return(Get_Cur_Value(strlen(arg)));
|
||||
}
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* *ArgvClass::Get_Cur_Value -- Get value of current argugment. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/23/1999 SKB : Created. *
|
||||
* 06/25/2001 SKB : add flag user can check to see if value was extracted from next location.*
|
||||
*=============================================================================================*/
|
||||
const char *ArgvClass::Get_Cur_Value(unsigned prefixlen, bool * val_in_next)
|
||||
{
|
||||
if (val_in_next) *val_in_next = false;
|
||||
if (CurrentPos < 0) {
|
||||
return NULL;
|
||||
}
|
||||
char *ptr = Argv[CurrentPos];
|
||||
|
||||
if (strlen(ptr) < prefixlen) {
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
ptr += prefixlen;
|
||||
|
||||
// Look for non white space (or eol).
|
||||
while (*ptr && !isgraph(*ptr)) {
|
||||
ptr++;
|
||||
}
|
||||
if (*ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Goto next line to handle '-P data' case on command line.
|
||||
ptr = Argv[CurrentPos + 1];
|
||||
if (!ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (*ptr) {
|
||||
if (isgraph(*ptr)) {
|
||||
if (val_in_next) *val_in_next = true;
|
||||
return ptr;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* void ArgvClass::Update_Value -- Add/Replace a value *
|
||||
* *
|
||||
* INPUT: *
|
||||
* attrib = cmd line attrib to add/replace *
|
||||
* value = new value for attrib *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: Not Tested! *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/13/1999 NAK : Created. *
|
||||
*=============================================================================================*/
|
||||
void ArgvClass::Update_Value(const char *attrib, const char *value)
|
||||
{
|
||||
if ((Find_Value(attrib))!=NULL)
|
||||
{
|
||||
if (((CurrentPos+1) < Argc) && (Argv[CurrentPos+1][0] != '-')) // update old value
|
||||
{
|
||||
free(Argv[CurrentPos+1]);
|
||||
Argv[CurrentPos+1]=strdup(value);
|
||||
}
|
||||
else // add new value
|
||||
{
|
||||
// shift vals down to make room
|
||||
memmove(&(Argv[CurrentPos+2]),&(Argv[CurrentPos+1]),sizeof(char *) * (MAX_ARGC-CurrentPos-2));
|
||||
Argv[CurrentPos+1]=strdup(value);
|
||||
Argc++;
|
||||
}
|
||||
}
|
||||
else // just add the new stuff
|
||||
Add_Value(attrib, value);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* void ArgvClass::Add_Value -- Add a value *
|
||||
* *
|
||||
* INPUT: *
|
||||
* attrib = thing to add *
|
||||
* value = new optional value *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/13/1999 NAK : Created. *
|
||||
*=============================================================================================*/
|
||||
void ArgvClass::Add_Value(const char *attrib, const char *value)
|
||||
{
|
||||
if (attrib)
|
||||
{
|
||||
Argv[Argc]=strdup(attrib);
|
||||
Argc++;
|
||||
|
||||
if (value)
|
||||
{
|
||||
Argv[Argc]=strdup(value);
|
||||
Argc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* bool ArgvClass::Remove_Value -- Remove a value *
|
||||
* *
|
||||
* INPUT: *
|
||||
* attrib = thing to remove *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* THIS CONTAINS A POTENTIAL BUG - I don't want to fix it because it might be a desired *
|
||||
* behavior. Given: *
|
||||
* Argv[0] = "-i test" "*.txt" as values in Argv, *
|
||||
* calling Remove_Value("-i") will remove *.txt as well. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/13/1999 NAK : Created. *
|
||||
* 06/25/2001 SKB : WARNINGS message *
|
||||
*=============================================================================================*/
|
||||
bool ArgvClass::Remove_Value(const char *attrib)
|
||||
{
|
||||
int removeCount=1;
|
||||
|
||||
if ((Find_Value(attrib))!=NULL)
|
||||
{
|
||||
free(Argv[CurrentPos]);
|
||||
if (((CurrentPos+1) < Argc)&&(Argv[CurrentPos+1][0]!='-')) // value for this arg
|
||||
{
|
||||
free(Argv[CurrentPos+1]);
|
||||
removeCount=2;
|
||||
}
|
||||
memmove(&(Argv[CurrentPos]),&(Argv[CurrentPos+removeCount]),sizeof(char *) * (MAX_ARGC-CurrentPos-removeCount));
|
||||
|
||||
Argc-=removeCount;
|
||||
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user