Add class configuration
authorArjen Baart <arjen@andromeda.nl>
Sun, 9 Feb 2020 10:02:12 +0000 (11:02 +0100)
committerArjen Baart <arjen@andromeda.nl>
Sun, 9 Feb 2020 10:02:12 +0000 (11:02 +0100)
17 files changed:
ChangeLog
TODO
config.h.in
configure.ac
src/Integer.cpp
src/Makefile.am
src/configuration.cpp [new file with mode: 0644]
src/configuration.h [new file with mode: 0644]
src/date.cpp
src/hour.cpp
src/regex.cpp
test/ACL.conf [new file with mode: 0644]
test/ACL_wrong.conf [new file with mode: 0644]
test/Makefile.am
test/configuration_find.cpp [new file with mode: 0644]
test/configuration_read.cpp [new file with mode: 0644]
test/configuration_read.exp [new file with mode: 0644]

index 169770f..fb8153d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,8 @@
   - Add parameter bool localtime to now() and today()
   - String: Boundary checking on index and subtring operators
   - Ported class Integer from the Gnu libg++ library.
+  - Added date::Weekday()
+  - Added class configration
 
 Oct 31, 2019 - Release 0.2
 ============================
diff --git a/TODO b/TODO
index 42de7cc..ce2e1d5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -7,6 +7,7 @@ Things to do:
 - String: format operator % like in python
 - String: split and join
 - String: assign fstream objects to read and write a file
+- regex:  throw an exception when contructing a regex returns an error
 
 - date: test parser for invalid dates and syntax errors
 - date: Parser for stream input
index 3ab1027..31bc546 100644 (file)
@@ -24,6 +24,9 @@
 /* Define to 1 if you have the <libintl.h> header file. */
 #undef HAVE_LIBINTL_H
 
+/* Define to 1 if you have the `xml2' library (-lxml2). */
+#undef HAVE_LIBXML2
+
 /* Define to 1 if your system has a GNU libc compatible `malloc' function, and
    to 0 otherwise. */
 #undef HAVE_MALLOC
index 1d282cb..19c4c15 100644 (file)
@@ -17,10 +17,24 @@ AM_PROG_AR
 
 # Checks for libraries.
 
+AC_PATH_PROG(XML_CONFIG,xml2-config,no)
+
+if test $XML_CONFIG = "no" 
+then
+   echo "XML library not found (see http://xmlsoft.org/)."
+   exit 1;
+fi
+
+XML_CFLAGS=`$XML_CONFIG --cflags`
+XML_LFLAGS=`$XML_CONFIG --libs`
+AC_CHECK_LIB(xml2, xmlParseFile)
+
 # Checks for header files.
 AC_FUNC_ALLOCA
 AC_CHECK_HEADERS([libintl.h malloc.h stddef.h stdlib.h string.h])
 
+CXXFLAGS="$CXXFLAGS $X_CFLAGS $XML_CFLAGS -Wall"
+LDFLAGS="$LDFLAGS $XML_LFLAGS"
 # Checks for typedefs, structures, and compiler characteristics.
 AC_CHECK_HEADER_STDBOOL
 AC_TYPE_SIZE_T
index 57de7d2..e116478 100644 (file)
@@ -2257,7 +2257,6 @@ char*  cvtItoa(const IntRep* x, char* fmt, int& fmtlen, int base, int showbase,
   else
   {
     char* p = fmt;
-    int gap = s - p;
     for (char* t = s; *t != 0; ++t, ++p) *p = *t;
     while (w++ < width) *p++ = fillchar;
     *p = 0;
index fc7abab..a52770b 100644 (file)
@@ -2,8 +2,9 @@ lib_LTLIBRARIES = libACL.la
 
 libACL_la_SOURCES = string.cpp regex.cpp date.cpp parsedate.c dateyacc.y datelex.c \
                     hour.cpp utc.cpp \
-                    Integer.cpp
+                    Integer.cpp \
+                    configuration.cpp
 
 libACL_la_LDFLAGS = -version-info 2:2:0
 
-include_HEADERS = String.h date.h Integer.h
+include_HEADERS = String.h date.h Integer.h configuration.h
diff --git a/src/configuration.cpp b/src/configuration.cpp
new file mode 100644 (file)
index 0000000..cbd2745
--- /dev/null
@@ -0,0 +1,252 @@
+
+/**************************************************************************
+**  (c) Copyright 2002, Andromeda Technology & Automation
+***************************************************************************
+** MODULE INFORMATION *
+***********************
+**      FILE NAME      : configuration.cpp
+**      SYSTEM NAME    : AXE - Andromeda X-windows Encapsulation
+**      VERSION NUMBER : $Revision: 1.6 $
+**
+**  DESCRIPTION      :  Implementation of configuration class
+**
+**  EXPORTED OBJECTS : 
+**  LOCAL    OBJECTS : 
+**  MODULES  USED    :
+***************************************************************************
+**  ADMINISTRATIVE INFORMATION *
+********************************
+**      ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
+**      CREATION DATE   : Jul 23, 2002
+**      LAST UPDATE     : Apr 13, 2007
+**      MODIFICATIONS   : 
+**************************************************************************/
+
+/*****************************
+   $Log: configuration.cpp,v $
+   Revision 1.6  2007-05-04 14:01:22  arjen
+   Added new arguments to configuration::find_parameter() to allow for a list of
+   sections and a list of parameters in sections.
+   The new arguments are section index and parameter index (default = 0).
+
+   Revision 1.5  2003/03/29 07:19:37  arjen
+   Bugfix: Do not read the config file in the home
+   directory if the HOME environment variable doesn't exist
+
+   Revision 1.4  2002/11/23 12:48:18  arjen
+   Check if a configuration file exists before feeding it to the XML parser.
+
+   Revision 1.3  2002/11/02 14:35:15  arjen
+   Uses the XML2 library
+   BugFix: segfault when finding a parameters that is not in the user-sepcific
+   config tree.
+
+   Revision 1.2  2002/09/28 06:48:46  arjen
+   Bugfix: In configuration::find_parameter(), check if the parameter node exists
+   before retrieving its contents.
+
+   Revision 1.1  2002/07/25 08:01:26  arjen
+   First checkin, AXE release 0.2
+
+*****************************/
+
+#include <fcntl.h>
+#include <unistd.h>
+#include "configuration.h"
+
+
+/*=========================================================================
+**  NAME           : configuration::read
+**  SYNOPSIS       :
+**  PARAMETERS     :
+**  RETURN VALUE   : true if any config files were found
+**
+**  DESCRIPTION    : 
+**
+**  VARS USED      :
+**  VARS CHANGED   :
+**  FUNCTIONS USED :
+**  SEE ALSO       :
+**  LAST MODIFIED  : Nov 22, 2002
+**=========================================================================
+*/
+
+bool configuration::read(const String name)
+{
+   String     filename;
+
+   app_name   = name;
+
+   //   Try to read the config files.
+   //   Two configuarions are read. The system and the user config.
+   //   First system config in /etc and if it does not exist, in /usr/local/etc
+   filename = "/etc/" + name + ".conf";
+   //  Check if we can read the file.
+
+   int fd = open(filename, O_RDONLY);
+   if (fd < 0)
+   {
+      filename = "/usr/local/etc/" + name + ".conf";
+      fd = open(filename, O_RDONLY);
+   }
+
+   if (fd > 0)
+   {
+      close(fd);
+      system = xmlParseFile(filename);
+   }
+
+   //  The user config is read from the current directory.
+   //  If that does not exist, try the home directory.
+
+   filename = name + ".conf";
+   fd = open(filename, O_RDONLY);
+   if (fd < 0)
+   {
+      if (getenv("HOME") != NULL)
+      {
+         filename = getenv("HOME");
+         filename += "/.";
+         filename += name + ".conf";
+         fd = open(filename, O_RDONLY);
+      }
+   }
+   if (fd > 0)
+   {
+      close(fd);
+      user = xmlParseFile(filename);
+   }
+
+   //  Check the root element, which must be the application name
+
+   xmlNodePtr   root;
+
+   if (system != NULL)
+   {
+      root = xmlDocGetRootElement(system);
+      if (app_name != (const char *)root->name)
+      {
+         std::cerr << "Wrong config file.\n";
+         xmlFreeDoc(system);
+         system = NULL;
+      }
+   }
+
+   if (user != NULL)
+   {
+      root = xmlDocGetRootElement(user);
+      if (app_name != (const char *)root->name)
+      {
+         std::cerr << "Wrong config file.\n";
+         xmlFreeDoc(user);
+         user = NULL;
+      }
+   }
+
+   return system != NULL || user != NULL;
+}
+
+/*=========================================================================
+**  NAME           : configuration::xmlFindTag
+**  SYNOPSIS       :
+**  PARAMETERS     :
+**  RETURN VALUE   : Pointer to the XML element or NULL
+**
+**  DESCRIPTION    : 
+**
+**  VARS USED      :
+**  VARS CHANGED   :
+**  FUNCTIONS USED :
+**  SEE ALSO       :
+**  LAST MODIFIED  : Apr 13, 2007
+**=========================================================================
+*/
+
+xmlNodePtr configuration::xmlFindTag(xmlNodePtr node, const String tag, int n)
+{
+   xmlNodePtr   element = NULL;
+
+   while (element == NULL && node != NULL)
+   {
+      if (node->type == XML_ELEMENT_NODE && tag == (char *)node->name)
+      {
+         if (n == 0)
+         {
+            element = node;
+         }
+         n--;
+      }
+      node = node->next;
+   }
+
+   return element;
+}
+
+/*=========================================================================
+**  NAME           : configuration::find_parameter
+**  SYNOPSIS       :
+**  PARAMETERS     :
+**  RETURN VALUE   : The content of the parameter or an empty string
+**
+**  DESCRIPTION    : 
+**
+**  VARS USED      :
+**  VARS CHANGED   :
+**  FUNCTIONS USED :
+**  SEE ALSO       :
+**  LAST MODIFIED  : Apr 13, 2007
+**=========================================================================
+*/
+
+String configuration::find_parameter(const String section, const String parameter, int sec_n, int param_n)
+{
+   xmlNodePtr     root_node;
+   xmlNodePtr     section_node;
+   xmlNodePtr     param_node;
+
+   String         param_value("");
+
+   //  First, we try to find the parameter in the system-wide config
+
+   if (system)
+   {
+      root_node    = xmlDocGetRootElement(system);
+      section_node = xmlFindTag(root_node->children, section, sec_n);
+      if (section_node != NULL)
+      {
+         param_node = xmlFindTag(section_node->children, parameter, param_n);
+         if (param_node != NULL)
+         {
+            param_node = param_node->children;
+         }
+         if (param_node != NULL)
+         {
+            param_value = (char *)param_node->content;
+         }
+      }
+   }
+
+   //  If the parameter is also defined in the user config, it will override
+   //  the system-wide value.
+
+   if (user)
+   {
+      root_node    = xmlDocGetRootElement(user);
+      section_node = xmlFindTag(root_node->children, section, sec_n);
+      if (section_node != NULL)
+      {
+         param_node = xmlFindTag(section_node->children, parameter, param_n);
+         if (param_node != NULL)
+         {
+            param_node = param_node->children;
+         }
+         if (param_node != NULL)
+         {
+            param_value = (char *)param_node->content;
+         }
+      }
+   }
+
+   return param_value;
+}
diff --git a/src/configuration.h b/src/configuration.h
new file mode 100644 (file)
index 0000000..c894a43
--- /dev/null
@@ -0,0 +1,107 @@
+/**************************************************************************
+**  (c) Copyright 2002, Andromeda Technology & Automation
+***************************************************************************
+** MODULE INFORMATION *
+***********************
+**      FILE NAME      : configuration.h
+**      SYSTEM NAME    : AXE - Andromeda X-windows Encapsulation
+**      VERSION NUMBER : $Revision: 1.4 $
+**
+**  DESCRIPTION      : Definition of configuration class 
+**
+**  EXPORTED OBJECTS : class configuration
+**  LOCAL    OBJECTS : 
+**  MODULES  USED    : String
+***************************************************************************
+**  ADMINISTRATIVE INFORMATION *
+********************************
+**      ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
+**      CREATION DATE   : Nov 02, 2002
+**      LAST UPDATE     : 
+**      MODIFICATIONS   : 
+**************************************************************************/
+
+/*****************************
+   $Log: configuration.h,v $
+   Revision 1.4  2007-05-04 14:01:22  arjen
+   Added new arguments to configuration::find_parameter() to allow for a list of
+   sections and a list of parameters in sections.
+   The new arguments are section index and parameter index (default = 0).
+
+   Revision 1.3  2002/11/02 14:35:15  arjen
+   Uses the XML2 library
+   BugFix: segfault when finding a parameters that is not in the user-sepcific
+   config tree.
+
+   Revision 1.2  2002/09/02 06:18:20  arjen
+   Fixed some date and time conversion functions
+
+   Revision 1.1  2002/07/25 08:01:26  arjen
+   First checkin, AXE release 0.2
+
+*****************************/
+
+/* static const char *RCSID = "$Id: configuration.h,v 1.4 2007-05-04 14:01:22 arjen Exp $"; */
+
+#ifndef CONFIGURATION_H
+#define CONFIGURATION_H
+
+#include <libxml/parser.h>   // usually in /usr/include/libxml2, see xml2-config
+
+#include "String.h"
+
+/*
+///////////////////////////////////////////////////////////////////////////
+//  NAME           : configuration
+//  BASECLASS      :
+//  MEMBERS        : 
+//  OPERATORS      :
+//  METHODS        : read
+//                   find_parameter
+//
+//  DESCRIPTION    : Handle configurational parameters for the application.
+//                   Many applications need some permanently stored configurational
+//                   data. The information is usually stored in two places: A system-
+//                   wide configuration file and a configuration file per user.
+//                   The content of the configuration file is in XML format.
+//                   The configuration base class takes care of finding the configuration
+//                   files, e.g. in /etc/app.conf or in /usr/local/etc/app.conf, along
+//                   with the configuration file in the user's home directory.
+//                   The config files are parsed with the gnome XML parser and a
+//                   framework is provided to find configurational items.
+//
+//  RELATIONS      : 
+//  SEE ALSO       :
+//  LAST MODIFIED  : Apr 13, 2007
+///////////////////////////////////////////////////////////////////////////
+*/
+
+class configuration
+{
+
+   xmlDocPtr     system;   // The system-wide config tree
+   xmlDocPtr     user;     // User-specific config tree
+   String        app_name; // Name of the application and XML root element
+
+   xmlNodePtr    xmlFindTag(xmlNodePtr, const String, int n = 0);
+
+public:
+
+   configuration()
+   {
+      system  = NULL;
+      user    = NULL;
+      app_name = "ACL";
+   }
+
+   //  Find the config files and parse the XML
+
+   bool read(const String name);
+
+   //  Return the value of a config parameter
+
+   String find_parameter(const String section, const String parameter, int sec_n = 0, int param_n = 0);
+
+};
+
+#endif // CONFIGURATION_H
index f9dd5ac..d988778 100644 (file)
@@ -41,8 +41,6 @@
 
 *****************************/
 
-static const char *RCSID = "$Id: date.cpp,v 1.3 2002-09-28 06:58:45 arjen Exp $";
-
 #include <iostream> 
 #include <time.h>
 #include "date.h"
index 7c762b5..eb1741e 100644 (file)
@@ -41,8 +41,6 @@
 
 *****************************/
 
-static const char *RCSID = "$Id: hour.cpp,v 1.3 2002-09-28 06:58:45 arjen Exp $";
-
 #include <time.h>
 
 #include "date.h"
index 2ec3132..ae4de84 100644 (file)
@@ -35,8 +35,6 @@
 
 *****************************/
 
-static const char RCSID[] = "$Id: regex.cpp,v 1.3 2007/05/04 13:56:05 arjen Exp $";
-
 #include <stdio.h>
 #include <ctype.h>
 #include "String.h"
@@ -47,18 +45,24 @@ regex::regex(const String &reg)
 {
    original = reg;
    int error = regcomp (&expression, reg.p->s, REG_EXTENDED);
+
+   //TODO: Handle error
 }
 
 regex::regex(const char *reg)
 {
    original = reg;
    int error = regcomp (&expression, reg, REG_EXTENDED);
+
+   //TODO: Handle error
 }
 
 regex::regex(const regex & reg)
 {
    original = reg.original;
    int error = regcomp (&expression, reg.original, REG_EXTENDED);
+
+   //TODO: Handle error
 }
 
 regex::~regex()
diff --git a/test/ACL.conf b/test/ACL.conf
new file mode 100644 (file)
index 0000000..d2a3aa8
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version='1.0'?>
+<ACL version='0.2.0'>
+   <section>
+      <parameter>Test1</parameter>
+   </section>
+</ACL>
+
diff --git a/test/ACL_wrong.conf b/test/ACL_wrong.conf
new file mode 100644 (file)
index 0000000..d2a3aa8
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version='1.0'?>
+<ACL version='0.2.0'>
+   <section>
+      <parameter>Test1</parameter>
+   </section>
+</ACL>
+
index 7a33525..cb977a1 100644 (file)
@@ -6,7 +6,8 @@ check_PROGRAMS = string_assign string_basics string_compare string_cat string_su
                  date_assign date_parse date_compare date_arithmetic date_attributes date_check_today \
                  hour_assign hour_parse hour_compare hour_arithmetic hour_check_now \
                  utc_assign utc_compare utc_arithmetic \
-                 integer_assign integer_factorial integer_fibonacci integer_pow64 integer_modulo
+                 integer_assign integer_factorial integer_fibonacci integer_pow64 integer_modulo \
+                 configuration_read configuration_find
 
 string_assign_SOURCES      = string_assign.cpp
 string_basics_SOURCES      = string_basics.cpp
@@ -41,3 +42,6 @@ integer_factorial_SOURCES  = integer_factorial.cpp tInteger.cpp
 integer_fibonacci_SOURCES  = integer_fibonacci.cpp tInteger.cpp
 integer_pow64_SOURCES      = integer_pow64.cpp tInteger.cpp
 integer_modulo_SOURCES     = integer_modulo.cpp tInteger.cpp
+
+configuration_read_SOURCES = configuration_read.cpp
+configuration_find_SOURCES = configuration_find.cpp
diff --git a/test/configuration_find.cpp b/test/configuration_find.cpp
new file mode 100644 (file)
index 0000000..beb1647
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************
+ *  Unit test for the configuration class
+ *
+ * test finding configuration parameters
+ ******************************************************
+ *
+ */
+
+#include "configuration.h"
+#include <assert.h>
+
+int main()
+{
+   configuration  config1;
+   bool           result;
+   String         value;
+
+   result = config1.read("ACL");
+   assert(result == true);
+
+   value = config1.find_parameter("section", "parameter");
+   assert(value == "Test1");
+
+   // Wrong parameter
+   value = config1.find_parameter("section", "not_exist");
+   assert(value == "");
+
+   // Wrong section
+   value = config1.find_parameter("not_exist", "parameter");
+   assert(value == "");
+
+   return 0;
+}
+
diff --git a/test/configuration_read.cpp b/test/configuration_read.cpp
new file mode 100644 (file)
index 0000000..974a804
--- /dev/null
@@ -0,0 +1,28 @@
+/*******************************************************
+ *  Unit test for the configuration class
+ *
+ * test reading the configuration file
+ ******************************************************
+ *
+ */
+
+#include "configuration.h"
+#include <assert.h>
+
+int main()
+{
+   configuration  config1;
+   bool           result;
+
+   result = config1.read("ACL_not_exist");
+   assert(result == false);
+
+   result = config1.read("ACL");
+   assert(result == true);
+
+   result = config1.read("ACL_wrong");
+   assert(result == false);
+
+   return 0;
+}
+
diff --git a/test/configuration_read.exp b/test/configuration_read.exp
new file mode 100644 (file)
index 0000000..2320687
--- /dev/null
@@ -0,0 +1,2 @@
+Wrong config file.
+PASS configuration_read (exit status: 0)