/* ** 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 . */ /****************************************************************************\ * 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: Carpenter (The RedAlert ladder creator) File Name : configfile.cpp Author : Neal Kettler Start Date : June 9, 1997 Last Update : June 17, 1997 This class will read in a config file and store the key value pairs for later access. This is a fairly simple class, the config file is assumed to be of the form: #comment key = value The value can then be retrieved as a string or an integer. The key on the left is used for retrieval and it must be specified in uppercase for the 'get' functions. E.g. getString("KEY",valWstring); \***************************************************************************/ #include #include #include #include "configfile.h" #include "wdebug.h" static uint32 Wstring_Hash(const Wstring &string); static char *Eat_Spaces(char *string); ConfigFile::ConfigFile() : Dictionary_(Wstring_Hash) { } ConfigFile::~ConfigFile() { } // Read and parse the config file. The key value pairs will be stored // for later access by the getString/getInt functions. bit8 ConfigFile::readFile(FILE *in) { char string[256]; char sectionname[256]; // section name like '[user parameters]' Wstring key; Wstring value; char *cptr; memset(string,0,256); memset(sectionname,0,256); sectionList.clear(); while (fgets(string,256,in)) { cptr=Eat_Spaces(string); if ((*cptr==0)||(*cptr=='#')) // '#' signals a comment continue; if (*cptr=='[') // new section { key=cptr; key.truncate(']'); // remove after & including the ] key.cat("]"); // put the ] back strcpy(sectionname,key.get()); // set the current section name Wstring wssectionname; if (strlen(sectionname)==2) // clear section with a "[]" { sectionname[0]=0; wssectionname.set(""); } else wssectionname.set(sectionname+1); wssectionname.truncate(']'); sectionList.addTail(wssectionname); continue; } if (strchr(cptr,'=')==NULL) // All config entries must have a '=' continue; key=cptr; key.truncate('='); key.removeSpaces(); // No spaces allowed in the key key.toUpper(); // make key all caps // Add the section name to the end of the key if (strlen(sectionname)) key.cat(sectionname); cptr=Eat_Spaces(strchr(cptr,'=')+1); // Jump to after the '=' value=cptr; value.truncate('\r'); value.truncate('\n'); value.truncate('#'); // Remove trailing spaces while(isgraph(value.get()[strlen(value.get())-1])==0) value.get()[strlen(value.get())-1]=0; Critsec_.lock(); Dictionary_.add(key,value); Critsec_.unlock(); } return(TRUE); } // // Enum through the config strings. To start, index & offset should be 0 // If retval is false you're done, ignore whatever's in key & value. // // Section specifies the configfile section. Set to NULL if you don't care. // bit8 ConfigFile::enumerate(int &index, int &offset, Wstring &key, Wstring &value, IN char *section) const { int seclen = strlen(section); while(1) { Critsec_.lock(); if (Dictionary_.iterate(index,offset,key,value)==FALSE) // out of keys? { Critsec_.unlock(); return(FALSE); } Critsec_.unlock(); if (section==NULL) // no specified section, so any will do... break; if (strlen(section)+2 >= strlen(key.get())) // key should have form: X[section] continue; // Is this key part of our section? const char *keystr = key.get() + strlen(key.get())-seclen-1; if (strncmp(keystr,section,strlen(section))==0) break; } key.truncate('['); // remove the section name return(TRUE); } // Get a config entry as a string bit8 ConfigFile::getString(IN Wstring &_key, Wstring &value, IN char *section) const { Wstring key(_key); key.toUpper(); if (section) // append section name to key { key+="["; key+=section; key+="]"; } Critsec_.lock(); bit8 retval=Dictionary_.getValue(key,value); Critsec_.unlock(); if (retval==FALSE) { DBGMSG("Config entry missing: "<>24); // ROL 8 } return(retval); } static char *Eat_Spaces(char *string) { char *retval=string; while (isspace(*retval)) retval++; return(retval); }