From be180588e158f3b1297ffaf3a715577fb3d73f85 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sun, 6 Nov 2011 08:55:58 +0100 Subject: [PATCH] added new self-made config parser with new config style --- .gitignore | 1 + INSTALL | 6 +- Makefile.am | 6 +- neonserv.example.conf | 11 ++ neonserv.example.ini | 7 - src/ConfigParser.c | 316 ++++++++++++++++++++++++++++++++++++++++++ src/ConfigParser.h | 27 ++++ src/main.c | 40 +++--- 8 files changed, 378 insertions(+), 36 deletions(-) create mode 100644 neonserv.example.conf delete mode 100644 neonserv.example.ini create mode 100644 src/ConfigParser.c create mode 100644 src/ConfigParser.h diff --git a/.gitignore b/.gitignore index ed4e2b5..2dee847 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ mysqlConfig.h neonserv.ini +neonserv.conf src/version.c src/version.php src/.deps diff --git a/INSTALL b/INSTALL index 6ac9d23..dc48fed 100644 --- a/INSTALL +++ b/INSTALL @@ -17,8 +17,8 @@ Quick Install: $ ./autogen.sh $ ./configure $ make -$ ${EDITOR} neonserv.ini - NOTE: You may want to copy neonserv.example.ini to neonserv.ini and +$ ${EDITOR} neonserv.conf + NOTE: You may want to copy neonserv.example.conf to neonserv.conf and edit that. $ ./neonserv @@ -50,7 +50,7 @@ Compiling: 6) You may now either type "make install" to install it to your installation path, or work from your build directory, either is fine. - 7) Copy neonserv.example.ini to neonserv.ini and edit the mysql information. + 7) Copy neonserv.example.conf to neonserv.conf and edit the mysql information. 10) Once you have NeonServ for the first time, it will create the neccesary tables in your database. Take a look into `bots` to edit Bot settings like diff --git a/Makefile.am b/Makefile.am index 0c8c81d..89c9ff0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -115,7 +115,7 @@ neonserv_SOURCES = src/version.c \ src/cmd_neonserv_noregister.c \ src/cmd_global_staff.c \ src/cmd_funcmds.c \ - src/lib/ini.c + src/ConfigParser.c neonserv_LDADD = $(MYSQL_LIBS) $(WINSOCK_LIBS) @@ -125,10 +125,10 @@ install-exec-local: $(INSTALL) -m 644 $(srcdir)/database.sql $(prefix) $(INSTALL) -m 644 $(srcdir)/database.upgrade.sql $(prefix) $(INSTALL) -m 644 $(srcdir)/database.defaults.sql $(prefix) - $(INSTALL) -m 600 $(srcdir)/neonserv.example.ini $(prefix) + $(INSTALL) -m 600 $(srcdir)/neonserv.example.conf $(prefix) $(INSTALL) -m 744 $(srcdir)/language.php $(prefix) @echo @echo NeonServ-$(VERSION) has been installed to $(prefix) - @echo Edit the neonserv.example.ini and save it as neonserv.ini before you start! + @echo Edit the neonserv.example.conf and save it as neonserv.conf before you start! @echo You should use an own database for this Bot - table names are NOT prefixed! @echo diff --git a/neonserv.example.conf b/neonserv.example.conf new file mode 100644 index 0000000..99775ae --- /dev/null +++ b/neonserv.example.conf @@ -0,0 +1,11 @@ +/* + NeonServ example configuration +*/ + +"MySQL" { + "host" = "127.0.0.1 "; + "port" = 3306; + "user" = "neonserv"; + "pass" = "password"; + "base" = "neonserv"; +}; \ No newline at end of file diff --git a/neonserv.example.ini b/neonserv.example.ini deleted file mode 100644 index 997d5ce..0000000 --- a/neonserv.example.ini +++ /dev/null @@ -1,7 +0,0 @@ -[MySQL] -host = 127.0.0.1 -port = 3306 - -user = neonserv -pass = password -base = neonserv diff --git a/src/ConfigParser.c b/src/ConfigParser.c new file mode 100644 index 0000000..775e062 --- /dev/null +++ b/src/ConfigParser.c @@ -0,0 +1,316 @@ +/* ConfigParser.c - NeonServ v5.2 + * Copyright (C) 2011 Philipp Kreil (pk910) + * + * 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 . + */ + +#include "ConfigParser.h" + +#define ENTRYTYPE_BLOCK 1 +#define ENTRYTYPE_STRING 2 +#define ENTRYTYPE_INTEGER 3 + +struct ConfigEntry { + char *name; + int type; + void *value; + struct ConfigEntry *next; +}; + +static struct ConfigEntry *root_entry = NULL; + +static char *parse_config_recursive(struct ConfigEntry *centry, char *buffer, int root_element); +static void free_entry_rekursiv(struct ConfigEntry *centry, int is_root_entry); + +int loadConfig(const char *filename) { + FILE *f; + f = fopen(filename, "rb"); + if(!f) return 0; + + // obtain file size: + long lSize; + fseek (f, 0, SEEK_END); + lSize = ftell(f); + rewind(f); + + // allocate memory to contain the whole file: + char *buffer = (char*) malloc (sizeof(char)*lSize + 1); + if (buffer == NULL) return 0; + + // copy the file into the buffer: + size_t result = fread (buffer, 1, lSize, f); + if (result != lSize) return 0; + buffer[lSize] = '\0'; + + // now parse the config file... + if(root_entry) { + free_loaded_config(); + } + root_entry = malloc(sizeof(*root_entry)); + if (!root_entry) return 0; + parse_config_recursive(root_entry, buffer, 1); + + // free the buffer... + free(buffer); + return 1; +} + +#define PARSER_FLAG_ESCAPED 0x01 +#define PARSER_FLAG_BLOCK 0x02 +#define PARSER_FLAG_STRING 0x04 +#define PARSER_FLAG_EXPECT_END 0x08 +#define PARSER_FLAG_NEXTCHAR 0x10 +#define PARSER_FLAG_INTEGER 0x20 +#define PARSER_FLAG_EOBN 0x40 /* End of Block name */ +#define PARSER_FLAG_COMMAND 0x80 +static char *parse_config_recursive(struct ConfigEntry *centry, char *buffer, int root_element) { + int flags = 0; + int type = (root_element ? ENTRYTYPE_BLOCK : 0); + char cbuf[1024]; + int cbufpos = 0; + struct ConfigEntry *sub_entrys = NULL; + while(*buffer) { + if(flags & PARSER_FLAG_NEXTCHAR) { + buffer++; + if(*buffer == '\0') + break; + } + flags |= PARSER_FLAG_NEXTCHAR; + if(flags & PARSER_FLAG_EOBN) { + flags &= ~(PARSER_FLAG_EOBN | PARSER_FLAG_NEXTCHAR); + struct ConfigEntry *new_entry = malloc(sizeof(*new_entry)); + if (!new_entry) return buffer; + new_entry->name = strdup(cbuf); + buffer = parse_config_recursive(new_entry, buffer, 0); + if(sub_entrys) + new_entry->next = sub_entrys; + else + new_entry->next = NULL; + sub_entrys = new_entry; + centry->value = sub_entrys; + } + if(flags & PARSER_FLAG_ESCAPED) { + cbuf[cbufpos++] = *buffer; + flags &= ~PARSER_FLAG_ESCAPED; + continue; + } + if(flags & PARSER_FLAG_EXPECT_END) { + if(*buffer == ';') { + centry->type = type; + return (buffer+1); + } + continue; + } + if(flags & PARSER_FLAG_STRING) { + if(*buffer == '"') { + cbuf[cbufpos] = '\0'; + flags &= ~PARSER_FLAG_STRING; + if(type == ENTRYTYPE_STRING) { + flags |= PARSER_FLAG_EXPECT_END; + centry->value = strdup(cbuf); + } else if(type == ENTRYTYPE_BLOCK) { + flags |= PARSER_FLAG_EOBN; + } + } else if(*buffer == '\\') + flags |= PARSER_FLAG_ESCAPED; + else + cbuf[cbufpos++] = *buffer; + continue; + } + if(flags & PARSER_FLAG_INTEGER) { + if(!isdigit(*buffer)) { + cbuf[cbufpos] = '\0'; + flags &= ~PARSER_FLAG_INTEGER; + if(type == ENTRYTYPE_INTEGER) { + flags |= PARSER_FLAG_EXPECT_END; + int *intbuf = malloc(sizeof(int)); + *intbuf = atoi(cbuf); + centry->value = intbuf; + } + if(*buffer == ';') { + centry->type = type; + return (buffer+1); + } + } else + cbuf[cbufpos++] = *buffer; + continue; + } + if(flags & PARSER_FLAG_COMMAND) { + int found_command = 0; + switch(*buffer) { + case '/': + buffer = strstr(buffer, "\n"); + found_command = 1; + break; + case '*': + //simple search for the next */ + buffer = strstr(buffer, "*/")+1; + found_command = 1; + } + flags &= ~PARSER_FLAG_COMMAND; + if(found_command) + continue; + } + switch(*buffer) { + case '\\': + flags |= PARSER_FLAG_ESCAPED; + break; + case '/': + if(!(flags & PARSER_FLAG_STRING)) { + flags |= PARSER_FLAG_COMMAND; + } + break; + case '{': + flags |= PARSER_FLAG_BLOCK; + type = ENTRYTYPE_BLOCK; + break; + case '}': + if(flags & PARSER_FLAG_BLOCK) + flags &= ~PARSER_FLAG_BLOCK; + flags |= PARSER_FLAG_EXPECT_END; + break; + case '"': + flags |= PARSER_FLAG_STRING; + if(!type) + type = ENTRYTYPE_STRING; + cbufpos = 0; + break; + case ';': + centry->type = type; + return (buffer+1); + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if(!type) + type = ENTRYTYPE_INTEGER; + flags |= PARSER_FLAG_INTEGER; + cbufpos = 0; + cbuf[cbufpos++] = *buffer; + break; + default: + break; + } + } + centry->type = type; + return buffer; //end of the buffer +} + +int get_int_field(char *field_path) { + struct ConfigEntry *centry = root_entry; + char *a, *b = field_path; + struct ConfigEntry *subentry; + while((a = strstr(b, ".")) && centry) { + if(centry->type == ENTRYTYPE_BLOCK) { + int found = 0; + for(subentry = centry->value; subentry; subentry = subentry->next) { + if(!stricmplen(subentry->name, b, a-b)) { + centry = subentry; + found = 1; + break; + } + } + if(!found) + return 0; + } else + return 0; + b = a+1; + } + if(centry->type == ENTRYTYPE_BLOCK) { + int found = 0; + for(subentry = centry->value; subentry; subentry = subentry->next) { + if(!stricmp(subentry->name, b)) { + centry = subentry; + found = 1; + break; + } + } + if(!found) + return 0; + } else + return 0; + if(centry->type == ENTRYTYPE_INTEGER) + return ((int *)centry->value)[0]; + else + return 0; +} + +char *get_string_field(char *field_path) { + struct ConfigEntry *centry = root_entry; + char *a, *b = field_path; + struct ConfigEntry *subentry; + while((a = strstr(b, ".")) && centry) { + if(centry->type == ENTRYTYPE_BLOCK) { + int found = 0; + for(subentry = centry->value; subentry; subentry = subentry->next) { + if(!stricmplen(subentry->name, b, a-b)) { + centry = subentry; + found = 1; + break; + } + } + if(!found) + return NULL; + } else + return NULL; + b = a+1; + } + if(centry->type == ENTRYTYPE_BLOCK) { + int found = 0; + for(subentry = centry->value; subentry; subentry = subentry->next) { + if(!stricmp(subentry->name, b)) { + centry = subentry; + found = 1; + break; + } + } + if(!found) + return NULL; + } else + return NULL; + if(centry->type == ENTRYTYPE_STRING) + return centry->value; + else + return NULL; +} + +void free_loaded_config() { + if(root_entry) { + free_entry_rekursiv(root_entry, 1); + root_entry = NULL; + } +} + +static void free_entry_rekursiv(struct ConfigEntry *centry, int is_root_entry) { + if(centry->type == ENTRYTYPE_BLOCK) { + struct ConfigEntry *subentry, *nextentry; + for(subentry = centry->value; subentry; subentry = nextentry) { + nextentry = subentry->next; + free_entry_rekursiv(subentry, 0); + } + } else if(centry->type == ENTRYTYPE_STRING) { + free(centry->value); + } else if(centry->type == ENTRYTYPE_INTEGER) { + free(centry->value); + } + if(!is_root_entry) + free(centry->name); + free(centry); +} diff --git a/src/ConfigParser.h b/src/ConfigParser.h new file mode 100644 index 0000000..1657765 --- /dev/null +++ b/src/ConfigParser.h @@ -0,0 +1,27 @@ +/* ConfigParser.h - NeonServ v5.2 + * Copyright (C) 2011 Philipp Kreil (pk910) + * + * 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 . + */ + +#ifndef _ConfigParser_h +#define _ConfigParser_h +#include "main.h" + +int loadConfig(const char *filename); +int get_int_field(char *field_path); +char *get_string_field(char *field_path); +void free_loaded_config(); + +#endif \ No newline at end of file diff --git a/src/main.c b/src/main.c index d6258a7..183ebae 100644 --- a/src/main.c +++ b/src/main.c @@ -34,7 +34,7 @@ #include "IRCQueue.h" #include "DBHelper.h" #include "commands.h" -#include "lib/ini.h" +#include "ConfigParser.h" time_t start_time; @@ -53,40 +53,34 @@ void cleanup() { } static int load_mysql_config() { - char mysql_host[MAXLEN], mysql_port_str[MAXLEN], mysql_user[MAXLEN], mysql_pass[MAXLEN], mysql_base[MAXLEN]; + char *mysql_host, *mysql_user, *mysql_pass, *mysql_base; int mysql_serverport; - if(loadINI("neonserv.ini") == FILE_SUCCESS) { - mysql_host[0] = '\0'; - ReadString("MySQL", "host", mysql_host); - if(!*mysql_host) { - perror("invalid neonserv.ini: missing MySQL host"); + if(loadConfig("neonserv.conf")) { + mysql_host = get_string_field("MySQL.host"); + if(!mysql_host) { + perror("invalid neonserv.conf: missing MySQL.host"); return 0; } - mysql_port_str[0] = '\0'; - ReadString("MySQL", "port", mysql_port_str); - mysql_serverport = atoi(mysql_port_str); + mysql_serverport = get_int_field("MySQL.port"); if(!mysql_serverport) mysql_serverport = 3306; - mysql_user[0] = '\0'; - ReadString("MySQL", "user", mysql_user); - if(!*mysql_user) { - perror("invalid neonserv.ini: missing MySQL user"); + mysql_user = get_string_field("MySQL.user"); + if(!mysql_user) { + perror("invalid neonserv.conf: missing MySQL.user"); return 0; } - mysql_pass[0] = '\0'; - ReadString("MySQL", "pass", mysql_pass); - if(!*mysql_pass) { - perror("invalid neonserv.ini: missing MySQL pass"); + mysql_pass = get_string_field("MySQL.pass"); + if(!mysql_pass) { + perror("invalid neonserv.conf: missing MySQL.pass"); return 0; } - mysql_base[0] = '\0'; - ReadString("MySQL", "base", mysql_base); - if(!*mysql_base) { - perror("invalid neonserv.ini: missing MySQL base"); + mysql_base = get_string_field("MySQL.base"); + if(!mysql_base) { + perror("invalid neonserv.conf: missing MySQL base"); return 0; } } else { - perror("Unable to load neonserv.ini"); + perror("Unable to load neonserv.conf"); return 0; } init_mysql(mysql_host, mysql_serverport, mysql_user, mysql_pass, mysql_base); -- 2.20.1