diff options
Diffstat (limited to '')
| -rw-r--r-- | libconfig++.pc.in | 14 | ||||
| -rw-r--r-- | libconfig++.vcproj | 229 | ||||
| -rw-r--r-- | libconfig++_stub.vcproj | 184 | ||||
| -rw-r--r-- | libconfig.c | 1489 | ||||
| -rw-r--r-- | libconfig.h | 266 | ||||
| -rw-r--r-- | libconfig.h++ | 424 | ||||
| -rw-r--r-- | libconfig.hh | 23 | ||||
| -rw-r--r-- | libconfig.pc.in | 14 | ||||
| -rw-r--r-- | libconfig.sln | 38 | ||||
| -rw-r--r-- | libconfig.spec | 84 | ||||
| -rw-r--r-- | libconfig.spec.in | 84 | ||||
| -rw-r--r-- | libconfig.vcproj | 212 | ||||
| -rw-r--r-- | libconfig_stub.vcproj | 184 | ||||
| -rw-r--r-- | libconfigcpp.c++ | 1112 | ||||
| -rw-r--r-- | libconfigcpp.cc | 23 | 
15 files changed, 4380 insertions, 0 deletions
| diff --git a/libconfig++.pc.in b/libconfig++.pc.in new file mode 100644 index 0000000..2771cc9 --- /dev/null +++ b/libconfig++.pc.in @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libconfig++ +Description: C++ Configuration File Library +Version: @VERSION@ +URL: http://www.hyperrealm.com/main.php?s=libconfig +Requires: +Conflicts: +Libs: -L${libdir} -lconfig++ +Libs.private: @LIBS@  +Cflags: -I${includedir} diff --git a/libconfig++.vcproj b/libconfig++.vcproj new file mode 100644 index 0000000..232849b --- /dev/null +++ b/libconfig++.vcproj @@ -0,0 +1,229 @@ +<?xml version="1.0" encoding="Windows-1252"?>
 +<VisualStudioProject
 +	ProjectType="Visual C++"
 +	Version="8.00"
 +	Name="libconfig++"
 +	ProjectGUID="{A0C36CE7-D908-4573-8B69-249EEEB7D2BE}"
 +	RootNamespace="libconfig_c"
 +	Keyword="Win32Proj"
 +	>
 +	<Platforms>
 +		<Platform
 +			Name="Win32"
 +		/>
 +	</Platforms>
 +	<ToolFiles>
 +	</ToolFiles>
 +	<Configurations>
 +		<Configuration
 +			Name="Debug|Win32"
 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
 +			IntermediateDirectory="$(ProjectName).$(ConfigurationName)"
 +			ConfigurationType="2"
 +			CharacterSet="1"
 +			>
 +			<Tool
 +				Name="VCPreBuildEventTool"
 +			/>
 +			<Tool
 +				Name="VCCustomBuildTool"
 +			/>
 +			<Tool
 +				Name="VCXMLDataGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCWebServiceProxyGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCMIDLTool"
 +			/>
 +			<Tool
 +				Name="VCCLCompilerTool"
 +				Optimization="0"
 +				AdditionalIncludeDirectories="."
 +				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCONFIG_EXPORTS;YY_NO_UNISTD_H"
 +				RuntimeLibrary="3"
 +				UsePrecompiledHeader="0"
 +			/>
 +			<Tool
 +				Name="VCManagedResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCPreLinkEventTool"
 +			/>
 +			<Tool
 +				Name="VCLinkerTool"
 +				LinkIncremental="2"
 +				GenerateDebugInformation="true"
 +				SubSystem="2"
 +				TargetMachine="1"
 +			/>
 +			<Tool
 +				Name="VCALinkTool"
 +			/>
 +			<Tool
 +				Name="VCManifestTool"
 +			/>
 +			<Tool
 +				Name="VCXDCMakeTool"
 +			/>
 +			<Tool
 +				Name="VCBscMakeTool"
 +			/>
 +			<Tool
 +				Name="VCFxCopTool"
 +			/>
 +			<Tool
 +				Name="VCAppVerifierTool"
 +			/>
 +			<Tool
 +				Name="VCWebDeploymentTool"
 +			/>
 +			<Tool
 +				Name="VCPostBuildEventTool"
 +			/>
 +		</Configuration>
 +		<Configuration
 +			Name="Release|Win32"
 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
 +			IntermediateDirectory="$(ProjectName).$(ConfigurationName)"
 +			ConfigurationType="2"
 +			CharacterSet="1"
 +			WholeProgramOptimization="1"
 +			>
 +			<Tool
 +				Name="VCPreBuildEventTool"
 +			/>
 +			<Tool
 +				Name="VCCustomBuildTool"
 +			/>
 +			<Tool
 +				Name="VCXMLDataGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCWebServiceProxyGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCMIDLTool"
 +			/>
 +			<Tool
 +				Name="VCCLCompilerTool"
 +				AdditionalIncludeDirectories="."
 +				PreprocessorDefinitions="LIBCONFIG_EXPORTS;YY_NO_UNISTD_H;_CRT_SECURE_NO_DEPRECATE"
 +				RuntimeLibrary="2"
 +			/>
 +			<Tool
 +				Name="VCManagedResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCPreLinkEventTool"
 +			/>
 +			<Tool
 +				Name="VCLinkerTool"
 +				OptimizeReferences="2"
 +				EnableCOMDATFolding="2"
 +				TargetMachine="1"
 +			/>
 +			<Tool
 +				Name="VCALinkTool"
 +			/>
 +			<Tool
 +				Name="VCManifestTool"
 +			/>
 +			<Tool
 +				Name="VCXDCMakeTool"
 +			/>
 +			<Tool
 +				Name="VCBscMakeTool"
 +			/>
 +			<Tool
 +				Name="VCFxCopTool"
 +			/>
 +			<Tool
 +				Name="VCAppVerifierTool"
 +			/>
 +			<Tool
 +				Name="VCWebDeploymentTool"
 +			/>
 +			<Tool
 +				Name="VCPostBuildEventTool"
 +			/>
 +		</Configuration>
 +	</Configurations>
 +	<References>
 +	</References>
 +	<Files>
 +		<Filter
 +			Name="Source Files"
 +			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
 +			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 +			>
 +			<File
 +				RelativePath=".\grammar.c"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\libconfig.c"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\libconfigcpp.cc"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\scanner.c"
 +				>
 +			</File>
 +		</Filter>
 +		<Filter
 +			Name="Header Files"
 +			Filter="h;hpp;hxx;hm;inl;inc;xsd"
 +			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 +			>
 +			<File
 +				RelativePath=".\ac_config.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\config.tab.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\grammar.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\libconfig.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\libconfig.h++"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\libconfig.hh"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\private.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\scanner.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\wincompat.h"
 +				>
 +			</File>
 +		</Filter>
 +	</Files>
 +	<Globals>
 +	</Globals>
 +</VisualStudioProject>
 diff --git a/libconfig++_stub.vcproj b/libconfig++_stub.vcproj new file mode 100644 index 0000000..c89b53e --- /dev/null +++ b/libconfig++_stub.vcproj @@ -0,0 +1,184 @@ +<?xml version="1.0" encoding="Windows-1252"?>
 +<VisualStudioProject
 +	ProjectType="Visual C++"
 +	Version="8.00"
 +	Name="libconfig++_stub"
 +	ProjectGUID="{2A94C9E9-A7C7-4770-A24C-694312ADB850}"
 +	RootNamespace="libconfig_stub"
 +	Keyword="Win32Proj"
 +	>
 +	<Platforms>
 +		<Platform
 +			Name="Win32"
 +		/>
 +	</Platforms>
 +	<ToolFiles>
 +	</ToolFiles>
 +	<Configurations>
 +		<Configuration
 +			Name="Debug|Win32"
 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
 +			IntermediateDirectory="$(ProjectName).$(ConfigurationName)"
 +			ConfigurationType="1"
 +			CharacterSet="1"
 +			>
 +			<Tool
 +				Name="VCPreBuildEventTool"
 +			/>
 +			<Tool
 +				Name="VCCustomBuildTool"
 +			/>
 +			<Tool
 +				Name="VCXMLDataGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCWebServiceProxyGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCMIDLTool"
 +			/>
 +			<Tool
 +				Name="VCCLCompilerTool"
 +				AdditionalIncludeDirectories="."
 +				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
 +				RuntimeLibrary="3"
 +				WarningLevel="0"
 +			/>
 +			<Tool
 +				Name="VCManagedResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCPreLinkEventTool"
 +			/>
 +			<Tool
 +				Name="VCLinkerTool"
 +				LinkIncremental="2"
 +				GenerateDebugInformation="true"
 +				SubSystem="1"
 +				TargetMachine="1"
 +			/>
 +			<Tool
 +				Name="VCALinkTool"
 +			/>
 +			<Tool
 +				Name="VCManifestTool"
 +			/>
 +			<Tool
 +				Name="VCXDCMakeTool"
 +			/>
 +			<Tool
 +				Name="VCBscMakeTool"
 +			/>
 +			<Tool
 +				Name="VCFxCopTool"
 +			/>
 +			<Tool
 +				Name="VCAppVerifierTool"
 +			/>
 +			<Tool
 +				Name="VCWebDeploymentTool"
 +			/>
 +			<Tool
 +				Name="VCPostBuildEventTool"
 +			/>
 +		</Configuration>
 +		<Configuration
 +			Name="Release|Win32"
 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
 +			IntermediateDirectory="$(ProjectName).$(ConfigurationName)"
 +			ConfigurationType="1"
 +			CharacterSet="1"
 +			WholeProgramOptimization="1"
 +			>
 +			<Tool
 +				Name="VCPreBuildEventTool"
 +			/>
 +			<Tool
 +				Name="VCCustomBuildTool"
 +			/>
 +			<Tool
 +				Name="VCXMLDataGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCWebServiceProxyGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCMIDLTool"
 +			/>
 +			<Tool
 +				Name="VCCLCompilerTool"
 +				AdditionalIncludeDirectories="."
 +				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
 +				RuntimeLibrary="2"
 +			/>
 +			<Tool
 +				Name="VCManagedResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCPreLinkEventTool"
 +			/>
 +			<Tool
 +				Name="VCLinkerTool"
 +				GenerateDebugInformation="false"
 +				SubSystem="1"
 +				TargetMachine="1"
 +			/>
 +			<Tool
 +				Name="VCALinkTool"
 +			/>
 +			<Tool
 +				Name="VCManifestTool"
 +			/>
 +			<Tool
 +				Name="VCXDCMakeTool"
 +			/>
 +			<Tool
 +				Name="VCBscMakeTool"
 +			/>
 +			<Tool
 +				Name="VCFxCopTool"
 +			/>
 +			<Tool
 +				Name="VCAppVerifierTool"
 +			/>
 +			<Tool
 +				Name="VCWebDeploymentTool"
 +			/>
 +			<Tool
 +				Name="VCPostBuildEventTool"
 +			/>
 +		</Configuration>
 +	</Configurations>
 +	<References>
 +		<ProjectReference
 +			ReferencedProjectIdentifier="{A0C36CE7-D908-4573-8B69-249EEEB7D2BE}"
 +			RelativePathToProject=".\libconfig++.vcproj"
 +		/>
 +	</References>
 +	<Files>
 +		<Filter
 +			Name="Source Files"
 +			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
 +			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 +			>
 +			<File
 +				RelativePath=".\samples\c++\stubcpp.cpp"
 +				>
 +			</File>
 +		</Filter>
 +		<Filter
 +			Name="Header Files"
 +			Filter="h;hpp;hxx;hm;inl;inc;xsd"
 +			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 +			>
 +		</Filter>
 +	</Files>
 +	<Globals>
 +	</Globals>
 +</VisualStudioProject>
 diff --git a/libconfig.c b/libconfig.c new file mode 100644 index 0000000..c09921d --- /dev/null +++ b/libconfig.c @@ -0,0 +1,1489 @@ +/* ---------------------------------------------------------------------------- +   libconfig - A library for processing structured configuration files +   Copyright (C) 2005-2009  Mark A Lindner + +   This file is part of libconfig. + +   This 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 2.1 of +   the License, or (at your option) any later version. + +   This 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 Library General Public +   License along with this library; if not, see +   <http://www.gnu.org/licenses/>. +   ---------------------------------------------------------------------------- +*/ + +#ifdef HAVE_CONFIG_H +#include "ac_config.h" +#endif + +#include "libconfig.h" +#include "grammar.h" +#include "scanner.h" +#include "private.h" +#include "wincompat.h" + +#include <locale.h> + +#ifdef HAVE_XLOCALE_H +#include <xlocale.h> +#endif + +#include <stdlib.h> +#include <ctype.h> + +#define PATH_TOKENS ":./" +#define CHUNK_SIZE 10 +#define FLOAT_PRECISION 10 + +#define _new(T) (T *)calloc(sizeof(T), 1) /* zeroed */ +#define _delete(P) free((void *)(P)) + +/* ------------------------------------------------------------------------- */ + +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ +  return(TRUE); +} + +#endif + +/* ------------------------------------------------------------------------- */ + +static const char *__io_error = "file I/O error"; + +static void __config_list_destroy(config_list_t *list); +static void __config_write_setting(const config_setting_t *setting, +                                   FILE *stream, int depth); + +extern int libconfig_yyparse(void *scanner, struct parse_context *ctx); + +/* ------------------------------------------------------------------------- */ + +static void __config_locale_override() +{ +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \ +  && ! defined(__MINGW32__) + +  _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); +  setlocale(LC_NUMERIC, "C"); + +#elif defined(__APPLE__) + +  locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL); +  uselocale(loc); + +#elif ((defined HAVE_NEWLOCALE) && (defined HAVE_USELOCALE)) + +  locale_t loc = newlocale(LC_NUMERIC, "C", NULL); +  uselocale(loc); + +#else + +#warning "No way to modify calling thread's locale!" + +#endif +} + +/* ------------------------------------------------------------------------- */ + +static void __config_locale_restore() +{ +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \ +  && ! defined(__MINGW32__) + +    _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); + +#elif ((defined HAVE_USELOCALE) && (defined HAVE_FREELOCALE)) + +  locale_t loc = uselocale(LC_GLOBAL_LOCALE); +  freelocale(loc); + +#else + +#warning "No way to modify calling thread's locale!" + +#endif +} + +/* ------------------------------------------------------------------------- */ + +static int __config_name_compare(const char *a, const char *b) +{ +  const char *p, *q; + +  for(p = a, q = b; ; p++, q++) +  { +    int pd = ((! *p) || strchr(PATH_TOKENS, *p)); +    int qd = ((! *q) || strchr(PATH_TOKENS, *q)); + +    if(pd && qd) +      break; +    else if(pd) +      return(-1); +    else if(qd) +      return(1); +    else if(*p < *q) +      return(-1); +    else if(*p > *q) +      return(1); +  } + +  return(0); +} + +/* ------------------------------------------------------------------------- */ + +static void __config_write_value(const config_value_t *value, int type, +                                 int format, int depth, FILE *stream) +{ +  char fbuf[64]; + +  switch(type) +  { +    /* boolean */ +    case CONFIG_TYPE_BOOL: +      fputs(value->ival ? "true" : "false", stream); +      break; + +    /* int */ +    case CONFIG_TYPE_INT: +      switch(format) +      { +        case CONFIG_FORMAT_HEX: +          fprintf(stream, "0x%lX", value->ival); +          break; + +        case CONFIG_FORMAT_DEFAULT: +        default: +          fprintf(stream, "%ld", value->ival); +          break; +      } +      break; + +    /* 64-bit int */ +    case CONFIG_TYPE_INT64: +      switch(format) +      { +        case CONFIG_FORMAT_HEX: +          fprintf(stream, "0x" INT64_HEX_FMT "L", value->llval); +          break; + +        case CONFIG_FORMAT_DEFAULT: +        default: +          fprintf(stream, INT64_FMT "L", value->llval); +          break; +      } +      break; + +    /* float */ +    case CONFIG_TYPE_FLOAT: +    { +      char *q; + +      snprintf(fbuf, sizeof(fbuf) - 3, "%.*g", FLOAT_PRECISION, value->fval); + +      /* check for exponent */ + +      q = strchr(fbuf, 'e'); +      if(! q) +      { +        /* no exponent */ + +        if(! strchr(fbuf, '.')) /* no decimal point */ +          strcat(fbuf, ".0"); +        else +        { +          /* has decimal point */ + +          char *p; + +          for(p = fbuf + strlen(fbuf) - 1; p > fbuf; --p) +          { +            if(*p != '0') +            { +              *(++p) = '\0'; +              break; +            } +          } +        } +      } + +      fputs(fbuf, stream); +      break; +    } + +    /* string */ +    case CONFIG_TYPE_STRING: +    { +      char *p; + +      fputc('\"', stream); + +      if(value->sval) +      { +        for(p = value->sval; *p; p++) +        { +          switch(*p) +          { +            case '\"': +            case '\\': +              fputc('\\', stream); +              fputc(*p, stream); +              break; + +            case '\n': +              fputs("\\n", stream); +              break; + +            case '\r': +              fputs("\\r", stream); +              break; + +            case '\f': +              fputs("\\f", stream); +              break; + +            case '\t': +              fputs("\\t", stream); +              break; + +            default: +              fputc(*p, stream); +          } +        } +      } +      fputc('\"', stream); +      break; +    } + +    /* list */ +    case CONFIG_TYPE_LIST: +    { +      config_list_t *list = value->list; + +      fprintf(stream, "( "); + +      if(list) +      { +        int len = list->length; +        config_setting_t **s; + +        for(s = list->elements; len--; s++) +        { +          __config_write_value(&((*s)->value), (*s)->type, (*s)->format, +                               depth + 1, stream); + +          if(len) +            fputc(',', stream); + +          fputc(' ', stream); +        } +      } + +      fputc(')', stream); +      break; +    } + +    /* array */ +    case CONFIG_TYPE_ARRAY: +    { +      config_list_t *list = value->list; + +      fprintf(stream, "[ "); + +      if(list) +      { +        int len = list->length; +        config_setting_t **s; + +        for(s = list->elements; len--; s++) +        { +          __config_write_value(&((*s)->value), (*s)->type, (*s)->format, +                               depth + 1, stream); + +          if(len) +            fputc(',', stream); + +          fputc(' ', stream); +        } +      } + +      fputc(']', stream); +      break; +    } + +    /* group */ +    case CONFIG_TYPE_GROUP: +    { +      config_list_t *list = value->list; + +      if(depth > 0) +      { +#ifdef K_AND_R_STYLE /* Horrendous, but many people like it. */ +        fputc(' ', stream); +#else +        fputc('\n', stream); + +        if(depth > 1) +          fprintf(stream, "%*s", (depth - 1) * 2, " "); +#endif +        fprintf(stream, "{\n"); +      } + +      if(list) +      { +        int len = list->length; +        config_setting_t **s; + +        for(s = list->elements; len--; s++) +          __config_write_setting(*s, stream, depth + 1); +      } + +      if(depth > 1) +        fprintf(stream, "%*s", (depth - 1) * 2, " "); + +      if(depth > 0) +        fputc('}', stream); + +      break; +    } + +    default: +      /* this shouldn't happen, but handle it gracefully... */ +      fputs("???", stream); +      break; +  } +} + +/* ------------------------------------------------------------------------- */ + +static void __config_list_add(config_list_t *list, config_setting_t *setting) +{ +  if(list->length == list->capacity) +  { +    list->capacity += CHUNK_SIZE; +    list->elements = (config_setting_t **)realloc( +      list->elements, list->capacity * sizeof(config_setting_t *)); +  } + +  list->elements[list->length] = setting; +  list->length++; +} + +/* ------------------------------------------------------------------------- */ + +static config_setting_t *__config_list_search(config_list_t *list, +                                              const char *name, +                                              unsigned int *idx) +{ +  config_setting_t **found = NULL; +  unsigned int i; + +  if(! list) +    return(NULL); + +  for(i = 0, found = list->elements; i < list->length; i++, found++) +  { +    if(! (*found)->name) +      continue; + +    if(! __config_name_compare(name, (*found)->name)) +    { +      if(idx) +        *idx = i; + +      return(*found); +    } +  } + +  return(NULL); +} + +/* ------------------------------------------------------------------------- */ + +static config_setting_t *__config_list_remove(config_list_t *list, int idx) +{ +  config_setting_t *removed = *(list->elements + idx); +  int offset = (idx * sizeof(config_setting_t *)); +  int len = list->length - 1 - idx; +  char *base = (char *)list->elements + offset; + +  memmove(base, base + sizeof(config_setting_t *), +          len * sizeof(config_setting_t *)); + +  list->length--; + +  if((list->capacity - list->length) >= CHUNK_SIZE) +  { +    /* realloc smaller? */ +  } + +  return(removed); +} + +/* ------------------------------------------------------------------------- */ + +static void __config_setting_destroy(config_setting_t *setting) +{ +  if(setting) +  { +    if(setting->name) +      _delete(setting->name); + +    if(setting->type == CONFIG_TYPE_STRING) +      _delete(setting->value.sval); + +    else if((setting->type == CONFIG_TYPE_GROUP) +            || (setting->type == CONFIG_TYPE_ARRAY) +            || (setting->type == CONFIG_TYPE_LIST)) +    { +      if(setting->value.list) +        __config_list_destroy(setting->value.list); +    } + +    if(setting->hook && setting->config->destructor) +      setting->config->destructor(setting->hook); + +    _delete(setting); +  } +} + +/* ------------------------------------------------------------------------- */ + +static void __config_list_destroy(config_list_t *list) +{ +  config_setting_t **p; +  unsigned int i; + +  if(! list) +    return; + +  if(list->elements) +  { +    for(p = list->elements, i = 0; i < list->length; p++, i++) +      __config_setting_destroy(*p); + +    _delete(list->elements); +  } + +  _delete(list); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_vector_checktype(const config_setting_t *vector, int type) +{ +  /* if the array is empty, then it has no type yet */ + +  if(! vector->value.list) +    return(CONFIG_TRUE); + +  if(vector->value.list->length == 0) +    return(CONFIG_TRUE); + +  /* if it's a list, any type is allowed */ + +  if(vector->type == CONFIG_TYPE_LIST) +    return(CONFIG_TRUE); + +  /* otherwise the first element added determines the type of the array */ + +  return((vector->value.list->elements[0]->type == type) +         ? CONFIG_TRUE : CONFIG_FALSE); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_validate_name(const char *name) +{ +  const char *p = name; + +  if(*p == '\0') +    return(CONFIG_FALSE); + +  if(! isalpha(*p) && (*p != '*')) +    return(CONFIG_FALSE); + +  for(++p; *p; ++p) +  { +    if(! (isalpha(*p) || isdigit(*p) || strchr("*_-", (int)*p))) +      return(CONFIG_FALSE); +  } + +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_read(config_t *config, FILE *stream) +{ +  yyscan_t scanner; +  struct parse_context ctx; +  int r; + +  /* Reinitialize the config (keep the destructor) */ +  void (*destructor)(void *) = config->destructor; +  config_destroy(config); +  config_init(config); +  config->destructor = destructor; + +  ctx.config = config; +  ctx.parent = config->root; +  ctx.setting = config->root; + +  __config_locale_override(); + +  libconfig_yylex_init(&scanner); +  libconfig_yyrestart(stream, scanner); +  r = libconfig_yyparse(scanner, &ctx); +  libconfig_yylex_destroy(scanner); + +  __config_locale_restore(); + +  return(r == 0 ? CONFIG_TRUE : CONFIG_FALSE); +} + +/* ------------------------------------------------------------------------- */ + +static void __config_write_setting(const config_setting_t *setting, +                                   FILE *stream, int depth) +{ +  if(depth > 1) +    fprintf(stream, "%*s", (depth - 1) * 2, " "); + +  if(setting->name) +  { +    fputs(setting->name, stream); +    fprintf(stream, " %c ", (setting->type == CONFIG_TYPE_GROUP ? ':' : '=')); +  } + +  __config_write_value(&(setting->value), setting->type, setting->format, +                       depth, stream); + +  if(depth > 0) +  { +    fputc(';', stream); +    fputc('\n', stream); +  } +} + +/* ------------------------------------------------------------------------- */ + +void config_write(const config_t *config, FILE *stream) +{ +  __config_locale_override(); + +  __config_write_setting(config->root, stream, 0); + +  __config_locale_restore(); +} + +/* ------------------------------------------------------------------------- */ + +int config_read_file(config_t *config, const char *filename) +{ +  int ret; +  FILE *f = fopen(filename, "rt"); +  if(! f) +  { +    config->error_text = __io_error; +    return(CONFIG_FALSE); +  } + +  ret = config_read(config, f); +  fclose(f); +  return(ret); +} + +/* ------------------------------------------------------------------------- */ + +int config_write_file(config_t *config, const char *filename) +{ +  FILE *f = fopen(filename, "wt"); +  if(! f) +  { +    config->error_text = __io_error; +    return(CONFIG_FALSE); +  } + +  config_write(config, f); +  fclose(f); +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +void config_destroy(config_t *config) +{ +  __config_setting_destroy(config->root); + +  memset((void *)config, 0, sizeof(config_t)); +} + +/* ------------------------------------------------------------------------- */ + +void config_init(config_t *config) +{ +  memset((void *)config, 0, sizeof(config_t)); + +  config->root = _new(config_setting_t); +  config->root->type = CONFIG_TYPE_GROUP; +  config->root->config = config; +} + +/* ------------------------------------------------------------------------- */ + +void config_set_auto_convert(config_t *config, int flag) +{ +  if(flag) +    config->flags |= CONFIG_OPTION_AUTOCONVERT; +  else +    config->flags &= ~CONFIG_OPTION_AUTOCONVERT; +} + +/* ------------------------------------------------------------------------- */ + +int config_get_auto_convert(const config_t *config) +{ +  return((config->flags & CONFIG_OPTION_AUTOCONVERT) != 0); +} + +/* ------------------------------------------------------------------------- */ + +static config_setting_t *config_setting_create(config_setting_t *parent, +                                               const char *name, int type) +{ +  config_setting_t *setting; +  config_list_t *list; + +  if((parent->type != CONFIG_TYPE_GROUP) +     && (parent->type != CONFIG_TYPE_ARRAY) +     && (parent->type != CONFIG_TYPE_LIST)) +    return(NULL); + +  setting = _new(config_setting_t); +  setting->parent = parent; +  setting->name = (name == NULL) ? NULL : strdup(name); +  setting->type = type; +  setting->config = parent->config; +  setting->hook = NULL; +  setting->line = 0; + +  list = parent->value.list; + +  if(! list) +    list = parent->value.list = _new(config_list_t); + +  __config_list_add(list, setting); + +  return(setting); +} + +/* ------------------------------------------------------------------------- */ + +long config_setting_get_int(const config_setting_t *setting) +{ +  switch(setting->type) +  { +    case CONFIG_TYPE_INT: +      return(setting->value.ival); + +    case CONFIG_TYPE_INT64: +      if((setting->value.llval > INT32_MAX) +         || (setting->value.llval < INT32_MIN)) +        return(0); +      else +        return((long)setting->value.llval); + +    case CONFIG_TYPE_FLOAT: +      if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) +        return((long)(setting->value.fval)); +      else +        /* fall through */; + +    default: +      return(0); +  } +} + +/* ------------------------------------------------------------------------- */ + +long long config_setting_get_int64(const config_setting_t *setting) +{ +  switch(setting->type) +  { +    case CONFIG_TYPE_INT64: +      return(setting->value.llval); + +    case CONFIG_TYPE_INT: +      return((long long)setting->value.ival); + +    case CONFIG_TYPE_FLOAT: +      if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) +        return((long long)(setting->value.fval)); +      else +        /* fall through */; + +    default: +      return(0); +  } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_int(const config_setting_t *setting, +                              const char *name, long *value) +{ +  config_setting_t *member = config_setting_get_member(setting, name); +  if(! member) +    return(CONFIG_FALSE); + +  if(config_setting_type(member) != CONFIG_TYPE_INT) +    return(CONFIG_FALSE); + +  *value = config_setting_get_int(member); +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_int64(const config_setting_t *setting, +                                const char *name, long long *value) +{ +  config_setting_t *member = config_setting_get_member(setting, name); +  if(! member) +    return(CONFIG_FALSE); + +  if(config_setting_type(member) != CONFIG_TYPE_INT64) +    return(CONFIG_FALSE); + +  *value = config_setting_get_int64(member); +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_float(const config_setting_t *setting, +                                const char *name, double *value) +{ +  config_setting_t *member = config_setting_get_member(setting, name); +  if(! member) +    return(CONFIG_FALSE); + +  if(config_setting_type(member) != CONFIG_TYPE_FLOAT) +    return(CONFIG_FALSE); + +  *value = config_setting_get_float(member); +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_string(const config_setting_t *setting, +                                 const char *name, const char **value) +{ +  config_setting_t *member = config_setting_get_member(setting, name); +  if(! member) +    return(CONFIG_FALSE); + +  if(config_setting_type(member) != CONFIG_TYPE_STRING) +    return(CONFIG_FALSE); + +  *value = config_setting_get_string(member); +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_bool(const config_setting_t *setting, +                               const char *name, int *value) +{ +  config_setting_t *member = config_setting_get_member(setting, name); +  if(! member) +    return(CONFIG_FALSE); + +  if(config_setting_type(member) != CONFIG_TYPE_BOOL) +    return(CONFIG_FALSE); + +  *value = config_setting_get_bool(member); +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_int(config_setting_t *setting, long value) +{ +  switch(setting->type) +  { +    case CONFIG_TYPE_NONE: +      setting->type = CONFIG_TYPE_INT; +      /* fall through */ + +    case CONFIG_TYPE_INT: +      setting->value.ival = value; +      return(CONFIG_TRUE); + +    case CONFIG_TYPE_FLOAT: +      if(config_get_auto_convert(setting->config)) +      { +        setting->value.fval = (float)value; +        return(CONFIG_TRUE); +      } +      else +        return(CONFIG_FALSE); + +    default: +      return(CONFIG_FALSE); +  } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_int64(config_setting_t *setting, long long value) +{ +  switch(setting->type) +  { +    case CONFIG_TYPE_NONE: +      setting->type = CONFIG_TYPE_INT64; +      /* fall through */ + +    case CONFIG_TYPE_INT64: +      setting->value.llval = value; +      return(CONFIG_TRUE); + +    case CONFIG_TYPE_INT: +      if((value > INT32_MAX) || (value < INT32_MIN)) +        setting->value.ival = 0; +      else +        setting->value.ival = (long)value; +      return(CONFIG_TRUE); + +    case CONFIG_TYPE_FLOAT: +      if(config_get_auto_convert(setting->config)) +      { +        setting->value.fval = (float)value; +        return(CONFIG_TRUE); +      } +      else +        return(CONFIG_FALSE); + +    default: +      return(CONFIG_FALSE); +  } +} + +/* ------------------------------------------------------------------------- */ + +double config_setting_get_float(const config_setting_t *setting) +{ +  switch(setting->type) +  { +    case CONFIG_TYPE_FLOAT: +      return(setting->value.fval); + +    case CONFIG_TYPE_INT: +      if(config_get_auto_convert(setting->config)) +        return((double)(setting->value.ival)); +      else +        return(0.0); + +    case CONFIG_TYPE_INT64: +      if(config_get_auto_convert(setting->config)) +        return((double)(setting->value.llval)); +      else +        return(0.0); + +    default: +      return(0.0); +  } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_float(config_setting_t *setting, double value) +{ +  switch(setting->type) +  { +    case CONFIG_TYPE_NONE: +      setting->type = CONFIG_TYPE_FLOAT; +      /* fall through */ + +    case CONFIG_TYPE_FLOAT: +      setting->value.fval = value; +      return(CONFIG_TRUE); + +    case CONFIG_TYPE_INT: +      if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) +      { +        setting->value.ival = (long)value; +        return(CONFIG_TRUE); +      } +      else +        return(CONFIG_FALSE); + +    case CONFIG_TYPE_INT64: +      if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) +      { +        setting->value.llval = (long long)value; +        return(CONFIG_TRUE); +      } +      else +        return(CONFIG_FALSE); + +    default: +      return(CONFIG_FALSE); +  } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_get_bool(const config_setting_t *setting) +{ +  return((setting->type == CONFIG_TYPE_BOOL) ? setting->value.ival : 0); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_bool(config_setting_t *setting, int value) +{ +  if(setting->type == CONFIG_TYPE_NONE) +    setting->type = CONFIG_TYPE_BOOL; +  else if(setting->type != CONFIG_TYPE_BOOL) +    return(CONFIG_FALSE); + +  setting->value.ival = value; +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +const char *config_setting_get_string(const config_setting_t *setting) +{ +  return((setting->type == CONFIG_TYPE_STRING) ? setting->value.sval : NULL); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_string(config_setting_t *setting, const char *value) +{ +  if(setting->type == CONFIG_TYPE_NONE) +    setting->type = CONFIG_TYPE_STRING; +  else if(setting->type != CONFIG_TYPE_STRING) +    return(CONFIG_FALSE); + +  if(setting->value.sval) +    _delete(setting->value.sval); + +  setting->value.sval = (value == NULL) ? NULL : strdup(value); +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_format(config_setting_t *setting, short format) +{ +  if(((setting->type != CONFIG_TYPE_INT) +      && (setting->type != CONFIG_TYPE_INT64)) +     || ((format != CONFIG_FORMAT_DEFAULT) && (format != CONFIG_FORMAT_HEX))) +    return(CONFIG_FALSE); + +  setting->format = format; + +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +short config_setting_get_format(config_setting_t *setting) +{ +  return(setting->format); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_lookup(const config_t *config, const char *path) +{ +  const char *p = path; +  config_setting_t *setting = config->root, *found; + +  for(;;) +  { +    while(*p && strchr(PATH_TOKENS, *p)) +      p++; + +    if(! *p) +      break; + +    if(*p == '[') +      found = config_setting_get_elem(setting, atoi(++p)); +    else +      found = config_setting_get_member(setting, p); + +    if(! found) +      break; + +    setting = found; + +    while(! strchr(PATH_TOKENS, *p)) +      p++; +  } + +  return(*p ? NULL : setting); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_string(const config_t *config, const char *path, +                         const char **value) +{ +  const config_setting_t *s = config_lookup(config, path); +  if(! s) +    return(CONFIG_FALSE); + +  if(config_setting_type(s) != CONFIG_TYPE_STRING) +    return(CONFIG_FALSE); + +  *value = config_setting_get_string(s); + +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_int(const config_t *config, const char *path, +                      long *value) +{ +  const config_setting_t *s = config_lookup(config, path); +  if(! s) +    return(CONFIG_FALSE); + +  if(config_setting_type(s) != CONFIG_TYPE_INT) +    return(CONFIG_FALSE); + +  *value = config_setting_get_int(s); + +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_int64(const config_t *config, const char *path, +                        long long *value) +{ +  const config_setting_t *s = config_lookup(config, path); +  if(! s) +    return(CONFIG_FALSE); + +  if(config_setting_type(s) != CONFIG_TYPE_INT64) +    return(CONFIG_FALSE); + +  *value = config_setting_get_int64(s); + +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_float(const config_t *config, const char *path, +                        double *value) +{ +  const config_setting_t *s = config_lookup(config, path); +  if(! s) +    return(CONFIG_FALSE); + +  if(config_setting_type(s) != CONFIG_TYPE_FLOAT) +    return(CONFIG_FALSE); + +  *value = config_setting_get_float(s); +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_bool(const config_t *config, const char *path, int *value) +{ +  const config_setting_t *s = config_lookup(config, path); +  if(! s) +    return(CONFIG_FALSE); + +  if(config_setting_type(s) != CONFIG_TYPE_BOOL) +    return(CONFIG_FALSE); + +  *value = config_setting_get_bool(s); +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +long config_setting_get_int_elem(const config_setting_t *vector, int idx) +{ +  const config_setting_t *element = config_setting_get_elem(vector, idx); + +  return(element ? config_setting_get_int(element) : 0); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_int_elem(config_setting_t *vector, +                                              int idx, long value) +{ +  config_setting_t *element = NULL; + +  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) +    return(NULL); + +  if(idx < 0) +  { +    if(! __config_vector_checktype(vector, CONFIG_TYPE_INT)) +      return(NULL); + +    element = config_setting_create(vector, NULL, CONFIG_TYPE_INT); +  } +  else +  { +    element = config_setting_get_elem(vector, idx); + +    if(! element) +      return(NULL); +  } + +  if(! config_setting_set_int(element, value)) +    return(NULL); + +  return(element); +} + +/* ------------------------------------------------------------------------- */ + +long long config_setting_get_int64_elem(const config_setting_t *vector, +                                        int idx) +{ +  const config_setting_t *element = config_setting_get_elem(vector, idx); + +  return(element ? config_setting_get_int64(element) : 0); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_int64_elem(config_setting_t *vector, +                                                int idx, long long value) +{ +  config_setting_t *element = NULL; + +  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) +    return(NULL); + +  if(idx < 0) +  { +    if(! __config_vector_checktype(vector, CONFIG_TYPE_INT64)) +      return(NULL); + +    element = config_setting_create(vector, NULL, CONFIG_TYPE_INT64); +  } +  else +  { +    element = config_setting_get_elem(vector, idx); + +    if(! element) +      return(NULL); +  } + +  if(! config_setting_set_int64(element, value)) +    return(NULL); + +  return(element); +} + +/* ------------------------------------------------------------------------- */ + +double config_setting_get_float_elem(const config_setting_t *vector, int idx) +{ +  config_setting_t *element = config_setting_get_elem(vector, idx); + +  return(element ? config_setting_get_float(element) : 0.0); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_float_elem(config_setting_t *vector, +                                                int idx, double value) +{ +  config_setting_t *element = NULL; + +  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) +    return(NULL); + +  if(idx < 0) +  { +    if(! __config_vector_checktype(vector, CONFIG_TYPE_FLOAT)) +      return(NULL); + +    element = config_setting_create(vector, NULL, CONFIG_TYPE_FLOAT); +  } +  else +    element = config_setting_get_elem(vector, idx); + +  if(! element) +    return(NULL); + +  if(! config_setting_set_float(element, value)) +    return(NULL); + +  return(element); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_get_bool_elem(const config_setting_t *vector, int idx) +{ +  config_setting_t *element = config_setting_get_elem(vector, idx); + +  if(! element) +    return(CONFIG_FALSE); + +  if(element->type != CONFIG_TYPE_BOOL) +    return(CONFIG_FALSE); + +  return(element->value.ival); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_bool_elem(config_setting_t *vector, +                                               int idx, int value) +{ +  config_setting_t *element = NULL; + +  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) +    return(NULL); + +  if(idx < 0) +  { +    if(! __config_vector_checktype(vector, CONFIG_TYPE_BOOL)) +      return(NULL); + +    element = config_setting_create(vector, NULL, CONFIG_TYPE_BOOL); +  } +  else +    element = config_setting_get_elem(vector, idx); + +  if(! element) +    return(NULL); + +  if(! config_setting_set_bool(element, value)) +    return(NULL); + +  return(element); +} + +/* ------------------------------------------------------------------------- */ + +const char *config_setting_get_string_elem(const config_setting_t *vector, +                                           int idx) +{ +  config_setting_t *element = config_setting_get_elem(vector, idx); + +  if(! element) +    return(NULL); + +  if(element->type != CONFIG_TYPE_STRING) +    return(NULL); + +  return(element->value.sval); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_string_elem(config_setting_t *vector, +                                                 int idx, const char *value) +{ +  config_setting_t *element = NULL; + +  if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) +    return(NULL); + +  if(idx < 0) +  { +    if(! __config_vector_checktype(vector, CONFIG_TYPE_STRING)) +      return(NULL); + +    element = config_setting_create(vector, NULL, CONFIG_TYPE_STRING); +  } +  else +    element = config_setting_get_elem(vector, idx); + +  if(! element) +    return(NULL); + +  if(! config_setting_set_string(element, value)) +    return(NULL); + +  return(element); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_get_elem(const config_setting_t *vector, +                                          unsigned int idx) +{ +  config_list_t *list = vector->value.list; + +  if(((vector->type != CONFIG_TYPE_ARRAY) +      && (vector->type != CONFIG_TYPE_LIST) +      && (vector->type != CONFIG_TYPE_GROUP)) || ! list) +    return(NULL); + +  if(idx >= list->length) +    return(NULL); + +  return(list->elements[idx]); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_get_member(const config_setting_t *setting, +                                            const char *name) +{ +  if(setting->type != CONFIG_TYPE_GROUP) +    return(NULL); + +  return(__config_list_search(setting->value.list, name, NULL)); +} + +/* ------------------------------------------------------------------------- */ + +void config_set_destructor(config_t *config, void (*destructor)(void *)) +{ +  config->destructor = destructor; +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_length(const config_setting_t *setting) +{ +  if((setting->type != CONFIG_TYPE_GROUP) +     && (setting->type != CONFIG_TYPE_ARRAY) +     && (setting->type != CONFIG_TYPE_LIST)) +    return(0); + +  if(! setting->value.list) +    return(0); + +  return(setting->value.list->length); +} + +/* ------------------------------------------------------------------------- */ + +void config_setting_set_hook(config_setting_t *setting, void *hook) +{ +  setting->hook = hook; +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_add(config_setting_t *parent, +                                     const char *name, int type) +{ +  if((type < CONFIG_TYPE_NONE) || (type > CONFIG_TYPE_LIST)) +    return(NULL); + +  if(! parent) +    return(NULL); + +  if((parent->type == CONFIG_TYPE_ARRAY) || (parent->type == CONFIG_TYPE_LIST)) +    name = NULL; + +  if(name) +  { +    if(! __config_validate_name(name)) +      return(NULL); +  } + +  if(config_setting_get_member(parent, name) != NULL) +    return(NULL); /* already exists */ + +  return(config_setting_create(parent, name, type)); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_remove(config_setting_t *parent, const char *name) +{ +  unsigned int idx; +  config_setting_t *setting; + +  if(! parent) +    return(CONFIG_FALSE); + +  if(parent->type != CONFIG_TYPE_GROUP) +    return(CONFIG_FALSE); + +  if(! (setting = __config_list_search(parent->value.list, name, &idx))) +    return(CONFIG_FALSE); + +  __config_list_remove(parent->value.list, idx); +  __config_setting_destroy(setting); + +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_remove_elem(config_setting_t *parent, unsigned int idx) +{ +  config_list_t *list; +  config_setting_t *removed = NULL; + +  if(! parent) +    return(CONFIG_FALSE); + +  list = parent->value.list; + +  if(((parent->type != CONFIG_TYPE_ARRAY) +      && (parent->type != CONFIG_TYPE_LIST) +      && (parent->type != CONFIG_TYPE_GROUP)) || ! list) +    return(CONFIG_FALSE); + +  if(idx >= list->length) +    return(CONFIG_FALSE); + +  removed = __config_list_remove(list, idx); +  __config_setting_destroy(removed); + +  return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_index(const config_setting_t *setting) +{ +  config_setting_t **found = NULL; +  config_list_t *list; +  int i; + +  if(! setting->parent) +    return(-1); + +  list = setting->parent->value.list; + +  for(i = 0, found = list->elements; i < list->length; ++i, ++found) +  { +    if(*found == setting) +      return(i); +  } + +  return(-1); +} + +/* ------------------------------------------------------------------------- */ +/* eof */ diff --git a/libconfig.h b/libconfig.h new file mode 100644 index 0000000..cf6c67a --- /dev/null +++ b/libconfig.h @@ -0,0 +1,266 @@ +/* ---------------------------------------------------------------------------- +   libconfig - A library for processing structured configuration files +   Copyright (C) 2005-2009  Mark A Lindner + +   This file is part of libconfig. + +   This 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 2.1 of +   the License, or (at your option) any later version. + +   This 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 Library General Public +   License along with this library; if not, see +   <http://www.gnu.org/licenses/>. +   ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_h +#define __libconfig_h + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#if defined(LIBCONFIG_STATIC) +#define LIBCONFIG_API +#elif defined(LIBCONFIG_EXPORTS) +#define LIBCONFIG_API __declspec(dllexport) +#else /* ! LIBCONFIG_EXPORTS */ +#define LIBCONFIG_API __declspec(dllimport) +#endif /* LIBCONFIG_STATIC */ +#else /* ! WIN32 */ +#define LIBCONFIG_API +#endif /* WIN32 */ + +#include <stdio.h> + +#define CONFIG_TYPE_NONE    0 +#define CONFIG_TYPE_GROUP   1 +#define CONFIG_TYPE_INT     2 +#define CONFIG_TYPE_INT64   3 +#define CONFIG_TYPE_FLOAT   4 +#define CONFIG_TYPE_STRING  5 +#define CONFIG_TYPE_BOOL    6 +#define CONFIG_TYPE_ARRAY   7 +#define CONFIG_TYPE_LIST    8 + +#define CONFIG_FORMAT_DEFAULT  0 +#define CONFIG_FORMAT_HEX      1 + +#define CONFIG_OPTION_AUTOCONVERT 0x01 + +#define CONFIG_TRUE  (1) +#define CONFIG_FALSE (0) + +typedef union config_value_t +{ +  long ival; +  long long llval; +  double fval; +  char *sval; +  struct config_list_t *list; +} config_value_t; + +typedef struct config_setting_t +{ +  char *name; +  short type; +  short format; +  config_value_t value; +  struct config_setting_t *parent; +  struct config_t *config; +  void *hook; +  unsigned int line; +} config_setting_t; + +typedef struct config_list_t +{ +  unsigned int length; +  unsigned int capacity; +  config_setting_t **elements; +} config_list_t; + +typedef struct config_t +{ +  config_setting_t *root; +  void (*destructor)(void *); +  int flags; +  const char *error_text; +  int error_line; +} config_t; + +extern LIBCONFIG_API int config_read(config_t *config, FILE *stream); +extern LIBCONFIG_API void config_write(const config_t *config, FILE *stream); + +extern LIBCONFIG_API void config_set_auto_convert(config_t *config, int flag); +extern LIBCONFIG_API int config_get_auto_convert(const config_t *config); + +extern LIBCONFIG_API int config_read_file(config_t *config, +                                          const char *filename); +extern LIBCONFIG_API int config_write_file(config_t *config, +                                           const char *filename); + +extern LIBCONFIG_API void config_set_destructor(config_t *config, +                                                void (*destructor)(void *)); + +extern LIBCONFIG_API void config_init(config_t *config); +extern LIBCONFIG_API void config_destroy(config_t *config); + +extern LIBCONFIG_API long config_setting_get_int( +  const config_setting_t *setting); +extern LIBCONFIG_API long long config_setting_get_int64( +  const config_setting_t *setting); +extern LIBCONFIG_API double config_setting_get_float( +  const config_setting_t *setting); +extern LIBCONFIG_API int config_setting_get_bool( +  const config_setting_t *setting); +extern LIBCONFIG_API const char *config_setting_get_string( +  const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_lookup_int( +  const config_setting_t *setting, const char *name, long *value); +extern LIBCONFIG_API int config_setting_lookup_int64( +  const config_setting_t *setting, const char *name, long long *value); +extern LIBCONFIG_API int config_setting_lookup_float( +  const config_setting_t *setting, const char *name, double *value); +extern LIBCONFIG_API int config_setting_lookup_bool( +  const config_setting_t *setting, const char *name, int *value); +extern LIBCONFIG_API int config_setting_lookup_string( +  const config_setting_t *setting, const char *name, const char **value); + +extern LIBCONFIG_API int config_setting_set_int(config_setting_t *setting, +                                                long value); +extern LIBCONFIG_API int config_setting_set_int64(config_setting_t *setting, +                                                  long long value); +extern LIBCONFIG_API int config_setting_set_float(config_setting_t *setting, +                                                  double value); +extern LIBCONFIG_API int config_setting_set_bool(config_setting_t *setting, +                                                 int value); +extern LIBCONFIG_API int config_setting_set_string(config_setting_t *setting, +                                                   const char *value); + +extern LIBCONFIG_API int config_setting_set_format(config_setting_t *setting, +                                                   short format); +extern LIBCONFIG_API short config_setting_get_format(config_setting_t *setting); + +extern LIBCONFIG_API long config_setting_get_int_elem( +  const config_setting_t *setting, int idx); +extern LIBCONFIG_API long long config_setting_get_int64_elem( +  const config_setting_t *setting, int idx); +extern LIBCONFIG_API double config_setting_get_float_elem( +  const config_setting_t *setting, int idx); +extern LIBCONFIG_API int config_setting_get_bool_elem( +  const config_setting_t *setting, int idx); +extern LIBCONFIG_API const char *config_setting_get_string_elem( +  const config_setting_t *setting, int idx); + +extern LIBCONFIG_API config_setting_t *config_setting_set_int_elem( +  config_setting_t *setting, int idx, long value); +extern LIBCONFIG_API config_setting_t *config_setting_set_int64_elem( +  config_setting_t *setting, int idx, long long value); +extern LIBCONFIG_API config_setting_t *config_setting_set_float_elem( +  config_setting_t *setting, int idx, double value); +extern LIBCONFIG_API config_setting_t *config_setting_set_bool_elem( +  config_setting_t *setting, int idx, int value); +extern LIBCONFIG_API config_setting_t *config_setting_set_string_elem( +  config_setting_t *setting, int idx, const char *value); + +#define /* int */ config_setting_type(/* const config_setting_t * */ S) \ +  ((S)->type) + +#define /* int */ config_setting_is_group(/* const config_setting_t * */ S) \ +  ((S)->type == CONFIG_TYPE_GROUP) +#define /* int */ config_setting_is_array(/* const config_setting_t * */ S) \ +  ((S)->type == CONFIG_TYPE_ARRAY) +#define /* int */ config_setting_is_list(/* const config_setting_t * */ S) \ +  ((S)->type == CONFIG_TYPE_LIST) + +#define /* int */ config_setting_is_aggregate( \ +  /* const config_setting_t * */ S)                                     \ +  (((S)->type == CONFIG_TYPE_GROUP) || ((S)->type == CONFIG_TYPE_LIST)  \ +   || ((S)->type == CONFIG_TYPE_ARRAY)) +   +#define /* int */ config_setting_is_number(/* const config_setting_t * */ S) \ +  (((S)->type == CONFIG_TYPE_INT)                                       \ +   || ((S)->type == CONFIG_TYPE_INT64)                                  \ +   || ((S)->type == CONFIG_TYPE_FLOAT)) +   +#define /* int */ config_setting_is_scalar(/* const config_setting_t * */ S) \ +  (((S)->type == CONFIG_TYPE_BOOL) || ((S)->type == CONFIG_TYPE_STRING) \ +   || config_setting_is_number(S)) + +#define /* const char * */ config_setting_name( \ +  /* const config_setting_t * */ S)             \ +  ((S)->name) + +#define /* config_setting_t * */ config_setting_parent( \ +  /* const config_setting_t * */ S)                     \ +  ((S)->parent) + +#define /* int */ config_setting_is_root(       \ +  /* const config_setting_t * */ S)             \ +  ((S)->parent ? CONFIG_FALSE : CONFIG_TRUE) + +extern LIBCONFIG_API int config_setting_index(const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_length( +  const config_setting_t *setting); +extern LIBCONFIG_API config_setting_t *config_setting_get_elem( +  const config_setting_t *setting, unsigned int idx); + +extern LIBCONFIG_API config_setting_t *config_setting_get_member( +  const config_setting_t *setting, const char *name); + +extern LIBCONFIG_API config_setting_t *config_setting_add( +  config_setting_t *parent, const char *name, int type); +extern LIBCONFIG_API int config_setting_remove(config_setting_t *parent, +                                               const char *name); +extern LIBCONFIG_API int config_setting_remove_elem(config_setting_t *parent, +                                                    unsigned int idx); +extern LIBCONFIG_API void config_setting_set_hook(config_setting_t *setting, +                                                  void *hook); + +#define config_setting_get_hook(S) ((S)->hook) + +extern LIBCONFIG_API config_setting_t *config_lookup(const config_t *config, +                                                     const char *path); + +extern LIBCONFIG_API int config_lookup_int(const config_t *config, +                                           const char *path, long *value); +extern LIBCONFIG_API int config_lookup_int64(const config_t *config, +                                             const char *path, +                                             long long *value); +extern LIBCONFIG_API int config_lookup_float(const config_t *config, +                                             const char *path, double *value); +extern LIBCONFIG_API int config_lookup_bool(const config_t *config, +                                            const char *path, int *value); +extern LIBCONFIG_API int config_lookup_string(const config_t *config, +                                              const char *path, +                                              const char **value); + +#define /* config_setting_t * */ config_root_setting( \ +  /* const config_t * */ C)                           \ +  ((C)->root) + +#define /* unsigned short */ config_setting_source_line( \ +  /* const config_t */ C)                                \ +  ((C)->line) + +#define /* const char * */ config_error_text(/* const config_t * */ C)  \ +  ((C)->error_text) + +#define /* int */ config_error_line(/* const config_t * */ C)   \ +  ((C)->error_line) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __libconfig_h */ diff --git a/libconfig.h++ b/libconfig.h++ new file mode 100644 index 0000000..0a3b4b2 --- /dev/null +++ b/libconfig.h++ @@ -0,0 +1,424 @@ +/* ---------------------------------------------------------------------------- +   libconfig - A library for processing structured configuration files +   Copyright (C) 2005-2009  Mark A Lindner + +   This file is part of libconfig. + +   This 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 2.1 of +   the License, or (at your option) any later version. + +   This 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 Library General Public +   License along with this library; if not, see +   <http://www.gnu.org/licenses/>. +   ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_hpp +#define __libconfig_hpp + +#include <stdio.h> +#include <string> +#include <map> + +namespace libconfig +{ + +#include <libconfig.h> + +  class LIBCONFIG_API ConfigException : public std::exception { }; + +  class Setting; // fwd decl + +  class LIBCONFIG_API SettingException : public ConfigException +  { +    friend class Config; + +    public: + +    SettingException(const SettingException &other); +    SettingException& operator=(const SettingException &other); + +    virtual ~SettingException() throw(); + +    const char *getPath() const; + +    virtual const char *what() const throw(); + +    protected: + +    SettingException(const Setting &setting); +    SettingException(const Setting &setting, int idx); +    SettingException(const Setting &setting, const char *name); +    SettingException(const char *path); + +    private: + +    char *_path; +  }; + +  class LIBCONFIG_API SettingTypeException : public SettingException +  { +    friend class Config; +    friend class Setting; + +    const char *what() const throw(); + +    private: + +    SettingTypeException(const Setting &setting); +    SettingTypeException(const Setting &setting, int idx); +    SettingTypeException(const Setting &setting, const char *name); +  }; + +  class LIBCONFIG_API SettingNotFoundException : public SettingException +  { +    friend class Config; +    friend class Setting; + +    const char *what() const throw(); + +    private: + +    SettingNotFoundException(const Setting &setting, int idx); +    SettingNotFoundException(const Setting &setting, const char *name); +    SettingNotFoundException(const char *path); +  }; + +  class LIBCONFIG_API SettingNameException : public SettingException +  { +    friend class Config; +    friend class Setting; + +    const char *what() const throw(); + +    private: + +    SettingNameException(const Setting &setting, const char *name); +  }; + +  class LIBCONFIG_API FileIOException : public ConfigException +  { +    const char *what() const throw(); +  }; + +  class LIBCONFIG_API ParseException : public ConfigException +  { +    friend class Config; + +    public: + +    virtual ~ParseException() throw(); + +    inline int getLine() throw() +    { return(_line); } + +    inline const char *getError() throw() +    { return(_error); } + +    const char *what() const throw(); + +    private: + +    ParseException(int line, const char *error); + +    int _line; +    const char *_error; +  }; + +  class LIBCONFIG_API Setting +  { +    friend class Config; + +    public: + +    enum Type +    { +      TypeNone = 0, +      // scalar types +      TypeInt, +      TypeInt64, +      TypeFloat, +      TypeString, +      TypeBoolean, +      // aggregate types +      TypeGroup, +      TypeArray, +      TypeList +    }; + +    enum Format +    { +      FormatDefault = 0, +      FormatHex = 1 +    }; + +    private: + +    config_setting_t *_setting; +    Type _type; +    Format _format; + +    Setting(config_setting_t *setting); + +    void assertType(Type type) const +      throw(SettingTypeException); +    static Setting & wrapSetting(config_setting_t *setting); + +    Setting(const Setting& other); // not supported +    Setting& operator=(const Setting& other); // not supported + +    public: + +    virtual ~Setting() throw(); + +    inline Type getType() const throw() { return(_type); } + +    inline Format getFormat() const throw() { return(_format); } +    void setFormat(Format format) throw(); + +    operator bool() const throw(SettingTypeException); +    operator long() const throw(SettingTypeException); +    operator unsigned long() const throw(SettingTypeException); +    operator int() const throw(SettingTypeException); +    operator unsigned int() const throw(SettingTypeException); +    operator long long() const throw(SettingTypeException); +    operator unsigned long long() const throw(SettingTypeException); +    operator double() const throw(SettingTypeException); +    operator float() const throw(SettingTypeException); +    operator const char *() const throw(SettingTypeException); +    operator std::string() const throw(SettingTypeException); + +    Setting & operator=(bool value) throw(SettingTypeException); +    Setting & operator=(long value) throw(SettingTypeException); +    Setting & operator=(int value) throw(SettingTypeException); +    Setting & operator=(const long long &value) throw(SettingTypeException); +    Setting & operator=(const double &value) throw(SettingTypeException); +    Setting & operator=(float value) throw(SettingTypeException); +    Setting & operator=(const char *value) throw(SettingTypeException); +    Setting & operator=(const std::string &value) throw(SettingTypeException); + +    Setting & operator[](const char * key) const +      throw(SettingTypeException, SettingNotFoundException); + +    inline Setting & operator[](const std::string & key) const +      throw(SettingTypeException, SettingNotFoundException) +    { return(operator[](key.c_str())); } + +    Setting & operator[](int index) const +      throw(SettingTypeException, SettingNotFoundException); + +    bool lookupValue(const char *name, bool &value) const throw(); +    bool lookupValue(const char *name, long &value) const throw(); +    bool lookupValue(const char *name, unsigned long &value) const throw(); +    bool lookupValue(const char *name, int &value) const throw(); +    bool lookupValue(const char *name, unsigned int &value) const throw(); +    bool lookupValue(const char *name, long long &value) const throw(); +    bool lookupValue(const char *name, unsigned long long &value) +      const throw(); +    bool lookupValue(const char *name, double &value) const throw(); +    bool lookupValue(const char *name, float &value) const throw(); +    bool lookupValue(const char *name, const char *&value) const throw(); +    bool lookupValue(const char *name, std::string &value) const throw(); + +    inline bool lookupValue(const std::string &name, bool &value) +      const throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, long &value) +      const throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, unsigned long &value) +      const throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, int &value) const throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, unsigned int &value) +      const throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, long long &value) +      const throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, +                            unsigned long long &value) const throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, double &value) const +      throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, float &value) const +      throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, const char *&value) const +      throw() +    { return(lookupValue(name.c_str(), value)); } + +    inline bool lookupValue(const std::string &name, std::string &value) const +      throw() +    { return(lookupValue(name.c_str(), value)); } + +    void remove(const char *name) +      throw(SettingTypeException, SettingNotFoundException); + +    inline void remove(const std::string & name) +      throw(SettingTypeException, SettingNotFoundException) +    { remove(name.c_str()); } + +    void remove(unsigned int idx) +      throw(SettingTypeException, SettingNotFoundException); + +    inline Setting & add(const std::string & name, Type type) +      throw(SettingNameException, SettingTypeException) +    { return(add(name.c_str(), type)); } + +    Setting & add(const char *name, Type type) +      throw(SettingNameException, SettingTypeException); + +    Setting & add(Type type) throw(SettingTypeException); + +    inline bool exists(const std::string & name) const throw() +    { return(exists(name.c_str())); } + +    bool exists(const char *name) const throw(); + +    int getLength() const throw(); +    const char *getName() const throw(); +    std::string getPath() const; +    int getIndex() const throw(); + +    const Setting & getParent() const throw(SettingNotFoundException); +    Setting & getParent() throw(SettingNotFoundException); + +    bool isRoot() const throw(); + +    inline bool isGroup() const throw() +    { return(_type == TypeGroup); } + +    inline bool isArray() const throw() +    { return(_type == TypeArray); } + +    inline bool isList() const throw() +    { return(_type == TypeList); } + +    inline bool isAggregate() const throw() +    { return(_type >= TypeGroup); } + +    inline bool isScalar() const throw() +    { return((_type > TypeNone) && (_type < TypeGroup)); } + +    inline bool isNumber() const throw() +    { return((_type == TypeInt) || (_type == TypeInt64) +             || (_type == TypeFloat)); } + +    inline unsigned int getSourceLine() const throw() +    { return(config_setting_source_line(_setting)); } +  }; + +  class LIBCONFIG_API Config +  { +    private: + +    config_t _config; + +    static void ConfigDestructor(void *arg); +    Config(const Config& other); // not supported +    Config& operator=(const Config& other); // not supported + +    public: + +    Config(); +    virtual ~Config(); + +    void setAutoConvert(bool flag); +    bool getAutoConvert() const; + +    void read(FILE *stream) throw(ParseException); +    void write(FILE *stream) const; + +    void readFile(const char *filename) throw(FileIOException, ParseException); +    void writeFile(const char *filename) throw(FileIOException); + +    inline Setting & lookup(const std::string &path) const +      throw(SettingNotFoundException) +    { return(lookup(path.c_str())); } + +    Setting & lookup(const char *path) const throw(SettingNotFoundException); + +    inline bool exists(const std::string & path) const throw() +    { return(exists(path.c_str())); } + +    bool exists(const char *path) const throw(); + +    bool lookupValue(const char *path, bool &value) const throw(); +    bool lookupValue(const char *path, long &value) const throw(); +    bool lookupValue(const char *path, unsigned long &value) const throw(); +    bool lookupValue(const char *path, int &value) const throw(); +    bool lookupValue(const char *path, unsigned int &value) const throw(); +    bool lookupValue(const char *path, long long &value) const throw(); +    bool lookupValue(const char *path, unsigned long long &value) +      const throw(); +    bool lookupValue(const char *path, double &value) const throw(); +    bool lookupValue(const char *path, float &value) const throw(); +    bool lookupValue(const char *path, const char *&value) const throw(); +    bool lookupValue(const char *path, std::string &value) const throw(); + +    inline bool lookupValue(const std::string &path, bool &value) const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, long &value) const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, unsigned long &value) +      const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, int &value) const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, unsigned int &value) +      const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, long long &value) +      const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, +                            unsigned long long &value) const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, double &value) +      const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, float &value) +      const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, const char *&value) +      const throw() +    { return(lookupValue(path.c_str(), value)); } + +    inline bool lookupValue(const std::string &path, std::string &value) +      const throw() +    { return(lookupValue(path.c_str(), value)); } + +    Setting & getRoot() const; +  }; + +} // namespace libconfig + +#endif // __libconfig_hpp diff --git a/libconfig.hh b/libconfig.hh new file mode 100644 index 0000000..8b3b2d5 --- /dev/null +++ b/libconfig.hh @@ -0,0 +1,23 @@ +/* ---------------------------------------------------------------------------- +   libconfig - A structured configuration file parsing library +   Copyright (C) 2005-2008  Mark A Lindner +  +   This file is part of libconfig. +     +   This 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 2.1 of +   the License, or (at your option) any later version. +     +   This 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 this library; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA +   ---------------------------------------------------------------------------- +*/ + +#include <libconfig.h++> diff --git a/libconfig.pc.in b/libconfig.pc.in new file mode 100644 index 0000000..4f7628b --- /dev/null +++ b/libconfig.pc.in @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libconfig +Description: C Configuration File Library +Version: @VERSION@ +URL: http://www.hyperrealm.com/main.php?s=libconfig +Requires: +Conflicts: +Libs: -L${libdir} -lconfig +Libs.private: @LIBS@  +Cflags: -I${includedir} diff --git a/libconfig.sln b/libconfig.sln new file mode 100644 index 0000000..8a6c989 --- /dev/null +++ b/libconfig.sln @@ -0,0 +1,38 @@ +
 +Microsoft Visual Studio Solution File, Format Version 9.00
 +# Visual C++ Express 2005
 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libconfig++_stub", "libconfig++_stub.vcproj", "{2A94C9E9-A7C7-4770-A24C-694312ADB850}"
 +EndProject
 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libconfig++", "libconfig++.vcproj", "{A0C36CE7-D908-4573-8B69-249EEEB7D2BE}"
 +EndProject
 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libconfig", "libconfig.vcproj", "{1A234565-926D-49B2-83E4-D56E0C38C9F2}"
 +EndProject
 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libconfig_stub", "libconfig_stub.vcproj", "{6CD5E648-E434-4C9A-9872-AF884149CE93}"
 +EndProject
 +Global
 +	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 +		Debug|Win32 = Debug|Win32
 +		Release|Win32 = Release|Win32
 +	EndGlobalSection
 +	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 +		{2A94C9E9-A7C7-4770-A24C-694312ADB850}.Debug|Win32.ActiveCfg = Debug|Win32
 +		{2A94C9E9-A7C7-4770-A24C-694312ADB850}.Debug|Win32.Build.0 = Debug|Win32
 +		{2A94C9E9-A7C7-4770-A24C-694312ADB850}.Release|Win32.ActiveCfg = Release|Win32
 +		{2A94C9E9-A7C7-4770-A24C-694312ADB850}.Release|Win32.Build.0 = Release|Win32
 +		{A0C36CE7-D908-4573-8B69-249EEEB7D2BE}.Debug|Win32.ActiveCfg = Debug|Win32
 +		{A0C36CE7-D908-4573-8B69-249EEEB7D2BE}.Debug|Win32.Build.0 = Debug|Win32
 +		{A0C36CE7-D908-4573-8B69-249EEEB7D2BE}.Release|Win32.ActiveCfg = Release|Win32
 +		{A0C36CE7-D908-4573-8B69-249EEEB7D2BE}.Release|Win32.Build.0 = Release|Win32
 +		{1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug|Win32.ActiveCfg = Debug|Win32
 +		{1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug|Win32.Build.0 = Debug|Win32
 +		{1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release|Win32.ActiveCfg = Release|Win32
 +		{1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release|Win32.Build.0 = Release|Win32
 +		{6CD5E648-E434-4C9A-9872-AF884149CE93}.Debug|Win32.ActiveCfg = Debug|Win32
 +		{6CD5E648-E434-4C9A-9872-AF884149CE93}.Debug|Win32.Build.0 = Debug|Win32
 +		{6CD5E648-E434-4C9A-9872-AF884149CE93}.Release|Win32.ActiveCfg = Release|Win32
 +		{6CD5E648-E434-4C9A-9872-AF884149CE93}.Release|Win32.Build.0 = Release|Win32
 +	EndGlobalSection
 +	GlobalSection(SolutionProperties) = preSolution
 +		HideSolutionNode = FALSE
 +	EndGlobalSection
 +EndGlobal
 diff --git a/libconfig.spec b/libconfig.spec new file mode 100644 index 0000000..95e89c7 --- /dev/null +++ b/libconfig.spec @@ -0,0 +1,84 @@ +Name:		libconfig +Version:	1.3.2 +Release:	1 +Summary:	C/C++ Configuration File Library + +Group:		System Environment/Libraries +License:	LGPL +URL:		http://hyperrealm.com/main.php?s=libconfig +Source0:	%{name}-%{version}.tar.gz +BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id} -u -n) + +Packager:	Deneys S. Maartens  <dsm@tlabs.ac.za> + +BuildRequires:	texinfo + +%description +%{name} is a simple library for manipulating structured configuration +files. The file format is more compact and more readable than XML. And +unlike XML, it is type-aware, so it is not necessary to do string +parsing in application code. + +%{name} is very compact -- just 25K for the stripped C shared library +(one-fifth the size of the expat XML parser library) and 39K for the +stripped C++ shared library. This makes it well-suited for +memory-constrained systems like handheld devices. + +The library includes bindings for both the C and C++ languages. It works +on POSIX-compliant UNIX systems. + +%package devel +Summary:	%{name} development package +Group:		Development/Libraries +Requires:	%{name} = %{version} + +%description devel +Development files for %{name}. + +%prep +%setup -q + +%build +%configure +make %{?_smp_mflags} +make html + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +ldconfig + +%postun +ldconfig + +%files +%defattr(-,root,root,-) +%doc AUTHORS COPYING.LIB ChangeLog INSTALL NEWS README +%{_libdir}/%{name}.so* +%{_libdir}/%{name}++.so* + +%files devel +%defattr(-,root,root,-) +%doc AUTHORS COPYING.LIB ChangeLog INSTALL NEWS README +%doc doc/%{name}.html +%doc test.cfg +%doc samples/c/*.c +%doc samples/c++/*.cpp +%{_infodir} +%{_includedir} +%{_libdir}/pkgconfig +%{_libdir}/%{name}.a +%{_libdir}/%{name}.la +%{_libdir}/%{name}++.a +%{_libdir}/%{name}++.la + +%changelog +* Wed Aug 19 2007  Deneys S. Maartens  <dsm@tlabs.ac.za>  1.1.3-1 +- create spec file + +# -fin- diff --git a/libconfig.spec.in b/libconfig.spec.in new file mode 100644 index 0000000..963e4de --- /dev/null +++ b/libconfig.spec.in @@ -0,0 +1,84 @@ +Name:		@PACKAGE@ +Version:	@VERSION@ +Release:	1 +Summary:	C/C++ Configuration File Library + +Group:		System Environment/Libraries +License:	LGPL +URL:		http://hyperrealm.com/main.php?s=libconfig +Source0:	%{name}-%{version}.tar.gz +BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id} -u -n) + +Packager:	Deneys S. Maartens  <dsm@tlabs.ac.za> + +BuildRequires:	texinfo + +%description +%{name} is a simple library for manipulating structured configuration +files. The file format is more compact and more readable than XML. And +unlike XML, it is type-aware, so it is not necessary to do string +parsing in application code. + +%{name} is very compact -- just 25K for the stripped C shared library +(one-fifth the size of the expat XML parser library) and 39K for the +stripped C++ shared library. This makes it well-suited for +memory-constrained systems like handheld devices. + +The library includes bindings for both the C and C++ languages. It works +on POSIX-compliant UNIX systems. + +%package devel +Summary:	%{name} development package +Group:		Development/Libraries +Requires:	%{name} = %{version} + +%description devel +Development files for %{name}. + +%prep +%setup -q + +%build +%configure +make %{?_smp_mflags} +make html + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +ldconfig + +%postun +ldconfig + +%files +%defattr(-,root,root,-) +%doc AUTHORS COPYING.LIB ChangeLog INSTALL NEWS README +%{_libdir}/%{name}.so* +%{_libdir}/%{name}++.so* + +%files devel +%defattr(-,root,root,-) +%doc AUTHORS COPYING.LIB ChangeLog INSTALL NEWS README +%doc doc/%{name}.html +%doc test.cfg +%doc samples/c/*.c +%doc samples/c++/*.cpp +%{_infodir} +%{_includedir} +%{_libdir}/pkgconfig +%{_libdir}/%{name}.a +%{_libdir}/%{name}.la +%{_libdir}/%{name}++.a +%{_libdir}/%{name}++.la + +%changelog +* Wed Aug 19 2007  Deneys S. Maartens  <dsm@tlabs.ac.za>  1.1.3-1 +- create spec file + +# -fin- diff --git a/libconfig.vcproj b/libconfig.vcproj new file mode 100644 index 0000000..219f694 --- /dev/null +++ b/libconfig.vcproj @@ -0,0 +1,212 @@ +<?xml version="1.0" encoding="Windows-1252"?>
 +<VisualStudioProject
 +	ProjectType="Visual C++"
 +	Version="8.00"
 +	Name="libconfig"
 +	ProjectGUID="{1A234565-926D-49B2-83E4-D56E0C38C9F2}"
 +	RootNamespace="libconfig"
 +	>
 +	<Platforms>
 +		<Platform
 +			Name="Win32"
 +		/>
 +	</Platforms>
 +	<ToolFiles>
 +	</ToolFiles>
 +	<Configurations>
 +		<Configuration
 +			Name="Debug|Win32"
 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
 +			IntermediateDirectory="$(ProjectName).$(ConfigurationName)"
 +			ConfigurationType="2"
 +			>
 +			<Tool
 +				Name="VCPreBuildEventTool"
 +			/>
 +			<Tool
 +				Name="VCCustomBuildTool"
 +			/>
 +			<Tool
 +				Name="VCXMLDataGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCWebServiceProxyGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCMIDLTool"
 +			/>
 +			<Tool
 +				Name="VCCLCompilerTool"
 +				AdditionalIncludeDirectories=""
 +				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCONFIG_EXPORTS;YY_NO_UNISTD_H"
 +				RuntimeLibrary="3"
 +				CompileAs="1"
 +			/>
 +			<Tool
 +				Name="VCManagedResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCPreLinkEventTool"
 +			/>
 +			<Tool
 +				Name="VCLinkerTool"
 +				GenerateDebugInformation="true"
 +				GenerateMapFile="true"
 +				MapExports="true"
 +			/>
 +			<Tool
 +				Name="VCALinkTool"
 +			/>
 +			<Tool
 +				Name="VCManifestTool"
 +			/>
 +			<Tool
 +				Name="VCXDCMakeTool"
 +			/>
 +			<Tool
 +				Name="VCBscMakeTool"
 +			/>
 +			<Tool
 +				Name="VCFxCopTool"
 +			/>
 +			<Tool
 +				Name="VCAppVerifierTool"
 +			/>
 +			<Tool
 +				Name="VCWebDeploymentTool"
 +			/>
 +			<Tool
 +				Name="VCPostBuildEventTool"
 +			/>
 +		</Configuration>
 +		<Configuration
 +			Name="Release|Win32"
 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
 +			IntermediateDirectory="$(ProjectName).$(ConfigurationName)"
 +			ConfigurationType="2"
 +			>
 +			<Tool
 +				Name="VCPreBuildEventTool"
 +			/>
 +			<Tool
 +				Name="VCCustomBuildTool"
 +			/>
 +			<Tool
 +				Name="VCXMLDataGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCWebServiceProxyGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCMIDLTool"
 +			/>
 +			<Tool
 +				Name="VCCLCompilerTool"
 +				PreprocessorDefinitions="LIBCONFIG_EXPORTS;YY_NO_UNISTD_H;_CRT_SECURE_NO_DEPRECATE"
 +				RuntimeLibrary="2"
 +				CompileAs="1"
 +			/>
 +			<Tool
 +				Name="VCManagedResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCPreLinkEventTool"
 +			/>
 +			<Tool
 +				Name="VCLinkerTool"
 +			/>
 +			<Tool
 +				Name="VCALinkTool"
 +			/>
 +			<Tool
 +				Name="VCManifestTool"
 +			/>
 +			<Tool
 +				Name="VCXDCMakeTool"
 +			/>
 +			<Tool
 +				Name="VCBscMakeTool"
 +			/>
 +			<Tool
 +				Name="VCFxCopTool"
 +			/>
 +			<Tool
 +				Name="VCAppVerifierTool"
 +			/>
 +			<Tool
 +				Name="VCWebDeploymentTool"
 +			/>
 +			<Tool
 +				Name="VCPostBuildEventTool"
 +			/>
 +		</Configuration>
 +	</Configurations>
 +	<References>
 +	</References>
 +	<Files>
 +		<Filter
 +			Name="Source Files"
 +			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
 +			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 +			>
 +			<File
 +				RelativePath=".\grammar.c"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\libconfig.c"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\scanner.c"
 +				>
 +			</File>
 +		</Filter>
 +		<Filter
 +			Name="Header Files"
 +			Filter="h;hpp;hxx;hm;inl;inc;xsd"
 +			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 +			>
 +			<File
 +				RelativePath=".\ac_config.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\config.tab.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\grammar.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\libconfig.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\private.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\resource.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\scanner.h"
 +				>
 +			</File>
 +			<File
 +				RelativePath=".\wincompat.h"
 +				>
 +			</File>
 +		</Filter>
 +	</Files>
 +	<Globals>
 +	</Globals>
 +</VisualStudioProject>
 diff --git a/libconfig_stub.vcproj b/libconfig_stub.vcproj new file mode 100644 index 0000000..dc3e31f --- /dev/null +++ b/libconfig_stub.vcproj @@ -0,0 +1,184 @@ +<?xml version="1.0" encoding="Windows-1252"?>
 +<VisualStudioProject
 +	ProjectType="Visual C++"
 +	Version="8.00"
 +	Name="libconfig_stub"
 +	ProjectGUID="{6CD5E648-E434-4C9A-9872-AF884149CE93}"
 +	RootNamespace="libconfig_stub"
 +	Keyword="Win32Proj"
 +	>
 +	<Platforms>
 +		<Platform
 +			Name="Win32"
 +		/>
 +	</Platforms>
 +	<ToolFiles>
 +	</ToolFiles>
 +	<Configurations>
 +		<Configuration
 +			Name="Debug|Win32"
 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
 +			IntermediateDirectory="$(ProjectName).$(ConfigurationName)"
 +			ConfigurationType="1"
 +			CharacterSet="1"
 +			>
 +			<Tool
 +				Name="VCPreBuildEventTool"
 +			/>
 +			<Tool
 +				Name="VCCustomBuildTool"
 +			/>
 +			<Tool
 +				Name="VCXMLDataGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCWebServiceProxyGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCMIDLTool"
 +			/>
 +			<Tool
 +				Name="VCCLCompilerTool"
 +				AdditionalIncludeDirectories="."
 +				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
 +				RuntimeLibrary="3"
 +				CompileAs="1"
 +			/>
 +			<Tool
 +				Name="VCManagedResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCPreLinkEventTool"
 +			/>
 +			<Tool
 +				Name="VCLinkerTool"
 +				GenerateDebugInformation="true"
 +				SubSystem="1"
 +				TargetMachine="1"
 +			/>
 +			<Tool
 +				Name="VCALinkTool"
 +			/>
 +			<Tool
 +				Name="VCManifestTool"
 +			/>
 +			<Tool
 +				Name="VCXDCMakeTool"
 +			/>
 +			<Tool
 +				Name="VCBscMakeTool"
 +			/>
 +			<Tool
 +				Name="VCFxCopTool"
 +			/>
 +			<Tool
 +				Name="VCAppVerifierTool"
 +			/>
 +			<Tool
 +				Name="VCWebDeploymentTool"
 +			/>
 +			<Tool
 +				Name="VCPostBuildEventTool"
 +			/>
 +		</Configuration>
 +		<Configuration
 +			Name="Release|Win32"
 +			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
 +			IntermediateDirectory="$(ProjectName).$(ConfigurationName)"
 +			ConfigurationType="1"
 +			CharacterSet="1"
 +			WholeProgramOptimization="1"
 +			>
 +			<Tool
 +				Name="VCPreBuildEventTool"
 +			/>
 +			<Tool
 +				Name="VCCustomBuildTool"
 +			/>
 +			<Tool
 +				Name="VCXMLDataGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCWebServiceProxyGeneratorTool"
 +			/>
 +			<Tool
 +				Name="VCMIDLTool"
 +			/>
 +			<Tool
 +				Name="VCCLCompilerTool"
 +				AdditionalIncludeDirectories="."
 +				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
 +				RuntimeLibrary="2"
 +				UsePrecompiledHeader="0"
 +				CompileAs="1"
 +			/>
 +			<Tool
 +				Name="VCManagedResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCResourceCompilerTool"
 +			/>
 +			<Tool
 +				Name="VCPreLinkEventTool"
 +			/>
 +			<Tool
 +				Name="VCLinkerTool"
 +				SubSystem="1"
 +				TargetMachine="1"
 +			/>
 +			<Tool
 +				Name="VCALinkTool"
 +			/>
 +			<Tool
 +				Name="VCManifestTool"
 +			/>
 +			<Tool
 +				Name="VCXDCMakeTool"
 +			/>
 +			<Tool
 +				Name="VCBscMakeTool"
 +			/>
 +			<Tool
 +				Name="VCFxCopTool"
 +			/>
 +			<Tool
 +				Name="VCAppVerifierTool"
 +			/>
 +			<Tool
 +				Name="VCWebDeploymentTool"
 +			/>
 +			<Tool
 +				Name="VCPostBuildEventTool"
 +			/>
 +		</Configuration>
 +	</Configurations>
 +	<References>
 +		<ProjectReference
 +			ReferencedProjectIdentifier="{1A234565-926D-49B2-83E4-D56E0C38C9F2}"
 +			RelativePathToProject=".\libconfig.vcproj"
 +		/>
 +	</References>
 +	<Files>
 +		<Filter
 +			Name="Source Files"
 +			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
 +			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 +			>
 +			<File
 +				RelativePath=".\samples\c\stub.c"
 +				>
 +			</File>
 +		</Filter>
 +		<Filter
 +			Name="Header Files"
 +			Filter="h;hpp;hxx;hm;inl;inc;xsd"
 +			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 +			>
 +		</Filter>
 +	</Files>
 +	<Globals>
 +	</Globals>
 +</VisualStudioProject>
 diff --git a/libconfigcpp.c++ b/libconfigcpp.c++ new file mode 100644 index 0000000..82ad56e --- /dev/null +++ b/libconfigcpp.c++ @@ -0,0 +1,1112 @@ +/* ---------------------------------------------------------------------------- +   libconfig - A library for processing structured configuration files +   Copyright (C) 2005-2009  Mark A Lindner + +   This file is part of libconfig. + +   This 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 2.1 of +   the License, or (at your option) any later version. + +   This 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 Library General Public +   License along with this library; if not, see +   <http://www.gnu.org/licenses/>. +   ---------------------------------------------------------------------------- +*/ + +#include "libconfig.h++" + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +#include "wincompat.h" + +using namespace libconfig; + +#include <cstring> +#include <cstdlib> +#include <sstream> + +// --------------------------------------------------------------------------- + +ParseException::ParseException(int line, const char *error) +  : _line(line), _error(error) +{ +} + +// --------------------------------------------------------------------------- + +ParseException::~ParseException() throw() +{ +} + +// --------------------------------------------------------------------------- + +const char *ParseException::what() const throw() +{ +  return("ParseException"); +} + +// --------------------------------------------------------------------------- + +static int __toTypeCode(Setting::Type type) +{ +  int typecode; + +  switch(type) +  { +    case Setting::TypeGroup: +      typecode = CONFIG_TYPE_GROUP; +      break; + +    case Setting::TypeInt: +      typecode = CONFIG_TYPE_INT; +      break; + +    case Setting::TypeInt64: +      typecode = CONFIG_TYPE_INT64; +      break; + +    case Setting::TypeFloat: +      typecode = CONFIG_TYPE_FLOAT; +      break; + +    case Setting::TypeString: +      typecode = CONFIG_TYPE_STRING; +      break; + +    case Setting::TypeBoolean: +      typecode = CONFIG_TYPE_BOOL; +      break; + +    case Setting::TypeArray: +      typecode = CONFIG_TYPE_ARRAY; +      break; + +    case Setting::TypeList: +      typecode = CONFIG_TYPE_LIST; +      break; + +    default: +      typecode = CONFIG_TYPE_NONE; +  } + +  return(typecode); +} + +// --------------------------------------------------------------------------- + +static void __constructPath(const Setting &setting, +                            std::stringstream &path) +{ +  // head recursion to print path from root to target + +  if(! setting.isRoot()) +  { +    __constructPath(setting.getParent(), path); +    if(path.tellp() > 0) +      path << '.'; + +    const char *name = setting.getName(); +    if(name) +      path << name; +    else +      path << '[' << setting.getIndex() << ']'; +  } +} + +// --------------------------------------------------------------------------- + +SettingException::SettingException(const Setting &setting) +{ +  std::stringstream sstr; +  __constructPath(setting, sstr); + +  _path = ::strdup(sstr.str().c_str()); +} + +// --------------------------------------------------------------------------- + +SettingException::SettingException(const Setting &setting, int idx) +{ +  std::stringstream sstr; +  __constructPath(setting, sstr); +  sstr << ".[" << idx << "]"; + +  _path = ::strdup(sstr.str().c_str()); +} + +// --------------------------------------------------------------------------- + +SettingException::SettingException(const Setting &setting, const char *name) +{ +  std::stringstream sstr; +  __constructPath(setting, sstr); +  sstr << '.' << name; + +  _path = ::strdup(sstr.str().c_str()); +} + +// --------------------------------------------------------------------------- + +SettingException::SettingException(const char *path) +{ +  _path = ::strdup(path); +} + +// --------------------------------------------------------------------------- + +const char *SettingException::getPath() const +{ +  return(_path); +} + +// --------------------------------------------------------------------------- + +SettingException::SettingException(const SettingException &other) +{ +  _path = ::strdup(other._path); +} + +// --------------------------------------------------------------------------- + +SettingException &SettingException::operator=(const SettingException &other) +{ +  ::free(_path); +  _path = ::strdup(other._path); + +  return(*this); +} + +// --------------------------------------------------------------------------- + +const char *SettingException::what() const throw() +{ +  return("SettingException"); +} + +// --------------------------------------------------------------------------- + +SettingException::~SettingException() throw() +{ +  ::free(_path); +} + +// --------------------------------------------------------------------------- + +SettingTypeException::SettingTypeException(const Setting &setting) +  : SettingException(setting) +{ +} + +// --------------------------------------------------------------------------- + +SettingTypeException::SettingTypeException(const Setting &setting, int idx) +  : SettingException(setting, idx) +{ +} + +// --------------------------------------------------------------------------- + +SettingTypeException::SettingTypeException(const Setting &setting, +                                           const char *name) +  : SettingException(setting, name) +{ +} + +// --------------------------------------------------------------------------- + +const char *SettingTypeException::what() const throw() +{ +  return("SettingTypeException"); +} + +// --------------------------------------------------------------------------- + +SettingNotFoundException::SettingNotFoundException(const Setting &setting, +                                                   int idx) +  : SettingException(setting, idx) +{ +} + +// --------------------------------------------------------------------------- + +SettingNotFoundException::SettingNotFoundException(const Setting &setting, +                                                   const char *name) +  : SettingException(setting, name) +{ +} + +// --------------------------------------------------------------------------- + +SettingNotFoundException::SettingNotFoundException(const char *path) +  : SettingException(path) +{ +} + +// --------------------------------------------------------------------------- + +const char *SettingNotFoundException::what() const throw() +{ +  return("SettingNotFoundException"); +} + +// --------------------------------------------------------------------------- + +SettingNameException::SettingNameException(const Setting &setting, +                                           const char *name) +  : SettingException(setting, name) +{ +} + +// --------------------------------------------------------------------------- + +const char *SettingNameException::what() const throw() +{ +  return("SettingNameException"); +} + +// --------------------------------------------------------------------------- + +const char *FileIOException::what() const throw() +{ +  return("FileIOException"); +} + +// --------------------------------------------------------------------------- + +void Config::ConfigDestructor(void *arg) +{ +  delete reinterpret_cast<Setting *>(arg); +} + +// --------------------------------------------------------------------------- + +Config::Config() +{ +  config_init(& _config); +  config_set_destructor(& _config, ConfigDestructor); +} + +// --------------------------------------------------------------------------- + +Config::~Config() +{ +  config_destroy(& _config); +} + +// --------------------------------------------------------------------------- + +void Config::setAutoConvert(bool flag) +{ +  config_set_auto_convert(& _config, (flag ? CONFIG_TRUE : CONFIG_FALSE)); +} + +// --------------------------------------------------------------------------- + +bool Config::getAutoConvert() const +{ +  return(config_get_auto_convert(& _config) != CONFIG_FALSE); +} + +// --------------------------------------------------------------------------- + +void Config::read(FILE *stream) throw(ParseException) +{ +  if(! config_read(& _config, stream)) +    throw ParseException(config_error_line(& _config), +                         config_error_text(& _config)); +} + +// --------------------------------------------------------------------------- + +void Config::write(FILE *stream) const +{ +  config_write(& _config, stream); +} + +// --------------------------------------------------------------------------- + +void Config::readFile(const char *filename) throw(FileIOException, +                                                  ParseException) +{ +  FILE *f = fopen(filename, "rt"); +  if(f == NULL) +    throw FileIOException(); +  try +  { +    read(f); +    fclose(f); +  } +  catch(ParseException& p) +  { +    fclose(f); +    throw p; +  } +} + +// --------------------------------------------------------------------------- + +void Config::writeFile(const char *filename) throw(FileIOException) +{ +  if(! config_write_file(& _config, filename)) +    throw FileIOException(); +} + +// --------------------------------------------------------------------------- + +Setting & Config::lookup(const char *path) const +  throw(SettingNotFoundException) +{ +  config_setting_t *s = config_lookup(& _config, path); +  if(! s) +    throw SettingNotFoundException(path); + +  return(Setting::wrapSetting(s)); +} + +// --------------------------------------------------------------------------- + +bool Config::exists(const char *path) const throw() +{ +  config_setting_t *s = config_lookup(& _config, path); + +  return(s != NULL); +} + +// --------------------------------------------------------------------------- + +#define CONFIG_LOOKUP_NO_EXCEPTIONS(P, T, V)    \ +  try                                           \ +  {                                             \ +    Setting &s = lookup(P);                     \ +    V = (T)s;                                   \ +    return(true);                               \ +  }                                             \ +  catch(ConfigException)                        \ +  {                                             \ +    return(false);                              \ +  } + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, bool &value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, bool, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, long &value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, long, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, unsigned long &value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, unsigned long, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, int &value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, int, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, unsigned int &value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, unsigned int, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, long long &value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, long long, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, unsigned long long &value) +  const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, unsigned long long, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, double &value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, double, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, float &value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, float, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, const char *&value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, const char *, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, std::string &value) const throw() +{ +  CONFIG_LOOKUP_NO_EXCEPTIONS(path, const char *, value); +} + +// --------------------------------------------------------------------------- + +Setting & Config::getRoot() const +{ +  return(Setting::wrapSetting(config_root_setting(& _config))); +} + +// --------------------------------------------------------------------------- + +Setting::Setting(config_setting_t *setting) +  : _setting(setting) +{ +  switch(config_setting_type(setting)) +  { +    case CONFIG_TYPE_GROUP: +      _type = TypeGroup; +      break; + +    case CONFIG_TYPE_INT: +      _type = TypeInt; +      break; + +    case CONFIG_TYPE_INT64: +      _type = TypeInt64; +      break; + +    case CONFIG_TYPE_FLOAT: +      _type = TypeFloat; +      break; + +    case CONFIG_TYPE_STRING: +      _type = TypeString; +      break; + +    case CONFIG_TYPE_BOOL: +      _type = TypeBoolean; +      break; + +    case CONFIG_TYPE_ARRAY: +      _type = TypeArray; +      break; + +    case CONFIG_TYPE_LIST: +      _type = TypeList; +      break; + +    case CONFIG_TYPE_NONE: +    default: +      _type = TypeNone; +      break; +  } + +  switch(config_setting_get_format(setting)) +  { +    case CONFIG_FORMAT_HEX: +      _format = FormatHex; +      break; + +    case CONFIG_FORMAT_DEFAULT: +    default: +      _format = FormatDefault; +      break; +  } +} + +// --------------------------------------------------------------------------- + +Setting::~Setting() throw() +{ +  _setting = NULL; +} + +// --------------------------------------------------------------------------- + +void Setting::setFormat(Format format) throw() +{ +  if((_type == TypeInt) || (_type == TypeInt64)) +  { +    if(format == FormatHex) +      _format = FormatHex; +    else +      _format = FormatDefault; +  } +  else +    _format = FormatDefault; +} + +// --------------------------------------------------------------------------- + +Setting::operator bool() const throw(SettingTypeException)  +{ +  assertType(TypeBoolean); + +  return(config_setting_get_bool(_setting) ? true : false); +} + +// --------------------------------------------------------------------------- + +Setting::operator long() const throw(SettingTypeException) +{ +  assertType(TypeInt); + +  return(config_setting_get_int(_setting)); +} + +// --------------------------------------------------------------------------- + +Setting::operator unsigned long() const throw(SettingTypeException) +{ +  assertType(TypeInt); + +  long v = config_setting_get_int(_setting); + +  if(v < 0) +    v = 0; + +  return(static_cast<unsigned long>(v)); +} + +// --------------------------------------------------------------------------- + +Setting::operator int() const throw(SettingTypeException) +{ +  assertType(TypeInt); + +  // may cause loss of precision: +  return(static_cast<int>(config_setting_get_int(_setting))); +} + +// --------------------------------------------------------------------------- + +Setting::operator unsigned int() const throw(SettingTypeException) +{ +  assertType(TypeInt); + +  long v = config_setting_get_int(_setting); + +  if(v < 0) +    v = 0; + +  return(static_cast<unsigned int>(v)); +} + +// --------------------------------------------------------------------------- + +Setting::operator long long() const throw(SettingTypeException) +{ +  assertType(TypeInt64); + +  return(config_setting_get_int64(_setting)); +} + +// --------------------------------------------------------------------------- + +Setting::operator unsigned long long() const throw(SettingTypeException) +{ +  assertType(TypeInt64); + +  long long v = config_setting_get_int64(_setting); + +  if(v < INT64_CONST(0)) +    v = INT64_CONST(0); + +  return(static_cast<unsigned long long>(v)); +} + +// --------------------------------------------------------------------------- + +Setting::operator double() const throw(SettingTypeException) +{ +  assertType(TypeFloat); + +  return(config_setting_get_float(_setting)); +} + +// --------------------------------------------------------------------------- + +Setting::operator float() const throw(SettingTypeException) +{ +  assertType(TypeFloat); + +  // may cause loss of precision: +  return(static_cast<float>(config_setting_get_float(_setting))); +} + +// --------------------------------------------------------------------------- + +Setting::operator const char *() const throw(SettingTypeException) +{ +  assertType(TypeString); + +  return(config_setting_get_string(_setting)); +} + +// --------------------------------------------------------------------------- + +Setting::operator std::string() const throw(SettingTypeException) +{ +  assertType(TypeString); + +  const char *s = config_setting_get_string(_setting); + +  std::string str; +  if(s) +    str = s; + +  return(str); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(bool value) throw(SettingTypeException) +{ +  assertType(TypeBoolean); + +  config_setting_set_bool(_setting, value); + +  return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(long value) throw(SettingTypeException) +{ +  assertType(TypeInt); + +  config_setting_set_int(_setting, value); + +  return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(int value) throw(SettingTypeException) +{ +  assertType(TypeInt); + +  long cvalue = static_cast<long>(value); + +  config_setting_set_int(_setting, cvalue); + +  return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(const long long &value) +  throw(SettingTypeException) +{ +  assertType(TypeInt64); + +  config_setting_set_int64(_setting, value); + +  return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(const double &value) throw(SettingTypeException) +{ +  assertType(TypeFloat); + +  config_setting_set_float(_setting, value); + +  return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(float value) throw(SettingTypeException) +{ +  assertType(TypeFloat); + +  double cvalue = static_cast<double>(value); + +  config_setting_set_float(_setting, cvalue); + +  return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(const char *value) throw(SettingTypeException) +{ +  assertType(TypeString); + +  config_setting_set_string(_setting, value); + +  return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(const std::string &value) +  throw(SettingTypeException) +{ +  assertType(TypeString); + +  config_setting_set_string(_setting, value.c_str()); + +  return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator[](int i) const +  throw(SettingTypeException, SettingNotFoundException) +{ +  if((_type != TypeArray) && (_type != TypeGroup) && (_type != TypeList)) +    throw SettingTypeException(*this, i); + +  config_setting_t *setting = config_setting_get_elem(_setting, i); + +  if(! setting) +    throw SettingNotFoundException(*this, i); + +  return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator[](const char *key) const +  throw(SettingTypeException, SettingNotFoundException) +{ +  assertType(TypeGroup); + +  config_setting_t *setting = config_setting_get_member(_setting, key); + +  if(! setting) +    throw SettingNotFoundException(*this, key); + +  return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +#define SETTING_LOOKUP_NO_EXCEPTIONS(K, T, V)   \ +  try                                           \ +  {                                             \ +    Setting &s = operator[](K);                 \ +    V = (T)s;                                   \ +    return(true);                               \ +  }                                             \ +  catch(ConfigException)                        \ +  {                                             \ +    return(false);                              \ +  } + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, bool &value) const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, bool, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, long &value) const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, long, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, unsigned long &value) +  const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, unsigned long, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, int &value) const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, int, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, unsigned int &value) const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, unsigned int, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, long long &value) const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, long long, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, unsigned long long &value) +  const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, unsigned long long, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, double &value) const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, double, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, float &value) const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, float, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, const char *&value) const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, const char *, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, std::string &value) const throw() +{ +  SETTING_LOOKUP_NO_EXCEPTIONS(name, const char *, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::exists(const char *name) const throw() +{ +  if(_type != TypeGroup) +    return(false); + +  config_setting_t *setting = config_setting_get_member(_setting, name); + +  return(setting != NULL); +} + +// --------------------------------------------------------------------------- + +int Setting::getLength() const throw() +{ +  return(config_setting_length(_setting)); +} + +// --------------------------------------------------------------------------- + +const char * Setting::getName() const throw() +{ +  return(config_setting_name(_setting)); +} + +// --------------------------------------------------------------------------- + +std::string Setting::getPath() const +{ +  std::stringstream path; + +  __constructPath(*this, path); + +  return(path.str()); +} + +// --------------------------------------------------------------------------- + +const Setting & Setting::getParent() const throw(SettingNotFoundException) +{ +  config_setting_t *setting = config_setting_parent(_setting); + +  if(! setting) +    throw SettingNotFoundException(NULL); + +  return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::getParent() throw(SettingNotFoundException) +{ +  config_setting_t *setting = config_setting_parent(_setting); + +  if(! setting) +    throw SettingNotFoundException(NULL); + +  return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +bool Setting::isRoot() const throw() +{ +  return(config_setting_is_root(_setting)); +} + +// --------------------------------------------------------------------------- + +int Setting::getIndex() const throw() +{ +  return(config_setting_index(_setting)); +} + +// --------------------------------------------------------------------------- + +void Setting::remove(const char *name) +  throw(SettingTypeException, SettingNotFoundException) +{ +  assertType(TypeGroup); + +  if(! config_setting_remove(_setting, name)) +    throw SettingNotFoundException(*this, name); +} + +// --------------------------------------------------------------------------- + +void Setting::remove(unsigned int idx) +  throw(SettingTypeException, SettingNotFoundException) +{ +  if((_type != TypeArray) && (_type != TypeGroup) && (_type != TypeList)) +    throw SettingTypeException(*this, idx); + +  if(! config_setting_remove_elem(_setting, idx)) +    throw SettingNotFoundException(*this, idx); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::add(const char *name, Setting::Type type) +  throw(SettingNameException, SettingTypeException) +{ +  assertType(TypeGroup); + +  int typecode = __toTypeCode(type); + +  if(typecode == CONFIG_TYPE_NONE) +    throw SettingTypeException(*this, name); + +  config_setting_t *setting = config_setting_add(_setting, name, typecode); + +  if(! setting) +    throw SettingNameException(*this, name); + +  return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::add(Setting::Type type) throw(SettingTypeException) +{ +  if((_type != TypeArray) && (_type != TypeList)) +    throw SettingTypeException(*this); + +  if(_type == TypeArray) +  { +    int idx = getLength(); + +    if(idx > 0) +    { +      Setting::Type atype = operator[](0).getType(); +      if(type != atype) +        throw SettingTypeException(*this, idx); +    } +    else +    { +      if((type != TypeInt) && (type != TypeFloat) && (type != TypeString) +         && (type != TypeBoolean)) +        throw SettingTypeException(*this, idx); +    } +  } + +  int typecode = __toTypeCode(type); +  config_setting_t *s = config_setting_add(_setting, NULL, typecode); + +  Setting &ns = wrapSetting(s); + +  switch(type) +  { +    case TypeInt: +      ns = 0; +      break; + +    case TypeInt64: +      ns = INT64_CONST(0); +      break; + +    case TypeFloat: +      ns = 0.0; +      break; + +    case TypeString: +      ns = (char *)NULL; +      break; + +    case TypeBoolean: +      ns = false; +      break; + +    default: +      // won't happen +      break; +  } + +  return(ns); +} + +// --------------------------------------------------------------------------- + +void Setting::assertType(Setting::Type type) const throw(SettingTypeException) +{ +  if(type != _type) +  { +    if(!(isNumber() && config_get_auto_convert(_setting->config) +         && ((type == TypeInt) || (type == TypeFloat)))) +      throw SettingTypeException(*this); +  } +} + +// --------------------------------------------------------------------------- + +Setting & Setting::wrapSetting(config_setting_t *s) +{ +  Setting *setting = NULL; + +  void *hook = config_setting_get_hook(s); +  if(! hook) +  { +    setting = new Setting(s); +    config_setting_set_hook(s, reinterpret_cast<void *>(setting)); +  } +  else +    setting = reinterpret_cast<Setting *>(hook); + +  return(*setting); +} + +// --------------------------------------------------------------------------- +// eof diff --git a/libconfigcpp.cc b/libconfigcpp.cc new file mode 100644 index 0000000..3917ee7 --- /dev/null +++ b/libconfigcpp.cc @@ -0,0 +1,23 @@ +/* ---------------------------------------------------------------------------- +   libconfig - A structured configuration file parsing library +   Copyright (C) 2005-2008  Mark A Lindner +  +   This file is part of libconfig. +     +   This 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 2.1 of +   the License, or (at your option) any later version. +     +   This 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 this library; if not, write to the Free Software +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA +   ---------------------------------------------------------------------------- +*/ + +#include "libconfigcpp.c++" | 
