diff --git a/Makefile b/Makefile index 7ccc55135..a814a2628 100644 --- a/Makefile +++ b/Makefile @@ -20,10 +20,12 @@ # 17/06/13 Mark Riddoch Addition of documentation and depend # targets # 18/06/13 Mark Riddoch Addition of install target +# 21/06/13 Mark Riddoch Addition of inih DEST=/usr/local/skysql all: + (cd inih/extra ; make -f Makefile.static) (cd core; make) (cd modules/routing; make) (cd modules/protocol; make) diff --git a/core/Makefile b/core/Makefile index 0b9b7ace6..7be7e61a0 100644 --- a/core/Makefile +++ b/core/Makefile @@ -21,16 +21,16 @@ # 17/06/13 Mark Riddoch Addition of dependency generation CC=cc -CFLAGS=-c -I/usr/include -I../include -Wall -g +CFLAGS=-c -I/usr/include -I../include -I../inih -Wall -g LDFLAGS=-rdynamic SRCS= atomic.c buffer.c spinlock.c gateway.c gateway_mysql_protocol.c gw_utils.c \ - utils.c dcb.c load_utils.c session.c service.c server.c poll.c + utils.c dcb.c load_utils.c session.c service.c server.c poll.c config.c HDRS= ../include/atomic.h ../include/buffer.h ../include/dcb.h \ ../include/gateway_mysql.h ../include/gw.h ../include/mysql_protocol.h \ ../include/session.h ../include/spinlock.h ../include/thread.h \ - ../include/modules.h ../include/poll.h + ../include/modules.h ../include/poll.h ../include/config.h OBJ=$(SRCS:.c=.o) -LIBS=-lssl +LIBS=-L../inih/extra -linih -lssl -lstdc++ gateway: $(OBJ) $(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@ diff --git a/core/config.c b/core/config.c new file mode 100644 index 000000000..06cf54e6b --- /dev/null +++ b/core/config.c @@ -0,0 +1,211 @@ +/* + * This file is distributed as part of the SkySQL Gateway. It 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, + * version 2. + * + * 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, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright SkySQL Ab 2013 + */ + +/** + * @file config.c - Read the gateway.cnf configuration file + * + * @verbatim + * Revision History + * + * Date Who Description + * 21/06/13 Mark Riddoch Initial implementation + * + * @endverbatim + */ +#include +#include +#include +#include +#include +#include +#include + + +static int process_config_context(CONFIG_CONTEXT *); +static char *config_get_value(CONFIG_PARAMETER *, const char *); + + +/** + * Config item handler + * + * @param userdata The config context element + * @param secton The config file section + * @param name The Parameter name + * @param value The Parameter value + */ +static int +handler(void *userdata, const char *section, const char *name, const char *value) +{ +CONFIG_CONTEXT *cntxt = (CONFIG_CONTEXT *)userdata; +CONFIG_CONTEXT *ptr = cntxt; +CONFIG_PARAMETER *param; + + /* + * If we already have some parameters for the object + * add the parameters to that object. If not create + * a new object. + */ + while (ptr && strcmp(ptr->object, section) != 0) + ptr = ptr->next; + if (!ptr) + { + if ((ptr = (CONFIG_CONTEXT *)malloc(sizeof(CONFIG_CONTEXT))) == NULL) + return 0; + ptr->object = strdup(section); + ptr->parameters = NULL; + ptr->next = cntxt->next; + cntxt->next = ptr; + } + if ((param = (CONFIG_PARAMETER *)malloc(sizeof(CONFIG_PARAMETER))) == NULL) + return 0; + param->name = strdup(name); + param->value = strdup(value); + param->next = ptr->parameters; + ptr->parameters = param; + + return 1; +} + +/** + * + * @param file The filename of the configuration file + */ +int +load_config(char *file) +{ +CONFIG_CONTEXT config; + + config.object = ""; + config.next = NULL; + + if (ini_parse(file, handler, &config) < 0) + return 0; + + return process_config_context(config.next); +} + +/** + * Process a configuration context and turn it into the set of object + * we need. + * + * @param context The configuration data + */ +static int +process_config_context(CONFIG_CONTEXT *context) +{ +CONFIG_CONTEXT *obj; + + /** + * Process the data and create the services and servers defined + * in the data. + */ + obj = context; + while (obj) + { + char *type = config_get_value(obj->parameters, "type"); + if (type == NULL) + fprintf(stderr, "Object %s has no type\n", obj->object); + else if (!strcmp(type, "service")) + { + char *router = config_get_value(obj->parameters, "router"); + if (router) + obj->element = service_alloc(obj->object, router); + else + fprintf(stderr, "No router define for service '%s'\n", + obj->object); + } + else if (!strcmp(type, "server")) + { + char *address = config_get_value(obj->parameters, "address"); + char *port = config_get_value(obj->parameters, "port"); + char *protocol = config_get_value(obj->parameters, "protocol"); + if (address && port && protocol) + obj->element = server_alloc(address, protocol, atoi(port)); + } + + obj = obj->next; + } + + /* + * Now we have the services we can add the servers to the services + * add the protocols to the services + */ + obj = context; + while (obj) + { + char *type = config_get_value(obj->parameters, "type"); + if (type == NULL) + ; + else if (!strcmp(type, "service")) + { + char *servers = config_get_value(obj->parameters, "servers"); + if (servers) + { + char *s = strtok(servers, ","); + while (s) + { + CONFIG_CONTEXT *obj1 = context; + while (obj1) + { + if (strcmp(s, obj1->object) == 0) + serviceAddBackend(obj->element, obj1->element); + obj1 = obj1->next; + } + s = strtok(NULL, ","); + } + } + } + else if (!strcmp(type, "listener")) + { + char *service = config_get_value(obj->parameters, "service"); + char *port = config_get_value(obj->parameters, "port"); + char *protocol = config_get_value(obj->parameters, "protocol"); + if (service && port && protocol) + { + CONFIG_CONTEXT *ptr = context; + while (ptr && strcmp(ptr->object, service) != 0) + ptr = ptr->next; + if (ptr) + serviceAddProtocol(ptr->element, protocol, atoi(port)); + } + } + + obj = obj->next; + } + + return 1; +} + +/** + * Get the value of a config parameter + * + * @param params The linked list of config parameters + * @param name The parameter to return + * @return the parameter value or NULL if not found + */ +static char * +config_get_value(CONFIG_PARAMETER *params, const char *name) +{ + while (params) + { + if (!strcmp(params->name, name)) + return params->value; + params = params->next; + } + return NULL; +} diff --git a/core/depend.mk b/core/depend.mk index 59a50e0b1..a7cd9ba42 100644 --- a/core/depend.mk +++ b/core/depend.mk @@ -69,7 +69,7 @@ gateway.o: gateway.c ../include/gw.h /usr/include/stdio.h \ /usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \ ../include/mysql_protocol.h ../include/dcb.h ../include/service.h \ ../include/server.h ../include/session.h ../include/modules.h \ - ../include/poll.h + ../include/config.h ../include/poll.h gateway_mysql_protocol.o: gateway_mysql_protocol.c ../include/gw.h \ /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ @@ -364,14 +364,35 @@ poll.o: poll.c /usr/include/stdio.h /usr/include/features.h \ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ /usr/include/string.h /usr/include/xlocale.h /usr/include/unistd.h \ /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \ - /usr/include/bits/confname.h /usr/include/getopt.h \ - /usr/include/sys/epoll.h /usr/include/stdint.h /usr/include/bits/wchar.h \ - /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h \ - /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/types.h \ + /usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \ /usr/include/bits/sigset.h /usr/include/bits/time.h \ /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - ../include/poll.h ../include/dcb.h ../include/spinlock.h \ - ../include/thread.h /usr/include/pthread.h /usr/include/sched.h \ - /usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \ - ../include/atomic.h + /usr/include/alloca.h /usr/include/sys/epoll.h /usr/include/stdint.h \ + /usr/include/bits/wchar.h ../include/poll.h ../include/dcb.h \ + ../include/spinlock.h ../include/thread.h /usr/include/pthread.h \ + /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/setjmp.h ../include/buffer.h ../include/atomic.h +config.o: config.c /usr/include/stdio.h /usr/include/features.h \ + /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ + /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ + /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ + /usr/include/string.h /usr/include/xlocale.h /usr/include/stdlib.h \ + /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \ + /usr/include/endian.h /usr/include/bits/endian.h \ + /usr/include/bits/byteswap.h /usr/include/sys/types.h \ + /usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \ + /usr/include/bits/sigset.h /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ + /usr/include/alloca.h ../inih/ini.h ../include/config.h \ + ../include/service.h ../include/spinlock.h ../include/thread.h \ + /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \ + /usr/include/bits/setjmp.h ../include/dcb.h ../include/buffer.h \ + ../include/server.h diff --git a/core/gateway.c b/core/gateway.c index 097be29ac..ee6d38317 100644 --- a/core/gateway.c +++ b/core/gateway.c @@ -29,6 +29,7 @@ * listening port * and bind addr is 0.0.0.0 * 19/06/13 Mark Riddoch Extract the epoll functionality + * 21/06/13 Mark Riddoch Added initial config support * * @endverbatim */ @@ -39,6 +40,7 @@ #include #include #include +#include #include /* basic signal handling */ @@ -168,48 +170,29 @@ main(int argc, char **argv) int daemon_mode = 1; sigset_t sigset; int n; -unsigned short port = 4406; -SERVICE *service1, *service2; -SERVER *server1, *server2, *server3; +char *cnf_file = "/etc/gateway.cnf"; + for (n = 0; n < argc; n++) { - if (strncmp(argv[n], "-p", 2) == 0) - { - port = atoi(&argv[n][2]); - } if (strcmp(argv[n], "-d") == 0) { // Debug mode daemon_mode = 0; } + if (strncmp(argv[n], "-c", 2) == 0) + { + cnf_file = &argv[n][2]; + } } - /* - * Build the services etc. This would normally be done by the - * configuration, however in lieu of that being available we - * will build a static configuration here - */ - - if ((service1 = service_alloc("Test Service", "readconnroute")) == NULL) + if (!load_config(cnf_file)) + { + fprintf(stderr, "Failed to load gateway configuration file %s\n", cnf_file); exit(1); - serviceAddProtocol(service1, "MySQLClient", port); + } - server1 = server_alloc("127.0.0.1", "MySQLBackend", 3306); - server2 = server_alloc("127.0.0.1", "MySQLBackend", 3307); - server3 = server_alloc("127.0.0.1", "MySQLBackend", 3308); - serviceAddBackend(service1, server1); - serviceAddBackend(service1, server2); - serviceAddBackend(service1, server3); - - - if ((service2 = service_alloc("Debug Service", "debugcli")) == NULL) - exit(1); - serviceAddProtocol(service2, "telnetd", 4442); - - fprintf(stderr, "(C) SkySQL Ab 2013\n"); - - load_module("testroute", "Router"); + fprintf(stderr, "SkySQL Gateway (C) SkySQL Ab 2013\n"); if (daemon_mode == 1) { @@ -238,15 +221,12 @@ SERVER *server1, *server2, *server3; fprintf(stderr, "GATEWAY is starting, PID %i\n\n", getpid()); - fprintf(stderr, ">> GATEWAY log is /dev/stderr\n"); - poll_init(); /* * Start the service that was created above */ - serviceStart(service1); - serviceStart(service2); + printf("Started %d services\n", serviceStartAll()); while (1) { diff --git a/core/poll.c b/core/poll.c index 42cc726bd..de10dfcef 100644 --- a/core/poll.c +++ b/core/poll.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/core/service.c b/core/service.c index 015edcf3b..eaa1cdb2c 100644 --- a/core/service.c +++ b/core/service.c @@ -126,6 +126,26 @@ GWPROTOCOL *funcs; return listeners; } +/** + * Start all the services + * + * @return Return the number of services started + */ +int +serviceStartAll() +{ +SERVICE *ptr; +int n = 0; + + ptr = allServices; + while (ptr) + { + n += serviceStart(ptr); + ptr = ptr->next; + } + return n; +} + /** * Deallocate the specified service * diff --git a/gateway.cnf b/gateway.cnf new file mode 100644 index 000000000..bbc355e72 --- /dev/null +++ b/gateway.cnf @@ -0,0 +1,41 @@ +# +# Example gateway.cnf configuration file +# +[Test Service] +type=service +router=readconnroute +servers=server1,server2,server3 + +[server1] +type=server +address=localhost +port=3306 +protocol=MySQLBackend + +[server2] +type=server +address=localhost +port=3307 +protocol=MySQLBackend + +[server3] +type=server +address=localhost +port=3308 +protocol=MySQLBackend + +[Debug Service] +type=service +router=debugcli + +[Debug Listener] +type=listener +service=Debug Service +protocol=telnetd +port=4042 + +[Test Listener] +type=listener +service=Test Service +protocol=MySQLClient +port=4006 diff --git a/include/config.h b/include/config.h new file mode 100644 index 000000000..1a6276dd6 --- /dev/null +++ b/include/config.h @@ -0,0 +1,53 @@ +#ifndef _CONFIG_H +#define _CONFIG_H +/* + * This file is distributed as part of the SkySQL Gateway. It 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, + * version 2. + * + * 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, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright SkySQL Ab 2013 + */ + +/** + * @file config.h The configuration handling elements + * + * @verbatim + * Revision History + * + * Date Who Description + * 21/06/13 Mark Riddoch Initial implementation + * + * @endverbatim + */ + +/** + * The config parameter + */ +typedef struct config_parameter { + char *name; /**< The name of the parameter */ + char *value; /**< The value of the parameter */ + struct config_parameter *next; /**< Next pointer in the linked list */ +} CONFIG_PARAMETER; +/** + * The config context structure, used to build the configuration + * data during the parse process + */ +typedef struct config_context { + char *object; /**< The name of the object being configured */ + CONFIG_PARAMETER *parameters; /**< The list of parameter values */ + void *element; /**< The element created from the data */ + struct config_context *next; /**< Next pointer in the linked list */ +} CONFIG_CONTEXT; + +extern int load_config(char *); +#endif diff --git a/include/service.h b/include/service.h index 378ac5de0..2e94291e0 100644 --- a/include/service.h +++ b/include/service.h @@ -96,6 +96,7 @@ extern int service_free(SERVICE *); extern int serviceAddProtocol(SERVICE *, char *, unsigned short); extern void serviceAddBackend(SERVICE *, SERVER *); extern int serviceStart(SERVICE *); +extern int serviceStartAll(); extern void printService(SERVICE *); extern void printAllServices(); extern void dprintAllServices(DCB *); diff --git a/inih/._LICENSE.txt b/inih/._LICENSE.txt new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/._LICENSE.txt differ diff --git a/inih/._README.txt b/inih/._README.txt new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/._README.txt differ diff --git a/inih/._cpp b/inih/._cpp new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/._cpp differ diff --git a/inih/._examples b/inih/._examples new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/._examples differ diff --git a/inih/._extra b/inih/._extra new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/._extra differ diff --git a/inih/._ini.c b/inih/._ini.c new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/._ini.c differ diff --git a/inih/._ini.h b/inih/._ini.h new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/._ini.h differ diff --git a/inih/._tests b/inih/._tests new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/._tests differ diff --git a/inih/LICENSE.txt b/inih/LICENSE.txt new file mode 100755 index 000000000..44a3093a3 --- /dev/null +++ b/inih/LICENSE.txt @@ -0,0 +1,27 @@ + +The "inih" library is distributed under the New BSD license: + +Copyright (c) 2009, Brush Technology +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Brush Technology nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/inih/README.txt b/inih/README.txt new file mode 100755 index 000000000..4bff76126 --- /dev/null +++ b/inih/README.txt @@ -0,0 +1,5 @@ + +inih is a simple .INI file parser written in C, released under the New BSD +license (see LICENSE.txt). Go to the project home page for more info: + +http://code.google.com/p/inih/ diff --git a/inih/cpp/._INIReader.cpp b/inih/cpp/._INIReader.cpp new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/cpp/._INIReader.cpp differ diff --git a/inih/cpp/._INIReader.h b/inih/cpp/._INIReader.h new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/cpp/._INIReader.h differ diff --git a/inih/cpp/._INIReaderTest.cpp b/inih/cpp/._INIReaderTest.cpp new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/cpp/._INIReaderTest.cpp differ diff --git a/inih/cpp/INIReader.cpp b/inih/cpp/INIReader.cpp new file mode 100755 index 000000000..43f695149 --- /dev/null +++ b/inih/cpp/INIReader.cpp @@ -0,0 +1,67 @@ +// Read an INI file into easy-to-access name/value pairs. + +#include +#include +#include +#include "../ini.h" +#include "INIReader.h" + +using std::string; + +INIReader::INIReader(string filename) +{ + _error = ini_parse(filename.c_str(), ValueHandler, this); +} + +int INIReader::ParseError() +{ + return _error; +} + +string INIReader::Get(string section, string name, string default_value) +{ + string key = MakeKey(section, name); + return _values.count(key) ? _values[key] : default_value; +} + +long INIReader::GetInteger(string section, string name, long default_value) +{ + string valstr = Get(section, name, ""); + const char* value = valstr.c_str(); + char* end; + // This parses "1234" (decimal) and also "0x4D2" (hex) + long n = strtol(value, &end, 0); + return end > value ? n : default_value; +} + +bool INIReader::GetBoolean(string section, string name, bool default_value) +{ + string valstr = Get(section, name, ""); + // Convert to lower case to make string comparisons case-insensitive + std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower); + if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1") + return true; + else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0") + return false; + else + return default_value; +} + +string INIReader::MakeKey(string section, string name) +{ + string key = section + "." + name; + // Convert to lower case to make section/name lookups case-insensitive + std::transform(key.begin(), key.end(), key.begin(), ::tolower); + return key; +} + +int INIReader::ValueHandler(void* user, const char* section, const char* name, + const char* value) +{ + INIReader* reader = (INIReader*)user; + string key = MakeKey(section, name); + if (reader->_values[key].size() > 0) + reader->_values[key] += "\n"; + reader->_values[key] += value; + return 1; +} diff --git a/inih/cpp/INIReader.h b/inih/cpp/INIReader.h new file mode 100755 index 000000000..7571a29d2 --- /dev/null +++ b/inih/cpp/INIReader.h @@ -0,0 +1,48 @@ +// Read an INI file into easy-to-access name/value pairs. + +// inih and INIReader are released under the New BSD license (see LICENSE.txt). +// Go to the project home page for more info: +// +// http://code.google.com/p/inih/ + +#ifndef __INIREADER_H__ +#define __INIREADER_H__ + +#include +#include + +// Read an INI file into easy-to-access name/value pairs. (Note that I've gone +// for simplicity here rather than speed, but it should be pretty decent.) +class INIReader +{ +public: + // Construct INIReader and parse given filename. See ini.h for more info + // about the parsing. + INIReader(std::string filename); + + // Return the result of ini_parse(), i.e., 0 on success, line number of + // first error on parse error, or -1 on file open error. + int ParseError(); + + // Get a string value from INI file, returning default_value if not found. + std::string Get(std::string section, std::string name, + std::string default_value); + + // Get an integer (long) value from INI file, returning default_value if + // not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2"). + long GetInteger(std::string section, std::string name, long default_value); + + // Get a boolean value from INI file, returning default_value if not found or if + // not a valid true/false value. Valid true values are "true", "yes", "on", "1", + // and valid false values are "false", "no", "off", "0" (not case sensitive). + bool GetBoolean(std::string section, std::string name, bool default_value); + +private: + int _error; + std::map _values; + static std::string MakeKey(std::string section, std::string name); + static int ValueHandler(void* user, const char* section, const char* name, + const char* value); +}; + +#endif // __INIREADER_H__ diff --git a/inih/cpp/INIReaderTest.cpp b/inih/cpp/INIReaderTest.cpp new file mode 100755 index 000000000..cb13b62c1 --- /dev/null +++ b/inih/cpp/INIReaderTest.cpp @@ -0,0 +1,20 @@ +// Example that shows simple usage of the INIReader class + +#include +#include "INIReader.h" + +int main() +{ + INIReader reader("../examples/test.ini"); + + if (reader.ParseError() < 0) { + std::cout << "Can't load 'test.ini'\n"; + return 1; + } + std::cout << "Config loaded from 'test.ini': version=" + << reader.GetInteger("protocol", "version", -1) << ", name=" + << reader.Get("user", "name", "UNKNOWN") << ", email=" + << reader.Get("user", "email", "UNKNOWN") << ", active=" + << reader.GetBoolean("user", "active", true) << "\n"; + return 0; +} diff --git a/inih/examples/._config.def b/inih/examples/._config.def new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/examples/._config.def differ diff --git a/inih/examples/._ini_dump.c b/inih/examples/._ini_dump.c new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/examples/._ini_dump.c differ diff --git a/inih/examples/._ini_example.c b/inih/examples/._ini_example.c new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/examples/._ini_example.c differ diff --git a/inih/examples/._ini_xmacros.c b/inih/examples/._ini_xmacros.c new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/examples/._ini_xmacros.c differ diff --git a/inih/examples/._test.ini b/inih/examples/._test.ini new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/examples/._test.ini differ diff --git a/inih/examples/config.def b/inih/examples/config.def new file mode 100755 index 000000000..f5c7ed5fe --- /dev/null +++ b/inih/examples/config.def @@ -0,0 +1,8 @@ +// CFG(section, name, default) + +CFG(protocol, version, "0") + +CFG(user, name, "Fatty Lumpkin") +CFG(user, email, "fatty@lumpkin.com") + +#undef CFG diff --git a/inih/examples/ini_dump.c b/inih/examples/ini_dump.c new file mode 100755 index 000000000..5c8c6d115 --- /dev/null +++ b/inih/examples/ini_dump.c @@ -0,0 +1,40 @@ +/* ini.h example that simply dumps an INI file without comments */ + +#include +#include +#include "../ini.h" + +static int dumper(void* user, const char* section, const char* name, + const char* value) +{ + static char prev_section[50] = ""; + + if (strcmp(section, prev_section)) { + printf("%s[%s]\n", (prev_section[0] ? "\n" : ""), section); + strncpy(prev_section, section, sizeof(prev_section)); + prev_section[sizeof(prev_section) - 1] = '\0'; + } + printf("%s = %s\n", name, value); + return 1; +} + +int main(int argc, char* argv[]) +{ + int error; + + if (argc <= 1) { + printf("Usage: ini_dump filename.ini\n"); + return 1; + } + + error = ini_parse(argv[1], dumper, NULL); + if (error < 0) { + printf("Can't read '%s'!\n", argv[1]); + return 2; + } + else if (error) { + printf("Bad config file (first error on line %d)!\n", error); + return 3; + } + return 0; +} diff --git a/inih/examples/ini_example.c b/inih/examples/ini_example.c new file mode 100755 index 000000000..962cef57a --- /dev/null +++ b/inih/examples/ini_example.c @@ -0,0 +1,44 @@ +/* Example: parse a simple configuration file */ + +#include +#include +#include +#include "../ini.h" + +typedef struct +{ + int version; + const char* name; + const char* email; +} configuration; + +static int handler(void* user, const char* section, const char* name, + const char* value) +{ + configuration* pconfig = (configuration*)user; + + #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 + if (MATCH("protocol", "version")) { + pconfig->version = atoi(value); + } else if (MATCH("user", "name")) { + pconfig->name = strdup(value); + } else if (MATCH("user", "email")) { + pconfig->email = strdup(value); + } else { + return 0; /* unknown section/name, error */ + } + return 1; +} + +int main(int argc, char* argv[]) +{ + configuration config; + + if (ini_parse("test.ini", handler, &config) < 0) { + printf("Can't load 'test.ini'\n"); + return 1; + } + printf("Config loaded from 'test.ini': version=%d, name=%s, email=%s\n", + config.version, config.name, config.email); + return 0; +} diff --git a/inih/examples/ini_xmacros.c b/inih/examples/ini_xmacros.c new file mode 100755 index 000000000..7d867acd6 --- /dev/null +++ b/inih/examples/ini_xmacros.c @@ -0,0 +1,46 @@ +/* Parse a configuration file into a struct using X-Macros */ + +#include +#include +#include "../ini.h" + +/* define the config struct type */ +typedef struct { + #define CFG(s, n, default) char *s##_##n; + #include "config.def" +} config; + +/* create one and fill in its default values */ +config Config = { + #define CFG(s, n, default) default, + #include "config.def" +}; + +/* process a line of the INI file, storing valid values into config struct */ +int handler(void *user, const char *section, const char *name, + const char *value) +{ + config *cfg = (config *)user; + + if (0) ; + #define CFG(s, n, default) else if (strcmp(section, #s)==0 && \ + strcmp(name, #n)==0) cfg->s##_##n = strdup(value); + #include "config.def" + + return 1; +} + +/* print all the variables in the config, one per line */ +void dump_config(config *cfg) +{ + #define CFG(s, n, default) printf("%s_%s = %s\n", #s, #n, cfg->s##_##n); + #include "config.def" +} + +int main(int argc, char* argv[]) +{ + if (ini_parse("test.ini", handler, &Config) < 0) + printf("Can't load 'test.ini', using defaults\n"); + dump_config(&Config); + return 0; +} diff --git a/inih/examples/test.ini b/inih/examples/test.ini new file mode 100755 index 000000000..e06e7f9ba --- /dev/null +++ b/inih/examples/test.ini @@ -0,0 +1,9 @@ +; Test config file for ini_example.c and INIReaderTest.cpp + +[protocol] ; Protocol configuration +version=6 ; IPv6 + +[user] +name = Bob Smith ; Spaces around '=' are stripped +email = bob@smith.com ; And comments (like this) ignored +active = true ; Test a boolean diff --git a/inih/extra/._Makefile.static b/inih/extra/._Makefile.static new file mode 100755 index 000000000..17b8574a4 Binary files /dev/null and b/inih/extra/._Makefile.static differ diff --git a/inih/extra/Makefile.static b/inih/extra/Makefile.static new file mode 100755 index 000000000..0d6519e38 --- /dev/null +++ b/inih/extra/Makefile.static @@ -0,0 +1,19 @@ +# Simple makefile to build inih as a static library using g++ + +SRC = ../ini.c +OBJ = $(SRC:.c=.o) +OUT = libinih.a +INCLUDES = -I.. +CCFLAGS = -g -O2 +CC = g++ + +default: $(OUT) + +.c.o: + $(CC) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) -c $< -o $@ + +$(OUT): $(OBJ) + ar rcs $(OUT) $(OBJ) $(EXTRAARFLAGS) + +clean: + rm -f $(OBJ) $(OUT) diff --git a/inih/ini.c b/inih/ini.c new file mode 100755 index 000000000..9f9110eaf --- /dev/null +++ b/inih/ini.c @@ -0,0 +1,176 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +http://code.google.com/p/inih/ + +*/ + +#include +#include +#include + +#include "ini.h" + +#if !INI_USE_STACK +#include +#endif + +#define MAX_SECTION 50 +#define MAX_NAME 50 + +/* Strip whitespace chars off end of given string, in place. Return s. */ +static char* rstrip(char* s) +{ + char* p = s + strlen(s); + while (p > s && isspace((unsigned char)(*--p))) + *p = '\0'; + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +static char* lskip(const char* s) +{ + while (*s && isspace((unsigned char)(*s))) + s++; + return (char*)s; +} + +/* Return pointer to first char c or ';' comment in given string, or pointer to + null at end of string if neither found. ';' must be prefixed by a whitespace + character to register as a comment. */ +static char* find_char_or_comment(const char* s, char c) +{ + int was_whitespace = 0; + while (*s && *s != c && !(was_whitespace && *s == ';')) { + was_whitespace = isspace((unsigned char)(*s)); + s++; + } + return (char*)s; +} + +/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ +static char* strncpy0(char* dest, const char* src, size_t size) +{ + strncpy(dest, src, size); + dest[size - 1] = '\0'; + return dest; +} + +/* See documentation in header file. */ +int ini_parse_file(FILE* file, + int (*handler)(void*, const char*, const char*, + const char*), + void* user) +{ + /* Uses a fair bit of stack (use heap instead if you need to) */ +#if INI_USE_STACK + char line[INI_MAX_LINE]; +#else + char* line; +#endif + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + char* start; + char* end; + char* name; + char* value; + int lineno = 0; + int error = 0; + +#if !INI_USE_STACK + line = (char*)malloc(INI_MAX_LINE); + if (!line) { + return -2; + } +#endif + + /* Scan through file line by line */ + while (fgets(line, INI_MAX_LINE, file) != NULL) { + lineno++; + + start = line; +#if INI_ALLOW_BOM + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && + (unsigned char)start[2] == 0xBF) { + start += 3; + } +#endif + start = lskip(rstrip(start)); + + if (*start == ';' || *start == '#') { + /* Per Python ConfigParser, allow '#' comments at start of line */ + } +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) { + /* Non-black line with leading whitespace, treat as continuation + of previous name's value (as per Python ConfigParser). */ + if (!handler(user, section, prev_name, start) && !error) + error = lineno; + } +#endif + else if (*start == '[') { + /* A "[section]" line */ + end = find_char_or_comment(start + 1, ']'); + if (*end == ']') { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + } + else if (!error) { + /* No ']' found on section line */ + error = lineno; + } + } + else if (*start && *start != ';') { + /* Not a comment, must be a name[=:]value pair */ + end = find_char_or_comment(start, '='); + if (*end != '=') { + end = find_char_or_comment(start, ':'); + } + if (*end == '=' || *end == ':') { + *end = '\0'; + name = rstrip(start); + value = lskip(end + 1); + end = find_char_or_comment(value, '\0'); + if (*end == ';') + *end = '\0'; + rstrip(value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0(prev_name, name, sizeof(prev_name)); + if (!handler(user, section, name, value) && !error) + error = lineno; + } + else if (!error) { + /* No '=' or ':' found on name[=:]value line */ + error = lineno; + } + } + } + +#if !INI_USE_STACK + free(line); +#endif + + return error; +} + +/* See documentation in header file. */ +int ini_parse(const char* filename, + int (*handler)(void*, const char*, const char*, const char*), + void* user) +{ + FILE* file; + int error; + + file = fopen(filename, "r"); + if (!file) + return -1; + error = ini_parse_file(file, handler, user); + fclose(file); + return error; +} diff --git a/inih/ini.h b/inih/ini.h new file mode 100755 index 000000000..b3a494a24 --- /dev/null +++ b/inih/ini.h @@ -0,0 +1,72 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +http://code.google.com/p/inih/ + +*/ + +#ifndef __INI_H__ +#define __INI_H__ + +/* Make this header file easier to include in C++ code */ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Parse given INI-style file. May have [section]s, name=value pairs + (whitespace stripped), and comments starting with ';' (semicolon). Section + is "" if name=value pair parsed before any section heading. name:value + pairs are also supported as a concession to Python's ConfigParser. + + For each name=value pair parsed, call handler function with given user + pointer as well as section, name, and value (data only valid for duration + of handler call). Handler should return nonzero on success, zero on error. + + Returns 0 on success, line number of first error on parse error (doesn't + stop on first error), -1 on file open error, or -2 on memory allocation + error (only when INI_USE_STACK is zero). +*/ +int ini_parse(const char* filename, + int (*handler)(void* user, const char* section, + const char* name, const char* value), + void* user); + +/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't + close the file when it's finished -- the caller must do that. */ +int ini_parse_file(FILE* file, + int (*handler)(void* user, const char* section, + const char* name, const char* value), + void* user); + +/* Nonzero to allow multi-line value parsing, in the style of Python's + ConfigParser. If allowed, ini_parse() will call the handler with the same + name for each subsequent line parsed. */ +#ifndef INI_ALLOW_MULTILINE +#define INI_ALLOW_MULTILINE 1 +#endif + +/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of + the file. See http://code.google.com/p/inih/issues/detail?id=21 */ +#ifndef INI_ALLOW_BOM +#define INI_ALLOW_BOM 1 +#endif + +/* Nonzero to use stack, zero to use heap (malloc/free). */ +#ifndef INI_USE_STACK +#define INI_USE_STACK 1 +#endif + +/* Maximum line length for any line in INI file. */ +#ifndef INI_MAX_LINE +#define INI_MAX_LINE 200 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __INI_H__ */ diff --git a/inih/tests/._bad_comment.ini b/inih/tests/._bad_comment.ini new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._bad_comment.ini differ diff --git a/inih/tests/._bad_multi.ini b/inih/tests/._bad_multi.ini new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._bad_multi.ini differ diff --git a/inih/tests/._bad_section.ini b/inih/tests/._bad_section.ini new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._bad_section.ini differ diff --git a/inih/tests/._baseline_multi.txt b/inih/tests/._baseline_multi.txt new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._baseline_multi.txt differ diff --git a/inih/tests/._baseline_single.txt b/inih/tests/._baseline_single.txt new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._baseline_single.txt differ diff --git a/inih/tests/._bom.ini b/inih/tests/._bom.ini new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._bom.ini differ diff --git a/inih/tests/._multi_line.ini b/inih/tests/._multi_line.ini new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._multi_line.ini differ diff --git a/inih/tests/._normal.ini b/inih/tests/._normal.ini new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._normal.ini differ diff --git a/inih/tests/._unittest.bat b/inih/tests/._unittest.bat new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._unittest.bat differ diff --git a/inih/tests/._unittest.c b/inih/tests/._unittest.c new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._unittest.c differ diff --git a/inih/tests/._user_error.ini b/inih/tests/._user_error.ini new file mode 100755 index 000000000..7fa6eb8a6 Binary files /dev/null and b/inih/tests/._user_error.ini differ diff --git a/inih/tests/bad_comment.ini b/inih/tests/bad_comment.ini new file mode 100755 index 000000000..7f4602eb9 --- /dev/null +++ b/inih/tests/bad_comment.ini @@ -0,0 +1 @@ +This is an error diff --git a/inih/tests/bad_multi.ini b/inih/tests/bad_multi.ini new file mode 100755 index 000000000..655017500 --- /dev/null +++ b/inih/tests/bad_multi.ini @@ -0,0 +1 @@ + indented diff --git a/inih/tests/bad_section.ini b/inih/tests/bad_section.ini new file mode 100755 index 000000000..90e31ac09 --- /dev/null +++ b/inih/tests/bad_section.ini @@ -0,0 +1,5 @@ +[section1] +name1=value1 +[section2 +[section3 ; comment ] +name2=value2 diff --git a/inih/tests/baseline_multi.txt b/inih/tests/baseline_multi.txt new file mode 100755 index 000000000..637f75258 --- /dev/null +++ b/inih/tests/baseline_multi.txt @@ -0,0 +1,47 @@ +no_file.ini: e=-1 user=0 +... [section1] +... one=This is a test; +... two=1234; +... [ section 2 ] +... happy=4; +... sad=; +... [comment_test] +... test1=1;2;3; +... test2=2;3;4;this won't be a comment, needs whitespace before ';'; +... test;3=345; +... test4=4#5#6; +... [colon_tests] +... Content-Type=text/html; +... foo=bar; +... adams=42; +normal.ini: e=0 user=101 +... [section1] +... name1=value1; +... name2=value2; +bad_section.ini: e=3 user=102 +bad_comment.ini: e=1 user=102 +... [section] +... a=b; +... user=parse_error; +... c=d; +user_error.ini: e=3 user=104 +... [section1] +... single1=abc; +... multi=this is a; +... multi=multi-line value; +... single2=xyz; +... [section2] +... multi=a; +... multi=b; +... multi=c; +... [section3] +... single=ghi; +... multi=the quick; +... multi=brown fox; +... name=bob smith; +multi_line.ini: e=0 user=105 +bad_multi.ini: e=1 user=105 +... [bom_section] +... bom_name=bom_value; +... key“=value“; +bom.ini: e=0 user=107 diff --git a/inih/tests/baseline_single.txt b/inih/tests/baseline_single.txt new file mode 100755 index 000000000..30d8a2600 --- /dev/null +++ b/inih/tests/baseline_single.txt @@ -0,0 +1,43 @@ +no_file.ini: e=-1 user=0 +... [section1] +... one=This is a test; +... two=1234; +... [ section 2 ] +... happy=4; +... sad=; +... [comment_test] +... test1=1;2;3; +... test2=2;3;4;this won't be a comment, needs whitespace before ';'; +... test;3=345; +... test4=4#5#6; +... [colon_tests] +... Content-Type=text/html; +... foo=bar; +... adams=42; +normal.ini: e=0 user=101 +... [section1] +... name1=value1; +... name2=value2; +bad_section.ini: e=3 user=102 +bad_comment.ini: e=1 user=102 +... [section] +... a=b; +... user=parse_error; +... c=d; +user_error.ini: e=3 user=104 +... [section1] +... single1=abc; +... multi=this is a; +... single2=xyz; +... [section2] +... multi=a; +... [section3] +... single=ghi; +... multi=the quick; +... name=bob smith; +multi_line.ini: e=4 user=105 +bad_multi.ini: e=1 user=105 +... [bom_section] +... bom_name=bom_value; +... key“=value“; +bom.ini: e=0 user=107 diff --git a/inih/tests/bom.ini b/inih/tests/bom.ini new file mode 100755 index 000000000..44c519f47 --- /dev/null +++ b/inih/tests/bom.ini @@ -0,0 +1,3 @@ +[bom_section] +bom_name=bom_value +key“ = value“ diff --git a/inih/tests/multi_line.ini b/inih/tests/multi_line.ini new file mode 100755 index 000000000..d6eb10445 --- /dev/null +++ b/inih/tests/multi_line.ini @@ -0,0 +1,15 @@ +[section1] +single1 = abc +multi = this is a + multi-line value +single2 = xyz +[section2] +multi = a + b + c +[section3] +single: ghi +multi: the quick + brown fox +name = bob smith ; comment line 1 + ; comment line 2 diff --git a/inih/tests/normal.ini b/inih/tests/normal.ini new file mode 100755 index 000000000..787ff8174 --- /dev/null +++ b/inih/tests/normal.ini @@ -0,0 +1,25 @@ +; This is an INI file +[section1] ; section comment +one=This is a test ; name=value comment +two = 1234 +; x=y + +[ section 2 ] +happy = 4 +sad = + +[empty] +; do nothing + +[comment_test] +test1 = 1;2;3 ; only this will be a comment +test2 = 2;3;4;this won't be a comment, needs whitespace before ';' +test;3 = 345 ; key should be "test;3" +test4 = 4#5#6 ; '#' only starts a comment at start of line +#test5 = 567 ; entire line commented + # test6 = 678 ; entire line commented, except in MULTILINE mode + +[colon_tests] +Content-Type: text/html +foo:bar +adams : 42 diff --git a/inih/tests/unittest.bat b/inih/tests/unittest.bat new file mode 100755 index 000000000..90969fe3f --- /dev/null +++ b/inih/tests/unittest.bat @@ -0,0 +1,2 @@ +@call tcc ..\ini.c -I..\ -run unittest.c > baseline_multi.txt +@call tcc ..\ini.c -I..\ -DINI_ALLOW_MULTILINE=0 -run unittest.c > baseline_single.txt diff --git a/inih/tests/unittest.c b/inih/tests/unittest.c new file mode 100755 index 000000000..5e8f8904c --- /dev/null +++ b/inih/tests/unittest.c @@ -0,0 +1,58 @@ +/* inih -- unit tests + +This works simply by dumping a bunch of info to standard output, which is +redirected to an output file (baseline_*.txt) and checked into the Subversion +repository. This baseline file is the test output, so the idea is to check it +once, and if it changes -- look at the diff and see which tests failed. + +Here's how I produced the two baseline files (with Tiny C Compiler): + +tcc -DINI_ALLOW_MULTILINE=1 ../ini.c -run unittest.c > baseline_multi.txt +tcc -DINI_ALLOW_MULTILINE=0 ../ini.c -run unittest.c > baseline_single.txt + +*/ + +#include +#include +#include +#include "../ini.h" + +int User; +char Prev_section[50]; + +int dumper(void* user, const char* section, const char* name, + const char* value) +{ + User = (int)user; + if (strcmp(section, Prev_section)) { + printf("... [%s]\n", section); + strncpy(Prev_section, section, sizeof(Prev_section)); + Prev_section[sizeof(Prev_section) - 1] = '\0'; + } + printf("... %s=%s;\n", name, value); + + return strcmp(name, "user")==0 && strcmp(value, "parse_error")==0 ? 0 : 1; +} + +void parse(const char* fname) { + static int u = 100; + int e; + + *Prev_section = '\0'; + e = ini_parse(fname, dumper, (void*)u); + printf("%s: e=%d user=%d\n", fname, e, User); + u++; +} + +int main(void) +{ + parse("no_file.ini"); + parse("normal.ini"); + parse("bad_section.ini"); + parse("bad_comment.ini"); + parse("user_error.ini"); + parse("multi_line.ini"); + parse("bad_multi.ini"); + parse("bom.ini"); + return 0; +} diff --git a/inih/tests/user_error.ini b/inih/tests/user_error.ini new file mode 100755 index 000000000..9798af35e --- /dev/null +++ b/inih/tests/user_error.ini @@ -0,0 +1,4 @@ +[section] +a = b +user = parse_error +c = d diff --git a/modules/protocol/depend.mk b/modules/protocol/depend.mk index efbcfdf86..a4eb68b17 100644 --- a/modules/protocol/depend.mk +++ b/modules/protocol/depend.mk @@ -33,10 +33,11 @@ mysql_client.o: mysql_client.c ../include/mysql_client_server_protocol.h \ /usr/include/arpa/inet.h \ /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \ /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/bits/stat.h \ - ../../include/dcb.h ../../include/spinlock.h ../../include/thread.h \ + ../../include/service.h ../../include/spinlock.h ../../include/thread.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../../include/buffer.h \ - ../../include/session.h ../../include/poll.h + /usr/include/bits/setjmp.h ../../include/dcb.h ../../include/buffer.h \ + ../../include/server.h ../../include/router.h ../../include/session.h \ + ../../include/poll.h mysql_common.o: mysql_common.c ../include/mysql_client_server_protocol.h \ /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ @@ -72,30 +73,30 @@ mysql_common.o: mysql_common.c ../include/mysql_client_server_protocol.h \ /usr/include/arpa/inet.h \ /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \ /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/bits/stat.h \ - ../../include/dcb.h ../../include/spinlock.h ../../include/thread.h \ + ../../include/service.h ../../include/spinlock.h ../../include/thread.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../../include/buffer.h \ - ../../include/session.h -mysql_backend.o: mysql_backend.c ../../include/session.h \ - /usr/include/time.h /usr/include/features.h /usr/include/sys/cdefs.h \ + /usr/include/bits/setjmp.h ../../include/dcb.h ../../include/buffer.h \ + ../../include/server.h ../../include/router.h ../../include/session.h \ + ../../include/poll.h +mysql_backend.o: mysql_backend.c \ + ../include/mysql_client_server_protocol.h /usr/include/stdio.h \ + /usr/include/features.h /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ /usr/include/gnu/stubs-64.h \ /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \ - /usr/include/bits/time.h /usr/include/bits/types.h \ - /usr/include/bits/typesizes.h /usr/include/xlocale.h \ - ../../include/server.h ../include/mysql_client_server_protocol.h \ - /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h \ - /usr/include/wchar.h \ + /usr/include/bits/types.h /usr/include/bits/typesizes.h \ + /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \ /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \ /usr/include/stdlib.h /usr/include/bits/waitflags.h \ /usr/include/bits/waitstatus.h /usr/include/endian.h \ /usr/include/bits/endian.h /usr/include/bits/byteswap.h \ - /usr/include/sys/types.h /usr/include/sys/select.h \ + /usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \ /usr/include/bits/select.h /usr/include/bits/sigset.h \ - /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \ - /usr/include/alloca.h /usr/include/stdint.h /usr/include/bits/wchar.h \ - /usr/include/string.h /usr/include/openssl/sha.h \ + /usr/include/bits/time.h /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h /usr/include/alloca.h \ + /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/string.h \ + /usr/include/xlocale.h /usr/include/openssl/sha.h \ /usr/include/openssl/e_os2.h /usr/include/openssl/opensslconf.h \ /usr/include/openssl/opensslconf-x86_64.h /usr/include/sys/ioctl.h \ /usr/include/bits/ioctls.h /usr/include/asm/ioctls.h \ @@ -113,9 +114,11 @@ mysql_backend.o: mysql_backend.c ../../include/session.h \ /usr/include/arpa/inet.h \ /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \ /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/bits/stat.h \ - ../../include/dcb.h ../../include/spinlock.h ../../include/thread.h \ + ../../include/service.h ../../include/spinlock.h ../../include/thread.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../../include/buffer.h + /usr/include/bits/setjmp.h ../../include/dcb.h ../../include/buffer.h \ + ../../include/server.h ../../include/router.h ../../include/session.h \ + ../../include/poll.h mysql_common.o: mysql_common.c ../include/mysql_client_server_protocol.h \ /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \ /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ @@ -151,7 +154,8 @@ mysql_common.o: mysql_common.c ../include/mysql_client_server_protocol.h \ /usr/include/arpa/inet.h \ /usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \ /usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/bits/stat.h \ - ../../include/dcb.h ../../include/spinlock.h ../../include/thread.h \ + ../../include/service.h ../../include/spinlock.h ../../include/thread.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \ - /usr/include/bits/setjmp.h ../../include/buffer.h \ - ../../include/session.h + /usr/include/bits/setjmp.h ../../include/dcb.h ../../include/buffer.h \ + ../../include/server.h ../../include/router.h ../../include/session.h \ + ../../include/poll.h