--- /dev/null
+<?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=""${workspace_loc:/${ProjName}}""/>
+ </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 "${plugin_state_location}/${specs_file}"'" 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 "${plugin_state_location}/specs.cpp"'" 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 "${plugin_state_location}/specs.c"'" 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 "${plugin_state_location}/${specs_file}"'" 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 "${plugin_state_location}/specs.cpp"'" 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 "${plugin_state_location}/specs.c"'" 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 "${plugin_state_location}/${specs_file}"'" 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 "${plugin_state_location}/specs.cpp"'" 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 "${plugin_state_location}/specs.c"'" 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 "${plugin_state_location}/${specs_file}"'" 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 "${plugin_state_location}/specs.cpp"'" 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 "${plugin_state_location}/specs.c"'" 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 "${plugin_state_location}/${specs_file}"'" 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 "${plugin_state_location}/specs.cpp"'" 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 "${plugin_state_location}/specs.c"'" 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>
--- /dev/null
+*.o
+dirtool
+alltest
--- /dev/null
+<?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>
--- /dev/null
+#! /bin/bash
+rm -Rf doxygen/*
+doxygen crepublib.doxyfile
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * @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 < 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_ */
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * @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*/
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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*/
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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*/
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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*/
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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(¤t, 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*/
+
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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*/
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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*/
+
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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*/
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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*/
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 < 0: string1 < string2 0: string1 == string2 > 0: string1 > 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*/
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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*/
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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*/
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+# 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
--- /dev/null
+/*
+ * 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*/
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * remath.hpp
+ *
+ * Created on: 23.12.2014
+ * Author: hm
+ */
+
+#ifndef REMATH_HPP_
+#define REMATH_HPP_
+
+#include "ReObfuscator.hpp"
+#include "ReRandomizer.hpp"
+
+#endif /* REMATH_HPP_ */
--- /dev/null
+/*
+ * 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 > 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());
+ }
+ }
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+ }
+}
+
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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_ */