From 108c20b23f2ca3d0ae67a44dfd8da31a7db7544c Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Sun, 11 Feb 2007 22:12:33 +0100 Subject: [PATCH] Changed from the old `libconfig' to the new `liboconfig'. Much work lies in front of us.. :/ --- configure.in | 5 +- src/Makefile.am | 6 +- src/collectd.c | 70 +++--- src/collectd.h | 7 +- src/configfile.c | 532 +++++++++++++++++---------------------------- src/configfile.h | 18 +- src/liboconfig/AUTHORS | 0 src/liboconfig/COPYING | 340 +++++++++++++++++++++++++++++ src/liboconfig/ChangeLog | 2 + src/liboconfig/Makefile.am | 11 + src/liboconfig/aux_types.h | 18 ++ src/liboconfig/oconfig.c | 84 +++++++ src/liboconfig/oconfig.h | 67 ++++++ src/liboconfig/parser.y | 220 +++++++++++++++++++ src/liboconfig/scanner.l | 57 +++++ 15 files changed, 1046 insertions(+), 391 deletions(-) create mode 100644 src/liboconfig/AUTHORS create mode 100644 src/liboconfig/COPYING create mode 100644 src/liboconfig/ChangeLog create mode 100644 src/liboconfig/Makefile.am create mode 100644 src/liboconfig/aux_types.h create mode 100644 src/liboconfig/oconfig.c create mode 100644 src/liboconfig/oconfig.h create mode 100644 src/liboconfig/parser.y create mode 100644 src/liboconfig/scanner.l diff --git a/configure.in b/configure.in index a6bc9416..be43e7e5 100644 --- a/configure.in +++ b/configure.in @@ -24,7 +24,8 @@ AC_SUBST(LTDLINCL) AC_SUBST(LIBLTDL) AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL -#AC_PROG_RANLIB +AC_PROG_LEX +AC_PROG_YACC AC_CONFIG_SUBDIRS(libltdl) # @@ -1088,7 +1089,7 @@ AC_COLLECTD([users], [disable], [module], [user count statistics]) AC_COLLECTD([vserver], [disable], [module], [vserver statistics]) AC_COLLECTD([wireless], [disable], [module], [wireless link statistics]) -AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/libconfig/Makefile src/liboping/Makefile) +AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/liboconfig/Makefile src/liboping/Makefile) cat < 0) && (dir[dirlen - 1] == '/')) dir[--dirlen] = '\0'; if (dirlen <= 0) return (-1); - if (chdir (dir) == -1) + status = chdir (dir); + free (dir); + + if (status != 0) { if (errno == ENOENT) { - if (mkdir (dir, 0755) == -1) + if (mkdir (orig_dir, 0755) == -1) { - syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno)); + syslog (LOG_ERR, "mkdir (%s): %s", orig_dir, + strerror (errno)); return (-1); } - else if (chdir (dir) == -1) + else if (chdir (orig_dir) == -1) { - syslog (LOG_ERR, "chdir (%s): %s", dir, strerror (errno)); + syslog (LOG_ERR, "chdir (%s): %s", orig_dir, + strerror (errno)); return (-1); } } else { - syslog (LOG_ERR, "chdir: %s", strerror (errno)); + syslog (LOG_ERR, "chdir (%s): %s", orig_dir, + strerror (errno)); return (-1); } } @@ -258,12 +273,10 @@ static int start_server (void) #endif /* HAVE_LIBRRD */ #if COLLECT_DAEMON -static int pidfile_create (const char *file) +static int pidfile_create (void) { FILE *fh; - - if (file == NULL) - file = PIDFILE; + const char *file = global_option_get ("PIDFile"); if ((fh = fopen (file, "w")) == NULL) { @@ -276,14 +289,11 @@ static int pidfile_create (const char *file) return (0); } /* static int pidfile_create (const char *file) */ -#endif /* COLLECT_DAEMON */ -#if COLLECT_DAEMON -static int pidfile_remove (const char *file) +static int pidfile_remove (void) { - if (file == NULL) { - file = PIDFILE; - } + const char *file = global_option_get ("PIDFile"); + return (unlink (file)); } /* static int pidfile_remove (const char *file) */ #endif /* COLLECT_DAEMON */ @@ -292,16 +302,15 @@ int main (int argc, char **argv) { struct sigaction sigIntAction; struct sigaction sigTermAction; - char *datadir = PKGLOCALSTATEDIR; char *configfile = CONFIGFILE; + const char *datadir; #if COLLECT_DAEMON struct sigaction sigChldAction; - char *pidfile = NULL; pid_t pid; int daemonize = 1; #endif #if COLLECT_DEBUG - char *logfile = LOGFILE; + const char *logfile; #endif #if HAVE_LIBRRD @@ -334,7 +343,7 @@ int main (int argc, char **argv) break; #if COLLECT_DAEMON case 'P': - pidfile = optarg; + global_option_set ("PIDFile", optarg); break; case 'f': daemonize = 0; @@ -347,7 +356,7 @@ int main (int argc, char **argv) } /* while (1) */ #if COLLECT_DEBUG - if ((logfile = cf_get_option ("LogFile", LOGFILE)) != NULL) + if ((logfile = global_option_get ("LogFile")) != NULL) DBG_STARTFILE (logfile, "Debug file opened."); #endif @@ -368,7 +377,7 @@ int main (int argc, char **argv) * Change directory. We do this _after_ reading the config and loading * modules to relative paths work as expected. */ - if ((datadir = cf_get_option ("DataDir", PKGLOCALSTATEDIR)) == NULL) + if ((datadir = global_option_get ("BaseDir")) != NULL) { fprintf (stderr, "Don't have a datadir to use. This should not happen. Ever."); return (1); @@ -386,13 +395,6 @@ int main (int argc, char **argv) sigChldAction.sa_handler = SIG_IGN; sigaction (SIGCHLD, &sigChldAction, NULL); - if ((pidfile == NULL) - && ((pidfile = cf_get_option ("PIDFile", PIDFILE)) == NULL)) - { - fprintf (stderr, "Cannot obtain pidfile. This shoud not happen. Ever."); - return (1); - } - if (daemonize) { if ((pid = fork ()) == -1) @@ -412,7 +414,7 @@ int main (int argc, char **argv) setsid (); /* Write pidfile */ - if (pidfile_create (pidfile)) + if (pidfile_create ()) exit (2); /* close standard descriptors */ @@ -470,7 +472,7 @@ int main (int argc, char **argv) #if COLLECT_DAEMON if (daemonize) - pidfile_remove (pidfile); + pidfile_remove (); #endif /* COLLECT_DAEMON */ return (0); diff --git a/src/collectd.h b/src/collectd.h index c05b3e7b..7784d554 100644 --- a/src/collectd.h +++ b/src/collectd.h @@ -221,11 +221,12 @@ # define COLLECTD_XFF 0.1 #endif +#define STATIC_ARRAY_LEN(array) (sizeof (array) / sizeof ((array)[0])) + extern time_t curtime; -#ifdef HAVE_LIBRRD -extern int operating_mode; -#endif +int pidfile_set (const char *file); +const char *pidfile_get (void); /* int main (int argc, char **argv); */ diff --git a/src/configfile.c b/src/configfile.c index 5472de4e..6aafc569 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -22,7 +22,7 @@ #include "collectd.h" -#include "libconfig/libconfig.h" +#include "liboconfig/oconfig.h" #include "common.h" #include "plugin.h" @@ -30,24 +30,11 @@ #include "network.h" #include "utils_debug.h" -#define SHORTOPT_NONE 0 - -#define ERR_NOT_NESTED "Sections cannot be nested.\n" -#define ERR_SECTION_ONLY "`%s' can only be used as section.\n" -#define ERR_NEEDS_ARG "Section `%s' needs an argument.\n" -#define ERR_NEEDS_SECTION "`%s' can only be used within a section.\n" - #define ESCAPE_NULL(str) ((str) == NULL ? "(null)" : (str)) -#define DEBUG_CALLBACK(shortvar, var, arguments, value) \ - DBG("shortvar = %s, var = %s, arguments = %s, value = %s, ...", \ - ESCAPE_NULL(shortvar), \ - ESCAPE_NULL(var), \ - ESCAPE_NULL(arguments), \ - ESCAPE_NULL(value)) - -extern int operating_mode; - +/* + * Private types + */ typedef struct cf_callback { const char *type; @@ -57,39 +44,52 @@ typedef struct cf_callback struct cf_callback *next; } cf_callback_t; -static cf_callback_t *first_callback = NULL; +typedef struct cf_value_map_s +{ + char *key; + int (*func) (const oconfig_item_t *); +} cf_value_map_t; -typedef struct cf_mode_item +typedef struct cf_global_option_s { char *key; char *value; - int mode; -} cf_mode_item_t; + char *def; +} cf_global_option_t; + +/* + * Prototypes of callback functions + */ +static int dispatch_value_pidfile (const oconfig_item_t *ci); +static int dispatch_value_plugindir (const oconfig_item_t *ci); +static int dispatch_value_loadplugin (const oconfig_item_t *ci); -/* TODO - * - LogFile +/* + * Private variables */ -static cf_mode_item_t cf_mode_list[] = +static cf_callback_t *first_callback = NULL; + +static cf_value_map_t cf_value_map[] = { - {"TimeToLive", NULL, MODE_CLIENT }, - {"PIDFile", NULL, MODE_CLIENT | MODE_SERVER | MODE_LOCAL | MODE_LOG }, - {"DataDir", NULL, MODE_CLIENT | MODE_SERVER | MODE_LOCAL | MODE_LOG }, - {"LogFile", NULL, MODE_CLIENT | MODE_SERVER | MODE_LOCAL | MODE_LOG } + {"PIDFile", dispatch_value_pidfile}, + {"PluginDir", dispatch_value_plugindir}, + {"LoadPlugin", dispatch_value_loadplugin} }; -static int cf_mode_num = 4; - -static int nesting_depth = 0; -static char *current_module = NULL; +static int cf_value_map_num = STATIC_ARRAY_LEN (cf_value_map); -/* `cf_register' needs this prototype */ -static int cf_callback_plugin_dispatch (const char *, const char *, - const char *, const char *, lc_flags_t, void *); +static cf_global_option_t cf_global_options[] = +{ + {"BaseDir", NULL, PKGLOCALSTATEDIR}, + {"LogFile", NULL, LOGFILE}, + {"PIDFile", NULL, PIDFILE} +}; +static int cf_global_options_num = STATIC_ARRAY_LEN (cf_global_options); /* * Functions to handle register/unregister, search, and other plugin related * stuff */ -static cf_callback_t *cf_search (char *type) +static cf_callback_t *cf_search (const char *type) { cf_callback_t *cf_cb; @@ -103,7 +103,8 @@ static cf_callback_t *cf_search (char *type) return (cf_cb); } -static int cf_dispatch (char *type, const char *orig_key, const char *orig_value) +static int cf_dispatch (const char *type, const char *orig_key, + const char *orig_value) { cf_callback_t *cf_cb; char *key; @@ -152,366 +153,229 @@ static int cf_dispatch (char *type, const char *orig_key, const char *orig_value return (ret); } -void cf_unregister (const char *type) +static int dispatch_value_pidfile (const oconfig_item_t *ci) { - cf_callback_t *this, *prev; + assert (strcasecmp (ci->key, "PIDFile") == 0); + + if (ci->values_num != 1) + return (-1); + if (ci->values[0].type != OCONFIG_TYPE_STRING) + return (-1); - for (prev = NULL, this = first_callback; - this != NULL; - prev = this, this = this->next) - if (strcasecmp (this->type, type) == 0) - { - if (prev == NULL) - first_callback = this->next; - else - prev->next = this->next; + return (global_option_set ("PIDFile", ci->values[0].value.string)); +} - free (this); - break; - } +static int dispatch_value_plugindir (const oconfig_item_t *ci) +{ + assert (strcasecmp (ci->key, "PluginDir") == 0); + + if (ci->values_num != 1) + return (-1); + if (ci->values[0].type != OCONFIG_TYPE_STRING) + return (-1); + + plugin_set_dir (ci->values[0].value.string); + return (0); } -void cf_register (const char *type, - int (*callback) (const char *, const char *), - const char **keys, int keys_num) +static int dispatch_value_loadplugin (const oconfig_item_t *ci) { - cf_callback_t *cf_cb; - char buf[64]; - int i; + assert (strcasecmp (ci->key, "LoadPlugin") == 0); - /* Remove this module from the list, if it already exists */ - cf_unregister (type); + if (ci->values_num != 1) + return (-1); + if (ci->values[0].type != OCONFIG_TYPE_STRING) + return (-1); - /* This pointer will be free'd in `cf_unregister' */ - if ((cf_cb = (cf_callback_t *) malloc (sizeof (cf_callback_t))) == NULL) - return; + return (plugin_load (ci->values[0].value.string)); +} /* int dispatch_value_loadplugin */ - cf_cb->type = type; - cf_cb->callback = callback; - cf_cb->keys = keys; - cf_cb->keys_num = keys_num; +static int dispatch_value_plugin (const char *plugin, oconfig_item_t *ci) +{ + char buffer[4096]; + char *buffer_ptr; + int buffer_free; + int i; - cf_cb->next = first_callback; - first_callback = cf_cb; + buffer_ptr = buffer; + buffer_free = sizeof (buffer); - for (i = 0; i < keys_num; i++) + for (i = 0; i < ci->values_num; i++) { - if (snprintf (buf, 64, "Plugin.%s", keys[i]) < 64) - { - /* This may be called multiple times for the same - * `key', but apparently `lc_register_*' can handle - * it.. */ - lc_register_callback (buf, SHORTOPT_NONE, - LC_VAR_STRING, cf_callback_plugin_dispatch, - NULL); - } - else - { - DBG ("Key was truncated: `%s'", ESCAPE_NULL(keys[i])); - } + int status = -1; + + if (ci->values[i].type == OCONFIG_TYPE_STRING) + status = snprintf (buffer_ptr, buffer_free, " %s", + ci->values[i].value.string); + else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) + status = snprintf (buffer_ptr, buffer_free, " %lf", + ci->values[i].value.number); + else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) + status = snprintf (buffer_ptr, buffer_free, " %s", + ci->values[i].value.boolean + ? "true" : "false"); + + if ((status < 0) || (status >= buffer_free)) + return (-1); + buffer_free -= status; + buffer_ptr += status; } -} + /* skip the initial space */ + buffer_ptr = buffer + 1; -/* - * Other query functions - */ -char *cf_get_option (const char *key, char *def) + return (cf_dispatch (plugin, ci->key, buffer_ptr)); +} /* int plugin_conf_dispatch */ + +static int dispatch_value (const oconfig_item_t *ci) { + int ret = -2; int i; - for (i = 0; i < cf_mode_num; i++) - { - if ((cf_mode_list[i].mode & operating_mode) == 0) - continue; + for (i = 0; i < cf_value_map_num; i++) + if (strcasecmp (cf_value_map[i].key, ci->key) == 0) + { + ret = cf_value_map[i].func (ci); + break; + } - if (strcasecmp (cf_mode_list[i].key, key) != 0) - continue; + return (ret); +} /* int dispatch_value */ - if (cf_mode_list[i].value != NULL) - return (cf_mode_list[i].value); - return (def); - } +static int dispatch_block_plugin (oconfig_item_t *ci) +{ + int i; + char *name; - return (NULL); -} + if (strcasecmp (ci->key, "Plugin") != 0) + return (-1); + if (ci->values_num != 1) + return (-1); + if (ci->values[0].type != OCONFIG_TYPE_STRING) + return (-1); -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Functions for the actual parsing * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + name = ci->values[0].value.string; -/* - * `cf_callback_mode' - * Chose the `operating_mode' - * - * Mode `value' - */ -static int cf_callback_mode (const char *shortvar, const char *var, - const char *arguments, const char *value, lc_flags_t flags, - void *extra) -{ - DEBUG_CALLBACK (shortvar, var, arguments, value); - - if (strcasecmp (value, "Client") == 0) - operating_mode = MODE_CLIENT; -#if HAVE_LIBRRD - else if (strcasecmp (value, "Server") == 0) - operating_mode = MODE_SERVER; - else if (strcasecmp (value, "Local") == 0) - operating_mode = MODE_LOCAL; -#else /* !HAVE_LIBRRD */ - else if (strcasecmp (value, "Server") == 0) - { - fprintf (stderr, "Invalid mode `Server': " - "You need to link against librrd for this " - "mode to be available.\n"); - syslog (LOG_ERR, "Invalid mode `Server': " - "You need to link against librrd for this " - "mode to be available."); - return (LC_CBRET_ERROR); - } - else if (strcasecmp (value, "Local") == 0) + for (i = 0; i < ci->children_num; i++) { - fprintf (stderr, "Invalid mode `Local': " - "You need to link against librrd for this " - "mode to be available.\n"); - syslog (LOG_ERR, "Invalid mode `Local': " - "You need to link against librrd for this " - "mode to be available."); - return (LC_CBRET_ERROR); - } -#endif - else if (strcasecmp (value, "Log") == 0) - operating_mode = MODE_LOG; - else - { - syslog (LOG_ERR, "Invalid value for config option `Mode': `%s'", value); - return (LC_CBRET_ERROR); + if (ci->children[i].children == NULL) + dispatch_value_plugin (name, ci->children + i); + else + {DBG ("No nested config blocks allow for plugins. Yet.");} } - return (LC_CBRET_OKAY); + return (0); } -/* - * `cf_callback_mode_plugindir' - * Change the plugin directory - * - * - * PluginDir `value' - * - */ -static int cf_callback_mode_plugindir (const char *shortvar, const char *var, - const char *arguments, const char *value, lc_flags_t flags, - void *extra) -{ - DEBUG_CALLBACK (shortvar, var, arguments, value); - plugin_set_dir (value); +static int dispatch_block (oconfig_item_t *ci) +{ + if (strcasecmp (ci->key, "Plugin") == 0) + return (dispatch_block_plugin (ci)); - return (LC_CBRET_OKAY); + return (0); } -static int cf_callback_mode_option (const char *shortvar, const char *var, - const char *arguments, const char *value, lc_flags_t flags, - void *extra) +/* + * Public functions + */ +int global_option_set (const char *option, const char *value) { - cf_mode_item_t *item; - - DEBUG_CALLBACK (shortvar, var, arguments, value); - - if (extra == NULL) - { - fprintf (stderr, "No extra..?\n"); - return (LC_CBRET_ERROR); - } + int i; - item = (cf_mode_item_t *) extra; + for (i = 0; i < cf_global_options_num; i++) + if (strcasecmp (cf_global_options[i].key, option) == 0) + break; - if (strcasecmp (item->key, shortvar)) - { - fprintf (stderr, "Wrong extra..\n"); - return (LC_CBRET_ERROR); - } + if (i >= cf_global_options_num) + return (-1); - if ((operating_mode & item->mode) == 0) - { - fprintf (stderr, "Option `%s' is not valid in this mode!\n", shortvar); - return (LC_CBRET_ERROR); - } + if (cf_global_options[i].value != NULL) + free (cf_global_options[i].value); - if (item->value != NULL) - { - free (item->value); - item->value = NULL; - } - - if ((item->value = strdup (value)) == NULL) - { - perror ("strdup"); - return (LC_CBRET_ERROR); - } + if (value != NULL) + cf_global_options[i].value = strdup (value); + else + cf_global_options[i].value = NULL; - return (LC_CBRET_OKAY); + return (0); } -/* - * `cf_callback_mode_loadmodule': - * Load a plugin. - * - * - * LoadPlugin `value' - * - */ -static int cf_callback_mode_loadmodule (const char *shortvar, const char *var, - const char *arguments, const char *value, lc_flags_t flags, - void *extra) +const char *global_option_get (const char *option) { - DEBUG_CALLBACK (shortvar, var, arguments, value); + int i; - if (plugin_load (value)) - syslog (LOG_ERR, "plugin_load (%s): failed to load plugin", value); + for (i = 0; i < cf_global_options_num; i++) + if (strcasecmp (cf_global_options[i].key, option) == 0) + break; - /* Return `okay' even if there was an error, because it's not a syntax - * problem.. */ - return (LC_CBRET_OKAY); -} + if (i >= cf_global_options_num) + return (NULL); + + return ((cf_global_options[i].value != NULL) + ? cf_global_options[i].value + : cf_global_options[i].def); +} /* char *global_option_get */ -/* - * `cf_callback_plugin' - * Start/end section `plugin' - * - * - * ... - * - */ -static int cf_callback_plugin (const char *shortvar, const char *var, - const char *arguments, const char *value, lc_flags_t flags, - void *extra) +void cf_unregister (const char *type) { - DEBUG_CALLBACK (shortvar, var, arguments, value); - - if (flags == LC_FLAGS_SECTIONSTART) - { - if (nesting_depth != 0) - { - fprintf (stderr, ERR_NOT_NESTED); - return (LC_CBRET_ERROR); - } - - if (arguments == NULL) - { - fprintf (stderr, ERR_NEEDS_ARG, shortvar); - return (LC_CBRET_ERROR); - } + cf_callback_t *this, *prev; - if ((current_module = strdup (arguments)) == NULL) + for (prev = NULL, this = first_callback; + this != NULL; + prev = this, this = this->next) + if (strcasecmp (this->type, type) == 0) { - perror ("strdup"); - return (LC_CBRET_ERROR); - } - - nesting_depth++; + if (prev == NULL) + first_callback = this->next; + else + prev->next = this->next; - if (cf_search (current_module) != NULL) - return (LC_CBRET_OKAY); - else - return (LC_CBRET_IGNORESECTION); - } - else if (flags == LC_FLAGS_SECTIONEND) - { - if (current_module != NULL) - { - free (current_module); - current_module = NULL; + free (this); + break; } - - nesting_depth--; - - return (LC_CBRET_OKAY); - } - else - { - fprintf (stderr, ERR_SECTION_ONLY, shortvar); - return (LC_CBRET_ERROR); - } } -/* - * `cf_callback_plugin_dispatch' - * Send options within `plugin' sections to the plugin that requests it. - * - * - * `var' `value' - * - */ -static int cf_callback_plugin_dispatch (const char *shortvar, const char *var, - const char *arguments, const char *value, lc_flags_t flags, - void *extra) +void cf_register (const char *type, + int (*callback) (const char *, const char *), + const char **keys, int keys_num) { - DEBUG_CALLBACK (shortvar, var, arguments, value); - - if ((nesting_depth == 0) || (current_module == NULL)) - { - fprintf (stderr, ERR_NEEDS_SECTION, shortvar); - return (LC_CBRET_ERROR); - } - - /* Send the data to the plugin */ - if (cf_dispatch (current_module, shortvar, value) < 0) - return (LC_CBRET_ERROR); - - return (LC_CBRET_OKAY); -} + cf_callback_t *cf_cb; -static void cf_init (void) -{ - static int run_once = 0; - int i; + /* Remove this module from the list, if it already exists */ + cf_unregister (type); - if (run_once != 0) + /* This pointer will be free'd in `cf_unregister' */ + if ((cf_cb = (cf_callback_t *) malloc (sizeof (cf_callback_t))) == NULL) return; - run_once = 1; - - lc_register_callback ("Mode", SHORTOPT_NONE, LC_VAR_STRING, - cf_callback_mode, NULL); - lc_register_callback ("Plugin", SHORTOPT_NONE, LC_VAR_SECTION, - cf_callback_plugin, NULL); - - lc_register_callback ("PluginDir", SHORTOPT_NONE, - LC_VAR_STRING, cf_callback_mode_plugindir, NULL); - lc_register_callback ("LoadPlugin", SHORTOPT_NONE, - LC_VAR_STRING, cf_callback_mode_loadmodule, NULL); - for (i = 0; i < cf_mode_num; i++) - { - cf_mode_item_t *item; - - item = &cf_mode_list[i]; + cf_cb->type = type; + cf_cb->callback = callback; + cf_cb->keys = keys; + cf_cb->keys_num = keys_num; - lc_register_callback (item->key, SHORTOPT_NONE, LC_VAR_STRING, - cf_callback_mode_option, (void *) item); - } -} + cf_cb->next = first_callback; + first_callback = cf_cb; +} /* void cf_register */ int cf_read (char *filename) { - cf_init (); - - if (filename == NULL) - filename = CONFIGFILE; - - DBG ("Starting to parse file `%s'", filename); + oconfig_item_t *conf; + int i; - /* int lc_process_file(const char *appname, const char *pathname, lc_conf_type_t type); */ - if (lc_process_file ("collectd", filename, LC_CONF_APACHE)) + conf = oconfig_parse_file (filename); + if (conf == NULL) { - syslog (LOG_ERR, "lc_process_file (%s): %s", filename, lc_geterrstr ()); + syslog (LOG_ERR, "Unable to read config file %s.", filename); return (-1); } - DBG ("Done parsing file `%s'", filename); - - /* free memory and stuff */ - lc_cleanup (); + for (i = 0; i < conf->children_num; i++) + { + if (conf->children[i].children == NULL) + dispatch_value (conf->children + i); + else + dispatch_block (conf->children + i); + } return (0); -} +} /* int cf_read */ diff --git a/src/configfile.h b/src/configfile.h index fec1cf4b..0ee8f33c 100644 --- a/src/configfile.h +++ b/src/configfile.h @@ -63,21 +63,6 @@ void cf_register (const char *type, /* * DESCRIPTION - * `cf_get_option' returns various general options. - * - * PARAMETERS - * `key' Name of the option to query. - * `def' Pointer to return as default value. - * - * RETURN VALUE - * The pointer returned is part of an internal structure and may not be - * changed. If the option is not found for whatever reason (wrong key, option - * not allowed for currently selected mode, ...) `NULL' is returned. - */ -char *cf_get_option (const char *key, char *def); - -/* - * DESCRIPTION * `cf_read' reads the config file `filename' and dispatches the read * information to functions/variables. Most important: Is calls `plugin_load' * to load specific plugins, depending on the current mode of operation. @@ -93,4 +78,7 @@ char *cf_get_option (const char *key, char *def); */ int cf_read (char *filename); +int global_option_set (const char *option, const char *value); +const char *global_option_get (const char *option); + #endif /* defined(CONFIGFILE_H) */ diff --git a/src/liboconfig/AUTHORS b/src/liboconfig/AUTHORS new file mode 100644 index 00000000..e69de29b diff --git a/src/liboconfig/COPYING b/src/liboconfig/COPYING new file mode 100644 index 00000000..623b6258 --- /dev/null +++ b/src/liboconfig/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/liboconfig/ChangeLog b/src/liboconfig/ChangeLog new file mode 100644 index 00000000..85f0dd9b --- /dev/null +++ b/src/liboconfig/ChangeLog @@ -0,0 +1,2 @@ +2007-02-11, Version 0.1.0 + * Initial release. diff --git a/src/liboconfig/Makefile.am b/src/liboconfig/Makefile.am new file mode 100644 index 00000000..4e8d0869 --- /dev/null +++ b/src/liboconfig/Makefile.am @@ -0,0 +1,11 @@ +AUTOMAKE_OPTIONS = foreign no-dependencies + +BUILT_SOURCES = parser.h +CLEANFILES = parser.[ch] scanner.c +AM_YFLAGS = -d + +include_HEADERS = oconfig.h +lib_LTLIBRARIES = liboconfig.la + +liboconfig_la_LDFLAGS = -version-info 0:0:0 $(LEXLIB) +liboconfig_la_SOURCES = oconfig.c oconfig.h scanner.l parser.y diff --git a/src/liboconfig/aux_types.h b/src/liboconfig/aux_types.h new file mode 100644 index 00000000..25b81ab6 --- /dev/null +++ b/src/liboconfig/aux_types.h @@ -0,0 +1,18 @@ +#ifndef AUX_TYPES_H +#define AUX_TYPES_H 1 + +struct statement_list_s +{ + oconfig_item_t *statement; + int statement_num; +}; +typedef struct statement_list_s statement_list_t; + +struct argument_list_s +{ + oconfig_value_t *argument; + int argument_num; +}; +typedef struct argument_list_s argument_list_t; + +#endif /* AUX_TYPES_H */ diff --git a/src/liboconfig/oconfig.c b/src/liboconfig/oconfig.c new file mode 100644 index 00000000..f8d18499 --- /dev/null +++ b/src/liboconfig/oconfig.c @@ -0,0 +1,84 @@ +/** + * oconfig - src/oconfig.c + * Copyright (C) 2006,2007 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "oconfig.h" + +/* Functions provided by the scanner */ +void yyset_in (FILE *); + +oconfig_item_t *ci_root; + +oconfig_item_t *oconfig_parse_fh (FILE *fh) +{ + int status; + oconfig_item_t *ret; + + yyset_in (fh); + + status = yyparse (); + if (status != 0) + { + fprintf (stderr, "yyparse returned error #%i\n", status); + return (NULL); + } + + ret = ci_root; + ci_root = NULL; + yyset_in ((FILE *) 0); + + return (ret); +} /* oconfig_item_t *oconfig_parse_fh */ + +oconfig_item_t *oconfig_parse_file (const char *file) +{ + FILE *fh; + oconfig_item_t *ret; + + fh = fopen (file, "r"); + if (fh == NULL) + { + fprintf (stderr, "fopen (%s) failed: %s\n", file, strerror (errno)); + return (NULL); + } + + ret = oconfig_parse_fh (fh); + fclose (fh); + + return (ret); +} /* oconfig_item_t *oconfig_parse_file */ + +void oconfig_free (oconfig_item_t *ci) +{ + int i; + + if (ci->values != NULL) + free (ci->values); + + for (i = 0; i < ci->children_num; i++) + oconfig_free (ci->children + i); +} + +/* + * vim:shiftwidth=2:tabstop=8:softtabstop=2 + */ diff --git a/src/liboconfig/oconfig.h b/src/liboconfig/oconfig.h new file mode 100644 index 00000000..e6e53e27 --- /dev/null +++ b/src/liboconfig/oconfig.h @@ -0,0 +1,67 @@ +#ifndef OCONFIG_H +#define OCONFIG_H 1 + +#include + +/** + * oconfig - src/oconfig.h + * Copyright (C) 2006,2007 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Types + */ +#define OCONFIG_TYPE_STRING 0 +#define OCONFIG_TYPE_NUMBER 1 +#define OCONFIG_TYPE_BOOLEAN 2 + +struct oconfig_value_s +{ + union + { + char *string; + double number; + int boolean; + } value; + int type; +}; +typedef struct oconfig_value_s oconfig_value_t; + +struct oconfig_item_s; +typedef struct oconfig_item_s oconfig_item_t; +struct oconfig_item_s +{ + char *key; + oconfig_value_t *values; + int values_num; + + oconfig_item_t *parent; + oconfig_item_t *children; + int children_num; +}; + +/* + * Functions + */ +oconfig_item_t *oconfig_parse_fh (FILE *fh); +oconfig_item_t *oconfig_parse_file (const char *file); + +void oconfig_free (oconfig_item_t *ci); + +/* + * vim: shiftwidth=2:tabstop=8:softtabstop=2 + */ +#endif /* OCONFIG_H */ diff --git a/src/liboconfig/parser.y b/src/liboconfig/parser.y new file mode 100644 index 00000000..6d1de2d6 --- /dev/null +++ b/src/liboconfig/parser.y @@ -0,0 +1,220 @@ +/** + * oconfig - src/parser.y + * Copyright (C) 2007 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +%{ +#include +#include +#include "oconfig.h" +#include "aux_types.h" + +static char *unquote (const char *orig); +static int yyerror (const char *s); + +/* Lexer variables */ +extern int yylineno; +extern char *yytext; + +extern oconfig_item_t *ci_root; +%} + +%start entire_file + +%union { + double number; + int boolean; + char *string; + oconfig_value_t cv; + oconfig_item_t ci; + argument_list_t al; + statement_list_t sl; +} + +%token NUMBER +%token TRUE FALSE +%token QUOTED_STRING UNQUOTED_STRING +%token SLASH OPENBRAC CLOSEBRAC EOL + +%type string +%type identifier +/* arguments */ +%type argument +%type argument_list +/* blocks */ +%type block_begin +%type block +%type block_end +/* statements */ +%type option +%type statement +%type statement_list +%type entire_file + +%% +string: + QUOTED_STRING {$$ = unquote ($1);} + | UNQUOTED_STRING {$$ = strdup ($1);} + ; + +argument: + NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;} + | TRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;} + | FALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;} + | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;} + ; + +argument_list: + argument_list argument + { + $$ = $1; + $$.argument_num++; + $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t)); + $$.argument[$$.argument_num-1] = $2; + } + | argument + { + $$.argument = malloc (sizeof (oconfig_value_t)); + $$.argument[0] = $1; + $$.argument_num = 1; + } + ; + +identifier: + UNQUOTED_STRING {$$ = strdup ($1);} + ; + +option: + identifier argument_list EOL + { + memset (&$$, '\0', sizeof ($$)); + $$.key = $1; + $$.values = $2.argument; + $$.values_num = $2.argument_num; + } + ; + +block_begin: + OPENBRAC identifier argument_list CLOSEBRAC EOL + { + memset (&$$, '\0', sizeof ($$)); + $$.key = $2; + $$.values = $3.argument; + $$.values_num = $3.argument_num; + } + ; + +block_end: + OPENBRAC SLASH identifier CLOSEBRAC EOL + { + $$ = $3; + } + ; + +block: + block_begin statement_list block_end + { + if (strcmp ($1.key, $3) != 0) + { + printf ("block_begin = %s; block_end = %s;\n", $1.key, $3); + yyerror ("Block not closed..\n"); + exit (1); + } + $$ = $1; + $$.children = $2.statement; + $$.children_num = $2.statement_num; + } + ; + +statement: + option {$$ = $1;} + | block {$$ = $1;} + | EOL {$$.values_num = 0;} + ; + +statement_list: + statement_list statement + { + $$ = $1; + if ($2.values_num > 0) + { + $$.statement_num++; + $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t)); + $$.statement[$$.statement_num-1] = $2; + } + } + | statement + { + if ($1.values_num > 0) + { + $$.statement = malloc (sizeof (oconfig_item_t)); + $$.statement[0] = $1; + $$.statement_num = 1; + } + else + { + $$.statement = NULL; + $$.statement_num = 0; + } + } + ; + +entire_file: + statement_list + { + ci_root = malloc (sizeof (oconfig_item_t)); + memset (ci_root, '\0', sizeof (oconfig_item_t)); + ci_root->children = $1.statement; + ci_root->children_num = $1.statement_num; + } + ; + +%% +static int yyerror (const char *s) +{ + fprintf (stderr, "Error in line %i near `%s': %s\n", yylineno, yytext, s); + return (-1); +} /* int yyerror */ + +static char *unquote (const char *orig) +{ + char *ret = strdup (orig); + int len; + int i; + + if (ret == NULL) + return (NULL); + + len = strlen (ret); + + if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"')) + return (ret); + + ret++; + len -= 2; + ret[len] = '\0'; + + for (i = 0; i < len; i++) + { + if (ret[i] == '\\') + { + memmove (ret + i, ret + (i + 1), len - i); + len--; + } + } + + return (ret); +} /* char *unquote */ diff --git a/src/liboconfig/scanner.l b/src/liboconfig/scanner.l new file mode 100644 index 00000000..aa111a29 --- /dev/null +++ b/src/liboconfig/scanner.l @@ -0,0 +1,57 @@ +/** + * oconfig - src/scanner.l + * Copyright (C) 2007 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +%{ +#include +#include "oconfig.h" +#include "aux_types.h" +#include "parser.h" +%} +WHITE_SPACE [\ \t\b] +QUOTED_STRING \"([^\\"]+|\\.)*\" +UNQUOTED_STRING [0-9A-Za-z_]+ +HEX_NUMBER 0[xX][0-9a-fA-F]+ +OCT_NUMBER 0[0-7]+ +DEC_NUMBER [\+\-]?[0-9]+ +FLOAT_NUMBER [\+\-]?[0-9]*\.[0-9]+([eE][\+\-][0-9]+)? +NUMBER ({FLOAT_NUMBER}|{HEX_NUMBER}|{OCT_NUMBER}|{DEC_NUMBER}) +BOOL_TRUE (true|yes|on) +BOOL_FALSE (false|no|off) +COMMENT #.* +PORT (6(5(5(3[0-5]|[0-2][0-9])|[0-4][0-9][0-9])|[0-4][0-9][0-9][0-9])|[1-5][0-9][0-9][0-9][0-9]|[1-9][0-9]?[0-9]?[0-9]?) +IP_BYTE (2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]) +IPV4_ADDR {IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}(:{PORT})? + +%% +{WHITE_SPACE} | +{COMMENT} {/* ignore */} + +\n {return (EOL);} +"/" {return (SLASH);} +"<" {return (OPENBRAC);} +">" {return (CLOSEBRAC);} +{BOOL_TRUE} {yylval.boolean = 1; return (TRUE);} +{BOOL_FALSE} {yylval.boolean = 0; return (FALSE);} + +{IPV4_ADDR} {yylval.string = yytext; return (UNQUOTED_STRING);} + +{NUMBER} {yylval.number = strtod (yytext, NULL); return (NUMBER);} + +{QUOTED_STRING} {yylval.string = yytext; return (QUOTED_STRING);} +{UNQUOTED_STRING} {yylval.string = yytext; return (UNQUOTED_STRING);} +%% -- 2.11.0