diff options
author | om <om@e03df62e-2008-0410-955e-edbf42e46eb7> | 2006-04-04 05:55:54 +0000 |
---|---|---|
committer | om <om@e03df62e-2008-0410-955e-edbf42e46eb7> | 2006-04-04 05:55:54 +0000 |
commit | 54963bee7003f65f5412ea52133b1a00c3b0763e (patch) | |
tree | d36a4fac2a323cf7be8a42312dc95fabb4924500 | |
parent | 7db1335b25f6a6cc884368138df4d16a1cafd493 (diff) |
All new shiny config parser, there's probably some bugs there somewhere but hey...I've been up all night. make clean before you try and compile this. Really. And nobody dare complain
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@3817 e03df62e-2008-0410-955e-edbf42e46eb7
-rw-r--r-- | include/globals.h | 3 | ||||
-rw-r--r-- | include/helperfuncs.h | 2 | ||||
-rw-r--r-- | include/inspircd_io.h | 64 | ||||
-rw-r--r-- | include/modules.h | 6 | ||||
-rw-r--r-- | src/channels.cpp | 1 | ||||
-rw-r--r-- | src/cmd_oper.cpp | 19 | ||||
-rw-r--r-- | src/cmd_stats.cpp | 15 | ||||
-rw-r--r-- | src/commands.cpp | 12 | ||||
-rw-r--r-- | src/helperfuncs.cpp | 13 | ||||
-rw-r--r-- | src/inspircd_io.cpp | 904 | ||||
-rw-r--r-- | src/modules.cpp | 116 |
11 files changed, 531 insertions, 624 deletions
diff --git a/include/globals.h b/include/globals.h index e9f106b05..9fd7e3705 100644 --- a/include/globals.h +++ b/include/globals.h @@ -27,6 +27,9 @@ #include "channels.h" typedef std::deque<std::string> file_cache; +typedef std::pair< std::string, std::string > KeyVal; +typedef std::vector< KeyVal > KeyValList; +typedef std::multimap< std::string, KeyValList > ConfigDataHash; void WriteOpers(char* text, ...); void log(int level, char *text, ...); diff --git a/include/helperfuncs.h b/include/helperfuncs.h index 90c23f776..3eeed21b6 100644 --- a/include/helperfuncs.h +++ b/include/helperfuncs.h @@ -53,7 +53,7 @@ void WriteCommonExcept_NoFormat(userrec *u, const char* text); std::string GetServerDescription(char* servername); void WriteCommon(userrec *u, char* text, ...); void WriteCommonExcept(userrec *u, char* text, ...); -void WriteOpers(char* text, ...); +void WriteOpers(const char* text, ...); void WriteMode(const char* modes, int flags, const char* text, ...); void NoticeAll(userrec *source, bool local_only, char* text, ...); void ServerNoticeAll(char* text, ...); diff --git a/include/inspircd_io.h b/include/inspircd_io.h index 9b9e1143a..a9de29917 100644 --- a/include/inspircd_io.h +++ b/include/inspircd_io.h @@ -20,6 +20,7 @@ #include <sstream> #include <string> #include <vector> +#include <map> #include "inspircd.h" #include "globals.h" #include "modules.h" @@ -70,25 +71,24 @@ class ServerConfig : public classbase */ std::vector<std::string> include_stack; - /** Used by the config file subsystem to - * safely read a C-style string without - * dependency upon any certain style of - * linefeed, e.g. it can read both windows - * and UNIX style linefeeds transparently. - */ - int fgets_safe(char* buffer, size_t maxsize, FILE* &file); - /** This private method processes one line of * configutation, appending errors to errorstream * and setting error if an error has occured. */ - std::string ConfProcess(char* buffer, long linenumber, std::stringstream* errorstream, bool &error, std::string filename); + bool ParseLine(ConfigDataHash &target, std::string &line, long linenumber, std::ostringstream &errorstream); + + bool DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream); /** Check that there is only one of each configuration item */ bool CheckOnce(char* tag, bool bail, userrec* user); - + public: + + /** This holds all the information in the config file, + * it's indexed by tag name to a vector of key/values. + */ + ConfigDataHash config_data; /** Holds the server name of the local server * as defined by the administrator. @@ -275,15 +275,6 @@ class ServerConfig : public classbase */ char PID[1024]; - /** The parsed configuration file as a stringstream. - * You should pass this to any configuration methods - * of this class, and not access it directly. It is - * recommended that modules use ConfigReader instead - * which provides a simpler abstraction of configuration - * files. - */ - std::stringstream config_f; - /** The connect classes in use by the IRC server. */ ClassVector Classes; @@ -349,13 +340,34 @@ class ServerConfig : public classbase */ void Read(bool bail, userrec* user); - bool LoadConf(const char* filename, std::stringstream *target, std::stringstream* errorstream); - int ConfValue(char* tag, char* var, int index, char *result, std::stringstream *config); - int ConfValueInteger(char* tag, char* var, int index, std::stringstream *config); - int ReadConf(std::stringstream *config_f,const char* tag, const char* var, int index, char *result); - int ConfValueEnum(char* tag,std::stringstream *config); - int EnumConf(std::stringstream *config_f,const char* tag); - int EnumValues(std::stringstream *config, const char* tag, int index); + /** Load 'filename' into 'target', with the new config parser everything is parsed into + * tag/key/value at load-time rather than at read-value time. + */ + bool LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream); + bool LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream); + + /* Both these return true if the value existed or false otherwise */ + + /* Writes 'length' chars into 'result' as a string */ + bool ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length); + bool ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result); + + /* Tries to convert the value to an integer and write it to 'result' */ + bool ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, int index, int &result); + bool ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, int &result); + + /* Returns true if the value exists and has a true value, false otherwise */ + bool ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, int index); + bool ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, int index); + + /* Returns the number of occurences of tag in the config file */ + int ConfValueEnum(ConfigDataHash &target, const char* tag); + int ConfValueEnum(ConfigDataHash &target, const std::string &tag); + + /* Returns the numbers of vars inside the index'th 'tag in the config file */ + int ConfVarEnum(ConfigDataHash &target, const char* tag, int index); + int ConfVarEnum(ConfigDataHash &target, const std::string &tag, int index); + Module* GetIOHook(int port); bool AddIOHook(int port, Module* iomod); bool DelIOHook(int port); diff --git a/include/modules.h b/include/modules.h index 88d4eecdf..a57fbef1a 100644 --- a/include/modules.h +++ b/include/modules.h @@ -64,6 +64,7 @@ enum TargetTypeFlags { TYPE_OTHER }; +#include "globals.h" #include "dynamic.h" #include "base.h" #include "ctables.h" @@ -1778,10 +1779,11 @@ class ConfigReader : public classbase * core is changed). It will contain a pointer to the configuration file data with unneeded data * (such as comments) stripped from it. */ - std::stringstream *cache; - std::stringstream *errorlog; + ConfigDataHash* data; + std::ostringstream* errorlog;; /** Used to store errors */ + bool privatehash; // If we're using our own config data hash or not. bool readerror; long error; diff --git a/src/channels.cpp b/src/channels.cpp index 3f2eca3f5..164525abe 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -64,7 +64,6 @@ extern int WHOWAS_MAX; extern time_t TIME; extern chan_hash chanlist; -using namespace std; chanrec* ForceChan(chanrec* Ptr,ucrec *a,userrec* user, int created); diff --git a/src/cmd_oper.cpp b/src/cmd_oper.cpp index 0c0026121..f4b9a1c21 100644 --- a/src/cmd_oper.cpp +++ b/src/cmd_oper.cpp @@ -90,23 +90,24 @@ void cmd_oper::Handle (char **parameters, int pcnt, userrec *user) snprintf(TheHost,MAXBUF,"%s@%s",user->ident,user->host); - for (int i = 0; i < Config->ConfValueEnum("oper",&Config->config_f); i++) + for (int i = 0; i < Config->ConfValueEnum(Config->config_data, "oper"); i++) { - Config->ConfValue("oper","name",i,LoginName,&Config->config_f); - Config->ConfValue("oper","password",i,Password,&Config->config_f); - Config->ConfValue("oper","type",i,OperType,&Config->config_f); - Config->ConfValue("oper","host",i,HostName,&Config->config_f); + Config->ConfValue(Config->config_data, "oper", "name", i, LoginName, MAXBUF); + Config->ConfValue(Config->config_data, "oper", "password", i, Password, MAXBUF); + Config->ConfValue(Config->config_data, "oper", "type", i, OperType, MAXBUF); + Config->ConfValue(Config->config_data, "oper", "host", i, HostName, MAXBUF); + if ((!strcmp(LoginName,parameters[0])) && (!operstrcmp(Password,parameters[1])) && (OneOfMatches(TheHost,HostName))) { fail2 = true; - for (j =0; j < Config->ConfValueEnum("type",&Config->config_f); j++) + for (j =0; j < Config->ConfValueEnum(Config->config_data, "type"); j++) { - Config->ConfValue("type","name",j,TypeName,&Config->config_f); + Config->ConfValue(Config->config_data, "type","name", j, TypeName, MAXBUF); if (!strcmp(TypeName,OperType)) { /* found this oper's opertype */ - Config->ConfValue("type","host",j,HostName,&Config->config_f); + Config->ConfValue(Config->config_data, "type","host", j, HostName, MAXBUF); if (*HostName) ChangeDisplayedHost(user,HostName); if (!isnick(TypeName)) @@ -158,5 +159,3 @@ void cmd_oper::Handle (char **parameters, int pcnt, userrec *user) } return; } - - diff --git a/src/cmd_stats.cpp b/src/cmd_stats.cpp index bf34edd62..4f2de6dfe 100644 --- a/src/cmd_stats.cpp +++ b/src/cmd_stats.cpp @@ -123,9 +123,9 @@ void cmd_stats::Handle (char **parameters, int pcnt, userrec *user) if (*parameters[0] == 'U') { char ulined[MAXBUF]; - for (int i = 0; i < Config->ConfValueEnum("uline",&Config->config_f); i++) + for (int i = 0; i < Config->ConfValueEnum(Config->config_data, "uline"); i++) { - Config->ConfValue("uline","server",i,ulined,&Config->config_f); + Config->ConfValue(Config->config_data, "uline","server", i, ulined, MAXBUF); WriteServ(user->fd,"248 %s U %s",user->nick,ulined); } } @@ -216,14 +216,14 @@ void cmd_stats::Handle (char **parameters, int pcnt, userrec *user) /* stats o */ if (*parameters[0] == 'o') { - for (int i = 0; i < Config->ConfValueEnum("oper",&Config->config_f); i++) + for (int i = 0; i < Config->ConfValueEnum(Config->config_data, "oper"); i++) { char LoginName[MAXBUF]; char HostName[MAXBUF]; char OperType[MAXBUF]; - Config->ConfValue("oper","name",i,LoginName,&Config->config_f); - Config->ConfValue("oper","host",i,HostName,&Config->config_f); - Config->ConfValue("oper","type",i,OperType,&Config->config_f); + Config->ConfValue(Config->config_data, "oper","name", i, LoginName, MAXBUF); + Config->ConfValue(Config->config_data, "oper","host", i, HostName, MAXBUF); + Config->ConfValue(Config->config_data, "oper","type", i, OperType, MAXBUF); WriteServ(user->fd,"243 %s O %s * %s %s 0",user->nick,HostName,LoginName,OperType); } } @@ -270,6 +270,3 @@ void cmd_stats::Handle (char **parameters, int pcnt, userrec *user) WriteOpers("*** Notice: Stats '%s' requested by %s (%s@%s)",parameters[0],user->nick,user->ident,user->host); } - - - diff --git a/src/commands.cpp b/src/commands.cpp index da4deff65..904b4277e 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -278,8 +278,8 @@ bool host_matches_everyone(const std::string &mask, userrec* user) char insanemasks[MAXBUF]; char buffer[MAXBUF]; char itrigger[MAXBUF]; - Config->ConfValue("insane","hostmasks",0,insanemasks,&Config->config_f); - Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f); + Config->ConfValue(Config->config_data, "insane","hostmasks", 0, insanemasks, MAXBUF); + Config->ConfValue(Config->config_data, "insane","trigger", 0, itrigger, MAXBUF); if (*itrigger == 0) strlcpy(itrigger,"95.5",MAXBUF); if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1')) @@ -306,8 +306,8 @@ bool ip_matches_everyone(const std::string &ip, userrec* user) { char insanemasks[MAXBUF]; char itrigger[MAXBUF]; - Config->ConfValue("insane","ipmasks",0,insanemasks,&Config->config_f); - Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f); + Config->ConfValue(Config->config_data, "insane","ipmasks",0,insanemasks,MAXBUF); + Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF); if (*itrigger == 0) strlcpy(itrigger,"95.5",MAXBUF); if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1')) @@ -331,8 +331,8 @@ bool nick_matches_everyone(const std::string &nick, userrec* user) { char insanemasks[MAXBUF]; char itrigger[MAXBUF]; - Config->ConfValue("insane","nickmasks",0,insanemasks,&Config->config_f); - Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f); + Config->ConfValue(Config->config_data, "insane","nickmasks",0,insanemasks,MAXBUF); + Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF); if (*itrigger == 0) strlcpy(itrigger,"95.5",MAXBUF); if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1')) diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp index 073b5b37c..830e1ef2d 100644 --- a/src/helperfuncs.cpp +++ b/src/helperfuncs.cpp @@ -955,7 +955,7 @@ void WriteCommonExcept_NoFormat(userrec *u, const char* text) * uses the oper list, which means if you have 2000 users but only 5 opers, * it iterates 5 times. */ -void WriteOpers(char* text, ...) +void WriteOpers(const char* text, ...) { char textbuffer[MAXBUF]; va_list argsPtr; @@ -1852,9 +1852,9 @@ void LoadAllModules(InspIRCd* ServerInstance) Config->module_names.clear(); MODCOUNT = -1; - for (int count = 0; count < Config->ConfValueEnum("module",&Config->config_f); count++) + for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "module"); count++) { - Config->ConfValue("module","name",count,configToken,&Config->config_f); + Config->ConfValue(Config->config_data, "module","name",count,configToken,MAXBUF); printf("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",configToken); if (!ServerInstance->LoadModule(configToken)) @@ -1863,13 +1863,6 @@ void LoadAllModules(InspIRCd* ServerInstance) printf("\nThere was an error loading a module: %s\n\n",ServerInstance->ModuleError()); Exit(0); } - - if (!ServerInstance->LoadModule(configToken)) - { - log(DEFAULT,"Exiting due to a module loader error."); - printf("\nThere was an error loading a module: %s\n\n",ServerInstance->ModuleError()); - Exit(0); - } } log(DEFAULT,"Total loaded modules: %lu",(unsigned long)MODCOUNT+1); diff --git a/src/inspircd_io.cpp b/src/inspircd_io.cpp index 9e5f18706..3d8af7e4a 100644 --- a/src/inspircd_io.cpp +++ b/src/inspircd_io.cpp @@ -104,7 +104,8 @@ bool ServerConfig::DelIOHook(int port) bool ServerConfig::CheckOnce(char* tag, bool bail, userrec* user) { - int count = ConfValueEnum(tag,&Config->config_f); + int count = ConfValueEnum(Config->config_data, tag); + if (count > 1) { if (bail) @@ -528,13 +529,11 @@ bool DoneMaxBans(const char* tag) void ServerConfig::Read(bool bail, userrec* user) { char debug[MAXBUF]; /* Temporary buffer for debugging value */ - char dataline[1024]; /* Temporary buffer for error output */ - char* convert; /* Temporary buffer used for reading singular values into */ char* data[12]; /* Temporary buffers for reading multiple occurance tags into */ void* ptr[12]; /* Temporary pointers for passing to callbacks */ int r_i[12]; /* Temporary array for casting */ int rem = 0, add = 0; /* Number of modules added, number of modules removed */ - std::stringstream errstr; /* String stream containing the error output */ + std::ostringstream errstr; /* String stream containing the error output */ /* These tags MUST occur and must ONLY occur once in the config file */ static char* Once[] = { "server", "admin", "files", "power", "options", "pid", NULL }; @@ -563,7 +562,7 @@ void ServerConfig::Read(bool bail, userrec* user) {"dns", "server", &this->DNSServer, DT_CHARPTR, ValidateDnsServer}, {"dns", "timeout", &this->dns_timeout, DT_INTEGER, ValidateDnsTimeout}, {"options", "moduledir", &this->ModPath, DT_CHARPTR, ValidateModPath}, - {"disabled", "commands", &this->DisabledCommands,DT_CHARPTR, NoValidation}, + {"disabled", "commands", &this->DisabledCommands,DT_CHARPTR, NoValidation}, {"options", "operonlystats", &this->OperOnlyStats, DT_CHARPTR, NoValidation}, {"options", "customversion", &this->CustomVersion, DT_CHARPTR, NoValidation}, {"options", "hidesplits", &this->HideSplits, DT_BOOLEAN, NoValidation}, @@ -637,12 +636,59 @@ void ServerConfig::Read(bool bail, userrec* user) include_stack.clear(); - /* Initially, load the config into memory, bail if there are errors - */ - if (!LoadConf(CONFIG_FILE,&Config->config_f,&errstr)) + /* Load and parse the config file, if there are any errors then explode */ + + /* Make a copy here so if it fails then we can carry on running with an unaffected config */ + ConfigDataHash newconfig; + + if (this->LoadConf(newconfig, CONFIG_FILE, errstr)) + { + /* If we succeeded, set the ircd config to the new one */ + Config->config_data = newconfig; + + int c = 1; + std::string last; + + for(ConfigDataHash::const_iterator i = this->config_data.begin(); i != this->config_data.end(); i++) + { + if(i->first != last) + c = 1; + else + c++; + + std::cout << "[" << i->first << " " << c << "/" << this->config_data.count(i->first) << "]" << std::endl; + + for(KeyValList::const_iterator j = i->second.begin(); j != i->second.end(); j++) + { + std::cout << "\t" << j->first << " = " << j->second << std::endl; + } + + std::cout << "[/" << i->first << " " << c << "/" << this->config_data.count(i->first) << "]" << std::endl; + + last = i->first; + } + + for(ConfigDataHash::const_iterator i = this->config_data.begin(); i != this->config_data.end(); i++) + { + std::cout << "There are " << ConfValueEnum(this->config_data, i->first) << " <" << i->first << "> tags" << std::endl; + + for(int j = 0; j < ConfValueEnum(this->config_data, i->first); j++) + { + std::string foo; + if(ConfValue(this->config_data, i->first, "name", j, foo)) + { + std::cout << "<" << i->first << ":name> " << foo << std::endl; + } + else + { + std::cout << "<" << i->first << ":name> undef" << std::endl; + } + } + } + } + else { - errstr.seekg(0); - log(DEFAULT,"There were errors in your configuration:\n%s",errstr.str().c_str()); + log(DEFAULT, "There were errors in your configuration:\n%s", errstr.str().c_str()); if (bail) { @@ -651,22 +697,32 @@ void ServerConfig::Read(bool bail, userrec* user) } else { + std::string errors = errstr.str(); + std::string::size_type start; + unsigned int prefixlen; + + start = 0; + /* ":Config->ServerName NOTICE user->nick :" */ + prefixlen = strlen(Config->ServerName) + strlen(user->nick) + 11; + if (user) { WriteServ(user->fd,"NOTICE %s :There were errors in the configuration file:",user->nick); - while (!errstr.eof()) + + while(start < errors.length()) { - errstr.getline(dataline,1024); - WriteServ(user->fd,"NOTICE %s :%s",user->nick,dataline); + WriteServ(user->fd, "NOTICE %s :%s",user->nick, errors.substr(start, 510 - prefixlen).c_str()); + start += 510 - prefixlen; } } else { WriteOpers("There were errors in the configuration file:"); - while (!errstr.eof()) + + while(start < errors.length()) { - errstr.getline(dataline,1024); - WriteOpers(dataline); + WriteOpers(errors.substr(start, 360).c_str()); + start += 360; } } @@ -690,21 +746,16 @@ void ServerConfig::Read(bool bail, userrec* user) switch (Values[Index].datatype) { case DT_CHARPTR: - ConfValue(Values[Index].tag, Values[Index].value, 0, val_c, &this->config_f); + /* Assuming MAXBUF here, potentially unsafe */ + ConfValue(this->config_data, Values[Index].tag, Values[Index].value, 0, val_c, MAXBUF); break; case DT_INTEGER: - convert = new char[MAXBUF]; - ConfValue(Values[Index].tag, Values[Index].value, 0, convert, &this->config_f); - *val_i = atoi(convert); - delete[] convert; + ConfValueInteger(this->config_data, Values[Index].tag, Values[Index].value, 0, *val_i); break; case DT_BOOLEAN: - convert = new char[MAXBUF]; - ConfValue(Values[Index].tag, Values[Index].value, 0, convert, &this->config_f); - *val_i = ((*convert == tolower('y')) || (*convert == tolower('t')) || (*convert == '1')); - delete[] convert; + *val_i = ConfValueBool(this->config_data, Values[Index].tag, Values[Index].value, 0); break; case DT_NOTHING: @@ -723,17 +774,19 @@ void ServerConfig::Read(bool bail, userrec* user) * and call the callbacks associated with them. We have three * callbacks for these, a 'start', 'item' and 'end' callback. */ + + /* XXX - Make this use ConfValueInteger and so on */ for (int Index = 0; MultiValues[Index].tag; Index++) { MultiValues[Index].init_function(MultiValues[Index].tag); - int number_of_tags = ConfValueEnum((char*)MultiValues[Index].tag, &this->config_f); + int number_of_tags = ConfValueEnum(this->config_data, MultiValues[Index].tag); for (int tagnum = 0; tagnum < number_of_tags; tagnum++) { for (int valuenum = 0; MultiValues[Index].items[valuenum]; valuenum++) { - ConfValue((char*)MultiValues[Index].tag,(char*)MultiValues[Index].items[valuenum], tagnum, data[valuenum], &this->config_f); + ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], tagnum, data[valuenum], MAXBUF); switch (MultiValues[Index].datatype[valuenum]) { @@ -924,6 +977,7 @@ bool DaemonSeed() * to work with other API functions */ +/* XXX - Needed? */ bool FileExists (const char* file) { FILE *input; @@ -938,551 +992,396 @@ bool FileExists (const char* file) } } -/* ConfProcess does the following things to a config line in the following order: - * - * Processes the line for syntax errors as shown below - * (1) Line void of quotes or equals (a malformed, illegal tag format) - * (2) Odd number of quotes on the line indicating a missing quote - * (3) number of equals signs not equal to number of quotes / 2 (missing an equals sign) - * (4) Spaces between the opening bracket (<) and the keyword - * (5) Spaces between a keyword and an equals sign - * (6) Spaces between an equals sign and a quote - * Removes trailing spaces - * Removes leading spaces - * Converts tabs to spaces - * Turns multiple spaces that are outside of quotes into single spaces - */ - -std::string ServerConfig::ConfProcess(char* buffer, long linenumber, std::stringstream* errorstream, bool &error, std::string filename) -{ - long number_of_quotes = 0; - long number_of_equals = 0; - bool has_open_bracket = false; - bool in_quotes = false; - char* trailing; - - error = false; - if (!buffer) - { - return ""; - } - // firstly clean up the line by stripping spaces from the start and end and converting tabs to spaces - for (char* d = buffer; *d; d++) - if (*d == 9) - *d = ' '; - while (*buffer == ' ') buffer++; - trailing = buffer + strlen(buffer) - 1; - while (*trailing == ' ') *trailing-- = '\0'; - - // empty lines are syntactically valid, as are comments - if (!(*buffer) || buffer[0] == '#') - return ""; - - for (char* c = buffer; *c; c++) - { - // convert all spaces that are OUTSIDE quotes into hardspace (0xA0) as this will make them easier to - // search and replace later :) - if ((!in_quotes) && (*c == ' ')) - *c = '\xA0'; - if ((*c == '<') && (!in_quotes)) - { - has_open_bracket = true; - if (!(*(buffer+1))) - { - *errorstream << "Tag without identifier at " << filename << ":" << linenumber << endl; - error = true; - return ""; - } - else if ((tolower(*(c+1)) < 'a') || (tolower(*(c+1)) > 'z')) - { - *errorstream << "Invalid characters in identifier at " << filename << ":" << linenumber << endl; - error = true; - return ""; - } - } - if (*c == '"') - { - number_of_quotes++; - in_quotes = (!in_quotes); - } - if ((*c == '=') && (!in_quotes)) - { - number_of_equals++; - if (*(c+1) == 0) - { - *errorstream << "Variable without a value at " << filename << ":" << linenumber << endl; - error = true; - return ""; - } - else if (*(c+1) != '"') - { - *errorstream << "Variable name not followed immediately by its value at " << filename << ":" << linenumber << endl; - error = true; - return ""; - } - else if (c == buffer) - { - *errorstream << "Value without a variable (line starts with '=') at " << filename << ":" << linenumber << endl; - error = true; - return ""; - } - else if (*(c-1) == '\xA0') - { - *errorstream << "Variable name not followed immediately by its value at " << filename << ":" << linenumber << endl; - error = true; - return ""; - } - } - } - // no quotes, and no equals. something freaky. - if ((!number_of_quotes) || (!number_of_equals) && (strlen(buffer)>2) && (*buffer == '<')) - { - *errorstream << "Malformed tag at " << filename << ":" << linenumber << endl; - error = true; - return ""; - } - // odd number of quotes. thats just wrong. - if ((number_of_quotes % 2) != 0) - { - *errorstream << "Missing \" at " << filename << ":" << linenumber << endl; - error = true; - return ""; - } - if (number_of_equals < (number_of_quotes/2)) - { - *errorstream << "Missing '=' at " << filename << ":" << linenumber << endl; - } - if (number_of_equals > (number_of_quotes/2)) - { - *errorstream << "Too many '=' at " << filename << ":" << linenumber << endl; - } - - std::string parsedata = buffer; - // turn multispace into single space - while (parsedata.find("\xA0\xA0") != std::string::npos) - { - parsedata.erase(parsedata.find("\xA0\xA0"),1); - } - - // turn our hardspace back into softspace - for (unsigned int d = 0; d < parsedata.length(); d++) - { - if (parsedata[d] == '\xA0') - parsedata[d] = ' '; - } - - // and we're done, the line is fine! - return parsedata; -} - -int ServerConfig::fgets_safe(char* buffer, size_t maxsize, FILE* &file) -{ - char c_read = 0; - size_t n = 0; - char* bufptr = buffer; - while ((!feof(file)) && (c_read != '\n') && (c_read != '\r') && (n < maxsize)) - { - c_read = fgetc(file); - if ((c_read != '\n') && (c_read != '\r')) - { - *bufptr++ = c_read; - n++; - } - } - *bufptr = 0; - return bufptr - buffer; -} - -bool ServerConfig::LoadConf(const char* filename, std::stringstream *target, std::stringstream* errorstream) +bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream) { - target->str(""); - errorstream->str(""); - long linenumber = 1; - // first, check that the file exists before we try to do anything with it - if (!FileExists(filename)) + std::ifstream conf(filename); + std::string line; + char ch; + long linenumber; + bool in_tag; + bool in_quote; + bool in_comment; + + linenumber = 1; + in_tag = false; + in_quote = false; + in_comment = false; + + /* Check if the file open failed first */ + if (!conf) { - *errorstream << "File " << filename << " not found." << endl; + errorstream << "LoadConf: Couldn't open config file: " << filename << std::endl; return false; } - // Fix the chmod of the file to restrict it to the current user and group + + /* Fix the chmod of the file to restrict it to the current user and group */ chmod(filename,0600); + for (unsigned int t = 0; t < include_stack.size(); t++) { if (std::string(filename) == include_stack[t]) { - *errorstream << "File " << filename << " is included recursively (looped inclusion)." << endl; + errorstream << "File " << filename << " is included recursively (looped inclusion)." << std::endl; return false; } } + + /* It's not already included, add it to the list of files we've loaded */ include_stack.push_back(filename); - // now open it - FILE* conf = fopen(filename,"r"); - char buffer[MAXBUF]; - if (conf) + + /* Start reading characters... */ + while(conf.get(ch)) { - while (!feof(conf)) + /* + * Here we try and get individual tags on separate lines, + * this would be so easy if we just made people format + * their config files like that, but they don't so... + * We check for a '<' and then know the line is over when + * we get a '>' not inside quotes. If we find two '<' and + * no '>' then die with an error. + */ + + if((ch == '#') && !in_quote) + in_comment = true; + + switch(ch) + { + case '\n': + linenumber++; + case '\r': + in_comment = false; + case '\0': + continue; + case '\t': + ch = ' '; + } + + if(in_comment) + continue; + + line += ch; + + if(ch == '<') { - if (fgets_safe(buffer, MAXBUF, conf)) + if(in_tag) { - if ((!feof(conf)) && (buffer) && (*buffer)) + if(!in_quote) { - if ((buffer[0] != '#') && (buffer[0] != '\r') && (buffer[0] != '\n')) - { - if (!strncmp(buffer,"<include file=\"",15)) - { - char* buf = buffer; - char confpath[10240],newconf[10240]; - // include file directive - buf += 15; // advance to filename - for (char* j = buf; *j; j++) - { - if (*j == '\\') - *j = '/'; - if (*j == '"') - { - *j = 0; - break; - } - } - log(DEBUG,"Opening included file '%s'",buf); - if (*buf != '/') - { - strlcpy(confpath,CONFIG_FILE,10240); - if (strstr(confpath,"/inspircd.conf")) - { - // leaves us with just the path - *(strstr(confpath,"/inspircd.conf")) = '\0'; - } - snprintf(newconf,10240,"%s/%s",confpath,buf); - } - else strlcpy(newconf,buf,10240); - std::stringstream merge(stringstream::in | stringstream::out); - // recursively call LoadConf and get the new data, use the same errorstream - if (LoadConf(newconf, &merge, errorstream)) - { - // append to the end of the file - std::string newstuff = merge.str(); - *target << newstuff; - } - else - { - // the error propogates up to its parent recursively - // causing the config reader to bail at the top level. - fclose(conf); - return false; - } - } - else - { - bool error = false; - std::string data = this->ConfProcess(buffer,linenumber++,errorstream,error,filename); - if (error) - { - return false; - } - *target << data; - } - } - else linenumber++; + errorstream << "Got another opening < when the first one wasn't closed on line " << linenumber << std::endl; + return false; } } - } - fclose(conf); - } - target->seekg(0); - return true; -} - -/* Counts the number of tags of a certain type within the config file, e.g. to enumerate opers */ - -int ServerConfig::EnumConf(std::stringstream *config, const char* tag) -{ - int ptr = 0; - char buffer[MAXBUF], c_tag[MAXBUF], c, lastc; - int in_token, in_quotes, tptr, idx = 0; - - std::string x = config->str(); - const char* buf = x.c_str(); - char* bptr = (char*)buf; - - ptr = 0; - in_token = 0; - in_quotes = 0; - lastc = '\0'; - while (*bptr) - { - lastc = c; - c = *bptr++; - if ((c == '#') && (lastc == '\n')) - { - while ((c != '\n') && (*bptr)) + else { - lastc = c; - c = *bptr++; + if(in_quote) + { + errorstream << "We're in a quote but outside a tag, interesting. Line: " << linenumber << std::endl; + return false; + } + else + { + // errorstream << "Opening new config tag on line " << linenumber << std::endl; + in_tag = true; + } } } - if ((c == '<') && (!in_quotes)) + else if(ch == '"') { - tptr = 0; - in_token = 1; - do { - c = *bptr++; - if (c != ' ') + if(in_tag) + { + if(in_quote) { - c_tag[tptr++] = c; - c_tag[tptr] = '\0'; + // errorstream << "Closing quote in config tag on line " << linenumber << std::endl; + in_quote = false; } - } while (c != ' '); - } - if (c == '"') - { - in_quotes = (!in_quotes); - } - if ((c == '>') && (!in_quotes)) - { - in_token = 0; - if (!strcmp(c_tag,tag)) + else + { + // errorstream << "Opening quote in config tag on line " << linenumber << std::endl; + in_quote = true; + } + } + else { - /* correct tag, but wrong index */ - idx++; + if(in_quote) + { + errorstream << "Found a (closing) \" outside a tag on line " << linenumber << std::endl; + } + else + { + errorstream << "Found a (opening) \" outside a tag on line " << linenumber << std::endl; + } } - c_tag[0] = '\0'; - buffer[0] = '\0'; - ptr = 0; - tptr = 0; } - if (c != '>') + else if(ch == '>') { - if ((in_token) && (c != '\n') && (c != '\r')) + if(!in_quote) { - buffer[ptr++] = c; - buffer[ptr] = '\0'; + if(in_tag) + { + // errorstream << "Closing config tag on line " << linenumber << std::endl; + in_tag = false; + + /* + * If this finds an <include> then ParseLine can simply call + * LoadConf() and load the included config into the same ConfigDataHash + */ + + if(!this->ParseLine(target, line, linenumber, errorstream)) + return false; + + line.clear(); + } + else + { + errorstream << "Got a closing > when we weren't inside a tag on line " << linenumber << std::endl; + return false; + } } } } - return idx; + + return true; } -/* Counts the number of values within a certain tag */ +bool ServerConfig::LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream) +{ + return this->LoadConf(target, filename.c_str(), errorstream); +} -int ServerConfig::EnumValues(std::stringstream *config, const char* tag, int index) +bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long linenumber, std::ostringstream &errorstream) { - int ptr = 0; - char buffer[MAXBUF], c_tag[MAXBUF], c, lastc; - int in_token, in_quotes, tptr, idx = 0; - bool correct_tag = false; - int num_items = 0; - const char* buf = config->str().c_str(); - char* bptr = (char*)buf; - - ptr = 0; - in_token = 0; - in_quotes = 0; - lastc = 0; - - while (*bptr) + std::string tagname; + std::string current_key; + std::string current_value; + KeyValList results; + bool got_name; + bool got_key; + bool in_quote; + + got_name = got_key = in_quote = false; + + std::cout << "ParseLine(data, '" << line << "', " << linenumber << ", stream)" << std::endl; + + for(std::string::iterator c = line.begin(); c != line.end(); c++) { - lastc = c; - c = *bptr++; - if ((c == '#') && (lastc == '\n')) + if(!got_name) { - while ((c != '\n') && (*bptr)) + /* We don't know the tag name yet. */ + + if(*c != ' ') + { + if(*c != '<') + { + tagname += *c; + } + } + else { - lastc = c; - c = *bptr++; + /* We got to a space, we should have the tagname now. */ + if(tagname.length()) + { + got_name = true; + } } } - if ((c == '<') && (!in_quotes)) + else { - tptr = 0; - in_token = 1; - do { - c = *bptr++; - if (c != ' ') + /* We have the tag name */ + if(!got_key) + { + /* We're still reading the key name */ + if(*c != '=') { - c_tag[tptr++] = c; - c_tag[tptr] = '\0'; - - if ((!strcmp(c_tag,tag)) && (idx == index)) + if(*c != ' ') { - correct_tag = true; + current_key += *c; } } - } while (c != ' '); - } - if (c == '"') - { - in_quotes = (!in_quotes); - } - - if ( (correct_tag) && (!in_quotes) && ( (c == ' ') || (c == '\n') || (c == '\r') ) ) - { - num_items++; - } - if ((c == '>') && (!in_quotes)) - { - in_token = 0; - if (correct_tag) - correct_tag = false; - if (!strcmp(c_tag,tag)) - { - /* correct tag, but wrong index */ - idx++; + else + { + /* We got an '=', end of the key name. */ + got_key = true; + } } - c_tag[0] = '\0'; - buffer[0] = '\0'; - ptr = 0; - tptr = 0; - } - if (c != '>') - { - if ((in_token) && (c != '\n') && (c != '\r')) + else { - buffer[ptr++] = c; - buffer[ptr] = '\0'; + /* We have the key name, now we're looking for quotes and the value */ + if(*c == '"') + { + if(!in_quote) + { + /* We're not already in a quote. */ + in_quote = true; + } + else + { + /* Leaving quotes, we have the value */ + results.push_back(KeyVal(current_key, current_value)); + std::cout << "<" << tagname << ":" << current_key << "> " << current_value << std::endl; + in_quote = false; + got_key = false; + + if((tagname == "include") && (current_key == "file")) + { + this->DoInclude(target, current_value, errorstream); + } + + current_key.clear(); + current_value.clear(); + } + } + else + { + if(in_quote) + { + current_value += *c; + } + } } } } - return num_items+1; -} - - -int ServerConfig::ConfValueEnum(char* tag, std::stringstream* config) -{ - return EnumConf(config,tag); + + /* Finished parsing the tag, add it to the config hash */ + target.insert(std::pair<std::string, KeyValList > (tagname, results)); + std::cout << "Finished parsing " << tagname << std::endl; + std::cout << "Count of <server> tag: " << target.count("server") << std::endl; + + return true; } - -int ServerConfig::ReadConf(std::stringstream *config, const char* tag, const char* var, int index, char *result) +bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream) { - int ptr = 0; - char buffer[65535], c_tag[MAXBUF], c, lastc, varname[MAXBUF]; - int in_token, in_quotes, tptr, idx = 0; - char* key; - char* bptr = (char*)config->str().c_str(); + std::string confpath; + std::string newfile; + std::string::size_type pos; - ptr = 0; - in_token = 0; - in_quotes = 0; - lastc = 0; - c_tag[0] = 0; - buffer[0] = 0; + confpath = CONFIG_FILE; + newfile = file; - /* - * Fun bug here, if was searching for whatever var was *in the whole tag*, - * so if you had the name of the var you were searching for in one of the values - * it would try to use that part of a value as the varnme, usually giving a value - * something like "anothervarname=" - */ - strlcpy(varname, var, MAXBUF); - strlcat(varname, "=", MAXBUF); - - while (*bptr) + for (std::string::iterator c = newfile.begin(); c != newfile.end(); c++) { - lastc = c; - c = *bptr++; - // FIX: Treat tabs as spaces - if (c == 9) - c = 32; - if ((c == '<') && (!in_quotes)) + if (*c == '\\') { - tptr = 0; - in_token = 1; - do { - c = *bptr++; - if (c != ' ') - { - c_tag[tptr++] = c; - c_tag[tptr] = '\0'; - } - // FIX: Tab can follow a tagname as well as space. - } while ((c != ' ') && (c != 9)); + *c = '/'; } - if (c == '"') + } + + if (file[0] != '/') + { + if((pos = confpath.find("/inspircd.conf")) != std::string::npos) { - in_quotes = (!in_quotes); + /* Leaves us with just the path */ + newfile = confpath.substr(0, pos) + std::string("/") + newfile; } - if ((c == '>') && (!in_quotes)) + else { - in_token = 0; - if (idx == index) - { - if (!strcmp(c_tag,tag)) - { - if ((buffer) && (c_tag) && (var)) - { - key = strstr(buffer,varname); - if (!key) - { - /* value not found in tag */ - *result = 0; - return 0; - } - else - { - key+=strlen(var); - while (*key !='"') - { - if (!*key) - { - /* missing quote */ - *result = 0; - return 0; - } - key++; - } - key++; - for (char* j = key; *j; j++) - { - if (*j == '"') - { - *j = 0; - break; - } - } - strlcpy(result,key,MAXBUF); - return 1; - } - } - } - } - if (!strcmp(c_tag,tag)) - { - /* correct tag, but wrong index */ - idx++; - } - c_tag[0] = '\0'; - buffer[0] = '\0'; - ptr = 0; - tptr = 0; + errorstream << "Couldn't get config path from: " << confpath << std::endl; + return false; } - if (c != '>') + } + + return LoadConf(target, newfile, errorstream); +} + +bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length) +{ + std::string value; + bool r = ConfValue(target, std::string(tag), std::string(var), index, value); + strlcpy(result, value.c_str(), length); + return r; +} + +bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result) +{ + ConfigDataHash::size_type pos = index; + if((pos >= 0) && (pos < target.count(tag))) + { + ConfigDataHash::const_iterator iter = target.find(tag); + + for(int i = 0; i < index; i++) + iter++; + + for(KeyValList::const_iterator j = iter->second.begin(); j != iter->second.end(); j++) { - if ((in_token) && (c != '\n') && (c != '\r')) + if(j->first == var) { - buffer[ptr++] = c; - buffer[ptr] = '\0'; + result = j->second; + return true; } } } + else + { + log(DEBUG, "ConfValue got an out-of-range index %d", index); + } - *result = 0; // value or its tag not found at all - return 0; + return false; +} + +bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, int index, int &result) +{ + return ConfValueInteger(target, std::string(tag), std::string(var), index, result); } +bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, int &result) +{ + std::string value; + std::istringstream stream; + bool r = ConfValue(target, tag, var, index, value); + stream.str(value); + if(!(stream >> result)) + return false; + return r; +} + +bool ServerConfig::ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, int index) +{ + return ConfValueBool(target, std::string(tag), std::string(var), index); +} +bool ServerConfig::ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, int index) +{ + std::string result; + if(!ConfValue(target, tag, var, index, result)) + return false; + + return ((result == "yes") || (result == "true") || (result == "1")); +} + +int ServerConfig::ConfValueEnum(ConfigDataHash &target, const char* tag) +{ + return ConfValueEnum(target, std::string(tag)); +} -int ServerConfig::ConfValue(char* tag, char* var, int index, char *result,std::stringstream *config) +int ServerConfig::ConfValueEnum(ConfigDataHash &target, const std::string &tag) { - ReadConf(config, tag, var, index, result); - return 0; + return target.count(tag); +} + +int ServerConfig::ConfVarEnum(ConfigDataHash &target, const char* tag, int index) +{ + return 1; } -int ServerConfig::ConfValueInteger(char* tag, char* var, int index, std::stringstream *config) +int ServerConfig::ConfVarEnum(ConfigDataHash &target, const std::string &tag, int index) { - char result[MAXBUF]; - ReadConf(config, tag, var, index, result); - return atoi(result); + ConfigDataHash::size_type pos = index; + + if((pos >= 0) && (pos < target.count(tag))) + { + ConfigDataHash::const_iterator iter = target.find(tag); + + for(int i = 0; i < index; i++) + iter++; + + return iter->second.size(); + } + else + { + log(DEBUG, "ConfVarEnum got an out-of-range index %d", index); + } + + return 0; } /** This will bind a socket to a port. It works for UDP/TCP. @@ -1599,11 +1498,12 @@ int BindPorts(bool bail) int InitialPortCount = ServerInstance->stats->BoundPortCount; log(DEBUG,"Initial port count: %d",InitialPortCount); - for (int count = 0; count < Config->ConfValueEnum("bind",&Config->config_f); count++) + for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "bind"); count++) { - Config->ConfValue("bind","port",count,configToken,&Config->config_f); - Config->ConfValue("bind","address",count,Addr,&Config->config_f); - Config->ConfValue("bind","type",count,Type,&Config->config_f); + Config->ConfValue(Config->config_data, "bind", "port", count, configToken, MAXBUF); + Config->ConfValue(Config->config_data, "bind", "address", count, Addr, MAXBUF); + Config->ConfValue(Config->config_data, "bind", "type", count, Type, MAXBUF); + if (((!*Type) || (!strcmp(Type,"clients"))) && (!HasPort(atoi(configToken),Addr))) { // modules handle server bind types now @@ -1646,11 +1546,11 @@ int BindPorts(bool bail) return InitialPortCount; } - for (int count = 0; count < Config->ConfValueEnum("bind",&Config->config_f); count++) + for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "bind"); count++) { - Config->ConfValue("bind","port",count,configToken,&Config->config_f); - Config->ConfValue("bind","address",count,Addr,&Config->config_f); - Config->ConfValue("bind","type",count,Type,&Config->config_f); + Config->ConfValue(Config->config_data, "bind", "port", count, configToken, MAXBUF); + Config->ConfValue(Config->config_data, "bind", "address", count, Addr, MAXBUF); + Config->ConfValue(Config->config_data, "bind", "type", count, Type, MAXBUF); if ((!*Type) || (!strcmp(Type,"clients"))) { diff --git a/src/modules.cpp b/src/modules.cpp index 529946220..680bd950a 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -849,30 +849,43 @@ Module* Server::FindModule(const std::string &name) ConfigReader::ConfigReader() { - Config->ClearStack(); - this->cache = new std::stringstream(std::stringstream::in | std::stringstream::out); - this->errorlog = new std::stringstream(std::stringstream::in | std::stringstream::out); - this->readerror = Config->LoadConf(CONFIG_FILE,this->cache,this->errorlog); - if (!this->readerror) - this->error = CONF_FILE_NOT_FOUND; + // Config->ClearStack(); + + /* Is there any reason to load the entire config file again here? + * it's needed if they specify another config file, but using the + * default one we can just use the global config data - pre-parsed! + */ + //~ this->cache = new std::stringstream(std::stringstream::in | std::stringstream::out); + this->errorlog = new std::ostringstream(std::stringstream::in | std::stringstream::out); + + //~ this->readerror = Config->LoadConf(CONFIG_FILE, this->cache,this->errorlog); + //~ if (!this->readerror) + //~ this->error = CONF_FILE_NOT_FOUND; + + this->data = &Config->config_data; + this->privatehash = false; } ConfigReader::~ConfigReader() { - if (this->cache) - delete this->cache; + //~ if (this->cache) + //~ delete this->cache; if (this->errorlog) delete this->errorlog; + if(this->privatehash) + delete this->data; } ConfigReader::ConfigReader(const std::string &filename) { Config->ClearStack(); - this->cache = new std::stringstream(std::stringstream::in | std::stringstream::out); - this->errorlog = new std::stringstream(std::stringstream::in | std::stringstream::out); - this->readerror = Config->LoadConf(filename.c_str(),this->cache,this->errorlog); + + this->data = new ConfigDataHash; + this->privatehash = true; + this->errorlog = new std::ostringstream(std::stringstream::in | std::stringstream::out); + this->readerror = Config->LoadConf(*this->data, filename, *this->errorlog); if (!this->readerror) this->error = CONF_FILE_NOT_FOUND; }; @@ -880,58 +893,39 @@ ConfigReader::ConfigReader(const std::string &filename) std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, int index) { /* Don't need to strlcpy() tag and name anymore, ReadConf() takes const char* */ - char val[MAXBUF]; - int res = Config->ReadConf(cache, tag.c_str(), name.c_str(), index, val); - if (!res) + std::string result; + + if (!Config->ConfValue(*this->data, tag, name, index, result)) { this->error = CONF_VALUE_NOT_FOUND; return ""; } - return val; + + return result; } bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, int index) { - /* Don't need to strlcpy() tag and name anymore, ReadConf() takes const char* */ - char val[MAXBUF]; - std::string s; - - int res = Config->ReadConf(cache, tag.c_str(), name.c_str(), index, val); - if (!res) - { - this->error = CONF_VALUE_NOT_FOUND; - return false; - } - - s = val; - - return ((s == "yes") || (s == "YES") || (s == "true") || (s == "TRUE") || (s == "1")); + return Config->ConfValueBool(*this->data, tag, name, index); } long ConfigReader::ReadInteger(const std::string &tag, const std::string &name, int index, bool needs_unsigned) { - char val[MAXBUF]; - - int res = Config->ReadConf(cache, tag.c_str(), name.c_str(), index, val); - if (!res) + int result; + + if(!Config->ConfValueInteger(*this->data, tag, name, index, result)) { this->error = CONF_VALUE_NOT_FOUND; return 0; } - for (char* i = val; *i; i++) - { - if (!isdigit(*i)) - { - this->error = CONF_NOT_A_NUMBER; - return 0; - } - } - if ((needs_unsigned) && (atoi(val)<0)) + + if ((needs_unsigned) && (result < 0)) { this->error = CONF_NOT_UNSIGNED; return 0; } - return atoi(val); + + return result; } long ConfigReader::GetError() @@ -943,36 +937,44 @@ long ConfigReader::GetError() void ConfigReader::DumpErrors(bool bail, userrec* user) { + /* XXX - Duplicated code */ + if (bail) { - printf("There were errors in your configuration:\n%s",errorlog->str().c_str()); - exit(0); + printf("There were errors in your configuration:\n%s", this->errorlog->str().c_str()); + Exit(0); } else { - char dataline[1024]; + std::string errors = this->errorlog->str(); + std::string::size_type start; + unsigned int prefixlen; + start = 0; + /* ":Config->ServerName NOTICE user->nick :" */ + prefixlen = strlen(Config->ServerName) + strlen(user->nick) + 11; + if (user) { WriteServ(user->fd,"NOTICE %s :There were errors in the configuration file:",user->nick); - - while (!errorlog->eof()) + + while(start < errors.length()) { - errorlog->getline(dataline,1024); - WriteServ(user->fd,"NOTICE %s :%s",user->nick,dataline); + WriteServ(user->fd, "NOTICE %s :%s",user->nick, errors.substr(start, 510 - prefixlen).c_str()); + start += 510 - prefixlen; } } else { - WriteOpers("There were errors in the configuration file:",user->nick); + WriteOpers("There were errors in the configuration file:"); - while (!errorlog->eof()) + while(start < errors.length()) { - errorlog->getline(dataline,1024); - WriteOpers(dataline); + WriteOpers(errors.substr(start, 360).c_str()); + start += 360; } } - + return; } } @@ -980,12 +982,12 @@ void ConfigReader::DumpErrors(bool bail, userrec* user) int ConfigReader::Enumerate(const std::string &tag) { - return Config->EnumConf(cache,tag.c_str()); + return Config->ConfValueEnum(*this->data, tag); } int ConfigReader::EnumerateValues(const std::string &tag, int index) { - return Config->EnumValues(cache, tag.c_str(), index); + return Config->ConfVarEnum(*this->data, tag, index); } bool ConfigReader::Verify() |