summaryrefslogtreecommitdiff
path: root/common/ini
diff options
context:
space:
mode:
authorDmitri Pal <dpal@redhat.com>2009-04-06 09:42:51 -0400
committerStephen Gallagher <sgallagh@redhat.com>2009-04-06 15:59:21 -0400
commit12454b937b53358e1dbb29dc7649e3f88b9bfd2d (patch)
tree8bb1a5b726772b230c7802ccdf3475d47c298f64 /common/ini
parentde6d6fb21bf367a94c7d292f2c3decd24cf42868 (diff)
downloadsssd-12454b937b53358e1dbb29dc7649e3f88b9bfd2d.tar.gz
sssd-12454b937b53358e1dbb29dc7649e3f88b9bfd2d.tar.bz2
sssd-12454b937b53358e1dbb29dc7649e3f88b9bfd2d.zip
First attempt to produce INI interface.
Diffstat (limited to 'common/ini')
-rw-r--r--common/ini/Makefile.am17
-rw-r--r--common/ini/ini.conf55
-rw-r--r--common/ini/ini.d/real.conf52
-rw-r--r--common/ini/ini.d/test.conf41
-rw-r--r--common/ini/ini_config.c1286
-rw-r--r--common/ini/ini_config.h160
-rw-r--r--common/ini/ini_config_ut.c701
7 files changed, 2312 insertions, 0 deletions
diff --git a/common/ini/Makefile.am b/common/ini/Makefile.am
new file mode 100644
index 00000000..a0131e94
--- /dev/null
+++ b/common/ini/Makefile.am
@@ -0,0 +1,17 @@
+#DEBUG_FLAGS=@DEBUG_VAR@
+TRACE_LEVEL=@TRACE_VAR@
+
+topdir=..
+AM_CPPFLAGS = -I$(topdir) -I$(topdir)/trace -I$(topdir)/collection $(TRACE_LEVEL)
+
+# Build static libraty
+noinst_LIBRARIES = libini_config.a
+libini_config_a_SOURCES = ini_config.c collection.h trace.h collection_tools.h collection_class.h ini_config.h
+
+# Build shared library
+#lib_LTLIBRARIES = libini.la
+#libini_la_SOURCES = ini_config.c collection.h trace.h collection_tools.h collection_class.h ini_config.h
+
+noinst_PROGRAMS = ini_config_ut
+ini_config_ut_SOURCES = ini_config_ut.c
+ini_config_ut_LDADD = libini_config.a -lm -lz ../collection/libcollection.a
diff --git a/common/ini/ini.conf b/common/ini/ini.conf
new file mode 100644
index 00000000..0d0c7edb
--- /dev/null
+++ b/common/ini/ini.conf
@@ -0,0 +1,55 @@
+# INI file that is used by unit test
+
+data = ds,mf.ds,mf.ds,m.ds,mds.,fmds.
+ dskjh = mdsmdssm ,md.sd,
+ C1 = "abcd"
+;test data
+
+wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww = haha
+
+ [
+
+ ]
+
+ [ wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww ]
+
+
+;more data
+
+ = "nmjdsbfmsdn"
+ s = "nmjdsbfmsdn
+
+ HEX1 = 'ABV1'
+ HEX2 = 'ABV'
+ [ ttt ]
+
+C2 ='Ab'
+
+int=-44i44
+int2=-66U
+
+c =
+
+with creame and sugar
+
+ [ dddd ]
+
+DC1 = 123U
+
+f=-9.0.0
+DC2 = -235L
+DC3 = -345.8907
+
+
+ [ zoo
+
+ something
+
+
+ [ ttt ]
+
+v=55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
+v1=55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555.55555555555555555555555555555555
+
+C3 = -34756.56
+C4 = .9
diff --git a/common/ini/ini.d/real.conf b/common/ini/ini.d/real.conf
new file mode 100644
index 00000000..f026bd89
--- /dev/null
+++ b/common/ini/ini.d/real.conf
@@ -0,0 +1,52 @@
+[config]
+version = 0.1
+
+[monitor]
+description = Monitor Configuration
+sbusTimeout = 10
+sbusAddress = unix:path=/var/lib/sss/pipes/private/dbus
+servicePingTime = 10
+bad_number = 5a
+
+[services]
+description = Local service configuration
+activeServices = dp, nss, pam, info
+
+[services/dp]
+description = Data Provider Configuration
+command = /usr/libexec/sssd/sssd_dp
+
+[services/nss]
+description = NSS Responder Configuration
+unixSocket = /var/lib/sss/pipes/nss
+command = /usr/libexec/sssd/sssd_nss
+
+[services/pam]
+command = /usr/libexec/sssd/sssd_pam
+description = PAM Responder Configuration
+unixSocket = /var/lib/sss/pipes/pam
+
+[services/info]
+description = InfoPipe Configuration
+command = ./sbin/sssd_info
+
+[domains]
+domainsOrder = LOCAL, EXAMPLE.COM , SOMEOTHER.COM
+
+[domains/LOCAL]
+description = Reserved domain for local configurations
+legacy = FALSE
+enumerate = 3
+
+[domains/EXAMPLE.COM]
+description = Example domain served by IPA
+provider = ipa
+server = ipaserver1.example.com
+server = ipabackupserver.example.com
+legacy = FALSE
+enumerate = 0
+binary_test = '010203'
+long_array = 1, 2; 4' ;8p .16/ 32?
+
+
+
diff --git a/common/ini/ini.d/test.conf b/common/ini/ini.d/test.conf
new file mode 100644
index 00000000..68e9c674
--- /dev/null
+++ b/common/ini/ini.d/test.conf
@@ -0,0 +1,41 @@
+
+data = ds,mf.ds,mf.ds,m.ds,mds.,fmds.
+ dskjh = mdsmdssm ,md.sd,
+ C1 = "abcd"
+;test data
+
+
+
+;more data
+
+ = "nmjdsbfmsdn"
+ s = "nmjdsbfmsdn
+
+ HEX1 = 'ABV1'
+ HEX2 = 'ABV'
+ [ ttt ]
+
+C2 ='AbBB'
+
+int=-44i44
+int2=-66U
+
+c =
+
+
+ [ dddd1 ]
+
+DC1 = 123U
+
+f=-9.0.0
+DC2 = -235L
+DC3 = -345.8907
+
+
+ [ ttt2 ]
+
+v=55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
+v1=55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555.55555555555555555555555555555555
+
+C3 = -34756.56
+C4 = .9
diff --git a/common/ini/ini_config.c b/common/ini/ini_config.c
new file mode 100644
index 00000000..cf70c9c8
--- /dev/null
+++ b/common/ini/ini_config.c
@@ -0,0 +1,1286 @@
+/*
+ INI LIBRARY
+
+ Reading configuration from INI file
+ and storing as a collection.
+
+ Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+ INI Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ INI Library 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with INI Library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "config.h"
+/* For error text */
+#include <libintl.h>
+#define _(String) gettext (String)
+/* INI file is used as a collection */
+#include "collection_priv.h"
+#include "collection.h"
+#include "collection_tools.h"
+#include "trace.h"
+#include "ini_config.h"
+
+#define NAME_OVERHEAD 10
+
+#define SLASH "/"
+
+/* Name of the special collection used to store parsing errors */
+#define FILE_ERROR_SET "ini_file_error_set"
+
+/* Text error strings used when errors are printed out */
+#define WARNING_TXT _("Warning")
+#define ERROR_TXT _("Error")
+#define WRONG_COLLECTION _("Passed in list is not a list of parse errors.\n")
+#define FAILED_TO_PROCCESS _("Internal Error. Failed to process error list.\n")
+#define ERROR_HEADER _("Parsing errors and warnings in file: %s\n")
+#define LINE_FORMAT _("%s (%d) on line %d: %s\n")
+
+/* Codes that parsing function can return */
+#define RET_PAIR 0
+#define RET_COMMENT 1
+#define RET_SECTION 2
+#define RET_INVALID 3
+#define RET_EMPTY 4
+#define RET_EOF 5
+#define RET_ERROR 6
+
+/* STATIC INTERNAL FUNCTIONS */
+#ifdef HAVE_PARSE_ERROR
+
+
+/* Function to return parsing error */
+inline const char *parsing_error_str(int parsing_error)
+{
+ char *placeholder= _("Unknown error.");
+ char *str_error[] = { _("Data is too long."),
+ _("No closing bracket."),
+ _("Section name is missing."),
+ _("Section name is too long."),
+ _("Equal sign is missing."),
+ _("Property name is missing."),
+ _("Property name is too long.")
+ };
+
+ /* Check the range */
+ if((parsing_error < 1) || (parsing_error > ERR_MAXPARSE)) return (const char *)placeholder;
+ else return (const char *)(str_error[parsing_error-1]);
+}
+
+#else
+
+
+inline const char *parsing_error_str(int parsing_error)
+{
+ char *placeholder= _("Parsing errors are not compiled.");
+ return (const char*)(placeholder);
+}
+
+#endif
+
+/* Add to collection or update - CONSIDER moving to the collection.c */
+static int add_or_update(struct collection_item *current_section,
+ char *key,
+ void *value,
+ int length,
+ int type)
+{
+ int found = COL_NOMATCH;
+ int error = EOK;
+
+ TRACE_FLOW_STRING("add_or_update", "Entry");
+
+ (void)is_item_in_collection(current_section,key,COL_TYPE_ANY,COL_TRAVERSE_IGNORE,&found);
+
+ if(found == COL_MATCH) {
+ TRACE_INFO_STRING("Updating...", "");
+ error = update_property(current_section,key,type,value,length,COL_TRAVERSE_IGNORE);
+ }
+ else {
+ TRACE_INFO_STRING("Adding...", "");
+ error = add_any_property(current_section,NULL,key,type,value,length);
+ }
+
+ TRACE_FLOW_NUMBER("add_or_update returning", error);
+ return error;
+}
+
+/***************************************************************************/
+/* Function to read single ini file and pupulate
+ * the provided collection with subcollcetions from the file */
+static int ini_to_collection(const char *filename,
+ struct collection_item *ini_config,
+ int error_level,
+ struct collection_item **error_list)
+{
+ FILE *file;
+ int error;
+ int status;
+ int section_count = 0;
+ char *key = NULL;
+ char *value = NULL;
+ struct collection_item *current_section = (struct collection_item *)(NULL);
+ int length;
+ int type;
+ int ext_err = -1;
+ struct parse_error pe;
+ int line = 0;
+ int created = 0;
+
+ TRACE_FLOW_STRING("ini_to_collection", "Entry");
+
+ /* Open file for reading */
+ file = fopen(filename,"r");
+ if(file == NULL) {
+ error = errno;
+ TRACE_ERROR_NUMBER("Failed to open file - but this is OK", error);
+ return EOK;
+ }
+
+ /* Open the collection of errors */
+ if(error_list != (struct collection_item **)(NULL)) {
+ *error_list = (struct collection_item *)(NULL);
+ error = create_collection(error_list,(char *)filename,COL_CLASS_INI_PERROR);
+ if(error) {
+ TRACE_ERROR_NUMBER("Failed to create error collection", error);
+ fclose(file);
+ return EOK;
+ }
+ created = 1;
+ }
+
+ /* Read file lines */
+ while((status = read_line(file,&key,&value,&length,&ext_err)) != RET_EOF) {
+
+ line++;
+
+ switch(status) {
+ case RET_PAIR:
+ /* Do we have a section at the top of the file ? */
+ if(section_count == 0) {
+ /* Check if collection already exists */
+ error = get_collection_reference(ini_config,&current_section,INI_DEFAULT_SECTION);
+ if(error != EOK) {
+ /* Create default collection */
+ if((error=create_collection(&current_section,INI_DEFAULT_SECTION,COL_CLASS_INI_SECTION)) ||
+ (error=add_collection_to_collection(ini_config,NULL,NULL,
+ current_section,
+ COL_ADD_MODE_REFERENCE))) {
+ TRACE_ERROR_NUMBER("Failed to create collection", error);
+ fclose(file);
+ destroy_collection(current_section);
+ if(created) destroy_collection(*error_list);
+ return error;
+ }
+ }
+ section_count++;
+ }
+
+ /* Put value into the collection */
+ if((error=add_or_update(current_section,key,value,length,COL_TYPE_STRING))) {
+ TRACE_ERROR_NUMBER("Failed to add pair to collection", error);
+ fclose(file);
+ destroy_collection(current_section);
+ if(created) destroy_collection(*error_list);
+ return error;
+ }
+ break;
+
+ case RET_SECTION:
+ /* Read a new section */
+ destroy_collection(current_section);
+ current_section = (struct collection_item *)(NULL);
+
+ error = get_collection_reference(ini_config,&current_section,key);
+ if(error != EOK) {
+ /* Create default collection */
+ if((error=create_collection(&current_section,key,COL_CLASS_INI_SECTION)) ||
+ (error=add_collection_to_collection(ini_config,NULL,NULL,
+ current_section,
+ COL_ADD_MODE_REFERENCE))) {
+ TRACE_ERROR_NUMBER("Failed to add collection", error);
+ fclose(file);
+ destroy_collection(current_section);
+ if(created) destroy_collection(*error_list);
+ return error;
+ }
+ }
+ section_count++;
+ break;
+
+ case RET_EMPTY:
+ TRACE_INFO_STRING("Empty string", "");
+ break;
+
+ case RET_COMMENT:
+ TRACE_INFO_STRING("Comment", "");
+ break;
+
+ case RET_ERROR:
+ pe.line = line;
+ pe.error = ext_err;
+ error = add_binary_property(*error_list,NULL, ERROR_TXT,(void *)&pe,sizeof(pe));
+ if(error) {
+ TRACE_ERROR_NUMBER("Failed to add error to collection", error);
+ fclose(file);
+ destroy_collection(current_section);
+ if(created) destroy_collection(*error_list);
+ return error;
+ }
+ /* Exit if there was an error parsing file */
+ if(error_level != INI_STOP_ON_NONE) {
+ TRACE_ERROR_STRING("Invalid format of the file", "");
+ destroy_collection(current_section);
+ fclose(file);
+ return EIO;
+ }
+ break;
+ case RET_INVALID:
+ default:
+ pe.line = line;
+ pe.error = ext_err;
+ error = add_binary_property(*error_list,NULL, WARNING_TXT,(void *)&pe,sizeof(pe));
+ if(error) {
+ TRACE_ERROR_NUMBER("Failed to add warning to collection", error);
+ fclose(file);
+ destroy_collection(current_section);
+ if(created) destroy_collection(*error_list);
+ return error;
+ }
+ /* Exit if we are told to exit on warnings */
+ if(error_level == INI_STOP_ON_ANY) {
+ TRACE_ERROR_STRING("Invalid format of the file", "");
+ if(created) destroy_collection(current_section);
+ fclose(file);
+ return EIO;
+ }
+ TRACE_ERROR_STRING("Invalid string", "");
+ break;
+ }
+ ext_err = -1;
+ }
+
+ /* Close file */
+ fclose(file);
+
+ DEBUG_COLLECTION(ini_config);
+
+ destroy_collection(current_section);
+
+ DEBUG_COLLECTION(ini_config);
+
+ TRACE_FLOW_STRING("ini_to_collection", "Success Exit");
+
+ return EOK;
+}
+
+/*********************************************************************/
+/* Read configuration information from a file */
+int config_from_file(const char *application,
+ const char *config_file,
+ struct collection_item **ini_config,
+ int error_level,
+ struct collection_item **error_list)
+{
+ int error;
+ int created = 0;
+
+ TRACE_FLOW_STRING("config_from_file", "Entry");
+
+ if((ini_config == (struct collection_item **)(NULL)) ||
+ (application == NULL)) {
+ TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
+ return EINVAL;
+ }
+
+ /* Create collection if needed */
+ if(*ini_config == (struct collection_item *)(NULL)) {
+ if((error=create_collection(ini_config,(char *)application,COL_CLASS_INI_CONFIG))) {
+ TRACE_ERROR_NUMBER("Failed to create collection", error);
+ return error;
+ }
+ created = 1;
+ }
+ /* Is the collection of the right class? */
+ else if(is_of_class(*ini_config,COL_CLASS_INI_CONFIG)) {
+ TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
+ return EINVAL;
+ }
+
+ /* Do the actual work */
+ error = ini_to_collection((char *)config_file, *ini_config,error_level, error_list);
+ /* In case of error when we created collection - delete it */
+ if((error) && (created)) {
+ destroy_collection(*ini_config);
+ *ini_config = (struct collection_item *)(NULL);
+ }
+
+ TRACE_FLOW_NUMBER("config_from_file. Returns", error);
+ return error;
+}
+
+/* Read default config file and then overwrite it with a specific one from the directory */
+int config_for_app(const char *application,
+ const char *config_file,
+ const char *config_dir,
+ struct collection_item **ini_config,
+ int error_level,
+ struct collection_item **error_set)
+{
+ int error=EOK;
+ char *file_name;
+ struct collection_item *error_list_common = (struct collection_item *)(NULL);
+ struct collection_item *error_list_specific = (struct collection_item *)(NULL);
+ struct collection_item **pass_common = (struct collection_item **)(NULL);
+ struct collection_item **pass_specific = (struct collection_item **)(NULL);
+ struct collection_item *error_file_set = (struct collection_item *)(NULL);
+ int created = 0;
+
+ TRACE_FLOW_STRING("config_to_collection", "Entry");
+
+ if(ini_config == (struct collection_item **)(NULL)) {
+ TRACE_ERROR_NUMBER("Failed to create collection", EINVAL);
+ return EINVAL;
+ }
+
+ /* Prepare error collection pointers */
+ if(error_set != (struct collection_item **)(NULL)) {
+ TRACE_INFO_STRING("Error set is not NULL", "preparing error set");
+ pass_common = &error_list_common;
+ pass_specific = &error_list_specific;
+ *error_set = (struct collection_item *)(NULL);
+ /* Construct the overarching error collection */
+ if((error=create_collection(error_set,FILE_ERROR_SET,COL_CLASS_INI_PESET))) {
+ TRACE_ERROR_NUMBER("Failed to create collection", error);
+ return error;
+ }
+ }
+ else {
+ TRACE_INFO_STRING("No error set. Errors will not be captured", "");
+ pass_common = (struct collection_item **)(NULL);
+ pass_specific = (struct collection_item **)(NULL);
+ }
+
+ /* Create collection if needed */
+ if(*ini_config == (struct collection_item *)(NULL)) {
+ TRACE_INFO_STRING("New config collection. Allocate.", "");
+ if((error=create_collection(ini_config,(char *)application,COL_CLASS_INI_CONFIG))) {
+ TRACE_ERROR_NUMBER("Failed to create collection", error);
+ destroy_collection(*error_set);
+ *error_set = (struct collection_item *)(NULL);
+ return error;
+ }
+ }
+ /* Is the collection of the right class? */
+ else if(is_of_class(*ini_config,COL_CLASS_INI_CONFIG)) {
+ TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
+ return EINVAL;
+ }
+
+ /* Read master file */
+ if(config_file != NULL) {
+ TRACE_INFO_STRING("Reading master file:", config_file);
+ if((error = ini_to_collection(config_file,*ini_config, error_level, pass_common))) {
+ TRACE_ERROR_NUMBER("Failed to read master file", error);
+ /* In case of error when we created collection - delete it */
+ if((error) && (created)) {
+ destroy_collection(*ini_config);
+ *ini_config = (struct collection_item *)(NULL);
+ }
+ /* We do not clear the error_set here */
+ return error;
+ }
+ /* Add error results if any to the overarching error collection */
+ if((pass_common != (struct collection_item **)(NULL)) &&
+ (*pass_common != (struct collection_item *)(NULL))) {
+ TRACE_INFO_STRING("Process erros resulting from file:", config_file);
+ error = add_collection_to_collection(*error_set,NULL,NULL,*pass_common,COL_ADD_MODE_EMBED);
+ if(error) {
+ if(created) {
+ destroy_collection(*ini_config);
+ *ini_config = (struct collection_item *)(NULL);
+ }
+ destroy_collection(*error_set);
+ *error_set = (struct collection_item *)(NULL);
+ TRACE_ERROR_NUMBER("Failed to add error collection to another error collection", error);
+ return error;
+ }
+ }
+ }
+
+ if(config_dir != NULL) {
+ /* Get specific application file */
+ file_name = malloc(strlen(config_dir) + strlen(application) + NAME_OVERHEAD);
+ if(file_name == NULL) {
+ error = errno;
+ TRACE_ERROR_NUMBER("Failed to allocate memory for file name", error);
+ /* In case of error when we created collection - delete it */
+ if((error) && (created)) {
+ destroy_collection(*ini_config);
+ *ini_config = (struct collection_item *)(NULL);
+ }
+ destroy_collection(*error_set);
+ *error_set = (struct collection_item *)(NULL);
+ return error;
+ }
+
+ sprintf(file_name,"%s%s%s.conf",config_dir, SLASH, application);
+ TRACE_INFO_STRING("Opening file:", file_name);
+
+ /* Read master file */
+ error = ini_to_collection(file_name,*ini_config,error_level,pass_specific);
+ free(file_name);
+ if(error) {
+ TRACE_ERROR_NUMBER("Failed to read specific application file", error);
+ /* In case of error when we created collection - delete it */
+ if((error) && (created)) {
+ destroy_collection(*ini_config);
+ *ini_config = (struct collection_item *)(NULL);
+ }
+ /* We do not clear the error_set here */
+ return error;
+ }
+
+ /* Add error results if any to the overarching error collection */
+ if((pass_specific != (struct collection_item **)(NULL)) &&
+ (*pass_specific != (struct collection_item *)(NULL))) {
+ TRACE_INFO_STRING("Process erros resulting from file:", file_name);
+ error = add_collection_to_collection(*error_set,NULL,NULL,*pass_specific,COL_ADD_MODE_EMBED);
+ if(error){
+ if(created) {
+ destroy_collection(*ini_config);
+ *ini_config = (struct collection_item *)(NULL);
+ }
+ destroy_collection(*error_set);
+ *error_set = (struct collection_item *)(NULL);
+ TRACE_ERROR_NUMBER("Failed to add error collection to another error collection", error);
+ return error;
+ }
+ }
+ }
+
+ TRACE_FLOW_STRING("config_to_collection", "Exit");
+ return EOK;
+}
+
+/* Reads a line from the file */
+int read_line(FILE *file,char **key,void **value, int *length, int *ext_error)
+{
+
+ char *res = NULL;
+ char buf[BUFFER_SIZE+1];
+ int len = 0;
+ char *buffer = NULL;
+ int i = 0;
+ int status = RET_INVALID;
+ char *eq = NULL;
+
+ TRACE_FLOW_STRING("read_line","Entry");
+
+ *ext_error = 0;
+
+ buffer = buf;
+
+ /* Get data from file */
+ res = fgets(buffer,BUFFER_SIZE,file);
+ if(res == NULL) {
+ TRACE_ERROR_STRING("Read nothing","");
+ return RET_EOF;
+ }
+
+ len = strlen(buffer);
+ if(len == 0) {
+ TRACE_ERROR_STRING("Nothing was read.","");
+ return RET_EMPTY;
+ }
+
+ /* Added \r just in case we deal with Windows in future */
+ if((*(buffer + len - 1) != '\n') && (*(buffer + len - 1) != '\r')) {
+ TRACE_ERROR_STRING("String it too big!","");
+ *ext_error = ERR_LONGDATA;
+ return RET_ERROR;
+ }
+
+ /* Ingnore comments */
+ if((*buffer == ';') || (*buffer == '#')) {
+ TRACE_FLOW_STRING("Comment",buf);
+ return RET_COMMENT;
+ }
+
+ TRACE_INFO_STRING("BUFFER before trimming:",buffer);
+
+ /* Trucate trailing spaces and CRs */
+ while(isspace(*(buffer + len - 1))) {
+ *(buffer + len - 1) = '\0';
+ len--;
+ }
+
+ TRACE_INFO_STRING("BUFFER after trimming trailing spaces:",buffer);
+
+ /* Trucate leading spaces */
+ while(isspace(*buffer)) {
+ buffer++;
+ len--;
+ }
+
+ TRACE_INFO_STRING("BUFFER after trimming leading spaces:",buffer);
+ TRACE_INFO_NUMBER("BUFFER length:",len);
+
+ /* Empty line */
+ if(len == 0) {
+ TRACE_FLOW_STRING("Empty line",buf);
+ return RET_EMPTY;
+ }
+
+ /* Section */
+ if(*buffer == '[') {
+ if(*(buffer+len-1) != ']') {
+ TRACE_ERROR_STRING("Invalid format for section",buf);
+ *ext_error = ERR_NOCLOSESEC;
+ return RET_ERROR;
+ }
+ buffer++;
+ len--;
+ while(isspace(*(buffer))) {
+ buffer++;
+ len--;
+ }
+ if(len == 0) {
+ TRACE_ERROR_STRING("Invalid format for section",buf);
+ *ext_error = ERR_NOSECTION;
+ return RET_ERROR;
+ }
+
+ *(buffer + len - 1) = '\0';
+ len--;
+ while(isspace(*(buffer + len - 1))) {
+ *(buffer + len - 1) = '\0';
+ len--;
+ }
+ if(len >= MAX_KEY) {
+ TRACE_ERROR_STRING("Section name is too long",buf);
+ *ext_error = ERR_SECTIONLONG;
+ return RET_ERROR;
+ }
+
+ *key = buffer;
+ return RET_SECTION;
+ }
+
+ /* Assume we are dealing with the K-V here */
+ /* Find "=" */
+ eq = strchr(buffer,'=');
+ if(eq == NULL) {
+ TRACE_ERROR_STRING("No equal sign",buf);
+ *ext_error = ERR_NOEQUAL;
+ return RET_BEST_EFFORT;
+ }
+
+ len -= eq-buffer;
+
+ /* Strip spaces around "=" */
+ i = eq - buffer - 1;
+ while((i >= 0) && isspace(*(buffer + i))) i--;
+ if(i<0) {
+ TRACE_ERROR_STRING("No key",buf);
+ *ext_error = ERR_NOKEY;
+ return RET_BEST_EFFORT;
+ }
+
+ /* Copy key into provided buffer */
+ if(i >= MAX_KEY) {
+ TRACE_ERROR_STRING("Section name is too long",buf);
+ *ext_error = ERR_LONGKEY;
+ return RET_BEST_EFFORT;
+ }
+ *key = buffer;
+ *(buffer+i+1) = '\0';
+ TRACE_INFO_STRING("KEY:",*key);
+
+ eq++;
+ len--;
+ while(isspace(*eq)) {
+ eq++;
+ len--;
+ }
+
+ *value = eq;
+ /* Make sure we include trailing 0 into data */
+ *length = len + 1;
+
+ TRACE_INFO_STRING("VALUE:",*value);
+ TRACE_INFO_NUMBER("LENGTH:",*length);
+
+ TRACE_FLOW_STRING("read_line","Exit");
+ return RET_PAIR;
+}
+
+
+/* Print errors and warnings that were detected while parsing one file */
+void print_file_parsing_errors(FILE *file,
+ struct collection_item *error_list)
+{
+ struct collection_iterator *iterator;
+ int error;
+ struct collection_item *item = (struct collection_item *)(NULL);
+ struct collection_header *header;
+ struct parse_error *pe;
+ int count;
+
+ TRACE_FLOW_STRING("print_file_parsing_errors", "Entry");
+
+ /* If we have something to print print it */
+ if(error_list == (struct collection_item *)(NULL)) {
+ TRACE_ERROR_STRING("No error list","");
+ return;
+ }
+
+ /* Make sure we go the right collection */
+ if(!is_of_class(error_list,COL_CLASS_INI_PERROR)) {
+ TRACE_ERROR_STRING("Wrong collection class:",WRONG_COLLECTION);
+ fprintf(file,"%s\n",WRONG_COLLECTION);
+ return;
+ }
+
+ /* Bind iterator */
+ error = bind_iterator(&iterator,error_list,COL_TRAVERSE_DEFAULT);
+ if(error) {
+ TRACE_ERROR_STRING("Error (bind):",FAILED_TO_PROCCESS);
+ fprintf(file,"%s\n",FAILED_TO_PROCCESS);
+ return;
+ }
+
+ do {
+ /* Loop through a collection */
+ error = iterate_collection(iterator, &item);
+ if(error) {
+ TRACE_ERROR_STRING("Error (iterate):",FAILED_TO_PROCCESS);
+ fprintf(file,"%s\n",FAILED_TO_PROCCESS);
+ unbind_iterator(iterator);
+ return;
+ }
+
+ /* Are we done ? */
+ if(item == (struct collection_item *)(NULL)) break;
+
+ /* Process collection header */
+ if(get_item_type(item) == COL_TYPE_COLLECTION) {
+ get_collection_count(item, &count);
+ if(count > 1) fprintf(file,ERROR_HEADER,get_item_property(item,NULL));
+ else break;
+ }
+ else {
+ /* Put error into provided format */
+ pe = (struct parse_error *)(get_item_data(item));
+ fprintf(file,LINE_FORMAT,
+ get_item_property(item,NULL), /* Error or warning */
+ pe->error, /* Error */
+ pe->line, /* Line */
+ parsing_error_str(pe->error)); /* Error str */
+ }
+
+ }
+ while(1);
+
+ /* Do not forget to unbind iterator - otherwise there will be a leak */
+ unbind_iterator(iterator);
+
+ TRACE_FLOW_STRING("print_file_parsing_errors", "Exit");
+}
+
+
+/* Print errors and warnings that were detected parsing configuration as a whole */
+void print_config_parsing_errors(FILE *file,struct collection_item *error_list)
+{
+ struct collection_iterator *iterator;
+ int error;
+ struct collection_item *item = (struct collection_item *)(NULL);
+ struct collection_item *file_errors = (struct collection_item *)(NULL);
+
+ TRACE_FLOW_STRING("print_config_parsing_errors", "Entry");
+
+ /* If we have something to print print it */
+ if(error_list == (struct collection_item *)(NULL)) {
+ TRACE_ERROR_STRING("No error list","");
+ return;
+ }
+
+ /* Make sure we go the right collection */
+ if(!is_of_class(error_list,COL_CLASS_INI_PESET)) {
+ TRACE_ERROR_STRING("Wrong collection class:",WRONG_COLLECTION);
+ fprintf(file,"%s\n",WRONG_COLLECTION);
+ return;
+ }
+
+ /* Bind iterator */
+ error = bind_iterator(&iterator,error_list,COL_TRAVERSE_DEFAULT);
+ if(error) {
+ TRACE_ERROR_STRING("Error (bind):",FAILED_TO_PROCCESS);
+ fprintf(file,"%s\n",FAILED_TO_PROCCESS);
+ return;
+ }
+
+ do {
+ /* Loop through a collection */
+ error = iterate_collection(iterator, &item);
+ if(error) {
+ TRACE_ERROR_STRING("Error (iterate):",FAILED_TO_PROCCESS);
+ fprintf(file,"%s\n",FAILED_TO_PROCCESS);
+ unbind_iterator(iterator);
+ return;
+ }
+
+ /* Are we done ? */
+ if(item == (struct collection_item *)(NULL)) break;
+
+ /* Print per file sets of errors */
+ if(get_item_type(item) == COL_TYPE_COLLECTIONREF) {
+ /* Extract a sub collection */
+ error = get_reference_from_item(item,&file_errors);
+ if(error) {
+ TRACE_ERROR_STRING("Error (extract):",FAILED_TO_PROCCESS);
+ fprintf(file,"%s\n",FAILED_TO_PROCCESS);
+ return;
+ }
+ print_file_parsing_errors(file,file_errors);
+ destroy_collection(file_errors);
+ }
+ }
+ while(1);
+
+ /* Do not forget to unbind iterator - otherwise there will be a leak */
+ unbind_iterator(iterator);
+
+ TRACE_FLOW_STRING("print_config_parsing_errors", "Exit");
+}
+
+
+/* Function to get value from the configration handle */
+int get_config_item(const char *section,
+ const char *name,
+ struct collection_item *ini_config,
+ struct collection_item **item)
+{
+ int error = EOK;
+ struct collection_item *section_handle = (struct collection_item *)(NULL);
+ char *to_find;
+ char default_section[] = INI_DEFAULT_SECTION;
+
+ TRACE_FLOW_STRING("get_config_item", "Entry");
+
+ /* Do we have the accepting memory ? */
+ if(item == (struct collection_item **)(NULL)) {
+ TRACE_ERROR_NUMBER("No buffer - invalid argument.", EINVAL);
+ return EINVAL;
+ }
+
+ /* Is the collection of a right type */
+ if(!is_of_class(ini_config,COL_CLASS_INI_CONFIG)) {
+ TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
+ return EINVAL;
+ }
+
+ *item == (struct collection_item *)(NULL);
+
+ if(section == NULL) to_find = default_section;
+ else to_find = (char *)section;
+
+ TRACE_INFO_STRING("Getting Name:", name);
+ TRACE_INFO_STRING("In Section:", section);
+
+ /* Get Subcollection */
+ error = get_collection_reference(ini_config,&section_handle,to_find);
+ /* Check error */
+ if((error) && (error != ENOENT)) {
+ TRACE_ERROR_NUMBER("Failed to get section", error);
+ return error;
+ }
+
+ /* Did we find a section */
+ if((error == ENOENT) || (section_handle == (struct collection_item *)(NULL))) {
+ /* We have not found section - return success */
+ TRACE_FLOW_STRING("get_value_from_config", "No such section");
+ return EOK;
+ }
+
+ /* Get item */
+ error = get_item(section_handle,(char *)name, COL_TYPE_STRING, COL_TRAVERSE_ONELEVEL, item);
+
+ TRACE_FLOW_NUMBER("get_config_item returning", error);
+ return error;
+}
+
+/* Get long value from config item */
+long get_long_config_value(struct collection_item *item, int strict, long def, int *error)
+{
+ char *endptr, *str;
+ long val = 0;
+
+ TRACE_FLOW_STRING("get_long_config_value", "Entry");
+
+ /* Do we have the item ? */
+ if((item == (struct collection_item *)(NULL)) ||
+ (get_item_type(item) != COL_TYPE_STRING)) {
+ TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+ if(error) *error = EINVAL;
+ return def;
+ }
+
+ if(error) *error = EOK;
+
+ /* Try to parse the value */
+ str = (char *)(get_item_data(item));
+ errno = 0;
+ val = strtol(str, &endptr, 10);
+
+ /* Check for various possible errors */
+ if (((errno == ERANGE) &&
+ ((val == LONG_MAX) ||
+ (val == LONG_MIN))) ||
+ ((errno != 0) && (val == 0)) ||
+ (endptr == str)) {
+ TRACE_ERROR_NUMBER("Conversion failed", EIO);
+ if(error) *error = EIO;
+ return def;
+ }
+
+ if ((strict) && (*endptr != '\0')) {
+ TRACE_ERROR_NUMBER("More characters than expected", EIO);
+ if(error) *error = EIO;
+ val = def;
+ }
+
+ TRACE_FLOW_NUMBER("get_long_config_value returning", val);
+ return val;
+}
+
+/* Get integer value from config item */
+inline int get_int_config_value(struct collection_item *item, int strict, int def, int *error)
+{
+ return (int)get_long_config_value(item, strict, (long)def, error);
+}
+
+/* Get unsigned integer value from config item */
+unsigned get_unsigned_config_value(struct collection_item *item, int strict, unsigned def, int *error)
+{
+ return (unsigned int)get_long_config_value(item, strict, (long)def, error);
+}
+
+/* Get unsigned long value from config item */
+unsigned long get_ulong_config_value(struct collection_item *item, int strict, unsigned long def, int *error)
+{
+ return (unsigned long)get_long_config_value(item, strict, (long)def, error);
+}
+
+/* Get double value */
+double get_double_config_value(struct collection_item *item, int strict, double def, int *error)
+{
+ char *endptr, *str;
+ double val = 0;
+
+ TRACE_FLOW_STRING("get_double_config_value", "Entry");
+
+ /* Do we have the item ? */
+ if((item == (struct collection_item *)(NULL)) ||
+ (get_item_type(item) != COL_TYPE_STRING)) {
+ TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+ if(error) *error = EINVAL;
+ return def;
+ }
+
+ if(error) *error = EOK;
+
+ /* Try to parse the value */
+ str = (char *)(get_item_data(item));
+ errno = 0;
+ val = strtod(str, &endptr);
+
+ /* Check for various possible errors */
+ if ((errno == ERANGE) ||
+ ((errno != 0) && (val == 0)) ||
+ (endptr == str)) {
+ TRACE_ERROR_NUMBER("Conversion failed", EIO);
+ if(error) *error = EIO;
+ return def;
+ }
+
+ if ((strict) && (*endptr != '\0')) {
+ TRACE_ERROR_NUMBER("More characters than expected", EIO);
+ if(error) *error = EIO;
+ val = def;
+ }
+
+ TRACE_FLOW_NUMBER("get_double_config_value returning", val);
+ return val;
+}
+
+/* Get boolean value */
+unsigned char get_bool_config_value(struct collection_item *item, unsigned char def, int *error)
+{
+ char *str;
+ int len;
+
+ TRACE_FLOW_STRING("get_bool_config_value", "Entry");
+
+ /* Do we have the item ? */
+ if((item == (struct collection_item *)(NULL)) ||
+ (get_item_type(item) != COL_TYPE_STRING)) {
+ TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+ if(error) *error = EINVAL;
+ return def;
+ }
+
+ if(error) *error = EOK;
+
+ str = (char *)(get_item_data(item));
+ len = get_item_length(item);
+
+ /* Try to parse the value */
+ if((strncasecmp(str,"true",len) == 0) ||
+ (strncasecmp(str,"yes",len) == 0)) {
+ TRACE_FLOW_STRING("Returning", "true");
+ return '\1';
+ }
+ else if((strncasecmp(str,"false",len) == 0) ||
+ (strncasecmp(str,"no",len) == 0)) {
+ TRACE_FLOW_STRING("Returning", "false");
+ return '\0';
+ }
+
+ TRACE_ERROR_STRING("Returning", "error");
+ if(error) *error = EIO;
+ return def;
+}
+
+/* Return a string out of the value */
+inline char *get_string_config_value(struct collection_item *item, int dup, int *error)
+{
+ char *str = NULL;
+
+ TRACE_FLOW_STRING("get_string_config_value", "Entry");
+
+ /* Do we have the item ? */
+ if((item == (struct collection_item *)(NULL)) ||
+ (get_item_type(item) != COL_TYPE_STRING)) {
+ TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+ if(error) *error = EINVAL;
+ return NULL;
+ }
+
+ /* If we are told to dup the value */
+ if(dup) {
+ errno = 0;
+ str = strdup((char *)(get_item_data(item)));
+ if(str == NULL) {
+ TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+ if(error) *error = ENOMEM;
+ return NULL;
+ }
+ }
+ else str = (char *)(get_item_data(item));
+
+ if(error) *error = EOK;
+
+ TRACE_FLOW_STRING("get_string_config_value", "Exit");
+ return str;
+}
+
+/* A special hex format is assumed.
+ * The string should be taken in single quotes
+ * and consist of hex encoded value two hex digits per byte.
+ * Example: '0A2BFECC'
+ * Case does not matter.
+ */
+char *get_bin_config_value(struct collection_item *item, int *length, int *error)
+{
+ int i;
+ char *value = NULL;
+ char *buff;
+ int size = 0;
+ unsigned char hex;
+ int len;
+ char *str;
+
+ TRACE_FLOW_STRING("get_bin_config_value", "Entry");
+
+ /* Do we have the item ? */
+ if((item == (struct collection_item *)(NULL)) ||
+ (get_item_type(item) != COL_TYPE_STRING)) {
+ TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+ if(error) *error = EINVAL;
+ return NULL;
+ }
+
+ /* Check the length */
+ len = get_item_length(item)-1;
+ if((len/2) *2 != len) {
+ TRACE_ERROR_STRING("Invalid length for binary data","")
+ if(error) *error = EINVAL;
+ return NULL;
+ }
+
+ str = (char *)(get_item_data(item));
+
+ /* Is the format correct ? */
+ if((*str != '\'') ||
+ (*(str + len -1) != '\'')) {
+ TRACE_ERROR_STRING("String is not escaped","")
+ if(error) *error = EIO;
+ return NULL;
+ }
+
+ /* Check that all the symbols are ok */
+ buff = str + 1;
+ len -= 2;
+ for(i=0;i<len;i+=2) {
+ if((!isxdigit(*(buff+i))) || (!isxdigit(*(buff+i+1)))) {
+ TRACE_ERROR_STRING("Invalid encoding for binary data",buff+i)
+ if(error) *error = EIO;
+ return NULL;
+ }
+ }
+
+ /* The value is good so we can allocate memory for it */
+ value = malloc(len/2);
+ if(value == NULL) {
+ TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+ if(error) *error = ENOMEM;
+ return NULL;
+ }
+
+ /* Convert the value */
+ for(i=0;i<len;i+=2) {
+ if(isdigit(*(buff+i))) {
+ if(isdigit(*(buff+i+1))) hex = 16 * (*(buff+i) - '0') + (*(buff+i+1) - '0');
+ else hex = 16 * (*(buff+i) - '0') + (tolower(*(buff+i+1)) - 'a' + 10);
+ }
+ else {
+ if(isdigit(*(buff+i+1))) hex = 16 * (tolower(*(buff+i)) - 'a') + (*(buff+i+1) - '0');
+ else hex = 16 * (tolower(*(buff+i)) - 'a' + 10) + (tolower(*(buff+i+1)) - 'a' + 10);
+ }
+
+ *(value+size) = (char)(hex);
+ size++;
+ }
+
+ if(error) *error = EOK;
+ if(length) *length = size;
+ TRACE_FLOW_STRING("get_bin_config_value", "Exit");
+ return value;
+}
+
+/* Function to free binary configuration value */
+inline void free_bin_config_value(char *value)
+{
+ if(value) free(value);
+}
+
+/* Arrays of stings and integers */
+char **get_string_config_array(struct collection_item *item, char *sep, int *size, int *error)
+{
+ char defsep[] = ",";
+ char *copy = NULL;
+ char *dest = NULL;
+ int total = 0;
+ int lensep;
+ char *buff;
+ int count = 0;
+ int len = 0;
+ int resume_len;
+ char **array;
+ char *start;
+ int i,j,k;
+ int growlen = 0;
+
+ TRACE_FLOW_STRING("get_string_config_array", "Entry");
+
+ /* Do we have the item ? */
+ if((item == (struct collection_item *)(NULL)) ||
+ (get_item_type(item) != COL_TYPE_STRING)) {
+ TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+ if(error) *error = EINVAL;
+ return NULL;
+ }
+
+ /* Handle the separators */
+ if(sep == NULL) sep = defsep;
+ lensep = strnlen(sep,3);
+
+ /* Allocate memory for the copy of the string */
+ copy = malloc(get_item_length(item));
+ if(copy == NULL) {
+ TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+ if(error) *error = ENOMEM;
+ return NULL;
+ }
+
+ /* Loop through the string */
+ dest = copy;
+ buff = item->data;
+ start = buff;
+ for(i=0;i<item->length;i++) {
+ growlen = 1;
+ for(j=0;j<lensep;j++) {
+ if(*(buff+i) == *(sep+j)) {
+ /* If we found one of the separators trim spaces around */
+ resume_len = len;
+ while(len > 0) {
+ if(isspace(*(start+len - 1))) len--;
+ else break;
+ }
+ if(len > 0) {
+ /* Save block aside */
+ memcpy(dest,start,len);
+ count++;
+ dest+=len;
+ *dest='\0';
+ dest++;
+ len = 0;
+ /* Move forward and trim spaces if any */
+ start += resume_len + 1;
+ i++;
+ TRACE_INFO_STRING("Remaining buffer :", start);
+ TRACE_INFO_STRING("Other pointer :", buff + i);
+ k = 0;
+ while(((i+k) < item->length) && (isspace(*start))) {
+ k++;
+ start++;
+ }
+ TRACE_INFO_STRING("Remaining buffer after triming spaces:", start);
+ if(k) i+=k-1;
+ /* Next iteration of the loop will add 1 */
+ }
+ /* Break out of the inner loop */
+ growlen = 0;
+ break;
+ }
+ }
+ if(growlen) len++;
+ }
+
+ /* Copy the remaining piece */
+ memcpy(dest,start,len);
+ count++;
+ dest+=len;
+ dest='\0';
+ dest++;
+
+ /* Now we know how many items are there in the list */
+ array = malloc((count + 1) * sizeof(char *));
+ if(array == NULL) {
+ free(copy);
+ TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+ if(error) *error = ENOMEM;
+ return NULL;
+ }
+
+ /* Loop again to fill in the pointers */
+ start = copy;
+ for(i=0;i<count;i++) {
+ *(array+i) = start;
+ while(*start!='\0') start++;
+ start++;
+ }
+ *(array+count) = NULL;
+
+ if(error) *error = EOK;
+ if(size) *size = count;
+ TRACE_FLOW_STRING("get_string_config_array", "Exit");
+ return array;
+}
+
+/* Special function to free string config array */
+void free_string_config_array(char **str_config)
+{
+ TRACE_FLOW_STRING("free_string_config_array", "Entry");
+
+ if(str_config != NULL) {
+ if(*str_config !=NULL) free(*str_config);
+ free(str_config);
+ }
+
+ TRACE_FLOW_STRING("free_string_config_array", "Exit");
+}
+
+/* Get an array of long values */
+long *get_long_config_array(struct collection_item *item, int *size, int *error)
+{
+ char *endptr, *str;
+ long val = 0;
+ long *array;
+ int count = 0;
+
+ TRACE_FLOW_STRING("get_long_config_array", "Entry");
+
+ /* Do we have the item ? */
+ if((item == (struct collection_item *)(NULL)) ||
+ (get_item_type(item) != COL_TYPE_STRING) ||
+ (size == (int *)(NULL))) {
+ TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+ if(error) *error = EINVAL;
+ return (long *)(NULL);
+ }
+
+ /* Assume that we have maximum number of different numbers */
+ array = (long *)malloc(sizeof(long) * get_item_length(item)/2);
+ if(array == NULL) {
+ TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+ if(error) *error = ENOMEM;
+ return (long *)(NULL);
+ }
+
+ /* Now parse the string */
+ str = (char *)(get_item_data(item));
+ while(*str != '\0') {
+ errno = 0;
+ val = strtol(str, &endptr, 10);
+ if (((errno == ERANGE) &&
+ ((val == LONG_MAX) ||
+ (val == LONG_MIN))) ||
+ ((errno != 0) && (val == 0)) ||
+ (endptr == str)) {
+ TRACE_ERROR_NUMBER("Conversion failed", EIO);
+ free(array);
+ if(error) *error = EIO;
+ return (long *)(NULL);
+ }
+ /* Save value */
+ *(array + count) = val;
+ count++;
+ /* Are we done? */
+ if(*endptr == 0) break;
+ /* Advance to the next valid number */
+ str = endptr;
+ while(!isdigit(*str) && (*str != 0) && (*str != '-') && (*str != '+')) str++;
+ }
+
+ *size = count;
+ if(error) *error = EOK;
+
+ TRACE_FLOW_NUMBER("get_long_config_value returning", val);
+ return array;
+
+}
+
+/* Special function to free long config array */
+inline void free_long_config_array(long *array)
+{
+ if(array != (long *)(NULL)) free(array);
+}
+
diff --git a/common/ini/ini_config.h b/common/ini/ini_config.h
new file mode 100644
index 00000000..8bf7373b
--- /dev/null
+++ b/common/ini/ini_config.h
@@ -0,0 +1,160 @@
+/*
+ INI LIBRARY
+
+ Header file for reading configuration from INI file
+ and storing as a collection.
+
+ Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+ INI Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ INI Library 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with INI Library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INI_CONFIG_H
+#define INI_CONFIG_H
+
+#include <limits.h>
+#include "collection.h"
+
+/* Name of the default (missing section in the INI file */
+#define INI_DEFAULT_SECTION "default"
+
+/* Collection classes used in INI processing */
+#define COL_CLASS_INI_BASE 20000
+#define COL_CLASS_INI_CONFIG COL_CLASS_INI_BASE + 0 /* Class for configuration collection. Implies a collection of sections */
+#define COL_CLASS_INI_SECTION COL_CLASS_INI_BASE + 1 /* A one level collection of key value pairs where values are always stings */
+#define COL_CLASS_INI_PERROR COL_CLASS_INI_BASE + 2 /* A one level collection of parse errors - store parse_error structs */
+#define COL_CLASS_INI_PESET COL_CLASS_INI_BASE + 3 /* A one level collection of parse error collections */
+
+
+/* Error levels */
+#define INI_STOP_ON_ANY 0 /* Fail if any problem is detected */
+#define INI_STOP_ON_NONE 1 /* Best effort - do not fail */
+#define INI_STOP_ON_ERROR 2 /* Fail on errors only */
+
+
+/* Parsing errors and warnings */
+#define ERR_LONGDATA 1 /* Error */
+#define ERR_NOCLOSESEC 2 /* Error */
+#define ERR_NOSECTION 3 /* Error */
+#define ERR_SECTIONLONG 4 /* Error */
+#define ERR_NOEQUAL 5 /* Warning */
+#define ERR_NOKEY 6 /* Warning */
+#define ERR_LONGKEY 7 /* Warning */
+
+#define ERR_MAXPARSE ERR_LONGKEY
+
+#ifdef HAVE_INI_BEST_EFFORT /* Ignore bad lines in the INI files */
+#define RET_BEST_EFFORT RET_INVALID
+#else
+#define RET_BEST_EFFORT RET_ERROR
+#endif
+
+/* Internal sizes */
+/* FIXME - make them configurable via config.h */
+#define MAX_KEY 1024
+#define MAX_VALUE PATH_MAX
+#define BUFFER_SIZE MAX_KEY + MAX_VALUE + 3
+
+struct parse_error {
+ unsigned line;
+ int error;
+};
+
+/* Function to return parsing error */
+const char *parsing_error_str(int parsing_error);
+
+/* Read configuration information from a file */
+int config_from_file(const char *application, /* Name of the application - will be used as name of the collection */
+ const char *config_file, /* Name of the config file - if NULL the collection will be empty */
+ struct collection_item **ini_config, /* If *ini_config is NULL a new ini object will be allocated, */
+ /* otherwise the one that is pointed to will be updated. */
+ int error_level, /* Error level - break for erros, warnings or best effort (don't break) */
+ struct collection_item **error_list); /* List of errors for a file */
+
+
+/* Read default config file and then overwrite it with a specific one from the directory */
+int config_for_app(const char *application, /* Name of the application that will be used to get config for */
+ const char *config_file, /* Name of the configuration file with default settings for all apps */
+ const char *config_dir, /* Name of the directory where the configuration files for different apps will be dropped */
+ struct collection_item **ini_config, /* New config object */
+ int error_level, /* Level of error tolerance */
+ struct collection_item **error_set); /* Collection of collections of parsing errors */
+
+/* Print errors and warnings that were detected while parsing one file */
+/* Use this function to print results of the config_from_file() call */
+void print_file_parsing_errors(FILE *file, /* File to send errors to */
+ struct collection_item *error_list); /* List of parsing errors */
+
+/* Print errors and warnings that were detected parsing configuration as a whole */
+/* Use this function to print results of the config_for_app() call */
+void print_config_parsing_errors(FILE *file, /* File to send errors to */
+ struct collection_item *error_list); /* Collection of collections of errors */
+
+/* Get a configuration item form the configuration */
+int get_config_item(const char *section, /* Section. If NULL assumed default */
+ const char *name, /* Name of the property to look up */
+ struct collection_item *ini_config, /* Collection to search */
+ struct collection_item **item); /* Item returned. Will be NULL is not found. /
+
+/* Convertion functions for the configuration item.
+ * Sets error to EINVAL if the item is bad.
+ * Sets error to EIO if the conversion failed.
+ * These functions do not allocate memory.
+ * They always return best effort conversion value.
+ * In case of error they return provided default.
+ * It is up to the caller to check an error and take an action.
+ */
+/* If "strict" parameter is non zero the function will fail if there are more
+ * characters after last digit.
+ */
+int get_int_config_value(struct collection_item *item, int strict, int def, int *error);
+long get_long_config_value(struct collection_item *item, int strict, long def, int *error);
+unsigned get_unsigned_config_value(struct collection_item *item, int strict, unsigned def, int *error);
+unsigned long get_ulong_config_value(struct collection_item *item, int strict, unsigned long def, int *error);
+double get_double_config_value(struct collection_item *item, int strict, double def, int *error);
+unsigned char get_bool_config_value(struct collection_item *item, unsigned char def, int *error);
+
+/* Function get_string_config_value returns pointer to the string out of item.
+ * If 'dup' is not 0 it makes a copyof the string otherwise it does not.
+ */
+char *get_string_config_value(struct collection_item *item, int dup, int *error);
+
+/* A get_bin_value and get_xxx_array functions allocate memory.
+ * It is the responsibility of the caller to free it after use.
+ * free_xxx conviniece wrappers are provided for this purpose.
+ * Functions will return NULL if conversion failed.
+ */
+/* A special hex format is assumed.
+ * The string should be taken in single quotes
+ * and consist of hex encoded value two hex digits per byte.
+ * Example: '0A2BFECC'
+ * Case does not matter.
+ */
+char *get_bin_config_value(struct collection_item *item, int *length, int *error);
+void free_bin_config_value(char *);
+
+/* Array of stings */
+/* Separator sting includes up to three different separators. If NULL comma is assumed. */
+/* The spaces are trimmed automatically around separators in the string. */
+char **get_string_config_array(struct collection_item *item, char *sep, int *size, int *error);
+/* Array of long values - separators are detected automatically. */
+/* The length of the allocated array is returned in "size" */
+long *get_long_config_array(struct collection_item *item, int *size, int *error);
+
+/* Special function to free string config array */
+void free_string_config_array(char **str_config);
+/* Special function to free long config array */
+void free_long_config_array(long *array);
+
+#endif
diff --git a/common/ini/ini_config_ut.c b/common/ini/ini_config_ut.c
new file mode 100644
index 00000000..2bb5517d
--- /dev/null
+++ b/common/ini/ini_config_ut.c
@@ -0,0 +1,701 @@
+/*
+ INI LIBRARY
+
+ Unit test for the INI library.
+
+ Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+ INI Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ INI Library 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with INI Library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#define TRACE_HOME
+#include "ini_config.h"
+#include "collection.h"
+#include "collection_tools.h"
+
+
+int basic_test()
+{
+ int error;
+ struct collection_item *ini_config = (struct collection_item *)(NULL);
+ struct collection_item *error_set = (struct collection_item *)(NULL);
+
+ error = config_for_app("test", "./ini/ini.conf", "./ini/ini.d", &ini_config,INI_STOP_ON_NONE,&error_set);
+ if(error) {
+ printf("Attempt to read configuration returned error: %d\n",error);
+ return error;
+ }
+
+ debug_collection(ini_config,COL_TRAVERSE_DEFAULT);
+ print_collection(ini_config);
+ print_collection(error_set);
+
+ printf("\n\n----------------------\n");
+ /* Output parsing errors (if any) */
+ print_config_parsing_errors(stdout,error_set);
+ printf("----------------------\n\n\n");
+
+
+ destroy_collection(ini_config);
+ destroy_collection(error_set);
+ return 0;
+}
+
+int single_file()
+{
+ int error;
+ struct collection_item *ini_config = (struct collection_item *)(NULL);
+ struct collection_item *error_set = (struct collection_item *)(NULL);
+
+ error = config_from_file("test", "./ini/ini.conf", &ini_config,INI_STOP_ON_NONE,&error_set);
+ if(error) {
+ printf("Attempt to read configuration returned error: %d\n",error);
+ return error;
+ }
+
+ debug_collection(ini_config,COL_TRAVERSE_DEFAULT);
+ print_collection(ini_config);
+ print_collection(error_set);
+
+ printf("\n\n----------------------\n");
+ /* Output parsing errors (if any) */
+ print_file_parsing_errors(stdout,error_set);
+ printf("----------------------\n\n\n");
+
+
+ destroy_collection(ini_config);
+ destroy_collection(error_set);
+ return 0;
+}
+
+int negative_test()
+{
+ int error;
+ int count;
+ struct collection_item *ini_config = (struct collection_item *)(NULL);
+ struct collection_item *error_set = (struct collection_item *)(NULL);
+
+ /* App name is null - expect failure */
+ error = config_for_app(NULL, NULL, NULL, NULL,INI_STOP_ON_NONE,NULL);
+ if(!error) {
+ printf("Expected error: %d got success\n",EINVAL);
+ return -1;
+ }
+
+ /* Config collection storage is NULL - expect failure */
+ error = config_for_app("real", NULL, NULL, NULL,INI_STOP_ON_NONE,NULL);
+ if(!error) {
+ printf("Expected error: %d got success\n",EINVAL);
+ return -1;
+ }
+
+ /* Config collection storage is NULL - expect failure */
+ error = config_for_app("real", "real.conf", NULL, NULL,INI_STOP_ON_NONE,NULL);
+ if(!error) {
+ printf("Expected error: %d got success\n",EINVAL);
+ return -1;
+ }
+
+ /* Expect success but empty config */
+ error = config_for_app("real", "real.conf", NULL, &ini_config,INI_STOP_ON_NONE,NULL);
+ if(error) {
+ printf("Expected success got error: %d\n",error);
+ return error;
+ }
+
+ count = 0;
+ (void)get_collection_count(ini_config,&count);
+ if(count > 1) {
+ printf("Expected empty collection but got contents with %d elements\n",count);
+ print_collection(ini_config);
+ return -1;
+ }
+
+ destroy_collection(ini_config);
+ return 0;
+
+}
+
+int real_test(const char *file)
+{
+ int error;
+ struct collection_item *ini_config = (struct collection_item *)(NULL);
+ struct collection_item *error_set = (struct collection_item *)(NULL);
+ struct collection_iterator *iterator = (struct collection_iterator *)(NULL);
+ struct collection_item *item = (struct collection_item *)(NULL);
+ int type;
+
+ printf("\n\n===== REAL TEST START ======\n");
+ printf("Reading collection\n");
+ error = config_for_app("real", file, "./ini/ini.d", &ini_config,INI_STOP_ON_NONE,&error_set);
+ if(error) {
+ printf("Attempt to read configuration returned error: %d\n",error);
+ return error;
+ }
+
+ printf("Debugging the config collection:\n");
+ debug_collection(ini_config,COL_TRAVERSE_DEFAULT);
+ printf("Debugging the error collection:\n");
+ debug_collection(error_set,COL_TRAVERSE_DEFAULT);
+
+ printf("About to print parsing errors:\n");
+ printf("\n\n----------------------\n");
+ /* Output parsing errors (if any) */
+ print_config_parsing_errors(stdout,error_set);
+ printf("----------------------\n\n\n");
+
+ printf("About to bind iterator to print the config file contents.\n");
+ /* Bind iterator */
+ error = bind_iterator(&iterator,ini_config,COL_TRAVERSE_DEFAULT|COL_TRAVERSE_END);
+ if(error) {
+ printf("Failed to bind iterator: %d\n",error);
+ destroy_collection(ini_config);
+ destroy_collection(error_set);
+ return error;
+ }
+
+ printf("About to start iteration loop.\n");
+ do {
+ /* Loop through a collection */
+ error = iterate_collection(iterator, &item);
+ if(error) {
+ printf("Error iterating collection: %d",error);
+ unbind_iterator(iterator);
+ return error;
+ }
+
+ /* Are we done ? */
+ if(item == (struct collection_item *)(NULL)) break;
+
+ type = get_item_type(item);
+
+ /* Start of the collection */
+ if(type == COL_TYPE_COLLECTION)
+ printf("Contents of the configuration for application %s\n",get_item_property(item,NULL));
+ /* End of section */
+ else if(type == COL_TYPE_END) printf("\n");
+ /* Section header ? */
+ else if(type == COL_TYPE_COLLECTIONREF) printf("[%s]\n",get_item_property(item,NULL));
+ /* Anything else - we know they are all strings*/
+ else printf("%s = %s\n",get_item_property(item,NULL), (char *)get_item_data(item));
+ }
+ while(1);
+
+ /* Do not forget to unbind iterator - otherwise there will be a leak */
+ printf("About to clean up.\n");
+ unbind_iterator(iterator);
+
+ destroy_collection(ini_config);
+ destroy_collection(error_set);
+ return 0;
+}
+
+int get_test()
+{
+
+ int error;
+ struct collection_item *ini_config = (struct collection_item *)(NULL);
+ struct collection_item *error_set = (struct collection_item *)(NULL);
+ struct collection_iterator *iterator = (struct collection_iterator *)(NULL);
+ struct collection_item *item = (struct collection_item *)(NULL);
+ int type;
+ int number;
+ long number_long;
+ double number_double;
+ unsigned number_unsigned;
+ unsigned long number_ulong;
+ unsigned char logical;
+ char *str;
+ void *binary;
+ int length;
+ int i;
+ char **strarray;
+ char **strptr;
+ int size;
+ long *array;
+
+ printf("\n\n===== GET TEST START ======\n");
+ printf("Reading collection\n");
+ error = config_for_app("real", NULL, "./ini/ini.d", &ini_config,INI_STOP_ON_NONE,&error_set);
+ if(error) {
+ printf("Attempt to read configuration returned error: %d\n",error);
+ return error;
+ }
+
+ printf("Debugging the config collection:\n");
+ debug_collection(ini_config,COL_TRAVERSE_DEFAULT);
+ printf("Debugging the error collection:\n");
+ debug_collection(error_set,COL_TRAVERSE_DEFAULT);
+ destroy_collection(error_set);
+
+ printf("Negtive test - trying to get non existing key-value pair.\n");
+
+ /* Negative test */
+ item = (struct collection_item *)(NULL);
+ error = get_config_item("monitor1","description1", ini_config, &item);
+ if(error) {
+ printf("Expected success but got error! %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Item should not be found */
+ if(item != (struct collection_item *)(NULL)) {
+ printf("Expected NULL but got something else!\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ /* Another negative test but section exists this time */
+ item = (struct collection_item *)(NULL);
+ error = get_config_item("monitor","description1", ini_config, &item);
+ if(error) {
+ printf("Expected success but got error! %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Item should not be found */
+ if(item != (struct collection_item *)(NULL)) {
+ printf("Expected NULL but got something else!\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ printf("Trying to get an item.\n");
+
+ /* Positive test */
+ item = (struct collection_item *)(NULL);
+ error = get_config_item("monitor","description", ini_config, &item);
+ if(error) {
+ printf("Expected success but got error! %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Item should be found */
+ if(item == (struct collection_item *)(NULL)) {
+ printf("Expected item but got something NULL!\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ debug_item(item);
+
+
+ printf("Get item as string without duplication from NULL item.\n");
+
+ /* Get a string without duplicication */
+ /* Negative test */
+ error = 0;
+ str = get_string_config_value(NULL, 0, &error);
+ if(!error) {
+ printf("Expected error got success.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ printf("Get item as string without duplication from correct item.\n");
+
+ /* Now get string from the right item */
+ error = 0;
+ str = get_string_config_value(item, 0, &error);
+ if(error) {
+ printf("Expected success got error %d.\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ printf("Value: [%s]\n",str);
+
+ /* Same thing but create a dup */
+
+ printf("Get item as string with duplication from correct item.\n");
+
+ error = 0;
+ str = get_string_config_value(item, 1, &error);
+ if(error) {
+ printf("Expected success got error %d.\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ printf("Value: [%s]\n",str);
+ free(str);
+
+
+ /* Get a badly formated number */
+ printf("Convert item to number with strict conversion.\n");
+
+ item = (struct collection_item *)(NULL);
+ error = get_config_item("monitor","bad_number", ini_config, &item);
+ if(error) {
+ printf("Expected success but got error! %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Item should be found */
+ if(item == (struct collection_item *)(NULL)) {
+ printf("Expected item but got something NULL!\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ debug_item(item);
+
+
+ /* Now try to get value in different ways */
+ error = 0;
+ number = get_int_config_value(item, 1, 10, &error);
+ if(error) {
+ /* We expected error in this case */
+ printf("Expected error.\n");
+ if(number != 10) {
+ printf("It failed to set default value.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+ }
+
+ printf("Convert item to number without strict conversion.\n");
+
+ error = 0;
+ number = 1;
+ number = get_int_config_value(item, 0, 10, &error);
+ if(error) {
+ /* We expected error in this case */
+ printf("Did not expect error.\n");
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ if(number != 5) {
+ /* We expected error in this case */
+ printf("We expected that the conversion will return 5.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+
+
+ /* Get real integer */
+
+ printf("Fetch another item from section \"domains/LOCAL\" named \"enumerate\".\n");
+
+ item = (struct collection_item *)(NULL);
+ error = get_config_item("domains/LOCAL","enumerate", ini_config, &item);
+ if(error) {
+ printf("Expected success but got error! %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Item should be found */
+ if(item == (struct collection_item *)(NULL)) {
+ printf("Expected success but got NULL.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ printf("Convert item to integer.\n");
+
+ /* Take number out of it */
+ error = 0;
+ number = get_int_config_value(item, 1, 100, &error);
+ if(error) {
+ printf("Did not expect error. Got %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* It is 3 in the file */
+ if(number != 3) {
+ printf("We expected that the conversion will return 3.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ printf("Expected 3 got %d\n", number);
+
+ printf("Convert item to long.\n");
+
+ /* Take number out of it */
+ error = 0;
+ number_long = get_long_config_value(item, 1, 100, &error);
+ if(error) {
+ printf("Did not expect error. Got %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* It is 3 in the file */
+ if(number_long != 3) {
+ printf("We expected that the conversion will return 3.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ printf("Expected 3 got %d\n", number_long);
+
+ printf("Convert item to unsigned.\n");
+
+ /* Take number out of it */
+ error = 0;
+ number_unsigned = get_unsigned_config_value(item, 1, 100, &error);
+ if(error) {
+ printf("Did not expect error. Got %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* It is 3 in the file */
+ if(number_unsigned != 3) {
+ printf("We expected that the conversion will return 3.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ printf("Expected 3 got %d\n", number_unsigned);
+
+ printf("Convert item to unsigned long.\n");
+
+ /* Take number out of it */
+ error = 0;
+ number_ulong = get_ulong_config_value(item, 1, 100, &error);
+ if(error) {
+ printf("Did not expect error. Got %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* It is 3 in the file */
+ if(number_ulong != 3) {
+ printf("We expected that the conversion will return 3.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ printf("Expected 3 got %d\n", number_ulong);
+
+ printf("Convert item to double.\n");
+
+ /* Take number out of it */
+ error = 0;
+ number_double = get_double_config_value(item, 1, 100., &error);
+ if(error) {
+ printf("Did not expect error. Got %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* It is 3 in the file */
+ if(number_double != 3.) {
+ printf("We expected that the conversion will return 3.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ printf("Expected 3 got %d\n", number_double);
+
+ printf("Convert item to bool.\n");
+
+ /* Take number out of it */
+ error = 0;
+ logical = get_bool_config_value(item, 1, &error);
+ if(!error) {
+ printf("Expect error. Got success.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ /* Get real bool item and convert it */
+ printf("Get real bool item \"legacy\" and convert it.\n");
+
+ item = (struct collection_item *)(NULL);
+ error = get_config_item("domains/LOCAL","legacy", ini_config, &item);
+ if(error) {
+ printf("Expected success but got error! %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Item should be found */
+ if(item == (struct collection_item *)(NULL)) {
+ printf("Expected success but got NULL.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ printf("Convert item to bool.\n");
+
+ error = 0;
+ logical = get_bool_config_value(item, 1, &error);
+ if(error) {
+ printf("Expect success got error %d.\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ if(logical) {
+ printf("Expected false but got true - bad.\n");
+ return -1;
+ }
+
+ printf("In the files it is FALSE so we got false.\n");
+
+ printf("Get binary item\n");
+
+ item = (struct collection_item *)(NULL);
+ error = get_config_item("domains/EXAMPLE.COM","binary_test", ini_config, &item);
+ if(error) {
+ printf("Expected success but got error! %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Item should be found */
+ if(item == (struct collection_item *)(NULL)) {
+ printf("Expected success but got NULL.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ debug_item(item);
+
+ error = 0;
+ binary = get_bin_config_value(item, &length, &error);
+ if(error) {
+ printf("Expect success got error %d.\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ printf("Binary value (expect 123) = ");
+ for(i=0;i<length;i++) {
+ printf("%d",*((unsigned char*)(binary)+i));
+ }
+ printf("\n");
+
+ free_bin_config_value(binary);
+
+ printf("Get string array item\n");
+
+ item = (struct collection_item *)(NULL);
+ error = get_config_item("domains","domainsorder", ini_config, &item);
+ if(error) {
+ printf("Expected success but got error! %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Item should be found */
+ if(item == (struct collection_item *)(NULL)) {
+ printf("Expected success but got NULL.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ debug_item(item);
+
+ printf("Get str array without size.\n");
+
+ error = 0;
+ strarray = get_string_config_array(item, ",", NULL, &error);
+ if(error) {
+ printf("Expect success got error %d.\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Can be used with this cycle */
+ strptr = strarray;
+ while(*strptr != NULL) {
+ printf("[%s]\n",*strptr);
+ strptr++;
+ }
+
+ free_string_config_array(strarray);
+
+ printf("Get str array with size.\n");
+
+ error = 0;
+ size = 0;
+ strarray = get_string_config_array(item, ",", &size, &error);
+ if(error) {
+ printf("Expect success got error %d.\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Can be used with this cycle */
+ for(i=0;i<size;i++) printf("[%s]\n",*(strarray + i));
+
+ free_string_config_array(strarray);
+
+ printf("Get long array item\n");
+
+ item = (struct collection_item *)(NULL);
+ error = get_config_item("domains/EXAMPLE.COM","long_array", ini_config, &item);
+ if(error) {
+ printf("Expected success but got error! %d\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Item should be found */
+ if(item == (struct collection_item *)(NULL)) {
+ printf("Expected success but got NULL.\n");
+ destroy_collection(ini_config);
+ return -1;
+ }
+
+ debug_item(item);
+
+ error = 0;
+ size = 0; /* Here size is not optional!!! */
+ array = get_long_config_array(item, &size, &error);
+ if(error) {
+ printf("Expect success got error %d.\n",error);
+ destroy_collection(ini_config);
+ return error;
+ }
+
+ /* Can be used with this cycle */
+ for(i=0;i<size;i++) printf("%d\n",*(array + i));
+
+ free_long_config_array(array);
+
+ printf("Done with get test!\n");
+ return EOK;
+}
+
+int main()
+{
+ int error;
+
+ if((error=basic_test()) ||
+ (error=single_file()) ||
+ (error=real_test(NULL)) ||
+ /* This should result in merged configuration */
+ (error=real_test("./ini/ini.conf")) ||
+ (error= get_test())) {
+ printf("Test failed! Error %d.\n",error);
+ return -1;
+ }
+ printf("Success!\n");
+ return 0;
+}