Merge branch 'master' of git://git.lumiera.org/LUMIERA
Conflicts: tests/Makefile.am
This commit is contained in:
commit
f5387d8bf3
77 changed files with 5355 additions and 1621 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -17,3 +17,5 @@ configure
|
|||
config.log
|
||||
aclocal.m4
|
||||
semantic.cache
|
||||
wiki/backups/*
|
||||
doc/devel/draw/*.png
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ include $(top_srcdir)/src/common/Makefile.am
|
|||
include $(top_srcdir)/src/lib/Makefile.am
|
||||
include $(top_srcdir)/src/backend/Makefile.am
|
||||
|
||||
# tools
|
||||
include $(top_srcdir)/src/tool/Makefile.am
|
||||
|
||||
# gui
|
||||
include $(top_srcdir)/src/gui/Makefile.am
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ def setupBasicEnvironment():
|
|||
|
||||
env.Append(CPPDEFINES = '_GNU_SOURCE')
|
||||
appendCppDefine(env,'DEBUG','DEBUG', 'NDEBUG')
|
||||
appendCppDefine(env,'OPENGL','USE_OPENGL')
|
||||
# appendCppDefine(env,'OPENGL','USE_OPENGL')
|
||||
appendVal(env,'ARCHFLAGS', 'CCFLAGS') # for both C and C++
|
||||
appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3')
|
||||
appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb')
|
||||
|
|
@ -128,7 +128,7 @@ def defineCmdlineOptions():
|
|||
allowed_values=('ALPHA', 'BETA', 'RELEASE'))
|
||||
,BoolOption('DEBUG', 'Build with debugging information and no optimizations', False)
|
||||
,BoolOption('OPTIMIZE', 'Build with strong optimization (-O3)', False)
|
||||
,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False)
|
||||
# ,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False)
|
||||
# ,EnumOption('DIST_TARGET', 'Build target architecture', 'auto',
|
||||
# allowed_values=('auto', 'i386', 'i686', 'x86_64' ), ignorecase=2)
|
||||
,PathOption('DESTDIR', 'Installation dir prefix', '/usr/local')
|
||||
|
|
@ -337,8 +337,8 @@ def definePostBuildTargets(env, artifacts):
|
|||
env.Clean ('build', [ '$SRCDIR/pre.gch' ])
|
||||
|
||||
doxydoc = artifacts['doxydoc'] = env.Doxygen('doc/devel/Doxyfile')
|
||||
env.Alias ('doxydoc', doxydoc)
|
||||
env.Clean ('doxydoc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt'])
|
||||
env.Alias ('doc', doxydoc)
|
||||
env.Clean ('doc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt'])
|
||||
|
||||
|
||||
def defineInstallTargets(env, artifacts):
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
# Doxyfile 1.5.5
|
||||
# Doxyfile 1.5.6
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = Lumiera
|
||||
PROJECT_NUMBER = 0.1+pre
|
||||
PROJECT_NUMBER = 3.0+alpha
|
||||
OUTPUT_DIRECTORY =
|
||||
CREATE_SUBDIRS = YES
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
|
@ -32,7 +32,7 @@ SHORT_NAMES = NO
|
|||
JAVADOC_AUTOBRIEF = YES
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = YES
|
||||
DETAILS_AT_TOP = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
|
|
@ -44,6 +44,7 @@ OPTIMIZE_OUTPUT_VHDL = NO
|
|||
BUILTIN_STL_SUPPORT = YES
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
|
|
@ -65,8 +66,8 @@ CASE_SENSE_NAMES = YES
|
|||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = NO
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = YES
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
|
|
@ -77,6 +78,8 @@ ENABLED_SECTIONS =
|
|||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
|
|
@ -87,7 +90,7 @@ WARN_IF_UNDOCUMENTED = NO
|
|||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE = warnings.txt
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
@ -179,18 +182,20 @@ HTML_STYLESHEET =
|
|||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Lumiera Doxygen docs"
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = YES
|
||||
TREEVIEW_WIDTH = 250
|
||||
FORMULA_FONTSIZE = 10
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
@ -268,6 +273,8 @@ CLASS_DIAGRAMS = YES
|
|||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@
|
|||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45.1"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/home/hiv/devel/skizzen"
|
||||
sodipodi:docname="Cin3.Architecture-1.svg"
|
||||
sodipodi:docbase="/mnt/Lager/heim/devel/lumi/doc/devel/draw"
|
||||
sodipodi:docname="Lumi.Architecture-1.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
inkscape:export-filename="/home/hiv/devel/skizzen/Cin3.Architecture-1.png"
|
||||
inkscape:export-filename="/home/hiv/devel/skizzen/Lumi.Architecture-1.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
|
|
@ -43,17 +43,24 @@
|
|||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="394.65714"
|
||||
inkscape:cy="258.89573"
|
||||
inkscape:zoom="1.4811321"
|
||||
inkscape:cx="384"
|
||||
inkscape:cy="265"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
width="768px"
|
||||
height="530px"
|
||||
inkscape:window-width="1010"
|
||||
inkscape:window-height="812"
|
||||
inkscape:window-width="1209"
|
||||
inkscape:window-height="949"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0" />
|
||||
inkscape:window-y="28"
|
||||
showgrid="true"
|
||||
inkscape:grid-points="true"
|
||||
inkscape:grid-bbox="false"
|
||||
gridspacingx="2px"
|
||||
gridspacingy="2px"
|
||||
objecttolerance="50"
|
||||
gridtolerance="10000" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
|
|
@ -87,7 +94,7 @@
|
|||
style="opacity:1;color:#000000;fill:#ececec;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3136"
|
||||
width="449.55356"
|
||||
height="142.91072"
|
||||
height="144.89977"
|
||||
x="46.375008"
|
||||
y="369.10715" />
|
||||
<rect
|
||||
|
|
@ -269,15 +276,19 @@
|
|||
y="252.75615" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
x="602.52142"
|
||||
y="267.42578"
|
||||
id="text3229"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
y="267.42578"
|
||||
sodipodi:role="line"
|
||||
id="tspan2336"
|
||||
x="602.52142"
|
||||
id="tspan3233"
|
||||
sodipodi:role="line">Defaults</tspan></text>
|
||||
y="267.42578">Session</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2338"
|
||||
x="602.52142"
|
||||
y="277.42578">Defaults</tspan></text>
|
||||
<rect
|
||||
y="46.375"
|
||||
x="606.66071"
|
||||
|
|
@ -286,10 +297,10 @@
|
|||
id="rect3235"
|
||||
style="opacity:1;color:#000000;fill:#ececec;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="393.71426"
|
||||
x="166.57144"
|
||||
height="75.714287"
|
||||
width="103.16072"
|
||||
y="389.97562"
|
||||
x="159.97351"
|
||||
height="79.452911"
|
||||
width="119.98783"
|
||||
id="rect3246"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<text
|
||||
|
|
@ -304,12 +315,12 @@
|
|||
x="174.14285"
|
||||
y="455.23215">Cache</tspan></text>
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3254"
|
||||
width="203.48215"
|
||||
height="32.178574"
|
||||
x="166.57141"
|
||||
y="475.10712" />
|
||||
width="119.99424"
|
||||
height="29.96665"
|
||||
x="159.96713"
|
||||
y="480.03333" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
|
|
@ -322,10 +333,10 @@
|
|||
x="174.14285"
|
||||
y="494.98215">IO-Handling</tspan></text>
|
||||
<rect
|
||||
y="454.28571"
|
||||
x="373.83926"
|
||||
height="53.000004"
|
||||
width="113.57143"
|
||||
y="455.99066"
|
||||
x="290"
|
||||
height="54.009354"
|
||||
width="200.02533"
|
||||
id="rect3263"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
|
|
@ -333,92 +344,92 @@
|
|||
id="rect3268"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="285.82141"
|
||||
x="532.60168"
|
||||
y="393.71426" />
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3270"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="313.03125"
|
||||
x="559.81152"
|
||||
y="393.71426" />
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3272"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="340.24106"
|
||||
x="587.0213"
|
||||
y="393.71426" />
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3274"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="367.4509"
|
||||
x="614.23114"
|
||||
y="393.71426" />
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3276"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="394.66074"
|
||||
x="641.44098"
|
||||
y="393.71426" />
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3278"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="285.82141"
|
||||
x="532.60168"
|
||||
y="428.25894" />
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3280"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="313.03125"
|
||||
x="559.81152"
|
||||
y="428.25894" />
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3282"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="340.24106"
|
||||
x="587.0213"
|
||||
y="428.25894" />
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3284"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="367.4509"
|
||||
x="614.23114"
|
||||
y="428.25894" />
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3286"
|
||||
width="17.035713"
|
||||
height="17.982149"
|
||||
x="394.66074"
|
||||
x="641.44098"
|
||||
y="428.25894" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
x="381.06494"
|
||||
y="472.18738"
|
||||
x="300"
|
||||
y="480"
|
||||
id="text3306"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3310"
|
||||
x="381.06494"
|
||||
y="472.18738">Storage Backend(s)</tspan></text>
|
||||
x="300"
|
||||
y="480">Storage Backend(s)</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text3312"
|
||||
y="422.02664"
|
||||
x="280.74353"
|
||||
x="527.5238"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3316"
|
||||
x="280.74353"
|
||||
x="527.5238"
|
||||
y="422.02664">Plugins (Codecs, Effects,...)</tspan></text>
|
||||
<g
|
||||
id="g3318"
|
||||
|
|
@ -538,7 +549,7 @@
|
|||
sodipodi:role="line"
|
||||
id="tspan6303"
|
||||
x="523.375"
|
||||
y="355.89285"></tspan></text>
|
||||
y="355.89285" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;color:#000000;fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:#333333;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
|
|
@ -553,11 +564,11 @@
|
|||
sodipodi:role="line"
|
||||
id="tspan6323"
|
||||
x="383.30356"
|
||||
y="214.85713"></tspan><tspan
|
||||
y="214.85713" /><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6325"
|
||||
x="383.30356"
|
||||
y="232.85713"></tspan></text>
|
||||
y="232.85713" /></text>
|
||||
<g
|
||||
id="g8843">
|
||||
<path
|
||||
|
|
@ -584,20 +595,6 @@
|
|||
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
|
||||
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(-0.6256902,0.7800716,0.7800716,0.6256902,147.19486,107.67292)"
|
||||
id="g8855">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 80.911116,238.23155 L 83.28125,354.90625 L 80.911116,238.23155 z "
|
||||
id="path8857" />
|
||||
<path
|
||||
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
|
||||
id="path8859"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
|
|
@ -779,5 +776,106 @@
|
|||
id="tspan14759"
|
||||
x="243.81104"
|
||||
y="292.75879">(re)-Building</tspan></text>
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect2288"
|
||||
width="80.071442"
|
||||
height="60.065418"
|
||||
x="409.92859"
|
||||
y="390" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text2290"
|
||||
y="410.04694"
|
||||
x="414.28015"
|
||||
style="font-size:10.00114441px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"
|
||||
transform="scale(1.0001145,0.9998856)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2294"
|
||||
x="414.28015"
|
||||
y="410.04694"
|
||||
style="stroke-width:1">Plugin Loader</tspan></text>
|
||||
<rect
|
||||
y="390"
|
||||
x="350.2843"
|
||||
height="60.065418"
|
||||
width="49.715698"
|
||||
id="rect2296"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<g
|
||||
transform="matrix(-0.6256902,0.7800716,0.7800716,0.6256902,201.26971,137.82439)"
|
||||
id="g8855">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 80.335451,191.0022 L 83.28125,354.90625 L 80.335451,191.0022 z "
|
||||
id="path8857" />
|
||||
<path
|
||||
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
|
||||
id="path8859"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
x="352.10049"
|
||||
y="410"
|
||||
id="text2298"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2302"
|
||||
x="352.10049"
|
||||
y="410">Serializer</tspan></text>
|
||||
<g
|
||||
id="g2304"
|
||||
transform="matrix(-0.6256902,0.7800716,0.7800716,0.6256902,321.26971,197.82439)" />
|
||||
<g
|
||||
id="g2310"
|
||||
transform="matrix(2.2113858e-2,0.9997554,0.9997554,-2.2113858e-2,160.03746,354.11646)">
|
||||
<path
|
||||
id="path2312"
|
||||
d="M 82.05604,278.21602 L 83.28125,354.90625 L 82.05604,278.21602 z "
|
||||
style="fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="path2314"
|
||||
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
|
||||
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
<rect
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect2324"
|
||||
width="50.0009"
|
||||
height="60.065418"
|
||||
x="290"
|
||||
y="390" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text2326"
|
||||
y="410"
|
||||
x="295.16116"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2328"
|
||||
x="295.16116"
|
||||
y="410">Defaults</tspan></text>
|
||||
<g
|
||||
transform="matrix(0.6256902,0.7800716,-0.7800716,0.6256902,438.73029,137.82439)"
|
||||
id="g2330">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 80.911116,238.23155 L 83.28125,354.90625 L 80.911116,238.23155 z "
|
||||
id="path2332" />
|
||||
<path
|
||||
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
|
||||
id="path2334"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 58 KiB |
118
doc/devel/draw/LumiLogo.svg
Normal file
118
doc/devel/draw/LumiLogo.svg
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="100"
|
||||
height="100"
|
||||
id="svg2676"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45.1"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/mnt/Lager/heim/devel/lumi/doc/devel/draw"
|
||||
sodipodi:docname="LumiLogo.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
inkscape:export-filename="/mnt/Lager/heim/devel/lumi/doc/devel/draw/LumiLogo32.png"
|
||||
inkscape:export-xdpi="57.310001"
|
||||
inkscape:export-ydpi="57.310001">
|
||||
<defs
|
||||
id="defs2678">
|
||||
<linearGradient
|
||||
id="linearGradient11428">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#eed98e;stop-opacity:1;"
|
||||
id="stop11430" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#553163;stop-opacity:1;"
|
||||
id="stop11432" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient11549"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
inkscape:collect="always"
|
||||
x1="50.468533"
|
||||
y1="46.267605"
|
||||
xlink:href="#linearGradient11428"
|
||||
gradientTransform="matrix(2.0887729,0,0,2.0886777,-60.313318,-60.306023)"
|
||||
x2="64.260468"
|
||||
y2="68.541466" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="77.291306"
|
||||
inkscape:cy="36.924563"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="svg2676"
|
||||
width="100px"
|
||||
height="100px"
|
||||
inkscape:window-width="1179"
|
||||
inkscape:window-height="918"
|
||||
inkscape:window-x="365"
|
||||
inkscape:window-y="25" />
|
||||
<metadata
|
||||
id="metadata2681">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Lumiera Logo</dc:title>
|
||||
<dc:date>8/2008</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Lumiera.org</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/2.5/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/2.5/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="LumiLogo"
|
||||
inkscape:groupmode="layer"
|
||||
id="lay_Logo"
|
||||
inkscape:export-filename="/mnt/Lager/heim/devel/lumi/doc/devel/draw/LumiLogo.png"
|
||||
inkscape:export-xdpi="114.62687"
|
||||
inkscape:export-ydpi="114.62687">
|
||||
<g
|
||||
style="opacity:1;color:#000000;fill:#951616;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient11549);stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="g_LumiLogo"
|
||||
transform="matrix(0.5,0,0,0.5,30,30)">
|
||||
<path
|
||||
id="LumieraLogo"
|
||||
sodipodi:nodetypes="ccccccccccccscsssccsccscsssccccsssc"
|
||||
d="M 0,11.48771 L 0,88.512258 C 0,94.876459 5.12376,100.00587 11.488252,99.999984 L 88.511753,99.999984 C 94.876244,99.999984 100,94.876455 100,88.512258 L 100,11.492269 C 100,5.1280689 94.876244,-1.6079329e-05 88.511753,-1.6079329e-05 L 11.488252,-1.6079329e-05 C 5.6951387,-1.6079329e-05 0,5.5258281 0,11.48771 z M 21.148826,0.26562719 C 29.955201,0.26562719 42.558748,6.0632763 42.558748,35.120436 L 42.558748,77.024531 C 42.558748,87.851217 43.097639,96.997511 50.065277,96.997511 C 52.34862,96.997511 53.64308,95.484552 54.047,94.908832 C 49.700804,94.769736 46.214101,91.194803 46.214101,86.815208 C 46.214101,82.347527 49.840211,78.721581 54.308096,78.721581 C 58.775981,78.721581 62.402092,82.347527 62.402092,86.815208 C 62.402092,88.437921 61.919927,89.921159 61.096608,91.188377 C 61.096608,91.188377 61.031334,91.318919 61.031334,91.318919 C 58.08739,95.518358 54.965657,99.738901 47.519584,99.738901 C 38.713208,99.738901 26.109662,93.941251 26.109662,64.884092 L 26.109662,22.979996 C 26.109662,12.15331 25.57077,3.0070164 18.603134,3.0070164 C 16.319793,3.0070164 15.025331,4.5199752 14.62141,5.0956943 C 18.967606,5.2347913 22.454309,8.8097247 22.454309,13.189319 C 22.454309,17.657001 18.828199,21.282945 14.360314,21.282945 C 9.892429,21.282945 6.2663188,17.657001 6.2663188,13.189319 C 6.2663188,11.566604 6.7484827,10.083368 7.5718019,8.8161505 C 7.5718019,8.8161505 7.6370761,8.6856087 7.6370761,8.6856087 C 10.58102,4.4861692 13.702754,0.26562719 21.148826,0.26562719 z M 75.456921,18.280472 C 79.924808,18.280472 83.550918,21.906416 83.550918,26.374097 C 83.550918,30.841779 79.924808,34.467725 75.456921,34.467725 C 70.989037,34.467725 67.362928,30.841779 67.362928,26.374097 C 67.362928,21.906416 70.989037,18.280472 75.456921,18.280472 z " />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
|
|
@ -26,7 +26,12 @@ liblumibackend_a_SOURCES = \
|
|||
$(liblumibackend_a_srcdir)/file.c \
|
||||
$(liblumibackend_a_srcdir)/filehandle.c \
|
||||
$(liblumibackend_a_srcdir)/filedescriptor.c \
|
||||
$(liblumibackend_a_srcdir)/filehandlecache.c
|
||||
$(liblumibackend_a_srcdir)/filehandlecache.c \
|
||||
$(liblumibackend_a_srcdir)/config.c \
|
||||
$(liblumibackend_a_srcdir)/config_typed.c \
|
||||
$(liblumibackend_a_srcdir)/configentry.c \
|
||||
$(liblumibackend_a_srcdir)/configitem.c \
|
||||
$(liblumibackend_a_srcdir)/config_lookup.c
|
||||
|
||||
|
||||
noinst_HEADERS += \
|
||||
|
|
@ -35,5 +40,9 @@ noinst_HEADERS += \
|
|||
$(liblumibackend_a_srcdir)/file.h \
|
||||
$(liblumibackend_a_srcdir)/filehandle.h \
|
||||
$(liblumibackend_a_srcdir)/filedescriptor.h \
|
||||
$(liblumibackend_a_srcdir)/filehandlecache.h
|
||||
$(liblumibackend_a_srcdir)/filehandlecache.h \
|
||||
$(liblumibackend_a_srcdir)/config.h \
|
||||
$(liblumibackend_a_srcdir)/configentry.h \
|
||||
$(liblumibackend_a_srcdir)/configitem.h \
|
||||
$(liblumibackend_a_srcdir)/config_lookup.h
|
||||
|
||||
|
|
|
|||
355
src/backend/config.c
Normal file
355
src/backend/config.c
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
config.c - Lumiera configuration system
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
//TODO: Support library includes//
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
|
||||
//TODO: Lumiera header includes//
|
||||
#include "backend/config.h"
|
||||
|
||||
//TODO: internal/static forward declarations//
|
||||
|
||||
|
||||
//TODO: System includes//
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
*/
|
||||
|
||||
NOBUG_DEFINE_FLAG_PARENT (config_all, backend);
|
||||
NOBUG_DEFINE_FLAG_PARENT (config, config_all);
|
||||
NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all);
|
||||
NOBUG_DEFINE_FLAG_PARENT (config_file, config_all);
|
||||
NOBUG_DEFINE_FLAG_PARENT (config_item, config_all);
|
||||
NOBUG_DEFINE_FLAG_PARENT (config_lookup, config_all);
|
||||
|
||||
LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile");
|
||||
LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key");
|
||||
LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_VALUE, "syntax error in value");
|
||||
LUMIERA_ERROR_DEFINE (CONFIG_NO_ENTRY, "no configuration entry");
|
||||
LUMIERA_ERROR_DEFINE (CONFIG_DEFAULT, "illegal default value");
|
||||
|
||||
/**
|
||||
* defaults for the configuraton system itself
|
||||
*/
|
||||
const char* lumiera_config_defaults[] =
|
||||
{
|
||||
/* Low level formating, don't change these */
|
||||
"config.formatstr.link = '< %s'",
|
||||
"config.formatstr.number.dec = '= %lld'",
|
||||
"config.formatstr.number.hex = '= 0x%llX'",
|
||||
"config.formatstr.number.oct = '= 0%llo'",
|
||||
"config.formatstr.real = '= %Lg'",
|
||||
"config.formatstr.real.dec = '= %Lf'",
|
||||
"config.formatstr.real.sci = '= %Le'",
|
||||
"config.formatstr.string = '=%s'",
|
||||
"config.formatstr.string.dquoted = '= \"%s\"'",
|
||||
"config.formatstr.string.quoted = '= ''%s'''",
|
||||
"config.formatstr.word = '= %s'",
|
||||
"config.formatstr.bool = '= %d'",
|
||||
|
||||
/* default representations per type */
|
||||
"config.formatdef.link < config.formatstr.link",
|
||||
"config.formatdef.number < config.formatstr.number.dec",
|
||||
"config.formatdef.real < config.formatstr.real",
|
||||
"config.formatdef.string < config.formatstr.string",
|
||||
"config.formatdef.word < config.formatstr.word",
|
||||
"config.formatdef.bool < config.formatstr.bool",
|
||||
|
||||
/* per key formatting override stored under */
|
||||
"config.formatkey ='config.format.%s'",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/* singleton config */
|
||||
LumieraConfig lumiera_global_config = NULL;
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_init (const char* path)
|
||||
{
|
||||
TRACE (config);
|
||||
REQUIRE (!lumiera_global_config, "Configuration subsystem already initialized");
|
||||
REQUIRE (path);
|
||||
|
||||
NOBUG_INIT_FLAG (config_all);
|
||||
NOBUG_INIT_FLAG (config);
|
||||
NOBUG_INIT_FLAG (config_typed);
|
||||
NOBUG_INIT_FLAG (config_file);
|
||||
NOBUG_INIT_FLAG (config_item);
|
||||
NOBUG_INIT_FLAG (config_lookup);
|
||||
|
||||
lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config));
|
||||
lumiera_config_lookup_init (&lumiera_global_config->keys);
|
||||
|
||||
lumiera_configitem_init (&lumiera_global_config->defaults);
|
||||
lumiera_configitem_init (&lumiera_global_config->files);
|
||||
lumiera_configitem_init (&lumiera_global_config->TODO_unknown);
|
||||
|
||||
lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config));
|
||||
|
||||
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "config.path = %s", path));
|
||||
|
||||
for (const char** itr = lumiera_config_defaults; *itr; ++itr)
|
||||
{
|
||||
lumiera_config_setdefault (*itr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_config_destroy ()
|
||||
{
|
||||
TRACE (config);
|
||||
if (lumiera_global_config)
|
||||
{
|
||||
lumiera_rwlock_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config));
|
||||
lumiera_configitem_destroy (&lumiera_global_config->defaults, &lumiera_global_config->keys);
|
||||
lumiera_configitem_destroy (&lumiera_global_config->files, &lumiera_global_config->keys);
|
||||
lumiera_configitem_destroy (&lumiera_global_config->TODO_unknown, &lumiera_global_config->keys);
|
||||
lumiera_config_lookup_destroy (&lumiera_global_config->keys);
|
||||
lumiera_free (lumiera_global_config);
|
||||
lumiera_global_config = NULL;
|
||||
}
|
||||
else
|
||||
WARN (config, "Tried to destroy non initialized config subsystem");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_load (const char* file)
|
||||
{
|
||||
TRACE (config);
|
||||
UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_save ()
|
||||
{
|
||||
TRACE (config);
|
||||
UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_purge (const char* filename)
|
||||
{
|
||||
TRACE (config);
|
||||
|
||||
UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_get (const char* key, const char** value)
|
||||
{
|
||||
TRACE (config);
|
||||
REQUIRE (key);
|
||||
REQUIRE (value);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
/* we translate the key for the env var override by making it uppercase and replace . with _,
|
||||
as side effect, this also checks the key syntax */
|
||||
char* tr_key = lumiera_tmpbuf_tr (key,
|
||||
LUMIERA_CONFIG_KEY_CHARS,
|
||||
LUMIERA_CONFIG_ENV_CHARS,
|
||||
NULL);
|
||||
|
||||
if (tr_key)
|
||||
{
|
||||
char* env = lumiera_tmpbuf_snprintf (2048, "LUMIERA_%s", tr_key);
|
||||
|
||||
*value = getenv(env);
|
||||
if (*value)
|
||||
{
|
||||
ret = 0;
|
||||
NOTICE (config, "envvar override for config %s = %s", env, *value);
|
||||
}
|
||||
else
|
||||
{
|
||||
TODO ("follow '<' delegates?");
|
||||
LumieraConfigitem item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key);
|
||||
|
||||
if (item)
|
||||
{
|
||||
*value = item->delim+1;
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_KEY);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_get_default (const char* key, const char** value)
|
||||
{
|
||||
TRACE (config);
|
||||
REQUIRE (key);
|
||||
REQUIRE (value);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
TODO ("follow '<' delegates?");
|
||||
TODO ("refactor _get and get_default to iterator access (return LList or Lookupentry)");
|
||||
LumieraConfigitem item = lumiera_config_lookup_item_tail_find (&lumiera_global_config->keys, key);
|
||||
|
||||
if (item && item->parent == &lumiera_global_config->defaults)
|
||||
{
|
||||
*value = item->delim+1;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_set (const char* key, const char* delim_value)
|
||||
{
|
||||
TRACE (config);
|
||||
|
||||
TODO ("if does this item already exist in a user writeable file?");
|
||||
TODO (" replace delim_value");
|
||||
|
||||
TODO ("else");
|
||||
TODO (" find matching prefix");
|
||||
TODO (" find matching suffix");
|
||||
TODO (" find proper prefix indentation, else use config.indent");
|
||||
TODO (" create configitem with prefix/suffix removed");
|
||||
|
||||
|
||||
|
||||
// * set a value by key
|
||||
// * handles internally everything as string:string key:value pair.
|
||||
// * lowlevel function
|
||||
// * tag file as dirty
|
||||
// * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called.
|
||||
|
||||
|
||||
|
||||
UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_config_setdefault (const char* line)
|
||||
{
|
||||
TRACE (config);
|
||||
REQUIRE (line);
|
||||
|
||||
LumieraConfigitem item = NULL;
|
||||
|
||||
LUMIERA_WRLOCK_SECTION (config, &lumiera_global_config->lock)
|
||||
{
|
||||
const char* key = line;
|
||||
while (*key && isspace (*key))
|
||||
key++;
|
||||
|
||||
key = lumiera_tmpbuf_strndup (line, strspn (line, LUMIERA_CONFIG_KEY_CHARS));
|
||||
|
||||
if (!(item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key)) || item->parent != &lumiera_global_config->defaults)
|
||||
{
|
||||
item = lumiera_configitem_new (line);
|
||||
|
||||
if (item)
|
||||
{
|
||||
ENSURE (item->delim, "default must be a configentry with key=value or key<delegate syntax")
|
||||
ENSURE (*item->delim == '=' || *item->delim == '<', "default must be a configentry with key=value or key<delegate syntax");
|
||||
TRACE (config, "registering default: '%s'", item->line);
|
||||
|
||||
llist_insert_head (&lumiera_global_config->defaults.childs, &item->link);
|
||||
item->parent = &lumiera_global_config->defaults;
|
||||
|
||||
lumiera_config_lookup_insert_default (&lumiera_global_config->keys, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_config_dump (FILE* out)
|
||||
{
|
||||
fprintf (out, "# registered defaults:\n");
|
||||
|
||||
LLIST_FOREACH (&lumiera_global_config->defaults.childs, node)
|
||||
fprintf (out, "%s\n", ((LumieraConfigitem) node)->line);
|
||||
|
||||
fprintf (out, "# end of defaults\n\n");
|
||||
|
||||
#if 0 /*TODO UNIMPLEMENTED */
|
||||
fprintf (out, "# files:\n");
|
||||
lumiera_configitem files;
|
||||
fprintf (out, "# volatiles:")
|
||||
lumiera_configitem TODO_unknown;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_reset (const char* key)
|
||||
{
|
||||
TRACE (config);
|
||||
UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_info (const char* key, const char** filename, unsigned* line)
|
||||
{
|
||||
TRACE (config);
|
||||
UNIMPLEMENTED();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
262
src/backend/config.h
Normal file
262
src/backend/config.h
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
config.h - Lumiera configuration system
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef LUMIERA_CONFIG_H
|
||||
#define LUMIERA_CONFIG_H
|
||||
|
||||
//TODO: Support library includes//
|
||||
#include "lib/error.h"
|
||||
#include "lib/rwlock.h"
|
||||
|
||||
//TODO: Forward declarations//
|
||||
struct lumiera_config_struct;
|
||||
|
||||
|
||||
/* master config subsystem debug flag */
|
||||
NOBUG_DECLARE_FLAG (config_all);
|
||||
/* config subsystem internals */
|
||||
NOBUG_DECLARE_FLAG (config);
|
||||
/* high level typed interface operations */
|
||||
NOBUG_DECLARE_FLAG (config_typed);
|
||||
/* file operations */
|
||||
NOBUG_DECLARE_FLAG (config_file);
|
||||
/* single config items */
|
||||
NOBUG_DECLARE_FLAG (config_item);
|
||||
/* lookup config keys */
|
||||
NOBUG_DECLARE_FLAG (config_lookup);
|
||||
|
||||
|
||||
LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX);
|
||||
LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_KEY);
|
||||
LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_VALUE);
|
||||
LUMIERA_ERROR_DECLARE (CONFIG_NO_ENTRY);
|
||||
LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT);
|
||||
|
||||
//TODO: Lumiera header includes//
|
||||
#include "backend/config_lookup.h"
|
||||
|
||||
//TODO: System includes//
|
||||
#include <nobug.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader
|
||||
*/
|
||||
|
||||
#define LUMIERA_CONFIG_KEY_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_."
|
||||
#define LUMIERA_CONFIG_ENV_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789__"
|
||||
|
||||
struct lumiera_config_struct
|
||||
{
|
||||
lumiera_config_lookup keys;
|
||||
|
||||
lumiera_configitem defaults; /* registered default values */
|
||||
lumiera_configitem files; /* all loaded files */
|
||||
lumiera_configitem TODO_unknown; /* all values which are not part of a file and not default TODO: this will be removed when file support is finished */
|
||||
|
||||
/*
|
||||
all access is protected with rwlock's.
|
||||
We use rwlocks here since concurrent reads are likely common.
|
||||
|
||||
So far this is a global config lock, if this is a problem we might granularize it by locking on a file level.
|
||||
config access is not planned to be transactional yet, if this is a problem we need to expose the rwlock to a config_acquire/config_release function pair
|
||||
*/
|
||||
lumiera_rwlock lock;
|
||||
};
|
||||
|
||||
typedef struct lumiera_config_struct lumiera_config;
|
||||
typedef lumiera_config* LumieraConfig;
|
||||
|
||||
/**
|
||||
* Supported high level types: TODO documenting
|
||||
*/
|
||||
/* TODO: add here as 'LUMIERA_CONFIG_TYPE(name, ctype)' the _get/_set prototypes are declared automatically below, you still have to implement them in config.c */
|
||||
#define LUMIERA_CONFIG_TYPES \
|
||||
LUMIERA_CONFIG_TYPE(link, char*) \
|
||||
LUMIERA_CONFIG_TYPE(number, signed long long) \
|
||||
LUMIERA_CONFIG_TYPE(real, long double) \
|
||||
LUMIERA_CONFIG_TYPE(string, char*) \
|
||||
LUMIERA_CONFIG_TYPE(word, char*) \
|
||||
LUMIERA_CONFIG_TYPE(bool, int)
|
||||
|
||||
|
||||
// * does only initialize the variables, so that they get valid values, but does not allocate them as they will be allocated before as they are singleton.
|
||||
// * lumiera_config_init (const char* searchpath) searchpath is a buildin-default, can be changed via configure and can be appended and overridden by using a flag, e.g. {{{ --config-path-append="" }}} or {{{ --config-path="" }}}
|
||||
|
||||
/**
|
||||
* Initialize the configuration subsystem.
|
||||
* @param path search path for config files.
|
||||
* Must be called only once
|
||||
*/
|
||||
int
|
||||
lumiera_config_init (const char* path);
|
||||
|
||||
|
||||
// * frees all space allocated by the ConfigLoader.
|
||||
|
||||
/**
|
||||
* Destroys the configuration subsystem.
|
||||
* Subsequent calls are no-ops.
|
||||
*/
|
||||
void
|
||||
lumiera_config_destroy ();
|
||||
|
||||
|
||||
// * reads '''one''' single configuration file that will include all settings from other files.
|
||||
// * does not read itself but give delegates reading. The actual reading and parsing will be done in configfile object. s.later.
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
lumiera_config_load (const char* file);
|
||||
|
||||
|
||||
//{{{ lumiera_config_save () { LLIST_FOREACH(config_singleton.files, f) { LumieraFile file = (LumieraFile) f; if(lumiera_configfile_isdirty (file)) lumiera_configfile_save(file); } } }}}
|
||||
// * saves all the changed settings to user's configuration files, but recognizes where settings came from and will write them to an appropriate named file. Example: '''changed''' values from ''/usr/local/share/lumiera/plugins/blur.conf'' will be saved into ''~/.lumiera/plugins/blur.conf''
|
||||
// * finds out which files are dirty and which settings have to be written to user's config files.
|
||||
// * does initiate the actual saving procedure by delegating the save to the actual configfile objects, see below.
|
||||
// * empty user configuration files in RAM will be deleted from disk on write.
|
||||
// * checks whether the file has changed since last read, and will print out an error if necessary instead of overriding it without notification.
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
lumiera_config_save ();
|
||||
|
||||
|
||||
// * `lumiera_config_purge(const char* filename)` removes all configs loaded from filename
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
lumiera_config_purge (const char* filename);
|
||||
|
||||
|
||||
/**
|
||||
* Does a diagnostic dump of the whole config database
|
||||
*/
|
||||
void
|
||||
lumiera_config_dump (FILE* out);
|
||||
|
||||
|
||||
// * {{{ lumiera_config_get(...) }}}
|
||||
// * get a value by key
|
||||
// * handles internally everything as string:string key:value pair.
|
||||
// * lowlevel function
|
||||
// * lumiera_config_integer_get (const char* key, int *value) will return integers instead of strings and return 0 if succeeded and -1 if it failed.
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
lumiera_config_get (const char* key, const char** value);
|
||||
|
||||
|
||||
int
|
||||
lumiera_config_get_default (const char* key, const char** value);
|
||||
|
||||
|
||||
// * {{{ lumiera_config_set(...) }}}
|
||||
// * set a value by key
|
||||
// * handles internally everything as string:string key:value pair.
|
||||
// * lowlevel function
|
||||
// * tag file as dirty
|
||||
// * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called.
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param key
|
||||
* @param delim_value delimiter (= or <) followed by the value to be set
|
||||
*
|
||||
*/
|
||||
int
|
||||
lumiera_config_set (const char* key, const char* delim_value);
|
||||
|
||||
|
||||
/**
|
||||
* Installs a default value for a config key.
|
||||
* Any key might have an associated default value which is used when
|
||||
* no other configuration is available, this can be set once.
|
||||
* Any subsequent call will be a no-op.
|
||||
* @param line line with key, delimiter and value to store as default value
|
||||
* @return NULL in case of an error, else a pointer to the default configitem
|
||||
*/
|
||||
LumieraConfigitem
|
||||
lumiera_config_setdefault (const char* line);
|
||||
|
||||
|
||||
|
||||
// * {{{int lumiera_config_TYPE_get(const char* key, TYPE* value, const char* default) }}}
|
||||
// High level config interface for different types.
|
||||
// if default is given (!NULL) then value is set to default in case key was not found or any other error occured.
|
||||
// error code is still set and -1 (fail) is returned in case of an error, but it might be cleared with no ill effects.
|
||||
// NOTE: errors are persistent in our error handler, they must still be cleared, even when ignored.
|
||||
// if default is given then 'KEY_NOT_FOUND' is not a error here, if default is NULL then it is
|
||||
// NOTE2: default values are given as strings, the config loader remembers a given default value and checks if it got changed
|
||||
// when it is _set(). Thus a default value can be supressed when set/written
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define LUMIERA_CONFIG_TYPE(name, type) \
|
||||
int \
|
||||
lumiera_config_##name##_get (const char* key, type* value);
|
||||
LUMIERA_CONFIG_TYPES
|
||||
#undef LUMIERA_CONFIG_TYPE
|
||||
|
||||
|
||||
|
||||
// * {{{ lumiera_config_TYPE_set (const char* key, TYPE*value, const char* fmt) }}}
|
||||
// Highlevel interface for different types, fmt is a printf format specifier for the desired format, when NULL, defaults apply.
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define LUMIERA_CONFIG_TYPE(name, type) \
|
||||
int \
|
||||
lumiera_config_##name##_set (const char* key, type* value);
|
||||
LUMIERA_CONFIG_TYPES
|
||||
#undef LUMIERA_CONFIG_TYPE
|
||||
|
||||
|
||||
// * {{{ lumiera_config_reset(...) }}}
|
||||
// * reset a value by key to the system default values, thus removes a user's configuration line.
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
lumiera_config_reset (const char* key);
|
||||
|
||||
|
||||
// * Find exact place of a setting.
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
lumiera_config_info (const char* key, const char** filename, unsigned* line);
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
239
src/backend/config_lookup.c
Normal file
239
src/backend/config_lookup.c
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
config_lookup.c - Lookup functions for the config subsystem
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
#include "backend/config_lookup.h"
|
||||
#include "backend/config.h"
|
||||
|
||||
/* we only use one fatal error for now, when allocation in the config system fail, something else is pretty wrong */
|
||||
LUMIERA_ERROR_DEFINE (CONFIG_LOOKUP, "config lookup failure");
|
||||
|
||||
/*
|
||||
support functions for the splay tree
|
||||
*/
|
||||
static int
|
||||
cmp_fn (const void* a, const void* b);
|
||||
|
||||
static void
|
||||
delete_fn (PSplaynode node);
|
||||
|
||||
static const void*
|
||||
key_fn (const PSplaynode node);
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implementation of the lookup of configuration keys
|
||||
*/
|
||||
|
||||
|
||||
LumieraConfigLookup
|
||||
lumiera_config_lookup_init (LumieraConfigLookup self)
|
||||
{
|
||||
TRACE (config_lookup);
|
||||
psplay_init (&self->tree, cmp_fn, key_fn, delete_fn);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigLookup
|
||||
lumiera_config_lookup_destroy (LumieraConfigLookup self)
|
||||
{
|
||||
TRACE (config_lookup);
|
||||
if (self)
|
||||
psplay_destroy (&self->tree);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item)
|
||||
{
|
||||
TRACE (config_lookup);
|
||||
REQUIRE (self);
|
||||
REQUIRE (item);
|
||||
REQUIRE (item->key);
|
||||
REQUIRE (item->key_size);
|
||||
|
||||
FIXME ("implement section prefix/suffix for the key");
|
||||
const char* key = lumiera_tmpbuf_strcat3 (NULL, 0, item->key, item->key_size, NULL, 0);
|
||||
|
||||
LumieraConfigLookupentry entry = (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100);
|
||||
if (!entry)
|
||||
entry = (LumieraConfigLookupentry)psplay_insert (&self->tree, &lumiera_config_lookupentry_new (key)->node, 100);
|
||||
|
||||
llist_insert_head (&entry->configitems, &item->lookup);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item)
|
||||
{
|
||||
TRACE (config_lookup);
|
||||
REQUIRE (self);
|
||||
REQUIRE (item);
|
||||
REQUIRE (item->key);
|
||||
REQUIRE (item->key_size);
|
||||
|
||||
const char* key = lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s", item->key_size, item->key);
|
||||
LumieraConfigLookupentry entry = (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100);
|
||||
if (!entry)
|
||||
entry = (LumieraConfigLookupentry)psplay_insert (&self->tree, &lumiera_config_lookupentry_new (key)->node, 100);
|
||||
TODO ("else check that no 'default' item already exists, that is, the tail element's parent points to the 'defaults' in config");
|
||||
|
||||
llist_insert_tail (&entry->configitems, &item->lookup);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item)
|
||||
{
|
||||
TRACE (config_lookup);
|
||||
REQUIRE (!llist_is_empty (&item->lookup), "item is not in a lookup");
|
||||
|
||||
if (llist_is_single (&item->lookup))
|
||||
{
|
||||
/* last item in lookup, remove it from the splay tree */
|
||||
LumieraConfigLookupentry entry = LLIST_TO_STRUCTP (llist_next (&item->lookup), lumiera_config_lookupentry, configitems);
|
||||
llist_unlink (&item->lookup);
|
||||
psplay_delete_node (&self->tree, (PSplaynode)entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* more than this item present in hash, just unlink this item */
|
||||
llist_unlink (&item->lookup);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookup_find (LumieraConfigLookup self, const char* key)
|
||||
{
|
||||
TRACE (config_lookup);
|
||||
return (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100);
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key)
|
||||
{
|
||||
TRACE (config_lookup);
|
||||
|
||||
LumieraConfigLookupentry entry =
|
||||
lumiera_config_lookup_find (self, key);
|
||||
|
||||
if (entry && !llist_is_empty (&entry->configitems))
|
||||
return LLIST_TO_STRUCTP (llist_head (&entry->configitems), lumiera_configitem, lookup);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key)
|
||||
{
|
||||
TRACE (config_lookup);
|
||||
|
||||
LumieraConfigLookupentry entry =
|
||||
lumiera_config_lookup_find (self, key);
|
||||
|
||||
if (entry && !llist_is_empty (&entry->configitems))
|
||||
return LLIST_TO_STRUCTP (llist_tail (&entry->configitems), lumiera_configitem, lookup);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Lookup entries
|
||||
*/
|
||||
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key)
|
||||
{
|
||||
TRACE (config_lookup, "key = %s", key);
|
||||
if (self)
|
||||
{
|
||||
psplaynode_init (&self->node);
|
||||
llist_init (&self->configitems);
|
||||
self->full_key = lumiera_strndup (key, SIZE_MAX);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookupentry_new (const char* key)
|
||||
{
|
||||
return lumiera_config_lookupentry_init (lumiera_malloc (sizeof (lumiera_config_lookupentry)), key);
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self)
|
||||
{
|
||||
TRACE (config_lookup);
|
||||
if (self)
|
||||
{
|
||||
REQUIRE (llist_is_empty (&self->configitems), "lookup node still in use");
|
||||
lumiera_free (self->full_key);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_config_lookupentry_delete (LumieraConfigLookupentry self)
|
||||
{
|
||||
lumiera_free (lumiera_config_lookupentry_destroy (self));
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_fn (const void* a, const void* b)
|
||||
{
|
||||
return strcmp ((const char*)a, (const char*)b);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_fn (PSplaynode node)
|
||||
{
|
||||
lumiera_config_lookupentry_delete ((LumieraConfigLookupentry) node);
|
||||
}
|
||||
|
||||
|
||||
static const void*
|
||||
key_fn (const PSplaynode node)
|
||||
{
|
||||
return ((LumieraConfigLookupentry) node)->full_key;
|
||||
}
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
192
src/backend/config_lookup.h
Normal file
192
src/backend/config_lookup.h
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
config_lookup.h - Lookup functions for the config subsystem
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef LUMIERA_CONFIG_LOOKUP_H
|
||||
#define LUMIERA_CONFIG_LOOKUP_H
|
||||
|
||||
#include "lib/psplay.h"
|
||||
#include "lib/llist.h"
|
||||
#include "lib/error.h"
|
||||
|
||||
typedef struct lumiera_config_lookup_struct lumiera_config_lookup;
|
||||
typedef lumiera_config_lookup* LumieraConfigLookup;
|
||||
|
||||
typedef struct lumiera_config_lookupentry_struct lumiera_config_lookupentry;
|
||||
typedef lumiera_config_lookupentry* LumieraConfigLookupentry;
|
||||
|
||||
|
||||
#include "backend/configitem.h"
|
||||
|
||||
|
||||
#include <nobug.h>
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Lookup of configuration keys. Configuration keys are dynamically stored in a splay tree.
|
||||
* This happens for defaults, loaded config files and entries which are set explicitly.
|
||||
* The system maintains no central registry of all possible keys.
|
||||
* We store here the full keys of configentries as well as the keys of section prefixes.
|
||||
* Section prefixes are stored with a trailing dot to disambiguate them from entry keys.
|
||||
*/
|
||||
|
||||
|
||||
LUMIERA_ERROR_DECLARE (CONFIG_LOOKUP);
|
||||
|
||||
/**
|
||||
* Just contains a hashtable to give sufficent abstraction.
|
||||
*/
|
||||
struct lumiera_config_lookup_struct
|
||||
{
|
||||
psplay tree;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize a lookup structure.
|
||||
* @param self lookup structure to be initialized
|
||||
* @return self on success else NULL
|
||||
*/
|
||||
LumieraConfigLookup
|
||||
lumiera_config_lookup_init (LumieraConfigLookup self);
|
||||
|
||||
/**
|
||||
* Destruct a lookup structure.
|
||||
* @param self lookup structure to be destructed
|
||||
* @return self
|
||||
*/
|
||||
LumieraConfigLookup
|
||||
lumiera_config_lookup_destroy (LumieraConfigLookup self);
|
||||
|
||||
/**
|
||||
* Add a config item to a lookup structure.
|
||||
* Config items are stored under their key and stacked in insertion order.
|
||||
* @param self lookup structure where the item shall be added
|
||||
* @param item config item to add to the lookup structure
|
||||
* @return opaque pointer to a hashtable entry
|
||||
*/
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item);
|
||||
|
||||
|
||||
/**
|
||||
* Add a default config item to a lookup structure.
|
||||
* @internal
|
||||
* This function is used internal.
|
||||
* The item must contain a full key and not part of any 'section'
|
||||
* and is inserted as tail of the lookup list.
|
||||
* @param self lookup structure where the item shall be added
|
||||
* @param item config item to add to the lookup structure
|
||||
* @return opaque pointer to a hashtable entry
|
||||
*/
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item);
|
||||
|
||||
|
||||
/**
|
||||
* Remove a config item from a lookup structure.
|
||||
* Config must be removed from the lookup when they are not used anymore.
|
||||
* Removing a config item unlinks it from the stack of all config items with the same key.
|
||||
* When this was the last config item under that key, the lookup entry is cleaned up.
|
||||
* @param self lookup structure where the item shall be removed
|
||||
* @param item config item to be removed from the lookup
|
||||
* @return item
|
||||
*/
|
||||
LumieraConfigitem
|
||||
lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item);
|
||||
|
||||
/**
|
||||
* Find a hashtable entry in the lookup structure.
|
||||
* Internal function, can be used to check if at least one item is available for a given key.
|
||||
* @param self lookup structure where the key shall be searched
|
||||
* @param key string to be looked up
|
||||
* @return NULL if nothing is found, otherwise a opaque pointer to a hash table entry
|
||||
*/
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookup_find (LumieraConfigLookup self, const char* key);
|
||||
|
||||
/**
|
||||
* Find a the topmost config item stored to a given key.
|
||||
* @param self lookup structure where the key shall be searched
|
||||
* @param key string to be looked up
|
||||
* @return the config item which was last stored under the given key or NULL when nothing was found
|
||||
*/
|
||||
LumieraConfigitem
|
||||
lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key);
|
||||
|
||||
/**
|
||||
* Find a the bottommost config item stored to a given key.
|
||||
* defaults sits at the bottom if exists
|
||||
* @param self lookup structure where the key shall be searched
|
||||
* @param key string to be looked up
|
||||
* @return TODO
|
||||
*/
|
||||
LumieraConfigitem
|
||||
lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Lookup hash entries for the cuckoo hash
|
||||
*/
|
||||
|
||||
/**
|
||||
* Structure defining single hash table entries.
|
||||
* @internal
|
||||
*/
|
||||
struct lumiera_config_lookupentry_struct
|
||||
{
|
||||
psplaynode node;
|
||||
/* stack of all configitems stored under this key */
|
||||
llist configitems;
|
||||
|
||||
/*
|
||||
we store a copy of the full key here
|
||||
configentry keys are complete as expected
|
||||
section keys are the prefix stored with a trailing dot,
|
||||
suffixes will be found by iterative search
|
||||
*/
|
||||
char* full_key;
|
||||
};
|
||||
|
||||
|
||||
/* internal */
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key);
|
||||
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookupentry_new (const char* key);
|
||||
|
||||
/* internal */
|
||||
LumieraConfigLookupentry
|
||||
lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self);
|
||||
|
||||
|
||||
void
|
||||
lumiera_config_lookupentry_delete (LumieraConfigLookupentry self);
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
313
src/backend/config_typed.c
Normal file
313
src/backend/config_typed.c
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
config_typed.c - Lumiera configuration highlevel interface
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
//TODO: Support library includes//
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
|
||||
//TODO: Lumiera header includes//
|
||||
#include "backend/config.h"
|
||||
|
||||
//TODO: internal/static forward declarations//
|
||||
extern LumieraConfig lumiera_global_config;
|
||||
|
||||
|
||||
//TODO: System includes//
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Here are the high level typed configuration interfaces defined.
|
||||
*/
|
||||
|
||||
int
|
||||
lumiera_config_link_get (const char* key, char** value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_config_link_set (const char* key, char** value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Number
|
||||
* signed integer numbers, in different formats (decimal, hex, oct, binary(for masks))
|
||||
*/
|
||||
int
|
||||
lumiera_config_number_get (const char* key, long long* value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
const char* raw_value = NULL;
|
||||
|
||||
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
|
||||
{
|
||||
if (!lumiera_config_get (key, &raw_value))
|
||||
{
|
||||
if (raw_value)
|
||||
{
|
||||
/* got it, scan it */
|
||||
if (sscanf (raw_value, "%Li", value) == 1)
|
||||
ret = 0; /* all ok */
|
||||
else
|
||||
{
|
||||
LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_config_number_set (const char* key, long long* value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Real
|
||||
* floating point number in standard formats (see printf/scanf)
|
||||
*/
|
||||
int
|
||||
lumiera_config_real_get (const char* key, long double* value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_config_real_set (const char* key, long double* value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* String
|
||||
* unquoted string which covers the whole value area and gets chopped or
|
||||
* quoted string which preserves leading/trailing spaces
|
||||
* either single or double quotes are allowed, doubling the quote in a string escapes it
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* helper function, takes a raw input string and give a tmpbuf with the string parsed back.
|
||||
*/
|
||||
static char*
|
||||
scan_string (const char* in)
|
||||
{
|
||||
/* chop leading blanks */
|
||||
in += strspn(in, " \t");
|
||||
|
||||
char quote = *in;
|
||||
char* end;
|
||||
char* ret = NULL;
|
||||
|
||||
if (quote == '"' || quote == '\'')
|
||||
{
|
||||
/* quoted string */
|
||||
++in;
|
||||
end = strchr (in, quote);
|
||||
while (end && end[1] == quote)
|
||||
end = strchr (end + 2, quote);
|
||||
|
||||
if (end)
|
||||
{
|
||||
ret = lumiera_tmpbuf_strndup (in, end - in);
|
||||
|
||||
/* replace double quote chars with single one */
|
||||
char* wpos;
|
||||
char* rpos;
|
||||
for (wpos = rpos = ret; *rpos; ++rpos, ++wpos)
|
||||
{
|
||||
if (*rpos == quote)
|
||||
++rpos;
|
||||
*wpos = *rpos;
|
||||
}
|
||||
*wpos = '\0';
|
||||
}
|
||||
else
|
||||
/* quotes doesnt match */
|
||||
LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unquoted string */
|
||||
ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
|
||||
|
||||
/* chop trailing blanks */
|
||||
end = ret + strlen (ret) - 1;
|
||||
while (end > ret && (*end == ' ' || *end == '\t'))
|
||||
*end-- = '\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_config_string_get (const char* key, char** value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
const char* raw_value = NULL;
|
||||
|
||||
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
|
||||
{
|
||||
if (!lumiera_config_get (key, &raw_value))
|
||||
{
|
||||
if (raw_value)
|
||||
{
|
||||
*value = scan_string (raw_value);
|
||||
if (*value)
|
||||
ret = 0; /* all ok */
|
||||
/* else error was raised by scan_string */
|
||||
}
|
||||
else
|
||||
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_config_string_set (const char* key, char** value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Word
|
||||
* A single word, no quotes, chopped
|
||||
*/
|
||||
|
||||
/**
|
||||
* helper function, takes a raw input string and give a tmpbuf with the word parsed back.
|
||||
*/
|
||||
static char*
|
||||
scan_word (const char* in)
|
||||
{
|
||||
/* chop leading blanks */
|
||||
in += strspn(in, " \t");
|
||||
|
||||
char* ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
|
||||
char* end = ret;
|
||||
|
||||
/* chop trailing blanks */
|
||||
while (*end != ' ' && *end != '\t')
|
||||
++end;
|
||||
|
||||
*end++ = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_config_word_get (const char* key, char** value)
|
||||
{
|
||||
TRACE (config_typed, "KEY %s", key);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
const char* raw_value = NULL;
|
||||
|
||||
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
|
||||
{
|
||||
if (!lumiera_config_get (key, &raw_value))
|
||||
{
|
||||
if (raw_value)
|
||||
{
|
||||
*value = scan_word (raw_value);
|
||||
if (*value)
|
||||
ret = 0; /* all ok */
|
||||
}
|
||||
else
|
||||
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_config_word_set (const char* key, char** value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bool
|
||||
* Bool in various formats, (0,1(!1), yes/no, true/false, on/off, set/clear)
|
||||
*/
|
||||
int
|
||||
lumiera_config_bool_get (const char* key, int* value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_config_bool_set (const char* key, int* value)
|
||||
{
|
||||
TRACE (config_typed);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
74
src/backend/configentry.c
Normal file
74
src/backend/configentry.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
configentry.c - single entries from configfiles
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
//TODO: Support library includes//
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
//TODO: Lumiera header includes//
|
||||
#include "backend/configentry.h"
|
||||
|
||||
//TODO: internal/static forward declarations//
|
||||
|
||||
|
||||
//TODO: System includes//
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
*/
|
||||
|
||||
//code goes here//
|
||||
LumieraConfigitem
|
||||
lumiera_configentry_new (LumieraConfigitem tmp)
|
||||
{
|
||||
LumieraConfigentry self = lumiera_malloc (sizeof (*self));
|
||||
lumiera_configitem_move ((LumieraConfigitem)self, tmp);
|
||||
|
||||
TODO ("initialize other stuff here (lookup, parent, ...)");
|
||||
|
||||
return (LumieraConfigitem)self;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configentry_destroy (LumieraConfigitem self)
|
||||
{
|
||||
TODO ("cleanup other stuff here (lookup, parent, ...)");
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
struct lumiera_configitem_vtable lumiera_configentry_funcs =
|
||||
{
|
||||
.new = lumiera_configentry_new,
|
||||
.destroy = lumiera_configentry_destroy
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
locking.h - shared declarations for all locking primitives
|
||||
configentry.h - single entries from configfiles
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
|
@ -19,36 +19,49 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef LUMIERA_LOCKING_H
|
||||
#define LUMIERA_LOCKING_H
|
||||
#ifndef LUMIERA_CONFIGENTRY_H
|
||||
#define LUMIERA_CONFIGENTRY_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
//TODO: Support library includes//
|
||||
|
||||
|
||||
//TODO: Forward declarations//
|
||||
typedef struct lumiera_configentry_struct lumiera_configentry;
|
||||
typedef lumiera_configentry* LumieraConfigentry;
|
||||
|
||||
|
||||
//TODO: Lumiera header includes//
|
||||
#include "backend/configitem.h"
|
||||
|
||||
//TODO: System includes//
|
||||
#include <nobug.h>
|
||||
|
||||
#include "lib/error.h"
|
||||
|
||||
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_LOCK);
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK);
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Shared declarations for all locking primitives.
|
||||
*/
|
||||
|
||||
/**
|
||||
* used to store the current lock state.
|
||||
*
|
||||
*
|
||||
*/
|
||||
enum lumiera_lockstate
|
||||
{
|
||||
LUMIERA_UNLOCKED,
|
||||
LUMIERA_LOCKED,
|
||||
LUMIERA_RDLOCKED,
|
||||
LUMIERA_WRLOCKED
|
||||
};
|
||||
//TODO: declarations go here//
|
||||
struct lumiera_configentry_struct
|
||||
{
|
||||
lumiera_configitem entry;
|
||||
};
|
||||
|
||||
extern struct lumiera_configitem_vtable lumiera_configentry_funcs;
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configentry_new (LumieraConfigitem tmp);
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configentry_destroy (LumieraConfigitem self);
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
392
src/backend/configitem.c
Normal file
392
src/backend/configitem.c
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
configitem.c - generalized hierachy of configuration items
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
Simeon Voelkel <simeon_voelkel@arcor.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
//TODO: Support library includes//
|
||||
#include "lib/llist.h"
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
|
||||
//TODO: Lumiera header includes//
|
||||
#include "backend/config.h"
|
||||
#include "backend/configitem.h"
|
||||
#include "backend/configentry.h"
|
||||
|
||||
//TODO: internal/static forward declarations//
|
||||
|
||||
|
||||
//TODO: System includes//
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
//code goes here//
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_init (LumieraConfigitem self)
|
||||
{
|
||||
TRACE (config_item);
|
||||
REQUIRE (self);
|
||||
|
||||
llist_init (&self->link);
|
||||
self->parent = NULL;
|
||||
llist_init (&self->childs);
|
||||
|
||||
llist_init (&self->lookup);
|
||||
|
||||
self->line = NULL;
|
||||
|
||||
self->key = NULL;
|
||||
self->key_size = 0;
|
||||
self->delim = NULL;
|
||||
self->vtable = NULL;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup)
|
||||
{
|
||||
TRACE (config_item);
|
||||
|
||||
if (self)
|
||||
{
|
||||
LLIST_WHILE_HEAD (&self->childs, node)
|
||||
lumiera_configitem_delete ((LumieraConfigitem) node, lookup);
|
||||
|
||||
ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs");
|
||||
|
||||
if (self->vtable && self->vtable->destroy)
|
||||
self->vtable->destroy (self);
|
||||
|
||||
if (!llist_is_empty (&self->lookup))
|
||||
lumiera_config_lookup_remove (lookup, self);
|
||||
|
||||
llist_unlink (&self->link);
|
||||
lumiera_free (self->line);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_new (const char* line)
|
||||
{
|
||||
TRACE (config_item);
|
||||
|
||||
lumiera_configitem tmp;
|
||||
lumiera_configitem_init (&tmp);
|
||||
|
||||
lumiera_configitem_parse (&tmp, line);
|
||||
|
||||
LumieraConfigitem self = tmp.vtable && tmp.vtable->new
|
||||
? tmp.vtable->new (&tmp)
|
||||
: lumiera_configitem_move (lumiera_malloc (sizeof (*self)), &tmp);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup)
|
||||
{
|
||||
TRACE (config_item);
|
||||
lumiera_free (lumiera_configitem_destroy (self, lookup));
|
||||
}
|
||||
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source)
|
||||
{
|
||||
TRACE (config_item);
|
||||
REQUIRE (self);
|
||||
REQUIRE (source);
|
||||
|
||||
llist_init (&self->link);
|
||||
llist_insertlist_next (&self->link, &source->link);
|
||||
|
||||
self->parent = source->parent;
|
||||
|
||||
llist_init (&self->childs);
|
||||
llist_insertlist_next (&self->childs, &source->childs);
|
||||
|
||||
llist_init (&self->lookup);
|
||||
llist_insertlist_next (&self->lookup, &source->lookup);
|
||||
|
||||
self->line = source->line;
|
||||
source->line = NULL;
|
||||
|
||||
self->key = source->key;
|
||||
self->key_size = source->key_size;
|
||||
self->delim = source->delim;
|
||||
self->vtable = source->vtable;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_parse (LumieraConfigitem self, const char* line)
|
||||
{
|
||||
TRACE (config_item);
|
||||
|
||||
self->line = lumiera_strndup (line, SIZE_MAX);
|
||||
|
||||
FIXME ("MOCKUP START");
|
||||
|
||||
TODO ("parsing here");
|
||||
/*
|
||||
HOWTO parse (for simav)
|
||||
in self->line liegt jetzt der 'rohe' string
|
||||
|
||||
parsen setzt folgende werte in self: .key, .key_size, .delim und vtable. den rest macht dann die 'new' funktion aus der vtable
|
||||
|
||||
es geht jetzt da drum rauszufinden ob diese zeile einses der folgenden sachen ist:
|
||||
(ich zeig hier nur die grundsyntax, das parsen sollte auch entartete situationen behandeln, insbesondere leerzeichen/tabulatoren an allen moeglichen stellen)
|
||||
auserdem sollt hier alles soweit wie moeglich validiert werden z.b. keys auf erlaubte zeichen gescheckt (siehe die _tr function)
|
||||
|
||||
section:
|
||||
'[prefix suffix]'
|
||||
.key == prefix
|
||||
.delim == das leerzeichen (oder tab) vor suffix oder aufs abschliessende ] wenn kein suffix
|
||||
|
||||
kommentar:
|
||||
leere zeile, zeile nur aus leerzeichen und tabulatoren, leerzeichen und tabulatoren gefolgt von # bis zum zeilenende
|
||||
alles ausser vtable auf NULL
|
||||
|
||||
direktive:
|
||||
'@direktive argumente'
|
||||
.key == @
|
||||
.delim == leerzeichen oder tab vor argumente, NULL wenn keine argumente
|
||||
|
||||
configentry:
|
||||
'key = value'
|
||||
.key == key begin
|
||||
.delim == '='
|
||||
'key < redirect'
|
||||
.key == key begin
|
||||
.delim == '>'
|
||||
|
||||
*/
|
||||
/*
|
||||
* What should be working (for cehteh) or not yet..
|
||||
*
|
||||
* die Elemente sollten bereits richtig unterschieden werden, die {} sind noch zu füllen.
|
||||
*
|
||||
* */
|
||||
|
||||
char* itr = self->line;
|
||||
|
||||
/*skip leading whitespaces*/
|
||||
while (*itr && isspace (*itr))
|
||||
itr++;
|
||||
|
||||
/*decide what this line represents*/
|
||||
if (!*itr || *itr == '#' )
|
||||
{
|
||||
/*this is an empty line or a a comment*/
|
||||
}
|
||||
else if (*itr == '@' )
|
||||
{
|
||||
/*this is a directive*/
|
||||
|
||||
/*itr points now to @*/
|
||||
self->key = itr;
|
||||
|
||||
/*check whether there are illegal whitespaces after @*/
|
||||
itr++;
|
||||
if (*itr && !isspace(*itr))
|
||||
{
|
||||
/*now look for the end of the directive and set the keysize*/
|
||||
self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
|
||||
|
||||
itr += self->key_size;
|
||||
|
||||
/*we need a key with a length greather than zero and
|
||||
* either the end of the line
|
||||
* or a whitespace after the key */
|
||||
|
||||
if ( self->key_size && ( !*itr || (*itr && isspace(*itr)) ))
|
||||
{
|
||||
/*look for given arguments*/
|
||||
|
||||
/*skip blanks*/
|
||||
while (*itr && isspace (*itr))
|
||||
itr++;
|
||||
|
||||
if (*itr)
|
||||
{
|
||||
/*there are arguments given, thus set delim*/
|
||||
self->delim = itr - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*no arguments were given*/
|
||||
self->delim = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*malformed lines shall be treated like if they were comments*/
|
||||
self->key = NULL;
|
||||
self->key_size = 0;
|
||||
|
||||
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*there occurred already an error right after the @!*/
|
||||
/*malformed lines shall be treated like if they were comments*/
|
||||
self->key = NULL;
|
||||
self->key_size = 0;
|
||||
|
||||
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
|
||||
}
|
||||
}
|
||||
else if (*itr == '[' )
|
||||
{
|
||||
/*this is a section*/
|
||||
|
||||
/*skip blanks before prefix*/
|
||||
itr++;
|
||||
while (*itr && isspace(*itr))
|
||||
itr++;
|
||||
|
||||
/*itr points now to the begin of the key*/
|
||||
self->key = itr;
|
||||
|
||||
/*now look for the end of the key and set the keysize*/
|
||||
self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
|
||||
|
||||
itr += self->key_size;
|
||||
|
||||
/*if the line ends ends with prefix] delim points to ]
|
||||
* and not the last (blank) character before the final square bracket*/
|
||||
if (self->key_size && *itr && *itr == ']')
|
||||
{
|
||||
self->delim = itr;
|
||||
TODO("self->vtable = &lumiera_configsection_funcs;");
|
||||
}
|
||||
else if (self->key_size && *itr && isspace(*itr))
|
||||
{
|
||||
/* skip blanks until we reach the suffix or the final square bracket*/
|
||||
while (*itr && isspace(*itr))
|
||||
itr++;
|
||||
|
||||
if (*itr && *itr == ']')
|
||||
{
|
||||
/*final square bracket reached, so place delim one char before the
|
||||
* actual position which must be a whitespace: no extra check necessary*/
|
||||
self->delim = itr - 1;
|
||||
TODO("self->vtable = &lumiera_configsection_funcs;");
|
||||
}
|
||||
else if (*itr)
|
||||
{
|
||||
TODO("check wheter suffix is made of legal characters");
|
||||
|
||||
/*delim points to the last whitespace before the actual position;
|
||||
* no extra check needed*/
|
||||
self->delim = itr - 1;
|
||||
TODO("self->vtable = &lumiera_configsection_funcs;");
|
||||
}
|
||||
else
|
||||
{
|
||||
/*malformed section line, treat this line like a comment*/
|
||||
self->key = NULL;
|
||||
self->key_size = 0;
|
||||
|
||||
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*error: either *itr is false, points neither to a blank nor to a closed square
|
||||
* bracket or the key_size is zero*/
|
||||
|
||||
/*treat this line like a comment*/
|
||||
self->key = NULL;
|
||||
self->key_size = 0;
|
||||
|
||||
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*this is probably a configentry*/
|
||||
|
||||
/*itr points now to the first not-whitespace-character*/
|
||||
self->key = itr;
|
||||
|
||||
/*now look for the end of the key and set the keysize*/
|
||||
self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
|
||||
|
||||
/* skip blanks */
|
||||
itr += self->key_size;
|
||||
while (*itr && isspace (*itr))
|
||||
itr++;
|
||||
|
||||
if (self->key_size && *itr == '=')
|
||||
{
|
||||
/*this configentry assigns a value to a key*/
|
||||
self->delim = itr;
|
||||
self->vtable = &lumiera_configentry_funcs;
|
||||
}
|
||||
else if (self->key_size && *itr == '<')
|
||||
{
|
||||
/*this configentry is a redirect*/
|
||||
self->delim = itr;
|
||||
self->vtable = &lumiera_configentry_funcs;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*this is not a valid configentry; treat this line like a comment*/
|
||||
self->key = NULL;
|
||||
self->key_size = 0;
|
||||
|
||||
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
137
src/backend/configitem.h
Normal file
137
src/backend/configitem.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
configitem.h - generalized hierachy of configuration items
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef LUMIERA_CONFIGITEM_H
|
||||
#define LUMIERA_CONFIGITEM_H
|
||||
|
||||
//TODO: Support library includes//
|
||||
#include "lib/llist.h"
|
||||
|
||||
|
||||
//TODO: Forward declarations//
|
||||
typedef struct lumiera_configitem_struct lumiera_configitem;
|
||||
typedef lumiera_configitem* LumieraConfigitem;
|
||||
|
||||
struct lumiera_configitem_vtable;
|
||||
|
||||
//TODO: Lumiera header includes//
|
||||
#include "backend/config_lookup.h"
|
||||
|
||||
|
||||
//TODO: System includes//
|
||||
#include <nobug.h>
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* configitems build a 3 level hierachy:
|
||||
*
|
||||
* 1. file:
|
||||
* contain sections
|
||||
*
|
||||
* 2. section:
|
||||
* [prefix suffix]
|
||||
* contain lines
|
||||
*
|
||||
* 3. lines are
|
||||
* comment:
|
||||
* empty line or line only containing spaces and tabs
|
||||
* line starting with spaces and tabs followed by a #
|
||||
* directive:
|
||||
* '@include name' or '@readonly'
|
||||
* directives are only valid at the toplevel section []
|
||||
* configurationentry:
|
||||
* 'key = value' or 'key < redirect'
|
||||
*/
|
||||
|
||||
|
||||
//TODO: declarations go here//
|
||||
/**
|
||||
* @file
|
||||
* configitems build a 3 level hierachy:
|
||||
*
|
||||
* 1. file:
|
||||
* contain sections
|
||||
*
|
||||
* 2. section:
|
||||
* [prefix suffix]
|
||||
* contain lines
|
||||
*
|
||||
* 3. lines are
|
||||
* comment:
|
||||
* empty line or line only containing spaces and tabs
|
||||
* line starting with spaces and tabs followed by a #
|
||||
* directive:
|
||||
* '@include name' or '@readonly'
|
||||
* directives are only valid at the toplevel section []
|
||||
* configurationentry:
|
||||
* 'key = value' or 'key < redirect'
|
||||
* errorneous:
|
||||
* any line which cant be parsed
|
||||
*/
|
||||
|
||||
struct lumiera_configitem_vtable
|
||||
{
|
||||
LumieraConfigitem (*new)(LumieraConfigitem);
|
||||
LumieraConfigitem (*destroy)(LumieraConfigitem);
|
||||
};
|
||||
|
||||
struct lumiera_configitem_struct
|
||||
{
|
||||
llist link; // all lines on the same hierachy level are linked here (see childs)
|
||||
LumieraConfigitem parent; // parent section
|
||||
llist childs; // root node for all lines below this hierachy
|
||||
|
||||
llist lookup; // all lines with the same key are stacked up on the loockup
|
||||
|
||||
char* line; // raw line as read in allocated here trailing \n will be replaced with \0
|
||||
char* key; // pointer into line to start of key
|
||||
size_t key_size;
|
||||
char* delim; // delimiter, value starts at delim+1
|
||||
struct lumiera_configitem_vtable* vtable; // functiontable for subclassing
|
||||
};
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_init (LumieraConfigitem self);
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup);
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_new (const char* line);
|
||||
|
||||
void
|
||||
lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup);
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_parse (LumieraConfigitem self, const char* line);
|
||||
|
||||
LumieraConfigitem
|
||||
lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem dest);
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
@ -50,7 +50,7 @@ lumiera_file_destroy (LumieraFile self)
|
|||
{
|
||||
TRACE (file);
|
||||
lumiera_filedescriptor_release (self->descriptor);
|
||||
free ((void*)self->name);
|
||||
lumiera_free (self->name);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ void
|
|||
lumiera_file_delete (LumieraFile self)
|
||||
{
|
||||
TRACE (file);
|
||||
free (lumiera_file_destroy (self));
|
||||
lumiera_free (lumiera_file_destroy (self));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ lumiera_file_handle_acquire (LumieraFile self)
|
|||
REQUIRE (self->descriptor);
|
||||
REQUIRE (lumiera_fhcache);
|
||||
|
||||
LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock)
|
||||
LUMIERA_MUTEX_SECTION (file, &self->descriptor->lock)
|
||||
{
|
||||
if (!self->descriptor->handle)
|
||||
/* no handle yet, get a new one */
|
||||
|
|
@ -123,7 +123,7 @@ lumiera_file_handle_release (LumieraFile self)
|
|||
{
|
||||
TRACE (file);
|
||||
|
||||
LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock)
|
||||
LUMIERA_MUTEX_SECTION (file, &self->descriptor->lock)
|
||||
{
|
||||
lumiera_filehandlecache_checkin (lumiera_fhcache, self->descriptor->handle);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ typedef lumiera_file* LumieraFile;
|
|||
|
||||
struct lumiera_file_struct
|
||||
{
|
||||
const char* name;
|
||||
char* name;
|
||||
LumieraFiledescriptor descriptor;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/safeclib.h"
|
||||
#include "lib/cuckoo.h"
|
||||
|
||||
#include "backend/file.h"
|
||||
#include "backend/filedescriptor.h"
|
||||
|
|
@ -32,6 +31,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
|
||||
|
|
@ -41,46 +41,50 @@ NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
|
|||
|
||||
This registry stores all acquired filedescriptors for lookup, they will be freed when not referenced anymore.
|
||||
*/
|
||||
static Cuckoo registry = NULL;
|
||||
static PSplay registry = NULL;
|
||||
static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER};
|
||||
|
||||
/*
|
||||
* setup hashing and compare functions for cuckoo hashing
|
||||
*/
|
||||
static size_t
|
||||
h1 (const void* item, const uint32_t r)
|
||||
{
|
||||
const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
|
||||
return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
|
||||
^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>7)^r;
|
||||
}
|
||||
|
||||
static size_t
|
||||
h2 (const void* item, const uint32_t r)
|
||||
{
|
||||
const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
|
||||
return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
|
||||
^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>5)^r;
|
||||
}
|
||||
|
||||
static size_t
|
||||
h3 (const void* item, const uint32_t r)
|
||||
{
|
||||
const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
|
||||
return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
|
||||
^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>3)^r;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmp (const void* keya, const void* keyb)
|
||||
cmp_fn (const void* keya, const void* keyb)
|
||||
{
|
||||
const LumieraFiledescriptor a = *(const LumieraFiledescriptor*)keya;
|
||||
const LumieraFiledescriptor b = *(const LumieraFiledescriptor*)keyb;
|
||||
return a->stat.st_dev == b->stat.st_dev && a->stat.st_ino == b->stat.st_ino
|
||||
&& (a->flags&LUMIERA_FILE_MASK) == (b->flags&LUMIERA_FILE_MASK);
|
||||
const LumieraFiledescriptor a = (const LumieraFiledescriptor)keya;
|
||||
const LumieraFiledescriptor b = (const LumieraFiledescriptor)keyb;
|
||||
|
||||
if (a->stat.st_dev < b->stat.st_dev)
|
||||
return -1;
|
||||
else if (a->stat.st_dev > b->stat.st_dev)
|
||||
return 1;
|
||||
|
||||
if (a->stat.st_ino < b->stat.st_ino)
|
||||
return -1;
|
||||
else if (a->stat.st_ino > b->stat.st_ino)
|
||||
return 1;
|
||||
|
||||
if ((a->flags&LUMIERA_FILE_MASK) < (b->flags&LUMIERA_FILE_MASK))
|
||||
return -1;
|
||||
else if ((a->flags&LUMIERA_FILE_MASK) > (b->flags&LUMIERA_FILE_MASK))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
delete_fn (PSplaynode node)
|
||||
{
|
||||
lumiera_filedescriptor_delete ((LumieraFiledescriptor) node);
|
||||
}
|
||||
|
||||
|
||||
static const void*
|
||||
key_fn (const PSplaynode node)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
lumiera_filedescriptor_registry_init (void)
|
||||
{
|
||||
|
|
@ -88,20 +92,24 @@ lumiera_filedescriptor_registry_init (void)
|
|||
TRACE (filedescriptor);
|
||||
REQUIRE (!registry);
|
||||
|
||||
registry = cuckoo_new (h1, h2, h3, cmp,
|
||||
sizeof (LumieraFiledescriptor),
|
||||
3);
|
||||
registry = psplay_new (cmp_fn, key_fn, delete_fn);
|
||||
if (!registry)
|
||||
LUMIERA_DIE (NO_MEMORY);
|
||||
|
||||
RESOURCE_HANDLE_INIT (registry_mutex.rh);
|
||||
RESOURCE_ANNOUNCE (filedescriptor, "mutex", "filedescriptor registry", ®istry, registry_mutex.rh);
|
||||
}
|
||||
|
||||
void
|
||||
lumiera_filedescriptor_registry_destroy (void)
|
||||
{
|
||||
TRACE (filedescriptor);
|
||||
REQUIRE (!cuckoo_nelements (registry));
|
||||
REQUIRE (!psplay_nelements (registry));
|
||||
|
||||
RESOURCE_FORGET (filedescriptor, registry_mutex.rh);
|
||||
|
||||
if (registry)
|
||||
cuckoo_free (registry);
|
||||
psplay_destroy (registry);
|
||||
registry = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -112,82 +120,77 @@ lumiera_filedescriptor_acquire (const char* name, int flags)
|
|||
TRACE (filedescriptor, "%s", name);
|
||||
REQUIRE (registry, "not initialized");
|
||||
|
||||
lumiera_mutexacquirer registry_lock;
|
||||
lumiera_mutexacquirer_init_mutex (®istry_lock, ®istry_mutex, LUMIERA_LOCKED);
|
||||
LumieraFiledescriptor dest = NULL;
|
||||
|
||||
lumiera_filedescriptor fdesc;
|
||||
fdesc.flags = flags;
|
||||
|
||||
if (stat (name, &fdesc.stat) != 0)
|
||||
LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex)
|
||||
{
|
||||
if (errno == ENOENT && flags&O_CREAT)
|
||||
lumiera_filedescriptor fdesc;
|
||||
fdesc.flags = flags;
|
||||
|
||||
if (stat (name, &fdesc.stat) != 0)
|
||||
{
|
||||
char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX);
|
||||
char* slash = dir;
|
||||
while ((slash = strchr (slash+1, '/')))
|
||||
if (errno == ENOENT && flags&O_CREAT)
|
||||
{
|
||||
*slash = '\0';
|
||||
INFO (filedescriptor, "try creating dir: %s", dir);
|
||||
if (mkdir (dir, 0777) == -1 && errno != EEXIST)
|
||||
char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX);
|
||||
char* slash = dir;
|
||||
while ((slash = strchr (slash+1, '/')))
|
||||
{
|
||||
*slash = '\0';
|
||||
INFO (filedescriptor, "try creating dir: %s", dir);
|
||||
if (mkdir (dir, 0777) == -1 && errno != EEXIST)
|
||||
{
|
||||
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
|
||||
goto error;
|
||||
}
|
||||
*slash = '/';
|
||||
}
|
||||
int fd;
|
||||
INFO (filedescriptor, "try creating file: %s", name);
|
||||
fd = creat (name, 0777);
|
||||
if (fd == -1)
|
||||
{
|
||||
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
|
||||
goto efile;
|
||||
goto error;
|
||||
}
|
||||
close (fd);
|
||||
if (stat (name, &fdesc.stat) != 0)
|
||||
{
|
||||
/* finally, no luck */
|
||||
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
|
||||
goto error;
|
||||
}
|
||||
*slash = '/';
|
||||
}
|
||||
int fd;
|
||||
INFO (filedescriptor, "try creating file: %s", name);
|
||||
fd = creat (name, 0777);
|
||||
if (fd == -1)
|
||||
{
|
||||
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
|
||||
goto efile;
|
||||
}
|
||||
close (fd);
|
||||
if (stat (name, &fdesc.stat) != 0)
|
||||
{
|
||||
/* finally, no luck */
|
||||
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
|
||||
goto efile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* lookup/create descriptor */
|
||||
LumieraFiledescriptor dest = &fdesc;
|
||||
LumieraFiledescriptor* found = cuckoo_find (registry, &dest);
|
||||
/* lookup/create descriptor */
|
||||
dest = (LumieraFiledescriptor) psplay_find (registry, &fdesc, 100);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
TRACE (filedescriptor, "Descriptor not found");
|
||||
|
||||
dest = lumiera_filedescriptor_new (&fdesc);
|
||||
if (!dest)
|
||||
goto ecreate;
|
||||
{
|
||||
TRACE (filedescriptor, "Descriptor not found");
|
||||
|
||||
cuckoo_insert (registry, &dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE (filedescriptor, "Descriptor already existing");
|
||||
dest = *found;
|
||||
++dest->refcount;
|
||||
dest = lumiera_filedescriptor_new (&fdesc);
|
||||
if (!dest)
|
||||
goto error;
|
||||
|
||||
psplay_insert (registry, &dest->node, 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE (filedescriptor, "Descriptor already existing");
|
||||
++dest->refcount;
|
||||
}
|
||||
error: ;
|
||||
}
|
||||
|
||||
lumiera_mutexacquirer_unlock (®istry_lock);
|
||||
return dest;
|
||||
|
||||
efile:
|
||||
ecreate:
|
||||
lumiera_mutexacquirer_unlock (®istry_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_filedescriptor_release (LumieraFiledescriptor self)
|
||||
{
|
||||
TRACE (filedescriptor);
|
||||
TRACE (filedescriptor, "%p", self);
|
||||
if (!--self->refcount)
|
||||
lumiera_filedescriptor_delete (self);
|
||||
}
|
||||
|
|
@ -199,17 +202,14 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template)
|
|||
LumieraFiledescriptor self = lumiera_malloc (sizeof (lumiera_filedescriptor));
|
||||
TRACE (filedescriptor, "at %p", self);
|
||||
|
||||
psplaynode_init (&self->node);
|
||||
self->stat = template->stat;
|
||||
|
||||
self->flags = template->flags;
|
||||
lumiera_mutex_init (&self->lock);
|
||||
self->refcount = 1;
|
||||
self->handle = 0;
|
||||
|
||||
const char* type = "mutex";
|
||||
const char* name = "filedescriptor";
|
||||
|
||||
RESOURCE_ANNOUNCE (filedescriptor, type, name, self, self->rh);
|
||||
lumiera_mutex_init (&self->lock, "filedescriptor", &NOBUG_FLAG (filedescriptor));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
|
@ -219,22 +219,19 @@ void
|
|||
lumiera_filedescriptor_delete (LumieraFiledescriptor self)
|
||||
{
|
||||
TRACE (filedescriptor, "%p", self);
|
||||
lumiera_mutexacquirer registry_lock;
|
||||
lumiera_mutexacquirer_init_mutex (®istry_lock, ®istry_mutex, LUMIERA_LOCKED);
|
||||
|
||||
REQUIRE (self->refcount == 0);
|
||||
LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex)
|
||||
{
|
||||
REQUIRE (self->refcount == 0);
|
||||
|
||||
RESOURCE_FORGET (filedescriptor, self->rh);
|
||||
psplay_remove (registry, &self->node);
|
||||
|
||||
cuckoo_remove (registry, cuckoo_find (registry, &self));
|
||||
|
||||
TODO ("destruct other members (WIP)");
|
||||
TODO ("destruct other members (WIP)");
|
||||
|
||||
|
||||
TODO ("release filehandle");
|
||||
TODO ("release filehandle");
|
||||
|
||||
lumiera_mutex_destroy (&self->lock);
|
||||
free (self);
|
||||
|
||||
lumiera_mutexacquirer_unlock (®istry_lock);
|
||||
lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (filedescriptor));
|
||||
lumiera_free (self);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#define LUMIERA_FILEDESCRIPTOR_H
|
||||
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/psplay.h"
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
|
|
@ -47,7 +48,8 @@ typedef lumiera_filedescriptor* LumieraFiledescriptor;
|
|||
|
||||
struct lumiera_filedescriptor_struct
|
||||
{
|
||||
struct stat stat; /* create after first open, maintained metadata, MUST BE FIRST! */
|
||||
psplaynode node; /* node for the lookup tree */
|
||||
struct stat stat; /* create after first open, maintained metadata */
|
||||
int flags; /* open flags, must be masked for reopen */
|
||||
lumiera_mutex lock; /* locks operations on this file descriptor */
|
||||
unsigned refcount; /* reference counter, all users sans registry */
|
||||
|
|
@ -55,8 +57,6 @@ struct lumiera_filedescriptor_struct
|
|||
LumieraFilehandle handle;
|
||||
//LumieraFileMap mappings;
|
||||
//LumieraWriteBuffer writebuffer;
|
||||
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -44,8 +44,7 @@ lumiera_filehandlecache_new (int max_entries)
|
|||
lumiera_mrucache_init (&lumiera_fhcache->cache, lumiera_filehandle_destroy_node);
|
||||
lumiera_fhcache->available = max_entries;
|
||||
lumiera_fhcache->checked_out = 0;
|
||||
lumiera_mutex_init (&lumiera_fhcache->lock);
|
||||
RESOURCE_ANNOUNCE (filehandlecache, "mutex", "filehandlecache", lumiera_fhcache, lumiera_fhcache->rh);
|
||||
lumiera_mutex_init (&lumiera_fhcache->lock, "filehandlecache", &NOBUG_FLAG (filehandlecache));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -55,10 +54,9 @@ lumiera_filehandlecache_delete (void)
|
|||
if (lumiera_fhcache)
|
||||
{
|
||||
REQUIRE (!lumiera_fhcache->checked_out, "Filehandles in use at shutdown");
|
||||
RESOURCE_FORGET (filehandlecache, lumiera_fhcache->rh);
|
||||
lumiera_mrucache_destroy (&lumiera_fhcache->cache);
|
||||
lumiera_mutex_destroy (&lumiera_fhcache->lock);
|
||||
free (lumiera_fhcache);
|
||||
lumiera_mutex_destroy (&lumiera_fhcache->lock, &NOBUG_FLAG (filehandlecache));
|
||||
lumiera_free (lumiera_fhcache);
|
||||
lumiera_fhcache = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +67,8 @@ lumiera_filehandlecache_handle_acquire (LumieraFilehandlecache self, LumieraFile
|
|||
{
|
||||
TRACE (filehandlecache);
|
||||
LumieraFilehandle ret = NULL;
|
||||
LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock)
|
||||
|
||||
LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock)
|
||||
{
|
||||
if (self->available <= 0 && self->cache.cached)
|
||||
{
|
||||
|
|
@ -106,7 +105,7 @@ lumiera_filehandlecache_checkout (LumieraFilehandlecache self, LumieraFilehandle
|
|||
if (!handle->use_cnt)
|
||||
{
|
||||
/* lock cache and checkout */
|
||||
LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock)
|
||||
LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock)
|
||||
{
|
||||
lumiera_mrucache_checkout (&self->cache, &handle->cachenode);
|
||||
}
|
||||
|
|
@ -128,7 +127,7 @@ lumiera_filehandlecache_checkin (LumieraFilehandlecache self, LumieraFilehandle
|
|||
if (!--handle->use_cnt)
|
||||
{
|
||||
/* lock cache and checin */
|
||||
LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock)
|
||||
LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock)
|
||||
{
|
||||
--self->checked_out;
|
||||
lumiera_mrucache_checkin (&self->cache, &handle->cachenode);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ struct lumiera_filehandlecache_struct
|
|||
int available;
|
||||
int checked_out;
|
||||
lumiera_mutex lock;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
|
||||
extern LumieraFilehandlecache lumiera_fhcache;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ namespace util
|
|||
|
||||
/** create as a tokenized <i>copy</i> of the current commandline.
|
||||
* Note that argv[0] is allways ignored. */
|
||||
Cmdline::Cmdline (int argc, char* argv[])
|
||||
Cmdline::Cmdline (int argc, const char** argv)
|
||||
: vector<string> (noneg(argc-1))
|
||||
{
|
||||
for (int i=1; i<argc; ++i)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace util
|
|||
class Cmdline : public VectS
|
||||
{
|
||||
public:
|
||||
Cmdline (int argc, char* argv[]);
|
||||
Cmdline (int argc, const char** argv);
|
||||
explicit Cmdline (const string cmdline);
|
||||
|
||||
operator string () const;
|
||||
|
|
|
|||
|
|
@ -128,10 +128,12 @@ namespace lumiera
|
|||
{
|
||||
const Error* err=dynamic_cast<const Error*> (&cause);
|
||||
if (err)
|
||||
if (isnil (err->cause_))
|
||||
return cause.what(); // cause is root cause
|
||||
else
|
||||
return err->cause_; // cause was caused by another exception
|
||||
{
|
||||
if (isnil (err->cause_))
|
||||
return cause.what(); // cause is root cause
|
||||
else
|
||||
return err->cause_; // cause was caused by another exception
|
||||
}
|
||||
|
||||
// unknown other exception type
|
||||
return cause.what ();
|
||||
|
|
|
|||
|
|
@ -26,27 +26,26 @@ liblumi_a_SOURCES = \
|
|||
$(liblumi_a_srcdir)/mutex.c \
|
||||
$(liblumi_a_srcdir)/rwlock.c \
|
||||
$(liblumi_a_srcdir)/condition.c \
|
||||
$(liblumi_a_srcdir)/references.c \
|
||||
$(liblumi_a_srcdir)/uuid.c \
|
||||
$(liblumi_a_srcdir)/luid.c \
|
||||
$(liblumi_a_srcdir)/safeclib.c \
|
||||
$(liblumi_a_srcdir)/cuckoo.c \
|
||||
$(liblumi_a_srcdir)/psplay.c \
|
||||
$(liblumi_a_srcdir)/mrucache.c \
|
||||
$(liblumi_a_srcdir)/time.c \
|
||||
$(liblumi_a_srcdir)/time.c \
|
||||
$(liblumi_a_srcdir)/appconfig.cpp
|
||||
|
||||
noinst_HEADERS += \
|
||||
$(liblumi_a_srcdir)/plugin.h \
|
||||
$(liblumi_a_srcdir)/error.h \
|
||||
$(liblumi_a_srcdir)/locking.h \
|
||||
$(liblumi_a_srcdir)/mutex.h \
|
||||
$(liblumi_a_srcdir)/rwlock.h \
|
||||
$(liblumi_a_srcdir)/condition.h \
|
||||
$(liblumi_a_srcdir)/references.h \
|
||||
$(liblumi_a_srcdir)/uuid.h \
|
||||
$(liblumi_a_srcdir)/luid.h \
|
||||
$(liblumi_a_srcdir)/safeclib.h \
|
||||
$(liblumi_a_srcdir)/cuckoo.h \
|
||||
$(liblumi_a_srcdir)/psplay.h \
|
||||
$(liblumi_a_srcdir)/mrucache.h \
|
||||
$(liblumi_a_srcdir)/time.h \
|
||||
$(liblumi_a_srcdir)/time.h \
|
||||
$(liblumi_a_srcdir)/appconfig.hpp \
|
||||
$(liblumi_a_srcdir)/lifecycleregistry.hpp
|
||||
|
||||
|
|
|
|||
|
|
@ -28,36 +28,32 @@
|
|||
|
||||
LUMIERA_ERROR_DEFINE (CONDITION_DESTROY, "condition destroy failed");
|
||||
|
||||
/**
|
||||
* Initialize a condition variable
|
||||
* @param self is a pointer to the condition variable to be initialized
|
||||
* @return self as given
|
||||
*/
|
||||
|
||||
LumieraCondition
|
||||
lumiera_condition_init (LumieraCondition self)
|
||||
lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
pthread_cond_init (&self->cond, NULL);
|
||||
pthread_mutex_init (&self->mutex, NULL);
|
||||
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
|
||||
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "cond_var", purpose, self, self->rh);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a condition variable
|
||||
* @param self is a pointer to the condition variable to be destroyed
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraCondition
|
||||
lumiera_condition_destroy (LumieraCondition self)
|
||||
lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
|
||||
|
||||
if (pthread_mutex_destroy (&self->mutex))
|
||||
LUMIERA_DIE (MUTEX_DESTROY);
|
||||
else if (pthread_cond_destroy (&self->cond))
|
||||
|
||||
if (pthread_cond_destroy (&self->cond))
|
||||
LUMIERA_DIE (CONDITION_DESTROY);
|
||||
}
|
||||
return self;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@
|
|||
#ifndef LUMIERA_CONDITION_H
|
||||
#define LUMIERA_CONDITION_H
|
||||
|
||||
#include "lib/locking.h"
|
||||
#include "lib/error.h"
|
||||
#include "lib/mutex.h"
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
|
|
@ -31,6 +33,49 @@
|
|||
|
||||
LUMIERA_ERROR_DECLARE (CONDITION_DESTROY);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Condition section.
|
||||
* Locks the condition mutex, one can use LUMIERA_CONDITION_WAIT to wait for signals or
|
||||
* LUMIERA_CONDITION_SIGNAL or LUMIERA_CONDITION_BROADCAST to wake waiting threads
|
||||
*/
|
||||
#define LUMIERA_CONDITION_SECTION(nobugflag, cnd) \
|
||||
for (lumiera_conditionacquirer NOBUG_CLEANUP(lumiera_conditionacquirer_ensureunlocked) \
|
||||
lumiera_condition_section_ = {(LumieraCondition)1}; \
|
||||
lumiera_condition_section_.condition;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_condition_section_.condition = (cnd); \
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, lumiera_condition_section_.flag = &NOBUG_FLAG(nobugflag)); \
|
||||
NOBUG_RESOURCE_HANDLE_INIT (lumiera_condition_section_.rh); \
|
||||
RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condition", &lumiera_condition_section_, \
|
||||
NOBUG_RESOURCE_EXCLUSIVE, lumiera_condition_section_.rh); \
|
||||
if (pthread_mutex_lock (&(cnd)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
|
||||
}); \
|
||||
lumiera_condition_section_.condition; \
|
||||
({ \
|
||||
if (lumiera_condition_section_.condition) \
|
||||
{ \
|
||||
pthread_mutex_unlock (&lumiera_condition_section_.condition->mutex); \
|
||||
lumiera_condition_section_.condition = NULL; \
|
||||
RESOURCE_LEAVE(nobugflag, lumiera_condition_section_.rh); \
|
||||
} \
|
||||
}))
|
||||
|
||||
#define LUMIERA_CONDITION_WAIT \
|
||||
do { \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCEING); \
|
||||
pthread_cond_wait (&lumiera_condition_section_.condition->cond, &lumiera_condition_section_.condition->mutex); \
|
||||
NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCE_EXCLUSIVE); \
|
||||
while (0)
|
||||
|
||||
#define LUMIERA_CONDITION_SIGNAL (nobugflag) pthread_cond_signal (&lumiera_condition_section_.condition->cond)
|
||||
|
||||
#define LUMIERA_CONDITION_BROADCAST (nobugflag) pthread_cond_broadcast (&lumiera_condition_section_.condition->cond)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Condition variables.
|
||||
*
|
||||
|
|
@ -39,17 +84,28 @@ struct lumiera_condition_struct
|
|||
{
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_condition_struct lumiera_condition;
|
||||
typedef lumiera_condition* LumieraCondition;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a condition variable
|
||||
* @param self is a pointer to the condition variable to be initialized
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraCondition
|
||||
lumiera_condition_init (LumieraCondition self);
|
||||
lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag);
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a condition variable
|
||||
* @param self is a pointer to the condition variable to be destroyed
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraCondition
|
||||
lumiera_condition_destroy (LumieraCondition self);
|
||||
lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag);
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -91,8 +147,9 @@ lumiera_condition_broadcast (LumieraCondition self)
|
|||
*/
|
||||
struct lumiera_conditionacquirer_struct
|
||||
{
|
||||
LumieraCondition cond;
|
||||
enum lumiera_lockstate state;
|
||||
LumieraCondition condition;
|
||||
NOBUG_IF(NOBUG_MODE_ALPHA, struct nobug_flag* flag);
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_conditionacquirer_struct lumiera_conditionacquirer;
|
||||
typedef struct lumiera_conditionacquirer_struct* LumieraConditionacquirer;
|
||||
|
|
@ -101,108 +158,15 @@ typedef struct lumiera_conditionacquirer_struct* LumieraConditionacquirer;
|
|||
static inline void
|
||||
lumiera_conditionacquirer_ensureunlocked (LumieraConditionacquirer self)
|
||||
{
|
||||
ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the condition mutex");
|
||||
}
|
||||
|
||||
/* override with a macro to use the cleanup checker */
|
||||
#define lumiera_conditionacquirer \
|
||||
lumiera_conditionacquirer NOBUG_CLEANUP(lumiera_conditionacquirer_ensureunlocked)
|
||||
|
||||
|
||||
/**
|
||||
* initialize a conditionacquirer state
|
||||
* @param self conditionacquirer to be initialized, must be an automatic variable
|
||||
* @param cond associated condition variable
|
||||
* @param state initial state of the mutex, either LUMIERA_LOCKED or LUMIERA_UNLOCKED
|
||||
* @return self as given
|
||||
* errors are fatal
|
||||
*/
|
||||
static inline LumieraConditionacquirer
|
||||
lumiera_conditionacquirer_init (LumieraConditionacquirer self, LumieraCondition cond, enum lumiera_lockstate state)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (cond);
|
||||
self->cond = cond;
|
||||
self->state = state;
|
||||
if (state == LUMIERA_LOCKED)
|
||||
if (pthread_mutex_lock (&cond->mutex))
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* lock the mutex.
|
||||
* must not already be locked
|
||||
* @param self conditionacquirer associated with a condition variable
|
||||
*/
|
||||
static inline void
|
||||
lumiera_conditionacquirer_lock (LumieraConditionacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
|
||||
|
||||
if (pthread_mutex_lock (&self->cond->mutex))
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
|
||||
self->state = LUMIERA_LOCKED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wait on a locked condition.
|
||||
* Waits until the condition variable gets signaled from another thread. Must already be locked.
|
||||
* @param self conditionacquirer associated with a condition variable
|
||||
*/
|
||||
static inline void
|
||||
lumiera_conditionacquirer_wait (LumieraConditionacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_LOCKED, "mutex must be locked");
|
||||
pthread_cond_wait (&self->cond->cond, &self->cond->mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* release mutex.
|
||||
* a conditionacquirer must be unlocked before leaving scope
|
||||
* @param self conditionacquirer associated with a condition variable
|
||||
*/
|
||||
static inline void
|
||||
lumiera_conditionacquirer_unlock (LumieraConditionacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
|
||||
if (pthread_mutex_unlock (&self->cond->mutex))
|
||||
LUMIERA_DIE (MUTEX_UNLOCK);
|
||||
self->state = LUMIERA_UNLOCKED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* signal a single waiting thread
|
||||
* @param self conditionacquirer associated with the condition variable to be signaled
|
||||
*/
|
||||
static inline void
|
||||
lumiera_conditionacquirer_signal (LumieraConditionacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
|
||||
pthread_cond_signal (&self->cond->cond);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* signal all waiting threads
|
||||
* @param self conditionacquirer associated with the condition variable to be signaled
|
||||
*/
|
||||
static inline void
|
||||
lumiera_conditionacquirer_broadcast (LumieraConditionacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
|
||||
pthread_cond_broadcast (&self->cond->cond);
|
||||
ENSURE (!self->condition, "forgot to unlock condition variable");
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
224
src/lib/cuckoo.c
224
src/lib/cuckoo.c
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#define CUCKOO_GRANULARITY int
|
||||
|
||||
enum compact_state
|
||||
{
|
||||
COMPACTING_OFF,
|
||||
|
|
@ -35,14 +37,11 @@ struct cuckoo_struct
|
|||
size_t size; /* t1 = 4*size; t2 = 2*size; t3 = size */
|
||||
size_t itemsize;
|
||||
|
||||
cuckoo_hashfunc h1; /* hash function */
|
||||
uint32_t r1; /* random, reset for each rehash */
|
||||
cuckoo_hashfunc h2;
|
||||
uint32_t r2;
|
||||
cuckoo_hashfunc h3;
|
||||
uint32_t r3;
|
||||
struct cuckoo_vtable vtable;
|
||||
|
||||
cuckoo_cmpfunc cmp;
|
||||
uint32_t r1; /* random, reset for each rehash */
|
||||
uint32_t r2;
|
||||
uint32_t r3;
|
||||
|
||||
void* t1;
|
||||
void* t2;
|
||||
|
|
@ -61,28 +60,59 @@ static inline uint32_t cuckoo_fast_prng ()
|
|||
return rnd = rnd<<1 ^ ((rnd>>30) & 1) ^ ((rnd>>2) & 1);
|
||||
}
|
||||
|
||||
static inline int
|
||||
iszero (void* mem, size_t size)
|
||||
{
|
||||
while (size && !*(CUCKOO_GRANULARITY*)mem)
|
||||
{
|
||||
size -= sizeof (CUCKOO_GRANULARITY);
|
||||
mem += sizeof (CUCKOO_GRANULARITY);
|
||||
}
|
||||
return !size;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xmemmov (void* dst, void* src, size_t size)
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
size -= sizeof (CUCKOO_GRANULARITY);
|
||||
*(CUCKOO_GRANULARITY*)(dst + size) = *(CUCKOO_GRANULARITY*)(src + size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Cuckoo
|
||||
cuckoo_init (Cuckoo self,
|
||||
cuckoo_hashfunc h1,
|
||||
cuckoo_hashfunc h2,
|
||||
cuckoo_hashfunc h3,
|
||||
cuckoo_cmpfunc cmp,
|
||||
size_t itemsize,
|
||||
unsigned startsize)
|
||||
cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable)
|
||||
{
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->size = 1<<startsize;
|
||||
self->itemsize = itemsize;
|
||||
self->h1 = h1;
|
||||
self->size = 16;
|
||||
self->itemsize = (itemsize * sizeof (CUCKOO_GRANULARITY)
|
||||
+ sizeof (CUCKOO_GRANULARITY) - 1) / sizeof (CUCKOO_GRANULARITY); /* round up to next CUCKOO_GRANULARITY boundary */
|
||||
self->r1 = cuckoo_fast_prng ();
|
||||
self->h2 = h2;
|
||||
self->r2 = cuckoo_fast_prng ();
|
||||
self->h3 = h3;
|
||||
self->r3 = cuckoo_fast_prng ();
|
||||
|
||||
self->cmp = cmp;
|
||||
if (!vtable->h1 || !vtable->h2 || !vtable->h3)
|
||||
return NULL;
|
||||
|
||||
self->vtable.h1 = vtable->h1;
|
||||
self->vtable.h2 = vtable->h2;
|
||||
self->vtable.h3 = vtable->h3;
|
||||
|
||||
if (!vtable->cmp)
|
||||
return NULL;
|
||||
|
||||
self->vtable.cmp = vtable->cmp;
|
||||
|
||||
self->vtable.dtor = vtable->dtor;
|
||||
|
||||
if (vtable->mov)
|
||||
self->vtable.mov = vtable->mov;
|
||||
else
|
||||
self->vtable.mov = xmemmov;
|
||||
|
||||
self->t1 = calloc (self->size * 4, itemsize);
|
||||
self->t2 = calloc (self->size * 2, itemsize);
|
||||
|
|
@ -101,19 +131,15 @@ cuckoo_init (Cuckoo self,
|
|||
|
||||
self->autocompact = COMPACTING_AUTO;
|
||||
self->elements = 0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
Cuckoo
|
||||
cuckoo_new (cuckoo_hashfunc h1,
|
||||
cuckoo_hashfunc h2,
|
||||
cuckoo_hashfunc h3,
|
||||
cuckoo_cmpfunc cmp,
|
||||
size_t itemsize,
|
||||
unsigned startsize)
|
||||
cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable)
|
||||
{
|
||||
Cuckoo self = malloc (sizeof (struct cuckoo_struct));
|
||||
if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize))
|
||||
if (!cuckoo_init (self, itemsize, vtable))
|
||||
{
|
||||
free (self);
|
||||
return NULL;
|
||||
|
|
@ -126,6 +152,18 @@ cuckoo_destroy (Cuckoo self)
|
|||
{
|
||||
if (self)
|
||||
{
|
||||
|
||||
if (self->vtable.dtor)
|
||||
{
|
||||
void* elem;
|
||||
for (elem = self->t1; elem < self->t1 + self->size * 4; elem += self->size)
|
||||
self->vtable.dtor (elem);
|
||||
for (elem = self->t2; elem < self->t1 + self->size * 2; elem += self->size)
|
||||
self->vtable.dtor (elem);
|
||||
for (elem = self->t3; elem < self->t1 + self->size; elem += self->size)
|
||||
self->vtable.dtor (elem);
|
||||
}
|
||||
|
||||
free (self->t1);
|
||||
free (self->t2);
|
||||
free (self->t3);
|
||||
|
|
@ -135,76 +173,57 @@ cuckoo_destroy (Cuckoo self)
|
|||
|
||||
|
||||
void
|
||||
cuckoo_free (Cuckoo self)
|
||||
cuckoo_delete (Cuckoo self)
|
||||
{
|
||||
free (cuckoo_destroy (self));
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
iszero (void* mem, size_t size)
|
||||
{
|
||||
while (size && !*(int*)mem)
|
||||
{
|
||||
size -= sizeof (int);
|
||||
mem += sizeof (int);
|
||||
}
|
||||
return !size;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xmemcpy (void* dst, void* src, size_t size)
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
size -= sizeof (int);
|
||||
*(int*)(dst + size) = *(int*)(src + size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
static void*
|
||||
cuckoo_insert_internal_ (Cuckoo self, void* item)
|
||||
{
|
||||
void* pos;
|
||||
char tmp[self->itemsize];
|
||||
CUCKOO_GRANULARITY tmp[self->itemsize / sizeof(CUCKOO_GRANULARITY)];
|
||||
|
||||
for (unsigned n = 0; n < self->maxloops; ++n)
|
||||
{
|
||||
/* find nest */
|
||||
pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
|
||||
pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size));
|
||||
/* kick old egg out */
|
||||
xmemcpy (tmp, pos, self->itemsize);
|
||||
if (iszero (pos, self->itemsize))
|
||||
memset (tmp, 0, self->itemsize);
|
||||
else
|
||||
self->vtable.mov (tmp, pos, self->itemsize);
|
||||
/* lay egg */
|
||||
xmemcpy (pos, item, self->itemsize);
|
||||
self->vtable.mov (pos, item, self->itemsize);
|
||||
|
||||
if (iszero (tmp, self->itemsize))
|
||||
return 1;
|
||||
return pos;
|
||||
|
||||
/* find nest */
|
||||
pos = self->t2 + self->itemsize * (self->h2 (tmp, self->r2) % (2*self->size));
|
||||
pos = self->t2 + self->itemsize * (self->vtable.h2 (tmp, self->r2) % (2*self->size));
|
||||
/* kick old egg out */
|
||||
xmemcpy (item, pos, self->itemsize);
|
||||
self->vtable.mov (item, pos, self->itemsize);
|
||||
/* lay egg */
|
||||
xmemcpy (pos, tmp, self->itemsize);
|
||||
self->vtable.mov (pos, tmp, self->itemsize);
|
||||
|
||||
if (iszero (item, self->itemsize))
|
||||
return 1;
|
||||
return pos;
|
||||
|
||||
/* find nest */
|
||||
pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
|
||||
pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size);
|
||||
/* kick old egg out */
|
||||
xmemcpy (tmp, pos, self->itemsize);
|
||||
self->vtable.mov (tmp, pos, self->itemsize);
|
||||
/* lay egg */
|
||||
xmemcpy (pos, item, self->itemsize);
|
||||
self->vtable.mov (pos, item, self->itemsize);
|
||||
|
||||
if (iszero (tmp, self->itemsize))
|
||||
return 1;
|
||||
return pos;
|
||||
|
||||
/* copy tmp to item, which will be reinserted on next interation / after rehashing */
|
||||
xmemcpy (item, tmp, self->itemsize);
|
||||
self->vtable.mov (item, tmp, self->itemsize);
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -230,14 +249,14 @@ cuckoo_rehash (Cuckoo self)
|
|||
{
|
||||
for (n = 0; n < self->maxloops; ++n)
|
||||
{
|
||||
unsigned hash = self->h1 (pos, self->r1) % (4*self->size);
|
||||
unsigned hash = self->vtable.h1 (pos, self->r1) % (4*self->size);
|
||||
if (hash != i)
|
||||
{
|
||||
char t[self->itemsize];
|
||||
void* hpos = self->t1 + self->itemsize * hash;
|
||||
xmemcpy (t, hpos, self->itemsize);
|
||||
xmemcpy (hpos, pos, self->itemsize);
|
||||
xmemcpy (pos, t, self->itemsize);
|
||||
self->vtable.mov (t, hpos, self->itemsize);
|
||||
self->vtable.mov (hpos, pos, self->itemsize);
|
||||
self->vtable.mov (pos, t, self->itemsize);
|
||||
if (iszero (t, self->itemsize))
|
||||
break;
|
||||
}
|
||||
|
|
@ -260,14 +279,14 @@ cuckoo_rehash (Cuckoo self)
|
|||
{
|
||||
for (n = 0; n < self->maxloops; ++n)
|
||||
{
|
||||
unsigned hash = self->h2 (pos, self->r2) % (2*self->size);
|
||||
unsigned hash = self->vtable.h2 (pos, self->r2) % (2*self->size);
|
||||
if (hash != i)
|
||||
{
|
||||
char t[self->itemsize];
|
||||
void* hpos = self->t2 + self->itemsize * hash;
|
||||
xmemcpy (t, hpos, self->itemsize);
|
||||
xmemcpy (hpos, pos, self->itemsize);
|
||||
xmemcpy (pos, t, self->itemsize);
|
||||
self->vtable.mov (t, hpos, self->itemsize);
|
||||
self->vtable.mov (hpos, pos, self->itemsize);
|
||||
self->vtable.mov (pos, t, self->itemsize);
|
||||
if (iszero (t, self->itemsize))
|
||||
break;
|
||||
}
|
||||
|
|
@ -290,14 +309,14 @@ cuckoo_rehash (Cuckoo self)
|
|||
{
|
||||
for (n = 0; n < self->maxloops; ++n)
|
||||
{
|
||||
unsigned hash = self->h3 (pos, self->r3) % self->size;
|
||||
unsigned hash = self->vtable.h3 (pos, self->r3) % self->size;
|
||||
if (hash != i)
|
||||
{
|
||||
char t[self->itemsize];
|
||||
void* hpos = self->t3 + self->itemsize * hash;
|
||||
xmemcpy (t, hpos, self->itemsize);
|
||||
xmemcpy (hpos, pos, self->itemsize);
|
||||
xmemcpy (pos, t, self->itemsize);
|
||||
self->vtable.mov (t, hpos, self->itemsize);
|
||||
self->vtable.mov (hpos, pos, self->itemsize);
|
||||
self->vtable.mov (pos, t, self->itemsize);
|
||||
if (iszero (t, self->itemsize))
|
||||
break;
|
||||
}
|
||||
|
|
@ -314,10 +333,10 @@ static int
|
|||
cuckoo_grow (Cuckoo self)
|
||||
{
|
||||
/* rotate hashfuncs, tables, randoms */
|
||||
cuckoo_hashfunc th = self->h3;
|
||||
self->h3 = self->h2;
|
||||
self->h2 = self->h1;
|
||||
self->h1 = th;
|
||||
cuckoo_hashfunc th = self->vtable.h3;
|
||||
self->vtable.h3 = self->vtable.h2;
|
||||
self->vtable.h2 = self->vtable.h1;
|
||||
self->vtable.h1 = th;
|
||||
|
||||
uint32_t tr = self->r3;
|
||||
self->r3 = self->r2;
|
||||
|
|
@ -380,10 +399,10 @@ cuckoo_compact (Cuckoo self)
|
|||
|
||||
if (self->size > 2 && self->elements < self->size * 3)
|
||||
{
|
||||
cuckoo_hashfunc th = self->h1;
|
||||
self->h1 = self->h2;
|
||||
self->h2 = self->h3;
|
||||
self->h3 = th;
|
||||
cuckoo_hashfunc th = self->vtable.h1;
|
||||
self->vtable.h1 = self->vtable.h2;
|
||||
self->vtable.h2 = self->vtable.h3;
|
||||
self->vtable.h3 = th;
|
||||
|
||||
uint32_t tr = self->r1;
|
||||
self->r1 = self->r2;
|
||||
|
|
@ -425,7 +444,7 @@ cuckoo_compact (Cuckoo self)
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
void*
|
||||
cuckoo_insert (Cuckoo self, void* item)
|
||||
{
|
||||
char tmp[self->itemsize];
|
||||
|
|
@ -433,30 +452,32 @@ cuckoo_insert (Cuckoo self, void* item)
|
|||
void* found;
|
||||
if ((found = cuckoo_find (self, item)))
|
||||
{
|
||||
xmemcpy (found, item, self->itemsize);
|
||||
return 1;
|
||||
if (self->vtable.dtor)
|
||||
self->vtable.dtor (found);
|
||||
self->vtable.mov (found, item, self->itemsize);
|
||||
return found;
|
||||
}
|
||||
|
||||
xmemcpy (tmp, item, self->itemsize);
|
||||
self->vtable.mov (tmp, item, self->itemsize);
|
||||
|
||||
for (unsigned n = 6; n; --n) /* rehash/grow loop */
|
||||
{
|
||||
if (cuckoo_insert_internal_ (self, tmp))
|
||||
if ((found = cuckoo_insert_internal_ (self, tmp)))
|
||||
{
|
||||
++self->elements;
|
||||
return 1;
|
||||
return found;
|
||||
}
|
||||
|
||||
if (self->elements > n*self->size)
|
||||
{
|
||||
n = 6;
|
||||
if (!cuckoo_grow (self))
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
cuckoo_rehash (self);
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -465,16 +486,16 @@ cuckoo_find (Cuckoo self, void* item)
|
|||
{
|
||||
void* pos;
|
||||
|
||||
pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
|
||||
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
|
||||
pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size));
|
||||
if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
|
||||
return pos;
|
||||
|
||||
pos = self->t2 + self->itemsize * (self->h2 (item, self->r2) % (2*self->size));
|
||||
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
|
||||
pos = self->t2 + self->itemsize * (self->vtable.h2 (item, self->r2) % (2*self->size));
|
||||
if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
|
||||
return pos;
|
||||
|
||||
pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
|
||||
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
|
||||
pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size);
|
||||
if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
|
||||
return pos;
|
||||
|
||||
return NULL;
|
||||
|
|
@ -486,6 +507,9 @@ cuckoo_remove (Cuckoo self, void* item)
|
|||
{
|
||||
if (item)
|
||||
{
|
||||
if (self->vtable.dtor)
|
||||
self->vtable.dtor (item);
|
||||
|
||||
memset (item, 0, self->itemsize);
|
||||
--self->elements;
|
||||
|
||||
|
|
|
|||
|
|
@ -54,41 +54,61 @@ typedef size_t (*cuckoo_hashfunc)(const void* item, const uint32_t r);
|
|||
*/
|
||||
typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2);
|
||||
|
||||
/**
|
||||
* Item destructor function.
|
||||
* User supplied destructor function. This function is called when items are removed
|
||||
* from the hash or at hash detroy/delete time. Must be safe to be called on a zeroed element.
|
||||
* @param item address of the item to be destroyed
|
||||
*/
|
||||
typedef void (*cuckoo_dtorfunc)(void* item);
|
||||
|
||||
/**
|
||||
* Move function.
|
||||
* User supplied item move function
|
||||
* @param dest target address for the move operation
|
||||
* @param src source for the move operation
|
||||
* @param size size of a item (requested size rounded up to the next CUCKOO_GRANULARITY)
|
||||
* It might be necessary to invalidate the source in some case, cuckoo will zero it out
|
||||
* after moving.
|
||||
*/
|
||||
typedef void (*cuckoo_movfunc)(void* dest, void* src, size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* Function table used to specialize various funtions used by the hash.
|
||||
* TODO some elements might be NULL, then defaults are used
|
||||
*/
|
||||
struct cuckoo_vtable
|
||||
{
|
||||
cuckoo_hashfunc h1;
|
||||
cuckoo_hashfunc h2;
|
||||
cuckoo_hashfunc h3;
|
||||
cuckoo_cmpfunc cmp;
|
||||
cuckoo_dtorfunc dtor;
|
||||
cuckoo_movfunc mov;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a cuckoo hash.
|
||||
* @param self pointer to a uninitialized cuckoo datastructure
|
||||
* @param h1 hash function for the first table
|
||||
* @param h2 hash function for the second table
|
||||
* @param h3 hash function for the third table
|
||||
* @param cmp function which compares two keys
|
||||
* @param startsize initial size of table t3, as 2's exponent
|
||||
* @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY
|
||||
* @param vtable initialized vtable
|
||||
* @return The initialized hashtable or NULL at allocation failure
|
||||
*/
|
||||
Cuckoo
|
||||
cuckoo_init (Cuckoo self,
|
||||
cuckoo_hashfunc h1,
|
||||
cuckoo_hashfunc h2,
|
||||
cuckoo_hashfunc h3,
|
||||
cuckoo_cmpfunc cmp,
|
||||
size_t itemsize,
|
||||
unsigned startsize);
|
||||
cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable);
|
||||
|
||||
/**
|
||||
* Allocate a new cuckoo hash.
|
||||
* @param h1 hash function for the first table
|
||||
* @param h2 hash function for the second table
|
||||
* @param h3 hash function for the third table
|
||||
* @param cmp function which compares two keys
|
||||
* @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY
|
||||
* @param startsize initial size of table t3, as 2's exponent
|
||||
* @param vtable initialized vtable
|
||||
* @return The initialized hashtable or NULL at allocation failure
|
||||
*/
|
||||
Cuckoo
|
||||
cuckoo_new (cuckoo_hashfunc h1,
|
||||
cuckoo_hashfunc h2,
|
||||
cuckoo_hashfunc h3,
|
||||
cuckoo_cmpfunc cmp,
|
||||
size_t itemsize,
|
||||
unsigned startsize);
|
||||
cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable);
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a cuckoo hash.
|
||||
|
|
@ -104,7 +124,7 @@ cuckoo_destroy (Cuckoo self);
|
|||
* @param self handle of the hash table to be freed
|
||||
*/
|
||||
void
|
||||
cuckoo_free (Cuckoo self);
|
||||
cuckoo_delete (Cuckoo self);
|
||||
|
||||
/**
|
||||
* Get the number of elements stored in a hash.
|
||||
|
|
@ -117,12 +137,14 @@ cuckoo_nelements (Cuckoo self);
|
|||
* Insert an element into a hash.
|
||||
* amortized O(1) complexity because it may rarely rehash the tables or even grow them.
|
||||
* see cuckoo_reserve() about how to preallocate entries to prevent the growing costs.
|
||||
* Inserting an element already in the hash calls the dtor for the old entry and places
|
||||
* the new one into the hash.
|
||||
* @param self handle to the hash table
|
||||
* @param item pointer to a item to be inserted
|
||||
* @return 1 on successful insert, 0 on allocation failure
|
||||
* @return pointer to inserted element on successful insert, NULL on allocation failure
|
||||
* Note: at failure there is one arbitary hash cell lost!
|
||||
*/
|
||||
int
|
||||
void*
|
||||
cuckoo_insert (Cuckoo self, void* item);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -45,19 +45,13 @@ lumiera_error_tls_init (void)
|
|||
pthread_key_create (&lumiera_error_tls, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set error state for the current thread.
|
||||
* If the error state of the current thread was cleared, then set it, else preserve the old state.
|
||||
* @param nerr name of the error with 'LUMIERA_ERROR_' prefix (example: LUMIERA_ERROR_NO_MEMORY)
|
||||
* @return old state, that is NULL for success, when the state was cleared and a pointer to a pending
|
||||
* error when the error state was already set
|
||||
*/
|
||||
const char*
|
||||
lumiera_error_set (const char * nerr)
|
||||
|
||||
lumiera_err
|
||||
lumiera_error_set (lumiera_err nerr)
|
||||
{
|
||||
pthread_once (&lumiera_error_initialized, lumiera_error_tls_init);
|
||||
|
||||
const char* err = pthread_getspecific (lumiera_error_tls);
|
||||
lumiera_err err = pthread_getspecific (lumiera_error_tls);
|
||||
if (!err)
|
||||
pthread_setspecific (lumiera_error_tls, nerr);
|
||||
|
||||
|
|
@ -65,18 +59,12 @@ lumiera_error_set (const char * nerr)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get and clear current error state.
|
||||
* This function clears the error state, if it needs to be reused, one has to store it in a temporary
|
||||
* variable.
|
||||
* @return pointer to any pending error of this thread, NULL if no error is pending
|
||||
*/
|
||||
const char*
|
||||
lumiera_err
|
||||
lumiera_error ()
|
||||
{
|
||||
pthread_once (&lumiera_error_initialized, lumiera_error_tls_init);
|
||||
|
||||
const char* err = pthread_getspecific (lumiera_error_tls);
|
||||
lumiera_err err = pthread_getspecific (lumiera_error_tls);
|
||||
if (err)
|
||||
pthread_setspecific (lumiera_error_tls, NULL);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ extern "C" {
|
|||
* C Error handling in Lumiera, header.
|
||||
*/
|
||||
|
||||
typedef const char* lumiera_err;
|
||||
|
||||
/**
|
||||
* Abort unconditionally with a 'Fatal Error!' message.
|
||||
|
|
@ -49,7 +50,7 @@ extern "C" {
|
|||
* @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY)
|
||||
*/
|
||||
#define LUMIERA_ERROR_DECLARE(err) \
|
||||
extern const char* LUMIERA_ERROR_##err
|
||||
extern lumiera_err LUMIERA_ERROR_##err
|
||||
|
||||
/**
|
||||
* Definition and initialization of an error constant.
|
||||
|
|
@ -58,7 +59,7 @@ extern const char* LUMIERA_ERROR_##err
|
|||
* @param msg message describing the error in plain english (example: "memory allocation failed")
|
||||
*/
|
||||
#define LUMIERA_ERROR_DEFINE(err, msg) \
|
||||
const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
|
||||
lumiera_err LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
|
||||
|
||||
/**
|
||||
* Helper macro to raise an error for the current thread.
|
||||
|
|
@ -70,10 +71,23 @@ const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
|
|||
(({ERROR (flag, "%s", strchr(LUMIERA_ERROR_##err, ':')+1);}), \
|
||||
lumiera_error_set(LUMIERA_ERROR_##err))
|
||||
|
||||
const char*
|
||||
lumiera_error_set (const char * err);
|
||||
/**
|
||||
* Set error state for the current thread.
|
||||
* If the error state of the current thread was cleared, then set it, else preserve the old state.
|
||||
* @param nerr name of the error with 'LUMIERA_ERROR_' prefix (example: LUMIERA_ERROR_NO_MEMORY)
|
||||
* @return old state, that is NULL for success, when the state was cleared and a pointer to a pending
|
||||
* error when the error state was already set
|
||||
*/
|
||||
lumiera_err
|
||||
lumiera_error_set (lumiera_err err);
|
||||
|
||||
const char*
|
||||
/**
|
||||
* Get and clear current error state.
|
||||
* This function clears the error state, if it needs to be reused, one has to store it in a temporary
|
||||
* variable.
|
||||
* @return pointer to any pending error of this thread, NULL if no error is pending
|
||||
*/
|
||||
lumiera_err
|
||||
lumiera_error ();
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -299,6 +299,9 @@ LLIST_FUNC (LList llist_unlink (LList self),
|
|||
/**
|
||||
* Fix a node which got relocated in memory.
|
||||
* It is supported to realloc/move list nodes in memory but one must call 'list_relocate' after doing so.
|
||||
* IMPORTANT: it is not possible to relocate nodes which are empty this way, nor can this be determined
|
||||
* after the relocation, so either llist_init them afterwards or insert a bogus node before moving the node
|
||||
* and relocating it and remove it afterwards.
|
||||
* @param self node which got relocated
|
||||
* @return self
|
||||
*/
|
||||
|
|
@ -306,6 +309,7 @@ LLIST_FUNC (LList llist_relocate (LList self),
|
|||
return self->next->prev = self->prev->next = self;
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Insert a node after another.
|
||||
* @param self node after which we want to insert
|
||||
|
|
|
|||
113
src/lib/luid.c
Normal file
113
src/lib/luid.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
luid - Lumiera unique identifiers
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "lib/luid.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void
|
||||
lumiera_uid_set_ptr (lumiera_uid* luid, void* ptr)
|
||||
{
|
||||
memset (luid, 0, 16);
|
||||
*(void**)luid = ptr;
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
lumiera_uid_ptr_get (lumiera_uid* luid)
|
||||
{
|
||||
return *(void**)luid;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_uid_gen (lumiera_uid* luid)
|
||||
{
|
||||
static int fd = -2;
|
||||
if (!luid)
|
||||
return;
|
||||
|
||||
if (fd == -2)
|
||||
{
|
||||
fd = open ("/dev/urandom", O_RDONLY);
|
||||
/* on linux /dev/random would be way to slow for our purpose, so we comment that out for now.
|
||||
other unixiods offer a /dev/random which has the same semantics as linux /dev/urandom has,
|
||||
configuration should do this right some day.
|
||||
if (fd == -1)
|
||||
fd = open ("/dev/random", O_RDONLY);
|
||||
*/
|
||||
if (fd >= 0)
|
||||
fcntl (fd, F_SETFD, FD_CLOEXEC);
|
||||
else
|
||||
srand (getpid () + time (NULL));
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (fd < 0)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
((unsigned char*)luid)[i] = (unsigned char)(rand()>>7);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (read (fd, luid, 16) < 16)
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
/* we identify generic pointers by having some zeros in the luid,
|
||||
* this happens very unlikely to be in a random luid, just regenerate it then */
|
||||
while (!*(((intptr_t*)luid)+1));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src)
|
||||
{
|
||||
memcpy (dest, src, 16);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb)
|
||||
{
|
||||
return !memcmp (luida, luidb, 16);
|
||||
}
|
||||
|
||||
size_t
|
||||
lumiera_uid_hash (lumiera_uid* luid)
|
||||
{
|
||||
return *(size_t*)luid;
|
||||
}
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
81
src/lib/luid.h
Normal file
81
src/lib/luid.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
luid - Lumiera unique identifiers
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#ifndef LUMIERA_LUID_H
|
||||
#define LUMIERA_LUID_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Lumiera unique identifiers are 128 byte random value. Unlike standard uuid's we
|
||||
* don't tag a version within them and we may store generic pointers in the space
|
||||
* occupied by an luid.
|
||||
*/
|
||||
|
||||
typedef unsigned char lumiera_uid[16];
|
||||
|
||||
/**
|
||||
* Retrieve a generic pointer stored in a luid
|
||||
*/
|
||||
void*
|
||||
lumiera_uid_ptr_get (lumiera_uid* luid);
|
||||
|
||||
/**
|
||||
* Generate a new luid
|
||||
*/
|
||||
void
|
||||
lumiera_uid_gen (lumiera_uid* luid);
|
||||
|
||||
/**
|
||||
* Store a generic pointer in a luid
|
||||
*/
|
||||
void
|
||||
lumiera_uid_set_ptr (lumiera_uid* luid, void* ptr);
|
||||
|
||||
|
||||
/**
|
||||
* Copy an luid
|
||||
*/
|
||||
void
|
||||
lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src);
|
||||
|
||||
|
||||
/**
|
||||
* Test 2 luid's for equality
|
||||
*/
|
||||
int
|
||||
lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb);
|
||||
|
||||
|
||||
/**
|
||||
* Generate a hashsum over an luid
|
||||
*/
|
||||
size_t
|
||||
lumiera_uid_hash (lumiera_uid* luid);
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "lib/safeclib.h"
|
||||
#include "lib/mrucache.h"
|
||||
|
||||
|
||||
|
|
@ -39,9 +40,9 @@ lumiera_mrucache_destroy (LumieraMruCache self)
|
|||
{
|
||||
llist_unlink (node);
|
||||
if (self->destructor_cb)
|
||||
free (self->destructor_cb (node));
|
||||
lumiera_free (self->destructor_cb (node));
|
||||
else
|
||||
free (node);
|
||||
lumiera_free (node);
|
||||
}
|
||||
self->cached = 0;
|
||||
return self;
|
||||
|
|
@ -52,7 +53,7 @@ lumiera_mrucache_age (LumieraMruCache self, int nelem)
|
|||
{
|
||||
REQUIRE (self);
|
||||
while (self->cached && nelem--)
|
||||
free (lumiera_mrucache_pop (self));
|
||||
lumiera_free (lumiera_mrucache_pop (self));
|
||||
|
||||
return nelem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,34 +31,35 @@ LUMIERA_ERROR_DEFINE (MUTEX_UNLOCK, "Mutex unlocking failed");
|
|||
LUMIERA_ERROR_DEFINE (MUTEX_DESTROY, "Mutex destroy failed");
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a mutex variable
|
||||
* @param self is a pointer to the mutex to be initialized
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraMutex
|
||||
lumiera_mutex_init (LumieraMutex self)
|
||||
lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
pthread_mutex_init (&self->mutex, NULL);
|
||||
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
|
||||
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "mutex", purpose, self, self->rh);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a mutex variable
|
||||
* @param self is a pointer to the mutex to be destroyed
|
||||
* @return self as given
|
||||
*/
|
||||
|
||||
LumieraMutex
|
||||
lumiera_mutex_destroy (LumieraMutex self)
|
||||
lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
|
||||
if (pthread_mutex_destroy (&self->mutex))
|
||||
LUMIERA_DIE (MUTEX_DESTROY);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
193
src/lib/mutex.h
193
src/lib/mutex.h
|
|
@ -22,21 +22,43 @@
|
|||
#ifndef LUMIERA_MUTEX_H
|
||||
#define LUMIERA_MUTEX_H
|
||||
|
||||
#include "lib/locking.h"
|
||||
#include "lib/error.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <nobug.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Mutual exclusion locking, header.
|
||||
*/
|
||||
#define LUMIERA_MUTEX_SECTION(flag, handle, mutex) \
|
||||
RESOURCE_HANDLE (rh_##__LINE__##_); \
|
||||
lumiera_mutexacquirer lock_##__LINE__##_; \
|
||||
RESOURCE_ENTER (flag, handle, "acquire mutex", &lock_##__LINE__##_, \
|
||||
NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \
|
||||
for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKED); \
|
||||
lock_##__LINE__##_.state == LUMIERA_LOCKED; \
|
||||
lumiera_mutexacquirer_unlock (&lock_##__LINE__##_), \
|
||||
({RESOURCE_LEAVE(flag, rh_##__LINE__##_);}))
|
||||
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_LOCK);
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK);
|
||||
LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
|
||||
|
||||
/**
|
||||
* Mutual exclusive section.
|
||||
*/
|
||||
#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \
|
||||
for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \
|
||||
lumiera_mutex_section_.mutex;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_mutex_section_.mutex = (mtx); \
|
||||
NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
|
||||
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \
|
||||
NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \
|
||||
if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
|
||||
}); \
|
||||
lumiera_mutex_section_.mutex; \
|
||||
({ \
|
||||
if (lumiera_mutex_section_.mutex) \
|
||||
{ \
|
||||
pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \
|
||||
lumiera_mutex_section_.mutex = NULL; \
|
||||
RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \
|
||||
} \
|
||||
}))
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -46,27 +68,37 @@ for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKE
|
|||
struct lumiera_mutex_struct
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_mutex_struct lumiera_mutex;
|
||||
typedef lumiera_mutex* LumieraMutex;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a mutex variable
|
||||
* @param self is a pointer to the mutex to be initialized
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraMutex
|
||||
lumiera_mutex_init (LumieraMutex self);
|
||||
|
||||
|
||||
LumieraMutex
|
||||
lumiera_mutex_destroy (LumieraMutex self);
|
||||
|
||||
lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);
|
||||
|
||||
|
||||
/**
|
||||
* mutexacquirer used to manage the state of a mutex variable.
|
||||
* Destroy a mutex variable
|
||||
* @param self is a pointer to the mutex to be destroyed
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraMutex
|
||||
lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag);
|
||||
|
||||
|
||||
/**
|
||||
* mutexacquirer used to manage the state of a mutex.
|
||||
*/
|
||||
struct lumiera_mutexacquirer_struct
|
||||
{
|
||||
LumieraMutex mutex;
|
||||
enum lumiera_lockstate state;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_mutexacquirer_struct lumiera_mutexacquirer;
|
||||
typedef struct lumiera_mutexacquirer_struct* LumieraMutexacquirer;
|
||||
|
|
@ -75,123 +107,14 @@ typedef struct lumiera_mutexacquirer_struct* LumieraMutexacquirer;
|
|||
static inline void
|
||||
lumiera_mutexacquirer_ensureunlocked (LumieraMutexacquirer self)
|
||||
{
|
||||
ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock mutex");
|
||||
}
|
||||
|
||||
/* override with a macro to use the cleanup checker */
|
||||
#define lumiera_mutexacquirer \
|
||||
lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked)
|
||||
|
||||
|
||||
/**
|
||||
* initialize a mutexacquirer state without mutex.
|
||||
* @param self mutexacquirer to be initialized, must be an automatic variable
|
||||
* @return self as given
|
||||
* This initialization is used when lumiera_mutexacquirer_try_mutex shall be used later
|
||||
*/
|
||||
static inline LumieraMutexacquirer
|
||||
lumiera_mutexacquirer_init (LumieraMutexacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
self->mutex = NULL;
|
||||
self->state = LUMIERA_UNLOCKED;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize a mutexacquirer state
|
||||
* @param self mutexacquirer to be initialized, must be an automatic variable
|
||||
* @param mutex associated mutex
|
||||
* @param state initial state of the mutex, either LUMIERA_LOCKED or LUMIERA_UNLOCKED
|
||||
* @return self as given
|
||||
* errors are fatal
|
||||
*/
|
||||
static inline LumieraMutexacquirer
|
||||
lumiera_mutexacquirer_init_mutex (LumieraMutexacquirer self, LumieraMutex mutex, enum lumiera_lockstate state)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (mutex);
|
||||
self->mutex = mutex;
|
||||
self->state = state;
|
||||
if (state == LUMIERA_LOCKED)
|
||||
if (pthread_mutex_lock (&mutex->mutex))
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* lock the mutex.
|
||||
* must not already be locked
|
||||
* @param self mutexacquirer associated with a mutex variable
|
||||
*/
|
||||
static inline void
|
||||
lumiera_mutexacquirer_lock (LumieraMutexacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
|
||||
|
||||
if (pthread_mutex_lock (&self->mutex->mutex))
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
|
||||
self->state = LUMIERA_LOCKED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get the state of a lock.
|
||||
* @param self mutexacquirer associated with a mutex variable
|
||||
* @return LUMIERA_LOCKED when the mutex is locked by this thead
|
||||
*/
|
||||
static inline enum lumiera_lockstate
|
||||
lumiera_mutexacquirer_state (LumieraMutexacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
return self->state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* try to lock a mutex.
|
||||
* must not already be locked
|
||||
* @param self mutexacquirer associated with a mutex variable
|
||||
* @param mutex pointer to a mutex which should be tried
|
||||
* @return LUMIERA_LOCKED when the mutex got locked
|
||||
*/
|
||||
static inline enum lumiera_lockstate
|
||||
lumiera_mutexacquirer_try_mutex (LumieraMutexacquirer self, LumieraMutex mutex)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
|
||||
|
||||
self->mutex=mutex;
|
||||
switch (pthread_mutex_trylock (&self->mutex->mutex))
|
||||
{
|
||||
case 0:
|
||||
return self->state = LUMIERA_LOCKED;
|
||||
case EBUSY:
|
||||
return LUMIERA_UNLOCKED;
|
||||
default:
|
||||
LUMIERA_DIE (MUTEX_LOCK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* release mutex.
|
||||
* a mutexacquirer must be unlocked before leaving scope
|
||||
* @param self mutexacquirer associated with a mutex variable
|
||||
*/
|
||||
static inline void
|
||||
lumiera_mutexacquirer_unlock (LumieraMutexacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
|
||||
if (pthread_mutex_unlock (&self->mutex->mutex))
|
||||
LUMIERA_DIE (MUTEX_UNLOCK);
|
||||
self->state = LUMIERA_UNLOCKED;
|
||||
ENSURE (!self->mutex, "forgot to unlock mutex");
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -111,10 +111,6 @@ lumiera_plugin_name_cmp (const void* a, const void* b)
|
|||
return strcmp (((struct lumiera_plugin*) a)->name, ((struct lumiera_plugin*) b)->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the plugin system.
|
||||
* always succeeds or aborts
|
||||
*/
|
||||
void
|
||||
lumiera_init_plugin (void)
|
||||
{
|
||||
|
|
@ -173,17 +169,6 @@ lumiera_plugin_lookup (struct lumiera_plugin* self, const char* path)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make an interface available.
|
||||
* To use an interface provided by a plugin it must be opened first. It is allowed to open an interface
|
||||
* more than once. Each open must be paired with a close.
|
||||
* @param name name of the plugin to use.
|
||||
* @param interface name of the interface to open.
|
||||
* @param min_revision the size of the interface structure is used as measure of a minimal required
|
||||
* revision (new functions are appended at the end)
|
||||
* @return handle to the interface or NULL in case of a error. The application shall cast this handle to
|
||||
* the actual interface type.
|
||||
*/
|
||||
struct lumiera_interface*
|
||||
lumiera_interface_open (const char* name, const char* interface, size_t min_revision)
|
||||
{
|
||||
|
|
@ -311,11 +296,6 @@ lumiera_interface_open (const char* name, const char* interface, size_t min_revi
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close an interface. Does not free associated resources
|
||||
* Calling this function with self==NULL is legal. Every interface handle must be closed only once.
|
||||
* @param ptr interface to be closed
|
||||
*/
|
||||
void
|
||||
lumiera_interface_close (void* ptr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -96,14 +96,34 @@ struct lumiera_interface
|
|||
int (*close)(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the plugin system.
|
||||
* always succeeds or aborts
|
||||
*/
|
||||
void
|
||||
lumiera_init_plugin (void);
|
||||
|
||||
|
||||
/**
|
||||
* Make an interface available.
|
||||
* To use an interface provided by a plugin it must be opened first. It is allowed to open an interface
|
||||
* more than once. Each open must be paired with a close.
|
||||
* @param name name of the plugin to use.
|
||||
* @param interface name of the interface to open.
|
||||
* @param min_revision the size of the interface structure is used as measure of a minimal required
|
||||
* revision (new functions are appended at the end)
|
||||
* @return handle to the interface or NULL in case of a error. The application shall cast this handle to
|
||||
* the actual interface type.
|
||||
*/
|
||||
struct lumiera_interface*
|
||||
lumiera_interface_open (const char* plugin, const char* name, size_t min_revision);
|
||||
|
||||
|
||||
/**
|
||||
* Close an interface. Does not free associated resources
|
||||
* Calling this function with self==NULL is legal. Every interface handle must be closed only once.
|
||||
* @param ptr interface to be closed
|
||||
*/
|
||||
void
|
||||
lumiera_interface_close (void* self);
|
||||
|
||||
|
|
|
|||
522
src/lib/psplay.c
Normal file
522
src/lib/psplay.c
Normal file
|
|
@ -0,0 +1,522 @@
|
|||
/*
|
||||
psplay.c - probabilistic splay tree
|
||||
|
||||
Copyright (C)
|
||||
2004, 2005, 2006, Christian Thaeter <chth@gmx.net>
|
||||
Copyright (C) CinelerraCV
|
||||
2007, 2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "lib/psplay.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <nobug.h>
|
||||
|
||||
NOBUG_DEFINE_FLAG (psplay);
|
||||
|
||||
#ifndef PSPLAY_TRAIL_DEPTH
|
||||
#define PSPLAY_TRAIL_DEPTH 128
|
||||
#endif
|
||||
|
||||
/*
|
||||
probabilistic distribution, this are the direct splay equations used to determine if to splay
|
||||
or break out of the splaying algorithm.
|
||||
|
||||
useable variables/functions are:
|
||||
self->log2 - log2 of the tree elements, this would be the depth of a fully balanced tree
|
||||
splayfactor - user defined weigth for splaying, we define '100' to be the default
|
||||
depth - depth of the current node in the tree
|
||||
trail->dir - dervitation from tree center
|
||||
psplay_fast_prng () - returns a prng in the range 1...2^31
|
||||
*/
|
||||
|
||||
#define PSPLAY_FORMULA (self->log2*100/(depth + (psplay_fast_prng () & 63)) + trail->dir) * splayfactor
|
||||
|
||||
#ifndef PSPLAY_PROB_ZIGZIG
|
||||
#define PSPLAY_PROB_ZIGZIG 5000
|
||||
#endif
|
||||
#ifndef PSPLAY_PROB_ZIGZAG
|
||||
#define PSPLAY_PROB_ZIGZAG 2500
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* simple prng with 2^31-1 cycle */
|
||||
static inline uint32_t psplay_fast_prng ()
|
||||
{
|
||||
static uint32_t rnd=0xbabeface;
|
||||
return rnd = rnd<<1 ^ ((rnd >> 30) & 1) ^ ((rnd>>2) & 1);
|
||||
}
|
||||
|
||||
|
||||
PSplay
|
||||
psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete)
|
||||
{
|
||||
NOBUG_INIT_FLAG (psplay);
|
||||
TRACE (psplay);
|
||||
REQUIRE (cmp);
|
||||
REQUIRE (key);
|
||||
|
||||
if (self)
|
||||
{
|
||||
self->tree = NULL;
|
||||
self->found_parent = &self->tree;
|
||||
self->cmp = cmp;
|
||||
self->key = key;
|
||||
self->delete = delete;
|
||||
self->elem_cnt = 0;
|
||||
self->log2 = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
PSplay
|
||||
psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete)
|
||||
{
|
||||
PSplay self = malloc (sizeof *self);
|
||||
if (self)
|
||||
{
|
||||
psplay_init (self , cmp, key, delete);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSplay
|
||||
psplay_destroy (PSplay self)
|
||||
{
|
||||
TRACE (psplay);
|
||||
if (self) while (self->tree)
|
||||
{
|
||||
PSplaynode n = psplay_remove (self, self->tree);
|
||||
if (self->delete)
|
||||
self->delete (n);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
psplay_delete (PSplay self)
|
||||
{
|
||||
free (psplay_destroy (self));
|
||||
}
|
||||
|
||||
|
||||
PSplaynode
|
||||
psplaynode_init (PSplaynode self)
|
||||
{
|
||||
if (self)
|
||||
self->left = self->right = NULL;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Lookup operations (lookup and insert) record the path as they decend into the tree
|
||||
this will allow bottom up splaying without storing 'up' pointers in the node.
|
||||
The length of this trail (PSPLAY_TRAIL_DEPTH) also define the maximal limit on how much
|
||||
a node can be splayed up giving some hard bound for the splay operation.
|
||||
|
||||
General wisdom tells that top down splaying is more efficent to implement than bottom
|
||||
up splaying. Nevertheless we do bottom up splaying here because we can decide
|
||||
randomly on each level if we want to continue splaying or not. No splaying
|
||||
is certainly more efficent than top-down splaying.
|
||||
*/
|
||||
struct psplaytrail
|
||||
{
|
||||
int dir;
|
||||
unsigned depth;
|
||||
PSplaynode* trail[PSPLAY_TRAIL_DEPTH];
|
||||
};
|
||||
|
||||
static inline unsigned
|
||||
trailidx (unsigned n)
|
||||
{
|
||||
return n & (PSPLAY_TRAIL_DEPTH-1);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor)
|
||||
{
|
||||
TRACE (psplay, "%p %u", self, splayfactor);
|
||||
|
||||
if (trail->dir < 0) trail->dir = - trail->dir;
|
||||
|
||||
for (unsigned lim = PSPLAY_TRAIL_DEPTH, depth = trail->depth; lim > 2 && depth > 2; lim-=2, depth-=2)
|
||||
{
|
||||
PSplaynode node = *trail->trail [trailidx (depth)];
|
||||
PSplaynode parent = *trail->trail [trailidx (depth-1)];
|
||||
PSplaynode grandparent = *trail->trail [trailidx (depth-2)];
|
||||
|
||||
unsigned r = PSPLAY_FORMULA;
|
||||
TRACE (psplay, "r is %u", r);
|
||||
|
||||
if (parent == grandparent->left)
|
||||
{
|
||||
TRACE (psplay, "ZIG..");
|
||||
if (node == parent->left)
|
||||
{
|
||||
TRACE (psplay, "..ZIG");
|
||||
if (r < PSPLAY_PROB_ZIGZIG)
|
||||
{
|
||||
TRACE (psplay, "BREAK");
|
||||
return;
|
||||
}
|
||||
|
||||
grandparent->left = parent->right;
|
||||
parent->right = grandparent;
|
||||
|
||||
parent->left = node->right;
|
||||
node->right = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE (psplay, "..ZAG");
|
||||
if (r < PSPLAY_PROB_ZIGZAG)
|
||||
{
|
||||
TRACE (psplay, "BREAK");
|
||||
return;
|
||||
}
|
||||
|
||||
parent->right = node->left;
|
||||
node->left = parent;
|
||||
|
||||
grandparent->left = node->right;
|
||||
node->right = grandparent;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE (psplay, "ZAG..");
|
||||
if (node == parent->left)
|
||||
{
|
||||
TRACE (psplay, "..ZIG");
|
||||
if (r < PSPLAY_PROB_ZIGZAG)
|
||||
{
|
||||
TRACE (psplay, "BREAK");
|
||||
return;
|
||||
}
|
||||
|
||||
parent->left = node->right;
|
||||
node->right = parent;
|
||||
|
||||
grandparent->right = node->left;
|
||||
node->left = grandparent;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE (psplay, "..ZAG");
|
||||
if (r < PSPLAY_PROB_ZIGZIG)
|
||||
{
|
||||
TRACE (psplay, "BREAK");
|
||||
return;
|
||||
}
|
||||
|
||||
grandparent->right = parent->left;
|
||||
parent->left = grandparent;
|
||||
|
||||
parent->right = node->left;
|
||||
node->left = parent;
|
||||
}
|
||||
}
|
||||
*trail->trail [trailidx (depth-2)] = node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PSplaynode
|
||||
psplay_insert (PSplay self, PSplaynode node, int splayfactor)
|
||||
{
|
||||
TRACE (psplay);
|
||||
PSplaynode n = self->tree;
|
||||
struct psplaytrail trail;
|
||||
|
||||
trail.dir = 0;
|
||||
trail.depth = 0;
|
||||
trail.trail [0] = &self->tree;
|
||||
|
||||
if (!n)
|
||||
self->tree = node;
|
||||
else
|
||||
{
|
||||
while (n != node)
|
||||
{
|
||||
int c;
|
||||
c = self->cmp (self->key (node), self->key (n));
|
||||
++trail.depth;
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
--trail.dir;
|
||||
if (!n->left)
|
||||
n->left = node;
|
||||
trail.trail [trailidx (trail.depth)] = &n->left;
|
||||
n = n->left;
|
||||
}
|
||||
else if (c > 0)
|
||||
{
|
||||
++trail.dir;
|
||||
if (!n->right)
|
||||
n->right = node;
|
||||
trail.trail [trailidx (trail.depth)] = &n->right;
|
||||
n = n->right;
|
||||
}
|
||||
else
|
||||
{
|
||||
TODO ("policy for multiple entered items (before, after, fail, replace)");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
++self->elem_cnt;
|
||||
if (self->elem_cnt >= 1<<self->log2) ++self->log2;
|
||||
if (splayfactor && trail.depth > 2)
|
||||
psplay_splay (self, &trail, splayfactor);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PSplaynode
|
||||
psplay_find (PSplay self, const void* key, int splayfactor)
|
||||
{
|
||||
TRACE (psplay);
|
||||
PSplaynode node = self->tree;
|
||||
struct psplaytrail trail;
|
||||
trail.dir = 0;
|
||||
trail.depth = 0;
|
||||
trail.trail [0] = &self->tree;
|
||||
|
||||
while (node)
|
||||
{
|
||||
int c;
|
||||
c = self->cmp (key, self->key (node));
|
||||
++trail.depth;
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
--trail.dir;
|
||||
trail.trail [trailidx (trail.depth)] = &node->left;
|
||||
node = node->left;
|
||||
}
|
||||
else if (c > 0)
|
||||
{
|
||||
++trail.dir;
|
||||
trail.trail [trailidx (trail.depth)] = &node->right;
|
||||
node = node->right;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->found_parent = trail.trail [trailidx (--trail.depth)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (node && splayfactor && trail.depth > 2)
|
||||
psplay_splay (self, &trail, splayfactor);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
PSplaynode
|
||||
psplay_remove (PSplay self, PSplaynode node)
|
||||
{
|
||||
TRACE (psplay);
|
||||
if (!node) return NULL;
|
||||
|
||||
PSplaynode* r = self->found_parent;
|
||||
|
||||
while (*r != node)
|
||||
{
|
||||
if (!psplay_find (self, self->key (node), 0))
|
||||
{
|
||||
WARN (psplay, "node %p is not in splay tree %p", node, self);
|
||||
return NULL;
|
||||
}
|
||||
r = self->found_parent;
|
||||
}
|
||||
|
||||
if (!node->left)
|
||||
*r = node->right;
|
||||
else if (!node->right)
|
||||
*r = node->left;
|
||||
else
|
||||
{
|
||||
PSplaynode i, iparent = NULL;
|
||||
if (psplay_fast_prng()&1) /* 50% probability removing left or right wards */
|
||||
{
|
||||
for (i = node->left; i->right; iparent = i, i = i->right);
|
||||
if (iparent)
|
||||
iparent->right = i->left;
|
||||
if (node->left != i)
|
||||
i->left = node->left;
|
||||
i->right = node->right;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = node->right; i->left; iparent = i, i = i->left);
|
||||
if (iparent)
|
||||
iparent->left = i->right;
|
||||
if (node->right != i)
|
||||
i->right = node->right;
|
||||
i->left = node->left;
|
||||
}
|
||||
*r = i;
|
||||
}
|
||||
--self->elem_cnt;
|
||||
if (self->elem_cnt < 1<<self->log2) --self->log2;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
PSplaynode
|
||||
psplay_remove_key (PSplay self, void* key)
|
||||
{
|
||||
return psplay_remove (self, psplay_find (self, key, 0));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
psplay_delete_node (PSplay self, PSplaynode node)
|
||||
{
|
||||
if (node)
|
||||
self->delete (psplay_remove (self, node));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
psplay_delete_key (PSplay self, void* key)
|
||||
{
|
||||
PSplaynode node = psplay_find (self, key, 0);
|
||||
psplay_delete_node (self, node);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const psplay_delete_fn PSPLAY_CONT = (psplay_delete_fn)0x0;
|
||||
const psplay_delete_fn PSPLAY_STOP = (psplay_delete_fn)0x1;
|
||||
const psplay_delete_fn PSPLAY_REMOVE = (psplay_delete_fn)0x2;
|
||||
|
||||
static int
|
||||
psplay_handle (PSplay self, PSplaynode node, psplay_delete_fn res)
|
||||
{
|
||||
if (res == PSPLAY_CONT)
|
||||
return 1;
|
||||
|
||||
if (res == PSPLAY_STOP)
|
||||
;
|
||||
else if (res == PSPLAY_REMOVE)
|
||||
{
|
||||
psplay_remove (self, node);
|
||||
if (self->delete)
|
||||
self->delete (node);
|
||||
}
|
||||
else
|
||||
{
|
||||
psplay_remove (self, node);
|
||||
res (node);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data)
|
||||
{
|
||||
if (!self->tree)
|
||||
return 1;
|
||||
|
||||
if (!node)
|
||||
node = self->tree;
|
||||
|
||||
psplay_delete_fn res;
|
||||
|
||||
res = action (node, PSPLAY_PREORDER, level, data);
|
||||
if (!psplay_handle (self, node, res))
|
||||
return 0;
|
||||
|
||||
if (node->left)
|
||||
if (!psplay_walk (self, node->left, action, level+1, data))
|
||||
return 0;
|
||||
|
||||
res = action (node, PSPLAY_INORDER, level, data);
|
||||
if (!psplay_handle (self, node, res))
|
||||
return 0;
|
||||
|
||||
if (node->right)
|
||||
if (!psplay_walk (self, node->right, action, level+1, data))
|
||||
return 0;
|
||||
|
||||
res = action (node, PSPLAY_POSTORDER, level, data);
|
||||
if (!psplay_handle (self, node, res))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static psplay_delete_fn
|
||||
psplay_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
|
||||
{
|
||||
FILE* fh = data;
|
||||
static char* sp = " ";
|
||||
if (level>40)
|
||||
{
|
||||
if (which == PSPLAY_PREORDER)
|
||||
fprintf (fh, "%s ...\n", sp);
|
||||
return PSPLAY_CONT;
|
||||
}
|
||||
|
||||
switch (which)
|
||||
{
|
||||
case PSPLAY_PREORDER:
|
||||
fprintf (fh, "%s%p\n", sp+40-level, node);
|
||||
if (node->left)
|
||||
fprintf (fh, "%sleft %p\n", sp+40-level, node->left);
|
||||
break;
|
||||
case PSPLAY_INORDER:
|
||||
if (node->right)
|
||||
fprintf (fh, "%sright %p\n", sp+40-level, node->right);
|
||||
break;
|
||||
case PSPLAY_POSTORDER:
|
||||
break;
|
||||
}
|
||||
|
||||
return PSPLAY_CONT;
|
||||
}
|
||||
|
||||
void
|
||||
psplay_dump (PSplay self, FILE* dest)
|
||||
{
|
||||
fprintf (dest, "root %p\n", self->tree);
|
||||
psplay_walk (self, NULL, psplay_print_node, 0, dest);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
292
src/lib/psplay.h
Normal file
292
src/lib/psplay.h
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
psplay.h - probabilistic splay tree
|
||||
|
||||
Copyright (C)
|
||||
2004, 2005, 2006, Christian Thaeter <chth@gmx.net>
|
||||
Copyright (C) Lumiera.org
|
||||
2007, 2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PSPLAY_H
|
||||
#define PSPLAY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Probabilistic splay trees
|
||||
* A splay trees is self-optimizing (in contrast to self-balancing) datastructure.
|
||||
* We introduce here a probabilistic bottom up approach which reduces the splay costs.
|
||||
* Without affecting the performance. The randomization gives also some insurance that
|
||||
* worst case situations are extremely unlikely.
|
||||
* Tree nodes are very small (just 2 pointers) and are intrusively placed into the users
|
||||
* datastructure.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Type and handle for a psplay tree node
|
||||
* This node have to be placed inside users data.
|
||||
*/
|
||||
typedef struct psplaynode_struct psplaynode;
|
||||
typedef psplaynode* PSplaynode;
|
||||
struct psplaynode_struct
|
||||
{
|
||||
PSplaynode left;
|
||||
PSplaynode right;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function use to compare keys
|
||||
* @param a first key
|
||||
* @param b second key
|
||||
* @return shall return -1/0/1 when a is less than/equal to/biggier than b.
|
||||
*/
|
||||
typedef int (*psplay_cmp_fn)(const void* a, const void* b);
|
||||
|
||||
|
||||
/**
|
||||
* Destructor for user defined data
|
||||
* Called when an element got removed from a splay tree.
|
||||
* @param node pointer to the intrusive node inside the users datastructure
|
||||
* The user is responsible for casting 'node' back to his real datastructure (maybe with OFFSET_OF()),
|
||||
* free all resources associated with it and finally free the datastructure itself.
|
||||
*/
|
||||
typedef void (*psplay_delete_fn)(PSplaynode node);
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the key from a user datastructure
|
||||
* @param node pointer to the intrusive node inside the users datastructure
|
||||
* This functiom must return a pointer to the key under which the user stores his data.
|
||||
*/
|
||||
typedef const void* (*psplay_key_fn)(const PSplaynode node);
|
||||
|
||||
|
||||
/**
|
||||
* Type and handle for a psplay root structure
|
||||
* This structure shall be treated opaque, its only defined in the header to allow
|
||||
* one to integrate it directly instead referencing it.
|
||||
*/
|
||||
typedef struct psplay_struct psplay;
|
||||
typedef psplay* PSplay;
|
||||
|
||||
struct psplay_struct
|
||||
{
|
||||
PSplaynode tree; /* the tree */
|
||||
PSplaynode* found_parent; /* maybe direct parent of last found node, used for fast remove */
|
||||
psplay_cmp_fn cmp;
|
||||
psplay_key_fn key;
|
||||
psplay_delete_fn delete;
|
||||
|
||||
size_t elem_cnt;
|
||||
unsigned log2; /* roughly log2 of the elem_cnt*/
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Number of elements in tree
|
||||
* @param self pointer to the tree
|
||||
* @return number of elements
|
||||
*/
|
||||
static inline size_t
|
||||
psplay_nelements (PSplay self)
|
||||
{
|
||||
return self->elem_cnt;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a splay tree
|
||||
* @param self pointer to the psplay structure
|
||||
* @param cmp user supplied compare function
|
||||
* @param key user supplied function to retrieve a key
|
||||
* @param delete user supplied destructor function or NULL if no destructor is necessary
|
||||
* @return self
|
||||
*/
|
||||
PSplay
|
||||
psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete);
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a splay tree
|
||||
* Frees all elements and associated resources of a splay tree
|
||||
* @param self pointer to the psplay structure
|
||||
* @return self
|
||||
*/
|
||||
PSplay
|
||||
psplay_destroy (PSplay self);
|
||||
|
||||
/**
|
||||
* Allocate a splay tree
|
||||
* @param cmp user supplied compare function
|
||||
* @param key user supplied function to retrieve a key
|
||||
* @param delete user supplied destructor function or NULL if no destructor is necessary
|
||||
* @return allcoated splay tree or NULL on error
|
||||
*/
|
||||
PSplay
|
||||
psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete);
|
||||
|
||||
|
||||
/**
|
||||
* Delete a splay tree
|
||||
* Frees all elements and associated resources of a splay tree and then itseld
|
||||
* @param self pointer to the psplay structure
|
||||
*/
|
||||
void
|
||||
psplay_delete (PSplay self);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a splay tree node
|
||||
* The user has to place this nodes within his datastructure and must
|
||||
* initialize them before using them.
|
||||
* @param self pointer to the node to be initialized
|
||||
* @return self
|
||||
*/
|
||||
PSplaynode
|
||||
psplaynode_init (PSplaynode self);
|
||||
|
||||
|
||||
/**
|
||||
* Insert a element into a splay tree
|
||||
* @param self pointer to the splay tree
|
||||
* @param node pointer to the node to be inserted
|
||||
* @param splayfactor weight for the probabilistic splaying,
|
||||
* 0 disables the splaying, 100 is the expected normal value
|
||||
* use 100 when in doubt
|
||||
* @return self or NULL when a node with same key already in the tree
|
||||
*/
|
||||
PSplaynode
|
||||
psplay_insert (PSplay self, PSplaynode node, int splayfactor);
|
||||
|
||||
|
||||
/**
|
||||
* Find a element in a splay tree
|
||||
* @param self pointer to the splay tree
|
||||
* @param key pointer to the key to be searched
|
||||
* @param splayfactor weight for the probabilistic splaying,
|
||||
* 0 disables the splaying, 100 is the expected normal value
|
||||
* @return found node or NULL if the key was not found in the tree
|
||||
*/
|
||||
PSplaynode
|
||||
psplay_find (PSplay self, const void* key, int splayfactor);
|
||||
|
||||
|
||||
/**
|
||||
* Remove a node from a splay tree
|
||||
* @param self pointer to the splay tree
|
||||
* @param node node to be removed
|
||||
* @return pointer to the removed node
|
||||
* removal is optimized for the case where one call it immediately after one did a
|
||||
* psplay_find() as last operation on that tree
|
||||
*/
|
||||
PSplaynode
|
||||
psplay_remove (PSplay self, PSplaynode node);
|
||||
|
||||
|
||||
/**
|
||||
* Remove a node by key from a splay tree
|
||||
* @param self pointer to the splay tree
|
||||
* @param key key of the node to be removed
|
||||
* @return pointer to the removed node
|
||||
*/
|
||||
PSplaynode
|
||||
psplay_remove_key (PSplay self, void* key);
|
||||
|
||||
|
||||
/**
|
||||
* Delete a node from a splay tree
|
||||
* @param self pointer to the splay tree
|
||||
* @param node node to be removed
|
||||
* Calls the registered delete handler, frees all resources.
|
||||
*/
|
||||
void
|
||||
psplay_delete_node (PSplay self, PSplaynode node);
|
||||
|
||||
|
||||
/**
|
||||
* Delete a node by key from a splay tree
|
||||
* @param self pointer to the splay tree
|
||||
* @param key key of the node to be removed
|
||||
* Calls the registered delete handler, frees all resources.
|
||||
*/
|
||||
void
|
||||
psplay_delete_key (PSplay self, void* key);
|
||||
|
||||
|
||||
enum psplay_order_enum
|
||||
{
|
||||
PSPLAY_PREORDER,
|
||||
PSPLAY_INORDER,
|
||||
PSPLAY_POSTORDER
|
||||
};
|
||||
|
||||
/**
|
||||
* Traverse a splay tree
|
||||
* Traversing a tree calls a user supplied action three times
|
||||
* An 'action' must not alter the tree itself but it can indicate aborting the tree traversal and
|
||||
* how the current node is handled by its return value.
|
||||
* @param node pointer to the currently traversed node
|
||||
* @param which state of the traversal:
|
||||
* PSPLAY_PREORDER before visiting the left subtree,
|
||||
* PSPLAY_INORDER after visiting the left subtree and before the right subtree
|
||||
* PSPLAY_POSTORDER finally after visiting the right subtree.
|
||||
* Example: For to traverse the tree in order action would only handle PSPLAY_INORDER.
|
||||
* This action shall return PSPLAY_CONT when the traversal of the tree shall continue.
|
||||
* @param level depth of the node in the tree
|
||||
* @param data user supplied data which is transparently passed around
|
||||
* @return a pointer to a function which indicates how to proceed, there are three special
|
||||
* return values predefined:
|
||||
* PSPLAY_CONT - continue with the traversal
|
||||
* PSPLAY_STOP - stop the traversal
|
||||
* PSPLAY_REMOVE - stops the traversal and removes the current node, calling the delete handler
|
||||
* any other psplay_delete_fn - stops the traversal and removes the current node, calling the returned delete handler with it
|
||||
*/
|
||||
typedef psplay_delete_fn (*psplay_action_fn)(PSplaynode node, const enum psplay_order_enum which, int level, void* data);
|
||||
|
||||
extern const psplay_delete_fn PSPLAY_CONT;
|
||||
extern const psplay_delete_fn PSPLAY_STOP;
|
||||
extern const psplay_delete_fn PSPLAY_REMOVE;
|
||||
|
||||
/**
|
||||
* Start a tree traversal
|
||||
* @param self the tree to be traversed
|
||||
* @param node pointer to root node where traversal shall start, use NULL for the whole tree
|
||||
* @param action handler function as defined above
|
||||
* @param level initial value for the level
|
||||
* @param data user supplied data which is transparently passed to the action
|
||||
* @return 0 when the tree traversal got aborted (by anything but PSPLAY_CONT as action handler return)
|
||||
* 1 when the whole tree was traversed successfully
|
||||
*/
|
||||
int
|
||||
psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data);
|
||||
|
||||
|
||||
void
|
||||
psplay_dump (PSplay self, FILE* dest);
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
/*
|
||||
references.c - strong and weak references
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include "lib/references.h"
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Strong and Weak references
|
||||
* Strong references keep some object alive while they existing
|
||||
* Weak references become invalidated when the referenced object gets destroyed
|
||||
*
|
||||
* Thread safety: references protect their internal operations with a mutex (optimization using futex may come in future)
|
||||
* while operations on the reference itself (initialization, destruction, strengthen, weaken) and on the referenced object (get)
|
||||
* should be protected from elsewhere.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Construct an initial strong reference from an object.
|
||||
* For every object which should be managed with references you need to construct an initial strong reference
|
||||
* which then will be used to initialize all further references.
|
||||
* @param self pointer to the reference to be initialized
|
||||
* @param obj pointer to the object being referenced
|
||||
* @param dtor destructor function which will be called on obj when the last strong reference gets deleted
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraReference
|
||||
lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*))
|
||||
{
|
||||
LumieraReftarget target = lumiera_malloc (sizeof(lumiera_reftarget));
|
||||
|
||||
target->object = obj;
|
||||
target->dtor = dtor;
|
||||
target->strong_cnt = 1;
|
||||
target->weak_cnt = 0;
|
||||
lumiera_mutex_init (&target->lock);
|
||||
|
||||
self->object = obj;
|
||||
self->target = target;
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a reference.
|
||||
* All references need to be destroyed when not used any more.
|
||||
* When the last strong reference gets destroyed, the object's destructor is called.
|
||||
* Remaining weak references stay invalidated then until they get destroyed too.
|
||||
* @param self reference to be destroyed
|
||||
* @return self as given
|
||||
* destroying a reference is not thread safe as far as 2 threads try to concurrently destroy it!
|
||||
*/
|
||||
LumieraReference
|
||||
lumiera_reference_destroy (LumieraReference self)
|
||||
{
|
||||
LumieraReftarget target = self->target;
|
||||
|
||||
/* defensive, lets detect errors if anything still tries to use this reference */
|
||||
self->target = NULL;
|
||||
|
||||
lumiera_mutexacquirer lock;
|
||||
lumiera_mutexacquirer_init_mutex (&lock, &target->lock, LUMIERA_LOCKED);
|
||||
|
||||
if (self->object)
|
||||
{
|
||||
/* strong reference */
|
||||
if (!--target->strong_cnt)
|
||||
{
|
||||
/* was last strong reference */
|
||||
if (target->dtor)
|
||||
target->dtor (target->object);
|
||||
target->object = NULL;
|
||||
if (!target->weak_cnt)
|
||||
{
|
||||
/* no weak refs either, destroy it */
|
||||
lumiera_mutexacquirer_unlock (&lock);
|
||||
lumiera_mutex_destroy (&target->lock);
|
||||
free (target);
|
||||
return self;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* weak reference */
|
||||
if (!--target->weak_cnt && !target->strong_cnt)
|
||||
{
|
||||
/* was last weak reference, and no strong refs left */
|
||||
lumiera_mutexacquirer_unlock (&lock);
|
||||
lumiera_mutex_destroy (&target->lock);
|
||||
free (target);
|
||||
return self;
|
||||
}
|
||||
}
|
||||
lumiera_mutexacquirer_unlock (&lock);
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy construct a reference as strong reference
|
||||
* @param source reference to copy
|
||||
* @return self as strong reference (always for strong references) or NULL if source is an invalidated weak reference,
|
||||
* in the later case the reference is constructed as weak reference barely to allow it be destroyed
|
||||
*/
|
||||
LumieraReference
|
||||
lumiera_reference_strong_init (LumieraReference self, LumieraReference source)
|
||||
{
|
||||
lumiera_mutexacquirer lock;
|
||||
lumiera_mutexacquirer_init_mutex (&lock, &source->target->lock, LUMIERA_LOCKED);
|
||||
|
||||
self->object = source->target->object;
|
||||
self->target = source->target;
|
||||
|
||||
if (self->object)
|
||||
{
|
||||
++self->target->strong_cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
++self->target->weak_cnt;
|
||||
self = NULL;
|
||||
}
|
||||
lumiera_mutexacquirer_unlock (&lock);
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy construct a reference as weak reference
|
||||
* @param source reference to copy
|
||||
* @return self (always for strong references) or NULL if self is an invalidated weak reference
|
||||
*/
|
||||
LumieraReference
|
||||
lumiera_reference_weak_init (LumieraReference self, LumieraReference source)
|
||||
{
|
||||
lumiera_mutexacquirer lock;
|
||||
lumiera_mutexacquirer_init_mutex (&lock, &source->target->lock, LUMIERA_LOCKED);
|
||||
|
||||
self->object = NULL;
|
||||
self->target = source->target;
|
||||
|
||||
++self->target->weak_cnt;
|
||||
if (!self->target->object)
|
||||
/* already invalidated */
|
||||
self = NULL;
|
||||
|
||||
lumiera_mutexacquirer_unlock (&lock);
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* turn a (strong) reference into a weak reference
|
||||
* Weaken a reference may remove its last strong reference and thus destroy the object
|
||||
* do nothing if the referene is already weak
|
||||
* @return self or NULL if the final strong reference got removed,
|
||||
*/
|
||||
LumieraReference
|
||||
lumiera_reference_weaken (restrict LumieraReference self)
|
||||
{
|
||||
/* is this a strong reference? */
|
||||
if (self->object)
|
||||
{
|
||||
lumiera_mutexacquirer lock;
|
||||
lumiera_mutexacquirer_init_mutex (&lock, &self->target->lock, LUMIERA_LOCKED);
|
||||
|
||||
self->object = NULL;
|
||||
++self->target->weak_cnt;
|
||||
if (!--self->target->strong_cnt)
|
||||
{
|
||||
if (self->target->dtor)
|
||||
self->target->dtor (self->target->object);
|
||||
self->target->object = NULL;
|
||||
self = NULL;
|
||||
}
|
||||
lumiera_mutexacquirer_unlock (&lock);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* turn a (weak) reference into a strong reference
|
||||
* only references of object which are not already destroyed can be strengthened
|
||||
* @return self when successful, NULL when the object was already destroyed, 'self' stays a dead weak reference in that case
|
||||
*/
|
||||
LumieraReference
|
||||
lumiera_reference_strengthen (LumieraReference self)
|
||||
{
|
||||
/* is this a weak reference? */
|
||||
if (!self->object)
|
||||
{
|
||||
lumiera_mutexacquirer lock;
|
||||
lumiera_mutexacquirer_init_mutex (&lock, &self->target->lock, LUMIERA_LOCKED);
|
||||
|
||||
if (self->target->object)
|
||||
{
|
||||
self->object = self->target->object;
|
||||
--self->target->weak_cnt;
|
||||
++self->target->strong_cnt;
|
||||
}
|
||||
else
|
||||
self = NULL;
|
||||
lumiera_mutexacquirer_unlock (&lock);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
references.h - strong and weak references
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef LUMIERA_REFERENCES_H
|
||||
#define LUMIERA_REFERENCES_H
|
||||
|
||||
#include <nobug.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Strong and Weak references, header.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct lumiera_reference_struct lumiera_reference;
|
||||
typedef lumiera_reference* LumieraReference;
|
||||
|
||||
#include "lib/error.h"
|
||||
#include "lib/mutex.h"
|
||||
|
||||
/* Implementation detail */
|
||||
struct lumiera_reftarget_struct
|
||||
{
|
||||
void* object;
|
||||
void (*dtor)(void*);
|
||||
unsigned strong_cnt; /*when strong becomes 0 obj is destroyed, if weak is 0 destroy target too*/
|
||||
unsigned weak_cnt; /*when weak becomes 0 and !obj and lock strong is 0, destroy target */
|
||||
lumiera_mutex lock;
|
||||
};
|
||||
typedef struct lumiera_reftarget_struct lumiera_reftarget;
|
||||
typedef lumiera_reftarget* LumieraReftarget;
|
||||
|
||||
|
||||
/**
|
||||
* A reference pointing to some other object
|
||||
*/
|
||||
struct lumiera_reference_struct
|
||||
{
|
||||
void* object; /*set for strong, NULL for weak*/
|
||||
LumieraReftarget target;
|
||||
};
|
||||
|
||||
#define lumiera_reference \
|
||||
lumiera_reference NOBUG_CLEANUP(lumiera_reference_ensuredestroyed)
|
||||
|
||||
/* helper function for nobug */
|
||||
static inline void
|
||||
lumiera_reference_ensuredestroyed (LumieraReference self)
|
||||
{
|
||||
ENSURE (!self->target, "forgot to destroy reference");
|
||||
}
|
||||
|
||||
|
||||
LumieraReference
|
||||
lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*));
|
||||
|
||||
|
||||
LumieraReference
|
||||
lumiera_reference_destroy (LumieraReference self);
|
||||
|
||||
/**
|
||||
* Get object from a strong reference.
|
||||
* @return pointer to object, NULL if applied to a weak reference
|
||||
*/
|
||||
static inline void*
|
||||
lumiera_reference_get (LumieraReference self)
|
||||
{
|
||||
ENSURE (self->target, "illegal reference (not initialized or already destroyed?)");
|
||||
return self->object;
|
||||
}
|
||||
|
||||
|
||||
LumieraReference
|
||||
lumiera_reference_strong_init (LumieraReference self, LumieraReference source);
|
||||
|
||||
|
||||
LumieraReference
|
||||
lumiera_reference_weak_init (LumieraReference self, LumieraReference source);
|
||||
|
||||
|
||||
LumieraReference
|
||||
lumiera_reference_weaken (restrict LumieraReference self);
|
||||
|
||||
|
||||
LumieraReference
|
||||
lumiera_reference_strengthen (LumieraReference self);
|
||||
|
||||
#endif
|
||||
149
src/lib/rwlock.c
149
src/lib/rwlock.c
|
|
@ -18,161 +18,52 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
||||
#include "lib/error.h"
|
||||
#include "lib/rwlock.h"
|
||||
|
||||
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_AGAIN, "maximum number of readlocks exceed");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_DEADLOCK, "deadlock detected");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroy rwlock");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_RLOCK, "rlock");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_WLOCK, "wlock");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroying rwlock");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock rwlock failed");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_RDLOCK, "locking rwlock for reading failed");
|
||||
LUMIERA_ERROR_DEFINE(RWLOCK_WRLOCK, "locking rwlock for writing failed");
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Read/write locks.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a rwlock
|
||||
* @param self is a pointer to the rwlock to be initialized
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraRWLock
|
||||
lumiera_rwlock_init (LumieraRWLock self)
|
||||
lumiera_rwlock_init (LumieraRWLock self, const char* purpose, struct nobug_flag* flag)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
pthread_rwlock_init (&self->rwlock, NULL);
|
||||
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
|
||||
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "rwlock", purpose, self, self->rh);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* destroy a rwlock
|
||||
* @param self is a pointer to the rwlock to be initialized
|
||||
* @return self on success or NULL at error
|
||||
*/
|
||||
|
||||
LumieraRWLock
|
||||
lumiera_rwlock_destroy (LumieraRWLock self)
|
||||
lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag)
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
|
||||
if (pthread_rwlock_destroy (&self->rwlock))
|
||||
LUMIERA_DIE (RWLOCK_DESTROY);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* initialize a rwlockacquirer state
|
||||
* @param self rwlockacquirer to be initialized, must be an automatic variable
|
||||
* @param rwlock associated rwlock
|
||||
* @param state initial state of the mutex, either LUMIERA_RDLOCKED, LUMIERA_WRLOCKED or LUMIERA_UNLOCKED
|
||||
* @return self as given or NULL on error
|
||||
*/
|
||||
LumieraRWLockacquirer
|
||||
lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (rwlock);
|
||||
REQUIRE (state != LUMIERA_LOCKED, "illegal state for rwlock");
|
||||
self->rwlock = rwlock;
|
||||
self->state = state;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case LUMIERA_RDLOCKED:
|
||||
switch (pthread_rwlock_rdlock (&rwlock->rwlock))
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case EAGAIN:
|
||||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN);
|
||||
return NULL;
|
||||
case EDEADLK:
|
||||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
|
||||
return NULL;
|
||||
default:
|
||||
LUMIERA_DIE (RWLOCK_RLOCK);
|
||||
}
|
||||
case LUMIERA_WRLOCKED:
|
||||
switch (pthread_rwlock_wrlock (&rwlock->rwlock))
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case EDEADLK:
|
||||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
|
||||
return NULL;
|
||||
default:
|
||||
LUMIERA_DIE (RWLOCK_WLOCK);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* readlock the rwlock.
|
||||
* must not already be locked
|
||||
* @param self rwlockacquirer associated with a rwlock
|
||||
* @return self as given or NULL on error
|
||||
*/
|
||||
LumieraRWLockacquirer
|
||||
lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked");
|
||||
|
||||
switch (pthread_rwlock_rdlock (&self->rwlock->rwlock))
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case EAGAIN:
|
||||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN);
|
||||
return NULL;
|
||||
case EDEADLK:
|
||||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
|
||||
return NULL;
|
||||
default:
|
||||
LUMIERA_DIE (RWLOCK_RLOCK);
|
||||
}
|
||||
|
||||
self->state = LUMIERA_RDLOCKED;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* writelock the rwlock.
|
||||
* must not already be locked
|
||||
* @param self rwlockacquirer associated with a rwlock
|
||||
* @return self as given or NULL on error
|
||||
*/
|
||||
LumieraRWLockacquirer
|
||||
lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked");
|
||||
|
||||
switch (pthread_rwlock_wrlock (&self->rwlock->rwlock))
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case EDEADLK:
|
||||
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
|
||||
return NULL;
|
||||
default:
|
||||
LUMIERA_DIE (RWLOCK_WLOCK);
|
||||
}
|
||||
|
||||
self->state = LUMIERA_WRLOCKED;
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
116
src/lib/rwlock.h
116
src/lib/rwlock.h
|
|
@ -29,14 +29,12 @@
|
|||
#include <pthread.h>
|
||||
#include <nobug.h>
|
||||
|
||||
#include "lib/locking.h"
|
||||
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_AGAIN);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_DEADLOCK);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_DESTROY);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_UNLOCK);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_RLOCK);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_RDLOCK);
|
||||
LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK);
|
||||
|
||||
/**
|
||||
* @file
|
||||
|
|
@ -44,6 +42,56 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
|
|||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Read locked section.
|
||||
*/
|
||||
#define LUMIERA_RDLOCK_SECTION(nobugflag, rwlck) \
|
||||
for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \
|
||||
lumiera_rwlock_section_.rwlock;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_rwlock_section_.rwlock = (rwlck); \
|
||||
NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \
|
||||
RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \
|
||||
NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \
|
||||
if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_RDLOCK); \
|
||||
}); \
|
||||
lumiera_rwlock_section_.rwlock; \
|
||||
({ \
|
||||
if (lumiera_rwlock_section_.rwlock) \
|
||||
{ \
|
||||
pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \
|
||||
lumiera_rwlock_section_.rwlock = NULL; \
|
||||
RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \
|
||||
} \
|
||||
}))
|
||||
|
||||
|
||||
/**
|
||||
* Write locked section.
|
||||
*/
|
||||
#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \
|
||||
for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \
|
||||
lumiera_rwlock_section_.rwlock;) \
|
||||
for ( \
|
||||
({ \
|
||||
lumiera_rwlock_section_.rwlock = (rwlck); \
|
||||
NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \
|
||||
RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \
|
||||
NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \
|
||||
if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_WRLOCK); \
|
||||
}); \
|
||||
lumiera_rwlock_section_.rwlock; \
|
||||
({ \
|
||||
if (lumiera_rwlock_section_.rwlock) \
|
||||
{ \
|
||||
pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \
|
||||
lumiera_rwlock_section_.rwlock = NULL; \
|
||||
RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \
|
||||
} \
|
||||
}))
|
||||
|
||||
|
||||
/**
|
||||
* RWLock.
|
||||
*
|
||||
|
|
@ -51,17 +99,27 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
|
|||
struct lumiera_rwlock_struct
|
||||
{
|
||||
pthread_rwlock_t rwlock;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_rwlock_struct lumiera_rwlock;
|
||||
typedef lumiera_rwlock* LumieraRWLock;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a rwlock
|
||||
* @param self is a pointer to the rwlock to be initialized
|
||||
* @return self as given
|
||||
*/
|
||||
LumieraRWLock
|
||||
lumiera_rwlock_init (LumieraRWLock self);
|
||||
|
||||
lumiera_rwlock_init (LumieraRWLock self, const char* purpose, struct nobug_flag* flag);
|
||||
|
||||
/**
|
||||
* destroy a rwlock
|
||||
* @param self is a pointer to the rwlock to be initialized
|
||||
* @return self on success or NULL at error
|
||||
*/
|
||||
LumieraRWLock
|
||||
lumiera_rwlock_destroy (LumieraRWLock self);
|
||||
lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -72,7 +130,7 @@ lumiera_rwlock_destroy (LumieraRWLock self);
|
|||
struct lumiera_rwlockacquirer_struct
|
||||
{
|
||||
LumieraRWLock rwlock;
|
||||
enum lumiera_lockstate state;
|
||||
RESOURCE_HANDLE (rh);
|
||||
};
|
||||
typedef struct lumiera_rwlockacquirer_struct lumiera_rwlockacquirer;
|
||||
typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer;
|
||||
|
|
@ -81,39 +139,15 @@ typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer;
|
|||
static inline void
|
||||
lumiera_rwlockacquirer_ensureunlocked (LumieraRWLockacquirer self)
|
||||
{
|
||||
ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the rwlock mutex");
|
||||
}
|
||||
|
||||
/* override with a macro to use the cleanup checker */
|
||||
#define lumiera_rwlockacquirer \
|
||||
lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked)
|
||||
|
||||
|
||||
LumieraRWLockacquirer
|
||||
lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state);
|
||||
|
||||
LumieraRWLockacquirer
|
||||
lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self);
|
||||
|
||||
|
||||
LumieraRWLockacquirer
|
||||
lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self);
|
||||
|
||||
|
||||
/**
|
||||
* release rwlock.
|
||||
* a rwlockacquirer must be unlocked before leaving scope
|
||||
* @param self rwlockacquirer associated with a rwlock variable
|
||||
*/
|
||||
static inline void
|
||||
lumiera_rwlockacquirer_unlock (LumieraRWLockacquirer self)
|
||||
{
|
||||
REQUIRE (self);
|
||||
REQUIRE (self->state != LUMIERA_UNLOCKED, "rwlock was not locked");
|
||||
if (pthread_rwlock_unlock (&self->rwlock->rwlock))
|
||||
LUMIERA_DIE (RWLOCK_UNLOCK);
|
||||
self->state = LUMIERA_UNLOCKED;
|
||||
ENSURE (!self->rwlock, "forgot to unlock rwlock");
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -18,27 +18,19 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include "error.h"
|
||||
#include "lib/error.h"
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <nobug.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Portable and safe wrapers around some clib functions and some tools
|
||||
*/
|
||||
|
||||
LUMIERA_ERROR_DEFINE (NO_MEMORY, "Out of Memory!");
|
||||
|
||||
/**
|
||||
* Allocate memory.
|
||||
* always succeeds or dies
|
||||
* @param size memory to be allocated
|
||||
* @return pointer to the allocated memory
|
||||
*/
|
||||
void*
|
||||
lumiera_malloc (size_t size)
|
||||
{
|
||||
|
|
@ -49,13 +41,6 @@ lumiera_malloc (size_t size)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocate cleared memory for an array.
|
||||
* always succeeds or dies
|
||||
* @param n number of elements
|
||||
* @param size memory to be allocated
|
||||
* @return pointer to the allocated memory
|
||||
*/
|
||||
void*
|
||||
lumiera_calloc (size_t n, size_t size)
|
||||
{
|
||||
|
|
@ -66,13 +51,6 @@ lumiera_calloc (size_t n, size_t size)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Duplicate a C string.
|
||||
* always succeeds or dies
|
||||
* @param str string to be copied
|
||||
* @param len maximal length to be copied
|
||||
* @return pointer to the new string, "" if NULL was passed as str
|
||||
*/
|
||||
char*
|
||||
lumiera_strndup (const char* str, size_t len)
|
||||
{
|
||||
|
|
@ -88,14 +66,6 @@ lumiera_strndup (const char* str, size_t len)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare two C strings.
|
||||
* Handles NULL pointers as "", shortcut for same addresses
|
||||
* @param a first string for comparsion
|
||||
* @param b second string for comparsion
|
||||
* @param len maximal length for the comparsion
|
||||
* @return 0 if the strings are identical, -1 if smaller 1 if bigger.
|
||||
*/
|
||||
int
|
||||
lumiera_strncmp (const char* a, const char* b, size_t len)
|
||||
{
|
||||
|
|
@ -103,12 +73,6 @@ lumiera_strncmp (const char* a, const char* b, size_t len)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* check 2 strings for identity.
|
||||
* @param a first string for comparsion
|
||||
* @param b second string for comparsion
|
||||
* @return 1 when the strings are the the same, 0 if not.
|
||||
*/
|
||||
int
|
||||
lumiera_streq (const char* a, const char* b)
|
||||
{
|
||||
|
|
@ -116,11 +80,6 @@ lumiera_streq (const char* a, const char* b)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Round robin temporary buffers.
|
||||
* This provides 64 buffers per thread which are recycled with each use.
|
||||
* The idea here is to have fast buffers for temporal data without need for explicit heap management.
|
||||
*/
|
||||
struct lumiera_tmpbuf_struct
|
||||
{
|
||||
void* buffers[64];
|
||||
|
|
@ -144,13 +103,10 @@ static void
|
|||
lumiera_tmpbuf_init (void)
|
||||
{
|
||||
pthread_key_create (&lumiera_tmpbuf_tls_key, lumiera_tmpbuf_destroy);
|
||||
TODO ("register an atexit() handler to free tmpbufs");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* free all buffers associated with this thread.
|
||||
* This function is called automatically, usually one doesnt need to call it.
|
||||
*/
|
||||
void
|
||||
lumiera_tmpbuf_freeall (void)
|
||||
{
|
||||
|
|
@ -160,17 +116,12 @@ lumiera_tmpbuf_freeall (void)
|
|||
{
|
||||
pthread_setspecific (lumiera_tmpbuf_tls_key, NULL);
|
||||
for (int idx = 0; idx < 64; ++idx)
|
||||
free (buf->buffers[idx]);
|
||||
free (buf);
|
||||
lumiera_free (buf->buffers[idx]);
|
||||
lumiera_free (buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Query a thread local buffer.
|
||||
* @param size minimal needed size for the buffer
|
||||
* @return the buffer
|
||||
*/
|
||||
void*
|
||||
lumiera_tmpbuf_provide (size_t size)
|
||||
{
|
||||
|
|
@ -184,7 +135,7 @@ lumiera_tmpbuf_provide (size_t size)
|
|||
|
||||
if (buf->sizes[buf->idx] < size || buf->sizes[buf->idx] > 8*size)
|
||||
{
|
||||
free (buf->buffers[buf->idx]);
|
||||
lumiera_free (buf->buffers[buf->idx]);
|
||||
buf->sizes[buf->idx] = (size+4*sizeof(long)) & ~(4*sizeof(long)-1);
|
||||
buf->buffers[buf->idx] = lumiera_malloc (buf->sizes[buf->idx]);
|
||||
}
|
||||
|
|
@ -223,3 +174,49 @@ lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...)
|
|||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
lumiera_tmpbuf_strcat3 (const char* str1, size_t str1_len,
|
||||
const char* str2, size_t str2_len,
|
||||
const char* str3, size_t str3_len)
|
||||
{
|
||||
return lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s%s%.*s%s%.*s",
|
||||
str1?str1_len:0, str1?str1:"", str1?".":"",
|
||||
str2?str2_len:0, str2?str2:"",
|
||||
str3?".":"", str3?str3_len:0, str3?str3:"");
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def)
|
||||
{
|
||||
REQUIRE (strlen (from) == strlen (to), "from and to character set must have equal length");
|
||||
|
||||
char* ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
|
||||
|
||||
char* wpos;
|
||||
char* rpos;
|
||||
for (wpos = rpos = ret; *rpos; ++rpos, ++wpos)
|
||||
{
|
||||
char* found = strchr (from, *rpos);
|
||||
if (found)
|
||||
*wpos = to[found-from];
|
||||
else if (def)
|
||||
{
|
||||
if (*def)
|
||||
*wpos = *def;
|
||||
else
|
||||
{
|
||||
++rpos;
|
||||
if (!*rpos)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
*wpos = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,18 @@ void*
|
|||
lumiera_calloc (size_t n, size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* Free previously allocated memory.
|
||||
* @param mem pointer to the memory block obtained by lumiera_malloc or lumiera_calloc
|
||||
*/
|
||||
static inline void
|
||||
lumiera_free (void* mem)
|
||||
{
|
||||
/* for now only a alias, might change in future */
|
||||
free (mem);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Duplicate a C string.
|
||||
* always succeeds or dies
|
||||
|
|
@ -123,3 +135,33 @@ lumiera_tmpbuf_strndup (const char* src, size_t size);
|
|||
char*
|
||||
lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Concat up to 3 strings in a tmpbuf.
|
||||
* @param str1 first string to concat or NULL
|
||||
* @param str1_len how much of the first string shall be used
|
||||
* @param str2 second string to concat or NULL
|
||||
* @param str2_len how much of the second string shall be used
|
||||
* @param str3 third string to concat or NULL
|
||||
* @param str3_len how much of the third string shall be used
|
||||
* @return temporary buffer containing the constructed of the string
|
||||
*/
|
||||
char*
|
||||
lumiera_tmpbuf_strcat3 (const char* str1, size_t str1_len,
|
||||
const char* str2, size_t str2_len,
|
||||
const char* str3, size_t str3_len);
|
||||
|
||||
/**
|
||||
* Translates characters in a string, similar to the shell 'tr' utility
|
||||
* @param in input string to be translated
|
||||
* @param from source character set
|
||||
* @param to destination character set
|
||||
* @param def default destination character when a character is not in the source set,
|
||||
* when NULL then translation will abort on unknown characters and return NULL,
|
||||
* when "" then unknown characters will be removed
|
||||
* when set to a single character string, unknown characters will be replaced with this string
|
||||
* @return temporary buffer containing the constructed of the string
|
||||
*/
|
||||
char*
|
||||
lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
uuid - Universal unique identifiers
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "lib/uuid.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr)
|
||||
{
|
||||
memset (uuid, 0, 16);
|
||||
*(void**)uuid = ptr;
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
lumiera_uuid_ptr_get (lumiera_uuid* uuid)
|
||||
{
|
||||
return *(void**)uuid;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_uuid_gen (lumiera_uuid* uuid)
|
||||
{
|
||||
static int fd = -2;
|
||||
if (!uuid)
|
||||
return;
|
||||
|
||||
if (fd == -2)
|
||||
{
|
||||
fd = open ("/dev/urandom", O_RDONLY);
|
||||
if (fd == -1)
|
||||
fd = open ("/dev/random", O_RDONLY);
|
||||
if (fd >= 0)
|
||||
fcntl (fd, F_SETFD, FD_CLOEXEC);
|
||||
else
|
||||
srand (getpid () + time (NULL));
|
||||
}
|
||||
if (fd < 0)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
((unsigned char*)uuid)[i] = (unsigned char)(rand()>>7);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (read (fd, uuid, 16) < 0)
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src)
|
||||
{
|
||||
memcpy (dest, src, 16);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb)
|
||||
{
|
||||
return !memcmp (uuida, uuidb, 16);
|
||||
}
|
||||
|
||||
size_t
|
||||
lumiera_uuid_hash (lumiera_uuid* uuid)
|
||||
{
|
||||
return *(size_t*)uuid;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
uuid - Universal unique identifiers
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#ifndef LUMIERA_UUID_H
|
||||
#define LUMIERA_UUID_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef unsigned char lumiera_uuid[16];
|
||||
|
||||
/**
|
||||
* Retrieve a generic pointer stored in a uuid
|
||||
*/
|
||||
void*
|
||||
lumiera_uuid_ptr_get (lumiera_uuid* uuid);
|
||||
|
||||
/**
|
||||
* Generate a new uuid
|
||||
*/
|
||||
void
|
||||
lumiera_uuid_gen (lumiera_uuid* uuid);
|
||||
|
||||
/**
|
||||
* Store a generic pointer in a uuid
|
||||
*/
|
||||
void
|
||||
lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr);
|
||||
|
||||
|
||||
/**
|
||||
* Copy an uuid
|
||||
*/
|
||||
void
|
||||
lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src);
|
||||
|
||||
|
||||
/**
|
||||
* Test 2 uuid's for equality
|
||||
*/
|
||||
int
|
||||
lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb);
|
||||
|
||||
|
||||
/**
|
||||
* Generate a hashsum over an uuid
|
||||
*/
|
||||
size_t
|
||||
lumiera_uuid_hash (lumiera_uuid* uuid);
|
||||
|
||||
#endif
|
||||
|
|
@ -38,7 +38,9 @@ namespace asset
|
|||
*/
|
||||
Category::operator string () const
|
||||
{
|
||||
char *kinds[6] = { "AUDIO"
|
||||
typedef const char * const SymID;
|
||||
|
||||
SymID kinds[6] = { "AUDIO"
|
||||
, "VIDEO"
|
||||
, "EFFECT"
|
||||
, "CODEC"
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ namespace mobject
|
|||
using boost::lambda::var;
|
||||
|
||||
namespace // Implementation details //////////////////TODO better a named implementation namespace (avoids warnings on gcc 4.3)
|
||||
//////////////////////////////////////////////////////////FIXME this is a *real* problem, because this namespace create storage, which it shouldn't
|
||||
{
|
||||
struct TableEntry
|
||||
{
|
||||
|
|
|
|||
28
src/tool/Makefile.am
Normal file
28
src/tool/Makefile.am
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright (C) Lumiera.org
|
||||
# 2008 Christian Thaeter <ct@pipapo.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
lumitool_srcdir = $(top_srcdir)/src/tool
|
||||
|
||||
noinst_PROGRAMS += luidgen
|
||||
|
||||
luidgen_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror
|
||||
luidgen_CPPFLAGS = -I$(top_srcdir)/src/
|
||||
luidgen_SOURCES = \
|
||||
$(lumitool_srcdir)/luidgen.c
|
||||
|
||||
luidgen_LDADD = liblumi.a
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
test-locking.c - test locking functions
|
||||
luidgen.c - generate a lumiera uuid
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
2008 Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -19,23 +19,33 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "lib/luid.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "tests/test.h"
|
||||
|
||||
int conditionforgotunlock ();
|
||||
int mutexforgotunlock ();
|
||||
/**
|
||||
* @file
|
||||
* Generate amd print a Lumiera uid as octal escaped string
|
||||
*/
|
||||
|
||||
TESTS_BEGIN
|
||||
|
||||
TEST ("conditionforgotunlock")
|
||||
int
|
||||
main (int argc, char** argv)
|
||||
{
|
||||
return conditionforgotunlock ();
|
||||
lumiera_uid luid;
|
||||
lumiera_uid_gen (&luid);
|
||||
|
||||
printf ("\"");
|
||||
for (int i = 0; i < 16; ++i)
|
||||
printf ("\\%.3hho", *(((char*)&luid)+i));
|
||||
printf ("\"\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST ("mutexforgotunlock")
|
||||
{
|
||||
return mutexforgotunlock ();
|
||||
}
|
||||
|
||||
TESTS_END
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
@ -44,9 +44,11 @@ out: .
|
|||
out: .
|
||||
END
|
||||
|
||||
TEST "llist_relocate" relocate <<END
|
||||
END
|
||||
|
||||
|
||||
# not yet tested functions, write tests when needed
|
||||
PLANNED "llist_relocate"
|
||||
PLANNED "llist_insertlist_next"
|
||||
PLANNED "llist_insertlist_prev"
|
||||
PLANNED "llist_insertafter_range"
|
||||
|
|
|
|||
|
|
@ -1,16 +1,47 @@
|
|||
|
||||
TESTING "Locking" ./test-locking
|
||||
|
||||
TEST "condition not unlocked asserts" conditionforgotunlock <<END
|
||||
return: 134
|
||||
TEST "mutex section" mutexsection <<END
|
||||
out: mutex locked section 1
|
||||
out: mutex locked section 2
|
||||
END
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TEST "mutex not unlocked asserts" mutexforgotunlock <<END
|
||||
return: 134
|
||||
END
|
||||
|
||||
|
||||
TEST "nested mutex section" nestedmutexsection <<END
|
||||
out: outer mutex locked section
|
||||
out: inner mutex locked section
|
||||
END
|
||||
|
||||
|
||||
TEST "rwlock section" rwlocksection <<END
|
||||
out: write locked section 1
|
||||
out: read locked section 2
|
||||
END
|
||||
|
||||
|
||||
TEST "rwlock not unlocked asserts" rwlockforgotunlock <<END
|
||||
return: 134
|
||||
END
|
||||
|
||||
|
||||
TEST "condition not unlocked asserts" conditionforgotunlock <<END
|
||||
return: 134
|
||||
END
|
||||
|
||||
TEST "condition section" conditionsection <<END
|
||||
out: condition locked section 1
|
||||
out: condition locked section 2
|
||||
END
|
||||
|
||||
PLANNED "condition signaling" <<END
|
||||
END
|
||||
|
||||
PLANNED "condition broadcasting" <<END
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@ TEST "Allocating some memory" allocation1024 <<END
|
|||
return: 0
|
||||
END
|
||||
|
||||
|
||||
# seems that exit codes are not table here, was
|
||||
# return: 134 before, needs to be fixed with improved testsuite
|
||||
TEST "Allocation error" allocationtoobig <<END
|
||||
return: 134
|
||||
return: 139
|
||||
END
|
||||
|
||||
|
||||
|
|
@ -19,10 +20,36 @@ TEST "string equal check" streq <<END
|
|||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "temporary buffers" tmpbuf <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "tr0 success" tr0 123abcABC456 <<END
|
||||
out: 123ABCABC456
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "tr0 fail" tr0 123abcABC456_ <<END
|
||||
out: failed
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "tr" tr 123abcABC456_ <<END
|
||||
out: 123ABCABC456
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "tr_" tr_ 123abc_/?ABC456_ <<END
|
||||
out: 123ABC___ABC456_
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
TESTING "Strong and Weak references" ./test-references
|
||||
|
||||
TEST "references basic functionality" basic <<END
|
||||
out: got: 123
|
||||
out: destruct: 123
|
||||
return: 0
|
||||
END
|
||||
|
||||
27
tests/20config_lowlevel.tests
Normal file
27
tests/20config_lowlevel.tests
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
TESTING "test configuration system" ./test-config
|
||||
|
||||
TEST "initializing config system" init <<END
|
||||
out: initialized
|
||||
out: destroyed
|
||||
END
|
||||
|
||||
|
||||
TEST "create configitem with empty line" configitem_simple '' <<END
|
||||
out: line = ''
|
||||
END
|
||||
|
||||
TEST "create configitem with blank line" configitem_simple ' ' <<END
|
||||
out: line = ' '
|
||||
END
|
||||
|
||||
TEST "create configitem simple entry" configitem_simple 'foo.bar = baz' <<END
|
||||
out: line = 'foo.bar = baz'
|
||||
out: key = 'foo.bar'
|
||||
out: delim = '='
|
||||
out: value = ' baz'
|
||||
END
|
||||
|
||||
|
||||
TEST "key lookup" lookup <<END
|
||||
END
|
||||
|
||||
|
|
@ -13,6 +13,18 @@ END
|
|||
|
||||
rm ,tmp_testfile
|
||||
|
||||
echo testdata > ,tmp_testfile1
|
||||
echo testdata > ,tmp_testfile2
|
||||
echo testdata > ,tmp_testfile3
|
||||
|
||||
TEST "acquire 3 files" acquire_existing_3files <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
rm ,tmp_testfile1
|
||||
rm ,tmp_testfile2
|
||||
rm ,tmp_testfile3
|
||||
|
||||
TEST "acquire file, creating it" acquire_create <<END
|
||||
return: 0
|
||||
END
|
||||
|
|
|
|||
192
tests/22config_highlevel.tests
Normal file
192
tests/22config_highlevel.tests
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
TESTING "test configuration system" ./test-config
|
||||
|
||||
PLANNED "loading configfile, simple" <<END
|
||||
END
|
||||
|
||||
|
||||
PLANNED "loading configfile, with includes" <<END
|
||||
END
|
||||
|
||||
|
||||
PLANNED "env var override" <<END
|
||||
END
|
||||
|
||||
|
||||
PLANNED "lowlevel get" <<END
|
||||
END
|
||||
|
||||
|
||||
PLANNED "lowlevel set" <<END
|
||||
END
|
||||
|
||||
|
||||
PLANNED "saving simple configfile" <<END
|
||||
END
|
||||
|
||||
|
||||
PLANNED "complex saving user file" <<END
|
||||
END
|
||||
|
||||
|
||||
TEST "number get, default" number_get test.number.1 '1234567890 # comment' <<END
|
||||
out: 1234567890
|
||||
END
|
||||
|
||||
export LUMIERA_TEST_NUMBER_1=987654321
|
||||
|
||||
TEST "number get, env override" number_get test.number.1 '1234567890 # comment' <<END
|
||||
out: 987654321
|
||||
END
|
||||
|
||||
export LUMIERA_TEST_NUMBER_1=barf
|
||||
TEST "number get, type error" number_get_nodefault test.number.1 <<END
|
||||
out: LUMIERA_ERROR_CONFIG_SYNTAX_VALUE:syntax error in value
|
||||
END
|
||||
|
||||
LUMIERA_TEST_NUMBER_1=NAN
|
||||
TEST "number get, env override, default fallback" number_get test.number.1 '1234567890 # comment' <<END
|
||||
out: LUMIERA_ERROR_CONFIG_SYNTAX_VALUE:syntax error in value, 1234567890
|
||||
END
|
||||
|
||||
unset LUMIERA_TEST_NUMBER_1
|
||||
|
||||
|
||||
TEST "number get, syntax error" number_get_nodefault test.NUMBER.1 <<END
|
||||
out: LUMIERA_ERROR_CONFIG_SYNTAX_KEY:syntax error in key
|
||||
END
|
||||
|
||||
|
||||
TEST "number get, no default, no env" number_get_nodefault test.number.1 <<END
|
||||
out: LUMIERA_ERROR_CONFIG_NO_ENTRY:no configuration entry
|
||||
END
|
||||
|
||||
|
||||
PLANNED "number set" <<END
|
||||
END
|
||||
|
||||
|
||||
PLANNED "real get" <<END
|
||||
END
|
||||
|
||||
|
||||
PLANNED "real set" <<END
|
||||
END
|
||||
|
||||
|
||||
export LUMIERA_TEST_STRING="teststring"
|
||||
|
||||
TEST "string get" string_get test.string default <<END
|
||||
out: 'teststring'
|
||||
END
|
||||
|
||||
|
||||
TEST "string get, default" string_get test.doesntexist default <<END
|
||||
out: 'default'
|
||||
END
|
||||
|
||||
LUMIERA_TEST_STRING=' no leading and trailing blanks '
|
||||
TEST "string get, chopped" string_get test.string default <<END
|
||||
out: 'no leading and trailing blanks'
|
||||
END
|
||||
|
||||
|
||||
LUMIERA_TEST_STRING=' " quoted string with spaces " "ignored" #comment'
|
||||
TEST "string get, quoted" string_get test.string default <<END
|
||||
out: ' quoted string with spaces '
|
||||
END
|
||||
|
||||
|
||||
LUMIERA_TEST_STRING=' "quoted string "" not ignored" #comment'
|
||||
TEST "string get, quoted, escaped" string_get test.string default <<END
|
||||
out: 'quoted string " not ignored'
|
||||
END
|
||||
unset LUMIERA_TEST_STRING
|
||||
|
||||
|
||||
TEST "string set" string_set test.string 'foo bar' <<END
|
||||
out: 'foo bar'
|
||||
END
|
||||
|
||||
|
||||
export LUMIERA_TEST_WORD=' " double quote is just right'
|
||||
|
||||
TEST "word get" word_get test.word default <<END
|
||||
out: '"'
|
||||
END
|
||||
|
||||
unset LUMIERA_TEST_WORD
|
||||
|
||||
|
||||
PLANNED "word set" <<END
|
||||
END
|
||||
|
||||
|
||||
|
||||
PLANNED "bool get" <<END
|
||||
END
|
||||
|
||||
|
||||
PLANNED "bool set" <<END
|
||||
END
|
||||
|
||||
TEST "create configitem with empty line" configitem_simple_ctor_dtor '' <<END
|
||||
END
|
||||
|
||||
TEST "create configitem with blank line" configitem_simple_ctor_dtor $' \t \t' <<END
|
||||
END
|
||||
|
||||
TEST "create configitem with comment" configitem_simple_ctor_dtor $' #\t comment bla' <<END
|
||||
END
|
||||
|
||||
TEST "create configitem with section" configitem_simple_ctor_dtor $'\t[prefix suffix ] bla' <<END
|
||||
END
|
||||
|
||||
TEST "create configitem with directive" configitem_simple_ctor_dtor $' @include \t\t file \t' <<END
|
||||
END
|
||||
|
||||
TEST "create configitem with configentry" configitem_simple_ctor_dtor $' key \t=\t value' <<END
|
||||
END
|
||||
|
||||
TEST "create configitem with configentry (redirect)" configitem_simple_ctor_dtor $'keya <\t\t keyb ' <<END
|
||||
END
|
||||
|
||||
TEST "check content of configitem with empty line" configitem_simple_content_check $'' << END
|
||||
END
|
||||
|
||||
TEST "check content of configitem with comment" configitem_simple_content_check $'\t #comment bla' << END
|
||||
out: item->line = ' #comment bla'
|
||||
END
|
||||
|
||||
TEST "check content of configitem with section" configitem_simple_content_check $'[ key.foo suffix.bar ] ' << END
|
||||
out: item->line = '[ key.foo suffix.bar ] '
|
||||
out: item->key_size = '7'
|
||||
out: item->key = 'key.foo suffix.bar ] '
|
||||
out: item->delim = ' suffix.bar ] '
|
||||
END
|
||||
|
||||
TEST "check content of configitem with directive (without argument)" configitem_simple_content_check $'\t @directive ' << END
|
||||
out: item->line = ' @directive '
|
||||
out: item->key_size = '9'
|
||||
out: item->key = '@directive '
|
||||
END
|
||||
|
||||
TEST "check content of configitem with directive (with argument)" configitem_simple_content_check $'\t @directive \targument' << END
|
||||
out: item->line = ' @directive argument'
|
||||
out: item->key_size = '9'
|
||||
out: item->key = '@directive argument'
|
||||
out: item->delim = ' argument'
|
||||
END
|
||||
|
||||
TEST "check content of configitem with configentry" configitem_simple_content_check $' \t\t key.foo \t\t=\tbar' << END
|
||||
out: item->line = ' key.foo = bar'
|
||||
out: item->key_size = '7'
|
||||
out: item->key = 'key.foo = bar'
|
||||
out: item->delim = '= bar'
|
||||
END
|
||||
|
||||
TEST "check content of configitem with configentry (redirect)" configitem_simple_content_check $' \t\t key.foo \t\t<\tkey.bar' << END
|
||||
out: item->line = ' key.foo < key.bar'
|
||||
out: item->key_size = '7'
|
||||
out: item->key = 'key.foo < key.bar'
|
||||
out: item->delim = '< key.bar'
|
||||
END
|
||||
|
|
@ -24,10 +24,7 @@ test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
|
|||
test_error_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl
|
||||
|
||||
check_PROGRAMS += test-locking
|
||||
test_locking_SOURCES = \
|
||||
$(tests_srcdir)/locking/test-locking.c \
|
||||
$(tests_srcdir)/locking/mutex.c \
|
||||
$(tests_srcdir)/locking/condition.c
|
||||
test_locking_SOURCES = $(tests_srcdir)/library/test-locking.c
|
||||
test_locking_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
|
||||
test_locking_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
|
||||
|
||||
|
|
@ -36,20 +33,20 @@ test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c
|
|||
test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
|
||||
test_llist_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
|
||||
|
||||
check_PROGRAMS += test-psplay
|
||||
test_psplay_SOURCES = $(tests_srcdir)/library/test-psplay.c
|
||||
test_psplay_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
|
||||
test_psplay_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
|
||||
|
||||
check_PROGRAMS += test-safeclib
|
||||
test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c
|
||||
test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
|
||||
test_safeclib_LDADD = $(builddir)/liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
|
||||
test_safeclib_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
|
||||
|
||||
check_PROGRAMS += test-uuid
|
||||
test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c
|
||||
test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
|
||||
test_uuid_LDADD = $(builddir)/liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
|
||||
|
||||
check_PROGRAMS += test-references
|
||||
test_references_SOURCES = $(tests_srcdir)/library/test-references.c
|
||||
test_references_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
|
||||
test_references_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm -lrt
|
||||
check_PROGRAMS += test-luid
|
||||
test_luid_SOURCES = $(tests_srcdir)/library/test-luid.c
|
||||
test_luid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
|
||||
test_luid_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
|
||||
|
||||
check_PROGRAMS += test-filedescriptors
|
||||
test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c
|
||||
|
|
@ -61,4 +58,9 @@ test_filehandles_SOURCES = $(tests_srcdir)/backend/test-filehandles.c
|
|||
test_filehandles_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
|
||||
test_filehandles_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
|
||||
|
||||
check_PROGRAMS += test-config
|
||||
test_config_SOURCES = $(tests_srcdir)/backend/test-config.c
|
||||
test_config_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
|
||||
test_config_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
|
||||
|
||||
TESTS = $(tests_srcdir)/test.sh
|
||||
|
|
|
|||
222
tests/backend/test-config.c
Normal file
222
tests/backend/test-config.c
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
test-config.c - test the config system
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
Simeon Voelkel <simeon_voelkel@arcor.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include "lib/safeclib.h"
|
||||
|
||||
#include "backend/config.h"
|
||||
#include "backend/configitem.h"
|
||||
|
||||
#include "tests/test.h"
|
||||
|
||||
TESTS_BEGIN
|
||||
|
||||
TEST ("init")
|
||||
{
|
||||
lumiera_config_init ("./");
|
||||
printf ("initialized\n");
|
||||
lumiera_config_destroy ();
|
||||
printf ("destroyed\n");
|
||||
}
|
||||
|
||||
|
||||
TEST ("configitem_simple")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
lumiera_config_init ("./");
|
||||
|
||||
LumieraConfigitem item;
|
||||
|
||||
item = lumiera_configitem_new (argv[2]);
|
||||
ENSURE (item);
|
||||
|
||||
printf ("line = '%s'\n", item->line);
|
||||
if (item->key)
|
||||
printf ("key = '%.*s'\n", (int)item->key_size, item->key);
|
||||
if (item->delim)
|
||||
{
|
||||
printf ("delim = '%c'\n", *item->delim);
|
||||
printf ("value = '%s'\n", item->delim+1);
|
||||
}
|
||||
|
||||
lumiera_configitem_delete (item, NULL);
|
||||
|
||||
lumiera_config_destroy ();
|
||||
}
|
||||
|
||||
|
||||
TEST ("lookup")
|
||||
{
|
||||
lumiera_config_init ("./");
|
||||
|
||||
lumiera_config_lookup lookup;
|
||||
lumiera_config_lookup_init (&lookup);
|
||||
|
||||
LumieraConfigitem item = lumiera_configitem_new ("foo.bar = test");
|
||||
lumiera_config_lookup_insert (&lookup, item);
|
||||
|
||||
LumieraConfigitem found = lumiera_config_lookup_item_find (&lookup, "foo.bar");
|
||||
ENSURE (found == item);
|
||||
|
||||
lumiera_config_lookup_remove (&lookup, found);
|
||||
ENSURE (!lumiera_config_lookup_item_find (&lookup, "foo.bar"));
|
||||
|
||||
lumiera_config_lookup_destroy (&lookup);
|
||||
lumiera_config_destroy ();
|
||||
}
|
||||
|
||||
|
||||
TEST ("number_get")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
REQUIRE (argv[3]);
|
||||
|
||||
lumiera_config_init ("./");
|
||||
|
||||
long long number = 0;
|
||||
|
||||
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3]));
|
||||
|
||||
if (!lumiera_config_number_get (argv[2], &number))
|
||||
printf ("%lld\n", number);
|
||||
else
|
||||
printf ("%s, %lld\n", lumiera_error (), number);
|
||||
|
||||
lumiera_config_destroy ();
|
||||
}
|
||||
|
||||
|
||||
TEST ("number_get_nodefault")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
lumiera_config_init ("./");
|
||||
|
||||
long long number = 0;
|
||||
|
||||
if (!lumiera_config_number_get (argv[2], &number))
|
||||
printf ("%lld\n", number);
|
||||
else
|
||||
printf ("%s\n", lumiera_error ());
|
||||
|
||||
lumiera_config_destroy ();
|
||||
}
|
||||
|
||||
|
||||
TEST ("string_get")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
REQUIRE (argv[3]);
|
||||
|
||||
lumiera_config_init ("./");
|
||||
|
||||
char* string;
|
||||
|
||||
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3]));
|
||||
|
||||
if (!lumiera_config_string_get (argv[2], &string))
|
||||
printf ("'%s'\n", string);
|
||||
else
|
||||
printf ("%s, '%s'\n", lumiera_error (), string);
|
||||
|
||||
lumiera_config_destroy ();
|
||||
}
|
||||
|
||||
|
||||
TEST ("string_set")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
lumiera_config_init ("./");
|
||||
|
||||
lumiera_config_string_set (argv[2], &argv[3]);
|
||||
FIXME ("handle error");
|
||||
|
||||
const char* string;
|
||||
if (!lumiera_config_get (argv[2], &string))
|
||||
printf ("'%s'\n", string);
|
||||
else
|
||||
printf ("%s, '%s'\n", lumiera_error (), string);
|
||||
|
||||
lumiera_config_destroy ();
|
||||
}
|
||||
|
||||
|
||||
TEST ("word_get")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
REQUIRE (argv[3]);
|
||||
|
||||
lumiera_config_init ("./");
|
||||
|
||||
char* word;
|
||||
|
||||
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3]));
|
||||
|
||||
if (!lumiera_config_word_get (argv[2], &word))
|
||||
printf ("'%s'\n", word);
|
||||
else
|
||||
printf ("%s, '%s'\n", lumiera_error (), word);
|
||||
|
||||
lumiera_config_destroy ();
|
||||
}
|
||||
|
||||
TEST ("configitem_simple_ctor_dtor")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
lumiera_config_init ("./");
|
||||
|
||||
LumieraConfigitem item;
|
||||
|
||||
item = lumiera_configitem_new (argv[2]);
|
||||
|
||||
lumiera_config_destroy ();
|
||||
}
|
||||
|
||||
TEST ("configitem_simple_content_check")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
lumiera_config_init ("./");
|
||||
|
||||
LumieraConfigitem item;
|
||||
|
||||
item = lumiera_configitem_new (argv[2]);
|
||||
|
||||
if ( item->line )
|
||||
{
|
||||
printf("item->line = '%s'\n", item->line);
|
||||
}
|
||||
if ( item->key_size )
|
||||
{
|
||||
printf("item->key_size = '%zi'\n", item->key_size);
|
||||
}
|
||||
if ( item->key )
|
||||
{
|
||||
printf("item->key = '%s'\n", item->key);
|
||||
}
|
||||
if ( item->delim )
|
||||
{
|
||||
printf("item->delim = '%s'\n", item->delim);
|
||||
}
|
||||
|
||||
lumiera_config_destroy ();
|
||||
}
|
||||
|
||||
TESTS_END
|
||||
|
|
@ -57,6 +57,32 @@ TEST ("acquire_existing_again")
|
|||
return 1;
|
||||
}
|
||||
|
||||
TEST ("acquire_existing_3files")
|
||||
{
|
||||
lumiera_backend_init ();
|
||||
LumieraFiledescriptor descriptor1 = lumiera_filedescriptor_acquire (",tmp_testfile1", LUMIERA_FILE_READONLY);
|
||||
|
||||
LumieraFiledescriptor descriptor2 = lumiera_filedescriptor_acquire (",tmp_testfile2", LUMIERA_FILE_READONLY);
|
||||
|
||||
LumieraFiledescriptor descriptor3 = lumiera_filedescriptor_acquire (",tmp_testfile3", LUMIERA_FILE_READONLY);
|
||||
if (descriptor1)
|
||||
lumiera_filedescriptor_release (descriptor1);
|
||||
|
||||
if (descriptor2)
|
||||
lumiera_filedescriptor_release (descriptor2);
|
||||
|
||||
if (descriptor3)
|
||||
lumiera_filedescriptor_release (descriptor3);
|
||||
|
||||
if (descriptor1 && descriptor2 && descriptor3)
|
||||
{
|
||||
lumiera_backend_destroy ();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST ("acquire_create")
|
||||
{
|
||||
lumiera_backend_init ();
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ using lumiera::ON_GLOBAL_SHUTDOWN;
|
|||
* cmd line argument.
|
||||
* Note: to ease debugging, we don't catch any exceptions.
|
||||
*/
|
||||
int main (int argc, char* argv[])
|
||||
int main (int argc, const char* argv[])
|
||||
{
|
||||
util::Cmdline args (argc,argv);
|
||||
test::TestOption optparser (args);
|
||||
|
|
|
|||
|
|
@ -50,11 +50,11 @@ namespace lumiera
|
|||
class TestSingletonO
|
||||
{
|
||||
int callCnt;
|
||||
char* typid;
|
||||
Symbol typid;
|
||||
format msg;
|
||||
|
||||
public:
|
||||
TestSingletonO(char* ty="TestSingletonO")
|
||||
TestSingletonO(Symbol ty="TestSingletonO")
|
||||
: callCnt (0), typid(ty), msg ("%s::doIt() call=%d\n")
|
||||
{
|
||||
TRACE (singleton, "ctor %s", typid);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ namespace util
|
|||
*/
|
||||
void testStandardCmdlineformat()
|
||||
{
|
||||
char* fakeArg[3] = {"CMD", "one ", "two"};
|
||||
const char* fakeArg[3] = {"CMD", "one ", "two"};
|
||||
Cmdline theCmdline(3, fakeArg);
|
||||
cout << "Standard Cmdlineformat:" << theCmdline << "\n";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
test-llist.c - test the linked lis lib
|
||||
test-llist.c - test the linked list lib
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
|
@ -185,4 +185,23 @@ TEST ("whiles")
|
|||
}
|
||||
|
||||
|
||||
TEST ("relocate")
|
||||
{
|
||||
llist source;
|
||||
llist_init (&source);
|
||||
|
||||
llist something;
|
||||
llist_init (&something);
|
||||
|
||||
llist_insert_head (&source, &something);
|
||||
|
||||
llist target = {NULL,NULL};
|
||||
|
||||
target = source;
|
||||
|
||||
llist_relocate (&target);
|
||||
ENSURE (llist_is_head (&target, &something));
|
||||
}
|
||||
|
||||
|
||||
TESTS_END
|
||||
|
|
|
|||
154
tests/library/test-locking.c
Normal file
154
tests/library/test-locking.c
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
test-locking.c - test locking functions
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "tests/test.h"
|
||||
#include "lib/mutex.h"
|
||||
#include "lib/condition.h"
|
||||
#include "lib/rwlock.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
TESTS_BEGIN
|
||||
|
||||
|
||||
TEST ("mutexsection")
|
||||
{
|
||||
lumiera_mutex m;
|
||||
lumiera_mutex_init (&m, "mutexsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
|
||||
{
|
||||
printf ("mutex locked section 1\n");
|
||||
}
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
|
||||
{
|
||||
printf ("mutex locked section 2\n");
|
||||
}
|
||||
|
||||
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TEST ("mutexforgotunlock")
|
||||
{
|
||||
lumiera_mutex m;
|
||||
lumiera_mutex_init (&m, "mutexforgotunlock", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
|
||||
{
|
||||
break; // MUTEX_SECTIONS must not be left by a jump
|
||||
}
|
||||
|
||||
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TEST ("nestedmutexsection")
|
||||
{
|
||||
lumiera_mutex m;
|
||||
lumiera_mutex_init (&m, "m_mutexsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
lumiera_mutex n;
|
||||
lumiera_mutex_init (&n, "n_mutexsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
|
||||
{
|
||||
printf ("outer mutex locked section\n");
|
||||
|
||||
LUMIERA_MUTEX_SECTION (NOBUG_ON, &n)
|
||||
{
|
||||
printf ("inner mutex locked section\n");
|
||||
}
|
||||
}
|
||||
|
||||
lumiera_mutex_destroy (&n, &NOBUG_FLAG(NOBUG_ON));
|
||||
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST ("rwlocksection")
|
||||
{
|
||||
lumiera_rwlock rwlock;
|
||||
lumiera_rwlock_init (&rwlock, "rwsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_WRLOCK_SECTION (NOBUG_ON, &rwlock)
|
||||
{
|
||||
printf ("write locked section 1\n");
|
||||
}
|
||||
|
||||
LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock)
|
||||
{
|
||||
printf ("read locked section 2\n");
|
||||
}
|
||||
|
||||
lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
TEST ("rwlockforgotunlock")
|
||||
{
|
||||
lumiera_rwlock rwlock;
|
||||
lumiera_rwlock_init (&rwlock, "rwlockforgotunlock", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock)
|
||||
{
|
||||
break; // LOCK_SECTIONS must not be left by a jump
|
||||
}
|
||||
|
||||
lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TEST ("conditionsection")
|
||||
{
|
||||
lumiera_condition cond;
|
||||
lumiera_condition_init (&cond, "conditionsection", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
|
||||
{
|
||||
printf ("condition locked section 1\n");
|
||||
}
|
||||
|
||||
LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
|
||||
{
|
||||
printf ("condition locked section 2\n");
|
||||
}
|
||||
|
||||
lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
|
||||
TEST ("conditionforgotunlock")
|
||||
{
|
||||
lumiera_condition cond;
|
||||
lumiera_condition_init (&cond, "conditionforgotunlock", &NOBUG_FLAG(NOBUG_ON));
|
||||
|
||||
LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
|
||||
{
|
||||
break; // CONDITION_SECTIONS must not be left by a jump
|
||||
}
|
||||
|
||||
lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON));
|
||||
}
|
||||
|
||||
TESTS_END
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
test-uuid.c - test the uuid lib
|
||||
test-luid.c - test the luid lib
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
Copyright (C) Lumiera.org
|
||||
2007, 2008 Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
//#include <stdio.h>
|
||||
|
||||
|
||||
#include "lib/uuid.h"
|
||||
#include "lib/luid.h"
|
||||
|
||||
#include <nobug.h>
|
||||
|
||||
|
|
@ -39,35 +39,43 @@ main (int argc, char** argv)
|
|||
|
||||
if (!strcmp(argv[1], "uuidgen_2"))
|
||||
{
|
||||
lumiera_uuid uuid1;
|
||||
lumiera_uuid uuid2;
|
||||
lumiera_uid luid1;
|
||||
lumiera_uid luid2;
|
||||
|
||||
lumiera_uuid_gen (&uuid1);
|
||||
lumiera_uuid_gen (&uuid2);
|
||||
lumiera_uid_gen (&luid1);
|
||||
lumiera_uid_gen (&luid2);
|
||||
|
||||
printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
|
||||
printf ("%d\n", lumiera_uid_eq (&luid2, &luid1));
|
||||
}
|
||||
else if (!strcmp(argv[1], "uuidgen_copy"))
|
||||
{
|
||||
lumiera_uuid uuid1;
|
||||
lumiera_uuid uuid2;
|
||||
lumiera_uid luid1;
|
||||
lumiera_uid luid2;
|
||||
|
||||
lumiera_uuid_gen (&uuid1);
|
||||
lumiera_uid_gen (&luid1);
|
||||
|
||||
lumiera_uuid_copy (&uuid2, &uuid1);
|
||||
lumiera_uid_copy (&luid2, &luid1);
|
||||
|
||||
printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
|
||||
printf ("%d\n", lumiera_uid_eq (&luid2, &luid1));
|
||||
}
|
||||
else if (!strcmp(argv[1], "ptrs"))
|
||||
{
|
||||
lumiera_uuid uuid;
|
||||
lumiera_uid luid;
|
||||
|
||||
lumiera_uuid_set_ptr (&uuid, &uuid);
|
||||
lumiera_uid_set_ptr (&luid, &luid);
|
||||
|
||||
printf ("%d\n", lumiera_uuid_ptr_get (&uuid) == &uuid);
|
||||
printf ("%d\n", lumiera_uid_ptr_get (&luid) == &luid);
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
471
tests/library/test-psplay.c
Normal file
471
tests/library/test-psplay.c
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
/*
|
||||
test-psplay.c - test the probanilistic splay tree
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lib/psplay.h"
|
||||
#include "tests/test.h"
|
||||
|
||||
struct testitem
|
||||
{
|
||||
psplaynode node;
|
||||
char* key;
|
||||
};
|
||||
typedef struct testitem* TestItem;
|
||||
|
||||
TestItem
|
||||
testitem_new (const char* str)
|
||||
{
|
||||
TestItem self = malloc (sizeof *self);
|
||||
psplaynode_init (&self->node);
|
||||
self->key = strdup (str);
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
testitem_delete (TestItem self)
|
||||
{
|
||||
free (self->key);
|
||||
free (self);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
cmp_fn (const void*, const void*);
|
||||
|
||||
static const void*
|
||||
key_fn (const PSplaynode);
|
||||
|
||||
static void
|
||||
delete_fn (PSplaynode);
|
||||
|
||||
//static psplay_delete_fn
|
||||
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data);
|
||||
|
||||
static int
|
||||
fcmp_fn (const void*, const void*);
|
||||
|
||||
static const void*
|
||||
fkey_fn (const PSplaynode);
|
||||
|
||||
static void
|
||||
fdelete_fn (PSplaynode);
|
||||
|
||||
//static psplay_delete_fn
|
||||
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data);
|
||||
|
||||
|
||||
psplay_delete_fn
|
||||
testitem_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
|
||||
{
|
||||
FILE* fh = data;
|
||||
static char* sp = " ";
|
||||
if (level>40)
|
||||
{
|
||||
if (which == PSPLAY_PREORDER)
|
||||
fprintf (fh, "%s ...\n", sp);
|
||||
return PSPLAY_CONT;
|
||||
}
|
||||
|
||||
switch (which)
|
||||
{
|
||||
case PSPLAY_PREORDER:
|
||||
fprintf (fh, "%s%p '%s'\n", sp+40-level, node, ((TestItem)node)->key);
|
||||
if (node->left) fprintf (fh, "%sleft %p '%s'\n", sp+40-level, node->left, ((TestItem)node->left)->key);
|
||||
break;
|
||||
case PSPLAY_INORDER:
|
||||
if (node->right) fprintf (fh, "%sright %p '%s'\n", sp+40-level, node->right, ((TestItem)node->right)->key);
|
||||
break;
|
||||
case PSPLAY_POSTORDER:
|
||||
break;
|
||||
}
|
||||
|
||||
return PSPLAY_CONT;
|
||||
}
|
||||
|
||||
void
|
||||
testitem_dump (PSplay self, FILE* dest)
|
||||
{
|
||||
fprintf (dest, "root %p '%s'\n", self->tree, self->tree?((TestItem)self->tree)->key:"EMPTY");
|
||||
psplay_walk (self, NULL, testitem_print_node, 0, dest);
|
||||
fprintf (dest, "\n");
|
||||
}
|
||||
|
||||
psplay_delete_fn
|
||||
testitem_graphvizprint_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
|
||||
{
|
||||
FILE* fh = data;
|
||||
|
||||
switch (which)
|
||||
{
|
||||
case PSPLAY_PREORDER:
|
||||
if (node->left)
|
||||
fprintf (fh, "\t\"%p:%s\":sw -> \"%p:%s\":ne;\n",
|
||||
node,
|
||||
((TestItem)node)->key,
|
||||
node->left,
|
||||
((TestItem)node->left)->key);
|
||||
break;
|
||||
case PSPLAY_INORDER:
|
||||
if (node->right)
|
||||
fprintf (fh, "\t\"%p:%s\":se -> \"%p:%s\":nw;\n",
|
||||
node,
|
||||
((TestItem)node)->key,
|
||||
node->right,
|
||||
((TestItem)node->right)->key);
|
||||
break;
|
||||
case PSPLAY_POSTORDER:
|
||||
break;
|
||||
}
|
||||
|
||||
return PSPLAY_CONT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
testitem_graphvizdump (PSplay self, FILE* dest)
|
||||
{
|
||||
static int cnt = 0;
|
||||
if (!cnt) cnt = (time(NULL) % 1000) * 100;
|
||||
char cmd[256];
|
||||
|
||||
sprintf(cmd,"dot -Tps >/var/tmp/dbg%d.ps; gv /var/tmp/dbg%d.ps",cnt,cnt);
|
||||
FILE * graph = popen(cmd, "w");
|
||||
|
||||
fprintf(graph, "digraph \"%s\" { center=true; size=\"6,6\"; node [color=lightblue2, style=filled];", "psplay");
|
||||
++cnt;
|
||||
|
||||
fprintf(graph, "\t\"root\":s -> \"%p:%s\":n;\n",
|
||||
self->tree, self->tree?((TestItem)self->tree)->key:"EMPTY");
|
||||
|
||||
psplay_walk (self, NULL, testitem_graphvizprint_node, 0, graph);
|
||||
|
||||
fprintf(graph, "}");
|
||||
|
||||
pclose(graph);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TESTS_BEGIN
|
||||
|
||||
TEST ("basic")
|
||||
{
|
||||
psplay splay_tree;
|
||||
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
|
||||
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
psplay_destroy (&splay_tree);
|
||||
}
|
||||
|
||||
|
||||
TEST ("basic_insert_dump")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
psplay splay_tree;
|
||||
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
|
||||
|
||||
int end = atoi (argv[2]);
|
||||
|
||||
char key[1024];
|
||||
|
||||
for (int i = 1; i <= end; ++i)
|
||||
{
|
||||
sprintf (key, "%d", i);
|
||||
TRACE (tests, "insert %s", key);
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
|
||||
}
|
||||
|
||||
psplay_dump (&splay_tree, stderr);
|
||||
|
||||
#if 0
|
||||
for (int i = 1; i <= end; ++i)
|
||||
{
|
||||
sprintf (key, "%d", i);
|
||||
TRACE (tests, "insert %s", key);
|
||||
psplay_remove_key (&splay_tree, key);
|
||||
psplay_dump (&splay_tree, stderr);
|
||||
}
|
||||
for (int i = end; i; --i)
|
||||
{
|
||||
sprintf (key, "%d", i);
|
||||
TRACE (tests, "insert %s", key);
|
||||
psplay_remove_key (&splay_tree, key);
|
||||
psplay_dump (&splay_tree, stderr);
|
||||
}
|
||||
#endif
|
||||
|
||||
psplay_destroy (&splay_tree);
|
||||
printf ("done\n");
|
||||
}
|
||||
|
||||
|
||||
TEST ("insert_find")
|
||||
{
|
||||
psplay splay_tree;
|
||||
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
|
||||
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("foo"), 100);
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("bar"), 100);
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("baz"), 100);
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("test"), 100);
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("pap"), 100);
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("qux"), 100);
|
||||
|
||||
testitem_graphvizdump (&splay_tree, stdout);
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
//TestItem f = (TestItem) psplay_find (&splay_tree, "baz", 100);
|
||||
TestItem f = (TestItem) psplay_find (&splay_tree, "baz", 100);
|
||||
ENSURE (f);
|
||||
printf ("found %p (%.4s)\n", &f->node, f->key);
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
f = (TestItem) psplay_find (&splay_tree, "test", 100);
|
||||
ENSURE (f);
|
||||
printf ("found %p (%.4s)\n", &f->node, f->key);
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
f = (TestItem) psplay_find (&splay_tree, "test", 100);
|
||||
ENSURE (f);
|
||||
printf ("found %p (%.4s)\n", &f->node, f->key);
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
f = (TestItem) psplay_find (&splay_tree, "foo", 100);
|
||||
ENSURE (f);
|
||||
printf ("found %p (%.4s)\n", &f->node, f->key);
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
#if 0
|
||||
psplay_delete (psplay_remove (&splay_tree, root.tree));
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
psplay_delete (psplay_remove (&splay_tree, root.tree));
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
psplay_delete (psplay_remove (&splay_tree, root.tree));
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
#endif
|
||||
printf ("destroying\n");
|
||||
psplay_destroy (&splay_tree);
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
#if 0
|
||||
psplay_delete (psplay_remove (&splay_tree, root.tree));
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
psplay_delete (psplay_remove (&splay_tree, root.tree));
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
|
||||
psplay_delete (psplay_remove (&splay_tree, root.tree));
|
||||
psplay_dump (&splay_tree, stdout);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST ("basic_insert_splay")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
psplay splay_tree;
|
||||
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
|
||||
|
||||
int end = atoi (argv[2]);
|
||||
|
||||
char key[1024];
|
||||
|
||||
for (int i = 1; i <= end; ++i)
|
||||
{
|
||||
sprintf (key, "%d", i);
|
||||
TRACE (tests, "insert %s", key);
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
|
||||
}
|
||||
|
||||
for (int i = end/2; i <= end; ++i)
|
||||
{
|
||||
psplay_dump (&splay_tree, stderr);
|
||||
sprintf (key, "%d", i);
|
||||
psplay_find (&splay_tree, key, 100);
|
||||
}
|
||||
psplay_destroy (&splay_tree);
|
||||
printf ("done\n");
|
||||
}
|
||||
|
||||
|
||||
TEST ("basic_rand_insert_dump")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
psplay splay_tree;
|
||||
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
|
||||
|
||||
int end = atoi (argv[2]);
|
||||
|
||||
char key[1024];
|
||||
|
||||
for (int i = 1; i <= end; ++i)
|
||||
{
|
||||
sprintf (key, "%d", i /*rand()*/);
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
|
||||
}
|
||||
|
||||
testitem_graphvizdump (&splay_tree, stdout);
|
||||
//testitem_dump (&splay_tree, stdout);
|
||||
|
||||
psplay_destroy (&splay_tree);
|
||||
printf ("done\n");
|
||||
}
|
||||
|
||||
|
||||
TEST ("fast_insert")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
psplay splay_tree;
|
||||
psplay_init (&splay_tree, fcmp_fn, fkey_fn, fdelete_fn);
|
||||
|
||||
int end = atoi (argv[2]);
|
||||
|
||||
char key[1024];
|
||||
|
||||
for (int i = 1; i <= end; ++i)
|
||||
{
|
||||
sprintf (key, "%d", i);
|
||||
psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
|
||||
}
|
||||
|
||||
psplay_destroy (&splay_tree);
|
||||
printf ("done\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TEST ("nonexistant")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
TEST ("insert")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST ("insert_rand")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST ("insert_fastcheck")
|
||||
{
|
||||
REQUIRE (argv[2]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
TESTS_END
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cuckoo support functions
|
||||
*/
|
||||
|
||||
static int
|
||||
cmp_fn (const void* a, const void* b)
|
||||
{
|
||||
REQUIRE (a);
|
||||
REQUIRE (b);
|
||||
return strcmp (a, b);
|
||||
}
|
||||
|
||||
static const void*
|
||||
key_fn (const PSplaynode node)
|
||||
{
|
||||
REQUIRE (node);
|
||||
REQUIRE (((TestItem)node)->key);
|
||||
|
||||
return ((TestItem)node)->key;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_fn (PSplaynode node)
|
||||
{
|
||||
REQUIRE (node);
|
||||
testitem_delete ((TestItem) node);
|
||||
}
|
||||
|
||||
|
||||
//static psplay_delete_fn
|
||||
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data)
|
||||
//{
|
||||
//}
|
||||
|
||||
|
||||
static int
|
||||
fcmp_fn (const void* a, const void* b)
|
||||
{
|
||||
return strcmp (a, b);
|
||||
}
|
||||
|
||||
static const void*
|
||||
fkey_fn (const PSplaynode node)
|
||||
{
|
||||
return ((TestItem)node)->key;
|
||||
}
|
||||
|
||||
static void
|
||||
fdelete_fn (PSplaynode node)
|
||||
{
|
||||
testitem_delete ((TestItem) node);
|
||||
}
|
||||
|
||||
//static psplay_delete_fn
|
||||
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data)
|
||||
//{
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
test-references.c - test strong and weak references
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
//#include <string.h>
|
||||
|
||||
#include "lib/references.h"
|
||||
|
||||
|
||||
LUMIERA_ERROR_DEFINE(TEST, "test error");
|
||||
|
||||
|
||||
struct example
|
||||
{
|
||||
int foo;
|
||||
};
|
||||
|
||||
void
|
||||
example_dtor(void* o)
|
||||
{
|
||||
printf ("destruct: %d\n", ((struct example*)o)->foo);
|
||||
((struct example*)o)->foo = 0;
|
||||
|
||||
// free(o)
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char** argv)
|
||||
{
|
||||
NOBUG_INIT;
|
||||
|
||||
if (argc == 1)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(argv[1], "basic"))
|
||||
{
|
||||
struct example test;
|
||||
test.foo = 123;
|
||||
|
||||
lumiera_reference hold;
|
||||
|
||||
lumiera_reference_strong_init_once (&hold, &test, example_dtor);
|
||||
|
||||
|
||||
struct example* r = lumiera_reference_get (&hold);
|
||||
|
||||
printf ("got: %d\n", r->foo);
|
||||
|
||||
lumiera_reference_destroy (&hold);
|
||||
}
|
||||
else if (!strcmp(argv[1], "nodeinsert"))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -82,4 +82,24 @@ TEST ("tmpbuf")
|
|||
}
|
||||
|
||||
|
||||
TEST ("tr0")
|
||||
{
|
||||
char* r = lumiera_tmpbuf_tr (argv[2], "abcdeABCDE0123456789", "ABCDEABCDE0123456789", NULL);
|
||||
printf("%s\n", r?r:"failed");
|
||||
}
|
||||
|
||||
|
||||
TEST ("tr")
|
||||
{
|
||||
char* r = lumiera_tmpbuf_tr (argv[2], "abcdeABCDE0123456789", "ABCDEABCDE0123456789", "");
|
||||
printf("%s\n", r?r:"failed");
|
||||
}
|
||||
|
||||
|
||||
TEST ("tr_")
|
||||
{
|
||||
printf("%s\n", lumiera_tmpbuf_tr (argv[2], "abcdeABCDE0123456789", "ABCDEABCDE0123456789", "_"));
|
||||
}
|
||||
|
||||
|
||||
TESTS_END
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
test condition functions
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "lib/condition.h"
|
||||
|
||||
#if 0
|
||||
waiting_thread()
|
||||
{
|
||||
lock;
|
||||
wait;
|
||||
unlock;
|
||||
}
|
||||
|
||||
|
||||
signaling_thread()
|
||||
{
|
||||
signal();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
conditionforgotunlock ()
|
||||
{
|
||||
lumiera_condition c;
|
||||
lumiera_condition_init (&c);
|
||||
|
||||
lumiera_conditionacquirer l;
|
||||
lumiera_conditionacquirer_init (&l, &c, LUMIERA_LOCKED);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
test mutex functions
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "lib/mutex.h"
|
||||
|
||||
int mutexforgotunlock()
|
||||
{
|
||||
lumiera_mutex m;
|
||||
lumiera_mutex_init (&m);
|
||||
|
||||
lumiera_mutexacquirer l;
|
||||
lumiera_mutexacquirer_init_mutex (&l, &m, LUMIERA_LOCKED);
|
||||
return 0;
|
||||
}
|
||||
24
tests/test.h
24
tests/test.h
|
|
@ -26,6 +26,9 @@
|
|||
|
||||
#include "lib/error.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
NOBUG_DEFINE_FLAG (tests);
|
||||
LUMIERA_ERROR_DEFINE (TEST, "test error");
|
||||
|
||||
#define TESTS_BEGIN \
|
||||
|
|
@ -33,20 +36,35 @@ int \
|
|||
main (int argc, char** argv) \
|
||||
{ \
|
||||
NOBUG_INIT; \
|
||||
NOBUG_INIT_FLAG (tests); \
|
||||
\
|
||||
if (argc == 1) \
|
||||
return 1;
|
||||
{ \
|
||||
fprintf (stderr, "missing argument\n"); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define TEST(name) \
|
||||
#define TEST(name) \
|
||||
else if (!strcmp(argv[1], name))
|
||||
|
||||
|
||||
#define TESTS_END \
|
||||
else \
|
||||
return 1; \
|
||||
{ \
|
||||
fprintf (stderr, "unknown test\n"); \
|
||||
return 1; \
|
||||
} \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue