]> gitweb.hamatoma.de Git - crepublib/commitdiff
initial state
authorhama <hama@siduction.net>
Wed, 24 Dec 2014 16:43:56 +0000 (17:43 +0100)
committerhama <hama@siduction.net>
Wed, 24 Dec 2014 16:43:56 +0000 (17:43 +0100)
54 files changed:
.cproject [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.project [new file with mode: 0644]
Doxy.sh [new file with mode: 0755]
base/ReByteBuffer.cpp [new file with mode: 0644]
base/ReByteBuffer.hpp [new file with mode: 0644]
base/ReCString.cpp [new file with mode: 0644]
base/ReCString.hpp [new file with mode: 0644]
base/ReConfigFile.cpp [new file with mode: 0644]
base/ReConfigFile.hpp [new file with mode: 0644]
base/ReDirectory.cpp [new file with mode: 0644]
base/ReDirectory.hpp [new file with mode: 0644]
base/ReException.cpp [new file with mode: 0644]
base/ReException.hpp [new file with mode: 0644]
base/ReHashList.cpp [new file with mode: 0644]
base/ReHashList.hpp [new file with mode: 0644]
base/ReI18N.cpp [new file with mode: 0644]
base/ReI18N.hpp [new file with mode: 0644]
base/ReLogger.cpp [new file with mode: 0644]
base/ReLogger.hpp [new file with mode: 0644]
base/ReProgramArgs.cpp [new file with mode: 0644]
base/ReProgramArgs.hpp [new file with mode: 0644]
base/ReSeqList.cpp [new file with mode: 0644]
base/ReSeqList.hpp [new file with mode: 0644]
base/ReStringList.cpp [new file with mode: 0644]
base/ReStringList.hpp [new file with mode: 0644]
base/ReStringUtils.cpp [new file with mode: 0644]
base/ReStringUtils.hpp [new file with mode: 0644]
base/ReTestUnit.cpp [new file with mode: 0644]
base/ReTestUnit.hpp [new file with mode: 0644]
base/ReVarArgs.cpp [new file with mode: 0644]
base/ReVarArgs.hpp [new file with mode: 0644]
base/baselocations.hpp [new file with mode: 0644]
base/rebase.hpp [new file with mode: 0644]
base/remath.hpp [new file with mode: 0644]
base/renet.hpp [new file with mode: 0644]
base/restring.hpp [new file with mode: 0644]
crepublib.doxyfile [new file with mode: 0644]
cunit/basetest.cpp [new file with mode: 0644]
cunit/cuReByteBuffer.cpp [new file with mode: 0644]
cunit/cuReCString.cpp [new file with mode: 0644]
cunit/cuReTraverser.cpp [new file with mode: 0644]
cunit/testall.cpp [new file with mode: 0644]
math/ReObfuscator.cpp [new file with mode: 0644]
math/ReObfuscator.hpp [new file with mode: 0644]
math/ReRandomizer.cpp [new file with mode: 0644]
math/ReRandomizer.hpp [new file with mode: 0644]
math/remath.hpp [new file with mode: 0644]
net/ReUdpConnection.cpp [new file with mode: 0644]
net/ReUdpConnection.hpp [new file with mode: 0644]
net/renet.hpp [new file with mode: 0644]
os/ReTraverser.cpp [new file with mode: 0644]
os/ReTraverser.hpp [new file with mode: 0644]
os/reos.hpp [new file with mode: 0644]

diff --git a/.cproject b/.cproject
new file mode 100644 (file)
index 0000000..5783069
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,676 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+       <storageModule moduleId="org.eclipse.cdt.core.settings">
+               <cconfiguration id="cdt.managedbuild.config.gnu.so.debug.643312255">
+                       <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.so.debug.643312255" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+                               <externalSettings>
+                                       <externalSetting>
+                                               <entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/crepublib"/>
+                                               <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/crepublib/Debug"/>
+                                               <entry flags="RESOLVED" kind="libraryFile" name="crepublib" srcPrefixMapping="" srcRootPath=""/>
+                                       </externalSetting>
+                               </externalSettings>
+                               <extensions>
+                                       <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+                               </extensions>
+                       </storageModule>
+                       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+                               <configuration artifactExtension="so" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.so.debug.643312255" name="Debug" parent="cdt.managedbuild.config.gnu.so.debug">
+                                       <folderInfo id="cdt.managedbuild.config.gnu.so.debug.643312255." name="/" resourcePath="">
+                                               <toolChain id="cdt.managedbuild.toolchain.gnu.so.debug.1583751107" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.so.debug">
+                                                       <targetPlatform id="cdt.managedbuild.target.gnu.platform.so.debug.579357820" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.so.debug"/>
+                                                       <builder buildPath="${workspace_loc:/crepublib/Debug}" id="cdt.managedbuild.target.gnu.builder.so.debug.1147210759" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.so.debug"/>
+                                                       <tool id="cdt.managedbuild.tool.gnu.archiver.base.1788488394" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+                                                       <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.so.debug.178145905" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.so.debug">
+                                                               <option id="gnu.cpp.compiler.so.debug.option.optimization.level.1559230217" name="Optimization Level" superClass="gnu.cpp.compiler.so.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
+                                                               <option id="gnu.cpp.compiler.so.debug.option.debugging.level.931063418" name="Debug Level" superClass="gnu.cpp.compiler.so.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
+                                                               <option id="gnu.cpp.compiler.option.include.paths.1008068360" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+                                                                       <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}&quot;"/>
+                                                               </option>
+                                                               <option id="gnu.cpp.compiler.option.dialect.std.2012961476" superClass="gnu.cpp.compiler.option.dialect.std" value="gnu.cpp.compiler.dialect.default" valueType="enumerated"/>
+                                                               <option id="gnu.cpp.compiler.option.other.pic.485320569" superClass="gnu.cpp.compiler.option.other.pic" value="true" valueType="boolean"/>
+                                                               <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1812241688" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.gnu.c.compiler.so.debug.2071123463" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.so.debug">
+                                                               <option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.so.debug.option.optimization.level.310457446" name="Optimization Level" superClass="gnu.c.compiler.so.debug.option.optimization.level" valueType="enumerated"/>
+                                                               <option id="gnu.c.compiler.so.debug.option.debugging.level.235148382" name="Debug Level" superClass="gnu.c.compiler.so.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
+                                                               <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.883885143" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.gnu.c.linker.so.debug.1534991917" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.so.debug">
+                                                               <option defaultValue="true" id="gnu.c.link.so.debug.option.shared.267793559" name="Shared (-shared)" superClass="gnu.c.link.so.debug.option.shared" valueType="boolean"/>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.gnu.cpp.linker.so.debug.637492518" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.so.debug">
+                                                               <option defaultValue="true" id="gnu.cpp.link.so.debug.option.shared.221107891" name="Shared (-shared)" superClass="gnu.cpp.link.so.debug.option.shared" valueType="boolean"/>
+                                                               <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.796158500" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+                                                                       <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+                                                                       <additionalInput kind="additionalinput" paths="$(LIBS)"/>
+                                                               </inputType>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.gnu.assembler.so.debug.293245349" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.so.debug">
+                                                               <inputType id="cdt.managedbuild.tool.gnu.assembler.input.83923718" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+                                                       </tool>
+                                               </toolChain>
+                                       </folderInfo>
+                                       <sourceEntries>
+                                               <entry excluding="math" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+                                               <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="math"/>
+                                       </sourceEntries>
+                               </configuration>
+                       </storageModule>
+                       <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+                       <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+                       <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+               </cconfiguration>
+               <cconfiguration id="cdt.managedbuild.config.gnu.so.release.1633034501">
+                       <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.so.release.1633034501" moduleId="org.eclipse.cdt.core.settings" name="Release">
+                               <externalSettings>
+                                       <externalSetting>
+                                               <entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/crepublib"/>
+                                               <entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/crepublib/Release"/>
+                                               <entry flags="RESOLVED" kind="libraryFile" name="crepublib" srcPrefixMapping="" srcRootPath=""/>
+                                       </externalSetting>
+                               </externalSettings>
+                               <extensions>
+                                       <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+                                       <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+                               </extensions>
+                       </storageModule>
+                       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+                               <configuration artifactExtension="so" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.sharedLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.sharedLib" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.so.release.1633034501" name="Release" parent="cdt.managedbuild.config.gnu.so.release">
+                                       <folderInfo id="cdt.managedbuild.config.gnu.so.release.1633034501." name="/" resourcePath="">
+                                               <toolChain id="cdt.managedbuild.toolchain.gnu.so.release.1640132741" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.so.release">
+                                                       <targetPlatform id="cdt.managedbuild.target.gnu.platform.so.release.237303036" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.so.release"/>
+                                                       <builder buildPath="${workspace_loc:/crepublib/Release}" id="cdt.managedbuild.target.gnu.builder.so.release.1809014317" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.so.release"/>
+                                                       <tool id="cdt.managedbuild.tool.gnu.archiver.base.392023158" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+                                                       <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.so.release.505452619" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.so.release">
+                                                               <option id="gnu.cpp.compiler.so.release.option.optimization.level.277842256" name="Optimization Level" superClass="gnu.cpp.compiler.so.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
+                                                               <option id="gnu.cpp.compiler.so.release.option.debugging.level.265711124" name="Debug Level" superClass="gnu.cpp.compiler.so.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+                                                               <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.100874624" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.gnu.c.compiler.so.release.1984914737" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.so.release">
+                                                               <option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.so.release.option.optimization.level.47295938" name="Optimization Level" superClass="gnu.c.compiler.so.release.option.optimization.level" valueType="enumerated"/>
+                                                               <option id="gnu.c.compiler.so.release.option.debugging.level.756407830" name="Debug Level" superClass="gnu.c.compiler.so.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
+                                                               <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.175582018" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.gnu.c.linker.so.release.132825748" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.so.release">
+                                                               <option defaultValue="true" id="gnu.c.link.so.release.option.shared.284729921" name="Shared (-shared)" superClass="gnu.c.link.so.release.option.shared" valueType="boolean"/>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.gnu.cpp.linker.so.release.412751413" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.so.release">
+                                                               <option defaultValue="true" id="gnu.cpp.link.so.release.option.shared.356182637" name="Shared (-shared)" superClass="gnu.cpp.link.so.release.option.shared" valueType="boolean"/>
+                                                               <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.311426747" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+                                                                       <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+                                                                       <additionalInput kind="additionalinput" paths="$(LIBS)"/>
+                                                               </inputType>
+                                                       </tool>
+                                                       <tool id="cdt.managedbuild.tool.gnu.assembler.so.release.514973674" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.so.release">
+                                                               <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1570029334" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+                                                       </tool>
+                                               </toolChain>
+                                       </folderInfo>
+                                       <sourceEntries>
+                                               <entry excluding="math" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+                                               <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="math"/>
+                                       </sourceEntries>
+                               </configuration>
+                       </storageModule>
+                       <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+                       <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+                       <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+               </cconfiguration>
+       </storageModule>
+       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+               <project id="crepublib.cdt.managedbuild.target.gnu.so.1996619726" name="Shared Library" projectType="cdt.managedbuild.target.gnu.so"/>
+       </storageModule>
+       <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets">
+               <buildTargets>
+                       <target name="doxygen" path="doxygen" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
+                               <buildCommand>make</buildCommand>
+                               <buildArguments/>
+                               <buildTarget>doxygen</buildTarget>
+                               <stopOnError>true</stopOnError>
+                               <useDefaultCommand>true</useDefaultCommand>
+                               <runAllBuilders>true</runAllBuilders>
+                       </target>
+                       <target name="all" path="cunit" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
+                               <buildCommand>make</buildCommand>
+                               <buildTarget>all</buildTarget>
+                               <stopOnError>true</stopOnError>
+                               <useDefaultCommand>true</useDefaultCommand>
+                               <runAllBuilders>true</runAllBuilders>
+                       </target>
+               </buildTargets>
+       </storageModule>
+       <storageModule moduleId="scannerConfiguration">
+               <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+               <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+                       <buildOutputProvider>
+                               <openAction enabled="true" filePath=""/>
+                               <parser enabled="true"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="specsFile">
+                               <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+                       <buildOutputProvider>
+                               <openAction enabled="true" filePath=""/>
+                               <parser enabled="true"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="makefileGenerator">
+                               <runAction arguments="-E -P -v -dD" command="" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+                       <buildOutputProvider>
+                               <openAction enabled="true" filePath=""/>
+                               <parser enabled="true"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="specsFile">
+                               <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+                       <buildOutputProvider>
+                               <openAction enabled="true" filePath=""/>
+                               <parser enabled="true"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="specsFile">
+                               <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+                       <buildOutputProvider>
+                               <openAction enabled="true" filePath=""/>
+                               <parser enabled="true"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="specsFile">
+                               <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+                       <buildOutputProvider>
+                               <openAction enabled="true" filePath=""/>
+                               <parser enabled="true"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="specsFile">
+                               <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+                       <buildOutputProvider>
+                               <openAction enabled="true" filePath=""/>
+                               <parser enabled="true"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="specsFile">
+                               <runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+                       <buildOutputProvider>
+                               <openAction enabled="true" filePath=""/>
+                               <parser enabled="true"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="specsFile">
+                               <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfile">
+                       <buildOutputProvider>
+                               <openAction enabled="false" filePath=""/>
+                               <parser enabled="false"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="specsFile">
+                               <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlc" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfileCPP">
+                       <buildOutputProvider>
+                               <openAction enabled="false" filePath=""/>
+                               <parser enabled="false"/>
+                       </buildOutputProvider>
+                       <scannerInfoProvider id="specsFile">
+                               <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlC" useDefault="true"/>
+                               <parser enabled="true"/>
+                       </scannerInfoProvider>
+               </profile>
+               <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.release.1633034501;cdt.managedbuild.config.gnu.so.release.1633034501.;cdt.managedbuild.tool.gnu.cpp.compiler.so.release.505452619;cdt.managedbuild.tool.gnu.cpp.compiler.input.100874624">
+                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+                       <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="makefileGenerator">
+                                       <runAction arguments="-E -P -v -dD" command="" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="false" filePath=""/>
+                                       <parser enabled="false"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="false" filePath=""/>
+                                       <parser enabled="false"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlC" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+               </scannerConfigBuildInfo>
+               <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.debug.643312255;cdt.managedbuild.config.gnu.so.debug.643312255.;cdt.managedbuild.tool.gnu.cpp.compiler.so.debug.178145905;cdt.managedbuild.tool.gnu.cpp.compiler.input.1812241688">
+                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+                       <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="makefileGenerator">
+                                       <runAction arguments="-E -P -v -dD" command="" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="false" filePath=""/>
+                                       <parser enabled="false"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="false" filePath=""/>
+                                       <parser enabled="false"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlC" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+               </scannerConfigBuildInfo>
+               <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.debug.643312255;cdt.managedbuild.config.gnu.so.debug.643312255.;cdt.managedbuild.tool.gnu.c.compiler.so.debug.2071123463;cdt.managedbuild.tool.gnu.c.compiler.input.883885143">
+                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+                       <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="makefileGenerator">
+                                       <runAction arguments="-E -P -v -dD" command="" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="false" filePath=""/>
+                                       <parser enabled="false"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="false" filePath=""/>
+                                       <parser enabled="false"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlC" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+               </scannerConfigBuildInfo>
+               <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.so.release.1633034501;cdt.managedbuild.config.gnu.so.release.1633034501.;cdt.managedbuild.tool.gnu.c.compiler.so.release.1984914737;cdt.managedbuild.tool.gnu.c.compiler.input.175582018">
+                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+                       <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="makefileGenerator">
+                                       <runAction arguments="-E -P -v -dD" command="" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+                               <buildOutputProvider>
+                                       <openAction enabled="true" filePath=""/>
+                                       <parser enabled="true"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfile">
+                               <buildOutputProvider>
+                                       <openAction enabled="false" filePath=""/>
+                                       <parser enabled="false"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlc" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+                       <profile id="org.eclipse.cdt.managedbuilder.xlc.core.XLCManagedMakePerProjectProfileCPP">
+                               <buildOutputProvider>
+                                       <openAction enabled="false" filePath=""/>
+                                       <parser enabled="false"/>
+                               </buildOutputProvider>
+                               <scannerInfoProvider id="specsFile">
+                                       <runAction arguments="-E -v ${plugin_state_location}/${specs_file}" command="${XL_compilerRoot}/xlC" useDefault="true"/>
+                                       <parser enabled="true"/>
+                               </scannerInfoProvider>
+                       </profile>
+               </scannerConfigBuildInfo>
+       </storageModule>
+       <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+       <storageModule moduleId="refreshScope" versionNumber="2">
+               <configuration configurationName="Release">
+                       <resource resourceType="PROJECT" workspacePath="/crepublib"/>
+               </configuration>
+               <configuration configurationName="Debug">
+                       <resource resourceType="PROJECT" workspacePath="/crepublib"/>
+               </configuration>
+       </storageModule>
+</cproject>
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..23f8dcb
--- /dev/null
@@ -0,0 +1,3 @@
+*.o
+dirtool
+alltest
diff --git a/.project b/.project
new file mode 100644 (file)
index 0000000..24b1d09
--- /dev/null
+++ b/.project
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>crepublib</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+                       <triggers>clean,full,incremental,</triggers>
+                       <arguments>
+                               <dictionary>
+                                       <key>?name?</key>
+                                       <value></value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.append_environment</key>
+                                       <value>true</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+                                       <value>all</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.buildArguments</key>
+                                       <value></value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.buildCommand</key>
+                                       <value>make</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.buildLocation</key>
+                                       <value>${workspace_loc:/crepublib/Debug}</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+                                       <value>clean</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.contents</key>
+                                       <value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+                                       <value>false</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+                                       <value>true</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.enableFullBuild</key>
+                                       <value>true</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+                                       <value>all</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.stopOnError</key>
+                                       <value>true</value>
+                               </dictionary>
+                               <dictionary>
+                                       <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+                                       <value>true</value>
+                               </dictionary>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+                       <triggers>full,incremental,</triggers>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.cdt.core.cnature</nature>
+               <nature>org.eclipse.cdt.core.ccnature</nature>
+               <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+               <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+       </natures>
+</projectDescription>
diff --git a/Doxy.sh b/Doxy.sh
new file mode 100755 (executable)
index 0000000..339cc85
--- /dev/null
+++ b/Doxy.sh
@@ -0,0 +1,3 @@
+#! /bin/bash
+rm -Rf doxygen/*
+doxygen crepublib.doxyfile
diff --git a/base/ReByteBuffer.cpp b/base/ReByteBuffer.cpp
new file mode 100644 (file)
index 0000000..ee44320
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * ReByteBuffer.cpp
+ *
+ *  Created on: 06.05.2010
+ *      Author: wk
+ */
+
+#include "rebase.hpp"
+
+/** @brief Constructor.
+ *
+ * @param delta                If a new storage must be allocated the size
+ *                                     is incremented by at least this count of bytes.
+ */
+ReByteBuffer::ReByteBuffer(size_t delta)
+       :
+       m_delta(delta),
+       // m_primaryBuffer
+       m_buffer(m_primaryBuffer),
+       m_length(0),
+       m_size(sizeof m_primaryBuffer - 1)
+{
+       m_buffer[0] = '\0';
+}
+/** @brief Copy constructor.
+ *
+ * @param source       The instance to copy (C string).
+ */
+ReByteBuffer::ReByteBuffer(const char* source)
+       :
+       m_delta(256),
+       // m_primaryBuffer
+       m_buffer(m_primaryBuffer),
+       m_length(0),
+       m_size(sizeof m_primaryBuffer)
+{
+       m_buffer[0] = '\0';
+       append(source);
+}
+/** @brief Destructor.
+ *
+ */
+ReByteBuffer::~ReByteBuffer(){
+       if (m_buffer != m_primaryBuffer)
+               delete m_buffer;
+       m_buffer = NULL;
+       m_size = 0;
+       m_length = 0;
+}
+/** @brief Copy constructor.
+ *
+ * @param source       The instance to copy.
+ */
+ReByteBuffer::ReByteBuffer(const ReByteBuffer& source)
+       :
+       m_delta(source.getDelta()),
+       // m_primaryBuffer
+       m_buffer(m_primaryBuffer),
+       m_length(0),
+       m_size(sizeof m_primaryBuffer)
+{
+       append(source.getBuffer(), source.getLength());
+}
+
+/** @brief The assignment operator.
+ *
+ * @param source       The instance to copy.
+ *
+ * @return The instance itself.
+ */
+ReByteBuffer& ReByteBuffer::operator =(const ReByteBuffer& source){
+       m_delta = source.getDelta();
+       set(source.getBuffer(), source.getLength());
+       return *this;
+}
+
+/** @brief Appends a byte sequence at the end of the buffer.
+ *
+ * If the space is not enough it will be allocated.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer buf;
+ * assert(4 == buf.append("abc", 3).append("x").getLength());
+ * </code></pre>
+ *
+ * @param source               The sequence to append.
+ * @param length               The length of the sequence.
+ *
+ * @return *this (for chaining).
+ */
+ReByteBuffer&  ReByteBuffer::append(const Byte* source, size_t length){
+       if (length == (size_t) -1)
+               length = strlen(source);
+       ensureSize(m_length + length);
+       memcpy(m_buffer + m_length, source, length);
+       m_length += length;
+       m_buffer[m_length] = '\0';
+       return *this;
+}
+/** @brief Appends an integer as string at the end of the buffer.
+ *
+ * If the space is not enough it will be allocated.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer buf;
+ * buf.appendInt(33, 4);
+ * assert(strcmp("33  ", buf.getBuffer()) == 0);
+ * </code></pre>
+ *
+ * @param number               The number to append.
+ * @param format               The format of the number used by <code>sprintf()</code>.
+ *
+ * @return *this (for chaining).
+ */
+ReByteBuffer&  ReByteBuffer::appendInt(int number, const char* format){
+       char buffer [256];
+
+       snprintf(buffer, sizeof buffer, format, number);
+       size_t length = strlen(buffer);
+
+       ensureSize(m_length + length);
+       memcpy(m_buffer + m_length, buffer, length);
+       m_length += length;
+       m_buffer[m_length] = '\0';
+       return *this;
+}
+
+/** @brief Appends the content of another <code>ReByteBuffer</code> instance at the end of the buffer.
+ *
+ * If the space is not enough it will be allocated.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer name; name.append("mydoc");
+ * ReByteBuffer ext; ext.append(".txt");
+ * name.append(ext);
+ * assert("mydoc.txt", name.getBuffer());
+ * </code></pre>
+ *
+ * @return *this (for chaining).
+ */
+ReByteBuffer& ReByteBuffer::append(ReByteBuffer& source){
+       return append(source.getBuffer(), source.getLength());
+}
+
+/** Converts a subsequence into an integer.
+ *
+ * The number may be a decimal or a hexadecimal number. Hex numbers start with 0x.
+ * <pre><code>Example:
+ * ReByteBuffer buf;
+ * buf.set("abc123", 6);
+ * assert(12 == buf.atoi(3, 3 + 2));
+ * </code></pre>
+ *
+ * @param start                The first index to convert.
+ * @param end          -1: all found digits will be converted.
+ *                                     Otherwise: The maximal number of digits to convert.
+ */
+int ReByteBuffer::atoi(size_t start, int end) const{
+       int rc = 0;
+       if (start < m_length){
+               if (end < 0)
+                       end = m_length;
+               char cc;
+               if (m_buffer[start] == '0' && tolower(m_buffer[start + 1]) == 'x'){
+                       // Hexadecimal number:
+                       start += 2;
+                       while (start < (size_t) end && (cc = m_buffer[start++]) >= '0' && isxdigit(cc))
+                               rc = rc * 16 + (cc <= '9' ? cc - '0' : toupper(cc) - 'A' + 10);
+               } else {
+                       // Decimal number:
+                       while (start < (size_t) end && (cc = m_buffer[start++]) >= '0' && cc <= '9')
+                               rc = rc * 10 + cc - '0';
+               }
+       }
+       return rc;
+}
+/** @brief Ensures that there is enough space.
+ *
+ * <p>If not it will be allocated and the old value will be copied.
+ * </p>
+ * <p>A new allocation will be use at least <code>m_delta</code> bytes.
+ * <p>The allocated space is incremented by one because of the ending '\\0'.
+ * </p>
+ *
+ * @param size At the end the size will be at least this value.
+ */
+void ReByteBuffer::ensureSize(size_t size){
+       if (m_size < size){
+               if (size - m_size < m_delta)
+                       size = m_size + m_delta;
+                       // Think for the ending '\0':
+               Byte* buffer = new Byte[size + 1];
+               assert(buffer != NULL);
+               memcpy(buffer, m_buffer, m_length);
+               if (m_buffer != m_primaryBuffer)
+                       delete m_buffer;
+               m_buffer = buffer;
+               m_size = size;
+       }
+}
+/** @brief Search for a byte sequence in the internal buffer.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer buf;
+ * buf.set("12abc123", 8);
+ * assert(5 == buf.indexOf("12", -1, 3));
+ * </code></pre>
+ *
+ * @param toFind               The sequence to find.
+ * @param toFindLength Length of <code>toFind</code>.
+ *                                             If -1 the <code>strlen(toFind)</code> will be taken.
+ * @param start                        The index of the internal buffer where the search starts.
+ *
+ * @return     -1: The sequence could not be found.
+ *                     Otherwise: The index of <code>toFind</code> in the internal buffer.
+ */
+int ReByteBuffer::indexOf(const Byte* toFind, size_t toFindLength, int start) const{
+       if (toFindLength == (size_t) -1)
+               toFindLength = strlen(toFind);
+       int rc = -1;
+       while(rc < 0 && start <= int(m_length - toFindLength)){
+               if (memcmp(toFind, m_buffer + start, toFindLength) == 0)
+                       rc = start;
+               else
+                       start++;
+       }
+       return rc;
+}
+/** @brief Replaces all occurrences of <code>toFind</code> with <code>replacement</code>.
+ *
+ * A single replacement can be done with <code>splice()</code>.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer buf;
+ * buf.set("12abc123", 8);
+ * buf.replaceAll("12", -1, "XYZ", -1);
+ * assert(strcmp("XYZabcXYZ3", buf.str()) == 0);
+ * </code></pre>
+ *
+ * @param toFind                       The substring which will be replaced.
+ * @param toFindLength         The length of <code>toFind</code>. -1: <code>strlen()</code> will be used.
+ * @param replacement          The replacement.
+ * @param replacementLength    The length of <code>replacement</code>. -1: <code>strlen()</code> will be used.
+ * @param start                                The first index to inspect.
+ */
+ReByteBuffer& ReByteBuffer::replaceAll(const Byte* toFind, size_t toFindLength,
+               const Byte* replacement, size_t replacementLength, int start){
+       if (toFindLength == size_t(-1))
+               toFindLength = strlen(toFind);
+       if (replacementLength == size_t(-1))
+               replacementLength = strlen(replacement);
+
+       while( (start = indexOf(toFind, toFindLength, start)) != -1){
+               splice(start, toFindLength, replacement, replacementLength);
+               start += replacementLength;
+       }
+       return *this;
+}
+
+/** @brief Sets the length to a given value.
+ *
+ * The new length is greater than the current size the buffer will reallocated.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer buf;
+ * buf.set("123", 3);
+ * buf.setLength(5);
+ * assert(strcmp("123", buf.str()) == 0);
+ * assert(5 == buf.getLength());
+ * </code></pre>
+ *
+ * @param length       The new length.
+ *
+ * @return *this (for chaining).
+ */
+ReByteBuffer&  ReByteBuffer::setLength(size_t length){
+       ensureSize(length);
+       m_length = length;
+       m_buffer[length] = '\0';
+       return *this;
+}
+/** @brief Sets the length to a given value and fills the new allocated part of the buffer with a given value.
+ *
+ * The new length is greater than the current size the buffer will reallocated.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer buf;
+ * buf.set("123", 3);
+ * buf.setLengthAndFill(5, 'X');
+ * assert(strcmp("123XX", buf.str()) == 0);
+ * </code></pre>
+ *
+ * @param length       The new length.
+ * @param filler       If the new length is greater than the current length the space
+ *                                     will be filled with this value.
+ * @return *this (for chaining).
+ */
+ReByteBuffer&  ReByteBuffer::setLengthAndFill(size_t length, Byte filler){
+       ensureSize(length);
+       if (length > m_length)
+               memset(m_buffer + m_length, filler, length - m_length);
+       m_length = length;
+       m_buffer[length] = '\0';
+       return *this;
+}
+/** @brief Cuts a sequence from the internal buffer and inserts another.
+ *
+ * This function implies a pure insertion and pure deletion of a subsequence.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer buf;
+ * buf.set("12345", 5);
+ * buf.splice(2, 2, "XYZ", 3);
+ * assert(strcmp("12XYZ5", buf.str()) == 0);
+ * </code></pre>
+ *
+ * @param ix                           The index where the cut/insertion takes place.
+ * @param replacedLength       The number of deleted bytes. If 0 a pure insertion will be done.
+ * @param source                       The sequence to insert. May be NULL (for pure deletion).
+ * @param length                       The length of the inserted sequence.
+ *                                                     If 0: a pure deletion will be done.
+ *                                                     If -1: <code>strlen(source)</code> will be taken.
+ *
+ * @return true: Success. false: <code>ix</code> out of range.
+ */
+bool ReByteBuffer::splice(size_t ix, size_t replacedLength,
+               const ReByteBuffer::Byte* source, size_t length){
+       bool rc;
+       if (ix < 0 || ix > m_length)
+               rc = false;
+       else{
+               rc = true;
+
+               if (source == NULL)
+                       length = 0;
+               if (length == (size_t) -1)
+                       length = strlen(source);
+               if (ix + replacedLength > m_length)
+                       replacedLength = m_length - ix;
+
+               ensureSize(m_length + length - replacedLength);
+
+               Byte* start = m_buffer + ix;
+               Byte* tail = start + replacedLength;
+               size_t lengthTail = m_length - ix;
+
+               if (length <= replacedLength){
+                       // The sequence will not be longer:
+                       if (length > 0)
+                               memcpy(start, source, length);
+                       if (length < replacedLength){
+                               memmove(start + length, tail, lengthTail);
+                       }
+               } else {
+                       // The sequence will be longer:
+                       memmove(start + length, tail, lengthTail);
+                       memcpy(start, source, length);
+               }
+               m_length += length - replacedLength;
+               m_buffer[m_length] = '\0';
+       }
+       return rc;
+}
diff --git a/base/ReByteBuffer.hpp b/base/ReByteBuffer.hpp
new file mode 100644 (file)
index 0000000..5fe2949
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * @file ReByteBuffer.hpp
+ *
+ *  Created on: 06.05.2010
+ *      Author: wk
+ */
+
+#ifndef REBYTEBUFFER_H_
+#define REBYTEBUFFER_H_
+
+/** @brief An efficient dynamic memory buffer.
+ *
+ * Implements a very efficient dynamic byte sequence.
+ * <p>
+ * <strong>Note:</strong><br>
+ * It is guaranteed that the sequence is terminated by a '\\0' like C strings.
+ * This end marker is outside the visible buffer.<br/>
+ * Technically: <br/>
+ * <code>ReByteBuffer buf; assert(buf.getBuffer()[buf.getLength()] == '\\0');</code>
+ * </p>
+ * <p>This class can be used as a poor man's string class.
+ * </p>
+ * <p>Very effizient:
+ * <ul>
+ * <li>Every instance contains an array (512 Bytes),
+ *             which is used if not more space is needed.
+ *             In many cases there is no need of heap allocation (new or malloc().</li>
+ * <li>Many of the methods are written as inlines.</li>
+ * </ul>
+ * </p>
+ */
+class ReByteBuffer {
+public:
+       typedef char Byte;
+public:
+       ReByteBuffer(size_t delta = 512);
+       ReByteBuffer(const char* source);
+       virtual ~ReByteBuffer();
+       ReByteBuffer(const ReByteBuffer& source);
+       ReByteBuffer& operator =(const ReByteBuffer& source);
+public:
+       ReByteBuffer& append(const Byte* source, size_t length = -1);
+       ReByteBuffer& append(ReByteBuffer& source);
+       ReByteBuffer& appendInt(int number, const char* format = "%d");
+       /** @brief Returns the n-th byte of the internal buffer.
+        * @param index         The index of the wanted byte.
+        * @return 0: Wrong index. Otherwise: The byte from the wanted position.
+        */
+       inline Byte at(size_t index) const {
+               return index >= m_length ? 0 : m_buffer[index];
+       }
+       int atoi(size_t start = 0, int end = -1) const;
+       void ensureSize(size_t size);
+       /** @brief Returns the buffer.
+        * @return The internal used buffer.
+        */
+       inline Byte* getBuffer() const{
+               return m_buffer;
+       }
+       /**@brief Returns the minimum allocation unit.
+        * @return The minimum of bytes to allocate.
+        */
+       inline size_t getDelta() const{
+               return m_delta;
+       }
+       /**@brief Returns the length of the buffer (the count of used bytes).
+        * @return The count of the allocated bytes in the internal buffer.
+        */
+       inline size_t getLength() const{
+               return m_length;
+       }
+       /**@brief Returns the current size of the internal buffer.
+        * @return The  current size of the internal buffer.
+        */
+       inline size_t getSize() const{
+               return m_size;
+       }
+       /** @brief Finds the index of the first occurrence of a given byte.
+        * @param toFind        This byte will be searched.
+        * @param start         The first index for searching.
+        * @return -1: not found. Otherwise: The index of the first occurrence.
+        */
+       inline int indexOf(Byte toFind, int start = 0) const {
+               while ((size_t) start < m_length)
+                       if (m_buffer[start++] == toFind)
+                               return start - 1;
+               return -1;
+       }
+       int indexOf(const Byte* toFind, size_t toFindLength, int start = 0) const;
+       /** @brief Inserts a byte sequence.
+        * @param ix    The position in the internal buffer for the insertion.
+        * @param source                        The sequence to insert.
+        * @param length                        The length of the inserted sequence.
+        *
+        * @return true: Success. false: <code>ix</code> out of range.
+        */
+       inline bool insert(size_t ix, const Byte* source, size_t length){
+               return splice(ix, 0, source, length);
+       }
+       /** @brief Cuts a sequence from the internal buffer.
+        *
+        * @param ix                            The index where the cut/insertion takes place.
+        * @param deletedLength         The number of deleted bytes.
+        *                                                      This value may be larger than the existing bytes.
+        *
+        * @return true: Success. false: <code>ix</code> out of range.
+        */
+       inline bool remove(size_t ix, size_t deletedLength){
+               return splice(ix, deletedLength, NULL, 0);
+       }
+       ReByteBuffer& replaceAll(const Byte* toFind, size_t toFindLength,
+                       const Byte* replacement, size_t replacementLength, int start = 0);
+       /** @brief Finds the index of the last occurrence of a given byte (reverse index of).
+        * @param toFind        This byte will be searched.
+        * @param start         The first index for searching. If &lt; 0: relative to the end.
+        * @return -1: not found. Otherwise: The index of the last occurrence.
+        */
+       inline int rindexOf(Byte toFind, int start = -1) const {
+               if (start < 0)
+                       start = m_length  + start;
+               while (start >= 0)
+                       if (m_buffer[start--] == toFind)
+                               return start + 1;
+               return -1;
+       }
+       /** @brief Sets the content of the buffer by copying a byte sequence.
+        * @param source        The byte sequence to copy.
+        * @param length        The length of <code>source</code>.
+        * @return *this (for chaining).
+        */
+       inline ReByteBuffer& set(const Byte* source, size_t length){
+               return setLength(0).append(source, length);
+       }
+       ReByteBuffer& setLength(size_t length);
+       ReByteBuffer& setLengthAndFill(size_t length, Byte filler = 0);
+
+       bool splice(size_t ix, size_t replacedLength, const Byte* source, size_t length);
+       /** @brief Returns the buffer content as C string.
+        * This is exactly the same result as from <code>getBuffer()</code>.
+        * @return The internal used buffer.
+        */
+       inline const char* str() const{
+               return (const char*) m_buffer;
+       }
+protected:
+               // The minimum difference between old and new size after a new allocation.
+       size_t          m_delta;
+               //@ If the needed space is small enough this buffer will be used.
+       char            m_primaryBuffer[512];
+               //@ The internal buffer. Points to <code>m_primaryBuffer</code> if the space is small enough.
+       char*           m_buffer;
+               //@ The used bytes in <code>m_buffer</code>.
+       size_t          m_length;
+               //@ The size of <code>m_buffer</code>.
+       size_t          m_size;
+};
+
+#endif /* REBYTEBUFFER_H_ */
diff --git a/base/ReCString.cpp b/base/ReCString.cpp
new file mode 100644 (file)
index 0000000..95b0a2b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * ReString.cpp
+ *
+ *  Created on: 05.05.2010
+ *      Author: wk
+ */
+
+#include "../base/restring.hpp"
+
+/** @brief Replaces a substring by another.
+ *
+ * Cuts a substring from a string and inserts another substring.
+ *
+ * @param start                                In/Out: The string to change.
+ * @param bufferSize           The size of <code>start</code>.
+ * @param lengthReplaced       The length of the substring to cut.
+ * @param newString                    The string which will be inserted.
+ */
+void replaceSubstring(char* start, size_t bufferSize, size_t lengthReplaced,
+       const char* newString)
+{
+       size_t lengthNew = strlen(newString);
+       char* tail = start + lengthReplaced;
+       size_t lengthTail = strlen(tail) + 1;
+
+       if (lengthNew <= lengthReplaced){
+               // The string will not be longer:
+               memcpy(start, newString, lengthNew);
+               if (lengthNew < lengthReplaced){
+                       memmove(start + lengthNew, tail, lengthTail);
+               }
+       } else {
+               // The string will be longer:
+               if (lengthTail + lengthNew - lengthReplaced > bufferSize)
+                       globalLogger()->sayF(LOG_ERROR|GRAN_USER|CAT_LIB, LC_CSTRING_REPLACE_1,
+                                       i18n("+++ The name size exceeds: $1 / $2\n"))
+                                       .arg(int(lengthTail + lengthNew - lengthReplaced)).arg((int) bufferSize)
+                                       .end();
+               else {
+                       memmove(start + lengthNew, tail, lengthTail);
+                       memcpy(start, newString, lengthNew);
+               }
+       }
+}
diff --git a/base/ReCString.hpp b/base/ReCString.hpp
new file mode 100644 (file)
index 0000000..7784b6d
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * ReString.h
+ *
+ *  Created on: 05.05.2010
+ *      Author: wk
+ */
+
+#ifndef RESTRING_H_
+#define RESTRING_H_
+
+void replaceSubstring(char* start, size_t bufferSize, size_t lengthReplaced,
+       const char* newString);
+#endif /* RESTRING_H_ */
diff --git a/base/ReConfigFile.cpp b/base/ReConfigFile.cpp
new file mode 100644 (file)
index 0000000..25b1210
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * @file ReConfigFile.cpp
+ *
+ * @brief Configuration file handling for *.ini files.
+ */
+
+#include "rebase.hpp"
+
+const char* ReConfigFile::m_trueValues = i18nm(";true;t;1;j;ja;yes;");
+const char* ReConfigFile::m_falseValues = i18nm(";false;f;0;n;nein;no;");
+
+/** @brief Constructor.
+ *
+ * @param filename     The name of the configuration file.
+ */
+ReConfigFile::ReConfigFile(const char* filename)
+       :
+       ReHashList(),
+       m_filename(),
+       m_valid(false)
+{
+       readFile(filename);
+}
+
+/** @brief Constructor.
+ *
+ * @param filename     The name of the configuration file.
+ */
+ReConfigFile::~ReConfigFile() {
+       m_valid = false;
+}
+
+/** @brief Reads the file content into the internal structure.
+ *
+ * If the file cannot be read the <code>m_valid</code> flag is set to false.
+ *
+ * @param filename     The name of the configuration file.
+ */
+void ReConfigFile::readFile(const char* filename){
+       m_valid = false;
+       m_filename.set(filename, -1);
+       clear();
+       FILE* fp = fopen(filename, "r");
+       char line[4096];
+       char* equal;
+       ReByteBuffer buffer;
+
+       if (fp != NULL){
+               int lineNo = 0;
+               while (fgets(line, sizeof line, fp) != NULL){
+                       lineNo++;
+                       if (isalnum(line[0]) && (equal = strchr(line, '=')) != NULL){
+                               size_t ix = strlen(line) - 1;
+                               // Remove all newlines:
+                               while (ix > 0 && isspace(line[ix])){
+                                       line[ix] = '\0';
+                                       ix--;
+                               }
+                               *equal = '\0';
+                               if (get(line, -1, buffer))
+                                       globalLogger()->sayF(LOG_ERROR | CAT_LIB, LC_CONFIGFILE_DOUBLE,
+                                               "$1-$2: Key is defined again: $3").arg(filename).arg(lineNo).arg(line).end();
+                               else
+                                       put(line, -1, equal + 1, -1);
+                       }
+               }
+               fclose(fp);
+       }
+}
+/** @brief Reads an integer from the configuration.
+ *
+ * @param key                  The key of the integer value.
+ * @param defaultVal   If the key could not found this value will be returned.
+ *
+ * @return The wanted integer or the default value.
+ */
+int ReConfigFile::getInteger(const char* key, int defaultVal){
+       ReByteBuffer value;
+       getString(key, value, NULL);
+       int rc = defaultVal;
+       if (! isdigit(value.at(0)))
+               globalLogger()->sayF(LOG_WARNING | CAT_LIB, LC_CONFIGFILE_NO_INT,
+                       "$1: Not an integer: $2 [$3]").arg(m_filename.str()).arg(value.str()).arg(key).end();
+       else
+               rc = value.atoi();
+       return rc;
+}
+/** @brief Reads a string from the configuration.
+ *
+ * @param key                  The key of the string value.
+ * @param buffer               Out: The buffer for the result string.
+ * @param defaultVal   If the key could not found this value will be returned. May be NULL.
+ */
+void ReConfigFile::getString(const char* key, ReByteBuffer& buffer, const char* defaultVal){
+       if (! get(key, -1, buffer)){
+               if (defaultVal == NULL)
+                       buffer.setLength(0);
+               else
+                       buffer.set(defaultVal, -1);
+       }
+}
+/** @brief Reads a boolean from the configuration.
+ *
+ * @param key                  The key of the boolean value.
+ * @param defaultVal   If the key could not found this value will be returned.
+ *
+ * @return The wanted boolean or the default value.
+ */
+bool ReConfigFile::getBool(const char* key, bool defaultVal){
+       ReByteBuffer value;
+       getString(key, value, NULL);
+       int rc = defaultVal;
+       if (ReStringUtils::isInList(value.str(), i18n(m_falseValues)))
+               rc = false;
+       else if (ReStringUtils::isInList(value.str(), i18n(m_trueValues)))
+               rc = true;
+       else
+               globalLogger()->sayF(LOG_WARNING | CAT_LIB, LC_CONFIGFILE_NO_BOOL,
+                       "$1: Not an boolean: $2 [$3] Allowed: $4$5").arg(m_filename.str())
+                       .arg(value.str()).arg(key).arg(i18n(m_falseValues))
+                       .arg(i18n(m_trueValues)).end();
+       return rc;
+}
+
+#if defined RE_TESTUNIT
+class TestReConfigFile : public ReTestUnit {
+       typedef ReHashList::Byte Byte;
+public:
+       TestReConfigFile() : ReTestUnit("ReConfigFile", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               testBasic();
+       }
+       void testBasic(){
+               createTestDir();
+               ReByteBuffer fn;
+               fn.append(getTestDir(), -1).append("reconfigfile.cfg", -1);
+               createFile(fn.str(), "#x.int=a\nx.int=1\nx.bool=true\nx.str=abc\nx.bool2=0\nstring=abc\n");
+               ReConfigFile config(fn.str());
+               checkT(config.isValid());
+               checkEqu(1, config.getInteger("x.int", 2));
+               checkEqu(2, config.getInteger("x.int2", 2));
+
+               checkT(config.getBool("x.bool", true));
+               checkT(config.getBool("x.bool", false));
+               checkT(config.getBool("y.bool", true));
+               checkF(config.getBool("y.bool", false));
+
+               checkF(config.getBool("x.bool2", true));
+               checkF(config.getBool("x.bool2", false));
+
+               ReByteBuffer buffer;
+               config.getString("string", buffer, "x");
+               checkEqu("abc", buffer.str());
+               config.getString("string1", buffer, "x");
+               checkEqu("x", buffer.str());
+       }
+};
+extern void testReConfigFile(void);
+
+void testReConfigFile(void){
+       TestReConfigFile unit;
+}
+#endif /*RE_TESTUNIT*/
diff --git a/base/ReConfigFile.hpp b/base/ReConfigFile.hpp
new file mode 100644 (file)
index 0000000..c8ac063
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * ReConfigFile.h
+ *
+ *  Created on: 18.05.2010
+ *      Author: wk
+ */
+
+#ifndef RECONFIGFILE_H_
+#define RECONFIGFILE_H_
+
+class ReConfigFile : protected ReHashList {
+public:
+       static const char* m_trueValues;
+       static const char* m_falseValues;
+public:
+       ReConfigFile(const char* filename);
+       virtual ~ReConfigFile();
+private:
+       //@ Not implemented and forbidden!
+       ReConfigFile(const ReConfigFile& source);
+       //@ Not implemented and forbidden!
+       ReConfigFile& operator =(const ReConfigFile& source);
+public:
+       void readFile(const char* filename);
+       int getInteger(const char* key, int defaultVal = 0);
+       void getString(const char* key, ReByteBuffer& buffer, const char* defaultVal = NULL);
+       bool getBool(const char* key, bool defaultVal = false);
+       /** @brief Returns whether the instance is in a valid state.
+        * @return true: The configuration is valid. false: Otherwise.
+        */
+       inline bool isValid() const {
+               return m_valid;
+       }
+protected:
+       ReByteBuffer    m_filename;
+       bool                    m_valid;
+};
+
+#endif /* RECONFIGFILE_H_ */
diff --git a/base/ReDirectory.cpp b/base/ReDirectory.cpp
new file mode 100644 (file)
index 0000000..73c1222
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * ReFileUtils.cpp
+ *
+ *  Created on: 16.05.2010
+ *      Author: wk
+ */
+
+#include "rebase.hpp"
+
+
+/** @brief Constructor.
+ */
+ReDirectory::ReDirectory()
+       :
+       m_valid(false),
+       m_dir(NULL),
+       m_path(),
+       m_entry(NULL),
+       m_pattern(),
+       m_isRegExpr(false),
+       m_regExprFlags(0)
+{
+}
+/** @brief Constructor.
+ *
+ * @param path         The path of the directory.
+ */
+ReDirectory::ReDirectory(const char* path)
+       :
+       m_valid(false),
+       m_dir(NULL),
+       m_path(),
+       m_entry(NULL),
+       m_pattern(),
+       m_isRegExpr(false),
+       m_regExprFlags(0)
+{
+       setDir(path);
+}
+/** @brief Destructor.
+ */
+ReDirectory::~ReDirectory(){
+       if (m_dir != NULL){
+               closedir(m_dir);
+               m_dir = NULL;
+               m_valid = false;
+       }
+}
+/** @brief Sets the directory.
+ *
+ * @param path         The name of the directory.
+ */
+void ReDirectory::setDir(const char* path){
+       if (m_dir != NULL){
+               closedir(m_dir);
+               m_dir = NULL;
+       }
+       m_entry = NULL;
+       m_path.set(path, -1);
+       m_dir = opendir(path);
+       m_valid = m_dir != NULL;
+       if (m_valid){
+               if (m_path.at(m_path.getLength() - 1) != ReStringUtils::pathSeparator())
+                       m_path.append(ReStringUtils::pathSeparatorStr(), 1);
+       }
+}
+/** @brief Returns the name of the directory.
+ *
+ * @return The name of the directory.
+ */
+const char* ReDirectory::getDir(void) const {
+       return m_path.getBuffer();
+}
+
+/** @brief Tests whether the directory state is valid.
+ *
+ * @return true: The instance is OK. false: Some error has occurred.
+ */
+bool ReDirectory::isValid(){
+       return m_valid;
+}
+/** @brief Sets the flags of the regular expression handling.
+ *
+ * @param flags                Usefull flags are: REG_ICASE: ignore case.
+ */
+void ReDirectory::setRegExprFlags(int flags){
+       m_regExprFlags = flags;
+}
+
+/** @brief Find the first file with a given filename pattern.
+ *
+ * @param pattern              A filename pattern.
+ * @param isRegExpr            true: The pattern contains regular expressions. false: The pattern contains wildcards.
+ *
+ * @return true: A file has been found. false: The directory contains no file with the given pattern.
+ */
+bool ReDirectory::findFirst(const char* pattern, bool isRegExpr){
+       bool rc = false;
+       if (m_valid){
+               m_pattern.set(pattern, -1);
+               m_isRegExpr = isRegExpr;
+               if (isRegExpr){
+                       int rc2 = regcomp(&m_regExpr, pattern, m_regExprFlags);
+
+                       if (rc2 != 0){
+                               rc = false;
+                       } else {
+                               rewinddir(m_dir);
+                               m_entry = NULL;
+                               rc = findNext();
+                       }
+               } else {
+                       rewinddir(m_dir);
+                       m_entry = NULL;
+                       rc = findNext();
+               }
+       }
+       return rc;
+}
+/** @brief Find the next file with the pattern defined with the last <code>findFirst()</code> call.
+ *
+ * @return true: A file has been found. false: The directory contains no more file with the given pattern.
+ */
+bool ReDirectory::findNext(){
+       bool rc = false;
+       if (m_valid){
+               while (! rc &&  (m_entry = readdir(m_dir)) != NULL){
+                       if (m_isRegExpr){
+                               regmatch_t match[10];
+                               int rc2 = regexec (&m_regExpr, m_entry->d_name, sizeof match / sizeof match[0], match, 0);
+                               if (rc2 == 0)
+                                       rc = true;
+                       } else {
+                               if (fnmatch(m_pattern.str(), m_entry->d_name, 0) == 0)
+                                       rc = true;
+                       }
+               }
+       }
+       return rc;
+}
+/** @brief Finds the file with the youngest modification date.
+ *
+ * The other search criteria will be set by the preceding call of <code>findFirst()</code>.
+ *
+ * @param filename     Out: "": No file found. Otherwise: The name of the youngest file.
+ *
+ * @param false: No file found. true: A file was found.
+ */
+bool ReDirectory::findYoungest(ReByteBuffer& filename){
+       bool rc = false;
+       filename.setLength(0);
+       if (m_entry != NULL)
+       {
+               ReByteBuffer fullname;
+               fullname.append(m_path);
+               size_t length = fullname.getLength();
+               struct stat info;
+               timespec youngest;
+               youngest.tv_sec = youngest.tv_nsec = 0;
+               do{
+                       fullname.setLength(length);
+                       fullname.append(m_entry->d_name, -1);
+                       if (stat(fullname.str(), &info) == 0
+                                       && (info.st_mtim.tv_sec > youngest.tv_sec
+                                               || (info.st_mtim.tv_sec == youngest.tv_sec
+                                                       && info.st_mtim.tv_nsec > youngest.tv_nsec))){
+                               youngest = info.st_mtim;
+                               filename.set(m_entry->d_name, -1);
+                               rc = true;
+                       }
+
+               } while(findNext());
+       }
+       return rc;
+}
+/** @brief Returns the name of the current file found by the last <code>findFirst()</code>
+ * or <code>findNext()</code>.
+ *
+ * @return NULL: No current file exists. Otherwise: The name of the current file.
+ *
+ */
+const char* ReDirectory::currentFile(){
+       const char* rc = m_entry == NULL ? NULL : m_entry->d_name;
+       return rc;
+}
+/** @brief Returns the full path of the current file or a given node.
+ *
+ * The current file is the file found by the last call of <code>findFirst()</code> or <code>findNext()</code>.
+ *
+ * @param path Out: The buffer for the full filename.
+ *                             If there is no current file the filename is empty.
+ * @param name NULL: The current file will be extended by the directory's path.
+ *                             Otherwise: This name will be extended by the directory's path.
+ *
+ * @return <code>path</code> (for chaining).
+ */
+ReByteBuffer& ReDirectory::fullpath(ReByteBuffer& path, const char* name){
+       path.setLength(0);
+       if (name != NULL){
+               path.append(m_path);
+               path.append(name, -1);
+       } else if (m_valid && m_entry != NULL){
+               path.append(m_path);
+               path.append(m_entry->d_name, -1);
+       }
+       return path;
+}
+
+/** @brief Find the first file matching a given filename pattern.
+ *
+ * @param dir                  The directory handle.
+ * @param pattern              The pattern for the searched files. May contain wildcards.
+ * @param useRegExpr   True: <code>pattern</code> is a regular expression.
+ */
+
+#if defined RE_TESTUNIT
+class TestReDirectory : public ReTestUnit {
+public:
+       TestReDirectory() : ReTestUnit("ReFileFinder", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               createTestDir();
+               ReByteBuffer dir;
+               dir.set(getTestDir(), -1);
+               ReByteBuffer file1 = dir;
+               file1.append("abc.1.txt", -1);
+               createFile(file1.str(), "abc1");
+
+               ReByteBuffer file2 = dir;
+               file2.append("abc.2.txt", -1);
+               createFile(file2.str(), "abc2");
+
+               ReDirectory finder(dir.str());
+               checkT(finder.isValid());
+
+               checkT(finder.findFirst("abc.*.txt", false));
+               checkEqu("abc.1.txt", finder.currentFile());
+               checkT(finder.findNext());
+               checkEqu("abc.2.txt", finder.currentFile());
+               checkF(finder.findNext());
+               checkF(finder.findFirst("abx.*.txt", false));
+
+               checkT(finder.findFirst("abc[.][0-9][.]txt", true));
+               checkEqu("abc.1.txt", finder.currentFile());
+               checkT(finder.findNext());
+               checkEqu("abc.2.txt", finder.currentFile());
+               checkF(finder.findNext());
+               checkF(finder.findFirst("abx[.][0-9][.]txt", true));
+       }
+};
+extern void testReDirectory(void);
+
+void testReDirectory(void){
+       TestReDirectory unit;
+}
+#endif /*RE_TESTUNIT*/
diff --git a/base/ReDirectory.hpp b/base/ReDirectory.hpp
new file mode 100644 (file)
index 0000000..3e93a43
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * ReFileUtils.h
+ *
+ *  Created on: 16.05.2010
+ *      Author: wk
+ */
+
+#ifndef REFILEFINDER_H_
+#define REFILEFINDER_H_
+
+/** <code>ReDirectory</code> searches files using pattern matching and/or file date.
+ */
+class ReDirectory{
+public:
+       ReDirectory();
+       ReDirectory(const char* path);
+       ~ReDirectory();
+public:
+       void setDir(const char* path);
+       const char* getDir(void) const;
+       bool isValid();
+       void setRegExprFlags(int flags);
+       bool findFirst(const char* pattern, bool isRegExpr);
+       bool findNext();
+       bool findYoungest(ReByteBuffer& filename);
+       const char* currentFile();
+       ReByteBuffer& fullpath(ReByteBuffer& path, const char* name = NULL);
+private:
+               //@ true: The directory is ok. false: The directory is undefined.
+       bool                            m_valid;
+       DIR*                            m_dir;
+               //@ The name of the current directory. Always ends with slash!
+       ReByteBuffer            m_path;
+       struct dirent*          m_entry;
+       ReByteBuffer            m_pattern;
+       bool                            m_isRegExpr;
+       regex_t                         m_regExpr;
+               // Flags for the regular expressions: REG_ICASE: ignore Case.
+       int                                     m_regExprFlags;
+};
+#endif /* REFILEFINDER_H_ */
diff --git a/base/ReException.cpp b/base/ReException.cpp
new file mode 100644 (file)
index 0000000..7876bf8
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * ReException.cpp
+ *
+ *  Created on: 07.05.2010
+ *      Author: wk
+ */
+
+#include "rebase.hpp"
+
+/** @brief Constructor.
+ *
+ * This constructor is for derived classes only.
+ * The constructor of the derived class must fill the <code>m_message</code>.
+ */
+ReException::ReException()
+       :
+       m_message(NULL)
+{
+}
+
+/** @brief Constructor.
+ *
+ * @param message      The error message.
+ */
+ReException::ReException(const char* message)
+       :
+       m_message(strdup(message))
+{
+}
+/** @brief Constructor.
+ *
+ * @param message      The error message.
+ * @param file         The name of the file where the exception is thrown.
+ * @param lineNo       The line no name of the file where the exception is thrown.
+ */
+ReException::ReException(const char* message, const char* file, int lineNo)
+       :
+       m_message(NULL)
+{
+       char buffer[512];
+       snprintf(buffer, sizeof buffer, "%s [%.100s-%d]", message, file, lineNo);
+       m_message = strdup(buffer);
+}
+/** @brief Destructor.
+ */
+ReException::~ReException(){
+       if (m_message != NULL)
+               free((void*)m_message);
+}
+
+ReException::ReException(const ReException& source)
+       :
+       m_message(strdup(source.getMessage()))
+{
+}
+ReException& ReException::operator =(const ReException& source){
+       if (m_message != NULL)
+               free((void*) m_message);
+       m_message = strdup(source.getMessage());
+       return *this;
+}
+
+/** @brief Constructor.
+ *
+ * @param message      The error message.
+ * @param format       The format string with the error.
+ */
+
+ReFormatException::ReFormatException(const char* message, const char* format)
+       :
+       ReException()
+{
+       char buffer[512];
+       snprintf(buffer, sizeof buffer, "%s%s", message, format == NULL ? "" : format);
+       m_message = strdup(buffer);
+
+}
+/** @brief Constructor.
+ *
+ * @param message      The error message.
+ * @param format       The format string with the error.
+ * @param file         The name of the file where the exception is thrown.
+ * @param lineNo       The line no name of the file where the exception is thrown.
+ */
+ReFormatException::ReFormatException(const char* message, const char* format,
+       const char* file, int lineNo)
+       :
+       ReException()
+{
+       char buffer[512];
+       snprintf(buffer, sizeof buffer, "%s%s [%.100s-%d]",
+               message, format == NULL ? "" : format, file, lineNo);
+       m_message = strdup(buffer);
+}
+
+/** @brief Constructor.
+ *
+ * @param name         Name of the array.
+ * @param index                The index which violates the array bounds.
+ * @param bound                The bound of the array: upper or lower.
+ */
+ReBoundsException::ReBoundsException(const char* name, int index, int bound)
+{
+       char buffer[256];
+       const char* format = index < bound
+               ? i18n("%s: index underflow: %d / %d") : i18n("%s: index overflow: %d / %d");
+       snprintf(buffer, sizeof buffer, format, name, index, bound);
+       m_message = strdup(buffer);
+}
+/** @brief Constructor.
+ *
+ * @param name         Name of the array.
+ * @param index                The index which violates the array bounds.
+ * @param bound                The bound of the array: upper or lower.
+ * @param file         The name of the file where the exception is thrown.
+ * @param lineNo       The line no name of the file where the exception is thrown.
+ */
+ReBoundsException::ReBoundsException(const char* name, int index, int bound, const char* file, int line)
+       :
+       ReException()
+{
+       char buffer[256];
+       const char* format = index < bound
+               ? i18n("%s: index underflow: %d / %d [%s-%d]") : i18n("%s: index overflow: %d / %d [%s-%d]");
+       snprintf(buffer, sizeof buffer, format, name, index, bound, file, line);
+       m_message = strdup(buffer);
+}
+
+#if defined RE_TESTUNIT
+class TestReException : public ReTestUnit, public ReVarArgTrigger {
+public:
+       TestReException()
+               :
+               ReTestUnit("ReException", __FILE__),
+               m_argNo(0),
+               m_maxNo(0)
+       {
+               run();
+       }
+       virtual void newArg(int no, int maxNo){
+               m_argNo = no;
+               m_maxNo = maxNo;
+       }
+private:
+       void run(){
+               try{
+                       throw ReException("ReException");
+                       checkT(false);
+               } catch (ReException& e){
+                       log(false, e.getMessage());
+               }
+               try{
+                       throw ReException("ReException", __FILE__, __LINE__);
+                       checkT(false);
+               } catch (ReException& e){
+                       log(false, e.getMessage());
+               }
+               try{
+                       throw ReFormatException("ReFormatException", "format");
+                       checkT(false);
+               } catch (ReException& e){
+                       log(false, e.getMessage());
+               }
+               try{
+                       throw ReFormatException("ReFormatException", "format",  __FILE__, __LINE__);
+                       checkT(false);
+               } catch (ReException& e){
+                       log(false, e.getMessage());
+               }
+               try{
+                       throw ReBoundsException("myArray", 101, 100);
+                       checkT(false);
+               } catch (ReException& e){
+                       log(false, e.getMessage());
+               }
+
+               try{
+                       throw ReBoundsException("myArray", -1, 0,  __FILE__, __LINE__);
+                       checkT(false);
+               } catch (ReException& e){
+                       log(false, e.getMessage());
+               }
+
+       }
+private:
+       int m_argNo;
+       int m_maxNo;
+};
+extern void testReException(void);
+
+void testReException(void){
+       TestReException unit;
+}
+#endif /*RE_TESTUNIT*/
+
diff --git a/base/ReException.hpp b/base/ReException.hpp
new file mode 100644 (file)
index 0000000..2aa09ec
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * ReException.h
+ *
+ *  Created on: 07.05.2010
+ *      Author: wk
+ */
+
+#ifndef REEXCEPTION_H_
+#define REEXCEPTION_H_
+
+/** The base exception.
+ */
+class ReException {
+public:
+       ReException(const char* message);
+       ReException(const char* message, const char* file, int line);
+       virtual ~ReException();
+public:
+       ReException(const ReException& source);
+       ReException& operator =(const ReException& source);
+protected:
+       ReException();
+public:
+       /** @brief Sets the message.
+        * @param message The new message.
+        */
+       inline void setMessage(const char* message){
+               if (m_message != NULL)
+                       free((void *) m_message);
+               m_message = strdup(message);
+       }
+       /** @brief Returns the message.
+        * @returns The description of the exception.
+        */
+       inline const char* getMessage() const{
+               return m_message;
+       }
+protected:
+       const char* m_message;
+};
+/** This exception is used on format errors.
+ */
+class ReFormatException : public ReException{
+public:
+       ReFormatException(const char* message, const char* format);
+       ReFormatException(const char* message, const char* format, const char* file, int line);
+};
+/** This exception is called when an index underflow or overflow is done.
+ */
+class ReBoundsException : public ReException{
+public:
+       ReBoundsException(const char* name, int index, int bound);
+       ReBoundsException(const char* name, int index, int bound, const char* file, int line);
+};
+
+#endif /* REEXCEPTION_H_ */
diff --git a/base/ReHashList.cpp b/base/ReHashList.cpp
new file mode 100644 (file)
index 0000000..88b9501
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * ReStringList.cpp
+ *
+ *  Created on: 18.05.2010
+ *      Author: wk
+ */
+
+#include "rebase.hpp"
+
+/** Constructor.
+ */
+ReHashList::ReHashList()
+       :
+       m_keys(),
+       m_values()
+{
+}
+/** Destructor
+ */
+ReHashList::~ReHashList() {
+}
+
+/** @brief Puts a key value pair into the hashlist.
+ *
+ * @param key                  The key byte sequence.
+ * @param keyLength            The length of <code>key</code>.
+ * @param value                        The value byte sequence.
+ * @param valueLength  The length of <code>value</code>.
+ */
+void ReHashList::put(const Byte* key, size_t keyLength,
+               const Byte* value, size_t valueLength){
+       if (keyLength == (size_t) -1)
+               keyLength = strlen(key) + 1;
+       if (valueLength == (size_t) -1)
+               valueLength = strlen(value) + 1;
+       int ix = find(key, keyLength);
+       bool storeValue = false;
+       if (ix < 0){
+               ReSeqList::Index pos = m_values.getLength();
+               storeValue = true;
+               m_keys.add(-1, key, keyLength, pos);
+       } else {
+               Sequence* seq = m_keys.getInfo(ix);
+               // m_tag contains the index into <code>m_values</code>.
+               Byte* ptr = m_values.getBuffer() + seq->m_tag;
+               size_t valLength = * (size_t *) ptr;
+               // Can we take the old storage?
+               if (valLength >= valueLength){
+                       // Yes, it is enough space:
+                       * (size_t *) ptr = valueLength;
+                       ptr += sizeof (size_t);
+                       memcpy(ptr, value, valueLength);
+               } else {
+                       storeValue = true;
+                       seq->m_tag = m_values.getLength();
+               }
+       }
+       if (storeValue){
+               m_values.append((Byte*) &valueLength, sizeof valueLength);
+               m_values.append(value, valueLength);
+       }
+}
+/** @brief Puts a key value pair into the hashlist.
+ *
+ * @param key                  The key. This is a C string.
+ * @param value                        The value. This is a C string.
+ */
+void ReHashList::put(const char* key, const char* value){
+       put(key, -1, value, -1);
+}
+/** @brief Puts a key value pair into the hashlist.
+ *
+ * @param key                  The key.
+ * @param value                        The value.
+ */
+void ReHashList::put(const ReByteBuffer& key, const ReByteBuffer& value){
+       put(key.getBuffer(), key.getLength(), value.getBuffer(), value.getLength());
+}
+/** @brief Returns the value of a key value pair.
+ *
+ * @param key                  The key byte sequence.
+ * @param keyLength            The length of <code>key</code>.
+ * @param value                        Out: The buffer for the value.
+ *
+ * @return false: The key was not found. true: The key was found.
+ */
+bool ReHashList::get(const Byte* key, size_t keyLength,
+               ReByteBuffer& value) const{
+       if (keyLength == (size_t) -1)
+               keyLength = strlen(key) + 1;
+
+       int ix = find(key, keyLength);
+       bool rc = ix >= 0;
+       if (rc){
+               ReSeqList::Sequence* seq = m_keys.getInfo(ix);
+               // m_tag contains the index into m_values:
+               Byte* ptr = m_values.getBuffer() + seq->m_tag;
+               // m_values contains <length><sequence>:
+               size_t valLength = * (size_t*) ptr;
+               ptr += sizeof (size_t);
+               value.set(ptr, valLength);
+       }
+       return rc;
+}
+/** @brief Returns the value of a key value pair.
+ *
+ * @param key                  The key.
+ * @param value                        Out: The buffer for the value.
+ *
+ * @return false: The key was not found. true: The key was found.
+ */
+bool ReHashList::get(const ReByteBuffer& key,
+               ReByteBuffer value) const{
+       bool rc = get(key.getBuffer(), key.getLength(), value);
+       return rc;
+}
+/** @brief Deletes all entries in the list.
+ */
+void ReHashList::clear(){
+       m_keys.clear();
+       m_values.setLength(0);
+}
+
+/** @brief Implements an iterator.
+ *
+ * Returns the next item with its key and/or its value.
+ *
+ * @param position     In/Out: The position of the next item. Set it to 0 for the first item.
+ * @param key          Out: The key of the found item. If NULL the key is not interesting.
+ * @param value                Out: The value of the found item. If NULL the value is not interesting.
+ *
+ * @param true: An item was found. false: No more items.
+ */
+bool ReHashList::next(size_t& position, ReByteBuffer* key, ReByteBuffer* value){
+       bool rc = position < m_keys.getCount();
+       if (rc){
+               ReSeqList::Sequence* seq = m_keys.getInfo(position++);
+               if (key != NULL){
+                       const Byte* ptr = m_keys.getContent() + seq->m_index;
+                       key->setLength(seq->m_length);
+                       memcpy(key->getBuffer(), ptr, seq->m_length);
+               }
+               if (value != NULL){
+                       const Byte* ptr = m_values.getBuffer() + seq->m_tag;
+                       size_t length = * (size_t*) ptr;
+                       ptr += sizeof (size_t);
+                       value->setLength(length);
+                       memcpy(value->getBuffer(), ptr, length);
+               }
+       }
+       return rc;
+}
+
+/** @brief Returns the index of key.
+ *
+ * @param key          The byte sequence of the key.
+ * @param length       The length of <code>key</code>.
+ *
+ * @return: -1: The key was not found. Otherwise: The index of the key in the key sequence array.
+ */
+int ReHashList::find(const Byte* key, size_t length) const{
+       if (length == (size_t) -1)
+               length = strlen(key) + 1;
+       int rc = -1;
+       int count = m_keys.getCount();
+       for (int ii = 0; rc < 0 && ii < count; ii++){
+               ReSeqList::Sequence* seq = m_keys.getInfo(ii);
+               if (seq->m_length == length){
+                       const Byte* ptr = m_keys.getContent() + seq->m_index;
+                       if (memcmp(ptr, key, length) == 0)
+                               rc = ii;
+               }
+       }
+       return rc;
+}
+
+#if defined RE_TESTUNIT
+class TestReHashList : public ReTestUnit {
+public:
+       TestReHashList() : ReTestUnit("ReHashList", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               testBasic();
+               testNext();
+       }
+       void testBasic(){
+               ReHashList hash;
+               ReByteBuffer key, value;
+
+               hash.put("abc", "123");
+               checkT(hash.get("abc", -1, value));
+               checkEqu("123", value.str());
+
+               hash.put("ab", "999");
+               checkT(hash.get("ab", -1, value));
+               checkEqu("999", value.str());
+
+               checkT(hash.get("abc", -1, value));
+               checkEqu("123", value.str());
+
+               hash.put("abc", "!!!");
+               checkT(hash.get("abc", -1, value));
+               checkEqu("!!!", value.str());
+
+               checkT(hash.get("ab", -1, value));
+               checkEqu("999", value.str());
+
+               hash.put("abc", "longer");
+               checkT(hash.get("abc", -1, value));
+               checkEqu("longer", value.str());
+
+               checkT(hash.get("ab", -1, value));
+               checkEqu("999", value.str());
+       }
+       void testNext(){
+               ReHashList hash;
+               hash.put("1", "8");
+               hash.put("2", "4");
+               hash.put("4", "2");
+               hash.put("8", "1");
+               int flagsKey = 0;
+               int flagsVal = 0;
+               size_t pos = 0;
+               ReByteBuffer key, value;
+               while(hash.next(pos, &key, &value)){
+                       int x = atol(key.getBuffer());
+                       int y = atol(value.getBuffer());
+                       checkEqu(8, x * y);
+                       flagsKey += x;
+                       flagsVal += y;
+               }
+               checkEqu(15, flagsKey);
+               checkEqu(15, flagsVal);
+       }
+};
+extern void testReHashList(void);
+
+void testReHashList(void){
+       TestReHashList unit;
+}
+#endif /*RE_TESTUNIT*/
+
diff --git a/base/ReHashList.hpp b/base/ReHashList.hpp
new file mode 100644 (file)
index 0000000..09f5e86
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * ReStringList.h
+ *
+ *  Created on: 18.05.2010
+ *      Author: wk
+ */
+
+#ifndef REHASHLIST_H_
+#define REHASHLIST_H_
+
+/** @brief A (very) simple associative array.
+ * <p>An instance stores key value pairs.</p>
+ * <p>Keys and values are byte sequences. This includes c strings.
+ * </p>
+ */
+class ReHashList {
+public:
+       typedef char Byte;
+       typedef ReSeqList::Sequence Sequence;
+public:
+       ReHashList();
+       virtual ~ReHashList();
+public:
+       void clear();
+       bool get(const Byte* key, size_t keyLength, ReByteBuffer& value) const;
+       bool get(const ReByteBuffer& key, ReByteBuffer value) const;
+       bool next(size_t& position, ReByteBuffer* key, ReByteBuffer* val);
+       void put(const Byte* key, size_t keyLength, const Byte* value, size_t valueLength);
+       void put(const char* key, const char* value);
+       void put(const ReByteBuffer& key, const ReByteBuffer& value);
+protected:
+       int find(const Byte* key, size_t length) const;
+
+protected:
+               //@ Containing an array of keys.
+       ReSeqList               m_keys;
+               //@ Containing the values. The tag of <code>m_key</code> is the index
+               //@of the start position in <code>m_values</code>.
+       ReByteBuffer    m_values;
+};
+
+#endif /* REHASHLIST_H_ */
diff --git a/base/ReI18N.cpp b/base/ReI18N.cpp
new file mode 100644 (file)
index 0000000..c40a121
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * ReI18N.cpp
+ *
+ *  Created on: 22.05.2010
+ *      Author: wk
+ */
+
+#include "../base/restring.hpp"
+
+//@ The current language. If NULL no language has been chosen.
+ReI18N::LanguagePack*  ReI18N::m_current = 0;
+//@ An array of all available translation packages.
+ReI18N::LanguagePack   ReI18N::m_list[8];
+//@ The number of available translations.
+int                                            ReI18N::m_count = 0;
+//@ This instance will be used for convenient usage of <code>i18nf(const char* key)</code>
+//@ Because of this <code>i18nf(const char* key)</code> is not reentrant.
+ReVarArgs                              ReI18N::m_varArgs;
+
+
+/** @brief Initializes the module.
+ *
+ * The language will be chosen in the following order:
+ * <ul>
+ * <li>Environmentvariable  LC_MESSAGES</li>
+ * <li>Environmentvariable  LC_ALL</li>
+ * <li>Environmentvariable LANG</li>
+ * <li>Default language: here "de"</li>
+ * </ul>
+ */
+void ReI18N::init() {
+       static bool first = true;
+       if (first){
+               if (m_current == NULL)
+               first = false;
+               if (getenv("LC_MESSAGES") != NULL){
+                       changeLanguage(getenv("LC_MESSAGES"));
+               } else if (getenv("LC_ALL") != NULL){
+                       changeLanguage(getenv("LC_ALL"));
+               } else if (getenv("LANG") != NULL){
+                       changeLanguage(getenv("LANG"));
+               } else
+                       changeLanguage("de");
+       }
+}
+/** @brief Puts a language package to the language list.
+ *
+ * <pre><strong>Typical usage:</strong>
+ * <code>
+ * static Phrase s_de [] = {
+ *    { "Example", "Beispiel" },
+ *    { "Very short", "Sehr kurz" }
+ * };
+ * static bool s_init = ReI18N::registerLanguage("de", s_de);
+ * </code></pre>
+ *
+ * @param language             The id of the language: xx or xx_yy or xx_yy.zz
+ * @param translation  A list of pairs: English message (key) and translated message.
+ *                                             The entries are sorted by the English text.
+ * @param count                        The number of entries in <code>translation</code>.
+ * @return true        So it can used in an expression.
+ */
+bool ReI18N::registerLanguage(const char* language,
+               const Phrase translation[], size_t count){
+       if ((size_t) m_count < sizeof m_list / sizeof m_list[0]){
+               LanguagePack* lang = m_list + m_count++;
+               lang->m_language = language;
+               lang->m_translation = translation;
+               lang->m_count = count;
+       }
+       return true;
+}
+/** @brief: Change the current language package.
+ *
+ * The best matching language package will be chosen:
+ * <strong>Example:</strong>
+ * language is "de_de".
+ * If a package exists with the id "de_ch" it will be chosen.
+ * If not and "de.*" exists it will be choosenI
+ * If not and "de_*" exists it will be choosenI
+ *
+ *
+ * @param language     The wanted language: may be xx or xx_yy*
+ */
+void ReI18N::changeLanguage(const char* language){
+       int found = -1;
+       // Search for xx_yy*
+       if (strlen(language) >= 5){
+               for (int ii = 0; found < 0 && ii < m_count; ii++){
+                       if (strncmp(m_list[ii].m_language, language, 5) == 0)
+                               found = ii;
+               }
+       }
+       if (found < 0){
+               // Search for xx or xx.*:
+               for (int ii = 0; found < 0 && ii < m_count; ii++){
+                       const char* current = m_list[ii].m_language;
+                       if (ReStringUtils::strnicmp(current, language, 2) == 0
+                                       && (strlen(current) == 2
+                                               || (strlen(current) > 2 && current[2] == '.')))
+                               found = ii;
+               }
+       }
+       // Search for xx*
+       if (found < 0 && strlen(language) >= 5){
+               for (int ii = 0; found < 0 && ii < m_count; ii++){
+                       if (strncmp(m_list[ii].m_language, language, 2) == 0)
+                               found = ii;
+               }
+       }
+
+       if (found >= 0)
+               m_current = m_list + found;
+}
+
+static int compare(const void* i1, const void* i2){
+       const char* s1 = ((ReI18N::Phrase*) i1)->m_key;
+       const char* s2 = ((ReI18N::Phrase*) i2)->m_key;
+       return strcmp(s1, s2);
+}
+/** @brief Translates a string without placeholders.
+ *
+ * <strong>Note</strong>: Despite of being static this method
+ * is reentrant and threadsafe.
+ *
+ * @param key          The english text.
+ *
+ * @return     key: No translation could be found.
+ *                     Otherwise: The translated key.
+ */
+const char* ReI18N::tr(const char* key){
+       init();
+       const char* rc = key;
+       if (m_current != NULL){
+               Phrase current;
+               current.m_key = key;
+               Phrase* found = (Phrase*) bsearch(&current, m_current->m_translation,
+                               m_current->m_count, sizeof (Phrase), compare);
+               if (found != NULL)
+                       rc = found->m_value;
+       }
+       return rc;
+}
+/** @brief Translates a string with placeholders.
+ *
+ * <strong>Note</strong>: This method is not reentrant
+ * and not threadsafe. It uses a static buffer.
+ *
+ * <pre>Typical usage:
+ * <code>
+ * printf ("%s\n",
+ *    ReI18N.trF("Number of files: $1 Number of dirs: $2")
+ *       .arg(files).arg(dirs).asCString());
+ * </code></pre>
+ * @param key          The english text.
+ *
+ * @return     An variant argument instance for chaining.
+ */
+ReVarArgs&  ReI18N::trF(const char* key){
+       return trF(key, m_varArgs);
+}
+/** @brief Translates a string with placeholders.
+ *
+ * <strong>Note</strong>: This method is reentrant
+ * and threadsafe.
+ *
+ * <pre>Typical usage:
+ * <code>
+ * ReVarArgs args;
+ * printf ("%s\n",
+ *    ReI18N.trF("Number of files: $1 Number of dirs: $2", args)
+ *       .arg(files).arg(dirs).asCString());
+ * </code></pre>
+ * @param key          The english text.
+ * @param args         A buffer for the variant argument handling.
+ *
+ * @return     The variant argument instance <code>args</code> for chaining.
+ */
+ReVarArgs&  ReI18N::trF(const char* key, ReVarArgs& args){
+       init();
+       // We hide the method name tr. xgettext must not see tr()
+#define translate tr
+       args.reset(translate(key));
+       return args;
+}
+
+#if defined RE_TESTUNIT
+class TestReI18N : public ReTestUnit {
+public:
+       TestReI18N()
+               :
+               ReTestUnit("ReI18N", __FILE__)
+       {
+               run();
+       }
+private:
+       void run(){
+               checkEqu("dies ist ein Test", i18n("this is a test"));
+               checkEqu("eins: 1 zwei: 2", i18nf("one: $1 two: $2").arg(1).arg(2).asCString());
+
+       }
+};
+extern void testReI18N(void);
+
+void testReI18N(void){
+       TestReI18N unit;
+}
+#endif /*RE_TESTUNIT*/
+
+
diff --git a/base/ReI18N.hpp b/base/ReI18N.hpp
new file mode 100644 (file)
index 0000000..070d00e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * ReI18N.h
+ *
+ *  Created on: 22.05.2010
+ *      Author: wk
+ */
+
+#ifndef REI18N_H_
+#define REI18N_H_
+
+class ReI18N {
+public:
+       //@ Storage for the ISO language names (with trailing '\\0').
+       typedef struct { char m_id[3]; } Language;
+       typedef struct {
+               const char* m_key;
+               const char* m_value;
+       } Phrase;
+       typedef struct {
+               const char*     m_language;
+               const Phrase*   m_translation;
+               size_t                  m_count;
+       } LanguagePack;
+public:
+       static void init();
+       static bool registerLanguage(const char* language,
+               const Phrase translation[], size_t count);
+       static const char* tr(const char* key);
+       static ReVarArgs& trF(const char* key);
+       static ReVarArgs& trF(const char* key, ReVarArgs& args);
+       static void changeLanguage(const char* language);
+protected:
+       static LanguagePack*    m_current;
+       static LanguagePack             m_list[8];
+       static int                              m_count;
+       static ReVarArgs                m_varArgs;
+};
+inline const char* i18n(const char* key){
+       return ReI18N::tr(key);
+}
+//@ Translates a string into another language.
+//@ Not threadsafe, not reentrant.
+inline  ReVarArgs& i18nf(const char* key){
+       return ReI18N::trF(key);
+}
+//@ Translates a string into another language.
+//@ Threadsafe, reentrant.
+inline  ReVarArgs& i18nf(const char* key, ReVarArgs& args){
+       return ReI18N::trF(key, args);
+}
+//@ Use this macros for transformable strings in initializations of variables.
+#define i18nm(key) key
+#endif /* REI18N_H_ */
diff --git a/base/ReLogger.cpp b/base/ReLogger.cpp
new file mode 100644 (file)
index 0000000..9a2699f
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * ReLogger.cpp
+ *
+ *  Created on: 05.05.2010
+ *      Author: wk
+ */
+
+#include "rebase.hpp"
+
+
+ReLogger* ReLogger::m_globalLogger = NULL;
+
+/** @brief Returns the global logger.
+ *
+ * If no global logger exists a standard logger will be initialized
+ * and set to the global logger.
+ *
+ * @return The global logger.
+ */
+ReLogger* ReLogger::globalLogger(){
+       if (m_globalLogger == NULL){
+               ReStreamAppender* stream = new ReStreamAppender(stderr);
+               ReFileAppender* file = new ReFileAppender();
+               file->setConfig("globallogger", 5, 1000100);
+               m_globalLogger = new ReLogger();
+               m_globalLogger->addAppender(stream);
+               m_globalLogger->addAppender(file);
+       }
+       return m_globalLogger;
+}
+/** @brief Constructor.
+ */
+ReAppender::ReAppender()
+       :
+       m_errorCategories(CAT_ALL),
+       m_warningCategories(CAT_ALL),
+       m_infoCategories(CAT_ALL),
+       m_granularities(GRAN_ALL)
+{
+}
+/** @brief Destructor.
+ */
+ReAppender::~ReAppender(){
+
+}
+/** Tests whether the log message should be logged.
+ *
+ * @param mode         The specification of the current log message.
+ *
+ * @return true: The
+ */
+bool ReAppender::accept(ReClassCategoryGranularity mode){
+       ReLogCategory category = (ReLogCategory) (mode & CAT_ALL);
+       ReLogClass aClass = (ReLogClass) (mode & LOG_CLASS_ALL);
+       bool rc;
+
+       switch (aClass)
+       {
+       case LOG_ERROR:
+       case LOG_ABORT:
+               rc = (m_errorCategories & category) != 0;
+               break;
+       case LOG_WARNING:
+               rc = (m_warningCategories & category) != 0;
+               break;
+       default:
+       {
+               ReLogGranularity granularity = (ReLogGranularity) (mode & GRAN_ALL);
+               if (granularity == 0)
+                       granularity = GRAN_USER;
+
+               rc = (m_infoCategories & category) != 0
+                               && (m_granularities & granularity) != 0;
+               break;
+       }
+       }
+       return rc;
+}
+/** @brief Sets the mode parameters.
+ *
+ * @param errors               The categories in which error logging will be done.
+ * @param warnings             The categories in which warning logging will be done.
+ * @param info                 The categories in which info logging will be done.
+ * @param granularities        The granularities in which info logging will be done.
+ */
+void ReAppender::setMode(ReLogCategories errors, ReLogCategories warnings,
+                       ReLogCategories infos, ReLogGranularities granularities){
+       m_errorCategories = (errors & CAT_ALL);
+       m_warningCategories = (warnings & CAT_ALL);
+       m_infoCategories = (infos & CAT_ALL);
+       m_granularities = (granularities & GRAN_ALL);
+}
+
+/** @brief Constructor.
+ *
+ * @param stream       An open stream used for the output.
+ */
+ReStreamAppender::ReStreamAppender(FILE* stream)
+       :
+       ReAppender(),
+       m_stream(stream)
+{
+}
+/** @brief Destructor.
+ */
+ReStreamAppender::~ReStreamAppender(){
+}
+
+/** @brief Puts a message into the internal stream.
+ *
+ * @param logger               The logger calling the method.
+ * @param message              The message to write.
+ */
+void ReStreamAppender::say(ReLogger* logger, const char* message){
+       const char* prefix = logger->getStandardPrefix();
+       fputs(prefix, m_stream);
+       if (message != NULL)
+               fputs(message, m_stream);
+       else
+               fputs(logger->asCString(), m_stream);
+       fputc('\n', m_stream);
+       fflush(m_stream);
+}
+/** @brief Constructor.
+ */
+ReFileAppender::ReFileAppender()
+       :
+       ReStreamAppender(NULL),
+       //m_filePattern
+       m_maxFiles(10),
+       m_maxSize(1000000),
+       m_currentSize(0),
+       m_currentFileNo(0)
+{
+       strcpy(m_filePattern, "logger.*");
+}
+/** @brief Destructor.
+ */
+ReFileAppender::~ReFileAppender(){
+}
+
+/** @brief Sets the configuration data.
+ *
+ * @param pattern      A filename pattern. Should contain a '*' which will replaced
+ *                                     with a version number.
+ * @param maxFiles     Maximum number of logfiles. If more files exist they will be deleted.
+ * @param maxSize      Maximum size of one logfile.
+ *
+ */
+void ReFileAppender::setConfig(const char* pattern, int maxFiles, int maxSize){
+       const char* placeholder = "%04d";
+       m_maxFiles = maxFiles < 2 ? 2 : maxFiles;
+       m_maxSize = maxSize < 10 ? 10 : maxSize;
+
+       const char* first = strchr(pattern, '*');
+       size_t len;
+       if (first == NULL){
+               snprintf(m_filePattern, sizeof m_filePattern, "%s.%s.log", pattern, placeholder);
+       } else {
+               len = first - pattern;
+               memcpy(m_filePattern, pattern, len);
+               strcpy(m_filePattern + len, placeholder);
+               strcat(m_filePattern + len, first + 1);
+       }
+
+       ReByteBuffer fn, protocol, path, name, ext;
+       ReStringUtils::splitPath(m_filePattern, &protocol, &path, &name, &ext);
+       ReStringUtils::joinPath(fn, &protocol, &path, NULL, NULL);
+       if (fn.getLength() == 0)
+               fn.set(".", 1);
+       ReDirectory dir(fn.str());
+       if (! dir.isValid()){
+               fprintf(stderr, "%s\n", i18nf("$1: Not a valid directory: $2").arg(pattern).arg(dir.getDir()).asCString());
+               assert(! dir.isValid());
+       } else {
+               ReStringUtils::joinPath(fn, NULL, NULL, &name, &ext);
+               int ix = fn.indexOf(placeholder, -1, 0);
+               fn.splice(ix, 4, "[0-9]{4}", -1);
+
+               // Looking for the current logfile:
+               if (! dir.findFirst(fn.str(), true)){
+                       fn.splice(ix, 8, "0001", 4);
+                       m_currentFileNo = 1;
+               } else {
+                       dir.findYoungest(fn);
+                       m_currentFileNo = fn.atoi(ix, 4);
+               }
+               struct stat info;
+               ReByteBuffer fullname;
+               dir.fullpath(fullname, fn.str());
+               int rc = lstat(fullname.str(), &info);
+
+               if (rc == 0 && (m_currentSize = info.st_size) > m_maxSize)
+                       changeFile();
+               else{
+                       m_stream = fopen(fullname.str(), "a");
+                       assert(m_stream != NULL);
+               }
+       }
+}
+/** @brief Opens a new file for logging.
+ */
+void ReFileAppender::changeFile(){
+       if (m_stream != NULL){
+               fclose(m_stream);
+               m_stream = NULL;
+       }
+
+       char filename[512];
+       const size_t FILENO_UBOUND = 10000;
+
+       // Delete some of the oldest files to make room for the new:
+       for (int ii = 0; ii < int(FILENO_UBOUND - m_maxFiles); ii++){
+               int fileNo = (FILENO_UBOUND + m_currentFileNo - m_maxFiles - ii) % m_maxFiles;
+               snprintf(filename, sizeof filename, m_filePattern, fileNo);
+               struct stat info;
+               if (lstat(filename, &info) == 0)
+                       unlink(filename);
+               else
+                       break;
+       }
+       if (++m_currentFileNo >= FILENO_UBOUND)
+               m_currentFileNo = 0;
+       snprintf(filename, sizeof filename, m_filePattern, m_currentFileNo);
+       m_stream = fopen(filename, "w");
+       m_currentSize = 0;
+}
+/** @brief Constructor.
+ */
+ReLogger::ReLogger(bool isGlobal)
+       :
+       ReVarArgs(),
+       m_appenderList(new ReAppender* [8]),
+       m_appenderListSize(8),
+       m_appenderListLength(0),
+       // m_standardPrefix[64]
+       m_mode(0),
+       m_location(0),
+       m_stdConsoleAppender(NULL),
+       m_stdFileAppender(NULL),
+       m_locationOfOpenSayF(0)
+{
+       if (isGlobal)
+               m_globalLogger = this;
+       m_standardPrefix[0] = '\0';
+}
+/** @brief Destructor.
+ */
+ReLogger::~ReLogger(){
+       delete m_stdConsoleAppender;
+       m_stdConsoleAppender = NULL;
+       delete m_stdFileAppender;
+       m_stdFileAppender = NULL;
+
+       delete[] m_appenderList;
+       m_appenderList = NULL;
+       m_appenderListSize = 0;
+}
+/** @brief Issues a log message.
+ *
+ * The message will be put to all appenders which accept the log message.
+ *
+ * @param mode         The mode controlling the issuing of the logging.
+ *                                     This mode will be compared to the settings of the appenders.
+ * @param position     The identification of the call.
+ * @param message      The message to log.
+ *
+ * @return true
+ */
+bool ReLogger::say(ReClassCategoryGranularity mode, ReLogLocation location, const char* message){
+       m_mode = mode;
+       m_location = location;
+       m_standardPrefix[0] = '\0';
+
+       for (size_t ii = 0; ii < m_appenderListLength; ii++){
+               ReAppender* app = m_appenderList[ii];
+               if (app->accept(mode))
+                       app->say(this, message);
+       }
+       return true;
+}
+/** @brief Issues a formatted log message.
+ *
+ * The message will be put to all appenders which accept the log message.
+ * <strong>Note:</strong><br />
+ * Don't forget to finish the argument list with ReVarArgs::end()!
+ *
+ * @param mode         The mode controlling the issuing of the logging.
+ *                                     This mode will be compared to the settings of the appenders.
+ * @param location     The identification of the call.
+ * @param message      The message to log.
+ *
+ * @return true
+ */
+ReVarArgs& ReLogger::sayF(ReClassCategoryGranularity mode, ReLogLocation location,
+               const char* format){
+       if (m_locationOfOpenSayF != 0){
+               char message[128];
+               snprintf(message, sizeof message, "missing ReLogger::end(): Location: %d", m_locationOfOpenSayF);
+               say(LOG_ERROR|GRAN_USER|CAT_LIB, LC_LOGGER_SAYF_OPEN, message);
+       }
+       m_locationOfOpenSayF = location;
+       m_mode = mode;
+       m_location = location;
+       m_standardPrefix[0] = '\0';
+       reset(format);
+       return *this;
+}
+/** Adds an appender to the appender list.
+*
+* @param appender              The appender.
+*/
+void ReLogger::addAppender(ReAppender* appender){
+       if (m_appenderListLength >= m_appenderListSize)
+               throw ReBoundsException("appender list",
+                       m_appenderListLength + 1, m_appenderListSize,
+                       __FILE__, __LINE__);
+       m_appenderList[m_appenderListLength++] = appender;
+}
+
+/** Adds standard appenders to the appender list.
+*
+* @param console       true: A console appender will be added.
+* @param file          NULL: No file appender.
+*                                      Otherwise: A file appender will be appended.
+* @param maxFiles      The maximal count of log files produced by the file appender.
+* @param masSize       The maximal size of one log file produced by the file appender.
+*/
+void ReLogger::addStandardAppenders(bool console,
+               const char* file, int maxFiles, int maxSize){
+       if (console){
+               m_stdConsoleAppender = new ReStreamAppender(stdout);
+               addAppender(m_stdConsoleAppender);
+       }
+       if (file != NULL){
+               m_stdFileAppender = new ReFileAppender();
+               m_stdFileAppender->setConfig(file, maxFiles, maxSize);
+               addAppender(m_stdFileAppender);
+       }
+
+
+}
+
+/** @brief Returns the standard prefix of a log line.
+ *
+ * The standard prefix is log class, date, time, and location).
+ * Most of the appenders will use this prefix.
+ * It will be build on demand.
+ *
+ * @return The standard prefix.
+ */
+const char* ReLogger::getStandardPrefix(void){
+       if (m_standardPrefix[0] == 0)
+       {
+               char cc;
+               switch(m_mode & LOG_CLASS_ALL){
+               case LOG_ABORT:
+                       cc = '#';
+                       break;
+               case LOG_ERROR:
+                       cc = '!';
+                       break;
+               case LOG_WARNING:
+                       cc = '+';
+                       break;
+               default:
+                       cc = ' ';
+                       break;
+               }
+               m_standardPrefix[0] = cc;
+
+               time_t now = time(NULL);
+               struct tm* now1 = localtime(&now);
+               strftime(m_standardPrefix + 1, sizeof m_standardPrefix - 1,
+                               "%Y.%m.%d %H:%M:%S", now1);
+               size_t len = strlen(m_standardPrefix);
+               char* ptr = m_standardPrefix + len;
+               snprintf (ptr, sizeof m_standardPrefix - len, " %ld: ",
+                               (long) m_location);
+       }
+       return m_standardPrefix;
+}
+/** @brief Terminates the chain of <code>arg()</code> calls.
+ *
+ * This method puts the data to the (accepting) appenders.
+ *
+ */
+void ReLogger::end(void){
+       for (size_t ii = 0; ii < m_appenderListLength; ii++){
+               ReAppender* app = m_appenderList[ii];
+               if (app->accept(m_mode))
+                       app->say(this, NULL);
+       }
+       m_locationOfOpenSayF = 0;
+}
+
+#if defined RE_TESTUNIT
+class TestReLogger : public ReTestUnit {
+public:
+       TestReLogger() : ReTestUnit("ReLogger", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               ReStreamAppender app1(stdout);
+               app1.setMode(CAT_ALL, CAT_ALL, CAT_ALL, GRAN_ALL);
+
+               ReLogger logger;
+               logger.addAppender(&app1);
+               log(false, "2 Errors and a warning:");
+               logger.say(LOG_ABORT | CAT_TEST | GRAN_TRACE, __LINE__, "abort");;
+               logger.say(LOG_ERROR | CAT_TEST, __LINE__, "error");
+               logger.say(LOG_WARNING | CAT_TEST, __LINE__, "warning");
+
+               logger.sayF(CAT_TEST, __LINE__, "Two: $1 eleven: $021").arg(2).arg(1).end();
+               globalLogger()->say(CAT_LIB, __LINE__, "globalLogger()");
+       }
+};
+extern void testReLogger(void);
+
+void testReLogger(void){
+       TestReLogger unit;
+}
+#endif /*RE_TESTUNIT*/
+
diff --git a/base/ReLogger.hpp b/base/ReLogger.hpp
new file mode 100644 (file)
index 0000000..422adfc
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * ReLogger.h
+ *
+ *  Created on: 05.05.2010
+ *      Author: wk
+ */
+
+#ifndef RELOGGER_H_
+#define RELOGGER_H_
+
+/**
+ * Every call of the logger should have an unique id. This is the type for this.
+ */
+typedef unsigned long int ReLogLocation;
+/**
+ * The log messages can be divided in 4 classes:
+ * Aborts, errors, warnings and informations.
+ */
+enum ReLogClass{
+       LOG_ABORT       = 1,
+       LOG_ERROR       = 2,
+       LOG_WARNING = 4,
+       LOG_INFO        = 8,
+
+       LOG_CLASS_ALL = 0xf
+};
+/*
+ *
+ */
+typedef unsigned int ReSetOfClasses;
+/**
+ * The granularity allows to filter log messages under the aspect of the amount.
+ */
+enum ReLogGranularity{
+       GRAN_USER                       = 0x00000010,
+       GRAN_GURU                       = 0x00000020,
+       GRAN_DUMP                       = 0x00000040,
+       GRAN_TRACE                      = 0x00000080,
+       GRAN_SPECIAL_1          = 0x00000100,
+       GRAN_SPECIAL_2          = 0x00000200,
+       GRAN_SPECIAL_3          = 0x00000400,
+       GRAN_SPECIAL_4          = 0x00000800,
+
+       GRAN_ALL                        = 0x00000ff0
+};
+/** A (bitwise) combination of granularities.
+ */
+typedef unsigned long int ReLogGranularities;
+enum ReLogCategory{
+       CAT_START_STOP          = 0x00001000,
+       CAT_CONFIG                      = 0x00002000,
+       CAT_NETWORK                     = 0x00004000,
+       CAT_GUI                         = 0x00008000,
+       CAT_LIB                         = 0x00010000,
+       CAT_OS                          = 0x00020000,
+       CAT_FILE                        = 0x00040000,
+       CAT_PROG                        = 0x00080000,
+       CAT_RESOURCE            = 0x00100000,
+       CAT_TEST                        = 0x00200000,
+
+       CAT_ALL                         = 0xfffff000,
+};
+/** A (bitwise) combination of categories.
+ */
+typedef unsigned long int ReLogCategories;
+/** A (bitwise) combination of a class, a category and a granularity.
+ */
+typedef unsigned long int ReClassCategoryGranularity;
+class ReLogger;
+
+/**
+ * Implements an abstract base class for handling of the output of an logger.
+ */
+class ReAppender{
+public:
+       ReAppender();
+       virtual ~ReAppender();
+public:
+       virtual void say(ReLogger* logger, const char* message) = 0;
+       bool accept(ReClassCategoryGranularity mode);
+       void setMode(ReLogCategories errors, ReLogCategories warnings,
+                               ReLogCategories infos, ReLogGranularities granularities);
+protected:
+       ReLogCategories         m_errorCategories;
+       ReLogCategories         m_warningCategories;
+       ReLogCategories         m_infoCategories;
+       ReLogGranularities      m_granularities;
+};
+
+/**
+ * Implements a class which is writing log messages to a stream.
+ */
+class ReStreamAppender : public ReAppender{
+public:
+       ReStreamAppender(FILE* stream);
+       virtual ~ReStreamAppender();
+private:
+               // Not accessible, not implemented!
+       ReStreamAppender(const ReStreamAppender& source);
+               // Not accessible, not implemented!
+       ReStreamAppender& operator =(const ReStreamAppender& source);
+public:
+       virtual void say(ReLogger* logger, const char* message);
+protected:
+       FILE*   m_stream;
+};
+
+/**
+ * Implements a class which is writing log messages to a file.
+ */
+class ReFileAppender : public ReStreamAppender {
+public:
+       ReFileAppender();
+       virtual ~ReFileAppender();
+public:
+       void setConfig(const char* filename, int maxFiles, int maxSize);
+private:
+       void changeFile();
+
+protected:
+       char    m_filePattern[512];
+       size_t  m_maxFiles;
+       size_t  m_maxSize;
+       size_t  m_currentSize;
+       size_t  m_currentFileNo;
+};
+
+/** This class allows the logging of messages.
+ * The output itself is done by so called appenders.
+ * This allows a flexible handling of different media: files, dialog boxes, console...
+ * The message can be contain placeholders which will be replaced
+ * by computed data similar sprintf(), but in a typesafe way (@see sayF()).
+ */
+class ReLogger : public ReVarArgs {
+public:
+       static ReLogger* globalLogger();
+       static ReLogger* m_globalLogger;
+public:
+       ReLogger(bool isGlobal = true);
+       virtual ~ReLogger();
+private:
+               // Not accessible, not implemented!
+       ReLogger(const ReLogger& source);
+               // Not accessible, not implemented!
+       ReLogger& operator =(const ReLogger& source);
+public:
+       bool say(ReClassCategoryGranularity mode, ReLogLocation location, const char* message);
+       ReVarArgs& sayF(ReClassCategoryGranularity mode, ReLogLocation location, const char* format);
+       virtual void end(void);
+
+       void addAppender(ReAppender* appender);
+
+       const char* getStandardPrefix(void);
+       ReClassCategoryGranularity getCurrentMode(void) const;
+       int getCurrentPosition(void) const;
+       void addStandardAppenders(bool console, const char* file,
+                       int fileCount = 5, int fileSize = 1000100);
+protected:
+       ReAppender**    m_appenderList;
+       size_t                  m_appenderListSize;
+       size_t                  m_appenderListLength;
+       char                    m_standardPrefix[64];
+       ReClassCategoryGranularity m_mode;
+       ReLogLocation   m_location;
+       ReAppender*             m_stdConsoleAppender;
+       ReFileAppender* m_stdFileAppender;
+       int                             m_locationOfOpenSayF;
+};
+
+inline ReLogger* globalLogger() {
+       return ReLogger::globalLogger();
+}
+
+#endif /* RELOGGER_H_ */
diff --git a/base/ReProgramArgs.cpp b/base/ReProgramArgs.cpp
new file mode 100644 (file)
index 0000000..7deb6aa
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * ReProgramArgs.cpp
+ *
+ *  Created on: 25.05.2010
+ *      Author: wk
+ */
+
+#include "rebase.hpp"
+
+
+/** @brief Constructor.
+ *
+ * @param caller       The object which throw the exception.
+ * @param message      The error message with one or two placeholders.
+ * @param arg1         The first argument (for the first placeholder).
+ * @param arg2         The 2nd argument (for the 2nd placeholder). If NULL only one placeholder exists.
+*/
+ReOptionException::ReOptionException(ReProgramArgs* caller, const char* message,
+               const char* arg1, const char* arg2)
+       :
+       ReException()
+{
+       ReVarArgs args(message);
+       args.arg(arg1);
+       if (arg2 != NULL)
+               args.arg(arg2);
+       setMessage(args.asCString());
+       if (caller != NULL)
+               caller->setLastError(args.asCString());
+}
+
+/** @brief Constructor.
+ *
+ * @param usage                A string array with the description of the usage.
+ *                                     Every string will be issued in a separate line.
+ * @param examples     A string with one ore more calling examples.
+*                                      Every string will be issued in a separate line.
+*/
+ReProgramArgs::ReProgramArgs(const char* usageList[], const char* examples[])
+       :
+       m_usage(),
+       m_examples(),
+       m_properties(),
+       m_values(),
+       m_args(NULL),
+       m_argCount(0),
+       m_lastError()
+{
+       for (const char** argv = usageList; *argv != NULL; argv++){
+               m_usage.add(-1, *argv, -1);
+       }
+       if (examples != NULL){
+               for (const char** argv = examples; *argv != NULL; argv++){
+                       if (strncmp(*argv, "$0", 2) != 0)
+                               m_examples.append(*argv);
+                       else{
+                               ReByteBuffer line;
+                               line.append(m_program, -1);
+                               m_examples.append(line.str() + 2);
+                       }
+               }
+       }
+}
+/** @brief Constructor.
+ *
+ * @param usage                A string with the description of the usage.
+ *                                     It may contain <code>'\\n'</code> for separate lines.
+ * @param examples     A string with one ore more calling examples.
+ *                                     It may contain <code>'\\n'</code> for separate lines.
+*/
+ReProgramArgs::ReProgramArgs(const char* usageString, const char* examples)
+       :
+       m_usage(),
+       m_examples(),
+       m_properties(),
+       m_values(),
+       m_args(NULL),
+       m_argCount(0),
+       m_lastError()
+{
+       m_usage.split(usageString, '\n');
+       if (examples != NULL){
+               if (strstr(examples, "$0") != NULL)
+                       m_examples.split(examples, '\n');
+               else{
+                       ReByteBuffer line;
+                       line.append(examples, -1);
+                       line.replaceAll("$0", 2, m_program, -1);
+                       m_examples.split(line.str(), '\n');
+               }
+
+       }
+}
+/** @brief Destructor.
+ */
+ReProgramArgs::~ReProgramArgs() {
+}
+
+/** @brief Puts the property infos into the property string.
+ *
+ * The <strong>property string</strong> is a string stored in the hashlist.
+ * It contains all infos about the option but the current value.
+ *
+ * @param name                 The name of the option. Used in the methods <code>getInt()</code>, ...
+ * @param description  A short description of the option. Used in the user messages.
+ * @param shortOpt             The one character option identifier. Used in the arguments. Must be preceded by '-'.
+ * @param longOpt              The multi character option identifier.  Used in the arguments. Must be preceded by '--'.
+ * @param dataType             The data type of the option: DT_INT, DT_BOOL ...
+ * @param defaultValue The default value of the option.
+ * @param lengthValue  The length of <code>defaultValue</code>.
+ */
+void ReProgramArgs::addProperties(const char*name, const char* description, char shortOpt,
+               const char* longOpt, DataType dataType, const char* defaultValue, size_t lengthValue){
+       ReByteBuffer properties;
+       properties.append(description, strlen(description)).append("\1", 1);
+       properties.append(&shortOpt, 1).append("\1", 1);
+       properties.append(longOpt, strlen(longOpt)).append("\1", 1);
+       properties.append((char*) &dataType, 1).append("\1", 1);
+       properties.append(defaultValue, -1).append("\1", 1);
+       m_properties.put(name, properties.str());
+
+       // Mark current value as default:
+       properties.set("!", 1);
+       // Copy default value as current value:
+       properties.append(defaultValue, -1);
+       m_values.put(name, properties.str());
+}
+static const int IxDescr = 0;
+static const int IxShort = 1;
+static const int IxLong = 2;
+static const int IxType = 3;
+static const int IxDefault = 4;
+
+/** @brief Adds an option with an integer value.
+ *
+ * @param name                 The name of the option. Used in the methods <code>getInt()</code>.
+ * @param description  A short description of the option. Used in the user messages.
+ * @param shortOpt             The one character option identifier. Used in the arguments. Must be preceded by '-'.
+ * @param longOpt              The multi character option identifier.  Used in the arguments. Must be preceded by '--'.
+ * @param defaultValue The default value of the option.
+ *
+ * * @see getInt()
+ */
+void ReProgramArgs::addInt(const char* name, const char* description,
+               char shortOpt, const char* longOpt, int defaultVal){
+       ReByteBuffer number;
+       number.appendInt(defaultVal);
+       addProperties(name, description, shortOpt, longOpt, DT_INT,
+               number.str(), number.getLength());
+}
+
+/** @brief Adds an option with a boolean value.
+ *
+ * @param name                 The name of the option. Used in the methods <code>getBool()</code>.
+ * @param description  A short description of the option. Used in the user messages.
+ * @param shortOpt             The one character option identifier. Used in the arguments. Must be preceded by '-'.
+ * @param longOpt              The multi character option identifier.  Used in the arguments. Must be preceded by '--'.
+ * @param defaultValue The default value of the option.
+ *
+ * @see getBool()
+ */
+void ReProgramArgs::addBool(const char* name, const char* description,
+               char shortOpt, const char* longOpt, bool defaultVal){
+       addProperties(name, description, shortOpt, longOpt, DT_BOOL,
+               defaultVal ? "t" : "f", 1);
+}
+
+/** @brief Adds an option with a string value.
+ *
+ * @param name                 The name of the option. Used in the methods <code>getString()</code>.
+ * @param description  A short description of the option. Used in the user messages.
+ * @param shortOpt             The one character option identifier. Used in the arguments. Must be preceded by '-'.
+ * @param longOpt              The multi character option identifier.  Used in the arguments. Must be preceded by '--'.
+ * @param defaultValue The default value of the option.
+ *
+ * @see getString()
+ */
+void ReProgramArgs::addString(const char* name, const char* description,
+               char shortOpt, const char* longOpt, bool mayBeEmpty, const char* defaultVal){
+       addProperties(name, description, shortOpt, longOpt,
+               mayBeEmpty ? DT_STRING_EMPTY : DT_STRING,
+               defaultVal, strlen(defaultVal));
+}
+
+/** @brief Returns the value of a boolean option.
+ *
+ * @param name Name of the option.
+ *
+ * @return The value of the option set in the programs arguments or the default value.
+ *
+ * @throws ReOptionException   Unknown name or wrong type.
+ */
+bool ReProgramArgs::getBool(const char* name) {
+       ReStringList properties;
+       ReByteBuffer buffer;
+       ReVarArgs args;
+       if (! m_properties.get(name, -1, buffer))
+               ReOptionException(this, i18n("$1 is not an option name"), name);
+
+       properties.split(buffer.str(), '\1');
+       if (properties.getCStr(IxType)[0] != 'b')
+               ReOptionException(this, i18n("$1 is not an boolean option. Type is $2"), name,
+                       properties.getCStr(IxType));
+
+       m_values.get(name, -1, buffer);
+       bool rc = buffer.at(1) == 't';
+       return rc;
+}
+
+/** @brief Returns the value of an integer option.
+ *
+ * @param name Name of the option.
+ *
+ * @return The value of the option set in the programs arguments or the default value.
+ *
+ * @throws ReOptionException   Unknown name or wrong type.
+ */
+int ReProgramArgs::getInt(const char* name) {
+       ReStringList properties;
+       ReByteBuffer buffer;
+       ReVarArgs args;
+       if (! m_properties.get(name, -1, buffer))
+               ReOptionException(this, i18n("$1 is not an option name"), name);
+
+       properties.split(buffer.str(), '\1');
+       if (properties.getCStr(IxType)[0] != DT_INT)
+               ReOptionException(this, i18n("$1 is not an integer option. Type is $2"), name,
+                       properties.getCStr(IxType));
+
+       m_values.get(name, -1, buffer);
+       int rc = buffer.atoi(1);
+       return rc;
+}
+
+/** @brief Returns the value of a string option.
+ *
+ * @param name Name of the option.
+ *
+ * @return The value of the option set in the programs arguments or the default value.
+ *
+ * @throws ReOptionException   Unknown name or wrong type.
+ */
+const char* ReProgramArgs::getString(const char* name, ReByteBuffer& buffer) {
+       ReStringList properties;
+       ReVarArgs args;
+       if (! m_properties.get(name, -1, buffer))
+               ReOptionException(this, i18n("$1 is not an option name"), name);
+
+       properties.split(buffer.str(), '\1');
+       DataType dataType = (DataType) properties.getCStr(IxType)[0];
+       if (dataType != DT_STRING && dataType != DT_STRING_EMPTY)
+               ReOptionException(this, i18n("$1 is not a string option. Type is $2"), name,
+                       properties.getCStr(IxType));
+
+       m_values.get(name, -1, buffer);
+       const char* rc = buffer.getBuffer() + 1;
+       return rc;
+}
+
+/** @brief Returns the count of arguments (without options).
+ *
+ * @return The count of arguments.
+ */
+int ReProgramArgs::getArgCount() const{
+       return m_argCount;
+}
+
+/** @brief Returns a not option argument given by an index.
+ *
+ * @param index                The index of the wanted program argument which is not an option.
+ *
+ * @return NULL: Wrong index. Otherwise: The wanted argument.
+ */
+const char* ReProgramArgs::getArg(size_t index) const{
+       const char* rc = NULL;
+
+       if (index < (size_t) m_argCount)
+               rc = m_args[index];
+       return rc;
+}
+/** @brief Returns the program name.
+ *
+ * @return The name of the application.
+ */
+const char* ReProgramArgs::getProgramName() const{
+       return m_program;
+}
+
+/** @brief Search the property string of an option.
+ *
+ * @param shortName            The option`s short name. Not relevant if <code>longName != NULL</code>.
+ * @param LongName             The option`s long name. Not relevant if <code>longName == NULL</code>.
+ * @param name                 Out: The name of the option.
+ * @param list                 Out: The properties are returned in this list.
+ *
+ * @throws ReOptionException   Unknown option.
+ */
+void ReProgramArgs::search(char shortName, const char* longName,
+               ReByteBuffer& name, ReStringList& list){
+       size_t position = 0;
+       ReByteBuffer properties;
+       bool found = false;
+       size_t lengthLongName = 0;
+       if (longName != NULL){
+               const char* ptr;
+               if ( (ptr = strchr(longName, '=')) != NULL)
+                       lengthLongName = ptr - longName;
+               else
+                       lengthLongName = strlen(longName);
+       }
+       while (! found && m_properties.next(position, &name, &properties)){
+               list.split(properties.str(), '\1');
+               if (longName == NULL && shortName == list.getCStr(IxShort)[0])
+                       found = true;
+               else if (lengthLongName > 0 && list.getLength(IxLong) == lengthLongName + 1
+                       && strncmp(longName, list.getCStr(IxLong), lengthLongName) == 0)
+                       found = true;
+       }
+       if (! found){
+               if (longName == NULL)
+                       name.set(&shortName, 1);
+               else
+                       name.set(longName, lengthLongName);
+               ReOptionException(this, i18n("Unknown option: $1"), name.str());
+       }
+}
+/** @brief Sets the option value.
+ *
+ * @param name         The option's name.
+ * @param value                The option's value.
+ * @param dataType     Theo option's data type.
+ */
+void ReProgramArgs::setValue(const char* name, const char* value, const char* dataType){
+       switch(dataType[0]){
+       case DT_INT:
+               if (strspn(value, "01234567890") != strlen(value))
+                       ReOptionException(this, i18n("Option $1 expect an integer as parameter, not $2"),
+                                       name, value);
+               break;
+       case DT_STRING:
+               if (value[0] == '\0')
+                       ReOptionException(this, i18n("Option $1: Empty parameter is not allowed"), name);
+               break;
+       case DT_STRING_EMPTY:
+       case DT_BOOL:
+       default:
+               break;
+       }
+       ReByteBuffer buffer;
+       // First character says: defined.
+       buffer.append(" ", 1).append(value, -1);
+       m_values.put(name, buffer.str());
+}
+/** @brief Analyses one or more short name options.
+ *
+ * Multiple short name options can be written in one word:
+ * <p>Example: -x -y -z can be noted as -xyz</p>
+ * <p>On the other side an option with parameter can be written in two forms:</p>
+ * <ul>
+ * <li>-xABC</li>
+ * <li>-x ABC</li>
+ * </ul>
+ *
+ * @param opt          An option string.
+ * @param nextArg      The next argument behind the current option string.
+ *                                     May be NULL (no more arguments).
+ *
+ * @return     true a second word has been used: It was a parameter of an string or integer option.
+ *                     false: The next argument has not been used.
+ */
+bool ReProgramArgs::analyseShort(const char* opt, const char* nextArg){
+       bool rc = false;
+       ReStringList properties;
+       bool again;
+       ReByteBuffer name;
+       do {
+               again = false;
+
+               search(opt[0], NULL, name, properties);
+               const char* dataType = properties.getCStr(IxType);
+               const char* nameStr = name.str();
+               // Forget the option short name:
+               opt++;
+               switch (dataType[0]){
+               case DT_INT:
+               case DT_STRING:
+               case DT_STRING_EMPTY:
+                       if (opt[0] != '\0'){
+                               setValue(nameStr, opt, dataType);
+                       } else {
+                               if (nextArg == NULL || nextArg[0] == '-'){
+                                       if (dataType[0] == DT_STRING_EMPTY)
+                                               setValue(nameStr, "", dataType);
+                                       else
+                                               ReOptionException(this, i18n("Option $1 has type $2! There is no parameter."),
+                                                       nameStr, dataType);
+                               } else {
+                                       setValue(nameStr, nextArg, dataType);
+                                       rc = true;
+                               }
+                       }
+                       break;
+               case DT_BOOL:
+               {
+                       // Get the current value:
+                       const char* value = "t";
+                       if (opt[0] == '-'){
+                               opt++;
+                               value = "f";
+                       } else if (opt[0] == '+')
+                               opt++;
+                       // Invert the default value:
+                       if (properties.getCStr(IxDefault)[0] == 't')
+                               value = value[0] =='t' ? "f" : "t";
+                       setValue(nameStr, value, dataType);
+                       again = opt[0] != '\0';
+                       break;
+               }
+               default:
+                       break;
+               }
+       } while (again);
+       return rc;
+}
+/** @brief Analyses a long name option.
+ *
+ * The syntax of an long name option is --name or --name=value
+ *
+ * @param opt          The option string without --.
+ *
+  */
+void ReProgramArgs::analyseLong(const char* opt){
+       ReStringList properties;
+       ReByteBuffer name;
+       search('\0', opt, name, properties);
+
+       const char* nameStr = name.str();
+       const char* dataType = properties.getCStr(IxType);
+       const char* value = strchr(opt, '=');
+       if (value != NULL)
+               value++;
+
+       switch(dataType[0]){
+       case DT_INT:
+               if (value == NULL)
+                       ReOptionException(this, i18n("Option $1: parameter expected. Use --$2=number"),
+                                       nameStr, nameStr);
+               else
+                       setValue(nameStr, value, dataType);
+               break;
+       case DT_STRING:
+               if (value == NULL)
+                       ReOptionException(this, i18n("Option $1: parameter expected. Use --$2=string"),
+                                       nameStr, nameStr);
+               setValue(nameStr, value, dataType);
+               break;
+       case DT_STRING_EMPTY:
+               if (value == NULL)
+                       value = "";
+               setValue(nameStr, value, dataType);
+               break;
+       case DT_BOOL:
+       {
+               const char* boolValue = "f";
+               if (value == NULL || ReStringUtils::isInList(value,
+                               ReConfigFile::m_trueValues, true, ReStringUtils::AUTO_SEPARATOR))
+                       boolValue = "t";
+               else if (!  ReStringUtils::isInList(value, ReConfigFile::m_falseValues,
+                               true, ReStringUtils::AUTO_SEPARATOR))
+                       ReOptionException(this, i18n("Option $1: Not a boolean value: $2. Use true or false"),
+                                       nameStr, value);
+               // Invert the default value:
+               if (properties.getCStr(IxDefault)[0] == 't')
+                       boolValue = boolValue[0] =='t' ? "f" : "t";
+               setValue(nameStr, boolValue, dataType);
+               break;
+       }
+       default:
+               break;
+       }
+}
+/** @brief Initializes the options from the program arguments.
+ *
+ * While arguments are preceded by an '-' they will be treated as options.
+ * The rest of arguments are stored for retrieving with <code>getArg()</code>.
+ *
+ * @param argc         The count of program arguments (inclusive options).
+ * @param argv         The argument vector.
+ *
+ * @throws ReException
+ */
+void ReProgramArgs::init(int argc, char* argv[]){
+       m_program = argv[0];
+       argv++;
+       argc--;
+
+       while (argc > 0 && argv[0][0] == '-'){
+               if (argv[0][1] == '-')
+                       analyseLong(argv[0] + 2);
+               else{
+                       if (analyseShort(argv[0] + 1, argc <= 1 ? NULL : argv[1]))
+                               argc--, argv++;
+               }
+               argc--;
+               argv++;
+       }
+       m_argCount = argc;
+       m_args = (const char**) argv;
+}
+/** @brief Sets the last error message.
+ *
+ * @param message      The error message.
+ */
+void ReProgramArgs::setLastError(const char* message){
+       m_lastError.set(message, -1);
+}
+
+void ReProgramArgs::help(const char* message, bool issueLastError, ReStringList& lines){
+       lines.append(m_usage);
+       lines.append("");
+
+       size_t position = 0;
+       if (m_properties.next(position, NULL, NULL)){
+               lines.append(i18n("<options>:"));
+       }
+       ReByteBuffer name;
+       ReByteBuffer prop;
+       ReByteBuffer line;
+       ReByteBuffer param;
+
+       while(m_properties.next(position, &name, &prop)){
+               ReStringList properties;
+               properties.split(prop.str(), '\1');
+               line.setLength(0);
+               DataType dataType = DataType(properties.getCStr(IxType)[0]);
+               const char* shortName = properties.getCStr(IxShort);
+               param.setLength(0);
+               switch(dataType){
+               case DT_INT:
+                       param.append(i18n("<number>"), -1);
+                       break;
+               case DT_STRING:
+                       param.append(i18n("<not empty string>"), -1);
+                       break;
+               case DT_STRING_EMPTY:
+                       param.append(i18n("[<string>]"), -1);
+                       break;
+               default:
+                       break;
+               }
+               if (shortName[0] != HIDDEN_SHORT_NAME){
+                       line.append("-", 1).append(shortName, 1);
+                       line.append(param.str(), -1).append(" ", 1).append(i18n(" or "), -1);
+               }
+               line.append(i18n("--"), -1).append(properties.getCStr(IxLong), -1);
+               if (param.getLength() > 0)
+                       line.append("=", -1).append(param.str(), -1)
+                               .append(i18n(" Default value: "), -1).append(properties.getCStr(IxDefault), -1);
+               lines.append(line.str());
+               line.set("\t", 1).append(properties.getCStr(IxDescr), -1);
+               lines.append(line.str());
+       }
+       if (m_examples.getCount() > 0){
+               lines.append(i18n("Example:"));
+               lines.append(m_examples);
+       }
+       if (issueLastError && m_lastError.getLength() > 0){
+               line.set("+++ ", 4).append(m_lastError.str(), -1);
+               lines.append(line.str());
+       }
+
+       if (message != NULL){
+               line.set("+++ ", 4).append(message, -1);
+               lines.append(line.str());
+       }
+}
+
+void ReProgramArgs::help(const char* message, bool issueLastError, FILE* stream){
+       ReStringList lines;
+       help(message, issueLastError, lines);
+       for(size_t ii = 0; ii < lines.getCount(); ii++){
+               fputs(lines.getCStr(ii), stream);
+               fputc('\n', stream);
+       }
+}
+
+#if defined RE_TESTUNIT
+class TestReProgramArgs : public ReTestUnit {
+public:
+       TestReProgramArgs()
+               :
+               ReTestUnit("ReProgramArgs", __FILE__)
+       {
+               run();
+       }
+private:
+       void run(){
+               testLong();
+               testShort();
+       }
+       void testShort(){
+               ReProgramArgs args("test <opts> <args>\nThis tests the usage of ReProgramArgs",
+                               "$0 -b+ -B- file dir\n\ttest of an example");
+
+               args.addBool("boolarg", "This is a boolean arg", 'b', "boolval", false);
+               args.addBool("boolarg2", "This is the 2nd boolean arg", 'B', "boolval2", true);
+               args.addBool("boolarg3", "This is the 3rd boolean arg", 'x', "boolval3", false);
+               args.addBool("boolarg4", "This is the 4th boolean arg", 'Y', "boolval4", true);
+               args.addInt("intarg", "This is an integer arg", 'i', "intval", 9);
+               args.addInt("intarg2", "This is the 2nd integer arg", 'I', "intval", 1000);
+               args.addString("stringarg", "This string must be non empty", 's', "string", false, "abc");
+               args.addString("stringarg2", "This 2nd string must be non empty", 'u', "string2", false, "undef");
+               args.addString("estringarg", "This string may be empty", 'S', "estring", true, "empty");
+               args.addString("estringarg2", "This 2nd string may be empty", 'U', "estring2", true, "undef2");
+
+               checkF(args.getBool("boolarg"));
+               checkEqu(9, args.getInt("intarg"));
+               ReByteBuffer buffer;
+               checkEqu("empty", args.getString("estringarg", buffer));
+               checkEqu("abc", args.getString("stringarg", buffer));
+
+               const char* vector[] = {
+                       "testprog", "-bB+i123", "-S", "-x-", "-Y+", "-s", "2nd string", "arg1", "arg2"
+               };
+               args.init(sizeof vector / sizeof vector[0], (char**) vector);
+
+               checkEqu("testprog", args.getProgramName());
+               checkT(args.getBool("boolarg"));
+               checkF(args.getBool("boolarg2"));
+               checkF(args.getBool("boolarg3"));
+               checkF(args.getBool("boolarg4"));
+               checkEqu(123, args.getInt("intarg"));
+               checkEqu(1000, args.getInt("intarg2"));
+               checkEqu("", args.getString("estringarg", buffer));
+               checkEqu("2nd string", args.getString("stringarg", buffer));
+               checkEqu("undef", args.getString("stringarg2", buffer));
+               checkEqu("undef2", args.getString("estringarg2", buffer));
+               checkEqu("testprog", args.getProgramName());
+               checkEqu("arg1", args.getArg(0));
+               checkEqu("arg2", args.getArg(1));
+               checkEqu(2, args.getArgCount());
+
+               args.help("Not really an error!", false, stdout);
+       }
+       void testLong(){
+               const char* call[] = {
+                               "test <opts> <args>",
+                               "This tests the usage of ReProgramArgs",
+                               NULL
+               };
+               const char* examples[] = { "test -intval=10 --boolval=t",  NULL};
+               ReProgramArgs args(call, examples);
+
+               args.addBool("boolarg", "This is a boolean arg", 'b', "boolval", false);
+               char none = ReProgramArgs::HIDDEN_SHORT_NAME;
+               args.addBool("boolarg2", "This is the 2nd boolean arg", none, "boolval2", true);
+               args.addBool("boolarg3", "This is the 3rd boolean arg", 'x', "boolval3", false);
+               args.addBool("boolarg4", "This is the 3rd boolean arg", none, "boolval4", true);
+               args.addInt("intarg", "This is an integer arg", 'i', "intval", 9);
+               args.addString("stringarg", "This string must be non empty", 's', "string", false, "abc");
+               args.addString("estringarg", "This string may be empty", none, "estring", true, "empty");
+               args.addString("estringarg2", "This 2nd string may be empty", 'U', "estring2", true, "undef2");
+               args.addString("estringarg3", "This 3thrd string may be empty", 'V', "estring3", true, "undef3");
+
+               ReByteBuffer buffer;
+               const char* vector[] = {
+                       "testprog",
+                       "--boolval", "--boolval2=true", "--boolval3=f", "--boolval4=0",
+                       "--intval=3",
+                       "--string=x y", "--estring=", "--estring2=not empty",
+                       "arg1", "arg2"
+               };
+               args.init(sizeof vector / sizeof vector[0], (char**) vector);
+
+               checkEqu("testprog", args.getProgramName());
+               checkT(args.getBool("boolarg"));
+               checkF(args.getBool("boolarg2"));
+               checkF(args.getBool("boolarg3"));
+               checkT(args.getBool("boolarg4"));
+               checkEqu(3, args.getInt("intarg"));
+               checkEqu("x y", args.getString("stringarg", buffer));
+               checkEqu("", args.getString("estringarg", buffer));
+               checkEqu("not empty", args.getString("estringarg2", buffer));
+               checkEqu("arg1", args.getArg(0));
+               checkEqu("arg2", args.getArg(1));
+               checkEqu(2, args.getArgCount());
+               args.help(NULL, false, stdout);
+       }
+};
+extern void testReProgramArgs(void);
+
+void testReProgramArgs(void){
+       TestReProgramArgs unit;
+}
+#endif /*RE_TESTUNIT*/
+
+
diff --git a/base/ReProgramArgs.hpp b/base/ReProgramArgs.hpp
new file mode 100644 (file)
index 0000000..a07b08e
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * ReProgramArgs.h
+ *
+ *  Created on: 25.05.2010
+ *      Author: wk
+ */
+
+#ifndef REPROGRAMARGS_H_
+#define REPROGRAMARGS_H_
+
+class ReProgramArgs;
+/** All errors will reported by this exception.
+ */
+class ReOptionException : public ReException{
+public:
+       ReOptionException(ReProgramArgs* caller, const char* message,
+               const char* arg1, const char* arg2 = NULL);
+};
+
+/**
+ * This class analyses the program arguments and give an interface for retrieving them.
+ *
+ * Program arguments contains the program name, possibly options and "true" arguments.
+ * <p>Options are short name options or long name options.</p>
+ * <p>A short name option is preceded by a single dash ('-'), a long name option starts with two dashes: (--).</p>
+ * <p>There are three types of options: boolean, integer and string.</p>
+ * <p>Every option must have an default value.</p>
+ * <p>A boolean option has normally a default value <code>false</code>. If it appears in the arguments
+ * it will be have the value <code>true</code>.</p>
+ * <p>An integer or string option can be followed by an integer or string value:<br>
+ * Short name option: -x value or -xvalue<br>
+ * Long name option: -xxx=value</p>
+ * <p>The program must contain a definition of the options: <code>addInt(), addBool() and/or addString()</code>,
+ * the analyse (<code>init()</code>) and the retrieval (<code>getInt(), getBool() and/or getString()</code>.</p>
+ * <p>The connection between definition and retrieval are names.</p>
+ */
+class ReProgramArgs {
+public:
+       enum DataType {
+               DT_UNDEF = 0,
+               DT_INT = 'i',
+               DT_BOOL = 'b',
+               DT_STRING = 's',
+               DT_STRING_EMPTY = 'S'
+       };
+       enum {
+               HIDDEN_SHORT_NAME = 2
+       };
+public:
+       ReProgramArgs(const char* usageList[], const char* examples[] = NULL);
+       ReProgramArgs(const char* usageString, const char* examples = NULL);
+       virtual ~ReProgramArgs();
+public:
+       void addInt(const char* name, const char* description,
+               char shortOpt, const char* longOpt, int defaultVal);
+       void addBool(const char* name, const char* description,
+               char shortOpt, const char* longOpt, bool defaultVal);
+       void addString(const char* name, const char* description,
+               char shortOpt, const char* longOpt, bool mayBeEmpty,
+               const char* defaultVal);
+
+       bool getBool(const char* name);
+       int getInt(const char* name);
+       const char* getString(const char* name, ReByteBuffer& buffer);
+
+       int getArgCount() const;
+       const char* getArg(size_t index) const;
+       const char* getProgramName() const;
+
+       void init(int argc, char* argv[]);
+
+       void setLastError(const char* message);
+       void help(const char* message, bool issueLastError, ReStringList& lines);
+       void help(const char* message, bool issueLastError, FILE* stream);
+
+private:
+       void addProperties(const char*name, const char* description, char shortOpt,
+                       const char* longOpt, DataType dataType, const char* defaultValue, size_t lengthValue);
+       void search(char shortName, const char* longName, ReByteBuffer& name, ReStringList& list);
+       void setValue(const char* name, const char* value, const char* dataType);
+       bool analyseShort(const char* opt, const char* nextArg);
+       void analyseLong(const char* opt);
+private:
+       ReStringList    m_usage;
+       ReStringList    m_examples;
+       ReHashList              m_properties;
+       ReHashList              m_values;
+       const char**    m_args;
+       int                             m_argCount;
+       const char*             m_program;
+       ReByteBuffer    m_lastError;
+};
+
+#endif /* REPROGRAMARGS_H_ */
diff --git a/base/ReSeqList.cpp b/base/ReSeqList.cpp
new file mode 100644 (file)
index 0000000..4d5625a
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * ReSeqList.cpp
+ *
+ *  Created on: 19.05.2010
+ *      Author: wk
+ */
+
+#include "rebase.hpp"
+
+/** @brief Constructor.
+ *
+ * @param deltaList            If there is not enough space in the list (array)
+ *                                             this amount is the minimum to reserve.
+ * @param deltaList            If there is not enough space in the content buffer
+ *                                             this amount of bytes is the minimum to reserve.
+ */
+ReSeqList::ReSeqList(size_t deltaList, int deltaBuffer)
+       :
+       m_content(deltaBuffer),
+       m_list(deltaList),
+       m_lost(0)
+{
+}
+/** @brief Destructor.
+ */
+ReSeqList::~ReSeqList() {
+}
+/** @brief Copy constructor.
+ *
+ * @param source       This instance will be copied.
+ */
+ReSeqList::ReSeqList(const ReSeqList& source)
+       :
+       m_content(source.m_content),
+       m_list(source.m_list),
+       m_lost(source.m_lost)
+{
+
+}
+/** @brief Assignment operator.
+ *
+ * @param source       This instance will be copied.
+ *
+ * @result     The instance itself.
+ */
+ReSeqList& ReSeqList::operator = (const ReSeqList& source){
+       m_content = source.m_content;
+       m_list = source.m_list;
+       m_lost = source.m_lost;
+       return *this;
+}
+/** @brief Adds a byte sequence to the list.
+ *
+ * @param index                        The index of the new entry. If greater than the list length it will be appended.
+ * @param source               The pointer of the byte sequence to insert.
+ * @param sourceLength The length of the byte sequence to insert.
+ * @param tag                  An item stored with the byte sequence. We know nothing about this.
+ */
+void ReSeqList::add(Index index, const Byte* source, size_t sourceLength, Tag tag){
+       Sequence seq;
+       if (sourceLength == (size_t) -1)
+               sourceLength = strlen(source) + 1;
+       seq.m_index = m_content.getLength();
+       seq.m_length = sourceLength;
+       seq.m_tag = tag;
+       m_content.append(source, sourceLength);
+       if (index >= getCount()){
+               m_list.append((Byte*) &seq, sizeof seq);
+       }else{
+               m_list.insert(index * sizeof(Sequence), (Byte*) &seq, sizeof seq);
+       }
+}
+/** @brief Returns a byte sequence from the list.
+ *
+ * @param index                The index of the sequence in the list.
+ * @param value                Out: The stored sequence will be copied here.
+ * @param tag          Out: The info which is stored with the entry. May be <code>NULL</code>.
+ *
+ * @param      true: The index is ok, the sequence is in the output buffer.
+ *                     false: No copy has been done.
+ */
+bool ReSeqList::get(Index index, ReByteBuffer& value, Tag* tag) const{
+       bool rc = false;
+       if (index < getCount()){
+               Sequence* seq = ((Sequence*)m_list.getBuffer()) + index;
+               value.set(m_content.getBuffer() + seq->m_index, seq->m_length);
+               if (tag != NULL)
+                       *tag = seq->m_tag;
+               rc = true;
+       }
+       return rc;
+}
+/** @brief Replaces the byte sequence in the list.
+ *
+ * @param index                        The index of the sequence to replace.
+ * @param source               The new value.
+ * @param sourceLength The length of the new value.
+ * @param tag                  An additional info associated to the source.
+ */
+void ReSeqList::set(Index index, const Byte* source, size_t sourceLength, Tag tag){
+       if (index >= getCount())
+               add(index, source, sourceLength, tag);
+       else {
+               if (sourceLength == (size_t) -1)
+                       sourceLength = strlen(source) + 1;
+               Sequence* seq = getInfo(index);
+               seq->m_tag = tag;
+               if (seq->m_length >= sourceLength){
+                       // Use the existing space:
+                       memcpy(m_content.getBuffer() + seq->m_index, source, sourceLength);
+                       m_lost += seq->m_length - sourceLength;
+               } else {
+                       // New space must be allocated:
+                       m_lost += seq->m_length;
+                       seq->m_index = m_content.getLength();
+                       m_content.append(source, sourceLength);
+               }
+       }
+}
+/** @brief Removes an element given by its index.
+ *
+ * @param index The index of the entry to remove.
+ */
+void ReSeqList::remove(Index index){
+       if (index <= getCount()){
+               Sequence* seq = getInfo(index);
+               // Is this the last entry in m_content?
+               if (seq->m_index + seq->m_length >= m_content.getLength()){
+                       // We can free the content:
+                       m_content.setLength(seq->m_index);
+               } else {
+                       m_lost += seq->m_length;
+               }
+               // Remove the entry from the list:
+               m_list.remove(index * sizeof (Sequence), sizeof (Sequence));
+       }
+}
+
+/** @brief Deletes all entries in the list.
+ */
+void ReSeqList::clear(){
+       m_content.setLength(0);
+       m_list.setLength(0);
+}
+
+#if defined RE_TESTUNIT
+class TestReSeqList : public ReTestUnit {
+public:
+       TestReSeqList() : ReTestUnit("ReSeqList", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               testBase();
+               testRemove();
+       }
+       void testBase(){
+               ReSeqList list;
+               ReByteBuffer value;
+               ReSeqList::Tag tag = 0;
+
+               list.add(-1, "123", -1, 100);
+               checkEqu(1, list.getCount());
+               checkT(list.get(0, value, &tag));
+               checkEqu("123", value.str());
+               checkEqu(100, tag);
+
+               list.add(-1, "ab", -1, 200);
+               checkEqu(2, list.getCount());
+               checkT(list.get(0, value));
+               checkEqu("123", value.str());
+               checkT(list.get(1, value, &tag));
+               checkEqu("ab", value.str());
+               checkEqu(200, tag);
+
+               list.add(0, "xyz", -1, 300);
+               checkEqu(3, list.getCount());
+               checkT(list.get(0, value, &tag));
+               checkEqu("xyz", value.str());
+               checkT(list.get(1, value));
+               checkEqu("123", value.str());
+               checkT(list.get(2, value));
+               checkEqu("ab", value.str());
+               checkEqu(300, tag);
+
+               list.add(1, "vw", -1, 400);
+               checkEqu(4, list.getCount());
+               checkT(list.get(0, value));
+               checkEqu("xyz", value.str());
+               checkT(list.get(1, value, &tag));
+               checkEqu("vw", value.str());
+               checkT(list.get(2, value));
+               checkEqu("123", value.str());
+               checkT(list.get(3, value));
+               checkEqu("ab", value.str());
+               checkEqu(400, tag);
+
+               list.clear();
+               checkEqu(0, list.getCount());
+               checkF(list.get(0, value));
+       }
+       void testRemove(){
+               ReSeqList list;
+               ReByteBuffer value;
+               ReSeqList::Tag tag = 0;
+
+               list.add(-1, "abc", -1, 100);
+               list.add(-1, "def12", -1, 200);
+               list.add(-1, "ghi", -1, 300);
+               list.add(-1, "jkl134", -1, 400);
+
+               list.remove(3);
+               checkEqu(3, list.getCount());
+               list.get(0, value, &tag);
+               checkEqu("abc", value.str());
+               checkEqu(100, tag);
+               list.get(1, value, &tag);
+               checkEqu("def12", value.str());
+               checkEqu(200, tag);
+               list.get(2, value, &tag);
+               checkEqu("ghi", value.str());
+               checkEqu(300, tag);
+
+
+               list.remove(1);
+               checkEqu(2, list.getCount());
+               list.get(0, value, &tag);
+               checkEqu("abc", value.str());
+               checkEqu(100, tag);
+               list.get(1, value, &tag);
+               checkEqu("ghi", value.str());
+               checkEqu(300, tag);
+
+               list.remove(0);
+               checkEqu(1, list.getCount());
+               list.get(0, value, &tag);
+               checkEqu("ghi", value.str());
+               checkEqu(300, tag);
+
+       }
+};
+extern void testReSeqList(void);
+
+void testReSeqList(void){
+       TestReSeqList unit;
+}
+#endif /*RE_TESTUNIT*/
+
diff --git a/base/ReSeqList.hpp b/base/ReSeqList.hpp
new file mode 100644 (file)
index 0000000..34c938f
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * ReSeqList.h
+ *
+ *  Created on: 19.05.2010
+ *      Author: wk
+ */
+
+#ifndef RESEQLIST_H_
+#define RESEQLIST_H_
+
+/** @brief This class implements a dynamic (selfgrowing) array of byte sequences.
+ * <p>A <strong>byte sequence</strong> is an array of byte.
+ * The byte sequences may have different lengths.
+ * This implies the handling of C string arrays too.
+ * <p>There is room for storing a so called <strong>tag</strong> with any sequence.
+ * This can be used for any purpose.
+ * </p>
+ * <p>This is a very simple implementation: use it when:
+ * <ul><li>The needed size is known nearly.</li>
+ * <li>The array elements increment rarely their length.</li>
+ * </ul>
+ * </p>
+ */
+class ReSeqList {
+public:
+       typedef char Byte;
+       typedef unsigned int Index;
+       typedef long int Tag;
+       typedef struct {
+               Index   m_index;
+               size_t  m_length;
+               Tag             m_tag;
+       } Sequence;
+public:
+       ReSeqList(size_t deltaList = 128, int deltaBuffer = 1024);
+       virtual ~ReSeqList();
+       ReSeqList(const ReSeqList& source);
+       ReSeqList& operator = (const ReSeqList& source);
+public:
+       void clear();
+       void add(Index index, const Byte* source, size_t sourceLength, Tag tag = 0);
+       bool get(Index index, ReByteBuffer& value, Tag* tag = NULL) const;
+       void remove(Index index);
+       void set(Index index, const Byte* source, size_t sourceLength, Tag tag);
+       /** @brief Returns the count of defined entries in the list.
+        * @return The number of defined entries in the list (array).
+        */
+       inline Index getCount() const {
+               return m_list.getLength() / sizeof (Sequence);
+       }
+protected:
+       /** @brief Returns a pointer of the content buffer.
+        * @return A pointer of the first byte of the content buffer.
+        */
+       inline const Byte* getContent() const {
+               return m_content.getBuffer();
+       }
+       friend class ReHashList;
+       /** @brief Returns the info of an entry of the list.
+        * @param index         The index of the wanted entry.
+        * @return The pointer of the entry.
+        */
+       inline Sequence* getInfo(Index index) const {
+               return &((Sequence*) m_list.getBuffer())[index];
+       }
+
+protected:
+       // friend class ReSeqList;
+               //@ Contains the sequences itself.
+       ReByteBuffer    m_content;
+               //@ Contains an array of <code>Sequence</code>s.
+       ReByteBuffer    m_list;
+               //@ If strings have been replaced the space in m_content is still allocated.
+               //@ This is the sum of lost space.
+       size_t m_lost;
+};
+
+#endif /* RESEQLIST_H_ */
diff --git a/base/ReStringList.cpp b/base/ReStringList.cpp
new file mode 100644 (file)
index 0000000..6d4930f
--- /dev/null
@@ -0,0 +1,597 @@
+/*
+ * ReStringList.cpp
+ *
+ *  Created on: 20.05.2010
+ *      Author: wk
+ */
+
+#include "../base/restring.hpp"
+
+/** @brief Constructor.
+ */
+ReStringList::ReStringList()
+       :
+       ReSeqList()
+{
+
+}
+
+/** @brief Destructor.
+ */
+ReStringList::~ReStringList() {
+}
+/** @brief Appends a string at the end.
+ *
+ * @param source       The new string.
+ * @param tag          An item which will stored with the string. It can be retrieved by the same index.
+ *                             T       his class knows nothing about this.
+ */
+void ReStringList::append(const char* source, Tag tag){
+       add(-1, source, -1, tag);
+}
+/** @brief Appends a stringlist at the end.
+ *
+ * @param source       The new stringlist.
+ */
+void ReStringList::append(ReStringList& source){
+       for (size_t ii = 0; ii < source.getCount(); ii++)
+               add(-1, source.getCStr(ii), -1, source.getTag(ii));
+}
+/** @brief Inserts a string at a given index.
+ *
+ * If the index exceeds the length of the array it will be appended.
+ *
+ * @param source       The new string.
+ * @param tag          An item which will stored with the string. It can be retrieved by the same index.
+ *                                     This class knows nothing about this.
+ */
+void ReStringList::insert(Index index, const char* source, Tag tag){
+       add(index, source, -1, tag);
+}
+/** @brief Replaces an element in the internal array: a string and a tag.
+ *
+ * @param index        The element with this index will be replaced.
+ * @param source       The new string of the replaced element.
+ * @param tag          The tag of the replace element.
+ */
+void ReStringList::replace(Index index, const char* source, Tag tag){
+       set(index, source, -1, tag);
+}
+/** @brief Replaces a string in the internal array.
+ *
+ * The tag of the element remains unchanged.
+ *
+ * @param index        The element with this index will be replaced.
+ * @param source       The new string of the replaced element.
+ */
+void ReStringList::replaceString(Index index, const char* source){
+       if (index < getCount()){
+               Sequence* seq = getInfo(index);
+               set(index, source, -1, seq->m_tag);
+       }
+}
+/** @brief Replaces a tag in the internal array.
+ *
+ * The string of the element remains unchanged.
+ *
+ * @param index        The element with this index will be replaced.
+ * @param source       The new string of the replaced element.
+ */
+void ReStringList::replaceTag(Index index, Tag tag){
+       if (index < getCount()){
+               Sequence* seq = getInfo(index);
+               seq->m_tag = tag;
+       }
+}
+
+/** @brief Returns the C string given by an index.
+ *
+ * @param index                The index of the wanted string.
+ *
+ * @return     NULL: The index is too large.
+ *                     Otherwise: The wanted string.
+ */
+const char* ReStringList::getCStr(Index index) const{
+       const char* rc = NULL;
+       if (index < getCount()){
+               Sequence* seq = getInfo(index);
+               rc = m_content.getBuffer() + seq->m_index;
+       }
+       return rc;
+}
+/** @brief Returns the tag given by an index.
+ *
+ * A tag is an additional info stored with the string.
+ *
+ * @param index                The index of the wanted tag.
+ *
+ * @return     -1: The index is too large.
+ *                     Otherwise: The wanted tag.
+ */
+ReSeqList::Tag ReStringList::getTag(Index index) const{
+       Tag rc = -1;
+       if (index < getCount()){
+               Sequence* seq = getInfo(index);
+               rc = seq->m_tag;
+       }
+       return rc;
+}
+/** @brief Returns the length of the string given by an index.
+ *
+ * @param index                The index of the wanted string length.
+ *
+ * @return     0: The index is too large.
+ *                     Otherwise: The length of the <code>index</code>-th string.
+ */
+size_t ReStringList::ReStringList::getLength(Index index) const{
+       size_t rc = 0;
+       if (index < getCount()){
+               Sequence* seq = getInfo(index);
+               rc = seq->m_length;
+       }
+       return rc;
+}
+/** @brief Returns the sum of all string lengths stored in the array.
+ *
+ * @return The sum of all string lengths stored in the array.
+ */
+size_t ReStringList::sumOfLength() const{
+       size_t rc = 0;
+
+       for (int ii = getCount() - 1; ii >= 0; ii--){
+               Sequence* seq = getInfo(ii);
+               rc += seq->m_length;
+       }
+       return rc;
+}
+/** @brief Returns the index of a given string in the array.
+ *
+ * @param toFind               The string which will be searched.
+ * @param ignoreCase   true: The search is case insensitive.
+ *                                             false: The search is case sensitive.
+ * @param start                        The search starts at this index.
+ *
+ * @return -1: The string was not found. Otherwise: The index of the string.
+ */
+ReSeqList::Index ReStringList::indexOf(const char* toFind,
+               bool ignoreCase, Index start) const{
+       Index rc = (Index) -1;
+       Index count = getCount();
+
+       for (; rc == (size_t) -1 && start < count; start++){
+               const char* item = getCStr(start);
+               int rc2;
+               if (ignoreCase)
+                       rc2 = strcasecmp(item, toFind);
+               else
+                       rc2 = strcmp(item, toFind);
+               if (rc2 == 0)
+                       rc = start;
+       }
+       return rc;
+}
+/** Returns the index of the next string starting with a given substring.
+ *
+ * @param start                        The search starts at this index.
+ * @param prefix               The substring which will be searched.
+ * @param ignoreCase   true: The search is case insensitive.
+ *                                             false: The search is case sensitive.
+ *
+ * @return -1: The string was not found. Otherwise: The index of the string.
+ */
+ReSeqList::Index ReStringList::nextStartingWith(Index start,
+               const char* prefix, bool ignoreCase){
+       Index rc = (Index) -1;
+       Index count = getCount();
+       size_t length = strlen(prefix);
+
+       for (; rc == (size_t) -1 && start < count; start++){
+               const char* item = getCStr(start);
+               int rc2;
+               if (ignoreCase)
+                       rc2 = strncasecmp(item, prefix, length);
+               else
+                       rc2 = strncmp(item, prefix, length);
+               if (rc2 == 0)
+                       rc = start;
+       }
+       return rc;
+}
+/** @brief Splits a string in an array.
+ *
+ * @param list                 The string which is splitted.
+ * @param separator            The separator of the substrings.
+ *                                             If '\\n' a preceeding or trailing '\\r' will be ignored too.
+ * @param append               false: The list will be cleared at the beginning.
+ *                                             true: The new content is stored at the end.
+ */
+void ReStringList::split(const char* list, char separator, bool append){
+       if (! append)
+               clear();
+       const char* end = strchr(list, separator);
+       const char* end2;
+       ReByteBuffer item;
+       while(end != NULL){
+               if (separator == '\n' && end != list && end[-1] == '\r')
+                       end2 = end - 1;
+               else
+                       end2 = end;
+               item.setLength(0);
+               size_t length = end2 - list;
+               item.append(list, length);
+               // Append '\0':
+               item.append("", 1);
+               add(-1, item.getBuffer(), length + 1);
+               list = end + 1;
+               if (separator == '\n' && list[0] == '\r')
+                       list++;
+               end = strchr(list, separator);
+       }
+       if (list[0] != '\0')
+               add(-1, list, -1);
+}
+/** @brief Joins all string of the array into a string.
+ *
+ * @param separator            This string was put between the substrings. May be NULL or "".
+ * @param result               Out: The result buffer.
+ */
+void ReStringList::join(const char* separator, ReByteBuffer& result){
+       size_t count = getCount();
+
+       result.setLength(0);
+       size_t lengthSep = strlen(separator);
+
+       for (size_t ix = 0; ix < count; ix++){
+               result.append(getCStr(ix), getLength(ix) - 1);
+               if (ix != count - 1 && separator != NULL)
+                       result.append(separator, lengthSep);
+       }
+}
+/** @brief Writes the stringlist to a file.
+ *
+ * @param filename             The name of the file.
+ * @param separator            This string was put between the substrings. May be NULL.
+ * @param mode                 The file open mode: "w" for truncate and write, "a" for append.
+ *
+ * @return true: The file could be opened. false: otherwise.
+ */
+bool ReStringList::writeToFile(const char* filename,
+               const char* separator, const char* mode){
+       bool rc = false;
+       FILE* fp = fopen(filename, mode);
+       if (fp){
+               size_t count = getCount();
+               for (size_t ix = 0; ix < count; ix++){
+                       fputs(getCStr(ix), fp);
+                       if (ix != count - 1 && separator != NULL)
+                               fputs(separator, fp);
+               }
+               fclose(fp);
+               rc = true;
+       }
+       return rc;
+}
+/** @brief Reads a file into the array.
+ *
+ * Every line is stored as entry of the array.
+ *
+ * @param filename             The name of the file.
+ * @param cutNewline   true: The newline characters will be cut.
+ *                                             false: The newline characters will be stored.
+ *
+ * @return true: The file could be opened. false: otherwise.
+ */
+bool ReStringList::readFromFile(const char* filename, bool cutNewline){
+       FILE* fp = fopen(filename, "r");
+       bool rc = false;
+       if (fp != NULL){
+               char line[8096];
+
+               while(fgets(line, sizeof line, fp) != NULL){
+                       size_t length = strlen(line);
+                       if (cutNewline){
+                               while(--length > 0 && (line[length] == '\n' || line[length] == '\r'))
+                                       line[length] = '\n';
+                       }
+                       add(-1, line, length + 1);
+               }
+       }
+       return rc;
+}
+/** @brief Returns the index of the first different string.
+ *
+ * Compares the internal array of strings with another instance.
+ *
+ * @param toCompare    The other instance which will be compared.
+ *
+ * @return -1: The instances are equal. Otherwise: The index of the first different string.
+ *
+ */
+int ReStringList::firstDiff(const ReStringList& toCompare) const{
+       int rc = -1;
+       for (size_t ix = 0; rc == -1 && ix < getCount(); ix++){
+               if (ix >= toCompare.getCount())
+                       rc = (int) ix;
+               else if (getLength(ix) != toCompare.getLength(ix)
+                               || strcmp(getCStr(ix), toCompare.getCStr(ix)) != 0)
+                       rc = (int) ix;
+       }
+       if (rc == -1 && getCount() < toCompare.getCount())
+               rc = getCount();
+       return rc;
+}
+/** @brief Tests the equality with another instance.
+ *
+ * Compares the internal array of strings with another instance.
+ * Two instances are equal when the number of strings are equal
+ * and the n.th string is equal to the n.th string in the other instance.
+ *
+ * @param toCompare    The other instance which will be compared.
+ *
+ * @return true: The other instance is equal. false: Otherwise.
+ */
+bool ReStringList::equal(const ReStringList& toCompare) const{
+       bool rc = getCount() == toCompare.getCount() && firstDiff(toCompare) == -1;
+       return rc;
+}
+
+#if defined RE_TESTUNIT
+class TestReStringList : public ReTestUnit {
+public:
+       TestReStringList() : ReTestUnit("ReStringList", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               testBase();
+               testReplace();
+               testJoin();
+               testEqu();
+               testFile();
+       }
+       void testReplace(){
+               ReStringList list;
+
+               list.append("123", 100);
+               checkEqu(100, list.getTag(0));
+               list.append("2", 200);
+               checkEqu(100, list.getTag(0));
+               checkEqu(200, list.getTag(1));
+               list.append("34", 300);
+               checkEqu(100, list.getTag(0));
+               checkEqu(200, list.getTag(1));
+               checkEqu(300, list.getTag(2));
+
+               list.replace(0, "1", 111);
+               checkEqu("1", list.getCStr(0));
+               checkEqu(111, list.getTag(0));
+               checkEqu(200, list.getTag(1));
+               checkEqu(300, list.getTag(2));
+
+               list.replace(1, "124", 222);
+               checkEqu("124", list.getCStr(1));
+               checkEqu(111, list.getTag(0));
+               checkEqu(222, list.getTag(1));
+               checkEqu(300, list.getTag(2));
+
+               checkEqu(300, list.getTag(2));
+               list.replaceString(2, "4");
+               checkEqu("4", list.getCStr(2));
+               checkEqu(111, list.getTag(0));
+               checkEqu(222, list.getTag(1));
+               checkEqu(300, list.getTag(2));
+
+               list.replaceTag(2, 123);
+               checkEqu("4", list.getCStr(2));
+               checkEqu(111, list.getTag(0));
+               checkEqu(222, list.getTag(1));
+               checkEqu(123, list.getTag(2));
+       }
+       void testEqu(){
+               ReStringList list1;
+               ReStringList list2;
+
+               list1.split("1;2;1;3", ';');
+               list2.split("1\n2\n1\n3", '\n');
+               checkEqu(-1, list1.firstDiff(list2));
+               checkEqu(-1, list2.firstDiff(list1));
+               checkT(list1.equal(list2));
+               checkT(list2.equal(list1));
+
+               list1.insert(2, "x");
+               list1.remove(3);
+               checkEqu(2, list1.firstDiff(list2));
+               checkEqu(2, list2.firstDiff(list1));
+               checkF(list1.equal(list2));
+               checkF(list2.equal(list1));
+
+               list2.replace(2, "x");
+               checkEqu(-1, list1.firstDiff(list2));
+               checkEqu(-1, list2.firstDiff(list1));
+               checkT(list1.equal(list2));
+               checkT(list2.equal(list1));
+
+               list2.remove(3);
+               checkEqu(3, list1.firstDiff(list2));
+               checkEqu(3, list2.firstDiff(list1));
+               checkF(list1.equal(list2));
+               checkF(list2.equal(list1));
+
+               list1.replace(0, "");
+               checkEqu(0, list1.firstDiff(list2));
+               checkEqu(0, list2.firstDiff(list1));
+               checkF(list1.equal(list2));
+               checkF(list2.equal(list1));
+
+               list1.clear();
+               list2.clear();
+               checkEqu(-1, list1.firstDiff(list2));
+               checkEqu(-1, list2.firstDiff(list1));
+               checkT(list1.equal(list2));
+               checkT(list2.equal(list1));
+
+               list1.append("fjkdajfdkla");
+               checkEqu(0, list1.firstDiff(list2));
+               checkEqu(0, list2.firstDiff(list1));
+               checkF(list1.equal(list2));
+               checkF(list2.equal(list1));
+       }
+       void testJoin(){
+               ReStringList list;
+               const char* str = "1;abc;xyz;4;;99";
+               list.split(str, ';');
+               checkEqu(6, list.getCount());
+               checkEqu("1", list.getCStr(0));
+               checkEqu("abc", list.getCStr(1));
+               checkEqu("xyz", list.getCStr(2));
+               checkEqu("4", list.getCStr(3));
+               checkEqu("", list.getCStr(4));
+               checkEqu("99", list.getCStr(5));
+               ReByteBuffer value;
+               list.join(";", value);
+               checkEqu(str, value.str());
+
+               list.split("1\r\n2\n\r3", '\n');
+               checkEqu(3, list.getCount());
+               checkEqu("1", list.getCStr(0));
+               checkEqu("2", list.getCStr(1));
+               checkEqu("3", list.getCStr(2));
+
+               list.split("xyz\tXYZ", '\t', true);
+               checkEqu(5, list.getCount());
+               checkEqu("1", list.getCStr(0));
+               checkEqu("2", list.getCStr(1));
+               checkEqu("3", list.getCStr(2));
+               checkEqu("xyz", list.getCStr(3));
+               checkEqu("XYZ", list.getCStr(4));
+
+
+       }
+       void testFile(){
+               createTestDir();
+               ReByteBuffer file;
+               file.set(getTestDir(), -1).append("abc.csv", -1);
+
+               ReStringList list;
+               const char* str = "1;abc;xyz;4;;99";
+               list.split(str, ';');
+               list.writeToFile(file.str(), "\n");
+
+               ReStringList list2;
+               list2.readFromFile(file.str(), true);
+
+               checkEqu(-1, list2.firstDiff(list2));
+       }
+       void testBase(){
+               ReStringList list;
+               ReByteBuffer value;
+
+               list.append("123", 100);
+               list.append("a", 200);
+               list.append("vwxyz", 300);
+
+               checkEqu(3, list.getCount());
+               int index = 0;
+               checkEqu("123", list.getCStr(index));
+               checkEqu(4, list.getLength(index));
+               checkEqu(100, list.getTag(index));
+
+               index++;
+               checkEqu("a", list.getCStr(index));
+               checkEqu(2, list.getLength(index));
+               checkEqu(200, list.getTag(index));
+
+               index++;
+               checkEqu("vwxyz", list.getCStr(index));
+               checkEqu(6, list.getLength(index));
+               checkEqu(300, list.getTag(index));
+
+               checkEqu(12, list.sumOfLength());
+
+               list.insert(0, "0", 50);
+               checkEqu(4, list.getCount());
+               checkEqu(14, list.sumOfLength());
+
+               index = 0;
+               checkEqu("0", list.getCStr(index));
+               checkEqu(2, list.getLength(index));
+               checkEqu(50, list.getTag(index));
+
+               index++;
+               checkEqu("123", list.getCStr(index));
+               checkEqu(4, list.getLength(index));
+               checkEqu(100, list.getTag(index));
+
+               index++;
+               checkEqu("a", list.getCStr(index));
+               checkEqu(2, list.getLength(index));
+               checkEqu(200, list.getTag(index));
+
+               index++;
+               checkEqu("vwxyz", list.getCStr(index));
+               checkEqu(6, list.getLength(index));
+               checkEqu(300, list.getTag(index));
+
+               checkEqu(0, list.indexOf("0"));
+               checkEqu(1, list.indexOf("123"));
+               checkEqu(2, list.indexOf("a"));
+               checkEqu(2, list.indexOf("A", true));
+               checkEqu(3, list.indexOf("vwxyz"));
+               checkEqu(3, list.indexOf("VwXyz", true));
+
+               checkEqu(0, list.indexOf("0", false, 0));
+               checkEqu(1, list.indexOf("123", false, 1));
+               checkEqu(2, list.indexOf("a", false, 1));
+               checkEqu(2, list.indexOf("a", false, 2));
+               checkEqu(2, list.indexOf("A", true, 2));
+               checkEqu(3, list.indexOf("vwxyz", false, 2));
+               checkEqu(3, list.indexOf("vwxyz", false, 3));
+               checkEqu(3, list.indexOf("VwXyz", true, 3));
+
+               checkEqu(-1, list.indexOf("A"));
+               checkEqu(-1, list.indexOf("0123"));
+               checkEqu(-1, list.indexOf("a", false, 3));
+               checkEqu(-1, list.indexOf("A", true, 3));
+
+               checkEqu(0, list.nextStartingWith(0, "0"));
+               checkEqu(1, list.nextStartingWith(0, "12"));
+               checkEqu(2, list.nextStartingWith(0, "a"));
+               checkEqu(2, list.nextStartingWith(1, "a"));
+               checkEqu(2, list.nextStartingWith(2, "a"));
+               checkEqu(2, list.nextStartingWith(0, "A", true));
+               checkEqu(-1, list.nextStartingWith(2, "Ab", true));
+               checkEqu(-1, list.nextStartingWith(0, "b", true));
+
+               checkEqu(3, list.nextStartingWith(0, "vwxy", false));
+               checkEqu(3, list.nextStartingWith(0, "vwxy", true));
+               checkEqu(-1, list.nextStartingWith(0, "vWxY", false));
+
+               ReStringList list2;
+               list2.append("a", 100);
+               list2.append("b", 200);
+               list2.append("c", 300);
+               ReStringList list3;
+               list3.append("x", 1000);
+               list3.append("y", 2000);
+
+               list2.append(list3);
+               checkEqu(5, list2.getCount());
+               checkEqu("a", list2.getCStr(0));
+               checkEqu(100, list2.getTag(0));
+               checkEqu("b", list2.getCStr(1));
+               checkEqu(200, list2.getTag(1));
+               checkEqu("c", list2.getCStr(2));
+               checkEqu(300, list2.getTag(2));
+               checkEqu("x", list2.getCStr(3));
+               checkEqu(1000, list2.getTag(3));
+               checkEqu("y", list2.getCStr(4));
+               checkEqu(2000, list2.getTag(4));
+       }
+};
+extern void testReStringList(void);
+
+void testReStringList(void){
+       TestReStringList unit;
+}
+#endif /*RE_TESTUNIT*/
+
diff --git a/base/ReStringList.hpp b/base/ReStringList.hpp
new file mode 100644 (file)
index 0000000..ceb35da
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * ReStringList.h
+ *
+ *  Created on: 20.05.2010
+ *      Author: wk
+ */
+
+#ifndef RESTRINGLIST_H_
+#define RESTRINGLIST_H_
+
+/**
+ * This class implements a dynamic array of C strings.
+ * <p>With this class it is very simple to break a string into a vector of substrings.</p>
+ * <pre>
+ * <strong>Example:</strong>
+ * This example adds a column with a current number to a CSV file (comma separated file):
+ * <code>
+ * ReStringList listIn, listOut;
+ * listIn.readFromFile("abc.csv");
+ * for (int ii = 0; ii < listIn.getCount(); ii++){
+ *    ReStringList cols;
+ *    cols.split(list.getCStr(ii), ',');
+ *    char number[20]; sprintf(number, "%d", ii + 1);
+ *    cols.append(0, nummber);
+ *    ReByteBuffer line; line.append(cols.join(",");
+ *    listOut.append(line.str());
+ * }
+ * listOut.writeToFile("abc.csv");
+ * </code></pre>
+ */
+class ReStringList : public ReSeqList {
+public:
+       ReStringList();
+       virtual ~ReStringList();
+public:
+       void append(const char* source, Tag tag = 0);
+       void append(ReStringList& source);
+       void insert(Index index, const char* source, Tag tag = 0);
+       void replace(Index index, const char* source, Tag tag = 0);
+       void replaceString(Index index, const char* source);
+       void replaceTag(Index index, Tag tag);
+
+       const char* getCStr(Index index) const;
+       Tag getTag(Index index) const;
+       size_t getLength(Index index) const;
+       size_t sumOfLength() const;
+
+       Index indexOf(const char* toFind, bool ignoreCase = false, Index start = 0) const;
+       Index nextStartingWith(Index index, const char* prefix, bool ignoreCase = false);
+
+       void split(const char* list, char separator, bool append = false);
+       void join(const char* separator, ReByteBuffer& result);
+
+       int firstDiff(const ReStringList& toCompare) const;
+       bool equal(const ReStringList& toCompare) const;
+
+       bool writeToFile(const char* filename, const char* separator = "\n", const char* mode = "w");
+       bool readFromFile(const char* filename, bool cutNewline = true);
+};
+
+#endif /* RESTRINGLIST_H_ */
diff --git a/base/ReStringUtils.cpp b/base/ReStringUtils.cpp
new file mode 100644 (file)
index 0000000..794a2be
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * ReStringUtils.cpp
+ *
+ *  Created on: 16.05.2010
+ *      Author: wk
+ */
+
+#include "../base/restring.hpp"
+
+char ReStringUtils::slash = ReStringUtils::initPathSeparator();
+const char* ReStringUtils::slashStr = NULL;
+const char ReStringUtils::AUTO_SEPARATOR = '\0';
+
+
+/** @brief Initializes the os specific path separator (char and string).
+ *
+ * @return The path separator: '/' under unix and '\\' under windows.
+ */
+char ReStringUtils::initPathSeparator(){
+       slashStr = NULL;
+       if (getenv("PATH") != NULL){
+               if (strchr(getenv("PATH"), '\\') != NULL)
+                       slashStr = "\\";
+               else if (strchr(getenv("PATH"), '/') == NULL)
+                       slashStr = "/";
+       }
+       if (slashStr != NULL && getenv("TMP") != NULL){
+               if (strchr(getenv("TMP"), '\\') != NULL)
+                       slashStr = "\\";
+               else if (strchr(getenv("TMP"), '/') == NULL)
+                       slashStr = "/";
+       }
+       if (slashStr == NULL && getenv("TEMP") != NULL){
+               if (strchr(getenv("TEMP"), '\\') != NULL)
+                       slashStr = "\\";
+               else if (strchr(getenv("TMP"), '/') == NULL)
+                       slashStr = "/";
+       }
+       if (slashStr == NULL)
+               slashStr = "/";
+       return slashStr[0];
+}
+
+
+/** @brief Splits a filename into its parts.
+ *
+ * Example: file:/etc/samba/smb.conf
+ * The 4 parts are:
+ * <ul><li>A protocol: file:</li>
+ * <li>The path. /etc/samba/ </li>
+ * <li>The name: smb</li>
+ * <li>The extension: .conf</li>
+ * </ul>
+ * All parts exclusive the name can be empty.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer protocol, path, name, ext;
+ * ReByteBuffer fnBackup;
+ * ReStringUtils::splitPath("/etc/sambe/smb.conf", &protocol, &path, &name, NULL);
+ * ext.append(".bak");
+ * ReStringUtils::joinPath(fnBackup, &protocol, &path, &name, &ext);
+ * assert("/etc/sambe/smb.bak", fnBackup.getBuffer());
+ * </code></pre>
+ *
+ * @param fullname                     The full name to split.
+ * @param protocol                     Out: The protocol part of the filename. May be NULL.
+ * @param path                         Out: The path of the filename. May be NULL.
+ * @param name                         Out: The name part of the filename. May be NULL.
+ * @param ext                          Out: The extension. May be NULL.
+ */
+void ReStringUtils::splitPath(const char* fullname,
+       ReByteBuffer* protocol, ReByteBuffer* path, ReByteBuffer* name, ReByteBuffer* ext){
+       const char* start = strchr(fullname, ':');
+       if (protocol != NULL){
+               protocol->setLength(0);
+               if (start != NULL)
+                       protocol->append(fullname, start - fullname + 1);
+       }
+       if (start == NULL)
+               start = fullname;
+       else
+               start++;
+
+       const char* end = strrchr(start, slash);
+
+       if (path != 0){
+               path->setLength(0);
+               if (end != NULL)
+                       path->append(start, end - start + 1);
+       }
+       if (end != NULL)
+               start = end + 1;
+       end = strrchr(start, '.');
+       if (name != NULL){
+               name->setLength(0);
+               if (end == NULL)
+                       name->append(start, strlen(start));
+               else
+                       name->append(start, end - start);
+       }
+       if (ext != NULL){
+               ext->setLength(0);
+               if (end != NULL)
+                       ext->append(end, strlen(end));
+       }
+}
+/** Joins a filename from parts.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer protocol, path, name, ext;
+ * ReByteBuffer fnBackup;
+ * ReStringUtils::splitPath("/etc/sambe/smb.conf", &protocol, &path, &name, NULL);
+ * ext.append(".bak");
+ * ReStringUtils::joinPath(fnBackup, &protocol, &path, &name, &ext);
+ * assert("/etc/sambe/smb.bak", fnBackup.getBuffer());
+ * </code></pre>
+ *
+ * @param fullpath                     Out: The full path of the filename.
+ * @param protocol                     The protocol part. May be NULL.
+ * @param path                         The path part. May be NULL.
+ * @param name                         The name part. May be NULL.
+ * @param ext                          The extension part. May be NULL.
+ *
+ * @result <code>fullpath</code>. (for chaining).
+ */
+ReByteBuffer& ReStringUtils::joinPath(ReByteBuffer& fullpath,
+               ReByteBuffer* protocol, ReByteBuffer* path, ReByteBuffer* name, ReByteBuffer* ext){
+       fullpath.setLength(0);
+       if (protocol != NULL)
+               fullpath.append(*protocol);
+       if (path != NULL)
+               fullpath.append(*path);
+       if (name != NULL)
+               fullpath.append(*name);
+       if (ext != NULL)
+               fullpath.append(*ext);
+       return fullpath;
+}
+/** Joins a filename from parts.
+ *
+ * <pre><code>Example:
+ * ReByteBuffer protocol, path, name;
+ * ReByteBuffer fnBackup;
+ * ReStringUtils::splitPath("/etc/sambe/smb.conf", &protocol, &path, &name, NULL);
+ * ReStringUtils::joinPath(fnBackup, protocol.getBuffer(), path.getBuffer(), name.getBuffer(), ".bak");
+ * assert("/etc/sambe/smb.bak", fnBackup.getBuffer());
+ * </code></pre>
+ *
+ * @param fullpath                     Out: The full path of the filename.
+ * @param protocol                     The protocol part. May be NULL.
+ * @param path                         The path part. May be NULL.
+ * @param name                         The name part. May be NULL.
+ * @param ext                          The extension part. May be NULL.
+ *
+ * @result <code>fullpath</code>. (for chaining).
+ */
+ReByteBuffer& ReStringUtils::joinPath(ReByteBuffer& fullpath,
+               const char* protocol, const char* path, const char* name, const char* ext){
+       fullpath.setLength(0);
+       if (protocol != NULL)
+               fullpath.append(protocol, strlen(protocol));
+       if (path != NULL)
+               fullpath.append(path, strlen(path));
+       if (name != NULL)
+               fullpath.append(name, strlen(name));
+       if (ext != NULL)
+               fullpath.append(ext, strlen(ext));
+       return fullpath;
+}
+
+/** @brief Compares two strings case insensitive.
+ *
+ * @param string1              The first C string to compare.
+ * @param string2              The second C string to compare.
+ * @param length               The maximum length to compare.
+ *
+ * @return &lt; 0: string1 &lt; string2 0: string1 == string2 &gt; 0: string1 &gt; string2
+ */
+int ReStringUtils::strnicmp(const char* string1, const char* string2, size_t length){
+       int rc = 0;
+       while(rc == 0 && length-- > 0){
+               char cc1 = *string1++;
+               char cc2 = *string2++;
+               if (toupper(cc1) != toupper(cc2))
+                       rc = toupper(cc1) - toupper(cc2);
+               else if (cc1 == '\0')
+                       break;
+       }
+       return rc;
+}
+
+/** @brief Tests whether a phrase is in a phrase list.
+ *
+ * @param phrase               The word to search.
+ * @param list                 The list to search. All phrases of the list are separated by <code>separator</code>.
+ * @param ignoreCase   true: The search is case insensitive. false: The search is case sensitive.
+ * @param separator            The separator in <code>list</code>. If <code>AUTO_SEPARATOR</code> the separator will
+ *                                             be taken from the list itself (the first character).
+ */
+bool ReStringUtils::isInList(const char* phrase, const char* list,
+               bool ignoreCase, char separator){
+       if (separator == AUTO_SEPARATOR)
+               separator = *list++;
+       const char* end = strchr(list, separator);
+       int phraseLength = strlen(phrase);
+       bool rc = false;
+       while(! rc && end != NULL){
+               if (end - list == phraseLength){
+                       if (ignoreCase)
+                               rc = strnicmp(list, phrase, phraseLength) == 0;
+                       else
+                               rc = strncmp(list, phrase, end - list) == 0;
+                       if (rc)
+                               break;
+               }
+               list = end + 1;
+               end = strchr(list, separator);
+       }
+       if (! rc){
+               if (ignoreCase)
+                       rc = strnicmp(list, phrase, end - list) == 0;
+               else
+                       rc = strncmp(list, phrase, end - list) == 0;
+       }
+       return rc;
+}
+
+#if defined RE_TESTUNIT
+class TestReStringUtils : public ReTestUnit {
+public:
+       TestReStringUtils() : ReTestUnit("ReStringUtils", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               testStrnicmp();
+               testIsInList();
+               testSplitPath();
+       }
+       void testStrnicmp(){
+               checkT(ReStringUtils::strnicmp("abc", "abc", 3) == 0);
+               checkT(ReStringUtils::strnicmp("abc", "ab", 3) > 0);
+               checkT(ReStringUtils::strnicmp("ab", "abc", 3) < 0);
+
+               checkT(ReStringUtils::strnicmp("aBc", "Abc", 3) == 0);
+               checkT(ReStringUtils::strnicmp("Abc", "aB", 3) > 0);
+               checkT(ReStringUtils::strnicmp("AB", "abc", 3) < 0);
+
+               checkT(ReStringUtils::strnicmp("ABC", "ABD", 2) == 0);
+               checkT(ReStringUtils::strnicmp("abC", "ABD", 2) == 0);
+
+               checkT(ReStringUtils::strnicmp("AAC", "ABD", 2) < 0);
+               checkT(ReStringUtils::strnicmp("aaC", "ABD", 2) < 0);
+
+               checkT(ReStringUtils::strnicmp("", "x", 99) < 0);
+               checkT(ReStringUtils::strnicmp("x", "", 99) > 0);
+
+               checkT(ReStringUtils::strnicmp("abc", "abc", 99) == 0);
+               checkT(ReStringUtils::strnicmp("abc", "ab", 99) > 0);
+               checkT(ReStringUtils::strnicmp("ab", "abc", 99) < 0);
+       }
+       void testIsInList(){
+               checkT(ReStringUtils::isInList("abc", ";abc;def", true));
+               checkT(ReStringUtils::isInList("aBc", ";abc;def", true));
+               checkF(ReStringUtils::isInList("aBc", ";abc;def", false));
+
+               checkF(ReStringUtils::isInList("aBc", ";abc;def", false));
+
+               checkT(ReStringUtils::isInList("abc", ";a;abc;def", true));
+               checkT(ReStringUtils::isInList("aBc", ";b;abc;def", true));
+               checkF(ReStringUtils::isInList("aBc", ";c;abc;def", false));
+
+               checkF(ReStringUtils::isInList("aBc", ";a;abcabc;def", false));
+
+               checkT(ReStringUtils::isInList("abc", ";abc", true));
+               checkT(ReStringUtils::isInList("aBc", ";abc", true));
+               checkF(ReStringUtils::isInList("aBc", ";abc", false));
+
+               checkF(ReStringUtils::isInList("aBc", ";abc", false));
+
+       }
+       void testSplitPath(){
+               ReByteBuffer fullname, protocol, path, name, ext;
+               const char* fn = "file:/etc/samba/smb.cnf";
+
+               ReStringUtils::splitPath(fn, &protocol, &path, &name, &ext);
+               checkEqu("file:", protocol.str());
+               checkEqu("/etc/samba/", path.str());
+               checkEqu("smb", name.str());
+               checkEqu(".cnf", ext.str());
+
+               ReStringUtils::joinPath(fullname, &protocol, &path, &name, &ext);
+               checkEqu(fn, fullname.str());
+
+               fn = "/etc/samba/smb.cnf";
+
+               ReStringUtils::splitPath(fn, &protocol, &path, &name, &ext);
+               checkEqu("", protocol.str());
+               checkEqu("/etc/samba/", path.str());
+               checkEqu("smb", name.str());
+               checkEqu(".cnf", ext.str());
+
+               ReStringUtils::joinPath(fullname, &protocol, &path, &name, &ext);
+               checkEqu(fn, fullname.str());
+
+               fn = "smb.cnf";
+
+               ReStringUtils::splitPath(fn, &protocol, &path, &name, &ext);
+               checkEqu("", protocol.str());
+               checkEqu("", path.str());
+               checkEqu("smb", name.str());
+               checkEqu(".cnf", ext.str());
+
+               ReStringUtils::joinPath(fullname, &protocol, &path, &name, &ext);
+               checkEqu(fn, fullname.str());
+
+               fn = "smb";
+
+               ReStringUtils::splitPath(fn, &protocol, &path, &name, &ext);
+               checkEqu("", protocol.str());
+               checkEqu("", path.str());
+               checkEqu("smb", name.str());
+               checkEqu("", ext.str());
+
+               ReStringUtils::joinPath(fullname, &protocol, &path, &name, &ext);
+               checkEqu(fn, fullname.str());
+
+               fn = "file:smb.003.cnf";
+
+               ReStringUtils::splitPath(fn, &protocol, &path, &name, &ext);
+               checkEqu("file:", protocol.str());
+               checkEqu("", path.str());
+               checkEqu("smb.003", name.str());
+               checkEqu(".cnf", ext.str());
+
+               ReStringUtils::joinPath(fullname, &protocol, &path, &name, &ext);
+               checkEqu(fn, fullname.str());
+
+               fn = "file:/etc.bak/smb";
+
+               ReStringUtils::splitPath(fn, &protocol, &path, &name, &ext);
+               checkEqu("file:", protocol.str());
+               checkEqu("/etc.bak/", path.str());
+               checkEqu("smb", name.str());
+               checkEqu("", ext.str());
+
+               ReStringUtils::joinPath(fullname, &protocol, &path, &name, &ext);
+               checkEqu(fn, fullname.str());
+
+               fn = "file:/etc/samba/smb.cnf";
+
+               ReStringUtils::splitPath(fn, NULL, &path, &name, &ext);
+               checkEqu("file:", protocol.str());
+               checkEqu("smb", name.str());
+               checkEqu(".cnf", ext.str());
+
+               ReStringUtils::joinPath(fullname, &protocol, NULL, &name, &ext);
+               checkEqu("file:smb.cnf", fullname.str());
+
+               fn = "file:/etc/samba/smb.cnf";
+
+               ReStringUtils::splitPath(fn, NULL, NULL, &name, &ext);
+               checkEqu("smb", name.str());
+               checkEqu(".cnf", ext.str());
+
+               ReStringUtils::joinPath(fullname, NULL, NULL, &name, &ext);
+               checkEqu("smb.cnf", fullname.str());
+
+               fn = "file:/etc/samba/smb.cnf";
+
+               ReStringUtils::splitPath(fn, NULL, NULL, &name, NULL);
+               //checkEqu("", protocol.str());
+               //checkEqu("/etc/samba/", path.str());
+               checkEqu("smb", name.str());
+               //checkEqu(".cnf", ext.str());
+
+               ReStringUtils::joinPath(fullname, NULL, NULL, &name, NULL);
+               checkEqu("smb", fullname.str());
+
+               fn = "file:/etc/samba/smb.cnf";
+
+               ReStringUtils::splitPath(fn, NULL, &path, NULL, &ext);
+               //checkEqu("", protocol.str());
+               checkEqu("/etc/samba/", path.str());
+               //checkEqu("smb", name.str());
+               checkEqu(".cnf", ext.str());
+
+               ReStringUtils::joinPath(fullname, NULL, &path, NULL, &ext);
+               checkEqu("/etc/samba/.cnf", fullname.str());
+
+               ReStringUtils::joinPath(fullname, "http:", "//any.de/", "name", ".ext");
+               checkEqu("http://any.de/name.ext", fullname.str());
+
+               ReStringUtils::joinPath(fullname, NULL, "/any.de/", "name", ".ext");
+               checkEqu("/any.de/name.ext", fullname.str());
+
+               ReStringUtils::joinPath(fullname, NULL, NULL, "name", ".ext");
+               checkEqu("name.ext", fullname.str());
+
+               ReStringUtils::joinPath(fullname, NULL, NULL, "name", NULL);
+               checkEqu("name", fullname.str());
+
+               ReStringUtils::joinPath(fullname, "file:", "/", NULL, NULL);
+               checkEqu("file:/", fullname.str());
+       }
+};
+extern void testReStringUtils(void);
+
+void testReStringUtils(void){
+       TestReStringUtils unit;
+}
+#endif /*RE_TESTUNIT*/
+
diff --git a/base/ReStringUtils.hpp b/base/ReStringUtils.hpp
new file mode 100644 (file)
index 0000000..20b667a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * ReStringUtils.h
+ *
+ *  Created on: 16.05.2010
+ *      Author: wk
+ */
+
+#ifndef RESTRINGUTILS_H_
+#define RESTRINGUTILS_H_
+
+/**
+ * This class contains static methods only. In other words it builds a protected namespace.
+ * The methods defined here handle services on strings implemented by <code>ReByteBuffer</code>.
+ */
+class ReStringUtils {
+public:
+       //@ If used in <code>isInList()</code> the first character of the list will be the separator.
+       static const char AUTO_SEPARATOR;
+public:
+       static char initPathSeparator();
+       static char pathSeparator()
+       { return slash; }
+       static const char* pathSeparatorStr()
+       { return slashStr; }
+       static void splitPath(const char* fullname,
+               ReByteBuffer* protocol, ReByteBuffer* path, ReByteBuffer* name, ReByteBuffer* ext);
+       static ReByteBuffer& joinPath(ReByteBuffer& result,
+                       ReByteBuffer* protocol, ReByteBuffer* path, ReByteBuffer* name, ReByteBuffer* ext);
+       static ReByteBuffer& joinPath(ReByteBuffer& result,
+                       const char* protocol, const char* path, const char* name, const char* ext);
+       static int strnicmp(const char* string1, const char* string2, size_t length);
+       static bool isInList(const char* phrase, const char* list,
+                       bool ignoreCase = true, char separator = AUTO_SEPARATOR);
+private:
+       static char slash;
+       static const char* slashStr;
+};
+
+#endif /* RESTRINGUTILS_H_ */
diff --git a/base/ReTestUnit.cpp b/base/ReTestUnit.cpp
new file mode 100644 (file)
index 0000000..4d72caa
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * ReTestUnit.cpp
+ *
+ *  Created on: 04.05.2010
+ *      Author: wk
+ */
+#include <stdarg.h>
+
+#include "rebase.hpp"
+/** @brief Constructor.
+ *
+ * @param name                 The name of the test class.
+ * @param sourceFile   The file where contain the tests.
+ *                                             This will be used for error messages.
+ */
+ReTestUnit::ReTestUnit(const char* name, const char* sourceFile)
+       :
+       m_name(strdup(name)),
+       m_errorCount(0),
+       m_sourceFile(strdup(sourceFile))
+{
+       logF(false, i18n("Start %s"), name);
+}
+
+/** @brief Destructor.
+ */
+ReTestUnit::~ReTestUnit() {
+       if (m_errorCount > 0)
+               logF(true, i18n("%s: %d error(s)"), m_name, m_errorCount);
+       free((void*) m_name);
+       free((void*) m_sourceFile);
+}
+/** @brief Checks a boolean expression. A false value will be logged.
+ *
+ * @param condition            This expression will be tested.
+ *                                             If false an error messsage will be issued.
+ * @param lineNo               The line number of the test (for the error messge).
+ */
+void ReTestUnit::assertTrue(bool condition, int lineNo)
+{
+       if (! condition){
+               logF(true, i18n("%s-%d: not true!"), m_sourceFile, lineNo);
+               m_errorCount++;
+       }
+}
+/** @brief Checks a boolean expression. A true value will be logged.
+ *
+ * @param condition            This expression will be tested.
+ *                                             If tre an error messsage will be issued.
+ * @param lineNo               The line number of the test (for the error messge).
+ */
+void ReTestUnit::assertFalse(bool condition, int lineNo)
+{
+       if (condition){
+               logF(true, i18n("%s-%d: not false!"), m_sourceFile, lineNo);
+               m_errorCount++;
+       }
+}
+/** @brief Checks a pointer expression. A not <code>null</code> value will be logged.
+ *
+ * @param pointer              This expression will be tested.
+ *                                             If not <code>null</code> an error messsage will be issued.
+ * @param lineNo               The line number of the test (for the error messge).
+ */
+void ReTestUnit::assertNull(void* pointer, int lineNo){
+       if (pointer != NULL){
+               logF(true, "%s-%d: is not null %lx", m_sourceFile, lineNo, pointer);
+               m_errorCount++;
+       }
+}
+/** @brief Checks a pointer expression. A <code>null</code> value will be logged.
+ *
+ * @param pointer              This expression will be tested.
+ *                                             If <code>null</code> an error messsage will be issued.
+ * @param lineNo               The line number of the test (for the error messge).
+ */
+void ReTestUnit::assertNotNull(void* pointer, int lineNo){
+       if (pointer == NULL){
+               logF(true, i18n("%s-%d: is null"), m_sourceFile, lineNo);
+               m_errorCount++;
+       }
+}
+/** @brief Compares two integer values. If not equal this will be logged.
+ *
+ * @param expected             The expected value
+ * @param current              The current value.
+ * @param lineNo               The line number of the test (for the error messge).
+ */
+void ReTestUnit::assertEqual(long expected, long current, int lineNo){
+       if (expected != current){
+               logF(true, i18n("%s-%d: expected: %ld (%lx) current: %ld (%lx)"),
+                       m_sourceFile, lineNo, expected, expected, current, current);
+               m_errorCount++;
+       }
+}
+/** @brief Compares two string values. If not equal this will be logged.
+ *
+ * @param expected             The expected value
+ * @param current              The current value.
+ * @param lineNo               The line number of the test (for the error messge).
+ */
+void ReTestUnit::assertEqual(const char* expected, const char* current, int lineNo){
+       if (current == NULL || strcmp(expected, current) != 0){
+               logF(true, i18n("%s-%d: expected / current: length: %d / %d\n%.512s\n%.512s"),
+                       m_sourceFile, lineNo, strlen(expected), current == NULL ? 0 : strlen(current),
+                               expected, current == NULL ? "<null>" : current);
+               m_errorCount++;
+       }
+}
+/** @brief Checks whether a file exists. If not this will be logged.
+ *
+ * @param name                 The filename.
+ * @param lineNo               The line number of the test (for the error messge).
+ */
+void ReTestUnit::assertFileExists(const char* name, int lineNo){
+       struct stat info;
+       if (stat(name, &info) != 0){
+               logF(true, i18n("%s-%d: File does not exist: %s"),
+                       m_sourceFile, lineNo, name);
+               m_errorCount++;
+       } else if ((info.st_mode & __S_IFDIR) != 0){
+               logF(true, i18n("%s-%d: File does exist but this is a directory: %s"),
+                       m_sourceFile, lineNo, name);
+               m_errorCount++;
+       }
+}
+/** @brief Creates an empty temporary directory.
+ * The name can be retrieved by <code>getTestDir()</code>.
+ */
+void ReTestUnit::createTestDir(){
+       char name[512];
+       if (getenv("TMP") != NULL){
+               strcpy(name, getenv("TMP"));
+       } else if (getenv("TEMP")){
+               strcpy(name, getenv("TEMP"));
+       } else {
+               strcpy(name, "/tmp/");
+       }
+       char* ptr = name + strlen(name) - 1;
+       if (*ptr != ReStringUtils::pathSeparator())
+               strcpy(ptr + 1, ReStringUtils::pathSeparatorStr());
+       strcat(ptr, "retestunit");
+       strcat(ptr, ReStringUtils::pathSeparatorStr());
+       struct stat info;
+       if (lstat(name, &info) != 0)
+               mkdir(name, ALLPERMS);
+       else{
+               char cmd[512 + 128];
+               snprintf(cmd, sizeof cmd, "rm -Rf %s*", name);
+               system(cmd);
+       }
+       strcpy(m_tempDir, name);
+}
+/** @brief Returns The temporary directory.
+ *
+ * @return The name of a temporary directory.
+ */
+const char* ReTestUnit::getTestDir(){
+       return (const char*) m_tempDir;
+}
+/** @brief Creates a file and fills it with an given content.
+ *
+ * @param filename     The name of the file.
+ * @param content      The content of the file. If NULL the file will be empty.
+ */
+void ReTestUnit::createFile(const char* filename, const char* content){
+       FILE* fp = fopen(filename, "w");
+       if (fp != NULL && content != NULL){
+               fwrite(content, strlen(content), 1, fp);
+               fclose(fp);
+       }
+}
+/** @brief Creates a file and fills it with an given content.
+ *
+ * @param filename     The name of the file.
+ * @param content      The content of the file. If NULL the file will be empty.
+ */
+void ReTestUnit::createDir(const char* filename){
+       mkdir(filename, ALLPERMS);
+}
+
+
+/** @brief Checks whether a directory exists. If not this will be logged.
+ *
+ * @param dir                  The name of the directory.
+ * @param lineNo               The line number of the test (for the error messge).
+ */
+void ReTestUnit::assertDirExists(const char* dir, int lineNo){
+       struct stat info;
+       if (stat(dir, &info) != 0){
+               logF(true, i18n("%s-%d: Directory does not exist: %s"),
+                       m_sourceFile, lineNo, dir);
+               m_errorCount++;
+       } else if ((info.st_mode & __S_IFDIR) == 0){
+               logF(true, i18n("%s-%d: File exists but this is not a directory: %s"),
+                       m_sourceFile, lineNo, dir);
+               m_errorCount++;
+       }
+}
+
+/** @brief Logs a message.
+ *
+ * It can be used to inform the user about coming (error-) messages.
+ *
+ * @param isError      true: The message is an error message. false: Otherwise.
+ * @param message      The message to issue.
+ *
+ * @return <code>! isError</code>
+ */
+bool ReTestUnit::log(bool isError, const char* message){
+       printf("%s%s\n", isError ? "+++ " : "", message);
+       return ! isError;
+}
+/** @brief Logs a formated message with placeholders.
+ *
+ * It can be used to inform the user about coming (error-) messages.
+ *
+ * @param isError      true: The message is an error message. false: Otherwise.
+ * @param format       The message with placeholders like <code>printf</code>.
+ * @param ...          A variable number of arguments which replace the placeholders.
+ *
+ * @return <code>! isError</code>
+ */
+bool ReTestUnit::logF(bool isError, const char* format, ...){
+       char buffer[2048];
+       va_list args;
+
+       va_start(args, format);
+       vsnprintf(buffer, sizeof buffer, format, args);
+       va_end(args);
+       return log(isError, buffer);
+}
+
+#if defined RE_TESTUNIT
+class TestTestUnit : public ReTestUnit {
+public:
+       TestTestUnit() : ReTestUnit("TestTest", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               checkT(true);
+               checkF(false);
+               checkN(NULL);
+               checkNN("");
+               checkEqu(1, 1);
+               checkEqu("abc", "abc");
+               checkDirExists("/etc/");
+               checkFileExists("/etc/passwd");
+               log(false, "8 errors follow:");
+               checkT(false);
+               checkF(true);
+               checkN("");
+               checkNN(NULL);
+               checkEqu(1, 2);
+               checkEqu("abc", "abcd");
+               checkDirExists("/etc!/");
+               checkFileExists("/etc!/passwd");
+               log(false, "8 errors expected!");
+       }
+};
+extern void testReTestUnit(void);
+
+void testReTestUnit(void){
+       TestTestUnit unit;
+}
+#endif /*RE_TESTUNIT*/
diff --git a/base/ReTestUnit.hpp b/base/ReTestUnit.hpp
new file mode 100644 (file)
index 0000000..3a8bc6c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * ReTestUnit.h
+ *
+ *  Created on: 04.05.2010
+ *      Author: wk
+ */
+
+#ifndef RETESTUNIT_H_
+#define RETESTUNIT_H_
+
+class ReTestUnit {
+public:
+       ReTestUnit(const char* name, const char* sourcefile);
+       virtual ~ReTestUnit();
+private:
+               // Not accessible, not implemented!
+       ReTestUnit(const ReTestUnit& source);
+               // Not accessible, not implemented!
+       ReTestUnit& operator =(const ReTestUnit& source);
+public:
+       void assertTrue(bool conditon, int lineNo);
+       void assertFalse(bool conditon, int lineNo);
+       void assertNull(void* pointer, int lineNo);
+       void assertNotNull(void* pointer, int lineNo);
+       void assertEqual(long expected, long current, int lineNo);
+       void assertEqual(const char* expected, const char* current, int lineNo);
+
+       void createTestDir();
+       const char* getTestDir();
+       void createFile(const char* filename, const char* content);
+       void createDir(const char* filename);
+
+       void assertFileExists(const char* name, int lineNo);
+       void assertDirExists(const char* dir, int lineNo);
+
+       virtual bool log(bool isError, const char* message);
+       virtual bool logF(bool isError, const char* format, ...);
+protected:
+       const char* m_name;
+       int m_errorCount;
+       const char* m_sourceFile;
+       char m_tempDir[512];
+};
+#define checkT(cond) assertTrue(cond, __LINE__)
+#define checkF(cond) assertFalse(cond, __LINE__)
+#define checkN(ptr) assertNull((void*) ptr, __LINE__)
+#define checkNN(ptr) assertNotNull((void*) ptr, __LINE__)
+#define checkEqu(exp, cur) assertEqual(exp, cur, __LINE__)
+#define checkFileExists(fn) assertFileExists(fn, __LINE__)
+#define checkDirExists(fn) assertDirExists(fn, __LINE__)
+#endif /* RETESTUNIT_H_ */
diff --git a/base/ReVarArgs.cpp b/base/ReVarArgs.cpp
new file mode 100644 (file)
index 0000000..96e8eea
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * ReVarArgs.cpp
+ *
+ *  Created on: 05.05.2010
+ *      Author: wk
+ */
+/**
+ * <pre><strong>Example:</strong>
+ * <code>
+ * struct stat info;
+ * stat("/etc/passwd");
+ * ReVarArgs list;
+ * const char* info2 = list.reset("$1: Size: $2 $3").arg(info.st_fname)
+ *     .arg(info.st_size, "%8d").arg(info.st_size, "%8x").asCString();
+ * </code></pre>
+ */
+#include "rebase.hpp"
+
+int const ReVarArgs::STD_SPACE = 20;
+char const ReVarArgs::PLACE_HOLDER_MARK = '$';
+
+typedef ReByteBuffer::Byte Byte;
+/** @brief Constructor.
+ */
+ReVarArgs::ReVarArgs(void)
+       :
+       m_argNo(0),
+       m_format(),
+       m_argBuffer(),
+       // m_args
+       m_stringIsReady(false),
+       m_trigger(NULL)
+{
+}
+
+/** @brief Constructor.
+ *
+ * @param format       The format with the placeholders.
+ * @throws <code>ReFormatException()</code> There are gaps in the numbers of the placeholders.
+ */
+ReVarArgs::ReVarArgs(const char* format)
+       :
+       m_argNo(0),
+       m_format(),
+       m_argBuffer(),
+       // m_args
+       m_stringIsReady(false),
+       m_trigger(NULL)
+{
+       reset(format);
+}
+/** @brief Resets the instance.
+ *
+ * Sets a new format and waits for the arguments.
+ *
+ * @param format       A format string containing placeholders for arguments.
+ *
+ * @result A reference for the instance itself. This allows chaining.
+ * @throws <code>ReFormatException()</code> There are gaps in the numbers of the placeholders.
+ */
+ReVarArgs& ReVarArgs::reset(const char* format){
+       m_argNo = 0;
+       memset(m_args, 0, sizeof m_args);
+       m_format.setLength(0);
+       m_format.append(format, strlen(format));
+       m_stringIsReady = false;
+
+       // Test the placehoders in the format and find the argument count:
+       // No gaps are allowed.
+       m_maxArgNo = 0;
+       int position = m_format.indexOf(PLACE_HOLDER_MARK);
+       int argNo;
+       while (position >= 0){
+               Byte cc = m_format.at(position + 1);
+               if (cc == PLACE_HOLDER_MARK){
+                               // $$ found: replace with $:
+                       position++;
+               } else if (! isdigit(cc)){
+                               // $ found. No action.
+                       position++;
+               } else {
+                       int argNoLen = 2;
+                       argNo = m_format.at(position + 1) - '0';
+                       cc = m_format.at(position + 2);
+                       if (isdigit(cc)){
+                               argNoLen++;
+                               argNo = 10 * argNo + cc - '0';
+                       }
+                       if (argNo > m_maxArgNo)
+                               m_maxArgNo = argNo;
+                       m_args[argNo]++;
+                       position += argNoLen;
+               }
+               position = m_format.indexOf(PLACE_HOLDER_MARK, position);
+       }
+               // Searching the first gap:
+       for (int ii = 1; ii < m_maxArgNo; ii++)
+               if (m_args[ii] == 0){
+                       char msg[128];
+                       snprintf(msg, sizeof msg, i18n("missing $%d in format: "), ii);
+                       throw ReFormatException(msg, format);
+               }
+
+       memset(m_args, 0, sizeof m_args);
+       return *this;
+}
+/** @brief Replaces the placeholders with the strings from <code>m_args</code>.
+ *
+ * @throws ReFormatException   There are wrong placeholders.
+ */
+void ReVarArgs::replacePlaceholder(){
+       int position = m_format.indexOf(PLACE_HOLDER_MARK);
+       int found = 0;
+       int argNo;
+       while (position >= 0){
+               Byte cc = m_format.at(position + 1);
+               if (cc == PLACE_HOLDER_MARK){
+                               // $$ found: replace with $:
+                       m_format.remove(position, 1);
+                       position++;
+               } else if (! isdigit(cc)){
+                               // $ found. No action.
+                       position++;
+               } else {
+                       found++;
+                       int argNoLen = 2;
+                       argNo = m_format.at(position + 1) - '0';
+                       cc = m_format.at(position + 2);
+                       if (isdigit(cc)){
+                               argNoLen++;
+                               argNo = 10 * argNo + cc - '0';
+                       }
+                       if (argNo > m_argNo){
+                               throw ReFormatException(i18n("Too large argument number: "),
+                                       m_format.getBuffer() + position,
+                                        __FILE__, __LINE__);
+                       } else {
+                               char* arg = m_argBuffer.getBuffer() + m_args[argNo];
+                               size_t argLen = strlen(arg);
+                               m_format.splice(position, argNoLen, arg, argLen);
+                               position += argLen;
+                       }
+               }
+               position = m_format.indexOf(PLACE_HOLDER_MARK, position);
+       }
+       if (found < m_argNo)
+               throw ReFormatException(i18n("Format contains to few placeholders"),
+                       m_format.getBuffer(), __FILE__, __LINE__);
+}
+/** @brief Stores an argument.
+ *
+ * After the argument is stored and a trigger exists this trigger will be called.
+ *
+ * @param value                The argument string.
+ * @param length       The length of <code>value</code>.
+ */
+void ReVarArgs::store(const char* value, int length){
+       if (length < 0)
+               length = strlen(value);
+               // Store the first index of the argument in <code>m_argBuffer</code>.
+       m_args[++m_argNo] = m_argBuffer.getLength();
+               // Store the string with trailing '\0':
+       m_argBuffer.append(value, length);
+       m_argBuffer.append("", 1);
+       if (m_trigger != NULL)
+               m_trigger->newArg(m_argNo, m_maxArgNo);
+}
+/* @brief Defines an integer argument.
+ *
+ * @param value                The integer value of the argument.
+ * @param format       The format (used with sprintf()) of the argument, e.g. "%d".
+ *
+ * @return The instance itself. This is useful for chaining.
+ */
+ReVarArgs& ReVarArgs::ReVarArgs::arg(int value, const char* format){
+       char number[256];
+       snprintf(number, sizeof number, format, value);
+       store(number);
+       return *this;
+}
+
+/** @brief Stores an long argument.
+ *
+ * @param value                The argument value.
+ * @param format       The format (used with sprintf()) of the argument, e.g. "%d".
+ *
+ * @return The instance itself. This is useful for chaining.
+ */
+ReVarArgs& ReVarArgs::arg(long value, const char* format){
+       char number[256];
+       snprintf(number, sizeof number, format, value);
+       store(number);
+       return *this;
+}
+/** @brief Stores a string argument.
+ *
+ * If the string is shorter than the given minimum the string was padded with a given filler.
+ * The position of the supplemented part (in top of or behind) was controlled by the alignment.
+ * If the string was longer than the given maximum the string was cut.
+ *
+ * @param value                The argument string.
+ * @param minWidth     The minimum length of the string.
+ *
+ * @return The instance itself. This is useful for chaining.
+ */
+ReVarArgs& ReVarArgs::arg(const char* value, int minWidth, int maxWidth, bool alignRight){
+       int length = strlen(value);
+       if (maxWidth <= 0 || length < maxWidth)
+               maxWidth = length;
+       if (minWidth > maxWidth)
+               maxWidth = minWidth;
+       if (length >= minWidth){
+               store(value, maxWidth);
+       } else {
+               ReByteBuffer buffer;
+               buffer.setLengthAndFill(minWidth, ' ');
+               if (alignRight)
+                       memcpy(buffer.getBuffer() + minWidth - length, value, length);
+               else
+                       memcpy(buffer.getBuffer(), value, length);
+               store (buffer.getBuffer(), buffer.getLength());
+       }
+       return *this;
+}
+/** @brief Stores an double argument.
+ *
+ * @param value                The argument value.
+ * @param format       The format (used with sprintf()) of the argument, e.g. "%d".
+ *
+ * @return The instance itself. This is useful for chaining.
+ */
+ReVarArgs& ReVarArgs::arg(double value, const char* format){
+       char number[256];
+       snprintf(number, sizeof number, format, value);
+       store(number);
+       return *this;
+}
+/** @brief Returns a C string with the expanded format.
+ *
+ * If not done the placeholders will be replaced by the arguments.
+ *
+ * @return     A C string with the string which is the format with
+ *                     the replaced placeholders.
+ * @throws ReFormatException() Too few arguments.
+ */
+const char* ReVarArgs::asCString(){
+       if (m_argNo != m_maxArgNo)
+               throw ReFormatException(i18n("To few arguments"),
+                       m_format.getBuffer());
+
+       if (! m_stringIsReady){
+               replacePlaceholder();
+               m_stringIsReady = true;
+       }
+       return m_format.getBuffer();
+}
+
+/** @brief Stores a trigger.
+ *
+ * @param trigger              An instance of <code>ReVarArgTrigger</code> or NULL.
+ *                                             After storing an argument (calling <code>arg()</code>
+ *                                             <code>trigger->newArg()</code> will be called.
+ */
+void ReVarArgs::registerTrigger(ReVarArgTrigger* trigger){
+       m_trigger = trigger;
+}
+/** @brief Marks the end of a <code>arg()</code> chain.
+ *
+ * This method is only meaningful in derived classes.
+ * If some actions can be done only when all arguments are known
+ * they will be defined in an overwritten method of <code>end()</code>.
+ * <pre>
+ * Example:
+ * <code>
+ * // ReLogger is derived from ReVarArgs:
+ * logger->sayF("Files: $1 Directories: $2").arg(files).arg(dirs).end();
+ * // The logging is done in the method end().
+ * </code></pre>
+ */
+void ReVarArgs::end(void){
+       // Nothing to do in this base class
+}
+
+#if defined RE_TESTUNIT
+class TestReVarArgs : public ReTestUnit, public ReVarArgTrigger {
+public:
+       TestReVarArgs()
+               :
+               ReTestUnit("ReVarArgs", __FILE__),
+               m_argNo(0),
+               m_maxNo(0)
+       {
+               run();
+       }
+       virtual void newArg(int no, int maxNo){
+               m_argNo = no;
+               m_maxNo = maxNo;
+       }
+private:
+       void run(){
+               ReVarArgs list("$1 $$ $2");
+               list.registerTrigger(this);
+
+               list.arg(0).arg(9, "%03u");
+               checkEqu(m_argNo, 2);
+               checkEqu(m_maxNo, 2);
+               checkEqu("0 $ 009", list.asCString());
+
+
+               list.reset("x$1y$2");
+               list.arg(1.5);
+               checkEqu(m_argNo, 1);
+               checkEqu(m_maxNo, 2);
+               list.arg(2.45,"%7.3f");
+               checkEqu(m_argNo, 2);
+               checkEqu(m_maxNo, 2);
+               checkEqu("x1.500000y  2.450", list.asCString());
+
+               list.reset("$2,$1!$3;$4");
+               list.arg("1").arg("ab", 4);
+               list.arg("xy", 0, 1);
+               checkEqu(m_argNo, 3);
+               checkEqu(m_maxNo, 4);
+               list.arg("ww", 5, 0, true);
+               checkEqu(m_argNo, 4);
+               checkEqu(m_maxNo, 4);
+               checkEqu("ab  ,1!x;   ww", list.asCString());
+       }
+private:
+       int m_argNo;
+       int m_maxNo;
+};
+extern void testReVarArgs(void);
+
+void testReVarArgs(void){
+       TestReVarArgs unit;
+}
+#endif /*RE_TESTUNIT*/
+
diff --git a/base/ReVarArgs.hpp b/base/ReVarArgs.hpp
new file mode 100644 (file)
index 0000000..e4258a1
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * ReVarArgs.h
+ *
+ *  Created on: 05.05.2010
+ *      Author: wk
+ */
+
+#ifndef REVARARGS_H_
+#define REVARARGS_H_
+
+/** This class will be used as callback method for <code>ReVarArgs</code>.
+ */
+class ReVarArgTrigger{
+public:
+       /** @brief This method will be called when a new <code>ReVarArg::log()</code> call was done.
+        * The call was done after the insertion of the argument into the internal structures.
+        * @param no    The number of the argument (1..max)
+        * @param maxNo The number of placeholders in the format.
+        */
+       virtual void newArg(int no, int maxNo) = 0;
+};
+/**
+ * Implements a typesafe method for populate a format string containing placeholders
+ * with some values.
+ * <p>Another known system with this functionality is <code>printf</code>.
+ * But the <code>ReVarArgs</code> is typesafe.</p>
+ */
+class ReVarArgs{
+private:
+       static int const STD_SPACE;
+       static char const PLACE_HOLDER_MARK;
+
+public:
+       ReVarArgs();
+       ReVarArgs(const char* format);
+private:
+       void initialize(size_t size);
+       void replacePlaceholder();
+       void store(const char* value, int length = -1);
+
+public:
+       ReVarArgs& reset(const char* format);
+       ReVarArgs& arg(int value, const char* format = "%d");
+       ReVarArgs& arg(long arg, const char* format = "%ld");
+       ReVarArgs& arg(const char* arg, int minWidth = 0, int maxWidth = 1024, bool alignRight = false);
+       ReVarArgs& arg(double arg, const char* format = "%f");
+       const char* asCString();
+       virtual void end(void);
+       void registerTrigger(ReVarArgTrigger* trigger);
+protected:
+               //@ The current argument number: 1..99
+       int                     m_argNo;
+               //@ The maximum of all argument numbers in the format.
+       int                             m_maxArgNo;
+               //@ Stores the format. When the first call of <code>asCharPtr()</code>
+               //@ the expanded string will be stored here.
+       ReByteBuffer    m_format;
+               //@ Stores the argument strings including the trailing '\0'.
+       ReByteBuffer    m_argBuffer;
+               //@ Stores the positions (indexes) of the arguments in m_argBuffer.
+       int                             m_args[100];
+               //@ true: The compound string is constructed (with expanded placeholders). false: Otherwise.
+       bool                    m_stringIsReady;
+               //@ Callback mechanism: <code>m_trigger.newArg()</code> will be called in <code>store()</code>.
+       ReVarArgTrigger* m_trigger;
+};
+
+#endif /* REVARARGS_H_ */
diff --git a/base/baselocations.hpp b/base/baselocations.hpp
new file mode 100644 (file)
index 0000000..c67c0ee
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * baselocations.hpp
+ *
+ *  Created on: 19.05.2010
+ *      Author: wk
+ */
+
+#ifndef BASELOCATIONS_HPP_
+#define BASELOCATIONS_HPP_
+
+/** The files of the REal PUBlic LIB use the range from 50000 until 99999.
+ */
+enum RELOC_RECONFIGFILE {
+       LC_CONFIGFILE_DOUBLE            = 50001,
+       LC_CONFIGFILE_NO_INT            = 50002,
+       LC_CONFIGFILE_NO_BOOL           = 50003,
+};
+enum RELOC_UDPCONNECTION {
+       LC_UDPCONNECTION_CONSTRUCT              = 50101,
+       LC_UDPCONNECTION_RECEIVE_1              = 50102,
+       LC_UDPCONNECTION_RECEIVE_2              = 50103,
+       LC_UDPCONNECTION_SEND_1                 = 50104,
+       LC_UDPCONNECTION_SEND_2                 = 50105,
+       LC_UDPCONNECTION_CLOSE_1                = 50106,
+       LC_UDPCONNECTION_CLOSE_2                = 50107,
+       LC_UDPCONNECTION_CONNECT_1              = 50108,
+       LC_UDPCONNECTION_CONNECT_2              = 50109,
+       LC_UDPCONNECTION_RUN_1                  = 50110,
+};
+enum RELOC_LOGGER {
+       LC_LOGGER_SAYF_OPEN                     = 50201,
+};
+enum RELOC_CSTRING {
+       LC_CSTRING_REPLACE_1            = 50301,
+};
+#endif /* BASELOCATIONS_HPP_ */
diff --git a/base/rebase.hpp b/base/rebase.hpp
new file mode 100644 (file)
index 0000000..bbcd5b1
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * stdincludes.hpp
+ *
+ *  Created on: 05.05.2010
+ *      Author: wk
+ */
+#ifndef REBASE_HPP_
+#define REBASE_HPP_
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+
+#define __LINUX__
+
+#if defined __LINUX__
+
+#include <dirent.h>
+#include <fnmatch.h>
+#include <regex.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#elif defined WIN32
+
+typedef _int64 int64_t;
+
+#endif
+
+#define RE_TESTUNIT
+#include "base/ReByteBuffer.hpp"
+#include "base/ReVarArgs.hpp"
+#include "base/ReLogger.hpp"
+#include "base/ReTestUnit.hpp"
+#include "base/ReCString.hpp"
+#include "base/ReException.hpp"
+#include "base/ReStringUtils.hpp"
+#include "base/ReDirectory.hpp"
+#include "base/ReSeqList.hpp"
+#include "base/ReStringList.hpp"
+#include "base/ReHashList.hpp"
+#include "base/ReConfigFile.hpp"
+#include "base/ReI18N.hpp"
+#include "base/ReProgramArgs.hpp"
+
+typedef unsigned char byte_t;
+
+#include "../base/baselocations.hpp"
+#endif /* REBASE_HPP_ */
diff --git a/base/remath.hpp b/base/remath.hpp
new file mode 100644 (file)
index 0000000..a7528d5
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * remath.hpp
+ *
+ *  Created on: 26.11.2010
+ *      Author: wk
+ */
+
+#ifndef REMATH_HPP_
+#define REMATH_HPP_
+
+#ifndef REBASE_HPP_
+#include "base/rebase.hpp"
+#endif
+#include "math/ReObfuscator.hpp"
+#include "math/ReRandomizer.hpp"
+
+#endif /* REMATH_HPP_ */
diff --git a/base/renet.hpp b/base/renet.hpp
new file mode 100644 (file)
index 0000000..4be9e2e
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * renet.hpp
+ *
+ *  Created on: 26.11.2010
+ *      Author: wk
+ */
+
+#ifndef RENET_HPP_
+#define RENET_HPP_
+
+#ifndef REBASE_HPP_
+#include "../base/rebase.hpp"
+#endif
+#include "net/ReUdpConnection.hpp"
+#endif /* RENET_HPP_ */
diff --git a/base/restring.hpp b/base/restring.hpp
new file mode 100644 (file)
index 0000000..3cbd7cd
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * restring.hpp
+ *
+ *  Created on: 15.11.2010
+ *      Author: wk
+ */
+
+#ifndef RESTRING_HPP_
+#define RESTRING_HPP_
+
+#ifndef REBASE_HPP_
+#include "../base/rebase.hpp"
+#endif
+// ReCString.hpp, ReI18N.hpp, ReStringList.hpp and ReStringUtils.hpp are included in rebase.hpp!
+
+#endif /* RESTRING_HPP_ */
diff --git a/crepublib.doxyfile b/crepublib.doxyfile
new file mode 100644 (file)
index 0000000..aec1b5c
--- /dev/null
@@ -0,0 +1,1630 @@
+# Doxyfile 1.7.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = crepublib
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = v0.3
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING = 
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST = YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = reinc base net string math 
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET = 
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME = 
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS = 
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS = 
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION = 
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvances is that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE = 
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA = 
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH = 
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans.ttf
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/cunit/basetest.cpp b/cunit/basetest.cpp
new file mode 100644 (file)
index 0000000..ff4a23a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * stdtest.cpp
+ *
+ *  Created on: 05.05.2010
+ *      Author: wk
+ */
+#include "../base/rebase.hpp"
+#if defined RE_TESTUNIT
+extern void testReBase(void);
+void testReBase(void){
+       try{
+               extern void testReProgramArgs(void);
+               testReProgramArgs();
+               extern void testReI18N(void);
+               testReI18N();
+               extern void testReStringList(void);
+               testReStringList();
+               extern void testReSeqList(void);
+               testReSeqList();
+               extern void testReHashList(void);
+               testReHashList();
+               void testReException(void);
+               testReException();
+               void testReStringUtils(void);
+               testReStringUtils();
+               extern void testReVarArgs(void);
+               testReVarArgs();
+               extern void testReByteBuffer();
+               testReByteBuffer();
+               extern void testReString(void);
+               testReString();
+               extern void testReVarArgs(void);
+               testReVarArgs();
+               extern void testReLogger(void);
+               testReLogger();
+               extern void testReDirectory(void);
+               testReDirectory();
+       } catch (ReException e){
+               fprintf(stderr, "unexpected exception: %s\n", e.getMessage());
+       }
+}
+#endif /*RE_TESTUNIT*/
diff --git a/cunit/cuReByteBuffer.cpp b/cunit/cuReByteBuffer.cpp
new file mode 100644 (file)
index 0000000..927fc17
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * cuReByteBuffer.cpp
+ *
+ *  Created on: 27.11.2010
+ *      Author: wk
+ */
+#include "../base/rebase.hpp"
+class TestReByteBuffer : public ReTestUnit {
+       typedef ReByteBuffer::Byte Byte;
+public:
+       TestReByteBuffer() : ReTestUnit("ReByteBuffer", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               testOpAssignCopyConstructor();
+               testAt();
+               testEnsureSizeGetLength();
+               testBasic();
+               testAtoi();
+               testIndexOfRIndexOf();
+               testInsert();
+               testRemove();
+               testSplice();
+               testReplace();
+       }
+       void testBasic(){
+               ReByteBuffer buffer(10);
+
+               buffer.append((Byte*)"123", 3);
+               checkEqu("123", buffer.getBuffer());
+               checkEqu("123", buffer.str());
+               checkEqu(3, buffer.getLength());
+               buffer.append((Byte*)"ab", 2);
+               checkEqu("123ab", buffer.getBuffer());
+               checkEqu(5, buffer.getLength());
+
+               buffer.setLengthAndFill(8, 'x');
+               checkEqu("123abxxx", buffer.getBuffer());
+               checkEqu(8, buffer.getLength());
+               buffer.setLength(3);
+               checkEqu("123", buffer.getBuffer());
+               checkEqu(3, buffer.getLength());
+
+               buffer.setLengthAndFill(511, 'y');
+               buffer.setLengthAndFill(512, 'z');
+               checkEqu("yyz", buffer.getBuffer() + 509);
+               checkEqu(521, buffer.getSize());
+
+               ReByteBuffer buffer2;
+               buffer2.set("xyz", -1);
+               buffer.set("abc", -1);
+               checkEqu("abc", buffer.getBuffer());
+               checkEqu(3, buffer.getLength());
+               buffer.append(buffer2);
+               checkEqu("abcxyz", buffer.getBuffer());
+               checkEqu("abcxyz", buffer.str());
+               checkEqu(6, buffer.getLength());
+
+               buffer.setLength(0);
+               buffer.appendInt(-1);
+               checkEqu("-1", buffer.str());
+               checkEqu(2, buffer.getLength());
+
+               buffer.appendInt(9, "%03d");
+               checkEqu("-1009", buffer.str());
+               checkEqu(5, buffer.getLength());
+       }
+       void testOpAssignCopyConstructor() {
+               ReByteBuffer buf1;
+               buf1.set("abc", 3);
+               ReByteBuffer buf3;
+               {
+                       ReByteBuffer buf2(buf1);
+                       checkEqu("abc", buf2.str());
+                       buf3 = buf2;
+                       buf2.append("123", 3);
+               }
+               checkEqu("abc", buf3.str());
+               checkEqu("abc", buf1.str());
+       }
+       void testAt(){
+               ReByteBuffer buf1;
+               buf1.set("abc", 3);
+               for (size_t ii = 0; ii < buf1.getLength(); ii++){
+                       checkEqu('a' + ii, buf1.at(ii));
+               }
+               checkEqu(0, buf1.at(-1));
+               checkEqu(0, buf1.at(3));
+               checkEqu(0, buf1.at(4));
+       }
+       void testAtoi(){
+               ReByteBuffer buffer;
+               buffer.set("y1234", -1);
+
+               checkEqu(1, buffer.atoi(1, 2));
+               checkEqu(12, buffer.atoi(1, 3));
+               checkEqu(123, buffer.atoi(1, 4));
+               checkEqu(1234, buffer.atoi(1, 5));
+               checkEqu(1234, buffer.atoi(1, 6));
+               checkEqu(0, buffer.atoi(0, 6));
+
+               buffer.set("456y", -1);
+
+               checkEqu(4, buffer.atoi(0, 1));
+               checkEqu(45, buffer.atoi(0, 2));
+               checkEqu(456, buffer.atoi(0, 3));
+               checkEqu(456, buffer.atoi(0, 4));
+               checkEqu(0, buffer.atoi(4, 6));
+
+               buffer.set("987654321", -1);
+               checkEqu(987654321, buffer.atoi());
+
+               buffer.set("187654302ab", -1);
+               checkEqu(187654302, buffer.atoi());
+
+
+               buffer.set("y0x1234", -1);
+
+               checkEqu(0x1, buffer.atoi(1, 4));
+               checkEqu(0x12, buffer.atoi(1, 5));
+               checkEqu(0x123, buffer.atoi(1, 6));
+               checkEqu(0x1234, buffer.atoi(1, 7));
+               checkEqu(0x1234, buffer.atoi(1, 8));
+               checkEqu(0, buffer.atoi(0, 8));
+               checkEqu(0, buffer.atoi(2, 8));
+
+               buffer.set("0x456y", -1);
+
+               checkEqu(0x4, buffer.atoi(0, 3));
+               checkEqu(0x45, buffer.atoi(0, 4));
+               checkEqu(0x456, buffer.atoi(0, 6));
+               checkEqu(0x456, buffer.atoi(0, 7));
+               checkEqu(0, buffer.atoi(5, 6));
+
+               buffer.set("0x98765432", -1);
+               checkEqu(0x98765432, buffer.atoi());
+
+               buffer.set("0xabcdef01", -1);
+               checkEqu(0xabcdef01, buffer.atoi());
+               buffer.set("0xABCDEF01", -1);
+               checkEqu(0xabcdef01, buffer.atoi());
+               buffer.set("0xaFFe01", -1);
+               checkEqu(0xaFFe01, buffer.atoi());
+       }
+       void testEnsureSizeGetLength(){
+               ReByteBuffer buf1;
+               buf1.ensureSize(2000);
+               checkEqu(2000, buf1.getSize());
+               buf1.set("0123456789", 10);
+               checkEqu(10, buf1.getLength());
+
+               buf1.setLength(5);
+               checkEqu("01234", buf1.str());
+               checkEqu(5, buf1.getLength());
+
+               buf1.setLengthAndFill(8, 'X');
+               checkEqu("01234XXX", buf1.str());
+               checkEqu(8, buf1.getLength());
+               checkEqu(2000, buf1.getSize());
+       }
+
+       void testIndexOfRIndexOf(){
+               ReByteBuffer buffer;
+               buffer.set("123123", -1);
+               checkEqu(0, buffer.indexOf('1'));
+               checkEqu(1, buffer.indexOf('2'));
+               checkEqu(3, buffer.indexOf('1', 1));
+               checkEqu(2, buffer.indexOf('3', 2));
+               checkEqu(5, buffer.indexOf('3', 3));
+               checkEqu(-1, buffer.indexOf('4'));
+               checkEqu(-1, buffer.indexOf('1', 4));
+
+               checkEqu(3, buffer.rindexOf('1'));
+               checkEqu(4, buffer.rindexOf('2'));
+               checkEqu(3, buffer.rindexOf('1', -2));
+               checkEqu(3, buffer.rindexOf('1', -3));
+               checkEqu(0, buffer.rindexOf('1', -4));
+
+               checkEqu(4, buffer.rindexOf('2', 4));
+               checkEqu(1, buffer.rindexOf('2', 3));
+
+               checkEqu(4, buffer.rindexOf('2', -2));
+               checkEqu(1, buffer.rindexOf('2', -3));
+
+               checkEqu(0, buffer.rindexOf('1', 0));
+
+               checkEqu(-1, buffer.rindexOf('4'));
+               checkEqu(-1, buffer.rindexOf('2', 0));
+
+               checkEqu(1, buffer.indexOf("23", 2, 0));
+               checkEqu(1, buffer.indexOf("23", -1, 0));
+               checkEqu(1, buffer.indexOf("23x", 2, 0));
+               checkEqu(4, buffer.indexOf("23", 2, 2));
+               checkEqu(4, buffer.indexOf("23", -1, 2));
+
+               checkEqu(-1, buffer.indexOf("234", -1, 0));
+               checkEqu(-1, buffer.indexOf("23", -1, 5));
+       }
+       void testInsert(){
+               ReByteBuffer buf1;
+               checkT(buf1.insert(0, "123", 2));
+               checkEqu("12", buf1.str());
+               checkEqu(2, buf1.getLength());
+
+               checkT(buf1.insert(0, "abc", 1));
+               checkEqu("a12", buf1.str());
+               checkEqu(3, buf1.getLength());
+
+               checkT(buf1.insert(1, "x", 1));
+               checkEqu("ax12", buf1.str());
+               checkEqu(4, buf1.getLength());
+
+               checkT(buf1.insert(4, "yz", 2));
+               checkEqu("ax12yz", buf1.str());
+               checkEqu(6, buf1.getLength());
+
+               checkF(buf1.insert(-1, "-", 1));
+               checkF(buf1.insert(8, "/", 1));
+
+       }
+       void testRemove(){
+               ReByteBuffer buf1;
+               buf1.set("1234567890", 10);
+               checkT(buf1.remove(0, 2));
+               checkEqu("34567890", buf1.str());
+               checkEqu(8, buf1.getLength());
+
+               checkF(buf1.remove(-1, 2));
+               checkEqu("34567890", buf1.str());
+               checkEqu(8, buf1.getLength());
+
+               checkF(buf1.remove(9, 2));
+               checkEqu("34567890", buf1.str());
+               checkEqu(8, buf1.getLength());
+
+               checkT(buf1.remove(7, 2));
+               checkEqu("3456789", buf1.str());
+               checkEqu(7, buf1.getLength());
+
+               checkT(buf1.remove(5, 2));
+               checkEqu("34567", buf1.str());
+               checkEqu(5, buf1.getLength());
+
+               checkT(buf1.remove(0, 99));
+               checkEqu("", buf1.str());
+               checkEqu(0, buf1.getLength());
+       }
+       void testReplace(){
+               ReByteBuffer buffer;
+
+               buffer.set("1234", 4);
+               buffer.replaceAll("12", 2, "abc", 3);
+               checkEqu("abc34", buffer.str());
+
+               buffer.replaceAll("c34", 2, "uv", 3);
+               checkEqu("abuv", buffer.str());
+
+               buffer.set("$$x$$", -1);
+               buffer.replaceAll("$", 1, "XX", 2);
+               checkEqu("XXXXxXXXX", buffer.str());
+       }
+       void testSplice(){
+               ReByteBuffer buffer;
+
+               buffer.append((Byte*) "12.ab", 5);
+               checkT(buffer.splice(0, 0, "xy", 2));
+               checkEqu("xy12.ab", buffer.getBuffer());
+               buffer.splice(2, 2, NULL, 0);
+               checkEqu("xy.ab", buffer.getBuffer());
+               buffer.splice(0, 2, "w", 1);
+               checkEqu("w.ab", buffer.getBuffer());
+
+               buffer.setLength(0);
+               buffer.append((Byte*) "123", 3);
+               buffer.insert(1, "ab", 2);
+               checkEqu("1ab23", buffer.getBuffer());
+               checkEqu(5, buffer.getLength());
+               buffer.remove(0, 1);
+               checkEqu("ab23", buffer.getBuffer());
+               checkEqu(4, buffer.getLength());
+               buffer.remove(3, 55);
+               checkEqu("ab2", buffer.getBuffer());
+               checkEqu(3, buffer.getLength());
+               buffer.remove(2, 2);
+               checkEqu("ab", buffer.getBuffer());
+               checkEqu(2, buffer.getLength());
+               buffer.remove(1, 1);
+               checkEqu("a", buffer.getBuffer());
+               checkEqu(1, buffer.getLength());
+       }
+};
+extern void testReByteBuffer(void);
+
+void testReByteBuffer(void){
+       TestReByteBuffer unit;
+}
+
diff --git a/cunit/cuReCString.cpp b/cunit/cuReCString.cpp
new file mode 100644 (file)
index 0000000..ae5aaa8
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * cuReCString.cpp
+ *
+ *  Created on: 23.11.2010
+ *      Author: wk
+ */
+#include "../base/restring.hpp"
+
+class TestReString : public ReTestUnit {
+public:
+       TestReString() : ReTestUnit("ReString", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               testReplaceSubstring();
+       }
+       void testReplaceSubstring(){
+               char buffer[256];
+
+               strcpy(buffer, "12.ab");
+               replaceSubstring(buffer, sizeof buffer, 0, "xy");
+               checkEqu("xy12.ab", buffer);
+               replaceSubstring(buffer + 2, sizeof buffer - 2, 2, "");
+               checkEqu("xy.ab", buffer);
+               replaceSubstring(buffer, sizeof buffer, 2, "w");
+               checkEqu("w.ab", buffer);
+               log(false, "1 error expected!");
+               replaceSubstring(buffer, 5, 0, "x");
+               replaceSubstring(buffer, 6, 0, "x");
+               checkEqu("xw.ab", buffer);
+       }
+};
+extern void testReString(void);
+
+void testReString(void){
+       TestReString unit;
+}
+
diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp
new file mode 100644 (file)
index 0000000..7ad4b2e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * cuReTraverser.cpp
+ *
+ *  Created on: 23.12.2014
+ *      Author: hm
+ */
+
+#include "base/rebase.hpp"
+#include "os/reos.hpp"
+
+class TestReTraverser : public ReTestUnit {
+public:
+       TestReTraverser() : ReTestUnit("ReTraverser", __FILE__){
+               run();
+       }
+private:
+       void run(){
+               testReplaceSubstring();
+       }
+       void testReplaceSubstring(){
+               ReTraverser traverser("/tmp/test");
+               int level = 0;
+               const DirStatus_t* entry = traverser.nextFile(level);
+               checkEqu("xy12.ab", nameOfEntry(entry));
+       }
+};
+extern void testReTraverser(void);
+
+void testReTraverser(void){
+       TestReTraverser unit;
+}
diff --git a/cunit/testall.cpp b/cunit/testall.cpp
new file mode 100644 (file)
index 0000000..6635971
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * testall.cpp
+ *
+ *  Created on: 24.11.2010
+ *      Author: wk
+ */
+#include "base/rebase.hpp"
+#include "os/reos.hpp"
+#include "net/renet.hpp"
+
+void testBase(){
+       extern void testReByteBuffer();
+       testReByteBuffer();
+       extern void testReSeqList(void);
+       testReSeqList();
+       extern void testReHashList(void);
+       testReHashList();
+       void testReException(void);
+       testReException();
+       extern void testReVarArgs(void);
+       testReVarArgs();
+       extern void testReString(void);
+       testReString();
+       extern void testReVarArgs(void);
+       testReVarArgs();
+       extern void testReLogger(void);
+       testReLogger();
+       extern void testReDirectory(void);
+       testReDirectory();
+       extern void testReProgramArgs(void);
+       testReProgramArgs();
+}
+void testString(){
+       void testReString();
+       testReString();
+       extern void testReI18N(void);
+       testReI18N();
+       extern void testReStringList(void);
+       testReStringList();
+       void testReStringUtils(void);
+       testReStringUtils();
+       extern void testReString(void);
+       testReString();
+}
+void testOs(){
+       void testReTraverser();
+       testReTraverser();
+}
+void testAll(){
+       try
+       {
+               testOs();
+               testBase();
+               testString();
+       } catch (ReException e){
+               fprintf(stderr, "testBase.cpp: unexpected exception: %s\n", e.getMessage());
+       }
+
+}
+void testCurrent(){
+       try
+       {
+               void testReByteBuffer();
+               testReByteBuffer();
+       } catch (ReException e){
+               fprintf(stderr, "testBase.cpp: unexpected exception: %s\n", e.getMessage());
+       }
+}
diff --git a/math/ReObfuscator.cpp b/math/ReObfuscator.cpp
new file mode 100644 (file)
index 0000000..8bd4e70
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * ReObfuscator.cpp
+ *
+ *  Created on: 13.11.2010
+ *      Author: wk
+ */
+
+#include "base/rebase.hpp"
+#include "base/remath.hpp"
+
+/** @brief Constructor.
+ *
+ * @param rand         Random generator.
+ * @param charSet      Specifies the character set which will be en/decoded.
+ */
+ReObfuscator::ReObfuscator(ReRandomizer& rand, CharSet charSet) :
+       m_rand(rand),
+       m_charSet(charSet),
+       m_min(0),
+       m_max(0),
+       m_range(0)
+{
+       switch(charSet){
+       case CHAR96:
+               m_min = ' ';
+               m_max = 127;
+               m_range = 96;
+               break;
+       case CHAR224:
+               m_min = ' ';
+               m_max = 255;
+               m_range = 224;
+               break;
+       case CHAR256:
+               m_min = 0;
+               m_max = 255;
+               m_range = 256;
+               break;
+       }
+}
+
+/** @brief Destructor.
+ */
+ReObfuscator::~ReObfuscator() {
+}
+
+/** @brief Decodes one character.
+ *
+ * @param cc   The character to decode.
+ *
+ * @return The decoded character.
+ */
+char ReObfuscator::decode(char cc) const{
+       char rc;
+       int src = (int) (unsigned char) cc;
+       switch(m_charSet){
+       case CHAR96:
+       case CHAR224:
+               if (src < m_min || src > m_max)
+                       rc = cc;
+               else {
+                       src = (src - m_min) - m_rand.nextInt(0, m_range - 1);
+                       if (src < 0)
+                               src += m_range;
+                       rc = (char) m_min + src;
+               }
+               break;
+       case CHAR256:
+               rc = (char) (src + (src + m_rand.nextInt(0, m_range - 1) % m_range));
+               break;
+       default:
+               rc = (char) src;
+               break;
+       }
+       return rc;
+
+}
+
+/** @brief Decodes a string.
+ *
+ * Decodes every character of a given string in place.
+ *
+ * @param buffer               In/Out: The string to encode.
+ * @param bufferLength -1: buffer contains a 0-terminated string.
+ *                                             Otherwise: The number of character to decode.
+ *
+ * @return The buffer.
+ */
+char* ReObfuscator::decode(char* buffer, int bufferLength) const {
+       if(bufferLength == -1)
+               bufferLength = strlen(buffer);
+       for (int ii = 0; ii < bufferLength; ii++)
+               buffer[ii] = decode(buffer[ii]);
+       return buffer;
+}
+
+/** @brief Encodes one character.
+ *
+ * @param cc   The character to encode.
+ *
+ * @return The encoded character.
+ */
+char ReObfuscator::encode(char cc) const{
+       char rc;
+       int src = (int) (unsigned char) cc;
+       switch(m_charSet)
+       {
+       case CHAR96:
+       case CHAR224:
+               if (src < m_min || src > m_max)
+                       rc = cc;
+               else
+                       rc = char (((src - m_min) + m_rand.nextInt(0, m_range - 1)) % m_range + m_min);
+               break;
+       case CHAR256:
+               rc = (char) (src + (src + m_rand.nextInt(0, m_range - 1) % m_range));
+               break;
+       default:
+               rc = (char) src;
+               break;
+       }
+       return rc;
+}
+
+/** @brief Encodes a string.
+ *
+ * Encodes every character of a given string in place.
+ *
+ * @param buffer               In/Out: The string to encode.
+ * @param bufferLength -1: buffer contains a 0-terminated string.
+ *                                             Otherwise: The number of character to encode.
+ *
+ * @return The buffer.
+ */
+char* ReObfuscator::encode(char* buffer, int bufferLength) const{
+       if(bufferLength == -1)
+               bufferLength = strlen(buffer);
+       for (int ii = 0; ii < bufferLength; ii++)
+               buffer[ii] = encode(buffer[ii]);
+       return buffer;
+}
+
+/** @brief Returns the current character set.
+ *
+ * @return The current character set.
+ */
+ReObfuscator::CharSet ReObfuscator::getCharSet() const{
+       return m_charSet;
+}
+
+/** @brief Returns the random generator
+ *
+ * @return The random generator.
+ */
+ReRandomizer& ReObfuscator::getRandomizer() const{
+       return m_rand;
+}
+
+/** @brief Sets the character set.
+ *
+ * @param newSet       The character set to set.
+ */
+void ReObfuscator::setCharSet(CharSet newSet){
+       m_charSet = newSet;
+}
+
+static void testOne(const char* src, int bufferLength,
+               ReObfuscator& obf, ReCongruentialGenerator& rand){
+       char buffer[256+1];
+       assert((size_t) bufferLength < sizeof buffer);
+       memcpy(buffer, src, bufferLength);
+       buffer[bufferLength] = '\0';
+       rand.setSeed(0x4711);
+       obf.encode(buffer, bufferLength);
+       char buffer2[256+1];
+       memcpy(buffer2, buffer, bufferLength);
+       buffer2[bufferLength] = '\0';
+       rand.setSeed(0x4711);
+       obf.decode(buffer2, bufferLength);
+       if (memcmp(buffer2, src, bufferLength) != 0)
+               printf("%3d:%s\n -> %s\n -> %s\n", (int) obf.getCharSet(), src, buffer, buffer2);
+}
+static void testIt(const char* src, int bufferLength,
+               ReObfuscator& obf, ReCongruentialGenerator& rand){
+       if (bufferLength == -1)
+               bufferLength = strlen(src);
+       obf.setCharSet(ReObfuscator::CHAR96);
+       testOne(src, bufferLength, obf, rand);
+       obf.setCharSet(ReObfuscator::CHAR224);
+       testOne(src, bufferLength, obf, rand);
+       obf.setCharSet(ReObfuscator::CHAR256);
+       testOne(src, bufferLength, obf, rand);
+}
+
+void testObfuscator(){
+       ReCongruentialGenerator rand;
+       ReObfuscator obf(rand);
+
+       //testOne(" ", obf, rand);
+       testIt("ABC", -1, obf, rand);
+       testIt("Hello Dolly!", -1, obf, rand);
+       testIt(" !§$%&/(()=`öäü1234\r\n\t\nabcdefghi", -1, obf, rand);
+       char line[256];
+       for (int ii = 0; ii < 255; ii++)
+               line[ii] = ii + 1;
+       line[255] = '\0';
+       testIt(line, 256, obf, rand);
+}
diff --git a/math/ReObfuscator.hpp b/math/ReObfuscator.hpp
new file mode 100644 (file)
index 0000000..38f5fa9
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * ReObfuscator.h
+ *
+ *  Created on: 13.11.2010
+ *      Author: wk
+ */
+
+#ifndef REOBFUSCATOR_H_
+#define REOBFUSCATOR_H_
+
+#include "math/ReRandomizer.hpp"
+
+class ReObfuscator {
+public:
+       enum CharSet {
+               CHAR96 = 96,
+               CHAR224 = 224,
+               CHAR256 = 256,
+       };
+public:
+       ReObfuscator(ReRandomizer& rand, CharSet charSet = CHAR96);
+       virtual ~ReObfuscator();
+public:
+       char encode(char cc) const;
+       char decode(char cc) const;
+       char* encode(char* buffer, int bufferLength = -1) const;
+       char* decode(char* buffer, int bufferLength = -1) const;
+       void setCharSet(CharSet newSet);
+       CharSet getCharSet() const;
+       ReRandomizer& getRandomizer() const;
+private:
+       ReRandomizer& m_rand;
+       CharSet m_charSet;
+       int m_min;
+       int m_max;
+       int m_range;
+};
+
+#endif /* REOBFUSCATOR_H_ */
diff --git a/math/ReRandomizer.cpp b/math/ReRandomizer.cpp
new file mode 100644 (file)
index 0000000..552b750
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * ReRandomizer.cpp
+ *
+ *  Created on: 01.11.2010
+ *      Author: wk
+ */
+
+#include "assert.h"
+#include "memory.h"
+#include "limits.h"
+#include "math.h"
+#include "remath.hpp"
+
+static bool s_trace = false;
+/**
+ * @brief Constructor.
+ */
+ReRandomizer::ReRandomizer(){
+}
+/**
+ * @brief Destructor.
+ */
+ReRandomizer::~ReRandomizer() {
+}
+
+inline int abs(int x) { return x < 0 ? -x : x; }
+
+/**
+ * @brief Returns the next random character.
+ *
+ * The character is in the range ' ' .. chr(127) (inclusive).
+ *
+ * @return The next random character.
+ */
+char ReRandomizer::nextChar()
+{
+       char rc = nextInt(' ', ' ' + CHARRANGE - 1);
+       return rc;
+}
+
+/**
+ * @brief Returns the next random integer.
+ *
+ *
+ * @param minValue     The minimum of the result.
+ * @param maxValue     The maximum of the result (including).
+ *
+ * @return The next seed.
+ */
+int ReRandomizer::nextInt(int minValue, int maxValue){
+       int rc;
+       if (minValue > maxValue){
+               rc = minValue;
+               minValue = maxValue;
+               maxValue = rc;
+       }
+       seed_t seed = nextSeed();
+       if (minValue == maxValue)
+               rc = minValue;
+       else if (minValue == 0 && maxValue == INT_MAX)
+               rc = abs(seed);
+       else if (unsigned(maxValue - minValue) < INT_MAX)
+               rc = minValue + seed % (maxValue - minValue + 1);
+       else {
+               double rc2 = minValue + fmod((double) seed, maxValue - minValue);
+               rc = (int) rc2;
+       }
+       if (s_trace){
+               static int count = 0;
+               printf ("%c %8x ", count++ % 4 == 0 ? '\n' : ' ', rc);
+       }
+       return rc;
+}
+
+/**
+ * @brief Calculates the next seed for the generator.
+ *
+ * @return The next seed.
+ */
+ReRandomizer::seed_t ReCongruentialGenerator::nextSeed(){
+       m_seed =  m_seed * m_factor + m_increment;
+       return m_seed;
+}
+
+/**
+ * @brief Returns a string with random characters.
+ *
+ * All character will be inside the range ' ' .. chr(127).
+ *
+ * @param buffer       Out: The place for the string.
+ * @param maxLength    The maximum length of the result string.
+ * @param minLength    The minimum length of the result string.
+ *
+ * @result The buffer.
+ */
+char* ReRandomizer::nextString(char* buffer, int maxLength, int minLength){
+       int len = nextInt(minLength, maxLength);
+       for (int ii = 0; ii < len; ii++){
+               buffer[ii] = nextChar();
+       }
+       buffer[len] = '\0';
+       return buffer;
+}
+/**
+ * @brief Builds a random permutation of an array.
+ *
+ * The operation will be done in place:
+ *
+ * @param array                In/Out: The array to shuffle.
+ * @param length       The length of the array.
+ * @param elemSize     The size of one element of the array.
+ */
+void ReRandomizer::shuffle(void* array, size_t length, size_t elemSize){
+       int ii;
+       char* cptr;
+       int* iptr;
+       int count = length * 3 / 2;
+
+       switch(elemSize)
+       {
+       case 1:
+               cptr = (char*) array;
+               for (ii = 0; ii < count; ii++){
+                       int ix1 = length - nextInt(1, length);
+                       int ix2 = length - nextInt(1, length);
+                       char x = cptr[ix1];
+                       cptr[ix1] = cptr[ix2];
+                       cptr[ix2] = x;
+               }
+               break;
+       case sizeof(int):
+               iptr = (int*) array;
+               for (ii = 0; ii < count; ii++){
+                       int ix1 = length - nextInt(1, length);
+                       int ix2 = length - nextInt(1, length);
+                       int x = iptr[ix1];
+                       iptr[ix1] = iptr[ix2];
+                       iptr[ix2] = x;
+               }
+               break;
+       default:
+       {
+               char buffer[0x10000];
+               assert(elemSize < sizeof buffer);
+               iptr = (int*) array;
+               for (ii = 0; ii < count; ii++){
+                       int ix1 = length - nextInt(1, length);
+                       int ix2 = length - nextInt(1, length);
+                       char* p1 = ((char*) array) + ix1 * elemSize;
+                       char* p2 = ((char*) array) + ix2 * elemSize;
+                       memcpy(buffer, p1, elemSize);
+                       memcpy(p1, p2, elemSize);
+                       memcpy(p2, buffer, elemSize);
+               }
+               break;
+       }
+       }
+}
+/**
+ * @brief Constructor.
+ */
+ReCongruentialGenerator::ReCongruentialGenerator() :
+       m_seed(0x4711),
+       m_factor(2631),
+       m_increment(0x9)
+{
+}
+/**
+ * @brief Destructor.
+ */
+ReCongruentialGenerator::~ReCongruentialGenerator(){
+}
+
+/**
+ * @brief Returns the current factor.
+ *
+ * @return The current factor.
+ */
+ReRandomizer::seed_t ReCongruentialGenerator::getFactor() const
+{
+    return m_factor;
+}
+
+/**
+ * @brief Returns the current increment.
+ *
+ * @return The current increment.
+ */
+ReRandomizer::seed_t ReCongruentialGenerator::getIncrement() const
+{
+    return m_increment;
+}
+
+/**
+ * Returns the current seed.
+ *
+ * @return The current seed.
+ */
+ReRandomizer::seed_t ReCongruentialGenerator::getSeed() const
+{
+    return m_seed;
+}
+
+/**
+ * Sets the factor.
+ *
+ * @param factor       The new factor.
+ */
+void ReCongruentialGenerator::setFactor(seed_t factor)
+{
+    this->m_factor = factor;
+}
+
+/**
+ * Sets the increment.
+ *
+ * @param increment    The new increment.
+ */
+void ReCongruentialGenerator::setIncrement(seed_t increment)
+{
+    this->m_increment = increment;
+}
+
+/** @brief Sets the current seed.
+ *
+ * @param seed The seed to set.
+ */
+void ReCongruentialGenerator::setSeed(seed_t seed)
+{
+    this->m_seed = seed;
+    if (s_trace)
+       printf(" Seed: %x ", seed);
+}
+
diff --git a/math/ReRandomizer.hpp b/math/ReRandomizer.hpp
new file mode 100644 (file)
index 0000000..958649b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * ReRandomizer.h
+ *
+ *  Created on: 01.11.2010
+ *      Author: wk
+ */
+
+#ifndef RANDOMIZER_H_
+#define RANDOMIZER_H_
+#include "stdio.h"
+#include "limits.h"
+
+/**
+ * This implements an abstract base class for random generators.
+ */
+class ReRandomizer {
+public:
+       enum { CHARRANGE = 128 - ' ' };
+       typedef unsigned int seed_t;
+public:
+       ReRandomizer();
+       virtual ~ReRandomizer();
+public:
+       virtual int nextInt(int minValue = 0, int maxValue = INT_MAX);
+       void shuffle(void* array, size_t length, size_t elemSize);
+       char nextChar();
+       char* nextString(char* buffer, int maxLength = 80, int minLength = 0);
+protected:
+    virtual seed_t nextSeed() = 0;
+};
+
+/**
+ * Implements a simple random generator.
+ * A linear congruential generator produces the next value using this formula:
+ * seed = (seed * factor + increment) % modulus
+ * In this implementation modulus is 2**32.
+ */
+class ReCongruentialGenerator : public ReRandomizer {
+public:
+       ReCongruentialGenerator();
+       virtual ~ReCongruentialGenerator();
+public:
+    seed_t getFactor() const;
+    seed_t getIncrement() const;
+    void setFactor(seed_t factor);
+    void setIncrement(seed_t increment);
+    seed_t getSeed() const;
+    void setSeed(seed_t m_seed);
+private:
+       virtual seed_t nextSeed();
+private:
+       seed_t m_seed;
+       seed_t m_factor;
+       seed_t m_increment;
+};
+
+#endif /* RANDOMIZER_H_ */
diff --git a/math/remath.hpp b/math/remath.hpp
new file mode 100644 (file)
index 0000000..d3b64bc
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * remath.hpp
+ *
+ *  Created on: 23.12.2014
+ *      Author: hm
+ */
+
+#ifndef REMATH_HPP_
+#define REMATH_HPP_
+
+#include "ReObfuscator.hpp"
+#include "ReRandomizer.hpp"
+
+#endif /* REMATH_HPP_ */
diff --git a/net/ReUdpConnection.cpp b/net/ReUdpConnection.cpp
new file mode 100644 (file)
index 0000000..6c2ad5b
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * ReUdpServer.cpp
+ *
+ *  Created on: 12.11.2010
+ *      Author: wk
+ */
+#include "../base/renet.hpp"
+
+/** @brief Constructor.
+ *
+ * param verbose       TRUE:
+ */
+ReUdpConnection::ReUdpConnection(bool isServer, ReLogger* logger) :
+       m_socket(0),
+       //m_address
+       m_buffer(8096),
+       m_port(-1),
+       m_logger(logger),
+       m_isServer(isServer)
+{
+       memset(&m_address, 0, sizeof m_address);
+    if ((m_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+        m_logger->sayF(LOG_ERROR|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_CONSTRUCT,
+                       i18n("Cannot creat a socket: $1")).arg(strerror(errno)).end();
+        exit(1);
+    }
+}
+/** @brief Destructor.
+ *
+ * Closes the connection.
+ */
+ReUdpConnection::~ReUdpConnection() {
+       close();
+}
+/** @brief Returns the ip address as a string.
+ *
+ * @return The IP address as string.
+ */
+const char* ReUdpConnection::getAddress() const {
+       const char* rc = inet_ntoa(m_address.sin_addr);
+       return rc;
+}
+/** @brief Receives an UDP message.
+ *
+ * There are two modes:
+ * <ul><li>Blocking: The method waits until the next message.</li>
+ * <li>Non blocking: The method returns when a message has been received
+ * or the timeout has reached.</li>
+ * </ul>
+ *
+ * @param timeout      0: Blocking mode.
+ *                                     Otherwise: The timeout in milliseconds.
+ * @param buffer       NULL: The internal buffer will be used.
+ *                                     Otherwise: The buffer for the received message.
+ *
+ * @return     0: No message has been received.
+ *                     Otherwise: The length of the received message.
+ *
+ */
+int ReUdpConnection::receive(int timeout, ReByteBuffer* buffer, bool doLog){
+       socklen_t addrLength = sizeof m_address;
+       bool doRead = true;
+       if (buffer == NULL){
+               buffer = &m_buffer;
+       }
+       if (timeout > 0){
+               int maxfd = m_socket;
+               fd_set rdset;
+               bzero(&rdset, sizeof rdset);
+               FD_SET(m_socket, &rdset);
+               timeval timeval;
+               timeval.tv_sec = timeout / 1000;
+               timeval.tv_usec = timeout % 1000 * 1000;
+               select(maxfd+1, &rdset, NULL, NULL, &timeval);
+               doRead = FD_ISSET(m_socket, &rdset);
+       }
+       buffer->ensureSize(8096 + 1);
+       size_t size = buffer->getSize();
+       buffer->setLength(size);
+       if (!doRead)
+               m_logger->sayF(LOG_WARNING|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_RECEIVE_2,
+                               i18n("Nothing received since $1 sec")).arg(timeout/1000.0, "%.3f").end();
+       else {
+               int length = recvfrom(
+                       m_socket,
+                       buffer->getBuffer(), size - 1, 0,
+                       (struct sockaddr *) &m_address,
+                       &addrLength);
+               buffer->setLength(length >= 0 ? length : 0);
+               if (doLog)
+                       m_logger->sayF(LOG_INFO|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_RECEIVE_1,
+                               "$1:$2 $3").arg(getAddress()).arg(m_port)
+                               .arg(buffer->getBuffer()).end();
+       }
+       return buffer->getLength();
+}
+/** @brief Sends a message.
+ *
+ * @param buffer               The buffer to send.
+ * @param bufferLength The length of buffer[].
+ *
+ * @return     &gt; 0: Failure.
+ *                     Otherwise: The number of sent bytes.
+ *
+ */
+int ReUdpConnection::send(const char* buffer, int bufferLength){
+       socklen_t size = sizeof (m_address);
+       if (bufferLength == -1)
+               bufferLength = strlen(buffer);
+       int rc = sendto(m_socket, buffer, bufferLength, 0,
+               (sockaddr*)&m_address, size);
+       if (rc <= 0)
+        m_logger->sayF(LOG_ERROR|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_SEND_1,
+                       i18n("Sending failed: $1:$2 $3"))
+                       .arg(getAddress()).arg(m_port).arg(strerror(errno)).end();
+       else
+        m_logger->sayF(LOG_INFO|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_SEND_2,
+                       i18n("$1 bytes sent")).arg(rc).end();
+       return rc;
+}
+/** @brief Returns the internal receive buffer.
+ *
+ * @return The internal buffer.
+ */
+ReByteBuffer& ReUdpConnection::getBuffer(){
+       return m_buffer;
+}
+
+/** @brief Closes the connection.
+ */
+void ReUdpConnection::close(){
+       if (m_socket != 0)
+       {
+        m_logger->sayF(LOG_INFO|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_CLOSE_1,
+                       i18n("Connection has been closed: $1:$2")).arg(getAddress()).arg(m_port).end();
+               if (::close(m_socket) != 0)
+               m_logger->sayF(LOG_ERROR|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_CLOSE_2,
+                               i18n("socket close failed: $1")).arg(strerror(errno)).end();
+               m_socket = 0;
+       }
+}
+
+/** @brief Constructor.
+ *
+ * @param logger       Logger.
+ */
+ReUdpServer::ReUdpServer(ReLogger* logger) :
+       ReUdpConnection(true, logger)
+{
+}
+
+/** @brief Destructor.
+ */
+ReUdpServer::~ReUdpServer() {
+}
+
+/** @brief Initializes a connection.
+ *
+ * @param port The port to connect.
+ *
+ * @return true: Success. false: Connection failed.
+ */
+
+bool ReUdpServer::connect(int port){
+       bool rc = true;
+    m_address.sin_family = AF_INET;
+    m_address.sin_port = htons(port);
+    m_address.sin_addr.s_addr = INADDR_ANY;
+    bzero(&(m_address.sin_zero), 8);
+
+    if (bind(m_socket,(struct sockaddr *)&m_address,
+        sizeof(struct sockaddr)) == -1)
+    {
+        m_logger->sayF(LOG_ERROR|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_CONNECT_1,
+                       i18n("bind() failed on port $1: $2")).arg(port).arg(strerror(errno)).end();
+        rc = false;
+    }
+    else
+               m_logger->sayF(LOG_INFO|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_CONNECT_2,
+                               i18n("Waiting for client on port $1")).arg(port).end();
+
+       m_port = port;
+       return rc;
+}
+/** @brief Constructor.
+ *
+ * @param logger       Logger.
+ */
+ReUdpClient::ReUdpClient(ReLogger* logger) :
+       ReUdpConnection(false, logger){
+}
+
+/** @brief Destructor.
+ */
+ReUdpClient::~ReUdpClient() {
+}
+
+/** @brief Initializes a UDP connection.
+ *
+ * @param ip   The IP address as string.
+ * @param port The port of the connection.
+ *
+ * @param return true: Success.
+ */
+bool ReUdpClient::connect(const char* ip, int port){
+    struct hostent *host;
+    bool rc = false;
+    host= (struct hostent *) gethostbyname((char *) ip);
+
+    if (host == NULL){
+               m_logger->sayF(LOG_ERROR|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_CONNECT_1,
+                               i18n("Invalid IP: $1")).arg(ip).end();
+    } else {
+               m_address.sin_family = AF_INET;
+               m_address.sin_port = htons(port);
+               m_address.sin_addr = *((struct in_addr *)host->h_addr);
+               bzero(&(m_address.sin_zero),8);
+
+               m_logger->sayF(LOG_INFO|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_CONNECT_2,
+                               i18n("Connected to $1:$2")).arg(ip).arg(port).end();
+               m_port = port;
+               rc = true;
+    }
+       return rc;
+}
+
+/** @brief Constructor.
+ *
+ * @param port         The port of the connection.
+ * @param logger       Logger.
+ */
+ReUdpMaster::ReUdpMaster(int port, ReLogger* logger) :
+               ReUdpServer(logger)
+{
+       connect(port);
+}
+
+/** @brief Destructor.
+ */
+ReUdpMaster::~ReUdpMaster(){
+}
+/** @brief Tests whether the message can be logged.
+ *
+ * This is a simple default method returning always true.
+ * A deriving class can overwrite to log some messages and
+ * hide others.
+ *
+ * @param message      The message to test.
+ *
+ * @return     true: The message should be logged.
+ *                     false: Otherwise.
+ */
+bool ReUdpMaster::canLog(ReByteBuffer& message){
+       return true;
+}
+
+/** @brief Receives UDP messages and send answers.
+ */
+void ReUdpMaster::run(){
+       ReByteBuffer answer;
+       bool again = true;
+       while(again){
+               receive(0, NULL, false);
+               answer.setLength(0);
+               if (canLog(m_buffer))
+                       m_logger->sayF(LOG_INFO|GRAN_USER|CAT_NETWORK, LC_UDPCONNECTION_RUN_1,
+                               "$1:$2 $3").arg(getAddress()).arg(m_port)
+                               .arg(m_buffer.getBuffer()).end();
+
+               again = handlePage(m_buffer, answer, *this);
+               if (answer.getLength() > 0){
+                       send(answer.getBuffer(), answer.getLength());
+               }
+       }
+}
diff --git a/net/ReUdpConnection.hpp b/net/ReUdpConnection.hpp
new file mode 100644 (file)
index 0000000..2b729d1
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * ReUdpServer.h
+ *
+ *  Created on: 12.11.2010
+ *      Author: wk
+ */
+
+#ifndef UDPSERVER_H_
+#define UDPSERVER_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+/**
+ * Implements a base class for UDP server and client.
+ */
+class ReUdpConnection {
+public:
+       ReUdpConnection(bool isServer, ReLogger* logger);
+       virtual ~ReUdpConnection();
+public:
+       const char* getAddress() const;
+       int getPort() const
+       { return m_port; }
+       int receive(int timeout = 0, ReByteBuffer* buffer = NULL, bool doLog = true);
+       int send(const char* buffer, int bufferLength = -1);
+       void close();
+       ReByteBuffer& getBuffer();
+protected:
+       int m_socket;
+       struct sockaddr_in m_address;
+       ReByteBuffer m_buffer;
+       int m_port;
+       time_t m_lastReceipt;
+       ReLogger* m_logger;
+       bool m_isServer;
+};
+
+/**
+ * Implements the base functionality of a server
+ * handling the UDP protocol.
+ */
+class ReUdpServer : public ReUdpConnection {
+public:
+       ReUdpServer(ReLogger* logger);
+       virtual ~ReUdpServer();
+public:
+       bool connect(int port);
+};
+
+/**
+ * Implements an abstract base class for a server
+ * handling the UDP protocol.
+ * A real server must implement only the method
+ * handlePage().
+ */
+class ReUdpMaster : public ReUdpServer
+{
+public:
+       ReUdpMaster(int port, ReLogger* logger);
+       virtual ~ReUdpMaster();
+       virtual bool canLog(ReByteBuffer& message);
+public:
+       void run();
+protected:
+       virtual bool handlePage(ReByteBuffer& buffer,
+               ReByteBuffer& answer, ReUdpMaster& server) = 0;
+};
+
+/**
+ * Implements a client handling the UDP protocol.
+ */
+class ReUdpClient : public ReUdpConnection {
+public:
+       ReUdpClient(ReLogger* logger);
+       virtual ~ReUdpClient();
+public:
+       bool connect(const char* ip, int port);
+};
+
+
+#endif /* UDPSERVER_H_ */
diff --git a/net/renet.hpp b/net/renet.hpp
new file mode 100644 (file)
index 0000000..ba71b75
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * renet.hpp
+ *
+ *  Created on: 23.12.2014
+ *      Author: hm
+ */
+
+#ifndef NET_RENET_HPP_
+#define NET_RENET_HPP_
+
+#include "net/ReUdpConnection.hpp"
+
+#endif /* NET_RENET_HPP_ */
diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp
new file mode 100644 (file)
index 0000000..61a73aa
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * ReTraverser.cpp
+ *
+ *  Created on: 23.12.2014
+ *      Author: hm
+ */
+
+#include "../base/rebase.hpp"
+#include "os/reos.hpp"
+
+#ifdef __LINUX__
+#define isUndefHandle(handle) ((handle) == NULL)
+#define findFirstEntry(path, data) opendir(path)
+#define findNextEntry(handle,data) (((data) = readdir(handle)) != NULL)
+#define closeDir(handle) closedir(handle)
+#define initEntryBuffer(entry)
+#define setHandleUndef(h) ((h) = NULL)
+#else
+#define isUndefHandle(handle) ((handle) == INVALID_HANDLE_VALUE)
+#define setHandleUndef(h) ((h) = INVALID_HANDLE_VALUE)
+#define findFirstEntry(path, pattern, data) FindFirstFileA(path, pattern, data)
+#define findNextEntry(handle, data) (FindNextFileA(handle, data) != 0)
+#define closeDir(handle) FindClose(handle)
+#define initEntryBuffer(entry) ((entry)->m_data = &(entry)->m_buffer)
+#endif
+
+/**
+ * Constructor.
+ */
+ReMatcher::ReMatcher() :
+       m_prefix(1),
+       m_suffix(1),
+       m_tokens(0),
+       m_findAll(false),
+       m_ignoreCase(true),
+       m_notPattern(false)
+{
+       memset((void*) m_tokenStart, 0, sizeof m_tokenStart);
+       memset((void*) m_tokenEnd, 0, sizeof m_tokenEnd);
+       memset((void*) m_tokenLength, 0, sizeof m_tokenLength);
+       memset((void*) m_type, 0, sizeof m_type);
+}
+/**
+ * Constructor.
+ *
+ * @param pattern              the search pattern
+ */
+ReMatcher::ReMatcher(const char* pattern) :
+       m_prefix(1),
+       m_suffix(1),
+       m_tokens(0),
+       m_findAll(false),
+       m_ignoreCase(true),
+       m_notPattern(false)
+{
+       memset((void*) m_tokenStart, 0, sizeof m_tokenStart);
+       memset((void*) m_tokenEnd, 0, sizeof m_tokenEnd);
+       memset((void*) m_tokenLength, 0, sizeof m_tokenLength);
+       memset((void*) m_type, 0, sizeof m_type);
+       compile(pattern);
+}
+/**
+ * Destructor.
+ */
+ReMatcher::~ReMatcher(){
+}
+
+/**
+ * Compiles the pattern into a internal structure.
+ *
+ * @param pattern              pattern to compile
+ * @return                     <code>true</code>: success<br>
+ *                                     <code>false</code>: error occurred
+ */
+bool ReMatcher::compile(const char* pattern){
+       bool rc = true;
+       const char* start = strchr(pattern, '*');
+       size_t length = strlen(pattern);
+       if (start == NULL){
+               m_prefix = pattern;
+               m_suffix = pattern;
+       } else {
+               if (length == 1)
+                       m_findAll = true;
+               else{
+                       size_t ix = size_t(start - pattern);
+                       if (start != pattern){
+                               m_prefix.append(pattern, ix);
+                       }
+                       if (ix < length - 1){
+                               m_suffix.append(start + 1, length - ix);
+                       }
+               }
+       }
+       return rc;
+}
+/**
+ * Tests whether a name matches the pattern stored in the instance.
+ *
+ * @param name         the name to test
+ * @return                     <code>true</code>: ! m_notPattern: the name matches<br>
+ *                                                                                      m_notPattern: the name matches not<br>
+ *                                     <code>false</code>: otherwise
+ */
+bool ReMatcher::match(const char* name){
+       bool rc = m_findAll;
+       if (! rc){
+               size_t width = m_prefix.getLength();
+               if (width == 0)
+                       rc = true;
+               else {
+                       rc = m_ignoreCase ? strncasecmp(name, m_prefix.str(), width) == 0
+                                               : strncmp(name, m_prefix.str(), width) == 0;
+               }
+               if (rc && (width = m_suffix.getLength()) != 0){
+                       size_t length = strlen(name);
+                       rc = length >= m_suffix.getLength();
+                       if (rc){
+                               const char* tail = name + length - width;
+                               rc = m_ignoreCase ? strncasecmp(tail, m_suffix.str(), width) == 0
+                                                       : strncmp(tail, m_suffix.str(), width) == 0;
+                       }
+               }
+       }
+       if (m_notPattern)
+               rc = ! rc;
+       return rc;
+}
+
+/**
+ * Constructor.
+ */
+RePatternList::RePatternList() :
+       m_patterns(NULL),
+       m_count(0)
+{
+}
+/**
+ * Destructor.
+ */
+RePatternList::~RePatternList(){
+       destroy();
+}
+void RePatternList::destroy(){
+       if (m_patterns != NULL){
+               for (int ix = 0; ix < m_count; ix++){
+                       delete m_patterns[ix];
+                       m_patterns[ix] = NULL;
+               }
+       }
+       delete[] m_patterns;
+       m_patterns = NULL;
+}
+/**
+ * Tests whether a name matches at least one of the patterns.
+ * @param name         name to test
+ * @return                     <code>true</code>: at least one pattern matches<br>
+ *                                     <code>false</code>: no pattern matches
+ */
+bool RePatternList::match(const char* name){
+       bool rc = false;
+       for (int ix = 0; ix < m_count; ix++)
+               if (m_patterns[ix]->match(name)){
+                       rc = true;
+                       break;
+               }
+       return rc;
+}
+/**
+ * Sets the pattern list from a string.
+ *
+ * @param patterns     a string with one or more patterns
+ * @param separator    NULL: the first char of <code>patterns</code> is the the separator<br>
+ *                                             otherwise: the separator between the patterns
+ */
+void RePatternList::set(const char* patterns, const char* separator){
+       char buffer[2];
+       destroy();
+       if (separator == NULL){
+               buffer[0] = patterns[0];
+               buffer[1] = '\0';
+               separator = buffer;
+               patterns++;
+       }
+       const char* start = patterns;
+       m_count = 1;
+       size_t length = strlen(separator);
+       while( (start = strstr(start, separator)) != NULL){
+               m_count++;
+               start += length;
+       }
+       m_patterns = new ReMatcher*[m_count];
+       int ix = 0;
+       start = patterns;
+       const char* end;
+       while( (end = strstr(start, separator)) != NULL){
+               setOne(ix, start, end - start);
+               start = end + length;
+               ix++;
+       }
+       setOne(ix, start, strlen(start));
+}
+
+/**
+ * Sets one pattern in the pattern list.
+ *
+ * @param ix                           index of the pattern in the list
+ * @param pattern                      the pattern string
+ * @param patternLength        the length of <code>pattern</code>
+ */
+void RePatternList::setOne(int ix, const char* pattern, size_t patternLength){
+       ReByteBuffer buffer;
+       buffer.append(pattern, patternLength);
+       m_patterns[ix] = new ReMatcher(buffer.str());
+}
+/**
+ * Constructor.
+ */
+DirEntryFilter_t::DirEntryFilter_t() :
+       m_regulars(true),
+       m_specials(true),
+       m_directories(true),
+       m_nodePatterns(),
+       m_pathPatterns(),
+       m_minSize(0),
+       m_maxSize(-1),
+       m_minAge(0),
+       m_maxAge(0)
+{
+}
+/**
+ *
+ */
+bool DirEntryFilter_t::match(DirStatus_t& entry){
+       bool rc = false;
+       do {
+               if (! m_directories && isDirEntry(&entry))
+                       break;
+               if (m_specials && (isDirEntry(&entry) || isRegularEntry(&entry)))
+                       break;
+               if (m_regulars && ! isRegularEntry(&entry))
+                       break;
+               if (m_minSize > 0 && sizeOfEntry(&entry) > m_minSize)
+                       break;
+               if (m_maxSize >= 0 && sizeOfEntry(&entry) < m_maxSize)
+                       break;
+               if (m_minAge != 0 && modifiedOfEntry(&entry) < m_minAge)
+                       break;
+               if (m_maxAge != 0 && modifiedOfEntry(&entry) > m_maxAge)
+                       break;
+               if (m_nodePatterns != NULL && ! m_nodePatterns->match(nameOfEntry(&entry)))
+                       break;
+               if (m_pathPatterns != NULL && ! m_pathPatterns->match(entry.m_path.str()))
+                       break;
+               rc = true;
+       } while(false);
+       return rc;
+};
+
+/**
+ * Returns the status of the current file (lazy loading).
+ *
+ * @return     the status of the current file
+ */
+struct stat* DirStatus_t::getStatus() {
+       if (m_status.st_ino == 0)
+               if (stat(m_data->d_name, &m_status) != 0)
+                       memset((void*) &m_status, 0, sizeof m_status);
+       return &m_status;
+}
+
+/**
+ * Constructor.
+ *
+ * @param base         the base directory. The traversal starts at this point
+ */
+ReTraverser::ReTraverser(const char* base) :
+       m_level(-1),
+       m_base(base)
+{
+       initEntry(base, 0);
+}
+
+/**
+ * Destructor.
+ */
+ReTraverser::~ReTraverser() {
+}
+
+/**
+ * Returns the info about the next file in the directory tree traversal.
+ *
+ * @param level        OUT: the level relative to the base.<br>
+ *                                     0 means the file is inside the base.<br>
+ *                                     Not defined if the result is NULL
+ * @return NULL        no more files<br>
+ *                                     otherwise: the stack entry with the next file in the
+ *                                     directory tree. May be a directory too
+ */
+DirStatus_t* ReTraverser::rawNextFile(int& level)
+{
+       DirStatus_t* rc = NULL;
+       bool again = false;
+       do{
+               if (m_level < 0){
+                       initEntry(m_base.str(), 0);
+                       if (! isUndefHandle(m_dirs[0].m_handle))
+                               rc = &m_dirs[0];
+               } else {
+                       DirStatus_t* current = &m_dirs[level];
+                       if (findNextEntry(current->m_handle, current->m_data)){
+                               if (current->m_passNo != m_passNoForDirSearch){
+                                       rc = &m_dirs[m_level];
+                               } else {
+
+                               }
+                       } else {
+                               if (current->m_passNo == 1){
+                                       initEntry(m_base.str(), m_level);
+                                       current->m_passNo = 2;
+                                       if (! isUndefHandle(m_dirs[0].m_handle))
+                                               rc = &m_dirs[0];
+                               }
+                       }
+               }
+       } while(again);
+       return rc;
+}
+/**
+ * Returns the info about the next file matching the filter options.
+ *
+ * @param level        OUT: the level relative to the base.<br>
+ *                                     0 means the file is inside the base.<br>
+ *                                     Not defined if the result is NULL
+ * @param filter       NULL: every file matches<br>
+ *                                     otherwise: each found file must match this filter conditions
+ * @return NULL        no more files<br>
+ *                                     otherwise: the info about the next file in the
+ *                                     directory tree
+ */
+DirStatus_t* ReTraverser::nextFile(int& level, DirEntryFilter_t* filter){
+       DirStatus_t* rc = rawNextFile(level);
+       while (rc != NULL){
+               if (filter == NULL || filter->match(*rc)){
+                       break;
+               }
+       }
+       return rc;
+}
+
+/**
+ * Initializes an entry in the directory entry stack.
+ *
+ * @param path         the name of the directory belonging to the entry
+ * @param level        the index of the entry in the stack
+ */
+void ReTraverser::initEntry(const char* path, int level){
+       if (level < MAX_ENTRY_STACK_DEPTH){
+               DirStatus_t* current = &m_dirs[level];
+               initEntryBuffer(current);
+               current->m_handle = findFirstEntry(path, &m_current->m_data);
+               m_level = level;
+       }
+}
+
+/**
+ * Frees the resources of an entry of the directory entry stack.
+ *
+ * @param level        the index of the entry in the stack
+ */
+void ReTraverser::freeEntry(int level){
+       if (level < MAX_ENTRY_STACK_DEPTH){
+               DirStatus_t* current = &m_dirs[level];
+               if (! isUndefHandle(current->m_handle)){
+                       closeDir(current->m_handle);
+                       setHandleUndef(current->m_handle);
+               }
+               current->m_path.setLength(0);
+       }
+}
+
diff --git a/os/ReTraverser.hpp b/os/ReTraverser.hpp
new file mode 100644 (file)
index 0000000..75e7db0
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * RpTraverser.hpp
+ *
+ *  Created on: 23.12.2014
+ *      Author: hm
+ */
+
+#ifndef OS_RETRAVERSER_HPP_
+#define OS_RETRAVERSER_HPP_
+
+#ifdef __LINUX__
+#include <sys/types.h>
+ #include <sys/stat.h>
+
+typedef DIR* FindFileHandle_t;
+typedef __off_t FileSize_t;
+typedef struct dirent DirInfoStruct_t;
+#define nameOfEntry(entry) ((entry)->m_data->d_name)
+#define isDirEntry(entry)      (((entry)->m_data->d_type != DT_UNKNOWN && (entry)->m_data->d_type == DT_DIR) \
+                       || S_ISDIR((entry)->getStatus()->st_mode))
+#define isLinkEntry(entry)     (((entry)->m_data->d_type != DT_UNKNOWN && (entry)->m_data->d_type == DT_LINK) \
+                       || S_ISLNK(entry.getStatus()->st_mode)))
+#define isRegularEntry(entry)  (((entry)->m_data->d_type != DT_UNKNOWN && (entry)->m_data->d_type == DT_REG) \
+                       || S_ISREG((entry)->getStatus()->st_mode))
+#define sizeOfEntry(entry) ((entry)->getStatus()->st_size)
+#define modifiedOfEntry(entry) ((entry)->getStatus()->st_mtime)
+#else
+typedef int64_t FileSize_t;
+typedef HANDLE FindFileHandle_t;
+typedef WIN32_FIND_DATAA DirInfoStruct_t;
+#define nameOfEntry(entry) ((entry)->m_data->d_name)
+#define isDirEntry(data)       (data.getStatus()) & )
+#endif
+class DirStatus_t{
+public:
+       ReByteBuffer m_path;
+       DirInfoStruct_t* m_data;
+       FindFileHandle_t m_handle;
+       int m_passNo;
+#if defined __LINUX__
+       struct stat m_status;
+public:
+       struct stat* getStatus();
+#elif defined WIN32
+       DirInfoStruct_t m_buffer;
+#endif
+
+};
+#define MAX_MATCHER_TOKEN 32
+class ReMatcher {
+public:
+       enum TokenType_t {
+               TT_UNDEF,
+               TT_STRING,
+               TT_STAR,
+               TT_ONE_CHAR,
+               TT_CHAR_CLASS
+       };
+public:
+       ReMatcher();
+       ReMatcher(const char* pattern);
+       ~ReMatcher();
+public:
+       bool compile(const char* pattern);
+       bool match(const char* name);
+private:
+       ReByteBuffer m_prefix;
+       ReByteBuffer m_suffix;
+       ReByteBuffer m_pattern;
+       int m_tokenStart[MAX_MATCHER_TOKEN];
+       int m_tokenEnd[MAX_MATCHER_TOKEN];
+       int m_tokenLength[MAX_MATCHER_TOKEN];
+       TokenType_t m_type[MAX_MATCHER_TOKEN];
+       int m_tokens;
+       bool m_findAll;
+       bool m_ignoreCase;
+       bool m_notPattern;
+};
+class RePatternList{
+public:
+       RePatternList();
+       ~RePatternList();
+public:
+       void destroy();
+       bool match(const char* pattern);
+       void set(const char* patterns, const char* separator = NULL);
+private:
+       void setOne(int ix, const char* pattern, size_t patternLength);
+private:
+       ReMatcher** m_patterns;
+       int m_count;
+};
+class DirEntryFilter_t {
+public:
+       DirEntryFilter_t();
+       ~DirEntryFilter_t();
+public:
+       bool match(DirStatus_t& entry);
+public:
+       bool m_regulars;
+       bool m_specials;
+       bool m_directories;
+       RePatternList* m_nodePatterns;
+       RePatternList* m_pathPatterns;
+       FileSize_t m_minSize;
+       FileSize_t m_maxSize;
+       time_t m_minAge;
+       time_t m_maxAge;
+};
+#define MAX_ENTRY_STACK_DEPTH 256
+class ReTraverser {
+public:
+       ReTraverser(const char* base);
+       virtual ~ReTraverser();
+public:
+       DirStatus_t* rawNextFile(int& level);
+       DirStatus_t* nextFile(int& level, DirEntryFilter_t* filter = NULL);
+protected:
+       void initEntry(const char* path, int level);
+       void freeEntry(int level);
+
+protected:
+       int m_level;
+       ReByteBuffer m_base;
+       DirStatus_t m_dirs[MAX_ENTRY_STACK_DEPTH];
+       /// each directory will be passed twice: for all files + for directories only
+       /// 1: depth first 2: breadth first
+       int m_passNoForDirSearch;
+};
+
+#endif /* OS_RETRAVERSER_HPP_ */
diff --git a/os/reos.hpp b/os/reos.hpp
new file mode 100644 (file)
index 0000000..e5efc38
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * reos.hpp
+ *
+ *  Created on: 23.12.2014
+ *      Author: hm
+ */
+
+#ifndef OS_REOS_HPP_
+#define OS_REOS_HPP_
+#define __LINUX__
+#if defined __LINUX__
+#include "unistd.h"
+#include <dirent.h>
+#elif defined WIN32
+#include <tchar.h>
+#include "windows.h"
+#else
+#error "unknown os"
+#endif
+
+#include "os/ReTraverser.hpp"
+
+
+#endif /* OS_REOS_HPP_ */