aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Doxyfile1608
-rw-r--r--src/experimental/debugmutex.cpp78
-rw-r--r--src/experimental/debugmutex.h102
-rw-r--r--src/stable/mutex.h8
-rw-r--r--src/stable/myriad.cpp167
-rw-r--r--src/stable/myriad.h81
-rw-r--r--src/stable/myriadstream.cpp6
-rw-r--r--src/stable/myriadstream.h1
-rw-r--r--src/tests/bigmyriad.cpp9
-rw-r--r--src/tests/myriad.cpp23
-rw-r--r--src/tests/myriadfs.cpp62
-rw-r--r--src/tools/myriad.cpp77
-rw-r--r--src/tools/myriadfs.cpp269
-rw-r--r--src/unit/myriad.unit385
-rw-r--r--src/unstable/bitstring.cpp12
-rw-r--r--src/unstable/bitstring.h10
-rw-r--r--src/unstable/myriadcache.cpp8
-rw-r--r--src/unstable/myriadcache.h150
-rw-r--r--src/unstable/myriadfs.cpp739
-rw-r--r--src/unstable/myriadfs.h211
20 files changed, 2406 insertions, 1600 deletions
diff --git a/Doxyfile b/Doxyfile
index 23de8ba..33a33f6 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -1,105 +1,20 @@
1# Doxyfile 1.8.1 1# Doxyfile 1.9.4
2
3# This file describes the settings to be used by the documentation system
4# doxygen (www.doxygen.org) for a project.
5#
6# All text after a hash (#) is considered a comment and will be ignored.
7# The format is:
8# TAG = value [value, ...]
9# For lists items can also be appended using:
10# TAG += value [value, ...]
11# Values that contain spaces should be placed between quotes (" ").
12 2
13#--------------------------------------------------------------------------- 3#---------------------------------------------------------------------------
14# Project related configuration options 4# Project related configuration options
15#--------------------------------------------------------------------------- 5#---------------------------------------------------------------------------
16
17# This tag specifies the encoding used for all characters in the config file
18# that follow. The default is UTF-8 which is also the encoding used for all
19# text before the first occurrence of this tag. Doxygen uses libiconv (or the
20# iconv built into libc) for the transcoding. See
21# http://www.gnu.org/software/libiconv for the list of possible encodings.
22
23DOXYFILE_ENCODING = UTF-8 6DOXYFILE_ENCODING = UTF-8
24
25# The PROJECT_NAME tag is a single word (or sequence of words) that should
26# identify the project. Note that if you do not use Doxywizard you need
27# to put quotes around the project name if it contains spaces.
28
29PROJECT_NAME = libbu++ 7PROJECT_NAME = libbu++
30
31# The PROJECT_NUMBER tag can be used to enter a project or revision number.
32# This could be handy for archiving the generated documentation or
33# if some version control system is used.
34
35PROJECT_NUMBER = $VERSION$ 8PROJECT_NUMBER = $VERSION$
36
37# Using the PROJECT_BRIEF tag one can provide an optional one line description
38# for a project that appears at the top of each page and should give viewer
39# a quick idea about the purpose of the project. Keep the description short.
40
41PROJECT_BRIEF = 9PROJECT_BRIEF =
42
43# With the PROJECT_LOGO tag one can specify an logo or icon that is
44# included in the documentation. The maximum height of the logo should not
45# exceed 55 pixels and the maximum width should not exceed 200 pixels.
46# Doxygen will copy the logo to the output directory.
47
48PROJECT_LOGO = 10PROJECT_LOGO =
49
50# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
51# base path where the generated documentation will be put.
52# If a relative path is entered, it will be relative to the location
53# where doxygen was started. If left blank the current directory will be used.
54
55OUTPUT_DIRECTORY = api 11OUTPUT_DIRECTORY = api
56
57# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
58# 4096 sub-directories (in 2 levels) under the output directory of each output
59# format and will distribute the generated files over these directories.
60# Enabling this option can be useful when feeding doxygen a huge amount of
61# source files, where putting all generated files in the same directory would
62# otherwise cause performance problems for the file system.
63
64CREATE_SUBDIRS = NO 12CREATE_SUBDIRS = NO
65 13CREATE_SUBDIRS_LEVEL = 8
66# The OUTPUT_LANGUAGE tag is used to specify the language in which all 14ALLOW_UNICODE_NAMES = NO
67# documentation generated by doxygen is written. Doxygen will use this
68# information to generate all constant output in the proper language.
69# The default language is English, other supported languages are:
70# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
71# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
72# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
73# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
74# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
75# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
76
77OUTPUT_LANGUAGE = English 15OUTPUT_LANGUAGE = English
78
79# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
80# include brief member descriptions after the members that are listed in
81# the file and class documentation (similar to JavaDoc).
82# Set to NO to disable this.
83
84BRIEF_MEMBER_DESC = YES 16BRIEF_MEMBER_DESC = YES
85
86# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
87# the brief description of a member or function before the detailed description.
88# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
89# brief descriptions will be completely suppressed.
90
91REPEAT_BRIEF = YES 17REPEAT_BRIEF = YES
92
93# This tag implements a quasi-intelligent brief description abbreviator
94# that is used to form the text in various listings. Each string
95# in this list, if found as the leading text of the brief description, will be
96# stripped from the text and the result after processing the whole list, is
97# used as the annotated text. Otherwise, the brief description is used as-is.
98# If left blank, the following values are used ("$name" is automatically
99# replaced with the name of the entity): "The $name class" "The $name widget"
100# "The $name file" "is" "provides" "specifies" "contains"
101# "represents" "a" "an" "the"
102
103ABBREVIATE_BRIEF = "The $name class" \ 18ABBREVIATE_BRIEF = "The $name class" \
104 "The $name widget" \ 19 "The $name widget" \
105 "The $name file" \ 20 "The $name file" \
@@ -111,582 +26,107 @@ ABBREVIATE_BRIEF = "The $name class" \
111 a \ 26 a \
112 an \ 27 an \
113 the 28 the
114
115# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
116# Doxygen will generate a detailed section even if there is only a brief
117# description.
118
119ALWAYS_DETAILED_SEC = NO 29ALWAYS_DETAILED_SEC = NO
120
121# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
122# inherited members of a class in the documentation of that class as if those
123# members were ordinary class members. Constructors, destructors and assignment
124# operators of the base classes will not be shown.
125
126INLINE_INHERITED_MEMB = NO 30INLINE_INHERITED_MEMB = NO
127
128# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
129# path before files name in the file list and in the header files. If set
130# to NO the shortest path that makes the file name unique will be used.
131
132FULL_PATH_NAMES = NO 31FULL_PATH_NAMES = NO
133
134# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
135# can be used to strip a user-defined part of the path. Stripping is
136# only done if one of the specified strings matches the left-hand part of
137# the path. The tag can be used to show relative paths in the file list.
138# If left blank the directory from which doxygen is run is used as the
139# path to strip.
140
141STRIP_FROM_PATH = 32STRIP_FROM_PATH =
142
143# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
144# the path mentioned in the documentation of a class, which tells
145# the reader which header file to include in order to use a class.
146# If left blank only the name of the header file containing the class
147# definition is used. Otherwise one should specify the include paths that
148# are normally passed to the compiler using the -I flag.
149
150STRIP_FROM_INC_PATH = 33STRIP_FROM_INC_PATH =
151
152# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
153# (but less readable) file names. This can be useful if your file system
154# doesn't support long names like on DOS, Mac, or CD-ROM.
155
156SHORT_NAMES = NO 34SHORT_NAMES = NO
157
158# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
159# will interpret the first line (until the first dot) of a JavaDoc-style
160# comment as the brief description. If set to NO, the JavaDoc
161# comments will behave just like regular Qt-style comments
162# (thus requiring an explicit @brief command for a brief description.)
163
164JAVADOC_AUTOBRIEF = YES 35JAVADOC_AUTOBRIEF = YES
165 36JAVADOC_BANNER = NO
166# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
167# interpret the first line (until the first dot) of a Qt-style
168# comment as the brief description. If set to NO, the comments
169# will behave just like regular Qt-style comments (thus requiring
170# an explicit \brief command for a brief description.)
171
172QT_AUTOBRIEF = NO 37QT_AUTOBRIEF = NO
173
174# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
175# treat a multi-line C++ special comment block (i.e. a block of //! or ///
176# comments) as a brief description. This used to be the default behaviour.
177# The new default is to treat a multi-line C++ comment block as a detailed
178# description. Set this tag to YES if you prefer the old behaviour instead.
179
180MULTILINE_CPP_IS_BRIEF = NO 38MULTILINE_CPP_IS_BRIEF = NO
181 39PYTHON_DOCSTRING = YES
182# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
183# member inherits the documentation from any documented member that it
184# re-implements.
185
186INHERIT_DOCS = YES 40INHERIT_DOCS = YES
187
188# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
189# a new page for each member. If set to NO, the documentation of a member will
190# be part of the file/class/namespace that contains it.
191
192SEPARATE_MEMBER_PAGES = NO 41SEPARATE_MEMBER_PAGES = NO
193
194# The TAB_SIZE tag can be used to set the number of spaces in a tab.
195# Doxygen uses this value to replace tabs by spaces in code fragments.
196
197TAB_SIZE = 4 42TAB_SIZE = 4
198
199# This tag can be used to specify a number of aliases that acts
200# as commands in the documentation. An alias has the form "name=value".
201# For example adding "sideeffect=\par Side Effects:\n" will allow you to
202# put the command \sideeffect (or @sideeffect) in the documentation, which
203# will result in a user-defined paragraph with heading "Side Effects:".
204# You can put \n's in the value part of an alias to insert newlines.
205
206ALIASES = 43ALIASES =
207
208# This tag can be used to specify a number of word-keyword mappings (TCL only).
209# A mapping has the form "name=value". For example adding
210# "class=itcl::class" will allow you to use the command class in the
211# itcl::class meaning.
212
213TCL_SUBST =
214
215# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
216# sources only. Doxygen will then generate output that is more tailored for C.
217# For instance, some of the names that are used will be different. The list
218# of all members will be omitted, etc.
219
220OPTIMIZE_OUTPUT_FOR_C = NO 44OPTIMIZE_OUTPUT_FOR_C = NO
221
222# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
223# sources only. Doxygen will then generate output that is more tailored for
224# Java. For instance, namespaces will be presented as packages, qualified
225# scopes will look different, etc.
226
227OPTIMIZE_OUTPUT_JAVA = NO 45OPTIMIZE_OUTPUT_JAVA = NO
228
229# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
230# sources only. Doxygen will then generate output that is more tailored for
231# Fortran.
232
233OPTIMIZE_FOR_FORTRAN = NO 46OPTIMIZE_FOR_FORTRAN = NO
234
235# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
236# sources. Doxygen will then generate output that is tailored for
237# VHDL.
238
239OPTIMIZE_OUTPUT_VHDL = NO 47OPTIMIZE_OUTPUT_VHDL = NO
240 48OPTIMIZE_OUTPUT_SLICE = NO
241# Doxygen selects the parser to use depending on the extension of the files it
242# parses. With this tag you can assign which parser to use for a given extension.
243# Doxygen has a built-in mapping, but you can override or extend it using this
244# tag. The format is ext=language, where ext is a file extension, and language
245# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
246# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
247# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
248# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
249# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
250
251EXTENSION_MAPPING = 49EXTENSION_MAPPING =
252
253# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
254# comments according to the Markdown format, which allows for more readable
255# documentation. See http://daringfireball.net/projects/markdown/ for details.
256# The output of markdown processing is further processed by doxygen, so you
257# can mix doxygen, HTML, and XML commands with Markdown formatting.
258# Disable only in case of backward compatibilities issues.
259
260MARKDOWN_SUPPORT = YES 50MARKDOWN_SUPPORT = YES
261 51TOC_INCLUDE_HEADINGS = 5
262# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 52AUTOLINK_SUPPORT = YES
263# to include (a tag file for) the STL sources as input, then you should
264# set this tag to YES in order to let doxygen match functions declarations and
265# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
266# func(std::string) {}). This also makes the inheritance and collaboration
267# diagrams that involve STL classes more complete and accurate.
268
269BUILTIN_STL_SUPPORT = NO 53BUILTIN_STL_SUPPORT = NO
270
271# If you use Microsoft's C++/CLI language, you should set this option to YES to
272# enable parsing support.
273
274CPP_CLI_SUPPORT = NO 54CPP_CLI_SUPPORT = NO
275
276# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
277# Doxygen will parse them like normal C++ but will assume all classes use public
278# instead of private inheritance when no explicit protection keyword is present.
279
280SIP_SUPPORT = NO 55SIP_SUPPORT = NO
281
282# For Microsoft's IDL there are propget and propput attributes to indicate getter
283# and setter methods for a property. Setting this option to YES (the default)
284# will make doxygen replace the get and set methods by a property in the
285# documentation. This will only work if the methods are indeed getting or
286# setting a simple type. If this is not the case, or you want to show the
287# methods anyway, you should set this option to NO.
288
289IDL_PROPERTY_SUPPORT = YES 56IDL_PROPERTY_SUPPORT = YES
290
291# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
292# tag is set to YES, then doxygen will reuse the documentation of the first
293# member in the group (if any) for the other members of the group. By default
294# all members of a group must be documented explicitly.
295
296DISTRIBUTE_GROUP_DOC = NO 57DISTRIBUTE_GROUP_DOC = NO
297 58GROUP_NESTED_COMPOUNDS = NO
298# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
299# the same type (for instance a group of public functions) to be put as a
300# subgroup of that type (e.g. under the Public Functions section). Set it to
301# NO to prevent subgrouping. Alternatively, this can be done per class using
302# the \nosubgrouping command.
303
304SUBGROUPING = YES 59SUBGROUPING = YES
305
306# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
307# unions are shown inside the group in which they are included (e.g. using
308# @ingroup) instead of on a separate page (for HTML and Man pages) or
309# section (for LaTeX and RTF).
310
311INLINE_GROUPED_CLASSES = NO 60INLINE_GROUPED_CLASSES = NO
312
313# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
314# unions with only public data fields will be shown inline in the documentation
315# of the scope in which they are defined (i.e. file, namespace, or group
316# documentation), provided this scope is documented. If set to NO (the default),
317# structs, classes, and unions are shown on a separate page (for HTML and Man
318# pages) or section (for LaTeX and RTF).
319
320INLINE_SIMPLE_STRUCTS = NO 61INLINE_SIMPLE_STRUCTS = NO
321
322# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
323# is documented as struct, union, or enum with the name of the typedef. So
324# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
325# with name TypeT. When disabled the typedef will appear as a member of a file,
326# namespace, or class. And the struct will be named TypeS. This can typically
327# be useful for C code in case the coding convention dictates that all compound
328# types are typedef'ed and only the typedef is referenced, never the tag name.
329
330TYPEDEF_HIDES_STRUCT = NO 62TYPEDEF_HIDES_STRUCT = NO
331
332# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
333# determine which symbols to keep in memory and which to flush to disk.
334# When the cache is full, less often used symbols will be written to disk.
335# For small to medium size projects (<1000 input files) the default value is
336# probably good enough. For larger projects a too small cache size can cause
337# doxygen to be busy swapping symbols to and from disk most of the time
338# causing a significant performance penalty.
339# If the system has enough physical memory increasing the cache will improve the
340# performance by keeping more symbols in memory. Note that the value works on
341# a logarithmic scale so increasing the size by one will roughly double the
342# memory usage. The cache size is given by this formula:
343# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
344# corresponding to a cache size of 2^16 = 65536 symbols.
345
346SYMBOL_CACHE_SIZE = 0
347
348# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
349# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
350# their name and scope. Since this can be an expensive process and often the
351# same symbol appear multiple times in the code, doxygen keeps a cache of
352# pre-resolved symbols. If the cache is too small doxygen will become slower.
353# If the cache is too large, memory is wasted. The cache size is given by this
354# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
355# corresponding to a cache size of 2^16 = 65536 symbols.
356
357LOOKUP_CACHE_SIZE = 0 63LOOKUP_CACHE_SIZE = 0
358 64NUM_PROC_THREADS = 1
359#--------------------------------------------------------------------------- 65#---------------------------------------------------------------------------
360# Build related configuration options 66# Build related configuration options
361#--------------------------------------------------------------------------- 67#---------------------------------------------------------------------------
362
363# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
364# documentation are documented, even if no documentation was available.
365# Private class members and static file members will be hidden unless
366# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
367
368EXTRACT_ALL = YES 68EXTRACT_ALL = YES
369
370# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
371# will be included in the documentation.
372
373EXTRACT_PRIVATE = YES 69EXTRACT_PRIVATE = YES
374 70EXTRACT_PRIV_VIRTUAL = YES
375# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. 71EXTRACT_PACKAGE = YES
376
377EXTRACT_PACKAGE = NO
378
379# If the EXTRACT_STATIC tag is set to YES all static members of a file
380# will be included in the documentation.
381
382EXTRACT_STATIC = YES 72EXTRACT_STATIC = YES
383
384# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
385# defined locally in source files will be included in the documentation.
386# If set to NO only classes defined in header files are included.
387
388EXTRACT_LOCAL_CLASSES = YES 73EXTRACT_LOCAL_CLASSES = YES
389
390# This flag is only useful for Objective-C code. When set to YES local
391# methods, which are defined in the implementation section but not in
392# the interface are included in the documentation.
393# If set to NO (the default) only methods in the interface are included.
394
395EXTRACT_LOCAL_METHODS = YES 74EXTRACT_LOCAL_METHODS = YES
396 75EXTRACT_ANON_NSPACES = YES
397# If this flag is set to YES, the members of anonymous namespaces will be 76RESOLVE_UNNAMED_PARAMS = YES
398# extracted and appear in the documentation as a namespace called
399# 'anonymous_namespace{file}', where file will be replaced with the base
400# name of the file that contains the anonymous namespace. By default
401# anonymous namespaces are hidden.
402
403EXTRACT_ANON_NSPACES = NO
404
405# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
406# undocumented members of documented classes, files or namespaces.
407# If set to NO (the default) these members will be included in the
408# various overviews, but no documentation section is generated.
409# This option has no effect if EXTRACT_ALL is enabled.
410
411HIDE_UNDOC_MEMBERS = NO 77HIDE_UNDOC_MEMBERS = NO
412
413# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
414# undocumented classes that are normally visible in the class hierarchy.
415# If set to NO (the default) these classes will be included in the various
416# overviews. This option has no effect if EXTRACT_ALL is enabled.
417
418HIDE_UNDOC_CLASSES = NO 78HIDE_UNDOC_CLASSES = NO
419
420# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
421# friend (class|struct|union) declarations.
422# If set to NO (the default) these declarations will be included in the
423# documentation.
424
425HIDE_FRIEND_COMPOUNDS = NO 79HIDE_FRIEND_COMPOUNDS = NO
426
427# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
428# documentation blocks found inside the body of a function.
429# If set to NO (the default) these blocks will be appended to the
430# function's detailed documentation block.
431
432HIDE_IN_BODY_DOCS = NO 80HIDE_IN_BODY_DOCS = NO
433
434# The INTERNAL_DOCS tag determines if documentation
435# that is typed after a \internal command is included. If the tag is set
436# to NO (the default) then the documentation will be excluded.
437# Set it to YES to include the internal documentation.
438
439INTERNAL_DOCS = YES 81INTERNAL_DOCS = YES
440
441# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
442# file names in lower-case letters. If set to YES upper-case letters are also
443# allowed. This is useful if you have classes or files whose names only differ
444# in case and if your file system supports case sensitive file names. Windows
445# and Mac users are advised to set this option to NO.
446
447CASE_SENSE_NAMES = YES 82CASE_SENSE_NAMES = YES
448
449# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
450# will show members with their full class and namespace scopes in the
451# documentation. If set to YES the scope will be hidden.
452
453HIDE_SCOPE_NAMES = NO 83HIDE_SCOPE_NAMES = NO
454 84HIDE_COMPOUND_REFERENCE= NO
455# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 85SHOW_HEADERFILE = YES
456# will put a list of the files that are included by a file in the documentation
457# of that file.
458
459SHOW_INCLUDE_FILES = YES 86SHOW_INCLUDE_FILES = YES
460 87SHOW_GROUPED_MEMB_INC = NO
461# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
462# will list include files with double quotes in the documentation
463# rather than with sharp brackets.
464
465FORCE_LOCAL_INCLUDES = NO 88FORCE_LOCAL_INCLUDES = NO
466
467# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
468# is inserted in the documentation for inline members.
469
470INLINE_INFO = YES 89INLINE_INFO = YES
471
472# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
473# will sort the (detailed) documentation of file and class members
474# alphabetically by member name. If set to NO the members will appear in
475# declaration order.
476
477SORT_MEMBER_DOCS = YES 90SORT_MEMBER_DOCS = YES
478
479# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
480# brief documentation of file, namespace and class members alphabetically
481# by member name. If set to NO (the default) the members will appear in
482# declaration order.
483
484SORT_BRIEF_DOCS = NO 91SORT_BRIEF_DOCS = NO
485
486# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
487# will sort the (brief and detailed) documentation of class members so that
488# constructors and destructors are listed first. If set to NO (the default)
489# the constructors will appear in the respective orders defined by
490# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
491# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
492# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
493
494SORT_MEMBERS_CTORS_1ST = NO 92SORT_MEMBERS_CTORS_1ST = NO
495
496# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
497# hierarchy of group names into alphabetical order. If set to NO (the default)
498# the group names will appear in their defined order.
499
500SORT_GROUP_NAMES = NO 93SORT_GROUP_NAMES = NO
501
502# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
503# sorted by fully-qualified names, including namespaces. If set to
504# NO (the default), the class list will be sorted only by class name,
505# not including the namespace part.
506# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
507# Note: This option applies only to the class list, not to the
508# alphabetical list.
509
510SORT_BY_SCOPE_NAME = NO 94SORT_BY_SCOPE_NAME = NO
511
512# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
513# do proper type resolution of all parameters of a function it will reject a
514# match between the prototype and the implementation of a member function even
515# if there is only one candidate or it is obvious which candidate to choose
516# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
517# will still accept a match between prototype and implementation in such cases.
518
519STRICT_PROTO_MATCHING = NO 95STRICT_PROTO_MATCHING = NO
520
521# The GENERATE_TODOLIST tag can be used to enable (YES) or
522# disable (NO) the todo list. This list is created by putting \todo
523# commands in the documentation.
524
525GENERATE_TODOLIST = YES 96GENERATE_TODOLIST = YES
526
527# The GENERATE_TESTLIST tag can be used to enable (YES) or
528# disable (NO) the test list. This list is created by putting \test
529# commands in the documentation.
530
531GENERATE_TESTLIST = YES 97GENERATE_TESTLIST = YES
532
533# The GENERATE_BUGLIST tag can be used to enable (YES) or
534# disable (NO) the bug list. This list is created by putting \bug
535# commands in the documentation.
536
537GENERATE_BUGLIST = YES 98GENERATE_BUGLIST = YES
538
539# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
540# disable (NO) the deprecated list. This list is created by putting
541# \deprecated commands in the documentation.
542
543GENERATE_DEPRECATEDLIST= YES 99GENERATE_DEPRECATEDLIST= YES
544
545# The ENABLED_SECTIONS tag can be used to enable conditional
546# documentation sections, marked by \if sectionname ... \endif.
547
548ENABLED_SECTIONS = 100ENABLED_SECTIONS =
549
550# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
551# the initial value of a variable or macro consists of for it to appear in
552# the documentation. If the initializer consists of more lines than specified
553# here it will be hidden. Use a value of 0 to hide initializers completely.
554# The appearance of the initializer of individual variables and macros in the
555# documentation can be controlled using \showinitializer or \hideinitializer
556# command in the documentation regardless of this setting.
557
558MAX_INITIALIZER_LINES = 30 101MAX_INITIALIZER_LINES = 30
559
560# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
561# at the bottom of the documentation of classes and structs. If set to YES the
562# list will mention the files that were used to generate the documentation.
563
564SHOW_USED_FILES = YES 102SHOW_USED_FILES = YES
565
566# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
567# This will remove the Files entry from the Quick Index and from the
568# Folder Tree View (if specified). The default is YES.
569
570SHOW_FILES = YES 103SHOW_FILES = YES
571
572# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
573# Namespaces page.
574# This will remove the Namespaces entry from the Quick Index
575# and from the Folder Tree View (if specified). The default is YES.
576
577SHOW_NAMESPACES = YES 104SHOW_NAMESPACES = YES
578
579# The FILE_VERSION_FILTER tag can be used to specify a program or script that
580# doxygen should invoke to get the current version for each file (typically from
581# the version control system). Doxygen will invoke the program by executing (via
582# popen()) the command <command> <input-file>, where <command> is the value of
583# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
584# provided by doxygen. Whatever the program writes to standard output
585# is used as the file version. See the manual for examples.
586
587FILE_VERSION_FILTER = 105FILE_VERSION_FILTER =
588
589# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
590# by doxygen. The layout file controls the global structure of the generated
591# output files in an output format independent way. The create the layout file
592# that represents doxygen's defaults, run doxygen with the -l option.
593# You can optionally specify a file name after the option, if omitted
594# DoxygenLayout.xml will be used as the name of the layout file.
595
596LAYOUT_FILE = 106LAYOUT_FILE =
597
598# The CITE_BIB_FILES tag can be used to specify one or more bib files
599# containing the references data. This must be a list of .bib files. The
600# .bib extension is automatically appended if omitted. Using this command
601# requires the bibtex tool to be installed. See also
602# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
603# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
604# feature you need bibtex and perl available in the search path.
605
606CITE_BIB_FILES = 107CITE_BIB_FILES =
607
608#--------------------------------------------------------------------------- 108#---------------------------------------------------------------------------
609# configuration options related to warning and progress messages 109# Configuration options related to warning and progress messages
610#--------------------------------------------------------------------------- 110#---------------------------------------------------------------------------
611
612# The QUIET tag can be used to turn on/off the messages that are generated
613# by doxygen. Possible values are YES and NO. If left blank NO is used.
614
615QUIET = NO 111QUIET = NO
616
617# The WARNINGS tag can be used to turn on/off the warning messages that are
618# generated by doxygen. Possible values are YES and NO. If left blank
619# NO is used.
620
621WARNINGS = YES 112WARNINGS = YES
622
623# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
624# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
625# automatically be disabled.
626
627WARN_IF_UNDOCUMENTED = YES 113WARN_IF_UNDOCUMENTED = YES
628
629# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
630# potential errors in the documentation, such as not documenting some
631# parameters in a documented function, or documenting parameters that
632# don't exist or using markup commands wrongly.
633
634WARN_IF_DOC_ERROR = YES 114WARN_IF_DOC_ERROR = YES
635 115WARN_IF_INCOMPLETE_DOC = YES
636# The WARN_NO_PARAMDOC option can be enabled to get warnings for
637# functions that are documented, but have no documentation for their parameters
638# or return value. If set to NO (the default) doxygen will only warn about
639# wrong or incomplete parameter documentation, but not about the absence of
640# documentation.
641
642WARN_NO_PARAMDOC = YES 116WARN_NO_PARAMDOC = YES
643 117WARN_AS_ERROR = NO
644# The WARN_FORMAT tag determines the format of the warning messages that
645# doxygen can produce. The string should contain the $file, $line, and $text
646# tags, which will be replaced by the file and line number from which the
647# warning originated and the warning text. Optionally the format may contain
648# $version, which will be replaced by the version of the file (if it could
649# be obtained via FILE_VERSION_FILTER)
650
651WARN_FORMAT = "$file:$line: $text" 118WARN_FORMAT = "$file:$line: $text"
652 119WARN_LINE_FORMAT = "at line $line of file $file"
653# The WARN_LOGFILE tag can be used to specify a file to which warning
654# and error messages should be written. If left blank the output is written
655# to stderr.
656
657WARN_LOGFILE = Doxywarn 120WARN_LOGFILE = Doxywarn
658
659#--------------------------------------------------------------------------- 121#---------------------------------------------------------------------------
660# configuration options related to the input files 122# Configuration options related to the input files
661#--------------------------------------------------------------------------- 123#---------------------------------------------------------------------------
662
663# The INPUT tag can be used to specify the files and/or directories that contain
664# documented source files. You may enter file names like "myfile.cpp" or
665# directories like "/usr/src/myproject". Separate the files or directories
666# with spaces.
667
668INPUT = src \ 124INPUT = src \
669 src/doxy \ 125 src/doxy \
670 src/stable \ 126 src/stable \
671 src/unstable \ 127 src/unstable \
672 src/experimental 128 src/experimental
673
674# This tag can be used to specify the character encoding of the source files
675# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
676# also the default input encoding. Doxygen uses libiconv (or the iconv built
677# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
678# the list of possible encodings.
679
680INPUT_ENCODING = UTF-8 129INPUT_ENCODING = UTF-8
681
682# If the value of the INPUT tag contains directories, you can use the
683# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
684# and *.h) to filter out the source-files in the directories. If left
685# blank the following patterns are tested:
686# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
687# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
688# *.f90 *.f *.for *.vhd *.vhdl
689
690FILE_PATTERNS = *.c \ 130FILE_PATTERNS = *.c \
691 *.cc \ 131 *.cc \
692 *.cxx \ 132 *.cxx \
@@ -733,1119 +173,225 @@ FILE_PATTERNS = *.c \
733 *.moc \ 173 *.moc \
734 *.xpm \ 174 *.xpm \
735 *.dox 175 *.dox
736
737# The RECURSIVE tag can be used to turn specify whether or not subdirectories
738# should be searched for input files as well. Possible values are YES and NO.
739# If left blank NO is used.
740
741RECURSIVE = NO 176RECURSIVE = NO
742
743# The EXCLUDE tag can be used to specify files and/or directories that should be
744# excluded from the INPUT source files. This way you can easily exclude a
745# subdirectory from a directory tree whose root is specified with the INPUT tag.
746# Note that relative paths are relative to the directory from which doxygen is
747# run.
748
749EXCLUDE = 177EXCLUDE =
750
751# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
752# directories that are symbolic links (a Unix file system feature) are excluded
753# from the input.
754
755EXCLUDE_SYMLINKS = NO 178EXCLUDE_SYMLINKS = NO
756
757# If the value of the INPUT tag contains directories, you can use the
758# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
759# certain files from those directories. Note that the wildcards are matched
760# against the file with absolute path, so to exclude all test directories
761# for example use the pattern */test/*
762
763EXCLUDE_PATTERNS = 179EXCLUDE_PATTERNS =
764
765# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
766# (namespaces, classes, functions, etc.) that should be excluded from the
767# output. The symbol name can be a fully qualified name, a word, or if the
768# wildcard * is used, a substring. Examples: ANamespace, AClass,
769# AClass::ANamespace, ANamespace::*Test
770
771EXCLUDE_SYMBOLS = 180EXCLUDE_SYMBOLS =
772
773# The EXAMPLE_PATH tag can be used to specify one or more files or
774# directories that contain example code fragments that are included (see
775# the \include command).
776
777EXAMPLE_PATH = 181EXAMPLE_PATH =
778
779# If the value of the EXAMPLE_PATH tag contains directories, you can use the
780# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
781# and *.h) to filter out the source-files in the directories. If left
782# blank all files are included.
783
784EXAMPLE_PATTERNS = * 182EXAMPLE_PATTERNS = *
785
786# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
787# searched for input files to be used with the \include or \dontinclude
788# commands irrespective of the value of the RECURSIVE tag.
789# Possible values are YES and NO. If left blank NO is used.
790
791EXAMPLE_RECURSIVE = NO 183EXAMPLE_RECURSIVE = NO
792
793# The IMAGE_PATH tag can be used to specify one or more files or
794# directories that contain image that are included in the documentation (see
795# the \image command).
796
797IMAGE_PATH = 184IMAGE_PATH =
798
799# The INPUT_FILTER tag can be used to specify a program that doxygen should
800# invoke to filter for each input file. Doxygen will invoke the filter program
801# by executing (via popen()) the command <filter> <input-file>, where <filter>
802# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
803# input file. Doxygen will then use the output that the filter program writes
804# to standard output.
805# If FILTER_PATTERNS is specified, this tag will be
806# ignored.
807
808INPUT_FILTER = 185INPUT_FILTER =
809
810# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
811# basis.
812# Doxygen will compare the file name with each pattern and apply the
813# filter if there is a match.
814# The filters are a list of the form:
815# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
816# info on how filters are used. If FILTER_PATTERNS is empty or if
817# non of the patterns match the file name, INPUT_FILTER is applied.
818
819FILTER_PATTERNS = 186FILTER_PATTERNS =
820
821# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
822# INPUT_FILTER) will be used to filter the input files when producing source
823# files to browse (i.e. when SOURCE_BROWSER is set to YES).
824
825FILTER_SOURCE_FILES = NO 187FILTER_SOURCE_FILES = NO
826
827# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
828# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
829# and it is also possible to disable source filtering for a specific pattern
830# using *.ext= (so without naming a filter). This option only has effect when
831# FILTER_SOURCE_FILES is enabled.
832
833FILTER_SOURCE_PATTERNS = 188FILTER_SOURCE_PATTERNS =
834 189USE_MDFILE_AS_MAINPAGE =
835#--------------------------------------------------------------------------- 190#---------------------------------------------------------------------------
836# configuration options related to source browsing 191# Configuration options related to source browsing
837#--------------------------------------------------------------------------- 192#---------------------------------------------------------------------------
838
839# If the SOURCE_BROWSER tag is set to YES then a list of source files will
840# be generated. Documented entities will be cross-referenced with these sources.
841# Note: To get rid of all source code in the generated output, make sure also
842# VERBATIM_HEADERS is set to NO.
843
844SOURCE_BROWSER = YES 193SOURCE_BROWSER = YES
845
846# Setting the INLINE_SOURCES tag to YES will include the body
847# of functions and classes directly in the documentation.
848
849INLINE_SOURCES = NO 194INLINE_SOURCES = NO
850
851# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
852# doxygen to hide any special comment blocks from generated source code
853# fragments. Normal C and C++ comments will always remain visible.
854
855STRIP_CODE_COMMENTS = YES 195STRIP_CODE_COMMENTS = YES
856
857# If the REFERENCED_BY_RELATION tag is set to YES
858# then for each documented function all documented
859# functions referencing it will be listed.
860
861REFERENCED_BY_RELATION = YES 196REFERENCED_BY_RELATION = YES
862
863# If the REFERENCES_RELATION tag is set to YES
864# then for each documented function all documented entities
865# called/used by that function will be listed.
866
867REFERENCES_RELATION = YES 197REFERENCES_RELATION = YES
868
869# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
870# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
871# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
872# link to the source code.
873# Otherwise they will link to the documentation.
874
875REFERENCES_LINK_SOURCE = YES 198REFERENCES_LINK_SOURCE = YES
876 199SOURCE_TOOLTIPS = YES
877# If the USE_HTAGS tag is set to YES then the references to source code
878# will point to the HTML generated by the htags(1) tool instead of doxygen
879# built-in source browser. The htags tool is part of GNU's global source
880# tagging system (see http://www.gnu.org/software/global/global.html). You
881# will need version 4.8.6 or higher.
882
883USE_HTAGS = NO 200USE_HTAGS = NO
884
885# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
886# will generate a verbatim copy of the header file for each class for
887# which an include is specified. Set to NO to disable this.
888
889VERBATIM_HEADERS = YES 201VERBATIM_HEADERS = YES
890 202CLANG_ASSISTED_PARSING = YES
203CLANG_ADD_INC_PATHS = YES
204CLANG_OPTIONS =
205CLANG_DATABASE_PATH =
891#--------------------------------------------------------------------------- 206#---------------------------------------------------------------------------
892# configuration options related to the alphabetical class index 207# Configuration options related to the alphabetical class index
893#--------------------------------------------------------------------------- 208#---------------------------------------------------------------------------
894
895# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
896# of all compounds will be generated. Enable this if the project
897# contains a lot of classes, structs, unions or interfaces.
898
899ALPHABETICAL_INDEX = YES 209ALPHABETICAL_INDEX = YES
900
901# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
902# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
903# in which this list will be split (can be a number in the range [1..20])
904
905COLS_IN_ALPHA_INDEX = 4
906
907# In case all classes in a project start with a common prefix, all
908# classes will be put under the same header in the alphabetical index.
909# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
910# should be ignored while generating the index headers.
911
912IGNORE_PREFIX = 210IGNORE_PREFIX =
913
914#--------------------------------------------------------------------------- 211#---------------------------------------------------------------------------
915# configuration options related to the HTML output 212# Configuration options related to the HTML output
916#--------------------------------------------------------------------------- 213#---------------------------------------------------------------------------
917
918# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
919# generate HTML output.
920
921GENERATE_HTML = YES 214GENERATE_HTML = YES
922
923# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
924# If a relative path is entered the value of OUTPUT_DIRECTORY will be
925# put in front of it. If left blank `html' will be used as the default path.
926
927HTML_OUTPUT = html 215HTML_OUTPUT = html
928
929# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
930# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
931# doxygen will generate files with .html extension.
932
933HTML_FILE_EXTENSION = .html 216HTML_FILE_EXTENSION = .html
934
935# The HTML_HEADER tag can be used to specify a personal HTML header for
936# each generated HTML page. If it is left blank doxygen will generate a
937# standard header. Note that when using a custom header you are responsible
938# for the proper inclusion of any scripts and style sheets that doxygen
939# needs, which is dependent on the configuration options used.
940# It is advised to generate a default header using "doxygen -w html
941# header.html footer.html stylesheet.css YourConfigFile" and then modify
942# that header. Note that the header is subject to change so you typically
943# have to redo this when upgrading to a newer version of doxygen or when
944# changing the value of configuration settings such as GENERATE_TREEVIEW!
945
946HTML_HEADER = 217HTML_HEADER =
947
948# The HTML_FOOTER tag can be used to specify a personal HTML footer for
949# each generated HTML page. If it is left blank doxygen will generate a
950# standard footer.
951
952HTML_FOOTER = 218HTML_FOOTER =
953
954# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
955# style sheet that is used by each HTML page. It can be used to
956# fine-tune the look of the HTML output. If the tag is left blank doxygen
957# will generate a default style sheet. Note that doxygen will try to copy
958# the style sheet file to the HTML output directory, so don't put your own
959# style sheet in the HTML output directory as well, or it will be erased!
960
961HTML_STYLESHEET = 219HTML_STYLESHEET =
962 220HTML_EXTRA_STYLESHEET =
963# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
964# other source files which should be copied to the HTML output directory. Note
965# that these files will be copied to the base HTML output directory. Use the
966# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
967# files. In the HTML_STYLESHEET file, use the file name only. Also note that
968# the files will be copied as-is; there are no commands or markers available.
969
970HTML_EXTRA_FILES = 221HTML_EXTRA_FILES =
971
972# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
973# Doxygen will adjust the colors in the style sheet and background images
974# according to this color. Hue is specified as an angle on a colorwheel,
975# see http://en.wikipedia.org/wiki/Hue for more information.
976# For instance the value 0 represents red, 60 is yellow, 120 is green,
977# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
978# The allowed range is 0 to 359.
979
980HTML_COLORSTYLE_HUE = 220 222HTML_COLORSTYLE_HUE = 220
981
982# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
983# the colors in the HTML output. For a value of 0 the output will use
984# grayscales only. A value of 255 will produce the most vivid colors.
985
986HTML_COLORSTYLE_SAT = 100 223HTML_COLORSTYLE_SAT = 100
987
988# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
989# the luminance component of the colors in the HTML output. Values below
990# 100 gradually make the output lighter, whereas values above 100 make
991# the output darker. The value divided by 100 is the actual gamma applied,
992# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
993# and 100 does not change the gamma.
994
995HTML_COLORSTYLE_GAMMA = 80 224HTML_COLORSTYLE_GAMMA = 80
996
997# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
998# page will contain the date and time when the page was generated. Setting
999# this to NO can help when comparing the output of multiple runs.
1000
1001HTML_TIMESTAMP = YES 225HTML_TIMESTAMP = YES
1002 226HTML_DYNAMIC_MENUS = YES
1003# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
1004# documentation will contain sections that can be hidden and shown after the
1005# page has loaded.
1006
1007HTML_DYNAMIC_SECTIONS = YES 227HTML_DYNAMIC_SECTIONS = YES
1008
1009# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
1010# entries shown in the various tree structured indices initially; the user
1011# can expand and collapse entries dynamically later on. Doxygen will expand
1012# the tree to such a level that at most the specified number of entries are
1013# visible (unless a fully collapsed tree already exceeds this amount).
1014# So setting the number of entries 1 will produce a full collapsed tree by
1015# default. 0 is a special value representing an infinite number of entries
1016# and will result in a full expanded tree by default.
1017
1018HTML_INDEX_NUM_ENTRIES = 100 228HTML_INDEX_NUM_ENTRIES = 100
1019
1020# If the GENERATE_DOCSET tag is set to YES, additional index files
1021# will be generated that can be used as input for Apple's Xcode 3
1022# integrated development environment, introduced with OSX 10.5 (Leopard).
1023# To create a documentation set, doxygen will generate a Makefile in the
1024# HTML output directory. Running make will produce the docset in that
1025# directory and running "make install" will install the docset in
1026# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
1027# it at startup.
1028# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
1029# for more information.
1030
1031GENERATE_DOCSET = NO 229GENERATE_DOCSET = NO
1032
1033# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
1034# feed. A documentation feed provides an umbrella under which multiple
1035# documentation sets from a single provider (such as a company or product suite)
1036# can be grouped.
1037
1038DOCSET_FEEDNAME = "Doxygen generated docs" 230DOCSET_FEEDNAME = "Doxygen generated docs"
1039 231DOCSET_FEEDURL =
1040# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
1041# should uniquely identify the documentation set bundle. This should be a
1042# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
1043# will append .docset to the name.
1044
1045DOCSET_BUNDLE_ID = org.doxygen.Project 232DOCSET_BUNDLE_ID = org.doxygen.Project
1046
1047# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
1048# the documentation publisher. This should be a reverse domain-name style
1049# string, e.g. com.mycompany.MyDocSet.documentation.
1050
1051DOCSET_PUBLISHER_ID = org.doxygen.Publisher 233DOCSET_PUBLISHER_ID = org.doxygen.Publisher
1052
1053# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
1054
1055DOCSET_PUBLISHER_NAME = Publisher 234DOCSET_PUBLISHER_NAME = Publisher
1056
1057# If the GENERATE_HTMLHELP tag is set to YES, additional index files
1058# will be generated that can be used as input for tools like the
1059# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
1060# of the generated HTML documentation.
1061
1062GENERATE_HTMLHELP = NO 235GENERATE_HTMLHELP = NO
1063
1064# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
1065# be used to specify the file name of the resulting .chm file. You
1066# can add a path in front of the file if the result should not be
1067# written to the html output directory.
1068
1069CHM_FILE = 236CHM_FILE =
1070
1071# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
1072# be used to specify the location (absolute path including file name) of
1073# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
1074# the HTML help compiler on the generated index.hhp.
1075
1076HHC_LOCATION = 237HHC_LOCATION =
1077
1078# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
1079# controls if a separate .chi index file is generated (YES) or that
1080# it should be included in the master .chm file (NO).
1081
1082GENERATE_CHI = NO 238GENERATE_CHI = NO
1083
1084# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
1085# is used to encode HtmlHelp index (hhk), content (hhc) and project file
1086# content.
1087
1088CHM_INDEX_ENCODING = 239CHM_INDEX_ENCODING =
1089
1090# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
1091# controls whether a binary table of contents is generated (YES) or a
1092# normal table of contents (NO) in the .chm file.
1093
1094BINARY_TOC = NO 240BINARY_TOC = NO
1095
1096# The TOC_EXPAND flag can be set to YES to add extra items for group members
1097# to the contents of the HTML help documentation and to the tree view.
1098
1099TOC_EXPAND = NO 241TOC_EXPAND = NO
1100
1101# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
1102# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
1103# that can be used as input for Qt's qhelpgenerator to generate a
1104# Qt Compressed Help (.qch) of the generated HTML documentation.
1105
1106GENERATE_QHP = NO 242GENERATE_QHP = NO
1107
1108# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
1109# be used to specify the file name of the resulting .qch file.
1110# The path specified is relative to the HTML output folder.
1111
1112QCH_FILE = 243QCH_FILE =
1113
1114# The QHP_NAMESPACE tag specifies the namespace to use when generating
1115# Qt Help Project output. For more information please see
1116# http://doc.trolltech.com/qthelpproject.html#namespace
1117
1118QHP_NAMESPACE = 244QHP_NAMESPACE =
1119
1120# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
1121# Qt Help Project output. For more information please see
1122# http://doc.trolltech.com/qthelpproject.html#virtual-folders
1123
1124QHP_VIRTUAL_FOLDER = doc 245QHP_VIRTUAL_FOLDER = doc
1125
1126# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
1127# add. For more information please see
1128# http://doc.trolltech.com/qthelpproject.html#custom-filters
1129
1130QHP_CUST_FILTER_NAME = 246QHP_CUST_FILTER_NAME =
1131
1132# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
1133# custom filter to add. For more information please see
1134# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
1135# Qt Help Project / Custom Filters</a>.
1136
1137QHP_CUST_FILTER_ATTRS = 247QHP_CUST_FILTER_ATTRS =
1138
1139# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
1140# project's
1141# filter section matches.
1142# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
1143# Qt Help Project / Filter Attributes</a>.
1144
1145QHP_SECT_FILTER_ATTRS = 248QHP_SECT_FILTER_ATTRS =
1146
1147# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
1148# be used to specify the location of Qt's qhelpgenerator.
1149# If non-empty doxygen will try to run qhelpgenerator on the generated
1150# .qhp file.
1151
1152QHG_LOCATION = 249QHG_LOCATION =
1153
1154# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
1155# will be generated, which together with the HTML files, form an Eclipse help
1156# plugin. To install this plugin and make it available under the help contents
1157# menu in Eclipse, the contents of the directory containing the HTML and XML
1158# files needs to be copied into the plugins directory of eclipse. The name of
1159# the directory within the plugins directory should be the same as
1160# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
1161# the help appears.
1162
1163GENERATE_ECLIPSEHELP = NO 250GENERATE_ECLIPSEHELP = NO
1164
1165# A unique identifier for the eclipse help plugin. When installing the plugin
1166# the directory name containing the HTML and XML files should also have
1167# this name.
1168
1169ECLIPSE_DOC_ID = org.doxygen.Project 251ECLIPSE_DOC_ID = org.doxygen.Project
1170
1171# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
1172# at top of each HTML page. The value NO (the default) enables the index and
1173# the value YES disables it. Since the tabs have the same information as the
1174# navigation tree you can set this option to NO if you already set
1175# GENERATE_TREEVIEW to YES.
1176
1177DISABLE_INDEX = NO 252DISABLE_INDEX = NO
1178
1179# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
1180# structure should be generated to display hierarchical information.
1181# If the tag value is set to YES, a side panel will be generated
1182# containing a tree-like index structure (just like the one that
1183# is generated for HTML Help). For this to work a browser that supports
1184# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
1185# Windows users are probably better off using the HTML help feature.
1186# Since the tree basically has the same information as the tab index you
1187# could consider to set DISABLE_INDEX to NO when enabling this option.
1188
1189GENERATE_TREEVIEW = NO 253GENERATE_TREEVIEW = NO
1190 254FULL_SIDEBAR = NO
1191# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
1192# (range [0,1..20]) that doxygen will group on one line in the generated HTML
1193# documentation. Note that a value of 0 will completely suppress the enum
1194# values from appearing in the overview section.
1195
1196ENUM_VALUES_PER_LINE = 4 255ENUM_VALUES_PER_LINE = 4
1197
1198# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
1199# used to set the initial width (in pixels) of the frame in which the tree
1200# is shown.
1201
1202TREEVIEW_WIDTH = 250 256TREEVIEW_WIDTH = 250
1203
1204# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
1205# links to external symbols imported via tag files in a separate window.
1206
1207EXT_LINKS_IN_WINDOW = NO 257EXT_LINKS_IN_WINDOW = NO
1208 258OBFUSCATE_EMAILS = YES
1209# Use this tag to change the font size of Latex formulas included 259HTML_FORMULA_FORMAT = png
1210# as images in the HTML documentation. The default is 10. Note that
1211# when you change the font size after a successful doxygen run you need
1212# to manually remove any form_*.png images from the HTML output directory
1213# to force them to be regenerated.
1214
1215FORMULA_FONTSIZE = 10 260FORMULA_FONTSIZE = 10
1216
1217# Use the FORMULA_TRANPARENT tag to determine whether or not the images
1218# generated for formulas are transparent PNGs. Transparent PNGs are
1219# not supported properly for IE 6.0, but are supported on all modern browsers.
1220# Note that when changing this option you need to delete any form_*.png files
1221# in the HTML output before the changes have effect.
1222
1223FORMULA_TRANSPARENT = YES 261FORMULA_TRANSPARENT = YES
1224 262FORMULA_MACROFILE =
1225# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
1226# (see http://www.mathjax.org) which uses client side Javascript for the
1227# rendering instead of using prerendered bitmaps. Use this if you do not
1228# have LaTeX installed or if you want to formulas look prettier in the HTML
1229# output. When enabled you may also need to install MathJax separately and
1230# configure the path to it using the MATHJAX_RELPATH option.
1231
1232USE_MATHJAX = NO 263USE_MATHJAX = NO
1233 264MATHJAX_VERSION = MathJax_2
1234# When MathJax is enabled you need to specify the location relative to the 265MATHJAX_FORMAT = HTML-CSS
1235# HTML output directory using the MATHJAX_RELPATH option. The destination
1236# directory should contain the MathJax.js script. For instance, if the mathjax
1237# directory is located at the same level as the HTML output directory, then
1238# MATHJAX_RELPATH should be ../mathjax. The default value points to
1239# the MathJax Content Delivery Network so you can quickly see the result without
1240# installing MathJax.
1241# However, it is strongly recommended to install a local
1242# copy of MathJax from http://www.mathjax.org before deployment.
1243
1244MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest 266MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
1245
1246# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
1247# names that should be enabled during MathJax rendering.
1248
1249MATHJAX_EXTENSIONS = 267MATHJAX_EXTENSIONS =
1250 268MATHJAX_CODEFILE =
1251# When the SEARCHENGINE tag is enabled doxygen will generate a search box
1252# for the HTML output. The underlying search engine uses javascript
1253# and DHTML and should work on any modern browser. Note that when using
1254# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
1255# (GENERATE_DOCSET) there is already a search function so this one should
1256# typically be disabled. For large projects the javascript based search engine
1257# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
1258
1259SEARCHENGINE = NO 269SEARCHENGINE = NO
1260
1261# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
1262# implemented using a PHP enabled web server instead of at the web client
1263# using Javascript. Doxygen will generate the search PHP script and index
1264# file to put on the web server. The advantage of the server
1265# based approach is that it scales better to large projects and allows
1266# full text search. The disadvantages are that it is more difficult to setup
1267# and does not have live searching capabilities.
1268
1269SERVER_BASED_SEARCH = NO 270SERVER_BASED_SEARCH = NO
1270 271EXTERNAL_SEARCH = NO
272SEARCHENGINE_URL =
273SEARCHDATA_FILE = searchdata.xml
274EXTERNAL_SEARCH_ID =
275EXTRA_SEARCH_MAPPINGS =
1271#--------------------------------------------------------------------------- 276#---------------------------------------------------------------------------
1272# configuration options related to the LaTeX output 277# Configuration options related to the LaTeX output
1273#--------------------------------------------------------------------------- 278#---------------------------------------------------------------------------
1274
1275# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
1276# generate Latex output.
1277
1278GENERATE_LATEX = yes 279GENERATE_LATEX = yes
1279
1280# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
1281# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1282# put in front of it. If left blank `latex' will be used as the default path.
1283
1284LATEX_OUTPUT = latex 280LATEX_OUTPUT = latex
1285
1286# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
1287# invoked. If left blank `latex' will be used as the default command name.
1288# Note that when enabling USE_PDFLATEX this option is only used for
1289# generating bitmaps for formulas in the HTML output, but not in the
1290# Makefile that is written to the output directory.
1291
1292LATEX_CMD_NAME = latex 281LATEX_CMD_NAME = latex
1293
1294# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
1295# generate index for LaTeX. If left blank `makeindex' will be used as the
1296# default command name.
1297
1298MAKEINDEX_CMD_NAME = makeindex 282MAKEINDEX_CMD_NAME = makeindex
1299 283LATEX_MAKEINDEX_CMD = makeindex
1300# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
1301# LaTeX documents. This may be useful for small projects and may help to
1302# save some trees in general.
1303
1304COMPACT_LATEX = NO 284COMPACT_LATEX = NO
1305
1306# The PAPER_TYPE tag can be used to set the paper type that is used
1307# by the printer. Possible values are: a4, letter, legal and
1308# executive. If left blank a4wide will be used.
1309
1310PAPER_TYPE = letter 285PAPER_TYPE = letter
1311
1312# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
1313# packages that should be included in the LaTeX output.
1314
1315EXTRA_PACKAGES = 286EXTRA_PACKAGES =
1316
1317# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
1318# the generated latex document. The header should contain everything until
1319# the first chapter. If it is left blank doxygen will generate a
1320# standard header. Notice: only use this tag if you know what you are doing!
1321
1322LATEX_HEADER = 287LATEX_HEADER =
1323
1324# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
1325# the generated latex document. The footer should contain everything after
1326# the last chapter. If it is left blank doxygen will generate a
1327# standard footer. Notice: only use this tag if you know what you are doing!
1328
1329LATEX_FOOTER = 288LATEX_FOOTER =
1330 289LATEX_EXTRA_STYLESHEET =
1331# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 290LATEX_EXTRA_FILES =
1332# is prepared for conversion to pdf (using ps2pdf). The pdf file will
1333# contain links (just like the HTML output) instead of page references
1334# This makes the output suitable for online browsing using a pdf viewer.
1335
1336PDF_HYPERLINKS = YES 291PDF_HYPERLINKS = YES
1337
1338# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
1339# plain latex in the generated Makefile. Set this option to YES to get a
1340# higher quality PDF documentation.
1341
1342USE_PDFLATEX = YES 292USE_PDFLATEX = YES
1343
1344# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
1345# command to the generated LaTeX files. This will instruct LaTeX to keep
1346# running if errors occur, instead of asking the user for help.
1347# This option is also used when generating formulas in HTML.
1348
1349LATEX_BATCHMODE = YES 293LATEX_BATCHMODE = YES
1350
1351# If LATEX_HIDE_INDICES is set to YES then doxygen will not
1352# include the index chapters (such as File Index, Compound Index, etc.)
1353# in the output.
1354
1355LATEX_HIDE_INDICES = NO 294LATEX_HIDE_INDICES = NO
1356
1357# If LATEX_SOURCE_CODE is set to YES then doxygen will include
1358# source code with syntax highlighting in the LaTeX output.
1359# Note that which sources are shown also depends on other settings
1360# such as SOURCE_BROWSER.
1361
1362LATEX_SOURCE_CODE = NO
1363
1364# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
1365# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
1366# http://en.wikipedia.org/wiki/BibTeX for more info.
1367
1368LATEX_BIB_STYLE = plain 295LATEX_BIB_STYLE = plain
1369 296LATEX_TIMESTAMP = NO
297LATEX_EMOJI_DIRECTORY =
1370#--------------------------------------------------------------------------- 298#---------------------------------------------------------------------------
1371# configuration options related to the RTF output 299# Configuration options related to the RTF output
1372#--------------------------------------------------------------------------- 300#---------------------------------------------------------------------------
1373
1374# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
1375# The RTF output is optimized for Word 97 and may not look very pretty with
1376# other RTF readers or editors.
1377
1378GENERATE_RTF = NO 301GENERATE_RTF = NO
1379
1380# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
1381# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1382# put in front of it. If left blank `rtf' will be used as the default path.
1383
1384RTF_OUTPUT = rtf 302RTF_OUTPUT = rtf
1385
1386# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
1387# RTF documents. This may be useful for small projects and may help to
1388# save some trees in general.
1389
1390COMPACT_RTF = NO 303COMPACT_RTF = NO
1391
1392# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
1393# will contain hyperlink fields. The RTF file will
1394# contain links (just like the HTML output) instead of page references.
1395# This makes the output suitable for online browsing using WORD or other
1396# programs which support those fields.
1397# Note: wordpad (write) and others do not support links.
1398
1399RTF_HYPERLINKS = YES 304RTF_HYPERLINKS = YES
1400
1401# Load style sheet definitions from file. Syntax is similar to doxygen's
1402# config file, i.e. a series of assignments. You only have to provide
1403# replacements, missing definitions are set to their default value.
1404
1405RTF_STYLESHEET_FILE = 305RTF_STYLESHEET_FILE =
1406
1407# Set optional variables used in the generation of an rtf document.
1408# Syntax is similar to doxygen's config file.
1409
1410RTF_EXTENSIONS_FILE = 306RTF_EXTENSIONS_FILE =
1411
1412#--------------------------------------------------------------------------- 307#---------------------------------------------------------------------------
1413# configuration options related to the man page output 308# Configuration options related to the man page output
1414#--------------------------------------------------------------------------- 309#---------------------------------------------------------------------------
1415
1416# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
1417# generate man pages
1418
1419GENERATE_MAN = NO 310GENERATE_MAN = NO
1420
1421# The MAN_OUTPUT tag is used to specify where the man pages will be put.
1422# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1423# put in front of it. If left blank `man' will be used as the default path.
1424
1425MAN_OUTPUT = man 311MAN_OUTPUT = man
1426
1427# The MAN_EXTENSION tag determines the extension that is added to
1428# the generated man pages (default is the subroutine's section .3)
1429
1430MAN_EXTENSION = .3 312MAN_EXTENSION = .3
1431 313MAN_SUBDIR =
1432# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
1433# then it will generate one additional man file for each entity
1434# documented in the real man page(s). These additional files
1435# only source the real man page, but without them the man command
1436# would be unable to find the correct page. The default is NO.
1437
1438MAN_LINKS = NO 314MAN_LINKS = NO
1439
1440#--------------------------------------------------------------------------- 315#---------------------------------------------------------------------------
1441# configuration options related to the XML output 316# Configuration options related to the XML output
1442#--------------------------------------------------------------------------- 317#---------------------------------------------------------------------------
1443
1444# If the GENERATE_XML tag is set to YES Doxygen will
1445# generate an XML file that captures the structure of
1446# the code including all documentation.
1447
1448GENERATE_XML = NO 318GENERATE_XML = NO
1449
1450# The XML_OUTPUT tag is used to specify where the XML pages will be put.
1451# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1452# put in front of it. If left blank `xml' will be used as the default path.
1453
1454XML_OUTPUT = xml 319XML_OUTPUT = xml
1455
1456# The XML_SCHEMA tag can be used to specify an XML schema,
1457# which can be used by a validating XML parser to check the
1458# syntax of the XML files.
1459
1460XML_SCHEMA =
1461
1462# The XML_DTD tag can be used to specify an XML DTD,
1463# which can be used by a validating XML parser to check the
1464# syntax of the XML files.
1465
1466XML_DTD =
1467
1468# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
1469# dump the program listings (including syntax highlighting
1470# and cross-referencing information) to the XML output. Note that
1471# enabling this will significantly increase the size of the XML output.
1472
1473XML_PROGRAMLISTING = YES 320XML_PROGRAMLISTING = YES
1474 321XML_NS_MEMB_FILE_SCOPE = NO
1475#--------------------------------------------------------------------------- 322#---------------------------------------------------------------------------
1476# configuration options for the AutoGen Definitions output 323# Configuration options related to the DOCBOOK output
324#---------------------------------------------------------------------------
325GENERATE_DOCBOOK = NO
326DOCBOOK_OUTPUT = docbook
327#---------------------------------------------------------------------------
328# Configuration options for the AutoGen Definitions output
1477#--------------------------------------------------------------------------- 329#---------------------------------------------------------------------------
1478
1479# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
1480# generate an AutoGen Definitions (see autogen.sf.net) file
1481# that captures the structure of the code including all
1482# documentation. Note that this feature is still experimental
1483# and incomplete at the moment.
1484
1485GENERATE_AUTOGEN_DEF = NO 330GENERATE_AUTOGEN_DEF = NO
1486
1487#--------------------------------------------------------------------------- 331#---------------------------------------------------------------------------
1488# configuration options related to the Perl module output 332# Configuration options related to the Perl module output
1489#--------------------------------------------------------------------------- 333#---------------------------------------------------------------------------
1490
1491# If the GENERATE_PERLMOD tag is set to YES Doxygen will
1492# generate a Perl module file that captures the structure of
1493# the code including all documentation. Note that this
1494# feature is still experimental and incomplete at the
1495# moment.
1496
1497GENERATE_PERLMOD = NO 334GENERATE_PERLMOD = NO
1498
1499# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
1500# the necessary Makefile rules, Perl scripts and LaTeX code to be able
1501# to generate PDF and DVI output from the Perl module output.
1502
1503PERLMOD_LATEX = YES 335PERLMOD_LATEX = YES
1504
1505# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
1506# nicely formatted so it can be parsed by a human reader.
1507# This is useful
1508# if you want to understand what is going on.
1509# On the other hand, if this
1510# tag is set to NO the size of the Perl module output will be much smaller
1511# and Perl will parse it just the same.
1512
1513PERLMOD_PRETTY = YES 336PERLMOD_PRETTY = YES
1514
1515# The names of the make variables in the generated doxyrules.make file
1516# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
1517# This is useful so different doxyrules.make files included by the same
1518# Makefile don't overwrite each other's variables.
1519
1520PERLMOD_MAKEVAR_PREFIX = 337PERLMOD_MAKEVAR_PREFIX =
1521
1522#--------------------------------------------------------------------------- 338#---------------------------------------------------------------------------
1523# Configuration options related to the preprocessor 339# Configuration options related to the preprocessor
1524#--------------------------------------------------------------------------- 340#---------------------------------------------------------------------------
1525
1526# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
1527# evaluate all C-preprocessor directives found in the sources and include
1528# files.
1529
1530ENABLE_PREPROCESSING = YES 341ENABLE_PREPROCESSING = YES
1531
1532# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
1533# names in the source code. If set to NO (the default) only conditional
1534# compilation will be performed. Macro expansion can be done in a controlled
1535# way by setting EXPAND_ONLY_PREDEF to YES.
1536
1537MACRO_EXPANSION = YES 342MACRO_EXPANSION = YES
1538
1539# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
1540# then the macro expansion is limited to the macros specified with the
1541# PREDEFINED and EXPAND_AS_DEFINED tags.
1542
1543EXPAND_ONLY_PREDEF = NO 343EXPAND_ONLY_PREDEF = NO
1544
1545# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
1546# pointed to by INCLUDE_PATH will be searched when a #include is found.
1547
1548SEARCH_INCLUDES = YES 344SEARCH_INCLUDES = YES
1549
1550# The INCLUDE_PATH tag can be used to specify one or more directories that
1551# contain include files that are not input files but should be processed by
1552# the preprocessor.
1553
1554INCLUDE_PATH = 345INCLUDE_PATH =
1555
1556# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
1557# patterns (like *.h and *.hpp) to filter out the header-files in the
1558# directories. If left blank, the patterns specified with FILE_PATTERNS will
1559# be used.
1560
1561INCLUDE_FILE_PATTERNS = 346INCLUDE_FILE_PATTERNS =
1562
1563# The PREDEFINED tag can be used to specify one or more macro names that
1564# are defined before the preprocessor is started (similar to the -D option of
1565# gcc). The argument of the tag is a list of macros of the form: name
1566# or name=definition (no spaces). If the definition and the = are
1567# omitted =1 is assumed. To prevent a macro definition from being
1568# undefined via #undef or recursively expanded use the := operator
1569# instead of the = operator.
1570
1571PREDEFINED = 347PREDEFINED =
1572
1573# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
1574# this tag can be used to specify a list of macro names that should be expanded.
1575# The macro definition that is found in the sources will be used.
1576# Use the PREDEFINED tag if you want to use a different macro definition that
1577# overrules the definition found in the source code.
1578
1579EXPAND_AS_DEFINED = 348EXPAND_AS_DEFINED =
1580
1581# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
1582# doxygen's preprocessor will remove all references to function-like macros
1583# that are alone on a line, have an all uppercase name, and do not end with a
1584# semicolon, because these will confuse the parser if not removed.
1585
1586SKIP_FUNCTION_MACROS = YES 349SKIP_FUNCTION_MACROS = YES
1587
1588#--------------------------------------------------------------------------- 350#---------------------------------------------------------------------------
1589# Configuration::additions related to external references 351# Configuration options related to external references
1590#--------------------------------------------------------------------------- 352#---------------------------------------------------------------------------
1591
1592# The TAGFILES option can be used to specify one or more tagfiles. For each
1593# tag file the location of the external documentation should be added. The
1594# format of a tag file without this location is as follows:
1595#
1596# TAGFILES = file1 file2 ...
1597# Adding location for the tag files is done as follows:
1598#
1599# TAGFILES = file1=loc1 "file2 = loc2" ...
1600# where "loc1" and "loc2" can be relative or absolute paths
1601# or URLs. Note that each tag file must have a unique name (where the name does
1602# NOT include the path). If a tag file is not located in the directory in which
1603# doxygen is run, you must also specify the path to the tagfile here.
1604
1605TAGFILES = 353TAGFILES =
1606
1607# When a file name is specified after GENERATE_TAGFILE, doxygen will create
1608# a tag file that is based on the input files it reads.
1609
1610GENERATE_TAGFILE = 354GENERATE_TAGFILE =
1611
1612# If the ALLEXTERNALS tag is set to YES all external classes will be listed
1613# in the class index. If set to NO only the inherited external classes
1614# will be listed.
1615
1616ALLEXTERNALS = NO 355ALLEXTERNALS = NO
1617
1618# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
1619# in the modules index. If set to NO, only the current project's groups will
1620# be listed.
1621
1622EXTERNAL_GROUPS = YES 356EXTERNAL_GROUPS = YES
1623 357EXTERNAL_PAGES = YES
1624# The PERL_PATH should be the absolute path and name of the perl script
1625# interpreter (i.e. the result of `which perl').
1626
1627PERL_PATH = /usr/bin/perl
1628
1629#--------------------------------------------------------------------------- 358#---------------------------------------------------------------------------
1630# Configuration options related to the dot tool 359# Configuration options related to the dot tool
1631#--------------------------------------------------------------------------- 360#---------------------------------------------------------------------------
1632 361DIA_PATH =
1633# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
1634# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
1635# or super classes. Setting the tag to NO turns the diagrams off. Note that
1636# this option also works with HAVE_DOT disabled, but it is recommended to
1637# install and use dot, since it yields more powerful graphs.
1638
1639CLASS_DIAGRAMS = YES
1640
1641# You can define message sequence charts within doxygen comments using the \msc
1642# command. Doxygen will then run the mscgen tool (see
1643# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
1644# documentation. The MSCGEN_PATH tag allows you to specify the directory where
1645# the mscgen tool resides. If left empty the tool is assumed to be found in the
1646# default search path.
1647
1648MSCGEN_PATH =
1649
1650# If set to YES, the inheritance and collaboration graphs will hide
1651# inheritance and usage relations if the target is undocumented
1652# or is not a class.
1653
1654HIDE_UNDOC_RELATIONS = YES 362HIDE_UNDOC_RELATIONS = YES
1655
1656# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
1657# available from the path. This tool is part of Graphviz, a graph visualization
1658# toolkit from AT&T and Lucent Bell Labs. The other options in this section
1659# have no effect if this option is set to NO (the default)
1660
1661HAVE_DOT = YES 363HAVE_DOT = YES
1662
1663# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
1664# allowed to run in parallel. When set to 0 (the default) doxygen will
1665# base this on the number of processors available in the system. You can set it
1666# explicitly to a value larger than 0 to get control over the balance
1667# between CPU load and processing speed.
1668
1669DOT_NUM_THREADS = 0 364DOT_NUM_THREADS = 0
1670
1671# By default doxygen will use the Helvetica font for all dot files that
1672# doxygen generates. When you want a differently looking font you can specify
1673# the font name using DOT_FONTNAME. You need to make sure dot is able to find
1674# the font, which can be done by putting it in a standard location or by setting
1675# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
1676# directory containing the font.
1677
1678DOT_FONTNAME = FreeSans 365DOT_FONTNAME = FreeSans
1679
1680# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
1681# The default size is 10pt.
1682
1683DOT_FONTSIZE = 10 366DOT_FONTSIZE = 10
1684
1685# By default doxygen will tell dot to use the Helvetica font.
1686# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
1687# set the path where dot can find it.
1688
1689DOT_FONTPATH = 367DOT_FONTPATH =
1690
1691# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
1692# will generate a graph for each documented class showing the direct and
1693# indirect inheritance relations. Setting this tag to YES will force the
1694# CLASS_DIAGRAMS tag to NO.
1695
1696CLASS_GRAPH = YES 368CLASS_GRAPH = YES
1697
1698# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
1699# will generate a graph for each documented class showing the direct and
1700# indirect implementation dependencies (inheritance, containment, and
1701# class references variables) of the class with other documented classes.
1702
1703COLLABORATION_GRAPH = YES 369COLLABORATION_GRAPH = YES
1704
1705# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
1706# will generate a graph for groups, showing the direct groups dependencies
1707
1708GROUP_GRAPHS = YES 370GROUP_GRAPHS = YES
1709
1710# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
1711# collaboration diagrams in a style similar to the OMG's Unified Modeling
1712# Language.
1713
1714UML_LOOK = NO 371UML_LOOK = NO
1715
1716# If the UML_LOOK tag is enabled, the fields and methods are shown inside
1717# the class node. If there are many fields or methods and many nodes the
1718# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
1719# threshold limits the number of items for each type to make the size more
1720# managable. Set this to 0 for no limit. Note that the threshold may be
1721# exceeded by 50% before the limit is enforced.
1722
1723UML_LIMIT_NUM_FIELDS = 10 372UML_LIMIT_NUM_FIELDS = 10
1724 373DOT_UML_DETAILS = NO
1725# If set to YES, the inheritance and collaboration graphs will show the 374DOT_WRAP_THRESHOLD = 17
1726# relations between templates and their instances.
1727
1728TEMPLATE_RELATIONS = NO 375TEMPLATE_RELATIONS = NO
1729
1730# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
1731# tags are set to YES then doxygen will generate a graph for each documented
1732# file showing the direct and indirect include dependencies of the file with
1733# other documented files.
1734
1735INCLUDE_GRAPH = YES 376INCLUDE_GRAPH = YES
1736
1737# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
1738# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
1739# documented header file showing the documented files that directly or
1740# indirectly include this file.
1741
1742INCLUDED_BY_GRAPH = YES 377INCLUDED_BY_GRAPH = YES
1743 378CALL_GRAPH = YES
1744# If the CALL_GRAPH and HAVE_DOT options are set to YES then 379CALLER_GRAPH = YES
1745# doxygen will generate a call dependency graph for every global function
1746# or class method. Note that enabling this option will significantly increase
1747# the time of a run. So in most cases it will be better to enable call graphs
1748# for selected functions only using the \callgraph command.
1749
1750CALL_GRAPH = NO
1751
1752# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
1753# doxygen will generate a caller dependency graph for every global function
1754# or class method. Note that enabling this option will significantly increase
1755# the time of a run. So in most cases it will be better to enable caller
1756# graphs for selected functions only using the \callergraph command.
1757
1758CALLER_GRAPH = NO
1759
1760# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
1761# will generate a graphical hierarchy of all classes instead of a textual one.
1762
1763GRAPHICAL_HIERARCHY = YES 380GRAPHICAL_HIERARCHY = YES
1764
1765# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
1766# then doxygen will show the dependencies a directory has on other directories
1767# in a graphical way. The dependency relations are determined by the #include
1768# relations between the files in the directories.
1769
1770DIRECTORY_GRAPH = NO 381DIRECTORY_GRAPH = NO
1771 382DIR_GRAPH_MAX_DEPTH = 1
1772# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
1773# generated by dot. Possible values are svg, png, jpg, or gif.
1774# If left blank png will be used. If you choose svg you need to set
1775# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
1776# visible in IE 9+ (other browsers do not have this requirement).
1777
1778DOT_IMAGE_FORMAT = png 383DOT_IMAGE_FORMAT = png
1779 384INTERACTIVE_SVG = YES
1780# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
1781# enable generation of interactive SVG images that allow zooming and panning.
1782# Note that this requires a modern browser other than Internet Explorer.
1783# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
1784# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
1785# visible. Older versions of IE do not have SVG support.
1786
1787INTERACTIVE_SVG = NO
1788
1789# The tag DOT_PATH can be used to specify the path where the dot tool can be
1790# found. If left blank, it is assumed the dot tool can be found in the path.
1791
1792DOT_PATH = 385DOT_PATH =
1793
1794# The DOTFILE_DIRS tag can be used to specify one or more directories that
1795# contain dot files that are included in the documentation (see the
1796# \dotfile command).
1797
1798DOTFILE_DIRS = 386DOTFILE_DIRS =
1799
1800# The MSCFILE_DIRS tag can be used to specify one or more directories that
1801# contain msc files that are included in the documentation (see the
1802# \mscfile command).
1803
1804MSCFILE_DIRS = 387MSCFILE_DIRS =
1805 388DIAFILE_DIRS =
1806# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 389PLANTUML_JAR_PATH =
1807# nodes that will be shown in the graph. If the number of nodes in a graph 390PLANTUML_CFG_FILE =
1808# becomes larger than this value, doxygen will truncate the graph, which is 391PLANTUML_INCLUDE_PATH =
1809# visualized by representing a node as a red box. Note that doxygen if the
1810# number of direct children of the root node in a graph is already larger than
1811# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
1812# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
1813
1814DOT_GRAPH_MAX_NODES = 50 392DOT_GRAPH_MAX_NODES = 50
1815
1816# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
1817# graphs generated by dot. A depth value of 3 means that only nodes reachable
1818# from the root by following a path via at most 3 edges will be shown. Nodes
1819# that lay further from the root node will be omitted. Note that setting this
1820# option to 1 or 2 may greatly reduce the computation time needed for large
1821# code bases. Also note that the size of a graph can be further restricted by
1822# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
1823
1824MAX_DOT_GRAPH_DEPTH = 1000 393MAX_DOT_GRAPH_DEPTH = 1000
1825
1826# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
1827# background. This is disabled by default, because dot on Windows does not
1828# seem to support this out of the box. Warning: Depending on the platform used,
1829# enabling this option may lead to badly anti-aliased labels on the edges of
1830# a graph (i.e. they become hard to read).
1831
1832DOT_TRANSPARENT = NO 394DOT_TRANSPARENT = NO
1833
1834# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
1835# files in one run (i.e. multiple -o and -T options on the command line). This
1836# makes dot run faster, but since only newer versions of dot (>1.8.10)
1837# support this, this feature is disabled by default.
1838
1839DOT_MULTI_TARGETS = NO 395DOT_MULTI_TARGETS = NO
1840
1841# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
1842# generate a legend page explaining the meaning of the various boxes and
1843# arrows in the dot generated graphs.
1844
1845GENERATE_LEGEND = YES 396GENERATE_LEGEND = YES
1846
1847# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
1848# remove the intermediate dot files that are used to generate
1849# the various graphs.
1850
1851DOT_CLEANUP = YES 397DOT_CLEANUP = YES
diff --git a/src/experimental/debugmutex.cpp b/src/experimental/debugmutex.cpp
new file mode 100644
index 0000000..2b61ae2
--- /dev/null
+++ b/src/experimental/debugmutex.cpp
@@ -0,0 +1,78 @@
1#include "bu/debugmutex.h"
2
3#include "bu/exceptionbase.h"
4
5Bu::DebugMutex::DebugMutex()
6{
7}
8
9Bu::DebugMutex::~DebugMutex()
10{
11}
12
13int Bu::DebugMutex::lock()
14{
15 pthread_t self = pthread_self();
16 mState.lock();
17 bool bFound = false;
18 for( ThreadList::iterator i = lThreads.begin(); i; i++ )
19 {
20 if( (*i) == self )
21 {
22 bFound = true;
23 if( (*i).bLocked == true )
24 {
25 throw Bu::ExceptionBase( Bu::String("Double lock in thread: %1").arg( (*i).sName ).end().getStr() );
26
27 }
28 else
29 {
30 (*i).bLocked = true;
31 }
32 break;
33 }
34 }
35 if( bFound == false )
36 {
37 lThreads.append( ThreadInfo( true ) );
38 }
39 mState.unlock();
40 return Bu::Mutex::lock();
41}
42
43int Bu::DebugMutex::unlock()
44{
45 pthread_t self = pthread_self();
46 mState.lock();
47 bool bFound = false;
48 for( ThreadList::iterator i = lThreads.begin(); i; i++ )
49 {
50 if( (*i) == self )
51 {
52 bFound = true;
53 if( (*i).bLocked == false )
54 {
55 throw Bu::ExceptionBase( Bu::String("Unlock in thread that did not lock: %1").arg( (*i).sName ).end().getStr() );
56
57 }
58 else
59 {
60 (*i).bLocked = false;
61 }
62 break;
63 }
64 }
65 if( bFound == false )
66 {
67 ThreadInfo info( false );
68 throw Bu::ExceptionBase( Bu::String("Unlock in thread that never locked mutex: %1").arg( info.sName ).end().getStr() );
69 }
70 mState.unlock();
71 return Bu::Mutex::unlock();
72}
73
74int Bu::DebugMutex::trylock()
75{
76 return Bu::Mutex::trylock();
77}
78
diff --git a/src/experimental/debugmutex.h b/src/experimental/debugmutex.h
new file mode 100644
index 0000000..ca8ef9f
--- /dev/null
+++ b/src/experimental/debugmutex.h
@@ -0,0 +1,102 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_DEBUG_MUTEX_H
9#define BU_DEBUG_MUTEX_H
10
11#include "bu/mutex.h"
12#include "bu/list.h"
13#include "bu/string.h"
14
15namespace Bu
16{
17 /**
18 * Simple mutex wrapper. Currently this doesn't do anything extra for you
19 * except keep all of the functionality together in an OO sorta' way and
20 * keep you from having to worry about cleaning up your mutexes properly,
21 * or initing them.
22 *@ingroup Threading
23 */
24 class DebugMutex : public Mutex
25 {
26 public:
27 /**
28 * Create an unlocked mutex.
29 */
30 DebugMutex();
31
32 /**
33 * Destroy a mutex. This can only be done when a mutex is unlocked.
34 * Failure to unlock before destroying a mutex object could cause it to
35 * wait for the mutex to unlock, the odds of which are usually farily
36 * low at deconstruction time.
37 */
38 virtual ~DebugMutex();
39
40 /**
41 * Lock the mutex. This causes all future calls to lock on this
42 * instance of mutex to block until the first thread that called mutex
43 * unlocks it. At that point the next thread that called lock will get
44 * a chance to go to work. Because of the nature of a mutex lock it is
45 * a very bad idea to do any kind of serious or rather time consuming
46 * computation within a locked section. This can cause thread-deadlock
47 * and your program may hang.
48 */
49 virtual int lock();
50
51 /**
52 * Unlock the mutex. This allows the next thread that asked for a lock
53 * to lock the mutex and continue with execution.
54 */
55 virtual int unlock();
56
57 /**
58 * Try to lock the mutex. This is the option to go with if you cannot
59 * avoid putting lengthy operations within a locked section. trylock
60 * will attempt to lock the mutex, if the mutex is already locked this
61 * function returns immediately with an error code.
62 */
63 virtual int trylock();
64
65 private:
66 Bu::Mutex mState;
67
68 class ThreadInfo
69 {
70 public:
71 ThreadInfo( bool bLocked=false ) :
72 idThread( pthread_self() ),
73 bLocked( bLocked )
74 {
75 char buf[64];
76 if( pthread_getname_np( idThread, buf, 64 ) == 0 )
77 sName = buf;
78 }
79 ~ThreadInfo() {}
80
81 bool operator==( const ThreadInfo &rhs )
82 {
83 return pthread_equal( idThread, rhs.idThread );
84 }
85
86 bool operator==( const pthread_t &rhs )
87 {
88 return pthread_equal( idThread, rhs );
89 }
90
91 pthread_t idThread;
92 Bu::String sName;
93 bool bLocked;
94 };
95 typedef Bu::List<ThreadInfo> ThreadList;
96 ThreadList lThreads;
97 };
98}
99
100#endif
101
102
diff --git a/src/stable/mutex.h b/src/stable/mutex.h
index d9e8910..8034974 100644
--- a/src/stable/mutex.h
+++ b/src/stable/mutex.h
@@ -33,7 +33,7 @@ namespace Bu
33 * wait for the mutex to unlock, the odds of which are usually farily 33 * wait for the mutex to unlock, the odds of which are usually farily
34 * low at deconstruction time. 34 * low at deconstruction time.
35 */ 35 */
36 ~Mutex(); 36 virtual ~Mutex();
37 37
38 /** 38 /**
39 * Lock the mutex. This causes all future calls to lock on this 39 * Lock the mutex. This causes all future calls to lock on this
@@ -44,13 +44,13 @@ namespace Bu
44 * computation within a locked section. This can cause thread-deadlock 44 * computation within a locked section. This can cause thread-deadlock
45 * and your program may hang. 45 * and your program may hang.
46 */ 46 */
47 int lock(); 47 virtual int lock();
48 48
49 /** 49 /**
50 * Unlock the mutex. This allows the next thread that asked for a lock 50 * Unlock the mutex. This allows the next thread that asked for a lock
51 * to lock the mutex and continue with execution. 51 * to lock the mutex and continue with execution.
52 */ 52 */
53 int unlock(); 53 virtual int unlock();
54 54
55 /** 55 /**
56 * Try to lock the mutex. This is the option to go with if you cannot 56 * Try to lock the mutex. This is the option to go with if you cannot
@@ -58,7 +58,7 @@ namespace Bu
58 * will attempt to lock the mutex, if the mutex is already locked this 58 * will attempt to lock the mutex, if the mutex is already locked this
59 * function returns immediately with an error code. 59 * function returns immediately with an error code.
60 */ 60 */
61 int trylock(); 61 virtual int trylock();
62 62
63 protected: 63 protected:
64 pthread_mutex_t mutex; /**< The internal mutex reference. */ 64 pthread_mutex_t mutex; /**< The internal mutex reference. */
diff --git a/src/stable/myriad.cpp b/src/stable/myriad.cpp
index 1bf2301..492676e 100644
--- a/src/stable/myriad.cpp
+++ b/src/stable/myriad.cpp
@@ -12,13 +12,13 @@
12#define MyriadRead( target, size ) if( rBacking.read( target, size ) < size ) \ 12#define MyriadRead( target, size ) if( rBacking.read( target, size ) < size ) \
13{ \ 13{ \
14 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \ 14 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \
15 "Insufficent data reading myriad data from backing stream."); \ 15 "Insufficient data reading myriad data from backing stream."); \
16} (void)0 16} (void)0
17 17
18#define ReqRead( stream, target, size ) if( stream.read( target, size ) < size ) \ 18#define ReqRead( stream, target, size ) if( stream.read( target, size ) < size ) \
19{ \ 19{ \
20 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \ 20 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \
21 "Insufficent data reading from myriad stream."); \ 21 "Insufficient data reading from myriad stream."); \
22} (void)0 22} (void)0
23 23
24namespace Bu 24namespace Bu
@@ -74,7 +74,7 @@ Bu::MyriadStream Bu::Myriad::create( Bu::Myriad::Mode eMode,
74 mhStream.unlock(); 74 mhStream.unlock();
75 bStructureChanged = true; 75 bStructureChanged = true;
76 76
77 return Bu::MyriadStream( *this, pStream, (Mode)(eMode&ReadWrite) ); 77 return Bu::MyriadStream( *this, pStream, eMode&ReadWrite );
78} 78}
79 79
80Bu::MyriadStream Bu::Myriad::open( Bu::Myriad::StreamId iStream, 80Bu::MyriadStream Bu::Myriad::open( Bu::Myriad::StreamId iStream,
@@ -84,7 +84,7 @@ Bu::MyriadStream Bu::Myriad::open( Bu::Myriad::StreamId iStream,
84 Bu::MutexLocker l( mhStream ); 84 Bu::MutexLocker l( mhStream );
85 if( (eMode&Create) ) 85 if( (eMode&Create) )
86 { 86 {
87 if( !hStream.has( iStream ) ) 87 if( hStream.has( iStream ) )
88 { 88 {
89 if( (eMode&Exclusive) ) 89 if( (eMode&Exclusive) )
90 { 90 {
@@ -112,7 +112,7 @@ Bu::MyriadStream Bu::Myriad::open( Bu::Myriad::StreamId iStream,
112 } 112 }
113 { 113 {
114 Bu::MutexLocker l2( mBacking ); 114 Bu::MutexLocker l2( mBacking );
115 if( (eMode&Write) && rBacking.isWritable() ) 115 if( (eMode&Write) && !rBacking.isWritable() )
116 { 116 {
117 throw Bu::MyriadException( MyriadException::badMode, 117 throw Bu::MyriadException( MyriadException::badMode,
118 "Backing stream does not support writing."); 118 "Backing stream does not support writing.");
@@ -129,8 +129,43 @@ Bu::MyriadStream Bu::Myriad::open( Bu::Myriad::StreamId iStream,
129 return Bu::MyriadStream( *this, pStream, eMode ); 129 return Bu::MyriadStream( *this, pStream, eMode );
130} 130}
131 131
132void Bu::Myriad::erase( Bu::Myriad::StreamId /*iStream*/ ) 132Bu::Myriad::StreamId Bu::Myriad::allocate()
133{ 133{
134 Bu::MutexLocker l( mAccess );
135
136 Stream *pStream = new Stream( *this, ++iLastUsedIndex, 0 );
137 mhStream.lock();
138 hStream.insert( pStream->iStream, pStream );
139 mhStream.unlock();
140 bStructureChanged = true;
141
142 return pStream->iStream;
143}
144
145void Bu::Myriad::erase( Bu::Myriad::StreamId iStream )
146{
147 // For now, let's prevent you from erasing a stream if it's open.
148 Bu::MutexLocker l( mhStream );
149 if( !hStream.has( iStream ) )
150 {
151 throw Bu::MyriadException( Bu::MyriadException::noSuchStream,
152 "No such stream exists.");
153 }
154 Stream *pStream = hStream.get( iStream );
155 Bu::MutexLocker sl( pStream->mAccess );
156 if( pStream->iOpenCount > 0 )
157 {
158 throw Bu::MyriadException( Bu::MyriadException::streamOpen,
159 "Cannot currently erase a stream while it is open.");
160 }
161
162 for( Bu::Array<int32_t>::iterator i = pStream->aBlocks.begin(); i; i++ )
163 {
164 releaseBlock( *i, false );
165 }
166 pStream->aBlocks.clear();
167 hStream.erase( iStream );
168 delete pStream;
134} 169}
135 170
136void Bu::Myriad::setSize( Bu::Myriad::StreamId iStream, 171void Bu::Myriad::setSize( Bu::Myriad::StreamId iStream,
@@ -144,6 +179,18 @@ void Bu::Myriad::setSize( Bu::Myriad::StreamId iStream,
144 pStream->setSize( iNewSize ); 179 pStream->setSize( iNewSize );
145} 180}
146 181
182int32_t Bu::Myriad::getSize( StreamId iStream ) const
183{
184 Bu::MutexLocker l( mhStream );
185 return hStream.get( iStream )->getSize();
186}
187
188bool Bu::Myriad::exists( StreamId iStream ) const
189{
190 Bu::MutexLocker l( mhStream );
191 return hStream.has( iStream );
192}
193
147Bu::String Bu::Myriad::getLocation() const 194Bu::String Bu::Myriad::getLocation() const
148{ 195{
149 Bu::MutexLocker l( mAccess ); 196 Bu::MutexLocker l( mAccess );
@@ -218,9 +265,62 @@ int32_t Bu::Myriad::getTotalUnusedBytes(int32_t iAssumeBlockSize ) const
218 return iTotal; 265 return iTotal;
219} 266}
220 267
268Bu::Myriad::StreamIdList Bu::Myriad::getStreamList() const
269{
270 mhStream.lock();
271 StreamIdList lIds = hStream.getKeys();
272 mhStream.unlock();
273 lIds.sort();
274 if( lIds.first() == 0 )
275 {
276 lIds.eraseFirst();
277 }
278 return lIds;
279}
280
281Bu::BitString Bu::Myriad::buildBlockUseMap() const
282{
283 Bu::MutexLocker l( mAccess );
284 Bu::BitString bsMap( iBlockCount );
285 bsMap.fill();
286 for( IndexList::const_iterator i = lFreeBlocks.begin(); i; i++ )
287 {
288 bsMap.setBit( *i, false );
289 }
290 return bsMap;
291}
292
293Bu::Myriad::StreamIdArray Bu::Myriad::buildBlockMap() const
294{
295 Bu::MutexLocker l( mAccess );
296 StreamIdArray bm( iBlockCount );
297 for( int j = 0; j < iBlockCount; j++ )
298 {
299 bm.append( -1 );
300 }
301 Bu::MutexLocker l2( mhStream );
302 for( StreamHash::const_iterator iStream = hStream.begin();
303 iStream; iStream++ )
304 {
305 int32_t iId = iStream.getKey();
306 Stream *pStream = iStream.getValue();
307 for( Bu::Array<int32_t>::const_iterator iBlock =
308 pStream->aBlocks.begin(); iBlock; iBlock++ )
309 {
310 bm[*iBlock] = iId;
311 }
312 }
313 return bm;
314}
315
316void Bu::Myriad::sync()
317{
318 writeHeader();
319}
320
221bool Bu::Myriad::loadMyriad() 321bool Bu::Myriad::loadMyriad()
222{ 322{
223 Bu::println("Load myriad!"); 323 //Bu::println("Load myriad!");
224 char sMagicCode[4]; 324 char sMagicCode[4];
225 rBacking.setPos( 0 ); 325 rBacking.setPos( 0 );
226 MyriadRead( sMagicCode, 4 ); 326 MyriadRead( sMagicCode, 4 );
@@ -323,7 +423,9 @@ bool Bu::Myriad::loadMyriad()
323 } 423 }
324 424
325 lFreeBlocks = hUnusedBlocks.getKeys(); 425 lFreeBlocks = hUnusedBlocks.getKeys();
326 Bu::println("Free blocks: %1").arg( lFreeBlocks.getSize() ); 426 //Bu::println("Free blocks: %1").arg( lFreeBlocks.getSize() );
427
428 bIsNewStream = false;
327 429
328 return true; 430 return true;
329} 431}
@@ -350,32 +452,21 @@ void Bu::Myriad::createMyriad( int32_t iBlockSize, int32_t iPreallocateBlocks )
350 // plus one block index. 452 // plus one block index.
351 int iHeaderStreamBlocks = blkDiv(iHeaderStreamBytes+4, iBlockSize ); 453 int iHeaderStreamBlocks = blkDiv(iHeaderStreamBytes+4, iBlockSize );
352 454
353 Bu::println("Initial estimate: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).") 455 //Bu::println("Initial estimate: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).").arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) ).arg( iHeaderStreamBlocks ).arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) ).arg( iHeaderStreamBlocks*iBlockSize );
354 .arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) )
355 .arg( iHeaderStreamBlocks )
356 .arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) )
357 .arg( iHeaderStreamBlocks*iBlockSize );
358 while( iHeaderStreamBytes+(iHeaderStreamBlocks*4) 456 while( iHeaderStreamBytes+(iHeaderStreamBlocks*4)
359 > iHeaderStreamBlocks*iBlockSize ) 457 > iHeaderStreamBlocks*iBlockSize )
360 { 458 {
361 iHeaderStreamBlocks = blkDiv((iHeaderStreamBytes+((iHeaderStreamBlocks+1)*4)), iBlockSize); 459 iHeaderStreamBlocks = blkDiv((iHeaderStreamBytes+((iHeaderStreamBlocks+1)*4)), iBlockSize);
362 if( iHeaderStreamBlocks > 100 ) 460 if( iHeaderStreamBlocks > 100 )
363 break; 461 break;
364 Bu::println(" Adjustment: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).") 462 //Bu::println(" Adjustment: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).").arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) ).arg( iHeaderStreamBlocks ).arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) ).arg( iHeaderStreamBlocks*iBlockSize );
365 .arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) )
366 .arg( iHeaderStreamBlocks )
367 .arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) )
368 .arg( iHeaderStreamBlocks*iBlockSize );
369 } 463 }
370 464
371 if( iPreallocateBlocks > iHeaderStreamBlocks ) 465 if( iPreallocateBlocks < iHeaderStreamBlocks )
372 { 466 {
373 rBacking.setSize( iBlockSize*iPreallocateBlocks ); 467 iPreallocateBlocks = iHeaderStreamBlocks;
374 }
375 else
376 {
377 rBacking.setSize( iBlockSize*iHeaderStreamBlocks );
378 } 468 }
469 rBacking.setSize( iBlockSize*iPreallocateBlocks );
379 470
380 // 471 //
381 // Write Myriad header 472 // Write Myriad header
@@ -417,12 +508,12 @@ void Bu::Myriad::createMyriad( int32_t iBlockSize, int32_t iPreallocateBlocks )
417 508
418void Bu::Myriad::writeHeader() 509void Bu::Myriad::writeHeader()
419{ 510{
511 Bu::MutexLocker l( mAccess );
420 if( !rBacking.isWritable() ) 512 if( !rBacking.isWritable() )
421 return; 513 return;
422 Bu::println("Writing stream breakdown:"); 514 //Bu::println("Writing stream breakdown:");
423 Bu::MemBuf mbHeader; 515 Bu::MemBuf mbHeader;
424 { 516 {
425 Bu::MutexLocker l( mAccess );
426 Bu::MutexLocker l2( mhStream ); 517 Bu::MutexLocker l2( mhStream );
427 518
428 int32_t iHdrStreamSize = __calcHeaderSize(); 519 int32_t iHdrStreamSize = __calcHeaderSize();
@@ -449,7 +540,7 @@ void Bu::Myriad::writeHeader()
449 psHeader->iSize = iHdrStreamSize; 540 psHeader->iSize = iHdrStreamSize;
450 } 541 }
451 542
452 Bu::println("Computed header size: %1 bytes. Ver=%2, Bpi=%3, BlockSize=%4").arg( iHdrStreamSize ).arg( 1 ).arg( 32 ).arg( iBlockSize ); 543 //Bu::println("Computed header size: %1 bytes. Ver=%2, Bpi=%3, BlockSize=%4").arg( iHdrStreamSize ).arg( 1 ).arg( 32 ).arg( iBlockSize );
453 544
454 uint8_t uVer = 1; 545 uint8_t uVer = 1;
455 uint8_t uBpi = 32; 546 uint8_t uBpi = 32;
@@ -474,17 +565,15 @@ void Bu::Myriad::writeHeader()
474 uint32_t uStreamSize = pStream->getSize(); 565 uint32_t uStreamSize = pStream->getSize();
475 mbHeader.write( &uStreamId, 4 ); 566 mbHeader.write( &uStreamId, 4 );
476 mbHeader.write( &uStreamSize, 4 ); 567 mbHeader.write( &uStreamSize, 4 );
568 int32_t iBlocks = Bu::blkDiv( uStreamSize, (uint32_t)iBlockSize );
477 Bu::Array<int32_t> aBlocks = pStream->getBlockList(); 569 Bu::Array<int32_t> aBlocks = pStream->getBlockList();
478 570
479 Bu::println(" Stream %1 is %2 bytes %3 blocks (%4 blocks computed)") 571 //Bu::println(" Stream %1 is %2 bytes %3 blocks (%4 blocks computed)").arg( *i ).arg( uStreamSize ).arg( aBlocks.getSize() ).arg( Bu::blkDiv( (int)uStreamSize, (int)iBlockSize ) );
480 .arg( *i ).arg( uStreamSize )
481 .arg( aBlocks.getSize() )
482 .arg( Bu::blkDiv( (int)uStreamSize, (int)iBlockSize ) );
483 572
484 for( Bu::Array<int32_t>::iterator i = aBlocks.begin(); i; i++ ) 573// for( Bu::Array<int32_t>::iterator i = aBlocks.begin(); i; i++ )
574 for( int j = 0; j < iBlocks; j++ )
485 { 575 {
486 int32_t iIdx = *i; 576 mbHeader.write( &aBlocks[j], 4 );
487 mbHeader.write( &iIdx, 4 );
488 } 577 }
489 } 578 }
490 579
@@ -517,15 +606,15 @@ int32_t Bu::Myriad::__calcHeaderSize()
517 } 606 }
518 } 607 }
519 608
520 Bu::println("HeaderCalc:"); 609 //Bu::println("HeaderCalc:");
521 Bu::println(" Base (no header stream): %1").arg( iHdrSize ); 610 //Bu::println(" Base (no header stream): %1").arg( iHdrSize );
522 int32_t iNewSize = iHdrSize; 611 int32_t iNewSize = iHdrSize;
523 int32_t iOldSize; 612 int32_t iOldSize;
524 613
525 do { 614 do {
526 iOldSize = iNewSize; 615 iOldSize = iNewSize;
527 iNewSize = iHdrSize + Bu::blkDiv(iNewSize, iBlockSize)*4; 616 iNewSize = iHdrSize + Bu::blkDiv(iNewSize, iBlockSize)*4;
528 Bu::println(" Recomp: %1").arg( iNewSize ); 617 //Bu::println(" Recomp: %1").arg( iNewSize );
529 } while( iOldSize != iNewSize ); 618 } while( iOldSize != iNewSize );
530 619
531 return iNewSize; 620 return iNewSize;
@@ -705,9 +794,7 @@ int32_t Bu::Myriad::Stream::read( int32_t iStart, void *pTarget,
705 794
706 if( iStart+iSize >= this->iSize ) 795 if( iStart+iSize >= this->iSize )
707 { 796 {
708 int32_t iDiff = this->iSize-(iStart+iSize); 797 iSize = this->iSize-iStart;
709 iSize -= iDiff;
710 iStart += iDiff;
711 } 798 }
712 799
713 while( iSize > 0 ) 800 while( iSize > 0 )
diff --git a/src/stable/myriad.h b/src/stable/myriad.h
index 58f700a..5accd1e 100644
--- a/src/stable/myriad.h
+++ b/src/stable/myriad.h
@@ -7,6 +7,8 @@
7#include "bu/array.h" 7#include "bu/array.h"
8#include "bu/hash.h" 8#include "bu/hash.h"
9 9
10#include "bu/bitstring.h"
11
10namespace Bu 12namespace Bu
11{ 13{
12 class MyriadStream; 14 class MyriadStream;
@@ -25,14 +27,25 @@ namespace Bu
25 invalidParameter, 27 invalidParameter,
26 invalidBackingStream, 28 invalidBackingStream,
27 badMode, 29 badMode,
30 streamOpen,
28 }; 31 };
29 subExceptionDeclEnd(); 32 subExceptionDeclEnd();
30 33
34 /**
35 * Myriad Stream Multiplexer. This is a system that allows you to store
36 * many streams within a single backing stream. This is great for databases,
37 * caching, etc. It's fairly lightweight, and allows all streams to grow
38 * dynamically using a block-allocation scheme. This is used extensively
39 * by the caching system and MyriadFs as well as other systems within
40 * libbu++.
41 */
31 class Myriad 42 class Myriad
32 { 43 {
33 public: 44 public:
34 typedef int32_t StreamId; 45 typedef int32_t StreamId;
35 enum Mode { 46 typedef Bu::Array<StreamId> StreamIdArray;
47 typedef Bu::List<StreamId> StreamIdList;
48 enum Mode : int32_t {
36 None = 0x00, 49 None = 0x00,
37 50
38 // Flags 51 // Flags
@@ -42,7 +55,7 @@ namespace Bu
42 Truncate = 0x08, ///< Truncate file if it does exist 55 Truncate = 0x08, ///< Truncate file if it does exist
43 Append = 0x10, ///< Start writing at end of file 56 Append = 0x10, ///< Start writing at end of file
44 //NonBlock = 0x20, ///< Open file in non-blocking mode 57 //NonBlock = 0x20, ///< Open file in non-blocking mode
45 Exclusive = 0x44, ///< Create file, if it exists then fail 58 Exclusive = 0x40, ///< Create file, if it exists then fail
46 59
47 // Helpful mixes 60 // Helpful mixes
48 ReadWrite = 0x03, ///< Open for reading and writing 61 ReadWrite = 0x03, ///< Open for reading and writing
@@ -52,8 +65,9 @@ namespace Bu
52 65
53 public: 66 public:
54 /** 67 /**
55 * Open existing Myriad stream, or initialize a new one if it doesn't 68 * Open existing Myriad container, or initialize a new one if the
56 * exist. 69 * backing stream is empty. If other data is already in the provided
70 * backing stream an error is thrown.
57 * 71 *
58 * Myriad format V0 72 * Myriad format V0
59 * 0 - 3: Myriad_MAGIC_CODE (0ad3fa84) 73 * 0 - 3: Myriad_MAGIC_CODE (0ad3fa84)
@@ -68,13 +82,40 @@ namespace Bu
68 * 4 - 7: Size of stream in bytes 82 * 4 - 7: Size of stream in bytes
69 * 8 - ...: List of blocks in stream (4 bytes per block 83 * 8 - ...: List of blocks in stream (4 bytes per block
70 */ 84 */
71 Myriad( Bu::Stream &rBacking, int32_t iBlockSize=-1, int32_t iPreallocateBlocks=-1 ); 85 Myriad( Bu::Stream &rBacking, int32_t iBlockSize=-1,
86 int32_t iPreallocateBlocks=-1 );
72 virtual ~Myriad(); 87 virtual ~Myriad();
73 88
89 /**
90 * Creates a new stream open in the specified eMode and, optionally,
91 * preallocates the specificed amount of space. The stream is zero
92 * bytes even if space is preallocated. The open stream is returned,
93 * ready for use. Use this if you don't care what the id is of the
94 * newly created stream.
95 */
74 MyriadStream create( Mode eMode, int32_t iPreallocateBytes=-1 ); 96 MyriadStream create( Mode eMode, int32_t iPreallocateBytes=-1 );
97
98 /**
99 * Open an existing stream or create a new stream with the specified
100 * id (iStream) with the specified eMode. This respects the normal file
101 * modes, see Bu::Myriad::Mode for details.
102 */
75 MyriadStream open( StreamId iStream, Mode eMode ); 103 MyriadStream open( StreamId iStream, Mode eMode );
104
105 /**
106 * Allocate a new stream but do not open it, just ensure it exists and
107 * return the id of the newly allocated stream.
108 */
109 StreamId allocate();
110
111 /**
112 * Erase the stream specified by iStream. This only can work when the
113 * stream is not open at the moment.
114 */
76 void erase( StreamId iStream ); 115 void erase( StreamId iStream );
77 void setSize( StreamId iStream, int32_t iNewSize ); 116 void setSize( StreamId iStream, int32_t iNewSize );
117 int32_t getSize( StreamId iStream ) const;
118 bool exists( StreamId iStream ) const;
78 Bu::String getLocation() const; 119 Bu::String getLocation() const;
79 int32_t getBlockSize() const; 120 int32_t getBlockSize() const;
80 int32_t getTotalBlocks() const; 121 int32_t getTotalBlocks() const;
@@ -83,6 +124,22 @@ namespace Bu
83 int32_t getTotalStreams() const; 124 int32_t getTotalStreams() const;
84 int32_t getTotalUsedBytes() const; 125 int32_t getTotalUsedBytes() const;
85 int32_t getTotalUnusedBytes( int32_t iAssumeBlockSize=-1 ) const; 126 int32_t getTotalUnusedBytes( int32_t iAssumeBlockSize=-1 ) const;
127 Bu::BitString buildBlockUseMap() const;
128 StreamIdArray buildBlockMap() const;
129
130 /**
131 * Lists all stream ids that you are allowed to open. Technically there
132 * is always a zero stream, but it is used by Myriad for stream/block
133 * accounting. It works like a normal stream but you should not open
134 * it.
135 */
136 StreamIdList getStreamList() const;
137
138 /**
139 * Flush all caches to the backing stream, write all structural and
140 * header changes.
141 */
142 void sync();
86 143
87 private: 144 private:
88 bool loadMyriad(); 145 bool loadMyriad();
@@ -175,6 +232,20 @@ namespace Bu
175 IndexList lFreeBlocks; 232 IndexList lFreeBlocks;
176 StreamId iLastUsedIndex; 233 StreamId iLastUsedIndex;
177 }; 234 };
235 constexpr Myriad::Mode operator&( Myriad::Mode a, Myriad::Mode b )
236 {
237 return static_cast<Myriad::Mode>(
238 static_cast<std::underlying_type<Myriad::Mode>::type>(a) &
239 static_cast<std::underlying_type<Myriad::Mode>::type>(b)
240 );
241 }
242 constexpr Myriad::Mode operator|( Myriad::Mode a, Myriad::Mode b )
243 {
244 return static_cast<Myriad::Mode>(
245 static_cast<std::underlying_type<Myriad::Mode>::type>(a) |
246 static_cast<std::underlying_type<Myriad::Mode>::type>(b)
247 );
248 }
178}; 249};
179 250
180#endif 251#endif
diff --git a/src/stable/myriadstream.cpp b/src/stable/myriadstream.cpp
index 9ea2e17..eaf91a5 100644
--- a/src/stable/myriadstream.cpp
+++ b/src/stable/myriadstream.cpp
@@ -166,3 +166,9 @@ Bu::String Bu::MyriadStream::getLocation() const
166 return pStream->getLocation(); 166 return pStream->getLocation();
167} 167}
168 168
169Bu::Myriad::StreamId Bu::MyriadStream::getId() const
170{
171 Bu::MutexLocker l( mAccess );
172 return pStream->getStreamId();
173}
174
diff --git a/src/stable/myriadstream.h b/src/stable/myriadstream.h
index b86dbd7..27a15d5 100644
--- a/src/stable/myriadstream.h
+++ b/src/stable/myriadstream.h
@@ -39,6 +39,7 @@ namespace Bu
39 virtual size getSize() const; 39 virtual size getSize() const;
40 virtual size getBlockSize() const; 40 virtual size getBlockSize() const;
41 virtual Bu::String getLocation() const; 41 virtual Bu::String getLocation() const;
42 Myriad::StreamId getId() const;
42 43
43 private: 44 private:
44 mutable Bu::Mutex mAccess; 45 mutable Bu::Mutex mAccess;
diff --git a/src/tests/bigmyriad.cpp b/src/tests/bigmyriad.cpp
index 9d24741..73a3315 100644
--- a/src/tests/bigmyriad.cpp
+++ b/src/tests/bigmyriad.cpp
@@ -5,14 +5,15 @@
5int main() 5int main()
6{ 6{
7 Bu::File f("big.myr", Bu::File::Read|Bu::File::Write|Bu::File::Create ); 7 Bu::File f("big.myr", Bu::File::Read|Bu::File::Write|Bu::File::Create );
8 Bu::Myriad m( f, 256, 12 ); 8 Bu::Myriad m( f, 512, 12 );
9 9
10 char *buf = new char[1024*1024*10]; 10#define SSIZE (1024*8) // 1024*1024*10
11 char *buf = new char[SSIZE];
11 12
12 for( int j = 0; j < 25; j++ ) 13 for( int j = 0; j < 25; j++ )
13 { 14 {
14 memset( buf, j, 1024*1024*10 ); 15 memset( buf, j, SSIZE );
15 m.create( Bu::Myriad::Write ).write( buf, 1024*1024*10 ); 16 m.create( Bu::Myriad::Write ).write( buf, SSIZE );
16// m.sync(); 17// m.sync();
17 printf("\r%03d%%", (j+1)*100/25 ); 18 printf("\r%03d%%", (j+1)*100/25 );
18 fflush( stdout ); 19 fflush( stdout );
diff --git a/src/tests/myriad.cpp b/src/tests/myriad.cpp
new file mode 100644
index 0000000..ee4eac4
--- /dev/null
+++ b/src/tests/myriad.cpp
@@ -0,0 +1,23 @@
1#include <bu/myriad.h>
2#include <bu/myriadstream.h>
3#include <bu/string.h>
4#include <bu/sio.h>
5#include <bu/file.h>
6
7int main( int , char *[] )
8{
9 Bu::File fMyriad("test.myr", Bu::File::WriteNew|Bu::File::Read );
10 Bu::Myriad m( fMyriad, 32 );
11
12 Bu::MyriadStream ms = m.create( Bu::Myriad::ReadWrite );
13 ms.setSize( 150 );
14 ms.setPos( 145 );
15 char stuff[10];
16 int32_t iRead = ms.read( stuff, 10 );
17
18 Bu::println("Tried to read 10, expect 5, got %1").arg( iRead );
19
20
21 return 0;
22}
23
diff --git a/src/tests/myriadfs.cpp b/src/tests/myriadfs.cpp
new file mode 100644
index 0000000..29ac3d9
--- /dev/null
+++ b/src/tests/myriadfs.cpp
@@ -0,0 +1,62 @@
1#include "bu/file.h"
2#include "bu/membuf.h"
3#include "bu/myriadfs.h"
4#include "bu/myriadstream.h"
5#include "bu/sio.h"
6
7using namespace Bu;
8
9int main()
10{
11// Bu::MemBuf mb;
12 Bu::File mb("store.mfs", File::Read|File::Write|File::Create );
13 Bu::MyriadFs mfs( mb, 512 );
14
15 sio << "Creating dirs..." << sio.nl;
16 mfs.create("/etc", Bu::MyriadFs::typeDir|0755 );
17 mfs.create("/dev", Bu::MyriadFs::typeDir|0755 );
18 mfs.create("/usr", Bu::MyriadFs::typeDir|0755 );
19
20 mfs.create("/dev/null", Bu::MyriadFs::typeChrDev|0666, 1, 3 );
21 mfs.create("/dev/zero", Bu::MyriadFs::typeChrDev|0666, 1, 5 );
22 mfs.create("/dev/sda", Bu::MyriadFs::typeBlkDev|0660, 8, 0 );
23
24 sio << "Creating files..." << sio.nl;
25 {
26 Bu::MyriadStream ms = mfs.open("/hello", Bu::MyriadFs::Read );
27 ms.write("world!");
28 }
29 {
30 Bu::MyriadStream ms = mfs.open("/etc/hello", Bu::MyriadFs::Read );
31 ms.write("world, again!");
32 }
33 {
34 Bu::MyriadStream ms = mfs.open("/etc/trunc", Bu::MyriadFs::Write );
35 ms.write("[longer text shouldn't be seen]");
36 }
37 {
38 Bu::MyriadStream ms = mfs.open("/etc/trunc", Bu::MyriadFs::Write|Bu::MyriadFs::Create|Bu::MyriadFs::Truncate );
39 ms.write("[short text]");
40 }
41
42 sio << "Reading files..." << sio.nl;
43 {
44 Bu::MyriadStream ms = mfs.open("/hello", Bu::MyriadFs::Read );
45 char buf[512];
46 buf[ms.read( buf, 512 )] = '\0';
47 sio << "read: '" << buf << "'" << sio.nl;
48 }
49 {
50 Bu::MyriadStream ms = mfs.open("/etc/hello", Bu::MyriadFs::Read );
51 char buf[512];
52 buf[ms.read( buf, 512 )] = '\0';
53 sio << "read: '" << buf << "'" << sio.nl;
54 }
55 {
56 Bu::MyriadStream ms = mfs.open("/etc/trunc", Bu::MyriadFs::Read );
57 char buf[512];
58 buf[ms.read( buf, 512 )] = '\0';
59 sio << "read: '" << buf << "'" << sio.nl;
60 }
61}
62
diff --git a/src/tools/myriad.cpp b/src/tools/myriad.cpp
index 1dc73ec..0dd9840 100644
--- a/src/tools/myriad.cpp
+++ b/src/tools/myriad.cpp
@@ -20,6 +20,7 @@ enum Mode
20 modeCreate, 20 modeCreate,
21 modeInfo, 21 modeInfo,
22 modeStreamNew, 22 modeStreamNew,
23 modeStreamErase,
23 modeStreamDump, 24 modeStreamDump,
24 modeStreamPut, 25 modeStreamPut,
25 modeStreamGet, 26 modeStreamGet,
@@ -44,6 +45,8 @@ public:
44 "Display some info about a Myriad file." ); 45 "Display some info about a Myriad file." );
45 addOption( eMode, 'n', "new", 46 addOption( eMode, 'n', "new",
46 "Create a new sub-stream in a Myriad file."); 47 "Create a new sub-stream in a Myriad file.");
48 addOption( eMode, 'e', "erase",
49 "Erase sub-stream in a Myriad file.");
47 addOption( eMode, 'd', "dump", 50 addOption( eMode, 'd', "dump",
48 "Display a hexdump of a stream from a Myriad file."); 51 "Display a hexdump of a stream from a Myriad file.");
49 addOption( eMode, "get", 52 addOption( eMode, "get",
@@ -67,6 +70,7 @@ public:
67 setOverride( "create", modeCreate ); 70 setOverride( "create", modeCreate );
68 setOverride( "info", modeInfo ); 71 setOverride( "info", modeInfo );
69 setOverride( "new", modeStreamNew ); 72 setOverride( "new", modeStreamNew );
73 setOverride( "erase", modeStreamErase );
70 setOverride( "dump", modeStreamDump ); 74 setOverride( "dump", modeStreamDump );
71 setOverride( "put", modeStreamPut ); 75 setOverride( "put", modeStreamPut );
72 setOverride( "get", modeStreamGet ); 76 setOverride( "get", modeStreamGet );
@@ -90,6 +94,49 @@ Bu::Formatter &operator>>( Bu::Formatter &f, Mode & /*e*/ )
90 return f; 94 return f;
91} 95}
92 96
97void printMap( const Bu::BitString &bs )
98{
99 for( int j = 0; j < bs.getSize(); j++ )
100 {
101 if( j>0 && (j%50) == 0 )
102 Bu::println("");
103 if( bs.getBit( j ) )
104 Bu::print("#");
105 else
106 Bu::print("-");
107 }
108 Bu::println("\n");
109}
110
111void printMap( const Bu::Array<int32_t> &bm )
112{
113 int iBigest = 0;
114 for( int j = 0; j < bm.getSize(); j++ )
115 {
116 if( iBigest < bm[j] )
117 iBigest = bm[j];
118 }
119 int iWidth = Bu::String("%1").arg( iBigest ).end().getSize();
120 Bu::String sEmpty;
121 for( int j = 0; j < iWidth; j++ )
122 {
123 sEmpty += '-';
124 }
125 int iBreakAt = 60/(iWidth+1);
126 for( int j = 0; j < bm.getSize(); j++ )
127 {
128 if( j>0 && (j%iBreakAt) == 0 )
129 Bu::println("");
130
131 if( bm[j] < 0 )
132 Bu::print("%1 ").arg( sEmpty, Bu::Fmt(2).right().fill(' '));
133 else
134 Bu::print("%1 ").arg( bm[j], Bu::Fmt(2).right().fill(' '));
135
136 }
137 Bu::println("\n");
138}
139
93int main( int argc, char *argv[] ) 140int main( int argc, char *argv[] )
94{ 141{
95 Options opts( argc, argv ); 142 Options opts( argc, argv );
@@ -153,6 +200,22 @@ int main( int argc, char *argv[] )
153 } 200 }
154 break; 201 break;
155 202
203 case modeStreamErase:
204 if( !opts.sFile.isSet() )
205 {
206 sio << "Please specify a file manipulate." << sio.nl;
207 return 0;
208 }
209 else
210 {
211 File fOut( opts.sFile, File::Write|File::Read );
212 Myriad m( fOut );
213 m.erase( opts.iStream );
214 printMap( m.buildBlockUseMap() );
215 printMap( m.buildBlockMap() );
216 }
217 break;
218
156 case modeStreamDump: 219 case modeStreamDump:
157 if( !opts.sFile.isSet() ) 220 if( !opts.sFile.isSet() )
158 { 221 {
@@ -255,17 +318,8 @@ int main( int argc, char *argv[] )
255 { 318 {
256 File fIn( opts.sFile, File::Write|File::Read ); 319 File fIn( opts.sFile, File::Write|File::Read );
257 Myriad m( fIn ); 320 Myriad m( fIn );
258/* Bu::BitString bs = m.getBlocksUsed(); 321 printMap( m.buildBlockUseMap() );
259 for( int j = 0; j < bs.getSize(); j++ ) 322 printMap( m.buildBlockMap() );
260 {
261 if( j>0 && (j%50) == 0 )
262 Bu::println("");
263 if( bs.getBit( j ) )
264 Bu::print("#");
265 else
266 Bu::print("-");
267 }*/
268 Bu::println("\n");
269 } 323 }
270 break; 324 break;
271 325
@@ -277,4 +331,3 @@ int main( int argc, char *argv[] )
277 331
278 return 0; 332 return 0;
279} 333}
280
diff --git a/src/tools/myriadfs.cpp b/src/tools/myriadfs.cpp
new file mode 100644
index 0000000..587bc89
--- /dev/null
+++ b/src/tools/myriadfs.cpp
@@ -0,0 +1,269 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/sio.h"
9#include "bu/streamstack.h"
10#include "bu/file.h"
11#include "bu/myriadfs.h"
12#include "bu/myriadstream.h"
13#include "bu/optparser.h"
14
15enum Mode
16{
17 modeList,
18 modeCat,
19 modeCopyIn,
20 modeCopyOut,
21 modeMkdir,
22 modeInitialize,
23 modeRm,
24
25 modeNone
26};
27
28Bu::Formatter &operator>>( Bu::Formatter &f, Mode & /*e*/ )
29{
30 Bu::sio << "Uh oh, the formatter was called..." << Bu::sio.nl;
31 return f;
32}
33
34class Options : public Bu::OptParser
35{
36public:
37 Options( int argc, char *argv[] ) :
38 eMode( modeNone ),
39 iBlockSize( 64 )
40 {
41 addHelpBanner("Options:");
42 addOption( sFile, 'f', "file", "Myriadfs file");
43 addOption( iBlockSize, 'b', "block-size",
44 "Specify the block size when initializing a new MyriadFs");
45
46 setNonOption( Bu::slot( this, &Options::nonOption ) );
47
48 addHelpOption();
49
50 parse( argc, argv );
51 }
52
53 int nonOption( Bu::Array<Bu::String> aParams )
54 {
55 if( eMode == modeNone )
56 {
57 //Bu::println("Checking mode");
58 // First param, must be the mode
59 if( aParams[0] == "ls" )
60 eMode = modeList;
61 else if( aParams[0] == "cat" )
62 eMode = modeCat;
63 else if( aParams[0] == "cp-in" )
64 eMode = modeCopyIn;
65 else if( aParams[0] == "cp-out" )
66 eMode = modeCopyOut;
67 else if( aParams[0] == "mkdir" )
68 eMode = modeMkdir;
69 else if( aParams[0] == "initialize" )
70 eMode = modeInitialize;
71 else if( aParams[0] == "rm" )
72 eMode = modeRm;
73 else
74 Bu::println("Unknown command, try --help");
75 return 0;
76 } else {
77 lParams.append( aParams[0] );
78 }
79 //Bu::println("Got option: \"%1\"").arg( aParams[0] );
80 return 0;
81 }
82
83 Mode eMode;
84 Bu::String sFile;
85 Bu::StringList lParams;
86 int iBlockSize;
87};
88
89int main( int argc, char *argv[] )
90{
91 Options opt( argc, argv );
92
93 if( opt.sFile.isEmpty() )
94 {
95 Bu::println("You must specify a MyriadFs stream (see -f).\n");
96 return 1;
97 }
98
99 if( opt.eMode == modeNone )
100 {
101 Bu::println("Specify an operation to perfrom.\n");
102 return 1;
103 }
104
105 int iFlags = Bu::File::ReadWrite;
106
107 if( opt.eMode == modeInitialize )
108 {
109 iFlags |= Bu::File::Create|Bu::File::Truncate;
110 }
111
112 Bu::File fFs( opt.sFile, iFlags );
113 Bu::MyriadFs mFs( fFs, opt.iBlockSize );
114
115 switch( opt.eMode )
116 {
117 case modeList:
118 {
119 Bu::String sPath = "/";
120 if( opt.lParams.getSize() > 0 )
121 {
122 sPath = opt.lParams.first();
123 }
124 Bu::MyriadFs::Dir lEnt = mFs.readDir( sPath );
125 for( Bu::MyriadFs::Dir::iterator i = lEnt.begin(); i; i++ )
126 {
127 Bu::String sPerm;
128 switch( (*i).uPerms&Bu::MyriadFs::typeMask )
129 {
130 case Bu::MyriadFs::typeDir: sPerm += "d"; break;
131 case Bu::MyriadFs::typeChrDev: sPerm += "c"; break;
132 case Bu::MyriadFs::typeBlkDev: sPerm += "b"; break;
133 case Bu::MyriadFs::typeSymLink: sPerm += "l"; break;
134 case Bu::MyriadFs::typeSocket: sPerm += "s"; break;
135 default: sPerm += "-"; break;
136 }
137 sPerm += ((*i).uPerms&Bu::MyriadFs::permUsrR)?"r":"-";
138 sPerm += ((*i).uPerms&Bu::MyriadFs::permUsrW)?"w":"-";
139 sPerm += ((*i).uPerms&Bu::MyriadFs::permUsrX)?"x":"-";
140 sPerm += ((*i).uPerms&Bu::MyriadFs::permGrpR)?"r":"-";
141 sPerm += ((*i).uPerms&Bu::MyriadFs::permGrpW)?"w":"-";
142 sPerm += ((*i).uPerms&Bu::MyriadFs::permGrpX)?"x":"-";
143 sPerm += ((*i).uPerms&Bu::MyriadFs::permOthR)?"r":"-";
144 sPerm += ((*i).uPerms&Bu::MyriadFs::permOthW)?"w":"-";
145 sPerm += ((*i).uPerms&Bu::MyriadFs::permOthX)?"x":"-";
146 Bu::println("%1 %2 %3:%4 %5 %6")
147 .arg( sPerm )
148 .arg( (*i).iNode )
149 .arg( (*i).iUser )
150 .arg( (*i).iGroup )
151 .arg( (*i).iSize )
152 .arg( (*i).sName );
153 }
154 }
155 break;
156
157 case modeCat:
158 {
159 if( opt.lParams.isEmpty() )
160 {
161 Bu::println("Specify at least one file.");
162 return 1;
163 }
164 int iBlockSize = 1024*1024;
165 char *pBuf = new char[iBlockSize];
166 for( Bu::StringList::iterator i = opt.lParams.begin(); i; i++ )
167 {
168 Bu::MyriadStream ms = mFs.open( *i, Bu::MyriadFs::Read );
169 int iRead = 0;
170 do
171 {
172 iRead = ms.read( pBuf, iBlockSize );
173 if( iRead > 0 )
174 {
175 Bu::sioRaw.write( pBuf, iRead );
176 }
177 } while( iRead == iBlockSize );
178 }
179 delete[] pBuf;
180 }
181 break;
182
183 case modeCopyIn:
184 {
185 if( opt.lParams.getSize() != 2 )
186 {
187 Bu::println("Specify a source file and destination file.");
188 return 1;
189 }
190 int iBlockSize = 1024*1024;
191 char *pBuf = new char[iBlockSize];
192 Bu::File fs = Bu::File(
193 opt.lParams.first(), Bu::File::Read );
194 Bu::MyriadStream ms = mFs.open(
195 opt.lParams.last(), Bu::MyriadFs::WriteNew );
196 int iRead = 0;
197 do
198 {
199 iRead = fs.read( pBuf, iBlockSize );
200 if( iRead > 0 )
201 {
202 ms.write( pBuf, iRead );
203 }
204 } while( iRead == iBlockSize );
205 delete[] pBuf;
206 }
207 break;
208
209 case modeCopyOut:
210 {
211 if( opt.lParams.getSize() != 2 )
212 {
213 Bu::println("Specify a source file and destination file.");
214 return 1;
215 }
216 int iBlockSize = 1024*1024;
217 char *pBuf = new char[iBlockSize];
218 Bu::MyriadStream ms = mFs.open(
219 opt.lParams.first(), Bu::MyriadFs::Read );
220 Bu::File fs = Bu::File(
221 opt.lParams.last(), Bu::File::WriteNew );
222 int iRead = 0;
223 do
224 {
225 iRead = ms.read( pBuf, iBlockSize );
226 if( iRead > 0 )
227 {
228 fs.write( pBuf, iRead );
229 }
230 } while( iRead == iBlockSize );
231 delete[] pBuf;
232 }
233 break;
234
235 case modeMkdir:
236 {
237 if( opt.lParams.isEmpty() )
238 {
239 Bu::println("Specify at least one directory.");
240 return 1;
241 }
242 for( Bu::StringList::iterator i = opt.lParams.begin(); i; i++ )
243 {
244 mFs.mkDir( *i, 0777 );
245 }
246 }
247 break;
248
249 case modeInitialize:
250 Bu::println("MyriadFs initialized.\n");
251 break;
252
253 case modeRm:
254 {
255 if( opt.lParams.getSize() != 1 )
256 {
257 Bu::println("Specify a file path.");
258 return 1;
259 }
260 mFs.unlink( opt.lParams.first() );
261 }
262 break;
263
264 case modeNone:
265 break;
266 }
267
268 return 0;
269}
diff --git a/src/unit/myriad.unit b/src/unit/myriad.unit
new file mode 100644
index 0000000..f7bea97
--- /dev/null
+++ b/src/unit/myriad.unit
@@ -0,0 +1,385 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/string.h"
10#include "bu/file.h"
11#include "bu/myriad.h"
12#include "bu/myriadstream.h"
13#include "bu/array.h"
14
15#include "bu/sio.h"
16#include "bu/archive.h"
17#include "bu/md5.h"
18#include "bu/unitsuite.h"
19
20#include <stdlib.h>
21
22using namespace Bu;
23
24class VerifyObject
25{
26friend Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const VerifyObject &vo );
27friend Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, VerifyObject &vo );
28public:
29 VerifyObject( int iUnits ) :
30 iUnits( iUnits ),
31 iBytesWritten( 0 )
32 {
33 }
34
35 virtual ~VerifyObject()
36 {
37 }
38
39 int getBytesWritten()
40 {
41 return iBytesWritten;
42 }
43
44private:
45 int iUnits;
46 mutable int iBytesWritten;
47};
48
49Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const VerifyObject &vo )
50{
51 Md5 sum;
52 ar << vo.iUnits;
53 vo.iBytesWritten = sizeof(int);
54 sum.addData( &vo.iUnits, sizeof(int) );
55 for( int j = 0; j < vo.iUnits; j++ )
56 {
57 int iRand = random()%128;
58// ar << iRand;
59 Bu::String sDat( iRand );
60 for( int j = 0; j < iRand; j++ )
61 sDat[j] = (char)((uint8_t)(random()%256));
62 ar << sDat;
63 sum.addData( &iRand, sizeof(int) );
64 sum.addData( sDat.getStr(), iRand );
65 vo.iBytesWritten += sizeof(long) + iRand;
66 }
67 Bu::String sRes = sum.getResult();
68 ar << sRes;
69 vo.iBytesWritten += sizeof(long) + sRes.getSize();
70 return ar;
71}
72
73Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, VerifyObject &vo )
74{
75 Md5 sum;
76 ar >> vo.iUnits;
77 sum.addData( &vo.iUnits, sizeof(int) );
78 for( int j = 0; j < vo.iUnits; j++ )
79 {
80 int iRand;
81// ar >> iRand;
82 Bu::String sStr;
83 ar >> sStr;
84 iRand = sStr.getSize();
85 sum.addData( &iRand, sizeof(int) );
86 sum.addData( sStr.getStr(), iRand );
87 }
88 Bu::String sSum;
89 ar >> sSum;
90 unitTest( sSum == sum.getResult() );
91 int iTooMuch;
92 try
93 {
94 ar >> iTooMuch;
95 unitFailed("should have thrown an exception.");
96 }
97 catch( Bu::ExceptionBase &e )
98 {
99 }
100 return ar;
101}
102
103suite Myriad
104{
105 test setSize
106 {
107 String sFileName("myriad-XXXXXXX");
108
109 File fMyriad = tempFile( sFileName );
110 Myriad m( fMyriad, 32 );
111
112 MyriadStream ms = m.create( Myriad::ReadWrite );
113 ms.setSize( 150 );
114 ms.setPos( 145 );
115 char stuff[10];
116 unitTest( ms.read( stuff, 10 ) == 5 );
117
118 ms.setSize( 12 );
119 unitTest( ms.read( stuff, 10 ) == 0 );
120 unitTest( ms.write( "hello", 5 ) == 5 );
121 unitTest( ms.tell() == 17 );
122
123 ms.setSize( 500 );
124 unitTest( ms.tell() == 17 );
125 }
126
127 void addBlock( Stream &s, bool bAppend=true )
128 {
129 if( bAppend )
130 s.setPosEnd( 0 );
131 int iSize = (random()%1016)+8;
132 s.write( &iSize, 4 );
133 char *buf = new char[iSize-8];
134 for( int j = 0; j < iSize-8; j++ )
135 {
136 buf[j] = (j+iSize)%256;
137 }
138 if( random()%2 == 0 )
139 {
140 s.write( buf, iSize-8 );
141 }
142 else
143 {
144 for( int j = 0; j < iSize-8; )
145 {
146 int iAmnt = (random()%8)+1;
147 if( iAmnt+j > iSize-8 )
148 iAmnt = iSize-8-j;
149 iAmnt = s.write( buf+j, iAmnt );
150 j += iAmnt;
151 }
152 }
153 delete[] buf;
154 iSize = ~iSize;
155 s.write( &iSize, 4 );
156 }
157
158 void verifyBlock( Stream &s )
159 {
160 int iSize, iInv;
161 if( s.read( &iSize, 4 ) == 0 )
162 return;
163 if( iSize < 8 || iSize > 1024 )
164 throw ExceptionBase("Read bad data, %d", iSize );
165 char *buf = new char[iSize-8];
166 if( s.read( buf, iSize-8 ) < (Bu::size)iSize-8 )
167 {
168 delete[] buf;
169 throw ExceptionBase("Block failed verify (insuffient block data).");
170 }
171 for( int j = 0; j < iSize-8; j++ )
172 {
173 if( buf[j] != (char)((j+iSize)%256) )
174 {
175 char b = buf[j];
176 delete[] buf;
177 throw ExceptionBase("Block failed computed data verify "
178 "(%02X==%02X).", b, (char)((j+iSize)%256) );
179 }
180 }
181 delete[] buf;
182 if( s.read( &iInv, 4 ) < 4 )
183 throw ExceptionBase("Block failed verify (insufficient data).");
184 if( iInv != ~iSize )
185 throw ExceptionBase("Block failed inversion verify.");
186 }
187
188 void verifyStream( Stream &s )
189 {
190 s.setPos( 0 );
191 while( !s.isEos() )
192 verifyBlock( s );
193 }
194
195 test stressGrow
196 {
197 String sFileName("myriad-XXXXXXX");
198
199 File fMyriad = tempFile( sFileName );
200 Myriad m( fMyriad, 64 );
201
202 Array<int> aStreams;
203 for( int j = 0; j < 5; j++ )
204 {
205 aStreams.append( m.create( Bu::Myriad::Read ).getId() );
206 }
207
208 srandom( 512 );
209
210 for( int j = 0; j < 2500; j++ )
211 {
212 switch( random()%5 )
213 {
214 case 0:
215 aStreams.append( m.create( Bu::Myriad::Read ).getId() );
216 break;
217
218 case 1:
219 if( aStreams.getSize() > 0 )
220 {
221 int iStream = random()%aStreams.getSize();
222 {
223 MyriadStream ms = m.open( aStreams[iStream], Myriad::Read );
224 verifyStream( ms );
225 }
226 m.erase( aStreams[iStream] );
227 Array<int>::iterator i = aStreams.begin();
228 for( int k = 0; k < iStream; k++ )
229 i++;
230 aStreams.erase( i );
231 }
232 break;
233
234 default:
235 if( aStreams.getSize() == 0 )
236 {
237 aStreams.append(
238 m.create( Bu::Myriad::Read ).getId()
239 );
240 }
241 {
242 int iStream = random()%aStreams.getSize();
243 MyriadStream ms = m.open( aStreams[iStream], Myriad::ReadWrite );
244 addBlock( ms );
245 verifyStream( ms );
246 }
247 break;
248 }
249 }
250
251 for( Array<int>::iterator i = aStreams.begin(); i; i++ )
252 {
253 MyriadStream ms = m.open( *i, Myriad::Read );
254 verifyStream( ms );
255 }
256 }
257
258 test stressTruncate
259 {
260 String sFileName("myriad-XXXXXXX");
261
262 File fMyriad = tempFile( sFileName );
263 Myriad m( fMyriad, 128 );
264
265 Array<int> aStream;
266
267 for( int j = 0; j < 5; j++ )
268 {
269 aStream.append( m.create( Bu::Myriad::Read ).getId() );
270 }
271
272 srandom( 1024 );
273
274 char b;
275 for( int iter = 0; iter < 2500; iter++ )
276 {
277 for( Array<int>::iterator i = aStream.begin(); i; i++ )
278 {
279 MyriadStream ms = m.open( *i, Myriad::ReadWrite );
280 addBlock( ms, false );
281 ms.setSize( ms.tell() );
282 unitTest( ms.read( &b, 1 ) == 0 );
283 ms.setPos( 0 );
284 verifyBlock( ms );
285 unitTest( ms.read( &b, 1 ) == 0 );
286 }
287 }
288 }
289
290 test stressTruncate2
291 {
292 String sFileName("myriad-XXXXXXX");
293
294 Array<int> aStream;
295
296 setStepCount( 5*2500 + 5 );
297
298 {
299 File fMyriad = tempFile( sFileName );
300 Myriad m( fMyriad, 128 );
301
302 for( int j = 0; j < 5; j++ )
303 {
304 aStream.append( m.create( Bu::Myriad::Read ).getId() );
305 incProgress();
306 }
307 }
308
309 srandom( 1024 );
310
311 char b;
312 for( int iter = 0; iter < 2500; iter++ )
313 {
314 File fMyriad( sFileName, File::ReadWrite );
315 Myriad m( fMyriad );
316 for( Array<int>::iterator i = aStream.begin(); i; i++ )
317 {
318 MyriadStream ms = m.open( *i, Myriad::ReadWrite );
319 addBlock( ms, false );
320 ms.setSize( ms.tell() );
321 unitTest( ms.read( &b, 1 ) == 0 );
322 ms.setPos( 0 );
323 verifyBlock( ms );
324 unitTest( ms.read( &b, 1 ) == 0 );
325 incProgress();
326 }
327 }
328 }
329
330 test stressArchive
331 {
332 String sFileName("myriad-XXXXXX");
333 Array<int> aStream;
334
335 srandom( 2096 );
336
337 setStepCount( 15*250 + 15 );
338
339 {
340 File fMyriad = tempFile( sFileName );
341 Myriad m( fMyriad, 1024 );
342
343 for( int j = 0; j < 15; j++ )
344 {
345 MyriadStream ms = m.create( Myriad::Write );
346 int iStream = ms.getId();
347 aStream.append( iStream );
348 VerifyObject vo( random()%1024 );
349 {
350 Archive ar( ms, Archive::save );
351 ar << vo;
352 unitTest( ms.tell() == vo.getBytesWritten() );
353 ms.setSize( ms.tell() );
354 }
355 unitTest( m.getSize( iStream ) == vo.getBytesWritten() );
356 incProgress();
357 }
358 }
359
360 for( int iter = 0; iter < 250; iter++ )
361 {
362 File fMyriad( sFileName, File::ReadWrite );
363 Myriad m( fMyriad );
364 for( Array<int>::iterator i = aStream.begin(); i; i++ )
365 {
366 VerifyObject vo( random()%1024 );
367 {
368 MyriadStream ms = m.open( *i, Myriad::Read );
369 Archive ar( ms, Archive::load );
370 ar >> vo;
371 }
372 {
373 MyriadStream ms = m.open( *i, Myriad::WriteNew );
374 Archive ar( ms, Archive::save );
375 ar << vo;
376 unitTest( ms.tell() == vo.getBytesWritten() );
377 ms.setSize( ms.tell() );
378 }
379 unitTest( m.getSize( *i ) == vo.getBytesWritten() );
380 incProgress();
381 }
382 }
383 }
384}
385
diff --git a/src/unstable/bitstring.cpp b/src/unstable/bitstring.cpp
index 21c1316..b80c073 100644
--- a/src/unstable/bitstring.cpp
+++ b/src/unstable/bitstring.cpp
@@ -209,7 +209,7 @@ void Bu::BitString::flipBit( long iBit )
209 caData[iBit/8] ^= (1<<(iBit%8)); 209 caData[iBit/8] ^= (1<<(iBit%8));
210} 210}
211 211
212bool Bu::BitString::getBit( long iBit ) 212bool Bu::BitString::getBit( long iBit ) const
213{ 213{
214 if( iBit >= iBits || iBit < 0 ) return false; 214 if( iBit >= iBits || iBit < 0 ) return false;
215 if( (caData[iBit/8] & (1<<(iBit%8))) == 0 ) 215 if( (caData[iBit/8] & (1<<(iBit%8))) == 0 )
@@ -224,7 +224,7 @@ long Bu::BitString::getBitLength()
224 return iBits; 224 return iBits;
225} 225}
226 226
227long Bu::BitString::getSize() 227long Bu::BitString::getSize() const
228{ 228{
229 return iBits; 229 return iBits;
230} 230}
@@ -311,6 +311,14 @@ void Bu::BitString::clear()
311 } 311 }
312} 312}
313 313
314void Bu::BitString::fill()
315{
316 if( caData != NULL )
317 {
318 memset( caData, 0xff, iBytes );
319 }
320}
321
314bool Bu::BitString::setBitLength( long iLength, bool bClear ) 322bool Bu::BitString::setBitLength( long iLength, bool bClear )
315{ 323{
316 return setSize( iLength, bClear ); 324 return setSize( iLength, bClear );
diff --git a/src/unstable/bitstring.h b/src/unstable/bitstring.h
index afc22fb..70ba822 100644
--- a/src/unstable/bitstring.h
+++ b/src/unstable/bitstring.h
@@ -88,7 +88,7 @@ namespace Bu
88 *@param iBit The index of the bit to test. 88 *@param iBit The index of the bit to test.
89 *@returns True for a 1, false for a 0. 89 *@returns True for a 1, false for a 0.
90 */ 90 */
91 bool getBit( long iBit ); 91 bool getBit( long iBit ) const;
92 92
93 /** 93 /**
94 * Inverts the entire BitString, in effect this calls flipBit on every 94 * Inverts the entire BitString, in effect this calls flipBit on every
@@ -106,7 +106,7 @@ namespace Bu
106 DEPRECATED 106 DEPRECATED
107 long getBitLength(); 107 long getBitLength();
108 108
109 long getSize(); 109 long getSize() const;
110 110
111 /** 111 /**
112 * Sets the entire BitString to zeros, but it does it very quickly. 112 * Sets the entire BitString to zeros, but it does it very quickly.
@@ -115,6 +115,12 @@ namespace Bu
115 void clear(); 115 void clear();
116 116
117 /** 117 /**
118 * Sets the entire BitString to ones, but it does it very quickly.
119 * This operation runs in O(N).
120 */
121 void fill();
122
123 /**
118 * Gets another BitString that is autonomous of the current one 124 * Gets another BitString that is autonomous of the current one
119 * (contains a copy of the memory, not a pointer) and contains a subset 125 * (contains a copy of the memory, not a pointer) and contains a subset
120 * of the data in the current BitString. This is an inclusive 126 * of the data in the current BitString. This is an inclusive
diff --git a/src/unstable/myriadcache.cpp b/src/unstable/myriadcache.cpp
new file mode 100644
index 0000000..c9eb9c4
--- /dev/null
+++ b/src/unstable/myriadcache.cpp
@@ -0,0 +1,8 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/myriadcache.h"
diff --git a/src/unstable/myriadcache.h b/src/unstable/myriadcache.h
new file mode 100644
index 0000000..f71f9b5
--- /dev/null
+++ b/src/unstable/myriadcache.h
@@ -0,0 +1,150 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MYRIAD_CACHE_H
9#define BU_MYRIAD_CACHE_H
10
11#include "bu/cachebase.h"
12#include "bu/myriad.h"
13#include "bu/myriadstream.h"
14#include "bu/file.h"
15#include "bu/streamstack.h"
16
17namespace Bu
18{
19 template<typename keytype, typename obtype>
20 class MyriadCache : public Bu::CacheBase<keytype, obtype>
21 {
22 public:
23 MyriadCache( Bu::Stream &sStore, int iBlockSize=512, int iPreallocate=8 ) :
24 sStore( sStore ),
25 mStore( sStore, iBlockSize, iPreallocate ),
26 bStructureChanged( false )
27 {
28 try
29 {
30 Bu::ReadWriteMutex::ReadLocker l( rwStore );
31 Bu::MyriadStream ms = mStore.open(
32 1, Bu::Myriad::WriteNew|Bu::Myriad::Read
33 );
34 Bu::Archive ar( ms, Bu::Archive::load );
35 uint8_t uVer;
36 ar >> uVer;
37 switch( uVer )
38 {
39 case 0:
40 ar >> hIndex;
41 break;
42 }
43 }
44 catch(...)
45 {
46 try
47 {
48 mStore.open( 1, Bu::Myriad::Create|Bu::Myriad::ReadWrite );
49 _sync();
50 }
51 catch(...)
52 {
53 throw Bu::ExceptionBase("Error creating index stream.");
54 }
55 }
56 }
57
58 virtual ~MyriadCache()
59 {
60 Bu::CacheBase<keytype,obtype>::sync();
61 }
62
63 using typename Bu::CacheBase<keytype,obtype>::KeyList;
64 using typename Bu::CacheBase<keytype,obtype>::ObjectType;
65
66 virtual typename Bu::CacheBase<keytype,obtype>::KeyList getKeys() const
67 {
68 Bu::ReadWriteMutex::ReadLocker rl( rwStore );
69 return hIndex.getKeys();
70 }
71
72 virtual int getSize() const
73 {
74 Bu::ReadWriteMutex::ReadLocker rl( rwStore );
75 return hIndex.getSize();
76 }
77
78 protected:
79 virtual bool _has( const keytype &key )
80 {
81 Bu::ReadWriteMutex::ReadLocker rl( rwStore );
82 return hIndex.has( key );
83 }
84
85 virtual void _create( const obtype *o )
86 {
87 Bu::ReadWriteMutex::WriteLocker wl( rwStore );
88 {
89 Bu::Myriad::StreamId id = mStore.allocate();
90 hIndex.insert( o->getKey(), id );
91 }
92 _save( o );
93
94 bStructureChanged = true;
95 }
96
97 virtual void _erase( const keytype &k )
98 {
99 Bu::ReadWriteMutex::WriteLocker wl( rwStore );
100 mStore.erase( hIndex.get( k ) );
101 hIndex.erase( k );
102
103 bStructureChanged = true;
104 }
105
106 virtual obtype *_load(
107 typename Bu::CacheObject<keytype, obtype>::Initializer &initObj,
108 const keytype &k
109 )
110 {
111 Bu::MyriadStream ms = mStore.openStream( hIndex.get( k ) );
112 return _cacheObjectLoad<keytype, obtype>( initObj, k, ms );
113 }
114
115 virtual void _save( const obtype *o )
116 {
117 Bu::MyriadStream ms = mStore.openStream( hIndex.get( o->getKey() ) );
118 _cacheObjectSave( ms, o );
119 ms.setSize( ms.tell() );
120
121 mStore.sync();
122 }
123
124 virtual void _sync()
125 {
126 Bu::ReadWriteMutex::WriteLocker wl( rwStore );
127 if( !bStructureChanged )
128 return;
129
130 Bu::MyriadStream ms = mStore.openStream( 1 );
131 Bu::Archive ar( ms, Bu::Archive::save );
132 ar << (uint8_t)0 << hIndex;
133 ar.close();
134 ms.setSize( ms.tell() );
135
136 bStructureChanged = false;
137
138 mStore.sync();
139 }
140
141 private:
142 Bu::Stream &sStore;
143 Bu::Myriad mStore;
144 Bu::Hash<keytype, int> hIndex;
145 mutable Bu::ReadWriteMutex rwStore;
146 bool bStructureChanged;
147 };
148}
149
150#endif
diff --git a/src/unstable/myriadfs.cpp b/src/unstable/myriadfs.cpp
new file mode 100644
index 0000000..f748a53
--- /dev/null
+++ b/src/unstable/myriadfs.cpp
@@ -0,0 +1,739 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/config.h"
9#include "bu/myriadfs.h"
10#include "bu/myriadstream.h"
11#include "bu/mutexlocker.h"
12
13#include <string.h>
14#include <unistd.h>
15#include <time.h>
16
17#include "bu/sio.h"
18using Bu::sio;
19using Bu::Fmt;
20
21namespace Bu { subExceptionDef( MyriadFsException ) }
22
23#define Myriad_Fs_MAGIC_CODE ((char *)"\xa7\x18\x8b\x39")
24
25Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) :
26 rStore( rStore ),
27 mStore( rStore, iBlockSize ),
28 iUser( 0 ),
29 iGroup( 0 )
30{
31#ifndef WIN32
32 iUser = getuid();
33 iGroup = getgid();
34#endif
35
36 if( mStore.exists( 1 ) )
37 {
38 // Check to see if this is a MyriadFs stream.
39 Bu::MyriadStream ms = mStore.open( 1, Bu::Myriad::Read );
40 char sMagic[4];
41 if( ms.read( sMagic, 4 ) < 4 )
42 throw MyriadFsException("The provided stream does not appear to be "
43 "a MyriadFs stream.");
44 if( ::strncmp( sMagic, Myriad_Fs_MAGIC_CODE, 4 ) )
45 throw MyriadFsException("The provided stream does not appear to be "
46 "a MyriadFs stream.");
47
48 int8_t iVer;
49 ms.read( &iVer, 1 );
50
51 int32_t iNumNodes;
52 ms.read( &iNumNodes, 4 );
53 for( int32_t j = 0; j < iNumNodes; j++ )
54 {
55 int32_t iNode;
56 int32_t iPos;
57 ms.read( &iNode, 4 );
58 ms.read( &iPos, 4 );
59 hNodeIndex.insert( iNode, iPos );
60 }
61 }
62 else
63 {
64 // Create initial header stream
65 {
66 Bu::MyriadStream ms = mStore.open(
67 1, Bu::Myriad::WriteNew|Bu::Myriad::Exclusive );
68 ms.write( Myriad_Fs_MAGIC_CODE, 4 );
69 int8_t iVer = 1;
70 int32_t iTmp = 1;
71 ms.write( &iVer, 1 );
72 ms.write( &iTmp, 4 ); // iNumNodes
73 iTmp = 0;
74 ms.write( &iTmp, 4 ); // iInode
75 ms.write( &iTmp, 4 ); // iPosition
76 hNodeIndex.insert( 0, 0 );
77 }
78
79 // Create initial inode stream, with one root node.
80 {
81 Bu::MyriadStream ms = mStore.open(
82 2, Bu::Myriad::WriteNew|Bu::Myriad::Exclusive );
83 RawStat rs;
84 rs.iNode = 0;
85 rs.iUser = iUser;
86 rs.iGroup = iGroup;
87 rs.uPerms = 0755|typeDir;
88 rs.iLinks = 1;
89 rs.uStreamIndex = 3;
90 rs.iCTime = rs.iMTime = rs.iATime = time(NULL);
91 ms.write( &rs, sizeof(RawStat) );
92 }
93
94 // Create inode 0's storage stream.
95 {
96 Bu::MyriadStream ms = mStore.open(
97 3, Bu::Myriad::WriteNew|Bu::Myriad::Exclusive );
98 int32_t iTmp32 = 0;
99 ms.write( &iTmp32, 4 ); // iChildCount
100 }
101 }
102}
103
104Bu::MyriadFs::~MyriadFs()
105{
106 writeHeader();
107}
108
109void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf )
110{
111 Bu::MutexLocker lLock( mAccess );
112 int32_t iParent;
113 int32_t iNode = lookupInode( sPath, iParent );
114 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::Read );
115 stat( iNode, rBuf, is );
116}
117
118Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int iMode,
119 uint16_t uPerms )
120{
121 Bu::MutexLocker lLock( mAccess );
122 int32_t iParent = -1;
123 int32_t iNode;
124 try
125 {
126 iNode = lookupInode( sPath, iParent );
127// sio << "File found." << sio.nl;
128 // The file was found
129 Bu::MyriadStream ms = openByInode( iNode );
130 if( (iMode&Truncate) )
131 {
132 ms.setSize( 0 );
133 }
134 return ms;
135 }
136 catch( Bu::MyriadFsException &e )
137 {
138 if( iParent < 0 )
139 throw;
140
141 // This means that an intermediate path component couldn't be found
142 if( e.getErrorCode() == 1 )
143 throw;
144
145 // The file wasn't found, but the path leading up to it was.
146 // first, figure out the final path element...
147 Bu::String sName = filePart( sPath );
148// sio << "End filename: " << sName << sio.nl;
149// sio << "Parent inode: " << iParent << sio.nl;
150 iNode = create( iParent, sName, (uPerms&permMask)|typeRegFile, 0 );
151// sio << "New iNode: " << iNode << sio.nl;
152 return openByInode( iNode );
153 }
154}
155
156void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms )
157{
158 create( sPath, iPerms, 0 );
159}
160
161void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
162 uint16_t iDevHi, uint16_t iDevLo )
163{
164 create( sPath, iPerms, ((uint32_t)iDevHi<<16)|(uint32_t)iDevLo );
165}
166
167void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
168 uint32_t uSpecial )
169{
170 Bu::MutexLocker lLock( mAccess );
171 int32_t iParent = -1;
172// int32_t iNode;
173 try
174 {
175 /*iNode =*/ lookupInode( sPath, iParent );
176// sio << "File found." << sio.nl;
177 }
178 catch( Bu::MyriadFsException &e )
179 {
180 if( iParent < 0 )
181 throw;
182
183 // This means that an intermediate path component couldn't be found
184 if( e.getErrorCode() == 1 )
185 throw;
186
187 // The file wasn't found, but the path leading up to it was.
188 // first, figure out the final path element...
189 Bu::String sName = filePart( sPath );
190// sio << "End filename: " << sName << sio.nl;
191// sio << "Parent inode: " << iParent << sio.nl;
192 /*iNode =*/ create( iParent, sName, iPerms, uSpecial );
193// sio << "New iNode: " << iNode << sio.nl;
194 }
195 // The file was found
196 //throw Bu::MyriadFsException("Path already exists.");
197}
198
199void Bu::MyriadFs::mkDir( const Bu::String &sPath, uint16_t iPerms )
200{
201 create( sPath, (iPerms&permMask)|typeDir, 0 );
202}
203
204void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget,
205 const Bu::String &sPath )
206{
207 Bu::MutexLocker lLock( mAccess );
208 int32_t iParent = -1;
209 int32_t iNode;
210 try
211 {
212 iNode = lookupInode( sPath, iParent );
213 }
214 catch( Bu::MyriadFsException &e )
215 {
216 if( iParent < 0 )
217 throw;
218
219 // This means that an intermediate path component couldn't be found
220 if( e.getErrorCode() == 1 )
221 throw;
222
223 // The file wasn't found, but the path leading up to it was.
224 // first, figure out the final path element...
225 Bu::String sName = filePart( sPath );
226// sio << "End filename: " << sName << sio.nl;
227// sio << "Parent inode: " << iParent << sio.nl;
228 iNode = create( iParent, sName, 0777|typeSymLink, 0 );
229// sio << "New iNode: " << iNode << sio.nl;
230 MyriadStream ms = openByInode( iNode );
231 ms.write( sTarget );
232 return;
233 }
234 throw Bu::MyriadFsException("Path already exists.");
235}
236
237void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget,
238 const Bu::String &sPath )
239{
240 Bu::MutexLocker lLock( mAccess );
241 int32_t iParent = -1;
242 int32_t iNode;
243
244 iNode = lookupInode( sTarget, iParent );
245
246 try
247 {
248 lookupInode( sPath, iParent );
249 throw Bu::MyriadFsException("Path already exists.");
250 }
251 catch( Bu::MyriadFsException &e )
252 {
253 if( iParent < 0 )
254 throw;
255
256 // This means that an intermediate path component couldn't be found
257 if( e.getErrorCode() == 1 )
258 throw;
259
260 // The file wasn't found, but the path leading up to it was.
261 // first, figure out the final path element...
262 Bu::String sName = filePart( sPath );
263// sio << "End filename: " << sName << sio.nl;
264// sio << "Parent inode: " << iParent << sio.nl;
265 addToDir( iParent, iNode, sName );
266 MyriadStream is = mStore.open( 2, Bu::Myriad::ReadWrite );
267 RawStat rs;
268 readInode( iNode, rs, is );
269 rs.iLinks++;
270 writeInode( rs, is );
271 }
272}
273
274Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath )
275{
276 Bu::MutexLocker lLock( mAccess );
277 int32_t iParent = -1;
278 int32_t iNode;
279 iNode = lookupInode( sPath, iParent );
280 MyriadStream ms = openByInode( iNode );
281 Bu::String sRet;
282 sRet.setSize( ms.getSize() );
283 ms.read( sRet.getStr(), ms.getSize() );
284 return sRet;
285}
286
287Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath )
288{
289 Bu::MutexLocker lLock( mAccess );
290 int32_t iParent = -1;
291 int32_t iNode = lookupInode( sPath, iParent );
292 return readDir( iNode );
293}
294
295void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime,
296 int64_t iMTime )
297{
298 Bu::MutexLocker lLock( mAccess );
299 int32_t iParent = -1;
300 int32_t iNode;
301
302 iNode = lookupInode( sPath, iParent );
303
304 setTimes( iNode, iATime, iMTime );
305}
306
307void Bu::MyriadFs::unlink( const Bu::String &sPath )
308{
309 Bu::MutexLocker lLock( mAccess );
310 int32_t iParent = -1;
311// int32_t iNode;
312
313 /*iNode =*/ lookupInode( sPath, iParent );
314
315 Dir lDir = readDir( iParent );
316
317 Bu::String sName = filePart( sPath );
318
319 for( Dir::iterator i = lDir.begin(); i; i++ )
320 {
321 if( sName == (*i).sName )
322 {
323 RawStat rs;
324 readInode( (*i).iNode, rs );
325 if( (rs.uPerms&typeMask) == typeDir )
326 {
327 MyriadStream msDir = mStore.open(
328 rs.uStreamIndex, Bu::Myriad::Read
329 );
330 int32_t iCount;
331 msDir.read( &iCount, 4 );
332 if( iCount > 0 )
333 {
334 throw Bu::MyriadFsException("Directory not empty.");
335 }
336 }
337 if( --rs.iLinks == 0 )
338 {
339 destroyNode( (*i).iNode );
340 }
341 else
342 {
343 writeInode( rs );
344 }
345 lDir.erase( i );
346 break;
347 }
348 }
349
350 Bu::MyriadStream ms = openByInode( iParent );
351 int32_t iNumChildren = lDir.getSize();
352 ms.write( &iNumChildren, 4 );
353 for( Dir::iterator i = lDir.begin(); i; i++ )
354 {
355 ms.write( &(*i).iNode, 4 );
356 uint8_t iSize = (*i).sName.getSize();
357 ms.write( &iSize, 1 );
358 ms.write( (*i).sName.getStr(), iSize );
359 }
360 ms.setSize( ms.tell() );
361}
362
363void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize )
364{
365 Bu::MutexLocker lLock( mAccess );
366 int32_t iParent = -1;
367 int32_t iNode;
368 iNode = lookupInode( sPath, iParent );
369 MyriadStream ms = openByInode( iNode );
370 ms.setSize( iSize );
371}
372
373void Bu::MyriadFs::rename( const Bu::String &sFrom, const Bu::String &sTo )
374{
375 Bu::MutexLocker lLock( mAccess );
376 mkHardLink( sFrom, sTo );
377 unlink( sFrom );
378}
379
380dev_t Bu::MyriadFs::devToSys( uint32_t uDev )
381{
382 return (((uDev&0xFFFF0000)>>8)&0xFF00) | ((uDev&0xFF));
383}
384
385uint32_t Bu::MyriadFs::sysToDev( dev_t uDev )
386{
387 return (((uint32_t)uDev&0xFF00)<<8) | ((uint32_t)uDev&0xFF);
388}
389
390int32_t Bu::MyriadFs::lookupInode( const Bu::String &sPath, int32_t &iParent )
391{
392 if( sPath == "/" )
393 {
394 return 0;
395 }
396 if( sPath[0] == '/' )
397 {
398 // Absolute lookup
399 return lookupInode( sPath.begin()+1, 0, iParent );
400 }
401 else
402 {
403 // Relative lookup
404 throw Bu::ExceptionBase(
405 "Relative lookups in MyriadFs are not working yet.");
406 }
407}
408
409int32_t Bu::MyriadFs::lookupInode( Bu::String::const_iterator iStart,
410 int32_t iNode, int32_t &iParent )
411{
412 iParent = iNode;
413
414 Bu::String::const_iterator iEnd = iStart.find('/');
415 Bu::String sTok( iStart, iEnd );
416
417// sio << "Direcotry component: " << sTok << sio.nl;
418
419 Dir lDir = readDir( iNode );
420
421 for( Dir::iterator i = lDir.begin(); i; i++ )
422 {
423 if( (*i).sName == sTok )
424 {
425 // We found an item
426 if( !iEnd )
427 {
428 // It's the last one in the requested path, return it
429 return (*i).iNode;
430 }
431 else
432 {
433 // Not the last one in our path, double check it's a dir
434 if( ((*i).uPerms&typeMask) == typeDir )
435 {
436 return lookupInode( iEnd+1, (*i).iNode, iParent );
437 }
438 else
439 {
440 iParent = -1;
441 throw Bu::MyriadFsException(
442 "Element '%s' in given path is not a directory.",
443 sTok.getStr() );
444 }
445 }
446 }
447 }
448
449 if( iEnd )
450 throw Bu::MyriadFsException( 1, "Path not found");
451 else
452 throw Bu::MyriadFsException( 2, "Path not found");
453}
454
455void Bu::MyriadFs::readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs )
456{
457 rIs.setPos( hNodeIndex.get( iNode )*sizeof(RawStat) );
458 if( rIs.read( &rs, sizeof(RawStat) ) < (int)sizeof(RawStat) )
459 throw Bu::MyriadFsException("Filesystem corruption detected.");
460 if( rs.iNode != iNode )
461 throw Bu::MyriadFsException("Filesystem corruption detected.");
462}
463
464void Bu::MyriadFs::readInode( int32_t iNode, RawStat &rs )
465{
466 MyriadStream ms = mStore.open( 2, Bu::Myriad::Read );
467 readInode( iNode, rs, ms );
468}
469
470void Bu::MyriadFs::writeInode( const RawStat &rs,
471 MyriadStream &rOs )
472{
473 rOs.setSize( hNodeIndex.getSize()*sizeof(RawStat) );
474 rOs.setPos( hNodeIndex.get( rs.iNode )*sizeof(RawStat) );
475 if( rOs.write( &rs, sizeof(RawStat) ) < (int)sizeof(RawStat) )
476 throw Bu::MyriadFsException("Error writing inode to header stream.");
477}
478
479void Bu::MyriadFs::writeInode( const RawStat &rs )
480{
481 MyriadStream ms = mStore.open( 2, Bu::Myriad::Write );
482 writeInode( rs, ms );
483}
484
485Bu::MyriadFs::Dir Bu::MyriadFs::readDir( int32_t iNode )
486{
487 Bu::MyriadStream ms = openByInode( iNode );
488 int32_t iNumChildren = 0;
489 ms.read( &iNumChildren, 4 );
490
491 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::Read );
492 Dir lDir;
493 // sio << "Reading dir " << iNode << ", " << iNumChildren << " entries:" << sio.nl;
494 for( int32_t j = 0; j < iNumChildren; j++ )
495 {
496 int32_t iChildNode = 0;
497 if( ms.read( &iChildNode, 4 ) < 4 )
498 {
499 throw Bu::MyriadFsException(
500 "Failed to read iChildNode from directory.");
501 }
502 Stat s;
503 stat( iChildNode, s, is );
504 uint8_t uLen;
505 if( ms.read( &uLen, 1 ) < 1 )
506 {
507 throw Bu::MyriadFsException(
508 "Failed to read uLen from directory.");
509 }
510 s.sName.setSize( uLen );
511 if( ms.read( s.sName.getStr(), uLen ) < uLen )
512 {
513 throw Bu::MyriadFsException(
514 "Failed to read sName from directory.");
515 }
516 lDir.append( s );
517
518// sio << " " << s.sName << sio.nl;
519 }
520
521 return lDir;
522}
523
524Bu::MyriadStream Bu::MyriadFs::openByInode( int32_t iNode )
525{
526 RawStat rs;
527 readInode( iNode, rs );
528 switch( (rs.uPerms&typeMask) )
529 {
530 case typeDir:
531 case typeSymLink:
532 case typeRegFile:
533 return mStore.open( rs.uStreamIndex, Bu::Myriad::ReadWrite );
534
535 default:
536 throw Bu::MyriadFsException(
537 "inode incorrect type for low-level openByInode.");
538 }
539}
540
541void Bu::MyriadFs::addToDir( int32_t iDir, int32_t iNode,
542 const Bu::String &sName )
543{
544 if( sName.getSize() > 255 )
545 {
546 throw Bu::MyriadFsException("Filename too long, max is 255 bytes.");
547 }
548 Bu::MyriadStream ms = openByInode( iDir );
549 int32_t iNumChildren = 0;
550 ms.read( &iNumChildren, 4 );
551 iNumChildren++;
552 ms.setPos( 0 );
553 ms.write( &iNumChildren, 4 );
554 ms.setPosEnd( 0 );
555 ms.write( &iNode, 4 );
556 uint8_t uLen = sName.getSize();
557 ms.write( &uLen, 1 );
558 ms.write( sName.getStr(), uLen );
559}
560
561int32_t Bu::MyriadFs::create( int32_t iParent, const Bu::String &sName,
562 uint16_t uPerms, uint32_t uSpecial )
563{
564 int32_t iNode = allocInode( uPerms, uSpecial );
565 addToDir( iParent, iNode, sName );
566 return iNode;
567}
568
569int32_t Bu::MyriadFs::allocInode( uint16_t uPerms, uint32_t uSpecial )
570{
571 int32_t iNode = 0;
572 for(; iNode < 0xfffffff; iNode++ )
573 {
574 if( !hNodeIndex.has( iNode ) )
575 {
576 hNodeIndex.insert( iNode, hNodeIndex.getSize() );
577 RawStat rs;
578 rs.iNode = iNode;
579 rs.iUser = iUser;
580 rs.iGroup = iGroup;
581 rs.uPerms = uPerms;
582 rs.iLinks = 1;
583 switch( (uPerms&typeMask) )
584 {
585 case typeRegFile:
586 case typeSymLink:
587 rs.uStreamIndex = mStore.allocate();
588 break;
589
590 case typeDir:
591// sio << "Creating directory node, storage: "
592// << rs.uStreamIndex << sio.nl;
593 {
594 Bu::MyriadStream msDir = mStore.create(
595 Bu::Myriad::Write
596 );
597 rs.uStreamIndex = msDir.getId();
598 uint32_t uSize = 0;
599 msDir.write( &uSize, 4 );
600 }
601 break;
602
603 case typeChrDev:
604 case typeBlkDev:
605 rs.uStreamIndex = uSpecial;
606 break;
607
608 default:
609 rs.uStreamIndex = 0;
610 break;
611 }
612 rs.iATime = time(NULL);
613 rs.iMTime = time(NULL);
614 rs.iCTime = time(NULL);
615 writeInode( rs );
616
617 return iNode;
618 }
619 }
620
621 throw Bu::MyriadFsException(
622 "No inode could be allocated. You've run out!");
623}
624
625void Bu::MyriadFs::stat( int32_t iNode, Stat &rBuf, MyriadStream &rIs )
626{
627 RawStat rs;
628 readInode( iNode, rs, rIs );
629 rBuf.iNode = iNode;
630 rBuf.iUser = rs.iUser;
631 rBuf.iGroup = rs.iGroup;
632 rBuf.uPerms = rs.uPerms;
633 rBuf.iLinks = rs.iLinks;
634 rBuf.iATime = rs.iATime;
635 rBuf.iMTime = rs.iMTime;
636 rBuf.iCTime = rs.iCTime;
637 rBuf.uDev = 0;
638 rBuf.iSize = 0;
639 switch( (rBuf.uPerms&typeMask) )
640 {
641 case typeRegFile:
642 case typeSymLink:
643 rBuf.iSize = mStore.getSize( rs.uStreamIndex );
644 break;
645
646 case typeChrDev:
647 case typeBlkDev:
648 rBuf.uDev = rs.uStreamIndex;
649 break;
650
651 default:
652 rBuf.iSize = 0;
653 break;
654 }
655}
656
657void Bu::MyriadFs::writeHeader()
658{
659 Bu::MyriadStream ms = mStore.open( 1, Bu::Myriad::Write );
660 ms.write( Myriad_Fs_MAGIC_CODE, 4 );
661 int8_t iVer = 1;
662 int32_t iNumNodes = hNodeIndex.getSize();
663 ms.write( &iVer, 1 );
664 ms.write( &iNumNodes, 4 ); // iNumNodes
665 for( NodeIndex::iterator i = hNodeIndex.begin(); i; i++ )
666 {
667 int32_t iNode = i.getKey();
668 int32_t iPosition = i.getValue();
669 ms.write( &iNode, 4 );
670 ms.write( &iPosition, 4 );
671 }
672
673 // Truncate the stream afterwards so we don't use up too much space.
674 ms.setSize( ms.tell() );
675}
676
677void Bu::MyriadFs::setTimes( int32_t iNode, int64_t iATime, int64_t iMTime )
678{
679 RawStat rs;
680 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::ReadWrite );
681
682 readInode( iNode, rs, is );
683 rs.iATime = iATime;
684 rs.iMTime = iMTime;
685 writeInode( rs, is );
686}
687
688void Bu::MyriadFs::destroyNode( int32_t iNode )
689{
690 if( iNode == 0 )
691 throw Bu::MyriadFsException("You cannot destroy the root.");
692
693 uint32_t iPosition;
694 RawStat rsOld;
695
696 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::ReadWrite );
697
698 // This will be overwritten with the last node
699 iPosition = hNodeIndex.get( iNode );
700 readInode( iNode, rsOld, is );
701
702 switch( (rsOld.uPerms&typeMask) )
703 {
704 case typeRegFile:
705 case typeDir:
706 case typeSymLink:
707 mStore.erase( rsOld.uStreamIndex );
708 break;
709 }
710
711 hNodeIndex.erase( iNode );
712
713 // Read the last node, can't use the helpers, because we don't know the
714 // iNode yet.
715 if( iPosition != hNodeIndex.getSize() )
716 {
717 // If this is the last node, then we don't need to do anything, but
718 // this case handles what to do if we aren't on the last node
719 RawStat rs;
720 is.setPos( (hNodeIndex.getSize())*sizeof(RawStat) );
721 is.read( &rs, sizeof(RawStat) );
722
723 hNodeIndex.get( rs.iNode ) = iPosition;
724 writeInode( rs, is );
725 }
726
727 is.setSize( hNodeIndex.getSize() * sizeof(RawStat) );
728}
729
730Bu::String Bu::MyriadFs::filePart( const Bu::String &sPath )
731{
732 Bu::String::const_iterator iStart = sPath.begin();
733 if( *iStart == '/' )
734 iStart++;
735 for( Bu::String::const_iterator iEnd = iStart.find('/'); iEnd;
736 iStart = iEnd+1, iEnd = iStart.find('/') ) { }
737 return Bu::String( iStart, sPath.end() );
738}
739
diff --git a/src/unstable/myriadfs.h b/src/unstable/myriadfs.h
new file mode 100644
index 0000000..e3008bc
--- /dev/null
+++ b/src/unstable/myriadfs.h
@@ -0,0 +1,211 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef MYRIAD_FS_H
9#define MYRIAD_FS_H
10
11#include <sys/types.h>
12
13#include "bu/myriad.h"
14#include "bu/debugmutex.h"
15
16namespace Bu
17{
18 class Stream;
19
20 subExceptionDecl( MyriadFsException );
21
22 /**
23 * A POSIX compliant, node based filesystem built on top of Myriad.
24 *
25 * A header is placed into stream 1.
26 * Header format:
27 * int32_t iMagicHeader (A7188B39)
28 * int8_t iVersion (1)
29 * int32_t iNumNodes
30 * NodeLookup[iNumNodes] nNode
31 *
32 * Node lookup:
33 * int32_t iInode
34 * int32_t iPosition
35 *
36 * The node headers or inode structures have a base size of 44 bytes.
37 * The name is stored in the directory format.
38 * Basic node header format:
39 * int32_t iNode
40 * int32_t iUser
41 * int32_t iGroup
42 * uint16_t uPerms
43 * int16_t iLinks
44 * uint32_t uStreamIndex
45 * int64_t iATime
46 * int64_t iMTime
47 * int64_t iCTime
48 *
49 * Some types get special formats for their assosiated data stream, or
50 * other special considerations, here's a list:
51 *
52 * - typeFifo: No stream, uStreamIndex unused (probably)
53 * - typeChrDev: No stream, uStreamIndex is device hi/lo
54 * - typeDir: The stream contains a directory contents listing, described
55 * below
56 * - typeBlkDev: No stream, uStreamIndex is device hi/lo
57 * - typeRegFile: The stream is the file data
58 * - typeSymLink: The stream is the destination of the symlink
59 * - typeSocket: No steram, uStreamIndex unused (probably)
60 *
61 * Directory streams have this simple listing format. They contain a list
62 * of all child elements, with no particular order at the moment. The . and
63 * .. entries are not listed, they are implicit:
64 * int32_t iNumNodes
65 * NodeTable[iNumNodes] nChildren
66 *
67 * NodeTable:
68 * int32_t iInode
69 * uint8_t uNameSize
70 * char[uNameSize] sName
71 */
72 class MyriadFs
73 {
74 public:
75 MyriadFs( Bu::Stream &rStore, int iBlockSize=512 );
76 virtual ~MyriadFs();
77
78 enum
79 {
80 permOthX = 0000001,
81 permOthW = 0000002,
82 permOthR = 0000004,
83 permGrpX = 0000010,
84 permGrpW = 0000020,
85 permGrpR = 0000040,
86 permUsrX = 0000100,
87 permUsrW = 0000200,
88 permUsrR = 0000400,
89 permSticky = 0001000,
90 permSetGid = 0002000,
91 permSetUid = 0004000,
92 permMask = 0007777,
93 typeFifo = 0010000,
94 typeChrDev = 0020000,
95 typeDir = 0040000,
96 typeBlkDev = 0060000,
97 typeRegFile = 0100000,
98 typeSymLink = 0120000,
99 typeSocket = 0140000,
100 typeMask = 0170000
101 };
102
103 enum
104 {
105 Read = 0x01, ///< Open file for reading
106 Write = 0x02, ///< Open file for writing
107 Create = 0x04, ///< Create file if it doesn't exist
108 Truncate = 0x08, ///< Truncate file if it does exist
109 Append = 0x10, ///< Always append on every write
110 NonBlock = 0x20, ///< Open file in non-blocking mode
111 Exclusive = 0x40, ///< Create file, if it exists then fail
112
113 // Helpful mixes
114 ReadWrite = 0x03, ///< Open for reading and writing
115 WriteNew = 0x0E ///< Create a file (or truncate) for writing.
116 /// Same as Write|Create|Truncate
117 };
118
119 class Stat
120 {
121 public:
122 int32_t iNode;
123 int32_t iUser;
124 int32_t iGroup;
125 uint16_t uPerms;
126 int16_t iLinks;
127 int64_t iATime;
128 int64_t iMTime;
129 int64_t iCTime;
130 int32_t iSize;
131 uint32_t uDev;
132 Bu::String sName;
133 };
134 typedef Bu::List<Stat> Dir;
135
136 void stat( const Bu::String &sPath, Stat &rBuf );
137 MyriadStream open( const Bu::String &sPath, int iMode,
138 uint16_t uPerms=0664 );
139 void create( const Bu::String &sPath, uint16_t iPerms );
140 void create( const Bu::String &sPath, uint16_t iPerms,
141 uint16_t iDevHi, uint16_t iDevLo );
142 void create( const Bu::String &sPath, uint16_t iPerms,
143 uint32_t uSpecial );
144 void mkDir( const Bu::String &sPath, uint16_t iPerms );
145 void mkSymLink( const Bu::String &sTarget, const Bu::String &sPath );
146 void mkHardLink( const Bu::String &sTarget, const Bu::String &sPath );
147 Bu::String readSymLink( const Bu::String &sPath );
148 Dir readDir( const Bu::String &sPath );
149 void setTimes( const Bu::String &sPath, int64_t iATime,
150 int64_t iMTime );
151 void unlink( const Bu::String &sPath );
152 void setFileSize( const Bu::String &sPath, int32_t iSize );
153 void rename( const Bu::String &sFrom, const Bu::String &sTo );
154
155 static dev_t devToSys( uint32_t uDev );
156 static uint32_t sysToDev( dev_t uDev );
157
158 private:
159 class RawStat
160 {
161 public:
162 int32_t iNode;
163 int32_t iUser;
164 int32_t iGroup;
165 uint16_t uPerms;
166 int16_t iLinks;
167 uint32_t uStreamIndex;
168 int64_t iATime;
169 int64_t iMTime;
170 int64_t iCTime;
171 };
172 typedef Bu::Hash<int32_t, int32_t> NodeIndex;
173
174 private:
175 /**
176 * Lookup inode.
177 */
178 int32_t lookupInode( const Bu::String &sPath, int32_t &iParent );
179 /**
180 * Lookup inode.
181 */
182 int32_t lookupInode( Bu::String::const_iterator iStart,
183 int32_t iNode, int32_t &iParent );
184 void readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs );
185 void readInode( int32_t iNode, RawStat &rs );
186 void writeInode( const RawStat &rs );
187 void writeInode( const RawStat &rs, MyriadStream &rOs );
188 Dir readDir( int32_t iNode );
189 MyriadStream openByInode( int32_t iNode );
190 void addToDir( int32_t iDir, int32_t iNode, const Bu::String &sName );
191 int32_t create( int32_t iParent, const Bu::String &sName,
192 uint16_t uPerms, uint32_t uSpecial );
193 int32_t allocInode( uint16_t uPerms, uint32_t uSpecial );
194 void stat( int32_t iNode, Stat &rBuf, MyriadStream &rIs );
195 void writeHeader();
196 void setTimes( int32_t iNode, int64_t iATime, int64_t iMTime );
197 void destroyNode( int32_t iNode );
198
199 static Bu::String filePart( const Bu::String &sPath );
200
201 private:
202 Bu::Stream &rStore;
203 Bu::Myriad mStore;
204 Bu::DebugMutex mAccess;
205 NodeIndex hNodeIndex;
206 int32_t iUser;
207 int32_t iGroup;
208 };
209};
210
211#endif