summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Doxyfile4
l---------bu1
-rw-r--r--build.conf38
-rw-r--r--fstringtest.dev59
-rw-r--r--libbu++.dev209
-rw-r--r--misc/taf26
-rw-r--r--misc/w3c-xml-1.1.html1598
-rwxr-xr-xmkincs.sh5
-rw-r--r--src/archival.cpp10
-rw-r--r--src/archival.h38
-rw-r--r--src/archive.cpp386
-rw-r--r--src/archive.h212
-rw-r--r--src/arraylist.cpp100
-rw-r--r--src/arraylist.h80
-rw-r--r--src/atom.cpp1
-rw-r--r--src/atom.h107
-rw-r--r--src/bzip2.cpp196
-rw-r--r--src/bzip2.h37
-rw-r--r--src/client.cpp206
-rw-r--r--src/client.h63
-rw-r--r--src/entities/bu-class48
-rw-r--r--src/exceptionbase.cpp16
-rw-r--r--src/exceptionbase.h127
-rw-r--r--src/exceptions.cpp15
-rw-r--r--src/exceptions.h43
-rw-r--r--src/file.cpp158
-rw-r--r--src/file.h78
-rw-r--r--src/filter.cpp97
-rw-r--r--src/filter.h65
-rw-r--r--src/fstring.cpp11
-rw-r--r--src/fstring.h1304
-rw-r--r--src/hash.cpp34
-rw-r--r--src/hash.h1488
-rw-r--r--src/hashable.cpp1
-rw-r--r--src/hashable.h12
-rw-r--r--src/hashfunction.cpp10
-rw-r--r--src/hashfunction.h48
-rw-r--r--src/hashfunctioncasestring.cpp39
-rw-r--r--src/hashfunctioncasestring.h28
-rw-r--r--src/hashfunctionint.cpp20
-rw-r--r--src/hashfunctionint.h26
-rw-r--r--src/hashfunctionstring.cpp51
-rw-r--r--src/hashfunctionstring.h27
-rw-r--r--src/hashtable.cpp424
-rw-r--r--src/hashtable.h308
-rw-r--r--src/inprogress/xmldocument.cpp9
-rw-r--r--src/inprogress/xmldocument.h22
-rw-r--r--src/inprogress/xmlnode.cpp9
-rw-r--r--src/inprogress/xmlnode.h22
-rw-r--r--src/inprogress/xmlreader.cpp267
-rw-r--r--src/inprogress/xmlreader.h121
-rw-r--r--src/inprogress/xmlwriter.cpp9
-rw-r--r--src/inprogress/xmlwriter.h22
-rw-r--r--src/ito.cpp40
-rw-r--r--src/ito.h98
-rw-r--r--src/itoatom.h56
-rw-r--r--src/itocondition.cpp42
-rw-r--r--src/itocondition.h81
-rw-r--r--src/itomutex.cpp27
-rw-r--r--src/itomutex.h61
-rw-r--r--src/itoqueue.h231
-rw-r--r--src/linkmessage.cpp7
-rw-r--r--src/linkmessage.h59
-rw-r--r--src/list.cpp10
-rw-r--r--src/list.h574
-rw-r--r--src/logger.cpp131
-rw-r--r--src/logger.h112
-rw-r--r--src/main.dox14
-rw-r--r--src/membuf.cpp120
-rw-r--r--src/membuf.h53
-rw-r--r--src/old/cgi.cpp (renamed from src/cgi.cpp)0
-rw-r--r--src/old/cgi.h (renamed from src/cgi.h)0
-rw-r--r--src/old/configmanagerbase.cpp (renamed from src/configmanagerbase.cpp)0
-rw-r--r--src/old/configmanagerbase.h (renamed from src/configmanagerbase.h)0
-rw-r--r--src/old/confpair.cpp (renamed from src/confpair.cpp)0
-rw-r--r--src/old/confpair.h (renamed from src/confpair.h)0
-rw-r--r--src/old/confpairbase.cpp (renamed from src/confpairbase.cpp)0
-rw-r--r--src/old/confpairbase.h (renamed from src/confpairbase.h)0
-rw-r--r--src/old/conftree.cpp (renamed from src/conftree.cpp)0
-rw-r--r--src/old/conftree.h (renamed from src/conftree.h)0
-rw-r--r--src/old/connection.cpp (renamed from src/connection.cpp)0
-rw-r--r--src/old/connection.h (renamed from src/connection.h)0
-rw-r--r--src/old/connectionmanager.cpp (renamed from src/connectionmanager.cpp)0
-rw-r--r--src/old/connectionmanager.h (renamed from src/connectionmanager.h)0
-rw-r--r--src/old/connectionmonitor.cpp (renamed from src/connectionmonitor.cpp)0
-rw-r--r--src/old/connectionmonitor.h (renamed from src/connectionmonitor.h)0
-rw-r--r--src/old/flexbuf.cpp (renamed from src/flexbuf.cpp)0
-rw-r--r--src/old/flexbuf.h (renamed from src/flexbuf.h)0
-rw-r--r--src/old/formula.cpp (renamed from src/formula.cpp)0
-rw-r--r--src/old/formula.h (renamed from src/formula.h)0
-rw-r--r--src/old/http.cpp (renamed from src/http.cpp)0
-rw-r--r--src/old/http.h (renamed from src/http.h)0
-rw-r--r--src/old/httpget.cpp (renamed from src/httpget.cpp)0
-rw-r--r--src/old/httpget.h (renamed from src/httpget.h)0
-rw-r--r--src/old/linkedlist.cpp (renamed from src/linkedlist.cpp)0
-rw-r--r--src/old/linkedlist.h (renamed from src/linkedlist.h)0
-rw-r--r--src/old/linkmessenger.cpp (renamed from src/linkmessenger.cpp)0
-rw-r--r--src/old/linkmessenger.h (renamed from src/linkmessenger.h)0
-rw-r--r--src/old/list.cpp10
-rw-r--r--src/old/list.h101
-rw-r--r--src/old/md5.cpp (renamed from src/md5.cpp)0
-rw-r--r--src/old/md5.h (renamed from src/md5.h)0
-rw-r--r--src/old/multilog.cpp (renamed from src/multilog.cpp)0
-rw-r--r--src/old/multilog.h (renamed from src/multilog.h)0
-rw-r--r--src/old/multilogchannel.cpp (renamed from src/multilogchannel.cpp)0
-rw-r--r--src/old/multilogchannel.h (renamed from src/multilogchannel.h)0
-rw-r--r--src/old/multilogtext.cpp (renamed from src/multilogtext.cpp)0
-rw-r--r--src/old/multilogtext.h (renamed from src/multilogtext.h)0
-rw-r--r--src/old/ordhash.cpp (renamed from src/ordhash.cpp)0
-rw-r--r--src/old/ordhash.h (renamed from src/ordhash.h)0
-rw-r--r--src/old/pqueue.cpp (renamed from src/pqueue.cpp)0
-rw-r--r--src/old/pqueue.h (renamed from src/pqueue.h)0
-rw-r--r--src/old/protocol.cpp20
-rw-r--r--src/old/protocol.h62
-rw-r--r--src/old/protocoltelnet.cpp (renamed from src/protocoltelnet.cpp)0
-rw-r--r--src/old/protocoltelnet.h (renamed from src/protocoltelnet.h)0
-rw-r--r--src/old/queue.cpp (renamed from src/queue.cpp)0
-rw-r--r--src/old/queue.h (renamed from src/queue.h)0
-rw-r--r--src/old/ringlist.cpp (renamed from src/ringlist.cpp)0
-rw-r--r--src/old/ringlist.h (renamed from src/ringlist.h)0
-rw-r--r--src/old/sbuffer.cpp (renamed from src/sbuffer.cpp)0
-rw-r--r--src/old/sbuffer.h (renamed from src/sbuffer.h)0
-rw-r--r--src/old/serializerbinary.cpp (renamed from src/serializerbinary.cpp)0
-rw-r--r--src/old/serializerbinary.h (renamed from src/serializerbinary.h)0
-rw-r--r--src/old/serializerbzip2.cpp (renamed from src/serializerbzip2.cpp)0
-rw-r--r--src/old/serializerbzip2.h (renamed from src/serializerbzip2.h)0
-rw-r--r--src/old/serializerconnection.cpp (renamed from src/serializerconnection.cpp)0
-rw-r--r--src/old/serializerconnection.h (renamed from src/serializerconnection.h)0
-rw-r--r--src/old/serializertext.cpp (renamed from src/serializertext.cpp)0
-rw-r--r--src/old/serializertext.h (renamed from src/serializertext.h)0
-rw-r--r--src/old/sha1.cpp (renamed from src/sha1.cpp)0
-rw-r--r--src/old/sha1.h (renamed from src/sha1.h)0
-rw-r--r--src/old/stack.cpp (renamed from src/stack.cpp)0
-rw-r--r--src/old/stack.h (renamed from src/stack.h)0
-rw-r--r--src/old/staticstring.cpp (renamed from src/staticstring.cpp)0
-rw-r--r--src/old/staticstring.h (renamed from src/staticstring.h)0
-rw-r--r--src/old/stringrep.cpp (renamed from src/stringrep.cpp)0
-rw-r--r--src/old/stringrep.h (renamed from src/stringrep.h)0
-rw-r--r--src/old/tests/clistress.cpp (renamed from src/tests/clistress.cpp)0
-rw-r--r--src/old/tests/confpair.cpp (renamed from src/tests/confpair.cpp)0
-rw-r--r--src/old/tests/connect.cpp (renamed from src/tests/connect.cpp)0
-rw-r--r--src/old/tests/exception.cpp (renamed from src/tests/exception.cpp)0
-rw-r--r--src/old/tests/formula.cpp (renamed from src/tests/formula.cpp)0
-rw-r--r--src/old/tests/hash.cpp116
-rw-r--r--src/old/tests/hashtest.cpp (renamed from src/tests/hashtest.cpp)0
-rw-r--r--src/old/tests/hashtest2.cpp (renamed from src/tests/hashtest2.cpp)0
-rw-r--r--src/old/tests/httpsrv/httpconnectionmonitor.cpp (renamed from src/tests/httpsrv/httpconnectionmonitor.cpp)0
-rw-r--r--src/old/tests/httpsrv/httpconnectionmonitor.h (renamed from src/tests/httpsrv/httpconnectionmonitor.h)0
-rw-r--r--src/old/tests/httpsrv/main.cpp (renamed from src/tests/httpsrv/main.cpp)0
-rw-r--r--src/old/tests/log.cpp (renamed from src/tests/log.cpp)0
-rw-r--r--src/old/tests/md5test.cpp (renamed from src/tests/md5test.cpp)0
-rw-r--r--src/old/tests/ordhash.cpp (renamed from src/tests/ordhash.cpp)0
-rw-r--r--src/old/tests/param.cpp (renamed from src/tests/param.cpp)0
-rw-r--r--src/old/tests/param.h (renamed from src/tests/param.h)0
-rw-r--r--src/old/tests/plugin/main.cpp (renamed from src/tests/plugin/main.cpp)0
-rw-r--r--src/old/tests/plugin/plugin.cpp (renamed from src/tests/plugin/plugin.cpp)0
-rw-r--r--src/old/tests/plugin/plugin.h (renamed from src/tests/plugin/plugin.h)0
-rw-r--r--src/old/tests/qsort.cpp (renamed from src/tests/qsort.cpp)0
-rw-r--r--src/old/tests/sbuffer.cpp (renamed from src/tests/sbuffer.cpp)0
-rw-r--r--src/old/tests/serialize.cpp (renamed from src/tests/serialize.cpp)0
-rw-r--r--src/old/tests/serializetext.cpp (renamed from src/tests/serializetext.cpp)0
-rw-r--r--src/old/tests/sha1.cpp (renamed from src/tests/sha1.cpp)0
-rw-r--r--src/old/tests/sptr.cpp (renamed from src/tests/sptr.cpp)30
-rw-r--r--src/old/tests/srvstress.cpp (renamed from src/tests/srvstress.cpp)0
-rw-r--r--src/old/tests/strhash.cpp (renamed from src/tests/strhash.cpp)0
-rw-r--r--src/old/tests/teltest/main.cpp (renamed from src/tests/teltest/main.cpp)0
-rw-r--r--src/old/tests/teltest/telnetmonitor.cpp (renamed from src/tests/teltest/telnetmonitor.cpp)0
-rw-r--r--src/old/tests/teltest/telnetmonitor.h (renamed from src/tests/teltest/telnetmonitor.h)0
-rw-r--r--src/old/tests/xmlreadtest.cpp (renamed from src/tests/xmlreadtest.cpp)0
-rw-r--r--src/old/tests/xmlrepltest.cpp (renamed from src/tests/xmlrepltest.cpp)0
-rw-r--r--src/old/tests/xmlwritetest.cpp (renamed from src/tests/xmlwritetest.cpp)0
-rw-r--r--src/old/tokenstring.cpp (renamed from src/tokenstring.cpp)0
-rw-r--r--src/old/tokenstring.h (renamed from src/tokenstring.h)0
-rw-r--r--src/old/tqsort.h (renamed from src/tqsort.h)0
-rw-r--r--src/old/unit/hashtable/hashtable.cpp (renamed from src/unit/hashtable/hashtable.cpp)0
-rw-r--r--src/old/unit/xml/xml.cpp (renamed from src/unit/xml/xml.cpp)0
-rw-r--r--src/old/xmldocument.cpp (renamed from src/xmldocument.cpp)20
-rw-r--r--src/old/xmldocument.h (renamed from src/xmldocument.h)8
-rw-r--r--src/old/xmlfilereader.cpp (renamed from src/xmlfilereader.cpp)0
-rw-r--r--src/old/xmlfilereader.h (renamed from src/xmlfilereader.h)0
-rw-r--r--src/old/xmlfilewriter.cpp (renamed from src/xmlfilewriter.cpp)0
-rw-r--r--src/old/xmlfilewriter.h (renamed from src/xmlfilewriter.h)0
-rw-r--r--src/old/xmlnode.cpp (renamed from src/xmlnode.cpp)106
-rw-r--r--src/old/xmlnode.h (renamed from src/xmlnode.h)101
-rw-r--r--src/old/xmlreader.cpp (renamed from src/xmlreader.cpp)170
-rw-r--r--src/old/xmlreader.h (renamed from src/xmlreader.h)31
-rw-r--r--src/old/xmlstringreader.cpp (renamed from src/xmlstringreader.cpp)0
-rw-r--r--src/old/xmlstringreader.h (renamed from src/xmlstringreader.h)0
-rw-r--r--src/old/xmlstringwriter.cpp (renamed from src/xmlstringwriter.cpp)0
-rw-r--r--src/old/xmlstringwriter.h (renamed from src/xmlstringwriter.h)0
-rw-r--r--src/old/xmlwriter.cpp (renamed from src/xmlwriter.cpp)62
-rw-r--r--src/old/xmlwriter.h (renamed from src/xmlwriter.h)16
-rw-r--r--src/paramproc.cpp98
-rw-r--r--src/paramproc.h265
-rw-r--r--src/plugger.h316
-rw-r--r--src/programchain.cpp49
-rw-r--r--src/programchain.h163
-rw-r--r--src/programlink.cpp14
-rw-r--r--src/programlink.h165
-rw-r--r--src/protocol.cpp16
-rw-r--r--src/protocol.h67
-rw-r--r--src/ringbuffer.cpp2
-rw-r--r--src/ringbuffer.h97
-rw-r--r--src/serializable.cpp8
-rw-r--r--src/serializable.h34
-rw-r--r--src/serializer.cpp338
-rw-r--r--src/serializer.h80
-rw-r--r--src/server.cpp96
-rw-r--r--src/server.h61
-rw-r--r--src/serversocket.cpp158
-rw-r--r--src/serversocket.h39
-rw-r--r--src/sfile.cpp74
-rw-r--r--src/sfile.h29
-rw-r--r--src/singleton.h101
-rw-r--r--src/socket.cpp294
-rw-r--r--src/socket.h55
-rw-r--r--src/sptr.cpp2
-rw-r--r--src/sptr.h272
-rw-r--r--src/stream.cpp4
-rw-r--r--src/stream.h148
-rw-r--r--src/tafnode.cpp165
-rw-r--r--src/tafnode.h94
-rw-r--r--src/tafreader.cpp155
-rw-r--r--src/tafreader.h35
-rw-r--r--src/tafwriter.cpp70
-rw-r--r--src/tafwriter.h30
-rw-r--r--src/tests/archive.cpp16
-rw-r--r--src/tests/atom.cpp25
-rw-r--r--src/tests/bzip2.cpp23
-rw-r--r--src/tests/constsptr.cpp94
-rw-r--r--src/tests/constsptr2.cpp30
-rw-r--r--src/tests/fstring.cpp108
-rw-r--r--src/tests/hash.cpp120
-rw-r--r--src/tests/itoqueue1.cpp110
-rw-r--r--src/tests/itoqueue2.cpp83
-rw-r--r--src/tests/list.cpp53
-rw-r--r--src/tests/logger.cpp28
-rw-r--r--src/tests/ringbuffer.cpp29
-rw-r--r--src/tests/taf.cpp24
-rw-r--r--src/unit/entities/unit30
-rw-r--r--src/unit/file.cpp111
-rw-r--r--src/unit/fstring.cpp28
-rw-r--r--src/unit/hash.cpp40
-rw-r--r--src/unit/membuf.cpp37
-rw-r--r--src/unit/taf.cpp48
-rw-r--r--src/unitsuite.cpp67
-rw-r--r--src/unitsuite.h96
-rw-r--r--test.taf7
-rw-r--r--tests/comments.xml12
-rw-r--r--tests/guy.cpp22
-rwxr-xr-xtests/makeplugin.sh3
251 files changed, 11269 insertions, 4473 deletions
diff --git a/Doxyfile b/Doxyfile
index 6c7412e..c3168fa 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -74,9 +74,9 @@ QUIET = NO
74WARNINGS = YES 74WARNINGS = YES
75WARN_IF_UNDOCUMENTED = YES 75WARN_IF_UNDOCUMENTED = YES
76WARN_IF_DOC_ERROR = YES 76WARN_IF_DOC_ERROR = YES
77WARN_NO_PARAMDOC = NO 77WARN_NO_PARAMDOC = YES
78WARN_FORMAT = "$file:$line: $text" 78WARN_FORMAT = "$file:$line: $text"
79WARN_LOGFILE = 79WARN_LOGFILE = Doxywarn
80#--------------------------------------------------------------------------- 80#---------------------------------------------------------------------------
81# configuration options related to the input files 81# configuration options related to the input files
82#--------------------------------------------------------------------------- 82#---------------------------------------------------------------------------
diff --git a/bu b/bu
new file mode 120000
index 0000000..02b8847
--- /dev/null
+++ b/bu
@@ -0,0 +1 @@
src/bu/ \ No newline at end of file
diff --git a/build.conf b/build.conf
index 5c4dbb6..d994977 100644
--- a/build.conf
+++ b/build.conf
@@ -1,13 +1,20 @@
1# This is a build file for libbu++ 1# This is a build file for libbu++
2 2
3default action: check "libbu++.a" 3default action: check group "lnhdrs", check "libbu++.a"
4"clean" action: clean targets() 4"tests" action: check group "lnhdrs", check group "tests"
5"tests" action: check targets() filter regexp("^tests/.*$") 5"all" action: check group "lnhdrs", check targets()
6"all" action: check targets()
7"fstring" action: check "tests/fstring"
8 6
9set "CXXFLAGS" += "-ggdb -Wall" 7set "CXXFLAGS" += "-ggdb -Wall"
10 8
9#set "CXXFLAGS" += "-pg"
10#set "LDFLAGS" += "-pg"
11
12filesIn("src") filter regexp("^src/(.*)\\.h$", "src/bu/{re:1}.h"):
13 rule "hln",
14 group "lnhdrs",
15 target file,
16 input "src/{re:1}.h"
17
11"libbu++.a": 18"libbu++.a":
12 rule "lib", 19 rule "lib",
13 target file, 20 target file,
@@ -17,6 +24,7 @@ set "CXXFLAGS" += "-ggdb -Wall"
17directoriesIn("src/tests","tests/"): 24directoriesIn("src/tests","tests/"):
18 rule "exe", 25 rule "exe",
19 target file, 26 target file,
27 group "tests",
20 requires "libbu++.a", 28 requires "libbu++.a",
21 set "CXXFLAGS" += "-Isrc", 29 set "CXXFLAGS" += "-Isrc",
22 set "LDFLAGS" += "-L. -lbu++", 30 set "LDFLAGS" += "-L. -lbu++",
@@ -25,6 +33,18 @@ directoriesIn("src/tests","tests/"):
25filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"): 33filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"):
26 rule "exe", 34 rule "exe",
27 target file, 35 target file,
36 group "tests",
37 requires "libbu++.a",
38 set "CXXFLAGS" += "-Isrc",
39 set "LDFLAGS" += "-L. -lbu++",
40 input "src/{target}.cpp"
41
42["tests/itoqueue1", "tests/itoqueue2"]: set "LDFLAGS" += "-lpthread"
43
44filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"):
45 rule "exe",
46 target file,
47 group "tests",
28 requires "libbu++.a", 48 requires "libbu++.a",
29 set "CXXFLAGS" += "-Isrc", 49 set "CXXFLAGS" += "-Isrc",
30 set "LDFLAGS" += "-L. -lbu++", 50 set "LDFLAGS" += "-L. -lbu++",
@@ -32,6 +52,8 @@ filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"):
32 52
33"tests/plugin": set "LDFLAGS" += "-ldl" 53"tests/plugin": set "LDFLAGS" += "-ldl"
34 54
55"tests/bzip2": set "LDFLAGS" += "-lbz2"
56
35rule "exe": 57rule "exe":
36 matches regexp("(.*)\\.o$"), 58 matches regexp("(.*)\\.o$"),
37 aggregate toString(" "), 59 aggregate toString(" "),
@@ -47,3 +69,9 @@ rule "cpp":
47 produces "{re:1}.o", 69 produces "{re:1}.o",
48 requires commandToList("g++ -M {CXXFLAGS} {match}", "make"), 70 requires commandToList("g++ -M {CXXFLAGS} {match}", "make"),
49 perform command("g++ {CXXFLAGS} -c -o {target} {match}") 71 perform command("g++ {CXXFLAGS} -c -o {target} {match}")
72
73rule "hln":
74 matches regexp("src/(.*)\\.h"),
75 produces "src/bu/{re:1}.h",
76 perform command("ln -s ../{re:1}.h {target}")
77
diff --git a/fstringtest.dev b/fstringtest.dev
new file mode 100644
index 0000000..297242d
--- /dev/null
+++ b/fstringtest.dev
@@ -0,0 +1,59 @@
1[Project]
2FileName=fstringtest.dev
3Name=fstringtest
4UnitCount=1
5Type=1
6Ver=1
7ObjFiles=
8Includes=z:\home\neonphog\wine_documents\libbu++\src\bu
9Libs=
10PrivateResource=
11ResourceIncludes=
12MakeIncludes=
13Compiler=
14CppCompiler=_@@_
15Linker=libbu++.a_@@_
16IsCpp=1
17Icon=
18ExeOutput=
19ObjectOutput=
20OverrideOutput=0
21OverrideOutputName=fstringtest.exe
22HostApplication=
23Folders=
24CommandLine=
25UseCustomMakefile=0
26CustomMakefile=
27IncludeVersionInfo=0
28SupportXPThemes=0
29CompilerSet=0
30CompilerSettings=0000000000000000000000
31
32[VersionInfo]
33Major=0
34Minor=1
35Release=1
36Build=1
37LanguageID=1033
38CharsetID=1252
39CompanyName=
40FileVersion=
41FileDescription=Developed using the Dev-C++ IDE
42InternalName=
43LegalCopyright=
44LegalTrademarks=
45OriginalFilename=
46ProductName=
47ProductVersion=
48AutoIncBuildNr=0
49
50[Unit1]
51FileName=src\tests\fstring.cpp
52CompileCpp=1
53Folder=fstringtest
54Compile=1
55Link=1
56Priority=1000
57OverrideBuildCmd=0
58BuildCmd=
59
diff --git a/libbu++.dev b/libbu++.dev
new file mode 100644
index 0000000..2fb1ae9
--- /dev/null
+++ b/libbu++.dev
@@ -0,0 +1,209 @@
1[Project]
2FileName=libbu++.dev
3Name=libbu++
4UnitCount=16
5Type=2
6Ver=1
7ObjFiles=
8Includes=z:\home\neonphog\wine_documents\libbu++\src\bu
9Libs=
10PrivateResource=
11ResourceIncludes=
12MakeIncludes=
13Compiler=
14CppCompiler=
15Linker=
16IsCpp=1
17Icon=
18ExeOutput=
19ObjectOutput=
20OverrideOutput=0
21OverrideOutputName=libbu++.a
22HostApplication=
23Folders=
24CommandLine=
25UseCustomMakefile=0
26CustomMakefile=
27IncludeVersionInfo=0
28SupportXPThemes=0
29CompilerSet=0
30CompilerSettings=0000000000000000000000
31
32[Unit1]
33FileName=src\stream.cpp
34CompileCpp=1
35Folder=libbu++
36Compile=1
37Link=1
38Priority=1000
39OverrideBuildCmd=0
40BuildCmd=
41
42[VersionInfo]
43Major=0
44Minor=1
45Release=1
46Build=1
47LanguageID=1033
48CharsetID=1252
49CompanyName=
50FileVersion=
51FileDescription=Developed using the Dev-C++ IDE
52InternalName=
53LegalCopyright=
54LegalTrademarks=
55OriginalFilename=
56ProductName=
57ProductVersion=
58AutoIncBuildNr=0
59
60[Unit2]
61FileName=src\stream.h
62CompileCpp=1
63Folder=libbu++
64Compile=1
65Link=1
66Priority=1000
67OverrideBuildCmd=0
68BuildCmd=
69
70[Unit3]
71FileName=src\file.cpp
72CompileCpp=1
73Folder=libbu++
74Compile=1
75Link=1
76Priority=1000
77OverrideBuildCmd=0
78BuildCmd=
79
80[Unit4]
81FileName=src\file.h
82CompileCpp=1
83Folder=libbu++
84Compile=1
85Link=1
86Priority=1000
87OverrideBuildCmd=0
88BuildCmd=
89
90[Unit5]
91FileName=src\fstring.h
92CompileCpp=1
93Folder=libbu++
94Compile=1
95Link=1
96Priority=1000
97OverrideBuildCmd=0
98BuildCmd=
99
100[Unit6]
101FileName=src\fstring.cpp
102CompileCpp=1
103Folder=libbu++
104Compile=1
105Link=1
106Priority=1000
107OverrideBuildCmd=0
108BuildCmd=
109
110[Unit7]
111FileName=src\archival.cpp
112CompileCpp=1
113Folder=libbu++
114Compile=1
115Link=1
116Priority=1000
117OverrideBuildCmd=0
118BuildCmd=
119
120[Unit8]
121FileName=src\archival.h
122CompileCpp=1
123Folder=libbu++
124Compile=1
125Link=1
126Priority=1000
127OverrideBuildCmd=0
128BuildCmd=
129
130[Unit9]
131FileName=src\archive.cpp
132CompileCpp=1
133Folder=libbu++
134Compile=1
135Link=1
136Priority=1000
137OverrideBuildCmd=0
138BuildCmd=
139
140[Unit10]
141FileName=src\archive.h
142CompileCpp=1
143Folder=libbu++
144Compile=1
145Link=1
146Priority=1000
147OverrideBuildCmd=0
148BuildCmd=
149
150[Unit11]
151FileName=src\hash.h
152CompileCpp=1
153Folder=libbu++
154Compile=1
155Link=1
156Priority=1000
157OverrideBuildCmd=0
158BuildCmd=
159
160[Unit12]
161FileName=src\hash.cpp
162CompileCpp=1
163Folder=libbu++
164Compile=1
165Link=1
166Priority=1000
167OverrideBuildCmd=0
168BuildCmd=
169
170[Unit13]
171FileName=src\exceptionbase.cpp
172CompileCpp=1
173Folder=libbu++
174Compile=1
175Link=1
176Priority=1000
177OverrideBuildCmd=0
178BuildCmd=
179
180[Unit14]
181FileName=src\exceptionbase.h
182CompileCpp=1
183Folder=libbu++
184Compile=1
185Link=1
186Priority=1000
187OverrideBuildCmd=0
188BuildCmd=
189
190[Unit15]
191FileName=src\list.cpp
192CompileCpp=1
193Folder=libbu++
194Compile=1
195Link=1
196Priority=1000
197OverrideBuildCmd=0
198BuildCmd=
199
200[Unit16]
201FileName=src\list.h
202CompileCpp=1
203Folder=libbu++
204Compile=1
205Link=1
206Priority=1000
207OverrideBuildCmd=0
208BuildCmd=
209
diff --git a/misc/taf b/misc/taf
new file mode 100644
index 0000000..045b042
--- /dev/null
+++ b/misc/taf
@@ -0,0 +1,26 @@
1{player:
2 password = "aoeuaoeuao"
3 userclass = "implementor"
4 species = "human"
5 sex = "male"
6 active
7 startroom = "Salourn::Xagafinelle's Room"
8 {stats: str=14 dex=12 spd=12 enr=7 rea=12 wil=10 int=13 cha=14}
9 {hp: cur = 100 max = 100}
10 {en: cur = 100 max = 100}
11 attackrate = 30
12 gold = 0
13 {inventory:
14 {: count=1 id="Salourn::Dark Blade"}
15 {: count=1 id="Salourn::Dark Suit"}
16 {: count=3 id="Salourn::Small Fig"}
17 }
18 {aliases:
19 {: key="." value="say"}
20 {: key="," value="yell"}
21 {: key="li" value="lightning"}
22 }
23 description = "They appear to be rather average looking, not particularly
24 tall or short, with facial features that are difficult to remember even
25 seconds after witnessing them."
26}
diff --git a/misc/w3c-xml-1.1.html b/misc/w3c-xml-1.1.html
new file mode 100644
index 0000000..6a9211a
--- /dev/null
+++ b/misc/w3c-xml-1.1.html
@@ -0,0 +1,1598 @@
1<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="EN" xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /><title>Extensible Markup Language (XML) 1.1</title><style type="text/css">
2code { font-family: monospace; }
3
4div.constraint,
5div.issue,
6div.note,
7div.notice { margin-left: 2em; }
8
9li p { margin-top: 0.3em;
10 margin-bottom: 0.3em; }
11
12div.exampleInner pre { margin-left: 1em;
13 margin-top: 0em; margin-bottom: 0em}
14div.exampleOuter {border: 4px double gray;
15 margin: 0em; padding: 0em}
16div.exampleInner { background-color: #d5dee3;
17 border-top-width: 4px;
18 border-top-style: double;
19 border-top-color: #d3d3d3;
20 border-bottom-width: 4px;
21 border-bottom-style: double;
22 border-bottom-color: #d3d3d3;
23 padding: 4px; margin: 0em }
24div.exampleWrapper { margin: 4px }
25div.exampleHeader { font-weight: bold;
26 margin: 4px}
27
28em.rfc2119 { text-transform: lowercase;
29 font-variant: small-caps;
30 font-style: normal; }
31</style><link rel="stylesheet" type="text/css" href="http://www.w3.org/StyleSheets/TR/W3C-REC.css" /></head><body><div class="head"><p><a href="http://www.w3.org/"><img src="http://www.w3.org/Icons/w3c_home" alt="W3C" height="48" width="72" /></a></p>
32<h1><a name="title" id="title" />Extensible Markup Language (XML) 1.1</h1>
33<h2><a name="w3c-doctype" id="w3c-doctype" />W3C Recommendation 04
34 February 2004, edited in place 15 April 2004</h2><dl><dt>This version:</dt><dd><a href="http://www.w3.org/TR/2004/REC-xml11-20040204/">http://www.w3.org/TR/2004/REC-xml11-20040204/</a></dd><dt>Latest version:</dt><dd><a href="http://www.w3.org/TR/xml11">http://www.w3.org/TR/xml11</a></dd><dt>Previous version:</dt><dd><a href="http://www.w3.org/TR/2003/PR-xml11-20031105/">http://www.w3.org/TR/2003/PR-xml11-20031105/</a></dd><dt>Editors:</dt><dd>Tim Bray, Textuality and Netscape <a href="mailto:tbray@textuality.com">&lt;tbray@textuality.com&gt;</a></dd><dd>Jean Paoli, Microsoft <a href="mailto:jeanpa@microsoft.com">&lt;jeanpa@microsoft.com&gt;</a></dd><dd>C. M. Sperberg-McQueen, W3C <a href="mailto:cmsmcq@w3.org">&lt;cmsmcq@w3.org&gt;</a></dd><dd>Eve Maler, Sun Microsystems, Inc. <a href="mailto:elm@east.sun.com">&lt;eve.maler@east.sun.com&gt;</a></dd><dd>François Yergeau <a href="mailto:fyergeau@alis.com">&lt;fyergeau@alis.com&gt;</a></dd><dd>John Cowan <a href="mailto:cowan@ccil.org">&lt;cowan@ccil.org&gt;</a></dd></dl><p>Please refer to the <a href="http://www.w3.org/XML/xml-V11-1e-errata"><strong>errata</strong></a> for this document, which may include some normative corrections.</p><p>This document is also available in these non-normative formats: <a href="REC-xml11-20040204.xml">XML</a> and <a href="REC-xml11-20040204-review.html">XHTML with color-coded revision indicators</a>.</p><p>See also <a href="http://www.w3.org/2003/03/Translations/byTechnology?technology=xml11"><strong>translations</strong></a>.</p><p class="copyright"><a href="http://www.w3.org/Consortium/Legal/ipr-notice#Copyright">Copyright</a> © 2004 <a href="http://www.w3.org/"><acronym title="World Wide Web Consortium">W3C</acronym></a><sup>®</sup> (<a href="http://www.csail.mit.edu/"><acronym title="Massachusetts Institute of Technology">MIT</acronym></a>, <a href="http://www.ercim.org/"><acronym title="European Research Consortium for Informatics and Mathematics">ERCIM</acronym></a>, <a href="http://www.keio.ac.jp/">Keio</a>), All Rights Reserved. W3C <a href="http://www.w3.org/Consortium/Legal/ipr-notice#Legal_Disclaimer">liability</a>, <a href="http://www.w3.org/Consortium/Legal/ipr-notice#W3C_Trademarks">trademark</a>, <a href="http://www.w3.org/Consortium/Legal/copyright-documents">document use</a> and <a href="http://www.w3.org/Consortium/Legal/copyright-software">software licensing</a> rules apply.</p></div><hr /><div> <h2><a name="abstract" id="abstract" />Abstract</h2><p>The Extensible Markup Language (XML) is a subset of SGML that is completely
35described in this document. Its goal is to enable generic SGML to be served,
36received, and processed on the Web in the way that is now possible with HTML.
37XML has been designed for ease of implementation and for interoperability
38with both SGML and HTML.</p></div><div> <h2><a name="status" id="status" />Status of this Document</h2><p><em>This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the <a href="http://www.w3.org/TR/">W3C technical reports index</a> at http://www.w3.org/TR/.</em></p><p>This document is a <a href="http://www.w3.org/2003/06/Process-20030618/tr.html#RecsW3C">Recommendation</a> of the W3C.
39It has been reviewed by W3C Members and other interested parties, and has
40been endorsed by the Director as a W3C Recommendation. It is a stable document and may be used as reference material or cited as a normative reference from another document. W3C's role in making the
41Recommendation is to draw attention to the specification and to promote its widespread deployment.
42This enhances the functionality and interoperability of the Web.</p><p>This document specifies a syntax created by subsetting an existing, widely
43used international text processing standard (Standard Generalized Markup Language,
44ISO 8879:1986(E) as amended and corrected) for use on the World Wide Web.
45It is a product of the <a
46 href="http://www.w3.org/XML/Activity.html">W3C XML
47 Activity</a>.</p>
48
49<p>On 15 April 2004, this document was edited in place to add two
50missing spaces to <a
51href="http://www.w3.org/TR/2004/REC-xml11-20040204/Overview.html#NT-document">production
52[1]</a> in section 2.1</p>
53
54<p>The English version of this specification is the only normative version. However,
55for translations of this document, see <a href="http://www.w3.org/2003/03/Translations/byTechnology?technology=xml11">http://www.w3.org/2003/03/Translations/byTechnology?technology=xml11</a>.
56</p><p>Documentation of intellectual property possibly relevant to this recommendation
57may be found at the Working Group's public
58<a href="http://www.w3.org/2002/08/xmlcore-IPR-statements">IPR disclosure page</a>.</p><p>An implementation report for XML 1.1 is available at <a href="http://www.w3.org/XML/2002/09/xml11-implementation.html">http://www.w3.org/XML/2002/09/xml11-implementation.html</a>.</p><p>Please report errors in this document to <a href="mailto:xml-editor@w3.org">xml-editor@w3.org</a>; <a href="http://lists.w3.org/Archives/Public/xml-editor">archives</a> are available. The errata list for this edition is available
59at <a href="http://www.w3.org/XML/xml-V11-1e-errata">http://www.w3.org/XML/xml-V11-1e-errata</a>.</p><p>A <a href="http://www.w3.org/XML/Test/">Test Suite</a> is maintained to help assessing conformance to this specification.</p></div><div class="toc"> <h2><a name="contents" id="contents" />Table of Contents</h2><p class="toc">1 <a href="#sec-intro">Introduction</a><br />     1.1 <a href="#sec-origin-goals">Origin and Goals</a><br />     1.2 <a href="#sec-terminology">Terminology</a><br />     1.3 <a href="#sec-xml11">Rationale and list of changes for XML 1.1</a><br /> 2 <a href="#sec-documents">Documents</a><br />     2.1 <a href="#sec-well-formed">Well-Formed XML Documents</a><br />     2.2 <a href="#charsets">Characters</a><br />     2.3 <a href="#sec-common-syn">Common Syntactic Constructs</a><br />     2.4 <a href="#syntax">Character Data and Markup</a><br />     2.5 <a href="#sec-comments">Comments</a><br />     2.6 <a href="#sec-pi">Processing Instructions</a><br />     2.7 <a href="#sec-cdata-sect">CDATA Sections</a><br />     2.8 <a href="#sec-prolog-dtd">Prolog and Document Type Declaration</a><br />     2.9 <a href="#sec-rmd">Standalone Document Declaration</a><br />     2.10 <a href="#sec-white-space">White Space Handling</a><br />     2.11 <a href="#sec-line-ends">End-of-Line Handling</a><br />     2.12 <a href="#sec-lang-tag">Language Identification</a><br />     2.13 <a href="#sec-normalization-checking">Normalization Checking</a><br /> 3 <a href="#sec-logical-struct">Logical Structures</a><br />     3.1 <a href="#sec-starttags">Start-Tags, End-Tags, and Empty-Element Tags</a><br />     3.2 <a href="#elemdecls">Element Type Declarations</a><br />         3.2.1 <a href="#sec-element-content">Element Content</a><br />         3.2.2 <a href="#sec-mixed-content">Mixed Content</a><br />     3.3 <a href="#attdecls">Attribute-List Declarations</a><br />         3.3.1 <a href="#sec-attribute-types">Attribute Types</a><br />         3.3.2 <a href="#sec-attr-defaults">Attribute Defaults</a><br />         3.3.3 <a href="#AVNormalize">Attribute-Value Normalization</a><br />     3.4 <a href="#sec-condition-sect">Conditional Sections</a><br /> 4 <a href="#sec-physical-struct">Physical Structures</a><br />     4.1 <a href="#sec-references">Character and Entity References</a><br />     4.2 <a href="#sec-entity-decl">Entity Declarations</a><br />         4.2.1 <a href="#sec-internal-ent">Internal Entities</a><br />         4.2.2 <a href="#sec-external-ent">External Entities</a><br />     4.3 <a href="#TextEntities">Parsed Entities</a><br />         4.3.1 <a href="#sec-TextDecl">The Text Declaration</a><br />         4.3.2 <a href="#wf-entities">Well-Formed Parsed Entities</a><br />         4.3.3 <a href="#charencoding">Character Encoding in Entities</a><br />         4.3.4 <a href="#sec-version-info">Version Information in Entities</a><br />     4.4 <a href="#entproc">XML Processor Treatment of Entities and References</a><br />         4.4.1 <a href="#not-recognized">Not Recognized</a><br />         4.4.2 <a href="#included">Included</a><br />         4.4.3 <a href="#include-if-valid">Included If Validating</a><br />         4.4.4 <a href="#forbidden">Forbidden</a><br />         4.4.5 <a href="#inliteral">Included in Literal</a><br />         4.4.6 <a href="#notify">Notify</a><br />         4.4.7 <a href="#bypass">Bypassed</a><br />         4.4.8 <a href="#as-PE">Included as PE</a><br />         4.4.9 <a href="#error">Error</a><br />     4.5 <a href="#intern-replacement">Construction of Entity Replacement Text</a><br />     4.6 <a href="#sec-predefined-ent">Predefined Entities</a><br />     4.7 <a href="#Notations">Notation Declarations</a><br />     4.8 <a href="#sec-doc-entity">Document Entity</a><br /> 5 <a href="#sec-conformance">Conformance</a><br />     5.1 <a href="#proc-types">Validating and Non-Validating Processors</a><br />     5.2 <a href="#safe-behavior">Using XML Processors</a><br /> 6 <a href="#sec-notation">Notation</a><br /> </p> <h3><a name="appendices" id="appendices" />Appendices</h3><p class="toc">A <a href="#sec-bibliography">References</a><br />     A.1 <a href="#sec-existing-stds">Normative References</a><br />     A.2 <a href="#null">Other References</a><br /> B <a href="#sec-CharNorm">Definitions for Character Normalization</a><br /> C <a href="#sec-entexpand">Expansion of Entity and Character References</a> (Non-Normative)<br /> D <a href="#determinism">Deterministic Content Models</a> (Non-Normative)<br /> E <a href="#sec-guessing">Autodetection of Character Encodings</a> (Non-Normative)<br />     E.1 <a href="#sec-guessing-no-ext-info">Detection Without External Encoding Information</a><br />     E.2 <a href="#sec-guessing-with-ext-info">Priorities in the Presence of External Encoding Information</a><br /> F <a href="#sec-xml-wg">W3C XML Working Group</a> (Non-Normative)<br /> G <a href="#sec-core-wg">W3C XML Core Working Group</a> (Non-Normative)<br /> H <a href="#prod-notes">Production Notes</a> (Non-Normative)<br /> I <a href="#sec-suggested-names">Suggestions for XML Names</a> (Non-Normative)<br /> </p></div><hr /><div class="body"><div class="div1"> <h2><a name="sec-intro" id="sec-intro" />1 Introduction</h2><p>Extensible Markup Language, abbreviated XML, describes a class of data
60objects called <a title="XML Document" href="#dt-xml-doc">XML documents</a> and partially
61describes the behavior of computer programs which process them. XML is an
62application profile or restricted form of SGML, the Standard Generalized Markup
63Language <a href="#ISO8879">[ISO 8879]</a>. By construction, XML documents are conforming
64SGML documents.</p><p>XML documents are made up of storage units called <a title="Entity" href="#dt-entity">entities</a>,
65which contain either parsed or unparsed data. Parsed data is made up of <a title="Character" href="#dt-character">characters</a>, some of which form <a title="Character Data" href="#dt-chardata">character
66data</a>, and some of which form <a title="Markup" href="#dt-markup">markup</a>.
67Markup encodes a description of the document's storage layout and logical
68structure. XML provides a mechanism to impose constraints on the storage layout
69and logical structure.</p><p>[<a name="dt-xml-proc" id="dt-xml-proc" title="XML Processor">Definition</a>: A software module called
70an <b>XML processor</b> is used to read XML documents and provide access
71to their content and structure.] [<a name="dt-app" id="dt-app" title="Application">Definition</a>: It
72is assumed that an XML processor is doing its work on behalf of another module,
73called the <b>application</b>.] This specification describes
74the required behavior of an XML processor in terms of how it must read XML
75data and the information it must provide to the application.</p><div class="div2"> <h3><a name="sec-origin-goals" id="sec-origin-goals" />1.1 Origin and Goals</h3><p>XML was developed by an XML Working Group (originally known as the SGML
76Editorial Review Board) formed under the auspices of the World Wide Web Consortium
77(W3C) in 1996. It was chaired by Jon Bosak of Sun Microsystems with the active
78participation of an XML Special Interest Group (previously known as the SGML
79Working Group) also organized by the W3C. The membership of the XML Working
80Group is given in an appendix. Dan Connolly served as the Working Group's contact with
81the W3C.</p><p>The design goals for XML are:</p><ol type="1"><li><p>XML shall be straightforwardly usable over the Internet.</p></li><li><p>XML shall support a wide variety of applications.</p></li><li><p>XML shall be compatible with SGML.</p></li><li><p>It shall be easy to write programs which process XML documents.</p></li><li><p>The number of optional features in XML is to be kept to the absolute
82minimum, ideally zero.</p></li><li><p>XML documents should be human-legible and reasonably clear.</p></li><li><p>The XML design should be prepared quickly.</p></li><li><p>The design of XML shall be formal and concise.</p></li><li><p>XML documents shall be easy to create.</p></li><li><p>Terseness in XML markup is of minimal importance.</p></li></ol><p>This specification, together with associated standards (Unicode
83<a href="#Unicode">[Unicode]</a> and ISO/IEC 10646 <a href="#ISO10646">[ISO/IEC 10646]</a>
84for characters, Internet RFC 3066 <a href="#RFC1766">[IETF RFC 3066]</a> for
85language identification tags, ISO 639 <a href="#ISO639">[ISO 639]</a>
86for language name codes, and ISO 3166 <a href="#ISO3166">[ISO 3166]</a> for
87country name codes), provides all the information necessary to
88understand XML Version 1.1 and construct computer
89programs to process it.</p><p>This version of the XML specification may be distributed freely, as long as
90all text and legal notices remain intact.</p></div><div class="div2"> <h3><a name="sec-terminology" id="sec-terminology" />1.2 Terminology</h3><p>The terminology used to describe XML documents is defined in the body of
91this specification. <span class="mustard">The key words <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">REQUIRED</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">SHALL</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">SHALL NOT</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD NOT</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">RECOMMENDED</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>, and <em class="rfc2119" title="Keyword in RFC 2119 context">OPTIONAL</em>, when <em class="rfc2119" title="Keyword in RFC 2119 context">EMPHASIZED</em>, are to be interpreted as described in <a href="#rfc2119">[IETF RFC 2119]</a>. In addition, </span>the terms defined in the following list are used in building
92those definitions and in describing the actions of an XML processor:</p><dl><dt class="label">error</dt><dd><p>[<a name="dt-error" id="dt-error" title="Error">Definition</a>: A violation of the rules of this specification;
93results are undefined. <span class="mustard">Unless otherwise specified, failure to observe a prescription of this specification indicated by one of the keywords <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">REQUIRED</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em>, <em class="rfc2119" title="Keyword in RFC 2119 context">SHALL</em> and <em class="rfc2119" title="Keyword in RFC 2119 context">SHALL NOT</em> is an error.</span> Conforming software <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> detect and report an error
94and <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> recover from it.]</p></dd><dt class="label">fatal error</dt><dd><p>[<a name="dt-fatal" id="dt-fatal" title="Fatal Error">Definition</a>: An error which a conforming <a title="XML Processor" href="#dt-xml-proc">XML processor</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> detect and report to the application.
95After encountering a fatal error, the processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> continue processing the
96data to search for further errors and <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> report such errors to the application.
97In order to support correction of errors, the processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> make unprocessed
98data from the document (with intermingled character data and markup) available
99to the application. Once a fatal error is detected, however, the processor
100<em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> continue normal processing (i.e., it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> continue to pass character
101data and information about the document's logical structure to the application
102in the normal way).]</p></dd><dt class="label">at user option</dt><dd><p>[<a name="dt-atuseroption" id="dt-atuseroption" title="At user option">Definition</a>: Conforming software
103<em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> or <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> (depending on the modal verb in the sentence) behave as described;
104if it does, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> provide users a means to enable or disable the behavior
105described.]</p></dd><dt class="label">validity constraint</dt><dd><p>[<a name="dt-vc" id="dt-vc" title="Validity constraint">Definition</a>: A rule which applies to
106all <a title="Validity" href="#dt-valid">valid</a> XML documents. Violations of validity
107constraints are errors; they <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>, at user option, be reported by <a title="Validating Processor" href="#dt-validating">validating XML processors</a>.]</p></dd><dt class="label">well-formedness constraint</dt><dd><p>[<a name="dt-wfc" id="dt-wfc" title="Well-formedness constraint">Definition</a>: A rule which applies
108to all <a title="Well-Formed" href="#dt-wellformed">well-formed</a> XML documents. Violations
109of well-formedness constraints are <a title="Fatal Error" href="#dt-fatal">fatal errors</a>.]</p></dd><dt class="label">match</dt><dd><p>[<a name="dt-match" id="dt-match" title="match">Definition</a>: (Of strings or names:) Two strings
110or names being compared <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be identical. Characters with multiple possible
111representations in Unicode (e.g. characters with both precomposed and
112base+diacritic forms) match only if they have the same representation in both
113strings. No
114case folding is performed. (Of strings and rules in the grammar:) A string
115matches a grammatical production if it belongs to the language generated by
116that production. (Of content and content models:) An element matches its declaration
117when it conforms in the fashion described in the constraint <b>[VC: <a href="#elementvalid">Element Valid</a>]</b>.]</p></dd><dt class="label">for compatibility</dt><dd><p>[<a name="dt-compat" id="dt-compat" title="For Compatibility">Definition</a>: Marks
118a sentence describing a feature of XML included solely to ensure
119that XML remains compatible with SGML.]</p></dd><dt class="label">for interoperability</dt><dd><p>[<a name="dt-interop" id="dt-interop" title="For interoperability">Definition</a>: Marks
120a sentence describing a non-binding recommendation included to increase
121the chances that XML documents can be processed by the existing installed
122base of SGML processors which predate the WebSGML Adaptations Annex to ISO 8879.]</p></dd></dl><p></p></div><div class="div2"> <h3><a name="sec-xml11" id="sec-xml11" />1.3 Rationale and list of changes for XML 1.1</h3><p>The W3C's XML 1.0 Recommendation was first issued in 1998, and
123despite the issuance of many errata culminating in a Third Edition
124of 2004, has remained (by intention) unchanged with respect to what
125is well-formed XML and what is not. This stability has been
126extremely useful for interoperability. However, the Unicode
127Standard on which XML 1.0 relies for character specifications has
128not remained static, evolving from version 2.0 to version 4.0 and
129beyond. Characters not present in Unicode 2.0 may already be used
130in XML 1.0 character data. However, they are not allowed in XML
131names such as element type names, attribute names, enumerated
132attribute values, processing instruction targets, and so on. In
133addition, some characters that should have been permitted in XML
134names were not, due to oversights and inconsistencies in Unicode
1352.0.</p><p>The overall philosophy of names has changed since XML 1.0.
136Whereas XML 1.0 provided a rigid definition of names, wherein
137everything that was not permitted was forbidden, XML 1.1 names are
138designed so that everything that is not forbidden (for a specific
139reason) is permitted. Since Unicode will continue to grow past
140version 4.0, further changes to XML can be avoided by allowing
141almost any character, including those not yet assigned, in
142names.</p><p>In addition, XML 1.0 attempts to adapt to the line-end
143conventions of various modern operating systems, but discriminates
144against the conventions used on IBM and IBM-compatible mainframes.
145As a result, XML documents on mainframes are not plain text files
146according to the local conventions. XML 1.0 documents generated on
147mainframes must either violate the local line-end conventions, or
148employ otherwise unnecessary translation phases before parsing and
149after generation. Allowing straightforward interoperability is
150particularly important when data stores are shared between
151mainframe and non-mainframe systems (as opposed to being copied
152from one to the other). Therefore XML 1.1 adds NEL (#x85) to the
153list of line-end characters. For completeness, the Unicode line
154separator character, #x2028, is also supported.
155</p><p>Finally, there is considerable demand to define a standard representation
156of arbitrary Unicode characters in XML documents. Therefore, XML 1.1
157allows the use of character references to the control characters #x1 through
158#x1F, most of which are forbidden in XML 1.0. For reasons of robustness,
159however, these characters still cannot be used directly in documents. In
160order to improve the robustness of character encoding detection, the additional
161control characters #x7F through #x9F, which were freely allowed in XML 1.0
162documents, now must also appear only as character references. (Whitespace
163characters are of course exempt.) The minor sacrifice of backward compatibility
164is considered not significant. Due to potential problems with APIs,
165#x0 is still forbidden both directly and as a character reference.
166</p><p>Finally, XML 1.1 defines a set of constraints called "full
167normalization" on XML documents, which document creators
168<em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> adhere to, and document processors
169<em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> verify. Using fully normalized documents
170ensures that identity comparisons of names, attribute values, and
171character content can be made correctly by simple binary comparison of
172Unicode strings.</p><p>A new XML version, rather than a set of errata to XML 1.0, is
173being created because the changes affect the definition of
174well-formed documents. XML 1.0 processors must continue to reject
175documents that contain new characters in XML names, new line-end
176conventions, and references to control characters. The distinction between XML 1.0 and XML 1.1 documents
177is indicated by the version number information in the XML
178declaration at the start of each document.
179</p></div></div><div class="div1"> <h2><a name="sec-documents" id="sec-documents" />2 Documents</h2><p>[<a name="dt-xml-doc" id="dt-xml-doc" title="XML Document">Definition</a>: A data object is an <b>XML
180document</b> if it is <a title="Well-Formed" href="#dt-wellformed">well-formed</a>,
181as defined in this specification. A well-formed XML document <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> in addition
182be <a title="Validity" href="#dt-valid">valid</a> if it meets certain further constraints.]</p><p>Each XML document has both a logical and a physical structure. Physically,
183the document is composed of units called <a title="Entity" href="#dt-entity">entities</a>.
184An entity <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> <a title="Entity Reference" href="#dt-entref">refer</a> to other entities to
185cause their inclusion in the document. A document begins in a "root"
186or <a title="Document Entity" href="#dt-docent">document entity</a>. Logically, the document
187is composed of declarations, elements, comments, character references, and
188processing instructions, all of which are indicated in the document by explicit
189markup. The logical and physical structures <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> nest properly, as described
190in <a href="#wf-entities"><b>4.3.2 Well-Formed Parsed Entities</b></a>.</p><div class="div2"> <h3><a name="sec-well-formed" id="sec-well-formed" />2.1 Well-Formed XML Documents</h3><p>[<a name="dt-wellformed" id="dt-wellformed" title="Well-Formed">Definition</a>: A textual object is a <b>well-formed</b>
191XML document if:]</p><ol type="1"><li><p>Taken as a whole, it matches the production labeled <a href="#NT-document">document</a>.</p></li><li><p>It meets all the well-formedness constraints given in this specification.</p></li><li><p>Each of the <a title="Text Entity" href="#dt-parsedent">parsed entities</a>
192which is referenced directly or indirectly within the document is <a
193title="Well-Formed"
194href="#dt-wellformed">well-formed</a>.</p></li></ol> <h5><a
195name="document" id="document" />Document</h5><table class="scrap"
196summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-document"
197id="NT-document"
198/>[1]   </td><td><code>document</code></td><td>   ::=   </td><td><code><a
199href="#NT-prolog">prolog</a> <a href="#NT-element">element</a> <a
200href="#NT-Misc">Misc</a>* - <a href="#NT-Char">Char</a>* <a
201href="#NT-RestrictedChar">RestrictedChar</a> <a href="#NT-Char">Char</a>*</code></td></tr></tbody></table><p>Matching the <a href="#NT-document">document</a> production implies that:</p><ol type="1"><li><p>It contains one or more <a title="Element" href="#dt-element">elements</a>.</p></li><li><p>[<a name="dt-root" id="dt-root" title="Root Element">Definition</a>: There is exactly one element,
202called the <b>root</b>, or document element, no part of which appears
203in the <a title="Content" href="#dt-content">content</a> of any other element.] For
204all other elements, if the <a title="Start-Tag" href="#dt-stag">start-tag</a> is in
205the content of another element, the <a title="End Tag" href="#dt-etag">end-tag</a>
206is in the content of the same element. More simply stated, the elements,
207delimited by start- and end-tags, nest properly within each other.</p></li></ol><p>[<a name="dt-parentchild" id="dt-parentchild" title="Parent/Child">Definition</a>: As a consequence of this,
208for each non-root element <code>C</code> in the document, there is one other element <code>P</code>
209in the document such that <code>C</code> is in the content of <code>P</code>, but
210is not in the content of any other element that is in the content of <code>P</code>. <code>P</code>
211is referred to as the <b>parent</b> of <code>C</code>, and <code>C</code> as
212a <b>child</b> of <code>P</code>.]</p></div><div class="div2"> <h3><a name="charsets" id="charsets" />2.2 Characters</h3><p>[<a name="dt-text" id="dt-text" title="Text">Definition</a>: A parsed entity contains <b>text</b>,
213a sequence of <a title="Character" href="#dt-character">characters</a>, which may
214represent markup or character data.] [<a name="dt-character" id="dt-character" title="Character">Definition</a>: A <b>character</b>
215is an atomic unit of text as specified by <span>ISO/IEC 10646 <a href="#ISO10646">[ISO/IEC 10646]</a></span>. Legal characters are tab, carriage
216return, line feed, and the legal characters
217of Unicode and ISO/IEC 10646. The
218versions of these standards cited in <a href="#sec-existing-stds"><b>A.1 Normative References</b></a> were
219current at the time this document was prepared. New characters may be added
220to these standards by amendments or new editions. Consequently, XML processors
221<em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> accept any character in the range specified for <a href="#NT-Char">Char</a>.]</p> <h5><a name="char32" id="char32" />Character Range</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-Char" id="NT-Char" />[2]   </td><td><code>Char</code></td><td>   ::=   </td><td><code>[#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]</code></td><td><i>/* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */</i></td></tr><tr valign="baseline"><td><a name="NT-RestrictedChar" id="NT-RestrictedChar" />[2a]   </td><td><code>RestrictedChar</code></td><td>   ::=   </td><td><code>[#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]</code></td></tr></tbody></table><p>The mechanism for encoding character code points into bit patterns <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>
222vary from entity to entity. All XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> accept the UTF-8 and UTF-16
223encodings of <span> Unicode
224<a href="#Unicode">[Unicode]</a></span>;
225the mechanisms for signaling which of the two is in use,
226or for bringing other encodings into play, are discussed later, in <a href="#charencoding"><b>4.3.3 Character Encoding in Entities</b></a>.</p><div class="note"><p class="prefix"><b>Note:</b></p><p>Document authors are encouraged to avoid
227"compatibility characters", as defined
228in Unicode <a href="#Unicode">[Unicode]</a>.
229The characters defined in the following ranges are also
230discouraged. They are either control characters or permanently undefined Unicode
231characters:</p><div class="exampleInner"><pre>
232[#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF],
233[#1FFFE-#x1FFFF], [#2FFFE-#x2FFFF], [#3FFFE-#x3FFFF],
234[#4FFFE-#x4FFFF], [#5FFFE-#x5FFFF], [#6FFFE-#x6FFFF],
235[#7FFFE-#x7FFFF], [#8FFFE-#x8FFFF], [#9FFFE-#x9FFFF],
236[#AFFFE-#xAFFFF], [#BFFFE-#xBFFFF], [#CFFFE-#xCFFFF],
237[#DFFFE-#xDFFFF], [#EFFFE-#xEFFFF], [#FFFFE-#xFFFFF],
238[#10FFFE-#x10FFFF].</pre></div></div></div><div class="div2"> <h3><a name="sec-common-syn" id="sec-common-syn" />2.3 Common Syntactic Constructs</h3><p>This section defines some symbols used widely in the grammar.</p><p><a href="#NT-S">S</a> (white space) consists of one or more space (#x20)
239characters, carriage returns, line feeds, or tabs.</p> <h5><a name="white" id="white" />White Space</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-S" id="NT-S" />[3]   </td><td><code>S</code></td><td>   ::=   </td><td><code>(#x20 | #x9 | #xD | #xA)+</code></td></tr></tbody></table><div class="note"><p class="prefix"><b>Note:</b></p><p>The presence of #xD in the above production is
240maintained purely for backward compatibility with the
241<a href="http://www.w3.org/TR/1998/REC-xml-19980210">First Edition</a>.
242As explained in <a href="#sec-line-ends"><b>2.11 End-of-Line Handling</b></a>,
243all #xD characters literally present in an XML document
244are either removed or replaced by #xA characters before
245any other processing is done. The only way to get a #xD character to match this production is to
246use a character reference in an entity value literal.</p></div><p>[<a name="dt-name" id="dt-name" title="Name">Definition</a>: A <b>Name</b> is a token beginning
247with a letter or one of a few punctuation characters, and continuing with
248letters, digits, hyphens, underscores, colons, or full stops, together known
249as name characters.] Names beginning with the string "<code>xml</code>",
250or <span>with</span> any string which would match <code>(('X'|'x') ('M'|'m') ('L'|'l'))</code>,
251are reserved for standardization in this or future versions of this specification.</p><div class="note"><p class="prefix"><b>Note:</b></p><p>The
252Namespaces in XML Recommendation <a href="#xml-names">[XML Names]</a> assigns a meaning
253to names containing colon characters. Therefore, authors should not use the
254colon in XML names except for namespace purposes, but XML processors must
255accept the colon as a name character.</p></div><p>An <a href="#NT-Nmtoken">Nmtoken</a> (name token) is any mixture of name
256characters.</p><p>The first character of a Name <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be a NameStartChar, and any
257other characters <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be NameChars; this mechanism is used to
258prevent names from beginning with European (ASCII) digits or with
259basic combining characters. Almost all characters are permitted in
260names, except those which either are or reasonably could be used as
261delimiters. The intention is to be inclusive rather than exclusive,
262so that writing systems not yet encoded in Unicode can be used in
263XML names. See <a href="#sec-suggested-names"><b>I Suggestions for XML Names</b></a> for suggestions on the creation of
264names.</p><p>Document authors are encouraged to use names which are
265meaningful words or combinations of words in natural languages, and
266to avoid symbolic or white space characters in names. Note that
267COLON, HYPHEN-MINUS, FULL STOP (period), LOW LINE (underscore), and
268MIDDLE DOT are explicitly permitted.</p><p>The ASCII symbols and punctuation marks, along with a fairly
269large group of Unicode symbol characters, are excluded from names
270because they are more useful as delimiters in contexts where XML
271names are used outside XML documents; providing this group gives
272those contexts hard guarantees about what <em>cannot</em> be part of
273an XML name. The character #x037E, GREEK QUESTION MARK, is excluded
274because when normalized it becomes a semicolon, which could change
275the meaning of entity references.</p> <h5><a name="IDABN1S" id="IDABN1S" />Names and Tokens</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-NameStartChar" id="NT-NameStartChar" />[4]   </td><td><code>NameStartChar</code></td><td>   ::=   </td><td><code>":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-NameChar" id="NT-NameChar" />[4a]   </td><td><code>NameChar</code></td><td>   ::=   </td><td><code><a href="#NT-NameStartChar">NameStartChar</a> | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-Name" id="NT-Name" />[5]   </td><td><code>Name</code></td><td>   ::=   </td><td><code><a href="#NT-NameStartChar">NameStartChar</a> (<a href="#NT-NameChar">NameChar</a>)*</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-Names" id="NT-Names" />[6]   </td><td><code>Names</code></td><td>   ::=   </td><td><code><a href="#NT-Name">Name</a> (#x20 <a href="#NT-Name">Name</a>)*</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-Nmtoken" id="NT-Nmtoken" />[7]   </td><td><code>Nmtoken</code></td><td>   ::=   </td><td><code>(<a href="#NT-NameChar">NameChar</a>)+</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-Nmtokens" id="NT-Nmtokens" />[8]   </td><td><code>Nmtokens</code></td><td>   ::=   </td><td><code><a href="#NT-Nmtoken">Nmtoken</a> (#x20 <a href="#NT-Nmtoken">Nmtoken</a>)*</code></td></tr></tbody></table><div class="note"><p class="prefix"><b>Note:</b></p><p>The <a href="#NT-Names">Names</a>
276and <a href="#NT-Nmtokens">Nmtokens</a> productions are used to define the validity
277of tokenized attribute values after normalization (see <a href="#sec-attribute-types"><b>3.3.1 Attribute Types</b></a>).</p></div><p>Literal data is any quoted string not containing the quotation mark used
278as a delimiter for that string. Literals are used for specifying the content
279of internal entities (<a href="#NT-EntityValue">EntityValue</a>), the values
280of attributes (<a href="#NT-AttValue">AttValue</a>), and external identifiers
281(<a href="#NT-SystemLiteral">SystemLiteral</a>). Note that a <a href="#NT-SystemLiteral">SystemLiteral</a>
282can be parsed without scanning for markup.</p> <h5><a name="IDAFR1S" id="IDAFR1S" />Literals</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-EntityValue" id="NT-EntityValue" />[9]   </td><td><code>EntityValue</code></td><td>   ::=   </td><td><code>'"' ([^%&amp;"] | <a href="#NT-PEReference">PEReference</a>
283| <a href="#NT-Reference">Reference</a>)* '"' </code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>|  "'" ([^%&amp;'] | <a href="#NT-PEReference">PEReference</a> | <a href="#NT-Reference">Reference</a>)* "'"</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-AttValue" id="NT-AttValue" />[10]   </td><td><code>AttValue</code></td><td>   ::=   </td><td><code>'"' ([^&lt;&amp;"] | <a href="#NT-Reference">Reference</a>)*
284'"' </code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>|  "'" ([^&lt;&amp;'] | <a href="#NT-Reference">Reference</a>)*
285"'"</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-SystemLiteral" id="NT-SystemLiteral" />[11]   </td><td><code>SystemLiteral</code></td><td>   ::=   </td><td><code>('"' [^"]* '"') | ("'" [^']* "'") </code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-PubidLiteral" id="NT-PubidLiteral" />[12]   </td><td><code>PubidLiteral</code></td><td>   ::=   </td><td><code>'"' <a href="#NT-PubidChar">PubidChar</a>* '"'
286| "'" (<a href="#NT-PubidChar">PubidChar</a> - "'")* "'"</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-PubidChar" id="NT-PubidChar" />[13]   </td><td><code>PubidChar</code></td><td>   ::=   </td><td><code>#x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]</code></td></tr></tbody></table><div class="note"><p class="prefix"><b>Note:</b></p><p>Although
287the <a href="#NT-EntityValue">EntityValue</a> production allows the definition
288of a general entity consisting of a single explicit <code>&lt;</code> in the literal
289(e.g., <code>&lt;!ENTITY mylt "&lt;"&gt;</code>), it is strongly advised to avoid
290this practice since any reference to that entity will cause a well-formedness
291error.</p></div></div><div class="div2"> <h3><a name="syntax" id="syntax" />2.4 Character Data and Markup</h3><p><a title="Text" href="#dt-text">Text</a> consists of intermingled <a title="Character Data" href="#dt-chardata">character data</a> and markup. [<a name="dt-markup" id="dt-markup" title="Markup">Definition</a>: <b>Markup</b> takes the form of <a title="Start-Tag" href="#dt-stag">start-tags</a>, <a title="End Tag" href="#dt-etag">end-tags</a>, <a title="Empty" href="#dt-empty">empty-element tags</a>, <a title="Entity Reference" href="#dt-entref">entity references</a>, <a title="Character Reference" href="#dt-charref">character
292references</a>, <a title="Comment" href="#dt-comment">comments</a>, <a title="CDATA Section" href="#dt-cdsection">CDATA section</a> delimiters, <a title="Document Type Declaration" href="#dt-doctype">document
293type declarations</a>, <a title="Processing instruction" href="#dt-pi">processing instructions</a>, <a href="#NT-XMLDecl">XML declarations</a>, <a href="#NT-TextDecl">text declarations</a>,
294and any white space that is at the top level of the document entity (that
295is, outside the document element and not inside any other markup).]</p><p>[<a name="dt-chardata" id="dt-chardata" title="Character Data">Definition</a>: All text that is not markup
296constitutes the <b>character data</b> of the document.]</p><p>The ampersand character (&amp;) and the left angle bracket (&lt;) <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> appear
297in their literal form<span class="mustard">, except</span> when used as markup delimiters, or
298within a <a title="Comment" href="#dt-comment">comment</a>, a <a title="Processing instruction" href="#dt-pi">processing
299instruction</a>, or a <a title="CDATA Section" href="#dt-cdsection">CDATA section</a>.
300
301If they are needed elsewhere, they <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be <a title="escape" href="#dt-escape">escaped</a>
302using either <a title="Character Reference" href="#dt-charref">numeric character references</a>
303or the strings "<code>&amp;amp;</code>" and "<code>&amp;lt;</code>"
304respectively. The right angle bracket (&gt;) <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be represented using the string "<code>&amp;gt;</code>",
305and <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>, <a title="For Compatibility" href="#dt-compat">for compatibility</a>, be escaped
306using <span>either</span> "<code>&amp;gt;</code>" or a character reference when it
307appears in the string "<code>]]&gt;</code>" in content, when
308that string is not marking the end of a <a title="CDATA Section" href="#dt-cdsection">CDATA
309section</a>.</p><p>In the content of elements, character data is any string of characters
310which does not contain the start-delimiter of any markup or the
311CDATA-section-close delimiter,
312"<code>]]&gt;</code>".
313In a CDATA section,
314character data is any string of characters not including the CDATA-section-close
315delimiter.</p><p>To allow attribute values to contain both single and double quotes, the
316apostrophe or single-quote character (') <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be represented as "<code>&amp;apos;</code>",
317and the double-quote character (") as "<code>&amp;quot;</code>".</p> <h5><a name="IDASZ1S" id="IDASZ1S" />Character Data</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-CharData" id="NT-CharData" />[14]   </td><td><code>CharData</code></td><td>   ::=   </td><td><code>[^&lt;&amp;]* - ([^&lt;&amp;]* ']]&gt;' [^&lt;&amp;]*)</code></td></tr></tbody></table></div><div class="div2"> <h3><a name="sec-comments" id="sec-comments" />2.5 Comments</h3><p>[<a name="dt-comment" id="dt-comment" title="Comment">Definition</a>: <b>Comments</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> appear
318anywhere in a document outside other <a title="Markup" href="#dt-markup">markup</a>;
319in addition, they <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> appear within the document type declaration at places
320allowed by the grammar. They are not part of the document's <a title="Character Data" href="#dt-chardata">character
321data</a>; an XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>, but need not, make it possible for an
322application to retrieve the text of comments. <a title="For Compatibility" href="#dt-compat">For
323compatibility</a>, the string "<code>--</code>" (double-hyphen)
324<em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> occur within comments.] Parameter
325entity references <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> be</span> recognized within comments.</p> <h5><a name="IDAL11S" id="IDAL11S" />Comments</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-Comment" id="NT-Comment" />[15]   </td><td><code>Comment</code></td><td>   ::=   </td><td><code>'&lt;!--' ((<a href="#NT-Char">Char</a> - '-') | ('-'
326(<a href="#NT-Char">Char</a> - '-')))* '--&gt;'</code></td></tr></tbody></table><p>An example of a comment:</p><div class="exampleInner"><pre>&lt;!-- declarations for &lt;head&gt; &amp; &lt;body&gt; --&gt;</pre></div><p>Note
327that the grammar does not allow a comment ending in <code>---&gt;</code>. The
328following example is <em>not</em> well-formed.</p><div class="exampleInner"><pre>&lt;!-- B+, B, or B---&gt;</pre></div></div><div class="div2"> <h3><a name="sec-pi" id="sec-pi" />2.6 Processing Instructions</h3><p>[<a name="dt-pi" id="dt-pi" title="Processing instruction">Definition</a>: <b>Processing instructions</b>
329(PIs) allow documents to contain instructions for applications.]</p> <h5><a name="IDAD31S" id="IDAD31S" />Processing Instructions</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-PI" id="NT-PI" />[16]   </td><td><code>PI</code></td><td>   ::=   </td><td><code>'&lt;?' <a href="#NT-PITarget">PITarget</a> (<a href="#NT-S">S</a>
330(<a href="#NT-Char">Char</a>* - (<a href="#NT-Char">Char</a>* '?&gt;' <a href="#NT-Char">Char</a>*)))? '?&gt;'</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-PITarget" id="NT-PITarget" />[17]   </td><td><code>PITarget</code></td><td>   ::=   </td><td><code><a href="#NT-Name">Name</a> - (('X' | 'x') ('M' |
331'm') ('L' | 'l'))</code></td></tr></tbody></table><p>PIs are not part of the document's <a title="Character Data" href="#dt-chardata">character
332data</a>, but <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be passed through to the application. The PI begins
333with a target (<a href="#NT-PITarget">PITarget</a>) used to identify the application
334to which the instruction is directed. The target names "<code>XML</code>", "<code>xml</code>",
335and so on are reserved for standardization in this or future versions of this
336specification. The XML <a title="Notation" href="#dt-notation">Notation</a> mechanism
337<em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be used for formal declaration of PI targets. Parameter
338entity references <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> be</span> recognized within processing instructions.</p></div><div class="div2"> <h3><a name="sec-cdata-sect" id="sec-cdata-sect" />2.7 CDATA Sections</h3><p>[<a name="dt-cdsection" id="dt-cdsection" title="CDATA Section">Definition</a>: <b>CDATA sections</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> occur anywhere character data may occur; they are used to escape blocks
339of text containing characters which would otherwise be recognized as markup.
340CDATA sections begin with the string "<code>&lt;![CDATA[</code>"
341and end with the string "<code>]]&gt;</code>":]</p> <h5><a name="IDAOA2S" id="IDAOA2S" />CDATA Sections</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-CDSect" id="NT-CDSect" />[18]   </td><td><code>CDSect</code></td><td>   ::=   </td><td><code><a href="#NT-CDStart">CDStart</a> <a href="#NT-CData">CData</a> <a href="#NT-CDEnd">CDEnd</a></code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-CDStart" id="NT-CDStart" />[19]   </td><td><code>CDStart</code></td><td>   ::=   </td><td><code>'&lt;![CDATA['</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-CData" id="NT-CData" />[20]   </td><td><code>CData</code></td><td>   ::=   </td><td><code>(<a href="#NT-Char">Char</a>* - (<a href="#NT-Char">Char</a>*
342']]&gt;' <a href="#NT-Char">Char</a>*)) </code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-CDEnd" id="NT-CDEnd" />[21]   </td><td><code>CDEnd</code></td><td>   ::=   </td><td><code>']]&gt;'</code></td></tr></tbody></table><p>Within a CDATA section, only the <a href="#NT-CDEnd">CDEnd</a> string is
343recognized as markup, so that left angle brackets and ampersands may occur
344in their literal form; they need not (and cannot) be escaped using "<code>&amp;lt;</code>"
345and "<code>&amp;amp;</code>". CDATA sections cannot nest.</p><p>An example of a CDATA section, in which "<code>&lt;greeting&gt;</code>"
346and "<code>&lt;/greeting&gt;</code>" are recognized as <a title="Character Data" href="#dt-chardata">character data</a>, not <a title="Markup" href="#dt-markup">markup</a>:</p><div class="exampleInner"><pre>&lt;![CDATA[&lt;greeting&gt;Hello, world!&lt;/greeting&gt;]]&gt; </pre></div></div><div class="div2"> <h3><a name="sec-prolog-dtd" id="sec-prolog-dtd" />2.8 Prolog and Document Type Declaration</h3><p>[<a name="dt-xmldecl" id="dt-xmldecl" title="XML Declaration">Definition</a>: XML 1.1 documents <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>
347begin with an <b>XML declaration</b> which specifies the version of
348XML being used.] For example, the following is a complete XML 1.1 document, <a title="Well-Formed" href="#dt-wellformed">well-formed</a> but not <a title="Validity" href="#dt-valid">valid</a>:</p><div class="exampleInner"><pre>&lt;?xml version="1.1"?&gt;
349&lt;greeting&gt;Hello, world!&lt;/greeting&gt; </pre></div><p>but the following is an XML 1.0 document because it
350does not have an XML declaration:</p><div class="exampleInner"><pre>&lt;greeting&gt;Hello, world!&lt;/greeting&gt;</pre></div><p>The function of the markup in an XML document is to describe its storage and
351logical structure and to associate <span>attribute
352name-value</span> pairs with its logical structures. XML provides a mechanism, the
353<a title="Document Type Declaration" href="#dt-doctype">document
354type declaration</a>, to define constraints on the logical structure
355and to support the use of predefined storage units. [<a name="dt-valid" id="dt-valid" title="Validity">Definition</a>: An XML document is <b>valid</b> if it has an associated
356document type declaration and if the document complies with the constraints
357expressed in it.]</p><p>The document type declaration <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> appear before the first <a title="Element" href="#dt-element">element</a>
358in the document.</p> <h5><a name="xmldoc" id="xmldoc" />Prolog</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-prolog" id="NT-prolog" />[22]   </td><td><code>prolog</code></td><td>   ::=   </td><td><code><a href="#NT-XMLDecl">XMLDecl</a> <a href="#NT-Misc">Misc</a>*
359(<a href="#NT-doctypedecl">doctypedecl</a> <a href="#NT-Misc">Misc</a>*)?</code></td></tr><tr valign="baseline"><td><a name="NT-XMLDecl" id="NT-XMLDecl" />[23]   </td><td><code>XMLDecl</code></td><td>   ::=   </td><td><code>'&lt;?xml' <a href="#NT-VersionInfo">VersionInfo</a> <a href="#NT-EncodingDecl">EncodingDecl</a>? <a href="#NT-SDDecl">SDDecl</a>? <a href="#NT-S">S</a>?'?&gt;'</code></td></tr><tr valign="baseline"><td><a name="NT-VersionInfo" id="NT-VersionInfo" />[24]   </td><td><code>VersionInfo</code></td><td>   ::=   </td><td><code><a href="#NT-S">S</a> 'version' <a href="#NT-Eq">Eq</a>
360("'" <a href="#NT-VersionNum">VersionNum</a> "'" | '"' <a href="#NT-VersionNum">VersionNum</a>
361'"')</code></td></tr><tr valign="baseline"><td><a name="NT-Eq" id="NT-Eq" />[25]   </td><td><code>Eq</code></td><td>   ::=   </td><td><code><a href="#NT-S">S</a>? '=' <a href="#NT-S">S</a>?</code></td></tr><tr valign="baseline"><td><a name="NT-VersionNum" id="NT-VersionNum" />[26]   </td><td><code>VersionNum</code></td><td>   ::=   </td><td><code>'1.1'</code></td></tr><tr valign="baseline"><td><a name="NT-Misc" id="NT-Misc" />[27]   </td><td><code>Misc</code></td><td>   ::=   </td><td><code><a href="#NT-Comment">Comment</a> | <a href="#NT-PI">PI</a>
362| <a href="#NT-S">S</a></code></td></tr></tbody></table><p>[<a name="dt-doctype" id="dt-doctype" title="Document Type Declaration">Definition</a>: The XML <b>document
363type declaration</b> contains or points to <a title="markup declaration" href="#dt-markupdecl">markup
364declarations</a> that provide a grammar for a class of documents. This
365grammar is known as a document type definition, or <b>DTD</b>. The document
366type declaration can point to an external subset (a special kind of <a title="External Entity" href="#dt-extent">external entity</a>) containing markup declarations,
367or can contain the markup declarations directly in an internal subset, or
368can do both. The DTD for a document consists of both subsets taken together.]</p><p>[<a name="dt-markupdecl" id="dt-markupdecl" title="markup declaration">Definition</a>: A <b>markup declaration</b>
369is an <a title="Element Type declaration" href="#dt-eldecl">element type declaration</a>, an <a title="Attribute-List Declaration" href="#dt-attdecl">attribute-list declaration</a>, an <a title="entity declaration" href="#dt-entdecl">entity
370declaration</a>, or a <a title="Notation Declaration" href="#dt-notdecl">notation declaration</a>.]
371These declarations <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be contained in whole or in part within <a title="Parameter entity" href="#dt-PE">parameter
372entities</a>, as described in the well-formedness and validity constraints
373below. For further
374information, see <a href="#sec-physical-struct"><b>4 Physical Structures</b></a>.</p> <h5><a name="dtd" id="dtd" />Document Type Definition</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-doctypedecl" id="NT-doctypedecl" />[28]   </td><td><code>doctypedecl</code></td><td>   ::=   </td><td><code>'&lt;!DOCTYPE' <a href="#NT-S">S</a> <a href="#NT-Name">Name</a>
375(<a href="#NT-S">S</a> <a href="#NT-ExternalID">ExternalID</a>)? <a href="#NT-S">S</a>?
376('[' <a href="#NT-intSubset">intSubset</a> ']' <a href="#NT-S">S</a>?)? '&gt;'</code></td><td><a href="#vc-roottype">[VC: Root Element Type]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#ExtSubset">[WFC: External Subset]</a></td></tr><tr valign="baseline"><td><a name="NT-DeclSep" id="NT-DeclSep" />[28a]   </td><td><code>DeclSep</code></td><td>   ::=   </td><td><code><a href="#NT-PEReference">PEReference</a> | <a href="#NT-S">S</a></code></td><td><a href="#PE-between-Decls">[WFC: PE Between Declarations]</a></td></tr><tr valign="baseline"><td><a name="NT-intSubset" id="NT-intSubset" />[28b]   </td><td><code>intSubset</code></td><td>   ::=   </td><td><code>(<a href="#NT-markupdecl">markupdecl</a> | <a href="#NT-DeclSep">DeclSep</a>)*</code></td></tr><tr valign="baseline"><td><a name="NT-markupdecl" id="NT-markupdecl" />[29]   </td><td><code>markupdecl</code></td><td>   ::=   </td><td><code><a href="#NT-elementdecl">elementdecl</a> | <a href="#NT-AttlistDecl">AttlistDecl</a> | <a href="#NT-EntityDecl">EntityDecl</a>
377| <a href="#NT-NotationDecl">NotationDecl</a> | <a href="#NT-PI">PI</a> | <a href="#NT-Comment">Comment</a></code></td><td><a href="#vc-PEinMarkupDecl">[VC: Proper Declaration/PE Nesting]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#wfc-PEinInternalSubset">[WFC: PEs in Internal Subset]</a></td></tr></tbody></table><p>Note
378that it is possible to construct a well-formed document containing a <a href="#NT-doctypedecl">doctypedecl</a>
379that neither points to an external subset nor contains an internal subset.</p><p>The markup declarations <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be made up in whole or in part of the <a title="Replacement Text" href="#dt-repltext">replacement text</a> of <a title="Parameter entity" href="#dt-PE">parameter
380entities</a>. The productions later in this specification for individual
381nonterminals (<a href="#NT-elementdecl">elementdecl</a>, <a href="#NT-AttlistDecl">AttlistDecl</a>,
382and so on) describe the declarations <em>after</em> all the parameter
383entities have been <a title="Include" href="#dt-include">included</a>.</p><p>Parameter
384entity references are recognized anywhere in the DTD (internal and external
385subsets and external parameter entities), except in literals, processing instructions,
386comments, and the contents of ignored conditional sections (see <a href="#sec-condition-sect"><b>3.4 Conditional Sections</b></a>).
387They are also recognized in entity value literals. The use of parameter entities
388in the internal subset is restricted as described below.</p><div class="constraint"><p class="prefix"><a name="vc-roottype" id="vc-roottype" /><b>Validity constraint: Root Element Type</b></p><p>The <a href="#NT-Name">Name</a>
389in the document type declaration <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the element type of the <a title="Root Element" href="#dt-root">root element</a>.</p></div><div class="constraint"><p class="prefix"><a name="vc-PEinMarkupDecl" id="vc-PEinMarkupDecl" /><b>Validity constraint: Proper Declaration/PE Nesting</b></p><p>Parameter-entity <a title="Replacement Text" href="#dt-repltext">replacement text</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be properly nested with markup declarations. That is to say, if either
390the first character or the last character of a markup declaration (<a href="#NT-markupdecl">markupdecl</a>
391above) is contained in the replacement text for a <a title="Parameter-entity reference" href="#dt-PERef">parameter-entity
392reference</a>, both <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be contained in the same replacement text.</p></div><div class="constraint"><p class="prefix"><a name="wfc-PEinInternalSubset" id="wfc-PEinInternalSubset" /><b>Well-formedness constraint: PEs in Internal Subset</b></p><p>In
393the internal DTD subset, <a title="Parameter-entity reference" href="#dt-PERef">parameter-entity references</a> <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> occur within markup declarations; they <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> occur where markup declarations can occur</span>.
394(This does not apply to references that occur in external parameter entities
395or to the external subset.)</p></div><div class="constraint"><p class="prefix"><a name="ExtSubset" id="ExtSubset" /><b>Well-formedness constraint: External Subset</b></p><p>The external subset, if any, <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the production for <a href="#NT-extSubset">extSubset</a>.</p></div><div class="constraint"><p class="prefix"><a name="PE-between-Decls" id="PE-between-Decls" /><b>Well-formedness constraint: PE Between Declarations</b></p><p>The replacement text of a parameter entity reference
396in a <a href="#NT-DeclSep">DeclSep</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the production <a href="#NT-extSubsetDecl">extSubsetDecl</a>.</p></div><p>Like the internal subset, the external subset and any external parameter
397entities referenced
398in a <a href="#NT-DeclSep">DeclSep</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> consist of a series of
399complete markup declarations of the types allowed by the non-terminal symbol <a href="#NT-markupdecl">markupdecl</a>, interspersed with white space or <a title="Parameter-entity reference" href="#dt-PERef">parameter-entity references</a>. However, portions of
400the contents of the external subset or of these
401external parameter entities <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> conditionally be ignored by using the <a title="conditional section" href="#dt-cond-section">conditional section</a> construct; this is not
402allowed in the internal subset<span> but is
403allowed in external parameter entities referenced in the internal subset</span>.</p> <h5><a name="ext-Subset" id="ext-Subset" />External Subset</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-extSubset" id="NT-extSubset" />[30]   </td><td><code>extSubset</code></td><td>   ::=   </td><td><code><a href="#NT-TextDecl">TextDecl</a>? <a href="#NT-extSubsetDecl">extSubsetDecl</a></code></td></tr><tr valign="baseline"><td><a name="NT-extSubsetDecl" id="NT-extSubsetDecl" />[31]   </td><td><code>extSubsetDecl</code></td><td>   ::=   </td><td><code>( <a href="#NT-markupdecl">markupdecl</a> | <a href="#NT-conditionalSect">conditionalSect</a> | <a href="#NT-DeclSep">DeclSep</a>)*</code></td></tr></tbody></table><p>The external subset and external parameter entities also differ from the
404internal subset in that in them, <a title="Parameter-entity reference" href="#dt-PERef">parameter-entity
405references</a> are permitted <em>within</em> markup declarations,
406not only <em>between</em> markup declarations.</p><p>An example of an XML document with a document type declaration:</p><div class="exampleInner"><pre>&lt;?xml version="1.1"?&gt;
407&lt;!DOCTYPE greeting SYSTEM "hello.dtd"&gt;
408&lt;greeting&gt;Hello, world!&lt;/greeting&gt; </pre></div><p>The <a title="System Identifier" href="#dt-sysid">system identifier</a> "<code>hello.dtd</code>"
409gives the address (a URI reference) of a DTD for the document.</p><p>The declarations can also be given locally, as in this example:</p><div class="exampleInner"><pre>&lt;?xml version="1.1" encoding="UTF-8" ?&gt;
410&lt;!DOCTYPE greeting [
411&lt;!ELEMENT greeting (#PCDATA)&gt;
412]&gt;
413&lt;greeting&gt;Hello, world!&lt;/greeting&gt;</pre></div><p>If both the external and internal subsets are used, the internal subset
414<span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be</span> considered to occur before the external subset.
415This has the effect that entity and attribute-list declarations in the internal
416subset take precedence over those in the external subset.</p><p>XML 1.1 processors <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> accept XML 1.0
417documents as well. If a document is well-formed or valid XML 1.0, and provided it
418does not contain any control characters
419in the range [#x7F-#x9F] other than as character escapes, it may be
420made well-formed or valid XML 1.1 respectively simply by changing the
421version number.</p></div><div class="div2"> <h3><a name="sec-rmd" id="sec-rmd" />2.9 Standalone Document Declaration</h3><p>Markup declarations can affect the content of the document, as passed from
422an <a title="XML Processor" href="#dt-xml-proc">XML processor</a> to an application; examples
423are attribute defaults and entity declarations. The standalone document declaration,
424which <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> appear as a component of the XML declaration, signals whether or
425not there are such declarations which appear external to the <a title="Document Entity" href="#dt-docent">document
426entity</a>
427or in parameter entities. [<a name="dt-extmkpdecl" id="dt-extmkpdecl" title="External Markup Declaration">Definition</a>: An <b>external
428markup declaration</b> is defined as a markup declaration occurring in
429the external subset or in a parameter entity (external or internal, the latter
430being included because non-validating processors are not required to read
431them).]</p> <h5><a name="fulldtd" id="fulldtd" />Standalone Document Declaration</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-SDDecl" id="NT-SDDecl" />[32]   </td><td><code>SDDecl</code></td><td>   ::=   </td><td><code>#x20+ 'standalone' <a href="#NT-Eq">Eq</a>
432(("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) </code></td><td><a href="#vc-check-rmd">[VC: Standalone Document Declaration]</a></td></tr></tbody></table><p>In a standalone document declaration, the value "yes" indicates
433that there are no <a title="External Markup Declaration" href="#dt-extmkpdecl">external markup declarations</a> which
434affect the information passed from the XML processor to the application. The
435value "no" indicates that there are or may be such external
436markup declarations. Note that the standalone document declaration only denotes
437the presence of external <em>declarations</em>; the presence, in a document,
438of references to external <em>entities</em>, when those entities are internally
439declared, does not change its standalone status.</p><p>If there are no external markup declarations, the standalone document declaration
440has no meaning. If there are external markup declarations but there is no
441standalone document declaration, the value "no" is assumed.</p><p>Any XML document for which <code>standalone="no"</code> holds can be converted
442algorithmically to a standalone document, which may be desirable for some
443network delivery applications.</p><div class="constraint"><p class="prefix"><a name="vc-check-rmd" id="vc-check-rmd" /><b>Validity constraint: Standalone Document Declaration</b></p><p>The
444standalone document declaration <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> have the value "no" if
445any external markup declarations contain declarations of:</p><ul><li><p>attributes with <a title="Attribute Default" href="#dt-default">default</a> values,
446if elements to which these attributes apply appear in the document without
447specifications of values for these attributes, or</p></li><li><p>entities (other than <code>amp</code>,
448<code>lt</code>,
449<code>gt</code>,
450<code>apos</code>,
451<code>quot</code>), if <a title="Entity Reference" href="#dt-entref">references</a>
452to those entities appear in the document, or</p></li><li><p>attributes with
453tokenized types, where the
454attribute appears in the document with a value such that
455<a href="#AVNormalize"><cite>normalization</cite></a>
456will produce a different value from that which would be produced
457in the absence of the declaration, or</p></li><li><p>element types with <a title="Element content" href="#dt-elemcontent">element content</a>,
458if white space occurs directly within any instance of those types.</p></li></ul></div><p>An example XML declaration with a standalone document declaration:</p><div class="exampleInner"><pre>&lt;?xml version="1.1" standalone='yes'?&gt;</pre></div></div><div class="div2"> <h3><a name="sec-white-space" id="sec-white-space" />2.10 White Space Handling</h3><p>In editing XML documents, it is often convenient to use "white space"
459(spaces, tabs, and blank lines)
460to set apart the markup for greater readability. Such white space is typically
461not intended for inclusion in the delivered version of the document. On the
462other hand, "significant" white space that should be preserved
463in the delivered version is common, for example in poetry and source code.</p><p>An <a title="XML Processor" href="#dt-xml-proc">XML processor</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> always pass
464all characters in a document that are not markup through to the application.
465A <a title="Validating Processor" href="#dt-validating"> validating XML processor</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> also
466inform the application which of these characters constitute white space appearing
467in <a title="Element content" href="#dt-elemcontent">element content</a>.</p><p>A special <a title="Attribute" href="#dt-attr">attribute</a> named <code>xml:space</code> <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be attached to an element to signal an intention that in that element,
468white space should be preserved by applications. In valid documents, this
469attribute, like any other, <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be <a title="Attribute-List Declaration" href="#dt-attdecl">declared</a>
470if it is used. When declared, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be given as an <a title="Enumerated Attribute&#xA;Values" href="#dt-enumerated">enumerated
471type</a> whose values
472are one or both of "default" and "preserve".
473For example:</p><div class="exampleInner"><pre>&lt;!ATTLIST poem xml:space (default|preserve) 'preserve'&gt;
474&lt;!ATTLIST pre xml:space (preserve) #FIXED 'preserve'&gt;</pre></div><p>The value "default" signals that applications' default white-space
475processing modes are acceptable for this element; the value "preserve"
476indicates the intent that applications preserve all the white space. This
477declared intent is considered to apply to all elements within the content
478of the element where it is specified, unless <span>overridden</span> with
479another instance of the <code>xml:space</code> attribute. <span>This specification does not give meaning to any value of <code>xml:space</code> other than "default" and "preserve". It is an error for other values to be specified; the XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> report the error or <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> recover by ignoring the attribute specification or by reporting the (erroneous) value to the application. Applications may ignore or reject erroneous values.</span></p><p>The <a title="Root Element" href="#dt-root">root element</a> of any document is considered
480to have signaled no intentions as regards application space handling, unless
481it provides a value for this attribute or the attribute is declared with a
482default value.</p></div><div class="div2"> <h3><a name="sec-line-ends" id="sec-line-ends" />2.11 End-of-Line Handling</h3><p>XML <a title="Text Entity" href="#dt-parsedent">parsed entities</a> are often stored
483in computer files which, for editing convenience, are organized into lines.
484These lines are typically separated by some combination of the characters
485CARRIAGE RETURN (#xD) and LINE FEED (#xA).</p><p>To
486simplify the tasks of <a title="Application" href="#dt-app">applications</a>, the
487<span><a title="XML Processor" href="#dt-xml-proc">XML
488processor</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> behave as if it</span> normalized all line breaks in external parsed
489entities (including the document entity) on input, before parsing, by translating
490
491<span>all of the following to a single #xA character:</span></p><ol type="1"><li><p>the two-character sequence #xD #xA</p></li><li><p>the two-character sequence #xD #x85</p></li><li><p>the single character #x85</p></li><li><p>the single character #x2028</p></li><li><p>any #xD character that is not immediately followed by #xA or #x85.</p></li></ol><p> The characters #x85 and #x2028 cannot be reliably recognized and
492translated until an entity's encoding declaration (if present) has
493been read. Therefore, it is a fatal error to use them within the XML
494declaration or text declaration.
495</p></div><div class="div2"> <h3><a name="sec-lang-tag" id="sec-lang-tag" />2.12 Language Identification</h3><p>In document processing, it is often useful to identify the natural or formal
496language in which the content is written. A special <a title="Attribute" href="#dt-attr">attribute</a>
497named <code>xml:lang</code> <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be inserted in documents to specify the language
498used in the contents and attribute values of any element in an XML document.
499In valid documents, this attribute, like any other, <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be <a title="Attribute-List Declaration" href="#dt-attdecl">declared</a>
500if it is used. The
501values of the attribute are language identifiers as defined by <a href="#RFC1766">[IETF RFC 3066]</a>, <cite>Tags
502for the Identification of Languages</cite>, or its successor<span>; in addition, the empty string <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be specified</span>.</p><p>(Productions 33 through 38 have been removed.)</p><p>For example:</p><div class="exampleInner"><pre>&lt;p xml:lang="en"&gt;The quick brown fox jumps over the lazy dog.&lt;/p&gt;
503&lt;p xml:lang="en-GB"&gt;What colour is it?&lt;/p&gt;
504&lt;p xml:lang="en-US"&gt;What color is it?&lt;/p&gt;
505&lt;sp who="Faust" desc='leise' xml:lang="de"&gt;
506&lt;l&gt;Habe nun, ach! Philosophie,&lt;/l&gt;
507&lt;l&gt;Juristerei, und Medizin&lt;/l&gt;
508&lt;l&gt;und leider auch Theologie&lt;/l&gt;
509&lt;l&gt;durchaus studiert mit hei&amp;#xDF;em Bem&amp;#xFC;h'n.&lt;/l&gt;
510&lt;/sp&gt;</pre></div><p>The intent declared with <code>xml:lang</code> is considered to apply to
511all attributes and content of the element where it is specified, unless overridden
512with an instance of <code>xml:lang</code> on another element within that content. <span>In particular, the empty value of <code>xml:lang</code> is used on an element B to override a specification of <code>xml:lang</code> on an enclosing element A, without specifying another language. Within B, it is considered that there is no language information available, just as if <code>xml:lang</code> had not been specified on B or any of its ancestors.</span></p><div class="note"><p class="prefix"><b>Note:</b></p><p>Language information may also be provided by external transport protocols (e.g. HTTP or
513MIME). When available, this information may be used by XML applications, but the more local
514information provided by <code>xml:lang</code> should be considered to override it.
515</p></div><p>A simple declaration for <code>xml:lang</code> might take the form</p><div class="exampleInner"><pre>xml:lang <span>CDATA</span> #IMPLIED</pre></div><p>but specific default values <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> also be given, if appropriate. In a collection
516of French poems for English students, with glosses and notes in English, the <code>xml:lang</code>
517attribute might be declared this way:</p><div class="exampleInner"><pre>&lt;!ATTLIST poem xml:lang <span>CDATA</span> 'fr'&gt;
518&lt;!ATTLIST gloss xml:lang <span>CDATA</span> 'en'&gt;
519&lt;!ATTLIST note xml:lang <span>CDATA</span> 'en'&gt;</pre></div></div><div class="div2"> <h3><a name="sec-normalization-checking" id="sec-normalization-checking" />2.13 Normalization Checking</h3><p>All XML <a title="Text Entity" href="#dt-parsedent"> parsed
520entities</a> (including <a title="Document Entity" href="#dt-docent"> document
521entities</a>) <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be <a title="fully normalized" href="#dt-fullnorm">fully
522normalized</a> as per the definition of
523<a href="#sec-CharNorm"><b>B Definitions for Character Normalization</b></a> supplemented by the following definitions of
524<em><a name="dt-relconst" id="dt-relconst" />relevant constructs</em> for XML:</p><ol type="1"><li><p>The <a title="Replacement Text" href="#dt-repltext">
525replacement text</a> of all <a title="Text Entity" href="#dt-parsedent">parsed
526entities</a></p></li><li><p>All text matching, in context, one of the following
527productions:</p><ol type="a"><li><p><a href="#NT-CData">
528CData</a></p></li><li><p><a href="#NT-CharData">
529CharData</a></p></li><li><p><a href="#NT-content">
530content</a></p></li><li><p><a href="#NT-Name"> Name</a></p></li><li><p><a href="#NT-Nmtoken">
531Nmtoken</a></p></li></ol></li></ol><p>However, a document is still well-formed even if it is not
532<a title="fully normalized" href="#dt-fullnorm">fully normalized</a>.
533XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> provide a user option to verify that the document being
534processed is in <a title="fully normalized" href="#dt-fullnorm">fully normalized</a> form, and report to the application whether
535it is or not. The option to not verify <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be chosen only when the
536input text is <a title="certified" href="#dt-certified">certified</a>,
537as defined by <a href="#sec-CharNorm"><b>B Definitions for Character Normalization</b></a>.</p><p>The verification of full normalization <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be carried out as if by
538first verifying that the entity is in <a title="include-normalized" href="#dt-inclnorm">include-normalized</a>
539form as defined by <a href="#sec-CharNorm"><b>B Definitions for Character Normalization</b></a> and by then verifying that none of the relevant
540constructs listed above begins (after character references are
541expanded) with a <a title="composing character" href="#dt-compchar">composing character</a> as defined by
542<a href="#sec-CharNorm"><b>B Definitions for Character Normalization</b></a>.
543Non-validating processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> ignore possible
544denormalizations that would be caused by inclusion of external
545entities that they do not read.</p><div class="note"><p class="prefix"><b>Note:</b></p><p>The <a title="composing character" href="#dt-compchar">composing character</a> are all
546Unicode characters of non-zero combining class, plus a small number
547of class-zero characters that nevertheless take part as a
548non-initial character in certain Unicode canonical
549decompositions. Since these characters are meant to follow
550base characters, restricting relevant constructs (including
551content) from beginning with a <a title="composing character" href="#dt-compchar">composing character</a> does not
552meaningfully diminish the expressiveness of XML.</p></div><p>If, while verifying full normalization, a processor encounters
553characters for which it cannot determine the normalization
554properties (i.e., characters introduced in a version of Unicode <a href="#Unicode">[Unicode]</a>
555later than the one used in the implementation of the processor),
556then the processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>, at user option, ignore any possible
557denormalizations caused by these characters. The option to ignore
558those denormalizations <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD NOT</em> be chosen by applications when
559reliability or security are critical.</p><p> XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> transform the input to be in
560<a title="fully normalized" href="#dt-fullnorm">fully normalized</a> form.
561XML applications that create XML 1.1 output
562from either XML 1.1 or XML 1.0 input <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> ensure that the output
563is <a title="fully normalized" href="#dt-fullnorm">fully normalized</a>; it is not necessary for internal processing
564forms to be <a title="fully normalized" href="#dt-fullnorm">fully normalized</a>.</p><p>The purpose of this section is to strongly encourage XML
565processors to ensure that the creators of XML documents have
566properly normalized them, so that XML applications can make tests
567such as identity comparisons of strings without having to worry
568about the different possible "spellings" of strings which
569Unicode allows.
570</p><p>When entities are in a non-Unicode encoding, if the processor
571transcodes them to Unicode, it <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> use a normalizing transcoder.
572</p></div></div><div class="div1"> <h2><a name="sec-logical-struct" id="sec-logical-struct" />3 Logical Structures</h2><p>[<a name="dt-element" id="dt-element" title="Element">Definition</a>: Each <a title="XML Document" href="#dt-xml-doc">XML
573document</a> contains one or more <b>elements</b>, the boundaries
574of which are either delimited by <a title="Start-Tag" href="#dt-stag">start-tags</a>
575and <a title="End Tag" href="#dt-etag">end-tags</a>, or, for <a title="Empty" href="#dt-empty">empty</a>
576elements, by an <a title="empty-element tag" href="#dt-eetag">empty-element tag</a>. Each
577element has a type, identified by name, sometimes called its "generic
578identifier" (GI), and <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> have a set of attribute specifications.]
579Each attribute specification has a <a title="Attribute Name" href="#dt-attrname">name</a>
580and a <a title="Attribute Value" href="#dt-attrval">value</a>.</p> <h5><a name="IDATJ3S" id="IDATJ3S" />Element</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-element" id="NT-element" />[39]   </td><td><code>element</code></td><td>   ::=   </td><td><code><a href="#NT-EmptyElemTag">EmptyElemTag</a></code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| <a href="#NT-STag">STag</a> <a href="#NT-content">content</a> <a href="#NT-ETag">ETag</a></code></td><td><a href="#GIMatch">[WFC: Element Type Match]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#elementvalid">[VC: Element Valid]</a></td></tr></tbody></table><p>This specification does not constrain the semantics, use, or (beyond syntax)
581names of the element types and attributes, except that names beginning with
582a match to <code>(('X'|'x')('M'|'m')('L'|'l'))</code> are reserved for standardization
583in this or future versions of this specification.</p><div class="constraint"><p class="prefix"><a name="GIMatch" id="GIMatch" /><b>Well-formedness constraint: Element Type Match</b></p><p>The <a href="#NT-Name">Name</a>
584in an element's end-tag <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the element type in the start-tag.</p></div><div class="constraint"><p class="prefix"><a name="elementvalid" id="elementvalid" /><b>Validity constraint: Element Valid</b></p><p>An element is valid
585if there is a declaration matching <a href="#NT-elementdecl">elementdecl</a>
586where the <a href="#NT-Name">Name</a> matches the element type, and one of
587the following holds:</p><ol type="1"><li><p>The declaration matches <b>EMPTY</b> and the element has no <a title="Content" href="#dt-content">content</a> <span>(not even entity
588references, comments, PIs or white space)</span>.</p></li><li><p>The declaration matches <a href="#NT-children">children</a> and the
589sequence of <a title="Parent/Child" href="#dt-parentchild">child elements</a> belongs
590to the language generated by the regular expression in the content model,
591with optional white space<span>, comments and
592PIs (i.e. markup matching production [27] <a href="#NT-Misc">Misc</a>)</span> between the
593start-tag and the first child element, between child elements, or between
594the last child element and the end-tag. Note that a CDATA section containing
595only white space <span>or a reference
596to an entity whose replacement text is character references expanding to white
597space</span> <span>do</span> not
598match the nonterminal <a href="#NT-S">S</a>, and
599hence cannot appear in these positions<span>; however, a
600reference to an internal entity with a literal value consisting of character
601references expanding to white space does match <a href="#NT-S">S</a>, since its
602replacement text is the white space resulting from expansion of the character
603references</span>.</p></li><li><p>The declaration matches <a href="#NT-Mixed">Mixed</a> and the content
604<span>(after replacing
605any entity references with their replacement text)</span> consists of
606<a title="Character Data" href="#dt-chardata">character data</a><span>,
607<a title="Comment" href="#dt-comment">comments</a>, <a title="Processing instruction" href="#dt-pi">PIs</a></span> and <a title="Parent/Child" href="#dt-parentchild">child elements</a> whose types match names in the
608content model.</p></li><li><p>The declaration matches <b>ANY</b>, and the
609<span>content
610<span>(after replacing
611any entity references with their replacement text)</span>
612consists of character data and <a title="Parent/Child" href="#dt-parentchild">child elements</a>
613whose types</span>
614have been declared.</p></li></ol></div><div class="div2"> <h3><a name="sec-starttags" id="sec-starttags" />3.1 Start-Tags, End-Tags, and Empty-Element Tags</h3><p>[<a name="dt-stag" id="dt-stag" title="Start-Tag">Definition</a>: The beginning of every non-empty
615XML element is marked by a <b>start-tag</b>.]</p> <h5><a name="IDA3O3S" id="IDA3O3S" />Start-tag</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-STag" id="NT-STag" />[40]   </td><td><code>STag</code></td><td>   ::=   </td><td><code>'&lt;' <a href="#NT-Name">Name</a> (<a href="#NT-S">S</a> <a href="#NT-Attribute">Attribute</a>)* <a href="#NT-S">S</a>? '&gt;'</code></td><td><a href="#uniqattspec">[WFC: Unique Att Spec]</a></td></tr><tr valign="baseline"><td><a name="NT-Attribute" id="NT-Attribute" />[41]   </td><td><code>Attribute</code></td><td>   ::=   </td><td><code><a href="#NT-Name">Name</a> <a href="#NT-Eq">Eq</a> <a href="#NT-AttValue">AttValue</a></code></td><td><a href="#ValueType">[VC: Attribute Value Type]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#NoExternalRefs">[WFC: No External Entity References]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#CleanAttrVals">[WFC: No &lt; in Attribute Values]</a></td></tr></tbody></table><p>The <a href="#NT-Name">Name</a> in the start- and end-tags gives the element's <b>type</b>. [<a name="dt-attr" id="dt-attr" title="Attribute">Definition</a>: The <a href="#NT-Name">Name</a>-<a href="#NT-AttValue">AttValue</a>
616pairs are referred to as the <b>attribute specifications</b> of the
617element], [<a name="dt-attrname" id="dt-attrname" title="Attribute Name">Definition</a>: with the <a href="#NT-Name">Name</a> in each pair referred to as the <b>attribute name</b>]
618and [<a name="dt-attrval" id="dt-attrval" title="Attribute Value">Definition</a>: the content of the <a href="#NT-AttValue">AttValue</a> (the text between the <code>'</code> or <code>"</code>
619delimiters) as the <b>attribute value</b>.] Note
620that the order of attribute specifications in a start-tag or empty-element
621tag is not significant.</p><div class="constraint"><p class="prefix"><a name="uniqattspec" id="uniqattspec" /><b>Well-formedness constraint: Unique Att Spec</b></p><p><span class="mustard">An attribute name
622<em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> appear more than once in the same start-tag or empty-element tag.</p></div><div class="constraint"><p class="prefix"><a name="ValueType" id="ValueType" /><b>Validity constraint: Attribute Value Type</b></p><p>The attribute <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>
623have been declared; the value <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be of the type declared for it. (For attribute
624types, see <a href="#attdecls"><b>3.3 Attribute-List Declarations</b></a>.)</p></div><div class="constraint"><p class="prefix"><a name="NoExternalRefs" id="NoExternalRefs" /><b>Well-formedness constraint: No External Entity References</b></p><p>Attribute
625values <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> contain direct or indirect entity references to external entities.</p></div><div class="constraint"><p class="prefix"><a name="CleanAttrVals" id="CleanAttrVals" /><b>Well-formedness constraint: No <code>&lt;</code> in Attribute Values</b></p><p>The <a title="Replacement Text" href="#dt-repltext">replacement text</a> of any entity
626referred to directly or indirectly in an attribute value <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> contain a <code>&lt;</code>.</p></div><p>An example of a start-tag:</p><div class="exampleInner"><pre>&lt;termdef id="dt-dog" term="dog"&gt;</pre></div><p>[<a name="dt-etag" id="dt-etag" title="End Tag">Definition</a>: The end of every element that begins
627with a start-tag <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be marked by an <b>end-tag</b> containing a name
628that echoes the element's type as given in the start-tag:]</p> <h5><a name="IDA3U3S" id="IDA3U3S" />End-tag</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-ETag" id="NT-ETag" />[42]   </td><td><code>ETag</code></td><td>   ::=   </td><td><code>'&lt;/' <a href="#NT-Name">Name</a> <a href="#NT-S">S</a>?
629'&gt;'</code></td></tr></tbody></table><p>An example of an end-tag:</p><div class="exampleInner"><pre>&lt;/termdef&gt;</pre></div><p>[<a name="dt-content" id="dt-content" title="Content">Definition</a>: The <a title="Text" href="#dt-text">text</a>
630between the start-tag and end-tag is called the element's <b>content</b>:]</p> <h5><a name="IDAKW3S" id="IDAKW3S" />Content of Elements</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-content" id="NT-content" />[43]   </td><td><code>content</code></td><td>   ::=   </td><td><code><a href="#NT-CharData">CharData</a>? ((<a href="#NT-element">element</a>
631| <a href="#NT-Reference">Reference</a> | <a href="#NT-CDSect">CDSect</a>
632| <a href="#NT-PI">PI</a> | <a href="#NT-Comment">Comment</a>) <a href="#NT-CharData">CharData</a>?)*</code></td></tr></tbody></table><p>[<a name="dt-empty" id="dt-empty" title="Empty">Definition</a>: An element
633with no <a href="#NT-content">content</a> is said to be <b>empty</b>.] The representation
634of an empty element is either a start-tag immediately followed by an end-tag,
635or an empty-element tag. [<a name="dt-eetag" id="dt-eetag" title="empty-element tag">Definition</a>: An <b>empty-element
636tag</b> takes a special form:]</p> <h5><a name="IDARY3S" id="IDARY3S" />Tags for Empty Elements</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-EmptyElemTag" id="NT-EmptyElemTag" />[44]   </td><td><code>EmptyElemTag</code></td><td>   ::=   </td><td><code>'&lt;' <a href="#NT-Name">Name</a> (<a href="#NT-S">S</a> <a href="#NT-Attribute">Attribute</a>)* <a href="#NT-S">S</a>? '/&gt;'</code></td><td><a href="#uniqattspec">[WFC: Unique Att Spec]</a></td></tr></tbody></table><p>Empty-element tags <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be used for any element which has no content, whether
637or not it is declared using the keyword <b>EMPTY</b>. <a title="For interoperability" href="#dt-interop">For
638interoperability</a>, the empty-element tag <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em>
639be used, and <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> only be used, for elements which are declared
640EMPTY.</p><p>Examples of empty elements:</p><div class="exampleInner"><pre>&lt;IMG align="left"
641src="http://www.w3.org/Icons/WWW/w3c_home" /&gt;
642&lt;br&gt;&lt;/br&gt;
643&lt;br/&gt;</pre></div></div><div class="div2"> <h3><a name="elemdecls" id="elemdecls" />3.2 Element Type Declarations</h3><p>The <a title="Element" href="#dt-element">element</a> structure of an <a title="XML Document" href="#dt-xml-doc">XML document</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>, for <a title="Validity" href="#dt-valid">validation</a>
644purposes, be constrained using element type and attribute-list declarations.
645An element type declaration constrains the element's <a title="Content" href="#dt-content">content</a>.</p><p>Element type declarations often constrain which element types can appear
646as <a title="Parent/Child" href="#dt-parentchild">children</a> of the element. At user
647option, an XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> issue a warning when a declaration mentions an
648element type for which no declaration is provided, but this is not an error.</p><p>[<a name="dt-eldecl" id="dt-eldecl" title="Element Type declaration">Definition</a>: An <b>element
649type declaration</b> takes the form:]</p> <h5><a name="IDAV13S" id="IDAV13S" />Element Type Declaration</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-elementdecl" id="NT-elementdecl" />[45]   </td><td><code>elementdecl</code></td><td>   ::=   </td><td><code>'&lt;!ELEMENT' <a href="#NT-S">S</a> <a href="#NT-Name">Name</a> <a href="#NT-S">S</a> <a href="#NT-contentspec">contentspec</a> <a href="#NT-S">S</a>?
650'&gt;'</code></td><td><a href="#EDUnique">[VC: Unique Element Type Declaration]</a></td></tr><tr valign="baseline"><td><a name="NT-contentspec" id="NT-contentspec" />[46]   </td><td><code>contentspec</code></td><td>   ::=   </td><td><code>'EMPTY' | 'ANY' | <a href="#NT-Mixed">Mixed</a>
651| <a href="#NT-children">children</a></code></td></tr></tbody></table><p>where the <a href="#NT-Name">Name</a> gives the element type being declared.</p><div class="constraint"><p class="prefix"><a name="EDUnique" id="EDUnique" /><b>Validity constraint: Unique Element Type Declaration</b></p><p><span class="mustard">An element
652type <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> be declared more than once.</p></div><p>Examples of element type declarations:</p><div class="exampleInner"><pre>&lt;!ELEMENT br EMPTY&gt;
653&lt;!ELEMENT p (#PCDATA|emph)* &gt;
654&lt;!ELEMENT %name.para; %content.para; &gt;
655&lt;!ELEMENT container ANY&gt;</pre></div><div class="div3"> <h4><a name="sec-element-content" id="sec-element-content" />3.2.1 Element Content</h4><p>[<a name="dt-elemcontent" id="dt-elemcontent" title="Element content">Definition</a>: An element <a title="Start-Tag" href="#dt-stag">type</a> has <b>element content</b> when elements
656of that type <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> contain only <a title="Parent/Child" href="#dt-parentchild">child</a>
657elements (no character data), optionally separated by white space (characters
658matching the nonterminal <a href="#NT-S">S</a>).] [<a name="dt-content-model" id="dt-content-model" title="Content model">Definition</a>: In this case, the constraint includes a <b>content
659model</b>, a simple grammar governing the allowed types of the
660child elements and the order in which they are allowed to appear.]
661The grammar is built on content particles (<a href="#NT-cp">cp</a>s), which
662consist of names, choice lists of content particles, or sequence lists of
663content particles:</p> <h5><a name="IDAP53S" id="IDAP53S" />Element-content Models</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-children" id="NT-children" />[47]   </td><td><code>children</code></td><td>   ::=   </td><td><code>(<a href="#NT-choice">choice</a> | <a href="#NT-seq">seq</a>)
664('?' | '*' | '+')?</code></td></tr><tr valign="baseline"><td><a name="NT-cp" id="NT-cp" />[48]   </td><td><code>cp</code></td><td>   ::=   </td><td><code>(<a href="#NT-Name">Name</a> | <a href="#NT-choice">choice</a>
665| <a href="#NT-seq">seq</a>) ('?' | '*' | '+')?</code></td></tr><tr valign="baseline"><td><a name="NT-choice" id="NT-choice" />[49]   </td><td><code>choice</code></td><td>   ::=   </td><td><code>'(' <a href="#NT-S">S</a>? <a href="#NT-cp">cp</a> ( <a href="#NT-S">S</a>? '|' <a href="#NT-S">S</a>? <a href="#NT-cp">cp</a> )+ <a href="#NT-S">S</a>? ')'</code></td><td><a href="#vc-PEinGroup">[VC: Proper Group/PE Nesting]</a></td></tr><tr valign="baseline"><td><a name="NT-seq" id="NT-seq" />[50]   </td><td><code>seq</code></td><td>   ::=   </td><td><code>'(' <a href="#NT-S">S</a>? <a href="#NT-cp">cp</a> ( <a href="#NT-S">S</a>? ',' <a href="#NT-S">S</a>? <a href="#NT-cp">cp</a> )* <a href="#NT-S">S</a>? ')'</code></td><td><a href="#vc-PEinGroup">[VC: Proper Group/PE Nesting]</a></td></tr></tbody></table><p>where each <a href="#NT-Name">Name</a> is the type of an element which
666<em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> appear as a <a title="Parent/Child" href="#dt-parentchild">child</a>. Any content
667particle in a choice list <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> appear in the <a title="Element content" href="#dt-elemcontent">element
668content</a> at the location where the choice list appears in the grammar;
669content particles occurring in a sequence list <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> each appear in the <a title="Element content" href="#dt-elemcontent">element content</a> in the order given in the list.
670The optional character following a name or list governs whether the element
671or the content particles in the list may occur one or more (<code>+</code>),
672zero or more (<code>*</code>), or zero or one times (<code>?</code>). The
673absence of such an operator means that the element or content particle <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>
674appear exactly once. This syntax and meaning are identical to those used in
675the productions in this specification.</p><p>The content of an element matches a content model if and only if it is
676possible to trace out a path through the content model, obeying the sequence,
677choice, and repetition operators and matching each element in the content
678against an element type in the content model. <a title="For Compatibility" href="#dt-compat">For
679compatibility</a>, it is an error if <span>the content model
680allows an element to match more than one occurrence of an element type in the
681content model</span>. For more information, see <a href="#determinism"><b>D Deterministic Content Models</b></a>.</p><div class="constraint"><p class="prefix"><a name="vc-PEinGroup" id="vc-PEinGroup" /><b>Validity constraint: Proper Group/PE Nesting</b></p><p>Parameter-entity <a title="Replacement Text" href="#dt-repltext">replacement text</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be properly nested with parenthesized
682groups. That is to say, if either of the opening or closing parentheses in
683a <a href="#NT-choice">choice</a>, <a href="#NT-seq">seq</a>, or <a href="#NT-Mixed">Mixed</a>
684construct is contained in the replacement text for a <a title="Parameter-entity reference" href="#dt-PERef">parameter
685entity</a>, both <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be contained in the same replacement text.</p><p><a title="For interoperability" href="#dt-interop">For interoperability</a>, if a parameter-entity reference
686appears in a <a href="#NT-choice">choice</a>, <a href="#NT-seq">seq</a>, or <a href="#NT-Mixed">Mixed</a> construct, its replacement text <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> contain at
687least one non-blank character, and neither the first nor last non-blank character
688of the replacement text <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be a connector (<code>|</code> or <code>,</code>).</p></div><p>Examples of element-content models:</p><div class="exampleInner"><pre>&lt;!ELEMENT spec (front, body, back?)&gt;
689&lt;!ELEMENT div1 (head, (p | list | note)*, div2*)&gt;
690&lt;!ELEMENT dictionary-body (%div.mix; | %dict.mix;)*&gt;</pre></div></div><div class="div3"> <h4><a name="sec-mixed-content" id="sec-mixed-content" />3.2.2 Mixed Content</h4><p>[<a name="dt-mixed" id="dt-mixed" title="Mixed Content">Definition</a>: An element <a title="Start-Tag" href="#dt-stag">type</a>
691has <b>mixed content</b> when elements of that type <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> contain character
692data, optionally interspersed with <a title="Parent/Child" href="#dt-parentchild">child</a>
693elements.] In this case, the types of the child elements <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be constrained,
694but not their order or their number of occurrences:</p> <h5><a name="IDAUHCU" id="IDAUHCU" />Mixed-content Declaration</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-Mixed" id="NT-Mixed" />[51]   </td><td><code>Mixed</code></td><td>   ::=   </td><td><code>'(' <a href="#NT-S">S</a>? '#PCDATA' (<a href="#NT-S">S</a>?
695'|' <a href="#NT-S">S</a>? <a href="#NT-Name">Name</a>)* <a href="#NT-S">S</a>?
696')*' </code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| '(' <a href="#NT-S">S</a>? '#PCDATA' <a href="#NT-S">S</a>? ')' </code></td><td><a href="#vc-PEinGroup">[VC: Proper Group/PE Nesting]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#vc-MixedChildrenUnique">[VC: No Duplicate Types]</a></td></tr></tbody></table><p>where the <a href="#NT-Name">Name</a>s give the types of elements that
697may appear as children. The
698keyword <b>#PCDATA</b> derives historically from the term "parsed
699character data."</p><div class="constraint"><p class="prefix"><a name="vc-MixedChildrenUnique" id="vc-MixedChildrenUnique" /><b>Validity constraint: No Duplicate Types</b></p><p>The
700same name <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> appear more than once in a single mixed-content declaration.</p></div><p>Examples of mixed content declarations:</p><div class="exampleInner"><pre>&lt;!ELEMENT p (#PCDATA|a|ul|b|i|em)*&gt;
701&lt;!ELEMENT p (#PCDATA | %font; | %phrase; | %special; | %form;)* &gt;
702&lt;!ELEMENT b (#PCDATA)&gt;</pre></div></div></div><div class="div2"> <h3><a name="attdecls" id="attdecls" />3.3 Attribute-List Declarations</h3><p><a title="Attribute" href="#dt-attr">Attributes</a> are used to associate name-value
703pairs with <a title="Element" href="#dt-element">elements</a>. Attribute specifications
704<span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> appear outside of</span> <a title="Start-Tag" href="#dt-stag">start-tags</a> and <a title="empty-element tag" href="#dt-eetag">empty-element tags</a>; thus, the productions used to
705recognize them appear in <a href="#sec-starttags"><b>3.1 Start-Tags, End-Tags, and Empty-Element Tags</b></a>. Attribute-list declarations
706<em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be used:</p><ul><li><p>To define the set of attributes pertaining to a given element type.</p></li><li><p>To establish type constraints for these attributes.</p></li><li><p>To provide <a title="Attribute Default" href="#dt-default">default values</a> for
707attributes.</p></li></ul><p>[<a name="dt-attdecl" id="dt-attdecl" title="Attribute-List Declaration">Definition</a>: <b>Attribute-list
708declarations</b> specify the name, data type, and default value (if any)
709of each attribute associated with a given element type:]</p> <h5><a name="IDADMCU" id="IDADMCU" />Attribute-list Declaration</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-AttlistDecl" id="NT-AttlistDecl" />[52]   </td><td><code>AttlistDecl</code></td><td>   ::=   </td><td><code>'&lt;!ATTLIST' <a href="#NT-S">S</a> <a href="#NT-Name">Name</a> <a href="#NT-AttDef">AttDef</a>* <a href="#NT-S">S</a>? '&gt;'</code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-AttDef" id="NT-AttDef" />[53]   </td><td><code>AttDef</code></td><td>   ::=   </td><td><code><a href="#NT-S">S</a> <a href="#NT-Name">Name</a> <a href="#NT-S">S</a> <a href="#NT-AttType">AttType</a> <a href="#NT-S">S</a> <a href="#NT-DefaultDecl">DefaultDecl</a></code></td></tr></tbody></table><p>The <a href="#NT-Name">Name</a> in the <a href="#NT-AttlistDecl">AttlistDecl</a>
710rule is the type of an element. At user option, an XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> issue
711a warning if attributes are declared for an element type not itself declared,
712but this is not an error. The <a href="#NT-Name">Name</a> in the <a href="#NT-AttDef">AttDef</a>
713rule is the name of the attribute.</p><p>When more than one <a href="#NT-AttlistDecl">AttlistDecl</a> is provided
714for a given element type, the contents of all those provided are merged. When
715more than one definition is provided for the same attribute of a given element
716type, the first declaration is binding and later declarations are ignored. <a title="For interoperability" href="#dt-interop">For interoperability,</a> writers of DTDs <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> choose
717to provide at most one attribute-list declaration for a given element type,
718at most one attribute definition for a given attribute name in an attribute-list
719declaration, and at least one attribute definition in each attribute-list
720declaration. For interoperability, an XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> at user option
721issue a warning when more than one attribute-list declaration is provided
722for a given element type, or more than one attribute definition is provided
723for a given attribute, but this is not an error.</p><div class="div3"> <h4><a name="sec-attribute-types" id="sec-attribute-types" />3.3.1 Attribute Types</h4><p>XML attribute types are of three kinds: a string type, a set of tokenized
724types, and enumerated types. The string type may take any literal string as
725a value; the tokenized types have varying lexical and semantic constraints.
726The validity constraints noted in the grammar are applied after the attribute
727value has been normalized as described in <span><a href="#AVNormalize"><b>3.3.3 Attribute-Value Normalization</b></a></span>.</p> <h5><a name="IDAPPCU" id="IDAPPCU" />Attribute Types</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-AttType" id="NT-AttType" />[54]   </td><td><code>AttType</code></td><td>   ::=   </td><td><code><a href="#NT-StringType">StringType</a> | <a href="#NT-TokenizedType">TokenizedType</a>
728| <a href="#NT-EnumeratedType">EnumeratedType</a></code></td></tr><tr valign="baseline"><td><a name="NT-StringType" id="NT-StringType" />[55]   </td><td><code>StringType</code></td><td>   ::=   </td><td><code>'CDATA'</code></td></tr><tr valign="baseline"><td><a name="NT-TokenizedType" id="NT-TokenizedType" />[56]   </td><td><code>TokenizedType</code></td><td>   ::=   </td><td><code>'ID'</code></td><td><a href="#id">[VC: ID]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#one-id-per-el">[VC: One ID per Element Type]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#id-default">[VC: ID Attribute Default]</a></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| 'IDREF'</code></td><td><a href="#idref">[VC: IDREF]</a></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| 'IDREFS'</code></td><td><a href="#idref">[VC: IDREF]</a></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| 'ENTITY'</code></td><td><a href="#entname">[VC: Entity Name]</a></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| 'ENTITIES'</code></td><td><a href="#entname">[VC: Entity Name]</a></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| 'NMTOKEN'</code></td><td><a href="#nmtok">[VC: Name Token]</a></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| 'NMTOKENS'</code></td><td><a href="#nmtok">[VC: Name Token]</a></td></tr></tbody></table><div class="constraint"><p class="prefix"><a name="id" id="id" /><b>Validity constraint: ID</b></p><p>Values of type <b>ID</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the <a href="#NT-Name">Name</a> production. A name <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> appear more than once
729in an XML document as a value of this type; i.e., ID values <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> uniquely
730identify the elements which bear them.</p></div><div class="constraint"><p class="prefix"><a name="one-id-per-el" id="one-id-per-el" /><b>Validity constraint: One ID per Element Type</b></p><p><span class="mustard">An element
731type <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> have more than one ID attribute specified.</p></div><div class="constraint"><p class="prefix"><a name="id-default" id="id-default" /><b>Validity constraint: ID Attribute Default</b></p><p>An ID attribute
732<em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> have a declared default of <b>#IMPLIED</b> or <b>#REQUIRED</b>.</p></div><div class="constraint"><p class="prefix"><a name="idref" id="idref" /><b>Validity constraint: IDREF</b></p><p>Values of type <b>IDREF</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>
733match the <a href="#NT-Name">Name</a> production, and values of type <b>IDREFS</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match <a href="#NT-Names">Names</a>; each <a href="#NT-Name">Name</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the value of an ID attribute on some element in the XML document;
734i.e. <b>IDREF</b> values <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the value of some ID attribute.</p></div><div class="constraint"><p class="prefix"><a name="entname" id="entname" /><b>Validity constraint: Entity Name</b></p><p>Values of type <b>ENTITY</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the <a href="#NT-Name">Name</a> production, values of type <b>ENTITIES</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match <a href="#NT-Names">Names</a>; each <a href="#NT-Name">Name</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the name of an <a title="Unparsed Entity" href="#dt-unparsed">unparsed entity</a>
735declared in the <a title="Document Type Declaration" href="#dt-doctype">DTD</a>.</p></div><div class="constraint"><p class="prefix"><a name="nmtok" id="nmtok" /><b>Validity constraint: Name Token</b></p><p>Values of type <b>NMTOKEN</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the <a href="#NT-Nmtoken">Nmtoken</a> production; values of type <b>NMTOKENS</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match <a href="#NT-Nmtokens">Nmtokens</a>.</p></div><p>[<a name="dt-enumerated" id="dt-enumerated" title="Enumerated Attribute&#xA;Values">Definition</a>: <b>Enumerated attributes</b> <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em></span> take one of a list of values
736provided in the declaration]. There are two kinds of enumerated types:</p> <h5><a name="IDAHXCU" id="IDAHXCU" />Enumerated Attribute Types</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-EnumeratedType" id="NT-EnumeratedType" />[57]   </td><td><code>EnumeratedType</code></td><td>   ::=   </td><td><code><a href="#NT-NotationType">NotationType</a>
737| <a href="#NT-Enumeration">Enumeration</a></code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-NotationType" id="NT-NotationType" />[58]   </td><td><code>NotationType</code></td><td>   ::=   </td><td><code>'NOTATION' <a href="#NT-S">S</a> '(' <a href="#NT-S">S</a>? <a href="#NT-Name">Name</a> (<a href="#NT-S">S</a>? '|' <a href="#NT-S">S</a>? <a href="#NT-Name">Name</a>)* <a href="#NT-S">S</a>? ')' </code></td><td><a href="#notatn">[VC: Notation Attributes]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#OneNotationPer">[VC: One Notation Per Element Type]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#NoNotationEmpty">[VC: No Notation on Empty Element]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#NoDuplicateTokens">[VC: No Duplicate
738Tokens]</a></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-Enumeration" id="NT-Enumeration" />[59]   </td><td><code>Enumeration</code></td><td>   ::=   </td><td><code>'(' <a href="#NT-S">S</a>? <a href="#NT-Nmtoken">Nmtoken</a>
739(<a href="#NT-S">S</a>? '|' <a href="#NT-S">S</a>? <a href="#NT-Nmtoken">Nmtoken</a>)* <a href="#NT-S">S</a>? ')'</code></td><td><a href="#enum">[VC: Enumeration]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#NoDuplicateTokens">[VC: No Duplicate
740Tokens]</a></td></tr></tbody></table><p>A <b>NOTATION</b> attribute identifies a <a title="Notation" href="#dt-notation">notation</a>,
741declared in the DTD with associated system and/or public identifiers, to be
742used in interpreting the element to which the attribute is attached.</p><div class="constraint"><p class="prefix"><a name="notatn" id="notatn" /><b>Validity constraint: Notation Attributes</b></p><p>Values of this type
743<em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match one of the <a href="#Notations"><cite>notation</cite></a> names
744included in the declaration; all notation names in the declaration <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be
745declared.</p></div><div class="constraint"><p class="prefix"><a name="OneNotationPer" id="OneNotationPer" /><b>Validity constraint: One Notation Per Element Type</b></p><p><span class="mustard">An element type <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> have more than one <b>NOTATION</b>
746attribute specified.</p></div><div class="constraint"><p class="prefix"><a name="NoNotationEmpty" id="NoNotationEmpty" /><b>Validity constraint: No Notation on Empty Element</b></p><p><a title="For Compatibility" href="#dt-compat">For compatibility</a>,
747an attribute of type <b>NOTATION</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> be declared on an element
748declared <b>EMPTY</b>.</p></div><div class="constraint"><p class="prefix"><a name="NoDuplicateTokens" id="NoDuplicateTokens" /><b>Validity constraint: No Duplicate
749Tokens</b></p><p>The notation names in a single <a href="#NT-NotationType">NotationType</a>
750attribute declaration, as well as the <a href="#NT-Nmtoken">NmToken</a>s in a single
751<a href="#NT-Enumeration">Enumeration</a> attribute declaration, <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> all be distinct.</p></div><div class="constraint"><p class="prefix"><a name="enum" id="enum" /><b>Validity constraint: Enumeration</b></p><p>Values of this type <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match
752one of the <a href="#NT-Nmtoken">Nmtoken</a> tokens in the declaration.</p></div><p><a title="For interoperability" href="#dt-interop">For interoperability,</a> the same <a href="#NT-Nmtoken">Nmtoken</a> <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD NOT</em> occur more than once in the enumerated
753attribute types of a single element type.</p></div><div class="div3"> <h4><a name="sec-attr-defaults" id="sec-attr-defaults" />3.3.2 Attribute Defaults</h4><p>An <a title="Attribute-List Declaration" href="#dt-attdecl">attribute declaration</a> provides information
754on whether the attribute's presence is <em class="rfc2119" title="Keyword in RFC 2119 context">REQUIRED</em>, and if not, how an XML processor
755<span>is
756to</span> react if a declared attribute is absent in a document.</p> <h5><a name="IDAR4CU" id="IDAR4CU" />Attribute Defaults</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-DefaultDecl" id="NT-DefaultDecl" />[60]   </td><td><code>DefaultDecl</code></td><td>   ::=   </td><td><code>'#REQUIRED' | '#IMPLIED' </code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| (('#FIXED' S)? <a href="#NT-AttValue">AttValue</a>)</code></td><td><a href="#RequiredAttr">[VC: Required Attribute]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#defattrvalid">[VC: Attribute
757Default Value Syntactically Correct]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#CleanAttrVals">[WFC: No &lt; in Attribute Values]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#FixedAttr">[VC: Fixed Attribute Default]</a></td></tr></tbody></table><p>In an attribute declaration, <b>#REQUIRED</b> means that the attribute
758<em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> always be provided, <b>#IMPLIED</b> that no default value is provided.
759[<a name="dt-default" id="dt-default" title="Attribute Default">Definition</a>: If
760the declaration is neither <b>#REQUIRED</b> nor <b>#IMPLIED</b>, then
761the <a href="#NT-AttValue">AttValue</a> value contains the declared <b>default</b>
762value; the <b>#FIXED</b> keyword states that the attribute <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> always have
763the default value.
764When an XML processor encounters
765an <span>element
766without a specification for an attribute for which it has read a default
767value declaration, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> report the attribute with the declared default
768value to the application</span>.]</p><div class="constraint"><p class="prefix"><a name="RequiredAttr" id="RequiredAttr" /><b>Validity constraint: Required Attribute</b></p><p>If the default
769declaration is the keyword <b>#REQUIRED</b>, then the attribute <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be
770specified for all elements of the type in the attribute-list declaration.</p></div><div class="constraint"><p class="prefix"><a name="defattrvalid" id="defattrvalid" /><b>Validity constraint: <span>Attribute
771Default Value Syntactically Correct</span></b></p><p>The declared default value <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> meet the <span>syntactic</span>
772constraints of the declared attribute type.</p><p>Note that only the
773syntactic constraints of the type are required here; other constraints (e.g.
774that the value be the name of a declared unparsed entity, for an attribute of
775type ENTITY) may come into play if the declared default value is actually used
776(an element without a specification for this attribute occurs).</p></div><div class="constraint"><p class="prefix"><a name="FixedAttr" id="FixedAttr" /><b>Validity constraint: Fixed Attribute Default</b></p><p>If an attribute
777has a default value declared with the <b>#FIXED</b> keyword, instances of
778that attribute <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the default value.</p></div><p>Examples of attribute-list declarations:</p><div class="exampleInner"><pre>&lt;!ATTLIST termdef
779id ID #REQUIRED
780name CDATA #IMPLIED&gt;
781&lt;!ATTLIST list
782type (bullets|ordered|glossary) "ordered"&gt;
783&lt;!ATTLIST form
784method CDATA #FIXED "POST"&gt;</pre></div></div><div class="div3"> <h4><a name="AVNormalize" id="AVNormalize" />3.3.3 Attribute-Value Normalization</h4><p>Before the value of an attribute is passed to the application or checked
785for validity, the XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> normalize the attribute value by applying
786the algorithm below, or by using some other method such that the value passed
787to the application is the same as that produced by the algorithm.</p><ol type="1"><li><p>All line breaks <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> have been normalized on input to #xA as described
788in <a href="#sec-line-ends"><b>2.11 End-of-Line Handling</b></a>, so the rest of this algorithm operates
789on text normalized in this way.</p></li><li><p>Begin with a normalized value consisting of the empty string.</p></li><li><p>For each character, entity reference, or character reference in the
790unnormalized attribute value, beginning with the first and continuing to the
791last, do the following:</p><ul><li><p>For a character reference, append the referenced character to the
792normalized value.</p></li><li><p>For an entity reference, recursively apply step 3 of this algorithm
793to the replacement text of the entity.</p></li><li><p>For a white space character (#x20, #xD, #xA, #x9), append a space
794character (#x20) to the normalized value.</p></li><li><p>For another character, append the character to the normalized value.</p></li></ul></li></ol><p>If the attribute type is not CDATA, then the XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> further
795process the normalized attribute value by discarding any leading and trailing
796space (#x20) characters, and by replacing sequences of space (#x20) characters
797by a single space (#x20) character.</p><p>Note that if the unnormalized attribute value contains a character reference
798to a white space character other than space (#x20), the normalized value contains
799the referenced character itself (#xD, #xA or #x9). This contrasts with the
800case where the unnormalized value contains a white space character (not a
801reference), which is replaced with a space character (#x20) in the normalized
802value and also contrasts with the case where the unnormalized value contains
803an entity reference whose replacement text contains a white space character;
804being recursively processed, the white space character is replaced with a
805space character (#x20) in the normalized value.</p><p>All attributes for which no declaration has been read <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be treated
806by a non-validating processor as if declared <b>CDATA</b>.</p><p>It
807is an error if an
808<span><a title="Attribute Value" href="#dt-attrval">attribute
809value</a> contains a <a title="Entity Reference" href="#dt-entref">reference</a> to an
810entity for which no declaration has been read.</span></p><p>Following are examples of attribute normalization. Given the following
811declarations:</p><div class="exampleInner"><pre>&lt;!ENTITY d "&amp;#xD;"&gt;
812&lt;!ENTITY a "&amp;#xA;"&gt;
813&lt;!ENTITY da "&amp;#xD;&amp;#xA;"&gt;</pre></div><p>the attribute specifications in the left column below would be normalized
814to the character sequences of the middle column if the attribute <code>a</code>
815is declared <b>NMTOKENS</b> and to those of the right columns if <code>a</code>
816is declared <b>CDATA</b>.</p><table border="1" frame="border" summary="Attribute normalization summary"><thead><tr><th rowspan="1" colspan="1">Attribute specification</th><th rowspan="1" colspan="1">a is NMTOKENS</th><th rowspan="1" colspan="1">a is CDATA</th></tr></thead><tbody><tr><td rowspan="1" colspan="1"><div class="exampleInner"><pre>a="
817xyz"</pre></div></td><td rowspan="1" colspan="1"><div class="exampleInner"><pre>x y z</pre></div></td><td rowspan="1" colspan="1"><div class="exampleInner"><pre>#x20 #x20 x y z</pre></div></td></tr><tr><td rowspan="1" colspan="1"><div class="exampleInner"><pre>a="&amp;d;&amp;d;A&amp;a;<span>&amp;#x20;</span>&amp;a;B&amp;da;"</pre></div></td><td rowspan="1" colspan="1"><div class="exampleInner"><pre>A #x20 B</pre></div></td><td rowspan="1" colspan="1"><div class="exampleInner"><pre>#x20 #x20 A #x20 <span>#x20</span> #x20 B #x20 #x20</pre></div></td></tr><tr><td rowspan="1" colspan="1"><div class="exampleInner"><pre>a=
818"&amp;#xd;&amp;#xd;A&amp;#xa;&amp;#xa;B&amp;#xd;&amp;#xa;"</pre></div></td><td rowspan="1" colspan="1"><div class="exampleInner"><pre>#xD #xD A #xA #xA B #xD #xA</pre></div></td><td rowspan="1" colspan="1"><div class="exampleInner"><pre>#xD #xD A #xA #xA B #xD #xA</pre></div></td></tr></tbody></table><p>Note that the last example is invalid (but well-formed) if <code>a</code>
819is declared to be of type <b>NMTOKENS</b>.</p></div></div><div class="div2"> <h3><a name="sec-condition-sect" id="sec-condition-sect" />3.4 Conditional Sections</h3><p>[<a name="dt-cond-section" id="dt-cond-section" title="conditional section">Definition</a>: <b>Conditional
820sections</b> are portions of the <a title="Document Type Declaration" href="#dt-doctype">document type
821declaration external subset</a> <span>or
822of external parameter entities </span>which are included in, or excluded from,
823the logical structure of the DTD based on the keyword which governs them.]</p> <h5><a name="IDAMHDU" id="IDAMHDU" />Conditional Section</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-conditionalSect" id="NT-conditionalSect" />[61]   </td><td><code>conditionalSect</code></td><td>   ::=   </td><td><code><a href="#NT-includeSect">includeSect</a> | <a href="#NT-ignoreSect">ignoreSect</a></code></td></tr><tr valign="baseline"><td><a name="NT-includeSect" id="NT-includeSect" />[62]   </td><td><code>includeSect</code></td><td>   ::=   </td><td><code>'&lt;![' S? 'INCLUDE' S? '[' <a href="#NT-extSubsetDecl">extSubsetDecl</a>
824']]&gt;' </code></td><td><a href="#condsec-nesting">[VC: Proper Conditional Section/PE Nesting]</a></td></tr><tr valign="baseline"><td><a name="NT-ignoreSect" id="NT-ignoreSect" />[63]   </td><td><code>ignoreSect</code></td><td>   ::=   </td><td><code>'&lt;![' S? 'IGNORE' S? '[' <a href="#NT-ignoreSectContents">ignoreSectContents</a>*
825']]&gt;'</code></td><td><a href="#condsec-nesting">[VC: Proper Conditional Section/PE Nesting]</a></td></tr><tr valign="baseline"><td><a name="NT-ignoreSectContents" id="NT-ignoreSectContents" />[64]   </td><td><code>ignoreSectContents</code></td><td>   ::=   </td><td><code><a href="#NT-Ignore">Ignore</a> ('&lt;![' <a href="#NT-ignoreSectContents">ignoreSectContents</a> ']]&gt;' <a href="#NT-Ignore">Ignore</a>)*</code></td></tr><tr valign="baseline"><td><a name="NT-Ignore" id="NT-Ignore" />[65]   </td><td><code>Ignore</code></td><td>   ::=   </td><td><code><a href="#NT-Char">Char</a>* - (<a href="#NT-Char">Char</a>*
826('&lt;![' | ']]&gt;') <a href="#NT-Char">Char</a>*) </code></td></tr></tbody></table><div class="constraint"><p class="prefix"><a name="condsec-nesting" id="condsec-nesting" /><b>Validity constraint: Proper Conditional Section/PE Nesting</b></p><p>If any of the "<code>&lt;![</code>",
827"<code>[</code>", or "<code>]]&gt;</code>" of a conditional section is contained
828in the replacement text for a parameter-entity reference, all of them <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>
829be contained in the same replacement text.</p></div><p>Like the internal and external DTD subsets, a conditional section may contain
830one or more complete declarations, comments, processing instructions, or nested
831conditional sections, intermingled with white space.</p><p>If the keyword of the conditional section is <b>INCLUDE</b>, then the
832contents of the conditional section <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be considered</span> part of the DTD. If the keyword of
833the conditional section is <b>IGNORE</b>, then the contents of the conditional
834section <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be considered as</span> not logically part of the DTD.
835If a conditional section with a keyword of <b>INCLUDE</b> occurs within
836a larger conditional section with a keyword of <b>IGNORE</b>, both the outer
837and the inner conditional sections <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be</span> ignored. The contents
838of an ignored conditional section <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be</span> parsed by ignoring all characters after
839the "<code>[</code>" following the keyword, except conditional section starts
840"<code>&lt;![</code>" and ends "<code>]]&gt;</code>", until the matching conditional
841section end is found. Parameter entity references <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> be</span> recognized in this
842process.</p><p>If the keyword of the conditional section is a parameter-entity reference,
843the parameter entity <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be replaced by its content before the processor
844decides whether to include or ignore the conditional section.</p><p>An example:</p><div class="exampleInner"><pre>&lt;!ENTITY % draft 'INCLUDE' &gt;
845&lt;!ENTITY % final 'IGNORE' &gt;
846&lt;![%draft;[
847&lt;!ELEMENT book (comments*, title, body, supplements?)&gt;
848]]&gt;
849&lt;![%final;[
850&lt;!ELEMENT book (title, body, supplements?)&gt;
851]]&gt;</pre></div></div></div><div class="div1"> <h2><a name="sec-physical-struct" id="sec-physical-struct" />4 Physical Structures</h2><p>[<a name="dt-entity" id="dt-entity" title="Entity">Definition</a>: An XML document may consist of one
852or many storage units. These
853are called <b>entities</b>; they all have <b>content</b> and are
854all (except for the <a title="Document Entity" href="#dt-docent">document entity</a> and
855the <a title="Document Type Declaration" href="#dt-doctype">external DTD subset</a>) identified by
856entity <b>name</b>.] Each XML document has one entity
857called the <a title="Document Entity" href="#dt-docent">document entity</a>, which serves
858as the starting point for the <a title="XML Processor" href="#dt-xml-proc">XML processor</a>
859and may contain the whole document.</p><p>Entities may be either parsed or unparsed. [<a name="dt-parsedent" id="dt-parsedent" title="Text Entity">Definition</a>: The contents of a <b>parsed
860entity</b> are referred to as its <a title="Replacement Text" href="#dt-repltext">replacement
861text</a>; this <a title="Text" href="#dt-text">text</a> is considered an
862integral part of the document.]</p><p>[<a name="dt-unparsed" id="dt-unparsed" title="Unparsed Entity">Definition</a>: An <b>unparsed entity</b>
863is a resource whose contents may or may not be <a title="Text" href="#dt-text">text</a>,
864and if text, may
865be other than XML. Each unparsed entity has an associated <a title="Notation" href="#dt-notation">notation</a>, identified by name. Beyond a requirement
866that an XML processor make the identifiers for the entity and notation available
867to the application, XML places no constraints on the contents of unparsed
868entities.]</p><p>Parsed entities are invoked by name using entity references; unparsed entities
869by name, given in the value of <b>ENTITY</b> or <b>ENTITIES</b> attributes.</p><p>[<a name="gen-entity" id="gen-entity" title="general entity">Definition</a>: <b>General entities</b>
870are entities for use within the document content. In this specification, general
871entities are sometimes referred to with the unqualified term <em>entity</em>
872when this leads to no ambiguity.] [<a name="dt-PE" id="dt-PE" title="Parameter entity">Definition</a>: <b>Parameter
873entities</b> are parsed entities for use within the DTD.]
874These two types of entities use different forms of reference and are recognized
875in different contexts. Furthermore, they occupy different namespaces; a parameter
876entity and a general entity with the same name are two distinct entities.</p><div class="div2"> <h3><a name="sec-references" id="sec-references" />4.1 Character and Entity References</h3><p>[<a name="dt-charref" id="dt-charref" title="Character Reference">Definition</a>: A <b>character
877reference</b> refers to a specific character in the ISO/IEC 10646 character
878set, for example one not directly accessible from available input devices.]</p> <h5><a name="IDAFYDU" id="IDAFYDU" />Character Reference</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-CharRef" id="NT-CharRef" />[66]   </td><td><code>CharRef</code></td><td>   ::=   </td><td><code>'&amp;#' [0-9]+ ';' </code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| '&amp;#x' [0-9a-fA-F]+ ';'</code></td><td><a href="#wf-Legalchar">[WFC: Legal Character]</a></td></tr></tbody></table><div class="constraint"><p class="prefix"><a name="wf-Legalchar" id="wf-Legalchar" /><b>Well-formedness constraint: Legal Character</b></p><p>Characters referred
879to using character references <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the production for <a href="#NT-Char">Char</a>.</p></div><p>If the character reference begins with "<code>&amp;#x</code>",
880the digits and letters up to the terminating <code>;</code> provide a hexadecimal
881representation of the character's code point in ISO/IEC 10646. If it begins
882just with "<code>&amp;#</code>", the digits up to the terminating <code>;</code>
883provide a decimal representation of the character's code point.</p><p>[<a name="dt-entref" id="dt-entref" title="Entity Reference">Definition</a>: An <b>entity reference</b>
884refers to the content of a named entity.] [<a name="dt-GERef" id="dt-GERef" title="General Entity Reference">Definition</a>: References to parsed general entities use
885ampersand (<code>&amp;</code>) and semicolon (<code>;</code>) as delimiters.] [<a name="dt-PERef" id="dt-PERef" title="Parameter-entity reference">Definition</a>: <b>Parameter-entity references</b>
886use percent-sign (<code>%</code>) and semicolon (<code>;</code>) as delimiters.]</p> <h5><a name="IDAS0DU" id="IDAS0DU" />Entity Reference</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-Reference" id="NT-Reference" />[67]   </td><td><code>Reference</code></td><td>   ::=   </td><td><code><a href="#NT-EntityRef">EntityRef</a> | <a href="#NT-CharRef">CharRef</a></code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-EntityRef" id="NT-EntityRef" />[68]   </td><td><code>EntityRef</code></td><td>   ::=   </td><td><code>'&amp;' <a href="#NT-Name">Name</a> ';'</code></td><td><a href="#wf-entdeclared">[WFC: Entity Declared]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#vc-entdeclared">[VC: Entity Declared]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#textent">[WFC: Parsed Entity]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#norecursion">[WFC: No Recursion]</a></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-PEReference" id="NT-PEReference" />[69]   </td><td><code>PEReference</code></td><td>   ::=   </td><td><code>'%' <a href="#NT-Name">Name</a> ';'</code></td><td><a href="#vc-entdeclared">[VC: Entity Declared]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#norecursion">[WFC: No Recursion]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#indtd">[WFC: In DTD]</a></td></tr></tbody></table><div class="constraint"><p class="prefix"><a name="wf-entdeclared" id="wf-entdeclared" /><b>Well-formedness constraint: Entity Declared</b></p><p>In a document
887without any DTD, a document with only an internal DTD subset which contains
888no parameter entity references, or a document with "<code>standalone='yes'</code>", for
889an entity reference that does not occur within the external subset or a parameter
890entity, the <a href="#NT-Name">Name</a> given in the entity reference <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> <a title="match" href="#dt-match">match</a> that in an <a href="#sec-entity-decl"><cite>entity
891declaration</cite></a> that does not occur within the external subset or a
892parameter entity, except that well-formed documents need not declare
893any of the following entities: <code>amp</code>,
894<code>lt</code>,
895<code>gt</code>,
896<code>apos</code>,
897<code>quot</code>. The
898declaration of a general entity <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> precede any reference to it which appears
899in a default value in an attribute-list declaration.</p><p><span>Note
900that non-validating processors are <a href="#include-if-valid"><cite>not
901obligated to</cite></a> to read and process entity declarations occurring in parameter entities or in
902the external subset</span>; for such documents,
903the rule that an entity must be declared is a well-formedness constraint only
904if <a href="#sec-rmd"><cite>standalone='yes'</cite></a>.</p></div><div class="constraint"><p class="prefix"><a name="vc-entdeclared" id="vc-entdeclared" /><b>Validity constraint: Entity Declared</b></p><p>In a document with
905an external subset or external parameter entities with "<code>standalone='no'</code>",
906the <a href="#NT-Name">Name</a> given in the entity reference <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> <a title="match" href="#dt-match">match</a> that in an <a href="#sec-entity-decl"><cite>entity
907declaration</cite></a>. For interoperability, valid documents <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> declare
908the entities <code>amp</code>,
909<code>lt</code>,
910<code>gt</code>,
911<code>apos</code>,
912<code>quot</code>, in the form specified in <a href="#sec-predefined-ent"><b>4.6 Predefined Entities</b></a>.
913The declaration of a parameter entity <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> precede any reference to it. Similarly,
914the declaration of a general entity <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> precede any attribute-list
915declaration containing a default value with a direct or indirect reference
916to that general entity.</p></div><div class="constraint"><p class="prefix"><a name="textent" id="textent" /><b>Well-formedness constraint: Parsed Entity</b></p><p>An entity reference <em class="rfc2119" title="Keyword in RFC 2119 context">MUST
917NOT</em> contain the name of an <a title="Unparsed Entity" href="#dt-unparsed">unparsed entity</a>.
918Unparsed entities may be referred to only in <a title="Attribute Value" href="#dt-attrval">attribute
919values</a> declared to be of type <b>ENTITY</b> or <b>ENTITIES</b>.</p></div><div class="constraint"><p class="prefix"><a name="norecursion" id="norecursion" /><b>Well-formedness constraint: No Recursion</b></p><p>A parsed entity <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> contain a recursive reference to itself, either directly or indirectly.</p></div><div class="constraint"><p class="prefix"><a name="indtd" id="indtd" /><b>Well-formedness constraint: In DTD</b></p><p>Parameter-entity references <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> appear outside</span>
920the <a title="Document Type Declaration" href="#dt-doctype">DTD</a>.</p></div><p>Examples of character and entity references:</p><div class="exampleInner"><pre>Type &lt;key&gt;less-than&lt;/key&gt; (&amp;#x3C;) to save options.
921This document was prepared on &amp;docdate; and
922is classified &amp;security-level;.</pre></div><p>Example of a parameter-entity reference:</p><div class="exampleInner"><pre>&lt;!-- declare the parameter entity "ISOLat2"... --&gt;
923&lt;!ENTITY % ISOLat2
924SYSTEM "http://www.xml.com/iso/isolat2-xml.entities" &gt;
925&lt;!-- ... now reference it. --&gt;
926%ISOLat2;</pre></div></div><div class="div2"> <h3><a name="sec-entity-decl" id="sec-entity-decl" />4.2 Entity Declarations</h3><p>[<a name="dt-entdecl" id="dt-entdecl" title="entity declaration">Definition</a>: Entities are declared
927thus:]</p> <h5><a name="IDAECEU" id="IDAECEU" />Entity Declaration</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-EntityDecl" id="NT-EntityDecl" />[70]   </td><td><code>EntityDecl</code></td><td>   ::=   </td><td><code><a href="#NT-GEDecl">GEDecl</a> | <a href="#NT-PEDecl">PEDecl</a></code></td></tr><tr valign="baseline"><td><a name="NT-GEDecl" id="NT-GEDecl" />[71]   </td><td><code>GEDecl</code></td><td>   ::=   </td><td><code>'&lt;!ENTITY' <a href="#NT-S">S</a> <a href="#NT-Name">Name</a> <a href="#NT-S">S</a> <a href="#NT-EntityDef">EntityDef</a> <a href="#NT-S">S</a>?
928'&gt;'</code></td></tr><tr valign="baseline"><td><a name="NT-PEDecl" id="NT-PEDecl" />[72]   </td><td><code>PEDecl</code></td><td>   ::=   </td><td><code>'&lt;!ENTITY' <a href="#NT-S">S</a> '%' <a href="#NT-S">S</a> <a href="#NT-Name">Name</a> <a href="#NT-S">S</a> <a href="#NT-PEDef">PEDef</a> <a href="#NT-S">S</a>? '&gt;'</code></td></tr><tr valign="baseline"><td><a name="NT-EntityDef" id="NT-EntityDef" />[73]   </td><td><code>EntityDef</code></td><td>   ::=   </td><td><code><a href="#NT-EntityValue">EntityValue</a>| (<a href="#NT-ExternalID">ExternalID</a> <a href="#NT-NDataDecl">NDataDecl</a>?)</code></td></tr><tr valign="baseline"><td><a name="NT-PEDef" id="NT-PEDef" />[74]   </td><td><code>PEDef</code></td><td>   ::=   </td><td><code><a href="#NT-EntityValue">EntityValue</a> | <a href="#NT-ExternalID">ExternalID</a></code></td></tr></tbody></table><p>The <a href="#NT-Name">Name</a> identifies the entity in an <a title="Entity Reference" href="#dt-entref">entity
929reference</a> or, in the case of an unparsed entity, in the value of
930an <b>ENTITY</b> or <b>ENTITIES</b> attribute. If the same entity is declared
931more than once, the first declaration encountered is binding; at user option,
932an XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> issue a warning if entities are declared multiple times.</p><div class="div3"> <h4><a name="sec-internal-ent" id="sec-internal-ent" />4.2.1 Internal Entities</h4><p>[<a name="dt-internent" id="dt-internent" title="Internal Entity Replacement Text">Definition</a>: If the
933entity definition is an <a href="#NT-EntityValue">EntityValue</a>, the defined
934entity is called an <b>internal entity</b>. There is no separate physical
935storage object, and the content of the entity is given in the declaration.]
936Note that some processing of entity and character references in the <a title="Literal Entity Value" href="#dt-litentval">literal entity value</a> may be required to produce
937the correct <a title="Replacement Text" href="#dt-repltext">replacement text</a>: see <a href="#intern-replacement"><b>4.5 Construction of Entity Replacement Text</b></a>.</p><p>An internal entity is a <a title="Text Entity" href="#dt-parsedent">parsed entity</a>.</p><p>Example of an internal entity declaration:</p><div class="exampleInner"><pre>&lt;!ENTITY Pub-Status "This is a pre-release of the
938specification."&gt;</pre></div></div><div class="div3"> <h4><a name="sec-external-ent" id="sec-external-ent" />4.2.2 External Entities</h4><p>[<a name="dt-extent" id="dt-extent" title="External Entity">Definition</a>: If the entity is not internal,
939it is an <b>external entity</b>, declared as follows:]</p> <h5><a name="IDAUIEU" id="IDAUIEU" />External Entity Declaration</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-ExternalID" id="NT-ExternalID" />[75]   </td><td><code>ExternalID</code></td><td>   ::=   </td><td><code>'SYSTEM' <a href="#NT-S">S</a> <a href="#NT-SystemLiteral">SystemLiteral</a></code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| 'PUBLIC' <a href="#NT-S">S</a> <a href="#NT-PubidLiteral">PubidLiteral</a> <a href="#NT-S">S</a> <a href="#NT-SystemLiteral">SystemLiteral</a></code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-NDataDecl" id="NT-NDataDecl" />[76]   </td><td><code>NDataDecl</code></td><td>   ::=   </td><td><code><a href="#NT-S">S</a> 'NDATA' <a href="#NT-S">S</a> <a href="#NT-Name">Name</a></code></td><td><a href="#not-declared">[VC: Notation Declared]</a></td></tr></tbody></table><p>If the <a href="#NT-NDataDecl">NDataDecl</a> is present, this is a general <a title="Unparsed Entity" href="#dt-unparsed">unparsed entity</a>; otherwise it is a parsed entity.</p><div class="constraint"><p class="prefix"><a name="not-declared" id="not-declared" /><b>Validity constraint: Notation Declared</b></p><p>The <a href="#NT-Name">Name</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> match the declared name of a <a title="Notation" href="#dt-notation">notation</a>.</p></div><p>[<a name="dt-sysid" id="dt-sysid" title="System Identifier">Definition</a>: The <a href="#NT-SystemLiteral">SystemLiteral</a> is called the entity's <b>system
940identifier</b>. It is <span>meant to be
941converted to</span> a URI reference
942(as defined in <a href="#rfc2396">[IETF RFC 2396]</a>, updated by <a href="#rfc2732">[IETF RFC 2732]</a>),
943<span>as part of the
944process of dereferencing it</span> to obtain input for the XML processor to construct the
945entity's replacement text.] It is an error for a fragment identifier
946(beginning with a <code>#</code> character) to be part of a system identifier.
947Unless otherwise provided by information outside the scope of this specification
948(e.g. a special XML element type defined by a particular DTD, or a processing
949instruction defined by a particular application specification), relative URIs
950are relative to the location of the resource within which the entity declaration
951occurs. <span>This is defined to
952be the external entity containing the '&lt;' which starts the declaration, at the
953point when it is parsed as a declaration.</span>
954A URI might thus be relative to the <a title="Document Entity" href="#dt-docent">document
955entity</a>, to the entity containing the <a title="Document Type Declaration" href="#dt-doctype">external
956DTD subset</a>, or to some other <a title="External Entity" href="#dt-extent">external parameter
957entity</a>. <span>Attempts to
958retrieve the resource identified by a URI <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be redirected at the parser
959level (for example, in an entity resolver) or below (at the protocol level,
960for example, via an HTTP <code>Location:</code> header). In the absence of additional
961information outside the scope of this specification within the resource,
962the base URI of a resource is always the URI of the actual resource returned.
963In other words, it is the URI of the resource retrieved after all redirection
964has occurred.</span></p><p>System
965identifiers (and other XML strings meant to be used as URI references) <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> contain
966characters that, according to <a href="#rfc2396">[IETF RFC 2396]</a> and <a href="#rfc2732">[IETF RFC 2732]</a>,
967must be escaped before a URI can be used to retrieve the referenced resource. The
968characters to be escaped are the control characters #x0 to #x1F and #x7F (most of
969which cannot appear in XML), space #x20, the delimiters '&lt;' #x3C, '&gt;' #x3E and
970'"' #x22, the <em>unwise</em> characters '{' #x7B, '}' #x7D, '|' #x7C, '\' #x5C, '^' #x5E and
971'`' #x60, as well as all characters above #x7F. Since escaping is not always a fully
972reversible process, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be performed only when absolutely necessary and as late
973as possible in a processing chain. In particular, neither the process of converting
974a relative URI to an absolute one nor the process of passing a URI reference to a
975process or software component responsible for dereferencing it <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> trigger escaping.
976When escaping does occur, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be performed as follows:</p><ol type="1"><li><p>Each
977character <span>to be escaped</span>
978is <span>represented in</span>
979UTF-8 <span><a href="#Unicode">[Unicode]</a></span>
980as one or more bytes.</p></li><li><p><span>The resulting bytes</span>
981are escaped with
982the URI escaping mechanism (that is, converted to <code>%</code><var>HH</var>,
983where HH is the hexadecimal notation of the byte value).</p></li><li><p>The original character is replaced by the resulting character sequence.</p></li></ol><p>[<a name="dt-pubid" id="dt-pubid" title="Public identifier">Definition</a>: In addition to a system
984identifier, an external identifier <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> include a <b>public identifier</b>.]
985An XML processor attempting to retrieve the entity's content <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> use
986<span>any combination of
987the public and system identifiers as well as additional information outside the
988scope of this specification</span> to try to generate an alternative URI reference.
989If the processor is unable to do so, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> use the URI
990reference specified in the system literal. Before a match is attempted,
991all strings of white space in the public identifier <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be normalized to
992single space characters (#x20), and leading and trailing white space <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>
993be removed.</p><p>Examples of external entity declarations:</p><div class="exampleInner"><pre>&lt;!ENTITY open-hatch
994SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml"&gt;
995&lt;!ENTITY open-hatch
996PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN"
997"http://www.textuality.com/boilerplate/OpenHatch.xml"&gt;
998&lt;!ENTITY hatch-pic
999SYSTEM "../grafix/OpenHatch.gif"
1000NDATA gif &gt;</pre></div></div></div><div class="div2"> <h3><a name="TextEntities" id="TextEntities" />4.3 Parsed Entities</h3><div class="div3"> <h4><a name="sec-TextDecl" id="sec-TextDecl" />4.3.1 The Text Declaration</h4><p>External parsed entities <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> each begin with a <b>text declaration</b>.</p> <h5><a name="IDAUPEU" id="IDAUPEU" />Text Declaration</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-TextDecl" id="NT-TextDecl" />[77]   </td><td><code>TextDecl</code></td><td>   ::=   </td><td><code>'&lt;?xml' <a href="#NT-VersionInfo">VersionInfo</a>? <a href="#NT-EncodingDecl">EncodingDecl</a> <a href="#NT-S">S</a>? '?&gt;'</code></td></tr></tbody></table><p>The text declaration <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be provided literally, not by reference
1001to a parsed entity. <span class="mustard">The</span> text declaration
1002<span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> appear at any
1003position other than the beginning of an external parsed entity. The text declaration
1004in an external parsed entity is not considered part of its <a title="Replacement Text" href="#dt-repltext">replacement text</a>.</p></div><div class="div3"> <h4><a name="wf-entities" id="wf-entities" />4.3.2 Well-Formed Parsed Entities</h4><p>The document entity is well-formed if it matches the production labeled <a href="#NT-document">document</a>. An external general parsed entity is well-formed
1005if it matches the production labeled <a href="#NT-extParsedEnt">extParsedEnt</a>. All
1006external parameter entities are well-formed by definition.</p> <h5><a name="IDA2REU" id="IDA2REU" />Well-Formed External Parsed Entity</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-extParsedEnt" id="NT-extParsedEnt" />[78]   </td><td><code>extParsedEnt</code></td><td>   ::=   </td><td><code><a href="#NT-TextDecl">TextDecl</a>? <a href="#NT-content">content</a> - <a href="#NT-Char">Char</a>* <a href="#NT-RestrictedChar">RestrictedChar</a> <a href="#NT-Char">Char</a>*</code></td></tr></tbody></table><p>An internal general parsed entity is well-formed if its replacement text
1007matches the production labeled <a href="#NT-content">content</a>. All internal
1008parameter entities are well-formed by definition.</p><p>A consequence of well-formedness in <span>general</span>
1009entities is that the logical and physical
1010structures in an XML document are properly nested; no <a title="Start-Tag" href="#dt-stag">start-tag</a>, <a title="End Tag" href="#dt-etag">end-tag</a>, <a title="Empty" href="#dt-empty">empty-element tag</a>, <a title="Element" href="#dt-element">element</a>, <a title="Comment" href="#dt-comment">comment</a>, <a title="Processing instruction" href="#dt-pi">processing instruction</a>, <a title="Character Reference" href="#dt-charref">character
1011reference</a>, or <a title="Entity Reference" href="#dt-entref">entity reference</a>
1012can begin in one entity and end in another.</p></div><div class="div3"> <h4><a name="charencoding" id="charencoding" />4.3.3 Character Encoding in Entities</h4><p>Each external parsed entity in an XML document <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> use a different encoding
1013for its characters. All XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be able to read entities in both
1014the UTF-8 and UTF-16 encodings. The terms "UTF-8"
1015and "UTF-16" in this specification do not apply to character
1016encodings with any other labels, even if the encodings or labels are very
1017similar to UTF-8 or UTF-16.</p><p>Entities encoded in UTF-16 <span><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em></span> <span>and entities
1018encoded in UTF-8 <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em></span> begin with the Byte Order Mark described in
1019ISO/IEC 10646 <a href="#ISO10646">[ISO/IEC 10646]</a> or Unicode <a href="#Unicode">[Unicode]</a>
1020(the ZERO WIDTH NO-BREAK SPACE character, #xFEFF). This is an encoding signature,
1021not part of either the markup or the character data of the XML document. XML
1022processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be able to use this character to differentiate between UTF-8
1023and UTF-16 encoded documents.</p><p>Although an XML processor is required to read only entities in the UTF-8
1024and UTF-16 encodings, it is recognized that other encodings are used around
1025the world, and it may be desired for XML processors to read entities that
1026use them. In
1027the absence of external character encoding information (such as MIME headers),
1028parsed entities which are stored in an encoding other than UTF-8 or UTF-16
1029<em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> begin with a text declaration (see <a href="#sec-TextDecl"><b>4.3.1 The Text Declaration</b></a>) containing
1030an encoding declaration:</p> <h5><a name="IDARVEU" id="IDARVEU" />Encoding Declaration</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-EncodingDecl" id="NT-EncodingDecl" />[80]   </td><td><code>EncodingDecl</code></td><td>   ::=   </td><td><code><a href="#NT-S">S</a> 'encoding' <a href="#NT-Eq">Eq</a>
1031('"' <a href="#NT-EncName">EncName</a> '"' | "'" <a href="#NT-EncName">EncName</a>
1032"'" ) </code></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-EncName" id="NT-EncName" />[81]   </td><td><code>EncName</code></td><td>   ::=   </td><td><code>[A-Za-z] ([A-Za-z0-9._] | '-')*</code></td><td><i>/* Encoding
1033name contains only Latin characters */</i></td></tr></tbody></table><p>In the <a title="Document Entity" href="#dt-docent">document entity</a>, the encoding
1034declaration is part of the <a title="XML Declaration" href="#dt-xmldecl">XML declaration</a>.
1035The <a href="#NT-EncName">EncName</a> is the name of the encoding used.</p><p>In an encoding declaration, the values "<code>UTF-8</code>", "<code>UTF-16</code>",
1036"<code>ISO-10646-UCS-2</code>", and "<code>ISO-10646-UCS-4</code>" <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be used
1037for the various encodings and transformations of Unicode / ISO/IEC 10646,
1038the values "<code>ISO-8859-1</code>", "<code>ISO-8859-2</code>",
1039... "<code>ISO-8859-</code><var>n</var>" (where <var>n</var>
1040is the part number) <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be used for the parts of ISO 8859, and
1041the values "<code>ISO-2022-JP</code>", "<code>Shift_JIS</code>",
1042and "<code>EUC-JP</code>" <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be used for the various encoded
1043forms of JIS X-0208-1997. It
1044is <em class="rfc2119" title="Keyword in RFC 2119 context">RECOMMENDED</em> that character encodings registered (as <em>charset</em>s)
1045with the Internet Assigned Numbers Authority <a href="#IANA">[IANA-CHARSETS]</a>,
1046other than those just listed, be referred to using their registered names;
1047other encodings <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> use names starting with an "x-" prefix.
1048XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> match character encoding names in a case-insensitive
1049way and <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> either interpret an IANA-registered name as the encoding registered
1050at IANA for that name or treat it as unknown (processors are, of course, not
1051required to support all IANA-registered encodings).</p><p>In the absence of information provided by an external transport protocol
1052(e.g. HTTP or MIME), it is a <a title="Fatal Error" href="#dt-fatal">fatal error</a> for
1053an entity including an encoding declaration to be presented to the XML processor
1054in an encoding other than that named in the declaration, or for an entity which
1055begins with neither a Byte Order Mark
1056nor an encoding declaration to use an encoding other than UTF-8. Note that
1057since ASCII is a subset of UTF-8, ordinary ASCII entities do not strictly
1058need an encoding declaration.</p><p>It is a <a title="Fatal Error" href="#dt-fatal">fatal error</a> for a <a href="#NT-TextDecl">TextDecl</a> to occur other
1059than at the beginning of an external entity.</p><p>It is a <a title="Fatal Error" href="#dt-fatal">fatal error</a> when an XML processor
1060encounters an entity with an encoding that it is unable to process. It
1061is a <a title="Fatal Error" href="#dt-fatal">fatal error</a> if an XML entity is determined (via default, encoding declaration,
1062or higher-level protocol) to be in a certain encoding but contains <span>byte</span>
1063sequences that are not legal in that encoding. <span>Specifically, it is a
1064fatal error if an entity encoded in UTF-8 contains any irregular code unit sequences,
1065as defined in Unicode <a href="#Unicode">[Unicode]</a>.</span> <span>Unless an encoding
1066is determined by a higher-level protocol, </span>it is also a <a title="Fatal Error" href="#dt-fatal">fatal error</a> if an XML entity
1067contains no encoding declaration and its content is not legal UTF-8 or UTF-16.</p><p>Examples of text declarations containing encoding declarations:</p><div class="exampleInner"><pre>&lt;?xml encoding='UTF-8'?&gt;
1068&lt;?xml encoding='EUC-JP'?&gt;</pre></div></div><div class="div3"> <h4><a name="sec-version-info" id="sec-version-info" />4.3.4 Version Information in Entities</h4><p>Each entity, including the <a title="Document Entity" href="#dt-docent">document entity</a>,
1069can be separately
1070declared as XML 1.0 or XML 1.1. The version declaration appearing
1071in the document entity determines the version of the document as a
1072whole. An XML 1.1 document may invoke XML 1.0 external entities, so
1073that otherwise duplicated versions of external entities,
1074particularly DTD external subsets, need not be maintained. However,
1075in such a case the rules of XML 1.1 are applied to the entire
1076document.</p><p> If an entity (including the document entity) is not labeled
1077with a version number, it is treated as if labeled as version
10781.0.</p></div></div><div class="div2"> <h3><a name="entproc" id="entproc" />4.4 XML Processor Treatment of Entities and References</h3><p>The table below summarizes the contexts in which character references,
1079entity references, and invocations of unparsed entities might appear and the
1080<em class="rfc2119" title="Keyword in RFC 2119 context">REQUIRED</em> behavior of an <a title="XML Processor" href="#dt-xml-proc">XML processor</a>
1081in each case. The labels in the leftmost column describe the recognition context: </p><dl><dt class="label">Reference in Content</dt><dd><p>as a reference anywhere after the <a title="Start-Tag" href="#dt-stag">start-tag</a>
1082and before the <a title="End Tag" href="#dt-etag">end-tag</a> of an element; corresponds
1083to the nonterminal <a href="#NT-content">content</a>.</p></dd><dt class="label">Reference in Attribute Value</dt><dd><p>as a reference within either the value of an attribute in a <a title="Start-Tag" href="#dt-stag">start-tag</a>,
1084or a default value in an <a title="Attribute-List Declaration" href="#dt-attdecl">attribute declaration</a>;
1085corresponds to the nonterminal <a href="#NT-AttValue">AttValue</a>.</p></dd><dt class="label">Occurs as Attribute Value</dt><dd><p>as a <a href="#NT-Name">Name</a>, not a reference, appearing either as
1086the value of an attribute which has been declared as type <b>ENTITY</b>,
1087or as one of the space-separated tokens in the value of an attribute which
1088has been declared as type <b>ENTITIES</b>.</p></dd><dt class="label">Reference in Entity Value</dt><dd><p>as a reference within a parameter or internal entity's <a title="Literal Entity Value" href="#dt-litentval">literal
1089entity value</a> in the entity's declaration; corresponds to the nonterminal <a href="#NT-EntityValue">EntityValue</a>.</p></dd><dt class="label">Reference in DTD</dt><dd><p>as a reference within either the internal or external subsets of the <a title="Document Type Declaration" href="#dt-doctype">DTD</a>, but outside of an <a href="#NT-EntityValue">EntityValue</a>, <a href="#NT-AttValue">AttValue</a>, <a href="#NT-PI">PI</a>, <a href="#NT-Comment">Comment</a>, <a href="#NT-SystemLiteral">SystemLiteral</a>, <a href="#NT-PubidLiteral">PubidLiteral</a>,
1090or the contents of an ignored conditional section (see <a href="#sec-condition-sect"><b>3.4 Conditional Sections</b></a>).</p><p>.</p></dd></dl><p></p><table border="1" frame="border" cellpadding="7" summary="Entity type/reference matrix"><tbody align="center"><tr><td rowspan="2" colspan="1"></td><td colspan="4" align="center" valign="bottom" rowspan="1">Entity
1091Type</td><td rowspan="2" align="center" colspan="1">Character</td></tr><tr align="center" valign="bottom"><td rowspan="1" colspan="1">Parameter</td><td rowspan="1" colspan="1">Internal General</td><td rowspan="1" colspan="1">External Parsed
1092General</td><td rowspan="1" colspan="1">Unparsed</td></tr><tr align="center" valign="middle"><td align="right" rowspan="1" colspan="1">Reference
1093in Content</td><td rowspan="1" colspan="1"><a href="#not-recognized"><cite>Not recognized</cite></a></td><td rowspan="1" colspan="1"><a href="#included"><cite>Included</cite></a></td><td rowspan="1" colspan="1"><a href="#include-if-valid"><cite>Included
1094if validating</cite></a></td><td rowspan="1" colspan="1"><a href="#forbidden"><cite>Forbidden</cite></a></td><td rowspan="1" colspan="1"><a href="#included"><cite>Included</cite></a></td></tr><tr align="center" valign="middle"><td align="right" rowspan="1" colspan="1">Reference in Attribute Value</td><td rowspan="1" colspan="1"><a href="#not-recognized"><cite>Not recognized</cite></a></td><td rowspan="1" colspan="1"><a href="#inliteral"><cite>Included
1095in literal</cite></a></td><td rowspan="1" colspan="1"><a href="#forbidden"><cite>Forbidden</cite></a></td><td rowspan="1" colspan="1"><a href="#forbidden"><cite>Forbidden</cite></a></td><td rowspan="1" colspan="1"><a href="#included"><cite>Included</cite></a></td></tr><tr align="center" valign="middle"><td align="right" rowspan="1" colspan="1">Occurs as Attribute
1096Value</td><td rowspan="1" colspan="1"><a href="#not-recognized"><cite>Not recognized</cite></a></td><td rowspan="1" colspan="1"><a href="#forbidden"><cite>Forbidden</cite></a></td><td rowspan="1" colspan="1"><a href="#forbidden"><cite>Forbidden</cite></a></td><td rowspan="1" colspan="1"><a href="#notify"><cite>Notify</cite></a></td><td rowspan="1" colspan="1"><a href="#not-recognized"><cite>Not recognized</cite></a></td></tr><tr align="center" valign="middle"><td align="right" rowspan="1" colspan="1">Reference in EntityValue</td><td rowspan="1" colspan="1"><a href="#inliteral"><cite>Included in literal</cite></a></td><td rowspan="1" colspan="1"><a href="#bypass"><cite>Bypassed</cite></a></td><td rowspan="1" colspan="1"><a href="#bypass"><cite>Bypassed</cite></a></td><td rowspan="1" colspan="1"><a href="#error"><cite><span>Error</span></cite></a></td><td rowspan="1" colspan="1"><a href="#included"><cite>Included</cite></a></td></tr><tr align="center" valign="middle"><td align="right" rowspan="1" colspan="1">Reference in DTD</td><td rowspan="1" colspan="1"><a href="#as-PE"><cite>Included as PE</cite></a></td><td rowspan="1" colspan="1"><a href="#forbidden"><cite>Forbidden</cite></a></td><td rowspan="1" colspan="1"><a href="#forbidden"><cite>Forbidden</cite></a></td><td rowspan="1" colspan="1"><a href="#forbidden"><cite>Forbidden</cite></a></td><td rowspan="1" colspan="1"><a href="#forbidden"><cite>Forbidden</cite></a></td></tr></tbody></table><div class="div3"> <h4><a name="not-recognized" id="not-recognized" />4.4.1 Not Recognized</h4><p>Outside the DTD, the <code>%</code> character has no special significance;
1097thus, what would be parameter entity references in the DTD are not recognized
1098as markup in <a href="#NT-content">content</a>. Similarly, the names of unparsed
1099entities are not recognized except when they appear in the value of an appropriately
1100declared attribute.</p></div><div class="div3"> <h4><a name="included" id="included" />4.4.2 Included</h4><p>[<a name="dt-include" id="dt-include" title="Include">Definition</a>: An entity is <b>included</b>
1101when its <a title="Replacement Text" href="#dt-repltext">replacement text</a> is retrieved
1102and processed, in place of the reference itself, as though it were part of
1103the document at the location the reference was recognized.] The replacement
1104text <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> contain both <a title="Character Data" href="#dt-chardata">character data</a>
1105and (except for parameter entities) <a title="Markup" href="#dt-markup">markup</a>,
1106which <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be recognized in the usual way. (The string "<code>AT&amp;amp;T;</code>"
1107expands to "<code>AT&amp;T;</code>" and the remaining ampersand
1108is not recognized as an entity-reference delimiter.) A character reference
1109is <b>included</b> when the indicated character is processed in place
1110of the reference itself. </p></div><div class="div3"> <h4><a name="include-if-valid" id="include-if-valid" />4.4.3 Included If Validating</h4><p>When an XML processor recognizes a reference to a parsed entity, in order
1111to <a title="Validity" href="#dt-valid">validate</a> the document, the processor
1112<em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> <a title="Include" href="#dt-include">include</a> its replacement text. If
1113the entity is external, and the processor is not attempting to validate the
1114XML document, the processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>, but need
1115not, include the entity's replacement text. If a non-validating processor
1116does not include the replacement text, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> inform the application that
1117it recognized, but did not read, the entity.</p><p>This rule is based on the recognition that the automatic inclusion provided
1118by the SGML and XML entity mechanism, primarily designed to support modularity
1119in authoring, is not necessarily appropriate for other applications, in particular
1120document browsing. Browsers, for example, when encountering an external parsed
1121entity reference, might choose to provide a visual indication of the entity's
1122presence and retrieve it for display only on demand.</p></div><div class="div3"> <h4><a name="forbidden" id="forbidden" />4.4.4 Forbidden</h4><p>The following are forbidden, and constitute <a title="Fatal Error" href="#dt-fatal">fatal
1123errors</a>:</p><ul><li><p>the appearance of a reference to an <a title="Unparsed Entity" href="#dt-unparsed">unparsed
1124entity</a><span>, except in the
1125<a href="#NT-EntityValue">EntityValue</a> in an entity declaration</span>.</p></li><li><p>the appearance of any character or general-entity reference in the
1126DTD except within an <a href="#NT-EntityValue">EntityValue</a> or <a href="#NT-AttValue">AttValue</a>.</p></li><li><p>a reference to an external entity in an attribute value.</p></li></ul></div><div class="div3"> <h4><a name="inliteral" id="inliteral" />4.4.5 Included in Literal</h4><p>When an <a title="Entity Reference" href="#dt-entref">entity reference</a> appears in
1127an attribute value, or a parameter entity reference appears in a literal entity
1128value, its <a title="Replacement Text" href="#dt-repltext">replacement text</a> <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be</span> processed
1129in place of the reference itself as though it were part of the document at
1130the location the reference was recognized, except that a single or double
1131quote character in the replacement text <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> always be</span> treated as a normal data
1132character and <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> terminate the literal. For example, this is well-formed:</p><div class="exampleInner"><pre>&lt;!ENTITY % YN '"Yes"' &gt;
1133&lt;!ENTITY WhatHeSaid "He said %YN;" &gt;</pre></div><p>while this is not:</p><div class="exampleInner"><pre>&lt;!ENTITY EndAttr "27'" &gt;
1134&lt;element attribute='a-&amp;EndAttr;&gt;</pre></div></div><div class="div3"> <h4><a name="notify" id="notify" />4.4.6 Notify</h4><p>When the name of an <a title="Unparsed Entity" href="#dt-unparsed">unparsed entity</a>
1135appears as a token in the value of an attribute of declared type <b>ENTITY</b>
1136or <b>ENTITIES</b>, a validating processor <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> inform the application of
1137the <a title="System Identifier" href="#dt-sysid">system</a> and <a title="Public identifier" href="#dt-pubid">public</a>
1138(if any) identifiers for both the entity and its associated <a title="Notation" href="#dt-notation">notation</a>.</p></div><div class="div3"> <h4><a name="bypass" id="bypass" />4.4.7 Bypassed</h4><p>When a general entity reference appears in the <a href="#NT-EntityValue">EntityValue</a>
1139in an entity declaration, it <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be</span> bypassed and left as is.</p></div><div class="div3"> <h4><a name="as-PE" id="as-PE" />4.4.8 Included as PE</h4><p>Just as with external parsed entities, parameter entities need only be <a href="#include-if-valid"><cite>included if validating</cite></a>. When a parameter-entity
1140reference is recognized in the DTD and included, its <a title="Replacement Text" href="#dt-repltext">replacement
1141text</a> <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be</span> enlarged by the attachment of one leading and one following
1142space (#x20) character; the intent is to constrain the replacement text of
1143parameter entities to contain an integral number of grammatical tokens in
1144the DTD. This
1145behavior <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> apply to parameter entity references within entity values;
1146these are described in <a href="#inliteral"><b>4.4.5 Included in Literal</b></a>.</p></div><div class="div3"> <h4><a name="error" id="error" />4.4.9 Error</h4><p>It is an <a title="Error" href="#dt-error">error</a> for a reference to
1147an unparsed entity to appear in the <a href="#NT-EntityValue">EntityValue</a> in an
1148entity declaration.</p></div></div><div class="div2"> <h3><a name="intern-replacement" id="intern-replacement" />4.5 Construction of Entity Replacement Text</h3><p>In discussing the treatment of entities, it is useful to distinguish
1149two forms of the entity's value.
1150[<a name="dt-litentval" id="dt-litentval" title="Literal Entity Value">Definition</a>: <span>For an
1151internal entity, </span>the <b>literal
1152entity value</b> is the quoted string actually present in the entity declaration,
1153corresponding to the non-terminal <a href="#NT-EntityValue">EntityValue</a>.] [<a name="dt-extlitentval" id="dt-extlitentval" title="Literal Entity Value">Definition</a>: For an external entity, the <b>literal
1154entity value</b> is the exact text contained in the entity.] [<a name="dt-repltext" id="dt-repltext" title="Replacement Text">Definition</a>: <span>For an
1155internal entity, </span>the <b>replacement text</b>
1156is the content of the entity, after replacement of character references and
1157parameter-entity references.] [<a name="dt-extrepltext" id="dt-extrepltext" title="Replacement Text">Definition</a>: For
1158an external entity, the <b>replacement text</b> is the content of the entity,
1159after stripping the text declaration (leaving any surrounding white space) if there
1160is one but without any replacement of character references or parameter-entity
1161references.]</p><p>The literal entity value as given in an internal entity declaration (<a href="#NT-EntityValue">EntityValue</a>) <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> contain character, parameter-entity,
1162and general-entity references. Such references <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be contained entirely
1163within the literal entity value. The actual replacement text that is <a title="Include" href="#dt-include">included</a><span> (or <a title="" href="#inliteral">included in literal</a>)</span> as described above
1164<em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> contain the <em>replacement
1165text</em> of any parameter entities referred to, and <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> contain the character
1166referred to, in place of any character references in the literal entity value;
1167however, general-entity references <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be left as-is, unexpanded. For example,
1168given the following declarations:</p><div class="exampleInner"><pre>&lt;!ENTITY % pub "&amp;#xc9;ditions Gallimard" &gt;
1169&lt;!ENTITY rights "All rights reserved" &gt;
1170&lt;!ENTITY book "La Peste: Albert Camus,
1171&amp;#xA9; 1947 %pub;. &amp;rights;" &gt;</pre></div><p>then the replacement text for the entity "<code>book</code>"
1172is:</p><div class="exampleInner"><pre>La Peste: Albert Camus,
1173© 1947 Éditions Gallimard. &amp;rights;</pre></div><p>The general-entity reference "<code>&amp;rights;</code>" would
1174be expanded should the reference "<code>&amp;book;</code>" appear
1175in the document's content or an attribute value.</p><p>These simple rules may have complex interactions; for a detailed discussion
1176of a difficult example, see <a href="#sec-entexpand"><b>C Expansion of Entity and Character References</b></a>.</p></div><div class="div2"> <h3><a name="sec-predefined-ent" id="sec-predefined-ent" />4.6 Predefined Entities</h3><p>[<a name="dt-escape" id="dt-escape" title="escape">Definition</a>: Entity and character references <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>
1177both be used to <b>escape</b> the left angle bracket, ampersand, and
1178other delimiters. A set of general entities (<code>amp</code>,
1179<code>lt</code>,
1180<code>gt</code>,
1181<code>apos</code>,
1182<code>quot</code>) is specified for
1183this purpose. Numeric character references <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> also be used; they are expanded
1184immediately when recognized and <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be treated as character data, so the
1185numeric character references "<code>&amp;#60;</code>" and "<code>&amp;#38;</code>" <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be used to escape <code>&lt;</code> and <code>&amp;</code> when they occur
1186in character data.]</p><p>All XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> recognize these entities whether they are declared
1187or not. <a title="For interoperability" href="#dt-interop">For interoperability</a>, valid XML
1188documents <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> declare these entities, like any others, before using them. If
1189the entities <code>lt</code> or <code>amp</code> are declared, they <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be
1190declared as internal entities whose replacement text is a character reference
1191to the respective
1192character (less-than sign or ampersand) being escaped; the double
1193escaping is <em class="rfc2119" title="Keyword in RFC 2119 context">REQUIRED</em> for these entities so that references to them produce
1194a well-formed result. If the entities <code>gt</code>, <code>apos</code>,
1195or <code>quot</code> are declared, they <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be declared as internal entities
1196whose replacement text is the single character being escaped (or a character
1197reference to that character; the double escaping here is <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">OPTIONAL</em></span> but harmless).
1198For example:</p><div class="exampleInner"><pre>&lt;!ENTITY lt "&amp;#38;#60;"&gt;
1199&lt;!ENTITY gt "&amp;#62;"&gt;
1200&lt;!ENTITY amp "&amp;#38;#38;"&gt;
1201&lt;!ENTITY apos "&amp;#39;"&gt;
1202&lt;!ENTITY quot "&amp;#34;"&gt;</pre></div></div><div class="div2"> <h3><a name="Notations" id="Notations" />4.7 Notation Declarations</h3><p>[<a name="dt-notation" id="dt-notation" title="Notation">Definition</a>: <b>Notations</b> identify
1203by name the format of <a title="External Entity" href="#dt-extent">unparsed entities</a>,
1204the format of elements which bear a notation attribute, or the application
1205to which a <a title="Processing instruction" href="#dt-pi">processing instruction</a> is addressed.]</p><p>[<a name="dt-notdecl" id="dt-notdecl" title="Notation Declaration">Definition</a>: <b>Notation declarations</b>
1206provide a name for the notation, for use in entity and attribute-list declarations
1207and in attribute specifications, and an external identifier for the notation
1208which may allow an XML processor or its client application to locate a helper
1209application capable of processing data in the given notation.]</p> <h5><a name="IDAYTFU" id="IDAYTFU" />Notation Declarations</h5><table class="scrap" summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-NotationDecl" id="NT-NotationDecl" />[82]   </td><td><code>NotationDecl</code></td><td>   ::=   </td><td><code>'&lt;!NOTATION' <a href="#NT-S">S</a> <a href="#NT-Name">Name</a> <a href="#NT-S">S</a> (<a href="#NT-ExternalID">ExternalID</a> | <a href="#NT-PublicID">PublicID</a>) <a href="#NT-S">S</a>? '&gt;'</code></td><td><a href="#UniqueNotationName">[VC: Unique Notation Name]</a></td></tr></tbody><tbody><tr valign="baseline"><td><a name="NT-PublicID" id="NT-PublicID" />[83]   </td><td><code>PublicID</code></td><td>   ::=   </td><td><code>'PUBLIC' <a href="#NT-S">S</a> <a href="#NT-PubidLiteral">PubidLiteral</a></code></td></tr></tbody></table><div class="constraint"><p class="prefix"><a name="UniqueNotationName" id="UniqueNotationName" /><b>Validity constraint: Unique Notation Name</b></p><p><span class="mustard">A given <a href="#NT-Name">Name</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> be declared in more than one notation declaration.</span></p></div><p>XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> provide applications with the name and external identifier(s)
1210of any notation declared and referred to in an attribute value, attribute
1211definition, or entity declaration. They <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> additionally resolve the external
1212identifier into the <a title="System Identifier" href="#dt-sysid">system identifier</a>, file
1213name, or other information needed to allow the application to call a processor
1214for data in the notation described. (It is not an error, however, for XML
1215documents to declare and refer to notations for which notation-specific applications
1216are not available on the system where the XML processor or application is
1217running.)</p></div><div class="div2"> <h3><a name="sec-doc-entity" id="sec-doc-entity" />4.8 Document Entity</h3><p>[<a name="dt-docent" id="dt-docent" title="Document Entity">Definition</a>: The <b>document entity</b>
1218serves as the root of the entity tree and a starting-point for an <a title="XML Processor" href="#dt-xml-proc">XML processor</a>.] This specification does
1219not specify how the document entity is to be located by an XML processor;
1220unlike other entities, the document entity has no name and might well appear
1221on a processor input stream without any identification at all.</p></div></div><div class="div1"> <h2><a name="sec-conformance" id="sec-conformance" />5 Conformance</h2><div class="div2"> <h3><a name="proc-types" id="proc-types" />5.1 Validating and Non-Validating Processors</h3><p>Conforming <a title="XML Processor" href="#dt-xml-proc">XML processors</a> fall into
1222two classes: validating and non-validating.</p><p>Validating and non-validating processors alike <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> report violations of
1223this specification's well-formedness constraints in the content of the <a title="Document Entity" href="#dt-docent">document entity</a> and any other <a title="Text Entity" href="#dt-parsedent">parsed
1224entities</a> that they read.</p><p>[<a name="dt-validating" id="dt-validating" title="Validating Processor">Definition</a>: <b>Validating
1225processors</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>,
1226at user option, report violations of the constraints expressed by
1227the declarations in the <a title="Document Type Declaration" href="#dt-doctype">DTD</a>, and failures
1228to fulfill the validity constraints given in this specification.]
1229To accomplish this, validating XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> read and process the entire
1230DTD and all external parsed entities referenced in the document.</p><p>Non-validating processors are <em class="rfc2119" title="Keyword in RFC 2119 context">REQUIRED</em> to check only the <a title="Document Entity" href="#dt-docent">document
1231entity</a>, including the entire internal DTD subset, for well-formedness. [<a name="dt-use-mdecl" id="dt-use-mdecl" title="Process Declarations">Definition</a>: While they are not required
1232to check the document for validity, they are <em class="rfc2119" title="Keyword in RFC 2119 context">REQUIRED</em> to <b>process</b>
1233all the declarations they read in the internal DTD subset and in any parameter
1234entity that they read, up to the first reference to a parameter entity that
1235they do <em>not</em> read; that is to say, they <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> use the information
1236in those declarations to <a href="#AVNormalize"><cite>normalize</cite></a>
1237attribute values, <a href="#included"><cite>include</cite></a> the replacement
1238text of internal entities, and supply <a href="#sec-attr-defaults"><cite>default
1239attribute values</cite></a>.] Except when <code>standalone="yes"</code>, they
1240<em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> <a title="Process Declarations" href="#dt-use-mdecl">process</a> <a title="entity declaration" href="#dt-entdecl">entity
1241declarations</a> or <a title="Attribute-List Declaration" href="#dt-attdecl">attribute-list declarations</a>
1242encountered after a reference to a parameter entity that is not read, since
1243the entity may have contained overriding declarations<span>; when <code>standalone="yes"</code>, processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>
1244process these declarations</span>.</p><p>Note
1245that when processing invalid documents with a non-validating
1246processor the application may not be presented with consistent
1247information. For example, several requirements for uniqueness
1248within the document may not be met, including more than one element
1249with the same id, duplicate declarations of elements or notations
1250with the same name, etc. In these cases the behavior of the parser
1251with respect to reporting such information to the application is
1252undefined.</p><p>XML 1.1 processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be able to process both XML 1.0
1253and XML 1.1 documents. Programs which generate XML <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em>
1254generate XML 1.0, unless one of the specific features of XML 1.1 is required.</p></div><div class="div2"> <h3><a name="safe-behavior" id="safe-behavior" />5.2 Using XML Processors</h3><p>The behavior of a validating XML processor is highly predictable; it must
1255read every piece of a document and report all well-formedness and validity
1256violations. Less is required of a non-validating processor; it need not read
1257any part of the document other than the document entity. This has two effects
1258that may be important to users of XML processors:</p><ul><li><p>Certain well-formedness errors, specifically those that require reading
1259external entities, <span>may fail to</span> be detected by a non-validating processor. Examples
1260include the constraints entitled <a href="#wf-entdeclared"><cite>Entity Declared</cite></a>, <a href="#textent"><cite>Parsed Entity</cite></a>, and <a href="#norecursion"><cite>No
1261Recursion</cite></a>, as well as some of the cases described as <a href="#forbidden"><cite>forbidden</cite></a> in <a href="#entproc"><b>4.4 XML Processor Treatment of Entities and References</b></a>.</p></li><li><p>The information passed from the processor to the application may
1262vary, depending on whether the processor reads parameter and external entities.
1263For example, a non-validating processor <span>may fail to</span> <a href="#AVNormalize"><cite>normalize</cite></a>
1264attribute values, <a href="#included"><cite>include</cite></a> the replacement
1265text of internal entities, or supply <a href="#sec-attr-defaults"><cite>default
1266attribute values</cite></a>, where doing so depends on having read declarations
1267in external or parameter entities.</p></li></ul><p>For maximum reliability in interoperating between different XML processors,
1268applications which use non-validating processors <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD NOT</em> rely on any behaviors
1269not required of such processors. Applications which require DTD facilities
1270not related to validation (such
1271as the declaration of default attributes and internal entities that are
1272or may be specified in
1273external entities <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> use validating XML processors.</p></div></div><div class="div1"> <h2><a name="sec-notation" id="sec-notation" />6 Notation</h2><p>The formal grammar of XML is given in this specification using a simple
1274Extended Backus-Naur Form (EBNF) notation. Each rule in the grammar defines
1275one symbol, in the form</p><div class="exampleInner"><pre>symbol ::= expression</pre></div><p>Symbols are written with an initial capital letter if they are the
1276start symbol of a regular language, otherwise with an initial lowercase
1277letter. Literal strings are quoted.</p><p>Within the expression on the right-hand side of a rule, the following expressions
1278are used to match strings of one or more characters: </p><dl><dt class="label"><code>#xN</code></dt><dd><p>where <code>N</code> is a hexadecimal integer, the expression matches the character
1279<span>whose</span><span> number
1280(code point) in</span> ISO/IEC 10646 <span>is <code>N</code></span>. The number of leading zeros in the <code>#xN</code>
1281form is insignificant.</p></dd><dt class="label"><code>[a-zA-Z]</code>, <code>[#xN-#xN]</code></dt><dd><p>matches any <a href="#NT-Char">Char</a> with a value in the range(s) indicated (inclusive).</p></dd><dt class="label"><code>[abc]</code>, <code>[#xN#xN#xN]</code></dt><dd><p>matches any <a href="#NT-Char">Char</a> with a value among the characters
1282enumerated. Enumerations and ranges can be mixed in one set of brackets.</p></dd><dt class="label"><code>[^a-z]</code>, <code>[^#xN-#xN]</code></dt><dd><p>matches any <a href="#NT-Char">Char</a> with a value <em>outside</em> the range
1283indicated.</p></dd><dt class="label"><code>[^abc]</code>, <code>[^#xN#xN#xN]</code></dt><dd><p>matches any <a href="#NT-Char">Char</a> with a value not among the characters given. Enumerations
1284and ranges of forbidden values can be mixed in one set of brackets.</p></dd><dt class="label"><code>"string"</code></dt><dd><p>matches a literal string <a title="match" href="#dt-match">matching</a> that
1285given inside the double quotes.</p></dd><dt class="label"><code>'string'</code></dt><dd><p>matches a literal string <a title="match" href="#dt-match">matching</a> that
1286given inside the single quotes.</p></dd></dl><p> These symbols may be combined to match more complex patterns as follows,
1287where <code>A</code> and <code>B</code> represent simple expressions: </p><dl><dt class="label">(<code>expression</code>)</dt><dd><p><code>expression</code> is treated as a unit and may be combined as described
1288in this list.</p></dd><dt class="label"><code>A?</code></dt><dd><p>matches <code>A</code> or nothing; optional <code>A</code>.</p></dd><dt class="label"><code>A B</code></dt><dd><p>matches <code>A</code> followed by <code>B</code>. This
1289operator has higher precedence than alternation; thus <code>A B | C D</code>
1290is identical to <code>(A B) | (C D)</code>.</p></dd><dt class="label"><code>A | B</code></dt><dd><p>matches <code>A</code> or <code>B</code>.</p></dd><dt class="label"><code>A - B</code></dt><dd><p>matches any string that matches <code>A</code> but does not match <code>B</code>.</p></dd><dt class="label"><code>A+</code></dt><dd><p>matches one or more occurrences of <code>A</code>. Concatenation
1291has higher precedence than alternation; thus <code>A+ | B+</code> is identical
1292to <code>(A+) | (B+)</code>.</p></dd><dt class="label"><code>A*</code></dt><dd><p>matches zero or more occurrences of <code>A</code>. Concatenation
1293has higher precedence than alternation; thus <code>A* | B*</code> is identical
1294to <code>(A*) | (B*)</code>.</p></dd></dl><p> Other notations used in the productions are: </p><dl><dt class="label"><code>/* ... */</code></dt><dd><p>comment.</p></dd><dt class="label"><code>[ wfc: ... ]</code></dt><dd><p>well-formedness constraint; this identifies by name a constraint on <a title="Well-Formed" href="#dt-wellformed">well-formed</a> documents associated with a production.</p></dd><dt class="label"><code>[ vc: ... ]</code></dt><dd><p>validity constraint; this identifies by name a constraint on <a title="Validity" href="#dt-valid">valid</a>
1295documents associated with a production.</p></dd></dl><p></p></div></div><div class="back"><div class="div1"> <h2><a name="sec-bibliography" id="sec-bibliography" />A References</h2><div class="div2"> <h3><a name="sec-existing-stds" id="sec-existing-stds" />A.1 Normative References</h3><dl><dt class="label"><a name="IANA" id="IANA" />IANA-CHARSETS</dt><dd>(Internet
1296Assigned Numbers Authority) <a href="http://www.iana.org/assignments/character-sets"><cite>Official Names for Character Sets</cite></a>,
1297ed. Keld Simonsen et al. (See http://www.iana.org/assignments/character-sets.)</dd><dt class="label"><a name="rfc2119" id="rfc2119" />IETF RFC 2119</dt><dd>IETF
1298(Internet Engineering Task Force). <a href="http://www.ietf.org/rfc/rfc2119.txt"><cite>RFC 2119: Key words for use in RFCs to Indicate Requirement Levels</cite></a>.
1299Scott Bradner, 1997. (See http://www.ietf.org/rfc/rfc2119.txt.)</dd><dt class="label"><a name="rfc2396" id="rfc2396" />IETF RFC 2396</dt><dd>IETF
1300(Internet Engineering Task Force). <a href="http://www.ietf.org/rfc/rfc2396.txt"><cite>RFC 2396: Uniform Resource Identifiers
1301(URI): Generic Syntax</cite></a>. T. Berners-Lee, R. Fielding, L. Masinter.
13021998. (See http://www.ietf.org/rfc/rfc2396.txt.)</dd><dt class="label"><a name="rfc2732" id="rfc2732" />IETF RFC 2732</dt><dd>IETF
1303(Internet Engineering Task Force). <a href="http://www.ietf.org/rfc/rfc2732.txt"><cite>RFC 2732: Format for Literal
1304IPv6 Addresses in URL's</cite></a>. R. Hinden, B. Carpenter, L. Masinter.
13051999. (See http://www.ietf.org/rfc/rfc2732.txt.)</dd><dt class="label"><a name="RFC1766" id="RFC1766" />IETF RFC 3066</dt><dd>IETF
1306(Internet Engineering Task Force). <a href="http://www.ietf.org/rfc/rfc3066.txt"><cite>RFC 3066: Tags for the Identification
1307of Languages</cite></a>, ed. H. Alvestrand. 2001. (See http://www.ietf.org/rfc/rfc3066.txt.)</dd><dt class="label"><a name="ISO10646" id="ISO10646" />ISO/IEC 10646</dt><dd><span>ISO (International
1308Organization for Standardization). <cite>ISO/IEC 10646-1:2000. Information
1309technology — Universal Multiple-Octet Coded Character Set (UCS) —
1310Part 1: Architecture and Basic Multilingual Plane</cite> and <cite>ISO/IEC 10646-2:2001.
1311Information technology — Universal Multiple-Octet Coded Character Set (UCS) — Part 2:
1312Supplementary Planes</cite>, as, from time to time, amended, replaced by a new edition or
1313expanded by the addition of new parts. [Geneva]: International Organization for Standardization.
1314(See <a href="http://www.iso.ch">http://www.iso.ch</a> for the latest version.)</span></dd><dt class="label"><a name="Unicode" id="Unicode" />Unicode</dt><dd>The Unicode Consortium. <em>The Unicode
1315Standard, Version 4.0.</em> Reading, Mass.: Addison-Wesley,
13162003,
1317as updated from time to time by the publication of new versions. (See
1318<a href="http://www.unicode.org/unicode/standard/versions">
1319http://www.unicode.org/unicode/standard/versions</a> for the latest version
1320and additional information on versions of the standard and of the Unicode
1321Character Database).</dd><dt class="label"><a name="XML1.0" />XML-1.0</dt><dd>W3C. <a href="http://www.w3.org/TR/REC-xml"><cite>Extensible Markup Language (XML) 1.0 (Third
1322Edition)</cite></a>. Tim Bray, Jean Paoli, C.M. Sperberg-McQueen, Eve Maler, François Yergeau
1323(editors) (See http://www.w3.org/TR/REC-xml.)</dd></dl></div><div class="div2"> <h3><a name="null" id="null" />A.2 Other References</h3><dl><dt class="label"><a name="Aho" id="Aho" />Aho/Ullman</dt><dd>Aho, Alfred V., Ravi Sethi, and Jeffrey D.
1324Ullman. <cite>Compilers: Principles, Techniques, and Tools</cite>.
1325Reading: Addison-Wesley, 1986, rpt. corr. 1988.</dd><dt class="label"><a name="ABK" id="ABK" />Brüggemann-Klein</dt><dd>Brüggemann-Klein,
1326Anne. <a href="ftp://ftp.informatik.uni-freiburg.de/documents/papers/brueggem/habil.ps"><cite>Formal Models in Document Processing</cite></a>. Habilitationsschrift. Faculty
1327of Mathematics at the University of Freiburg, 1993. (See ftp://ftp.informatik.uni-freiburg.de/documents/papers/brueggem/habil.ps.)</dd><dt class="label"><a name="ABKDW" id="ABKDW" />Brüggemann-Klein and Wood</dt><dd>Brüggemann-Klein,
1328Anne, and Derick Wood. <cite>Deterministic Regular Languages</cite>.
1329Universität Freiburg, Institut für Informatik, Bericht 38, Oktober 1991. Extended
1330abstract in A. Finkel, M. Jantzen, Hrsg., STACS 1992, S. 173-184. Springer-Verlag,
1331Berlin 1992. Lecture Notes in Computer Science 577. Full version titled <cite>One-Unambiguous
1332Regular Languages</cite> in Information and Computation 140 (2): 229-253,
1333February 1998.</dd><dt class="label"><a name="Charmod" />Charmod</dt><dd>W3C Working Draft.
1334
1335<a href="http://www.w3.org/TR/2003/WD-charmod-20030822/"><cite>Character Model for the World Wide Web 1.0</cite></a>.
1336
1337Martin J. Dürst, François Yergeau, Richard Ishida, Misha Wolf, Tex Texin. (See http://www.w3.org/TR/2003/WD-charmod-20030822/.)</dd><dt class="label"><a name="Clark" id="Clark" />Clark</dt><dd>James Clark.
1338<a href="http://www.w3.org/TR/NOTE-sgml-xml-971215"><cite>Comparison of SGML and XML</cite></a>. (See http://www.w3.org/TR/NOTE-sgml-xml-971215.)</dd><dt class="label"><a name="IANA-LANGCODES" id="IANA-LANGCODES" />IANA-LANGCODES</dt><dd>(Internet
1339Assigned Numbers Authority) <a href="http://www.iana.org/assignments/language-tags"><cite>Registry of Language Tags</cite></a>,
1340ed. Keld Simonsen et al. (See http://www.iana.org/assignments/language-tags.)</dd><dt class="label"><a name="RFC2141" id="RFC2141" />IETF RFC 2141</dt><dd>IETF
1341(Internet Engineering Task Force). <a href="http://www.ietf.org/rfc/rfc2141.txt"><cite>RFC 2141: URN Syntax</cite></a>, ed.
1342R. Moats. 1997. (See http://www.ietf.org/rfc/rfc2141.txt.)</dd><dt class="label"><a name="rfc2376" id="rfc2376" />IETF RFC 3023</dt><dd>IETF
1343(Internet Engineering Task Force). <a href="http://www.ietf.org/rfc/rfc3023.txt"><cite>RFC 3023: XML Media Types</cite></a>.
1344eds. M. Murata, S. St.Laurent, D. Kohn. 2001. (See http://www.ietf.org/rfc/rfc3023.txt.)</dd><dt class="label"><a name="rfc2781" id="rfc2781" />IETF RFC 2781</dt><dd>IETF
1345(Internet Engineering Task Force). <a href="http://www.ietf.org/rfc/rfc2781.txt"><cite>RFC 2781: UTF-16, an encoding
1346of ISO 10646</cite></a>, ed. P. Hoffman, F. Yergeau. 2000. (See http://www.ietf.org/rfc/rfc2781.txt.)</dd><dt class="label"><a name="ISO639" id="ISO639" />ISO 639</dt><dd>(International Organization for Standardization).
1347<cite>ISO 639:1988 (E).
1348Code for the representation of names of languages.</cite> [Geneva]: International
1349Organization for Standardization, 1988.</dd><dt class="label"><a name="ISO3166" id="ISO3166" />ISO 3166</dt><dd>(International Organization for Standardization).
1350<cite>ISO 3166-1:1997
1351(E). Codes for the representation of names of countries and their subdivisions —
1352Part 1: Country codes</cite> [Geneva]: International Organization for
1353Standardization, 1997.</dd><dt class="label"><a name="ISO8879" id="ISO8879" />ISO 8879</dt><dd>ISO (International Organization for Standardization). <cite>ISO
13548879:1986(E). Information processing — Text and Office Systems —
1355Standard Generalized Markup Language (SGML).</cite> First edition —
13561986-10-15. [Geneva]: International Organization for Standardization, 1986. </dd><dt class="label"><a name="ISO10744" id="ISO10744" />ISO/IEC 10744</dt><dd>ISO (International Organization for
1357Standardization). <cite>ISO/IEC 10744-1992 (E). Information technology —
1358Hypermedia/Time-based Structuring Language (HyTime). </cite> [Geneva]:
1359International Organization for Standardization, 1992. <em>Extended Facilities
1360Annexe.</em> [Geneva]: International Organization for Standardization, 1996. </dd><dt class="label"><a name="websgml" id="websgml" />WEBSGML</dt><dd>ISO
1361(International Organization for Standardization). <a href="http://www.sgmlsource.com/8879/n0029.htm"><cite>ISO 8879:1986
1362TC2. Information technology — Document Description and Processing Languages</cite></a>.
1363[Geneva]: International Organization for Standardization, 1998. (See http://www.sgmlsource.com/8879/n0029.htm.)</dd><dt class="label"><a name="xml-names" id="xml-names" />XML Names</dt><dd>Tim Bray,
1364Dave Hollander, and Andrew Layman, editors. <a href="http://www.w3.org/TR/REC-xml-names/"><cite>Namespaces in XML</cite></a>.
1365Textuality, Hewlett-Packard, and Microsoft. World Wide Web Consortium, 1999. (See http://www.w3.org/TR/REC-xml-names/.)</dd></dl></div></div><div class="div1"> <h2><a name="sec-CharNorm" id="sec-CharNorm" />B Definitions for Character Normalization</h2><p>This appendix contains the necessary definitions for character normalization.
1366For additional background information and examples, see <a href="#Charmod">[Charmod]</a>.</p><p>
1367[<a name="dt-Uni-encform" id="dt-Uni-encform" title="Unicode encoding form">Definition</a>: Text is said to be
1368in a <b>Unicode encoding form</b> if it is encoded in
1369UTF-8, UTF-16 or UTF-32.]</p><p>
1370[<a name="dt-legacyenc" id="dt-legacyenc" title="legacy encoding">Definition</a>: <b>Legacy encoding</b>
1371is taken to mean any character encoding not based on Unicode.]</p><p>
1372[<a name="dt-normtransc" id="dt-normtransc" title="normalizing transcoder">Definition</a>: A
1373<b>normalizing transcoder</b> is a transcoder that converts from a
1374<a title="legacy encoding" href="#dt-legacyenc">legacy encoding</a> to a
1375<a title="Unicode encoding form" href="#dt-Uni-encform">Unicode encoding form</a> and
1376ensures that the result is in Unicode Normalization Form C
1377(see UAX #15 <a href="#Unicode">[Unicode]</a>).]</p><p>[<a name="dt-charesc" id="dt-charesc" title="character escape">Definition</a>: A <b>character escape</b>
1378is a syntactic device defined in a markup or programming language that allows
1379one or more of:]</p><ol type="1"><li><p>expressing syntax-significant characters while disregarding
1380their significance in the syntax of the language, or</p></li><li><p>expressing characters not representable in the character encoding
1381chosen for an instance of the language, or</p></li><li><p>expressing characters in general, without use of the corresponding
1382character codes.</p></li></ol><p>
1383[<a name="dt-certified" id="dt-certified" title="certified">Definition</a>: <b>Certified</b> text
1384is text which satisfies at least one of the following conditions:]</p><ol type="1"><li><p>it has been confirmed through inspection that the text
1385is in normalized form</p></li><li><p>the source text-processing component is identified
1386and is known to produce only normalized text.</p></li></ol><p>
1387[<a name="dt-uninorm" id="dt-uninorm" title="Unicode-normalized">Definition</a>: Text is, for the purposes of
1388this specification, <b>Unicode-normalized</b> if it is in a
1389<a title="Unicode encoding form" href="#dt-Uni-encform">Unicode encoding form</a> and is in
1390Unicode Normalization Form C, according to a version of Unicode Standard Annex #15:
1391Unicode Normalization Forms <a href="#Unicode">[Unicode]</a> at least as recent as the
1392oldest version of the Unicode Standard that contains all the characters
1393actually present in the text, but no earlier
1394than version 3.2.]</p><p>
1395[<a name="dt-inclnorm" id="dt-inclnorm" title="include-normalized">Definition</a>: Text is
1396<b>include-normalized</b> if:]</p><ol type="1"><li><p>the text is <a title="Unicode-normalized" href="#dt-uninorm">Unicode-normalized</a>
1397and does not contain any <a title="character escape" href="#dt-charesc">character escapes</a>
1398or <a title="Include" href="#dt-include">includes</a> whose expansion would
1399cause the text to become no longer <a title="Unicode-normalized" href="#dt-uninorm">Unicode-normalized</a>;
1400or</p></li><li><p>the text is in a <a title="legacy encoding" href="#dt-legacyenc">legacy encoding</a> and, if it were transcoded
1401to a <a title="Unicode encoding form" href="#dt-Uni-encform">Unicode encoding form</a> by a
1402<a title="normalizing transcoder" href="#dt-normtransc">normalizing transcoder</a>, the resulting
1403text would satisfy clause 1 above.</p></li></ol><p>
1404[<a name="dt-compchar" id="dt-compchar" title="composing character">Definition</a>: A <b>composing character</b>
1405is a character that is one or both of the following:]</p><ol type="1"><li><p>the second character in the canonical decomposition mapping of
1406some primary composite (as defined in D3 of UAX #15 <a href="#Unicode">[Unicode]</a>), or</p></li><li><p>of non-zero canonical combining class (as defined in Unicode
1407<a href="#Unicode">[Unicode]</a>).</p></li></ol><p>
1408[<a name="dt-fullnorm" id="dt-fullnorm" title="fully normalized">Definition</a>: Text is
1409<b>fully-normalized</b> if:]</p><ol type="1"><li><p>the text is in a <a title="Unicode encoding form" href="#dt-Uni-encform">Unicode encoding
1410form</a>, is <a title="include-normalized" href="#dt-inclnorm">include-normalized</a> and
1411none of the <a title="" href="#dt-relconst"><span>relevant</span>
1412constructs</a> comprising the text begin with a
1413<a title="composing character" href="#dt-compchar">composing character</a> or a
1414character escape representing a
1415<a title="composing character" href="#dt-compchar">composing character</a>; or</p></li><li><p>the text is in a <a title="legacy encoding" href="#dt-legacyenc">legacy encoding</a> and,
1416if it were transcoded to a <a title="Unicode encoding form" href="#dt-Uni-encform">Unicode encoding form</a>
1417by a <a title="normalizing transcoder" href="#dt-normtransc">normalizing transcoder</a>, the resulting text
1418would satisfy clause 1 above.</p></li></ol></div><div class="div1"> <h2><a name="sec-entexpand" id="sec-entexpand" />C Expansion of Entity and Character References (Non-Normative)</h2><p>This appendix contains some examples illustrating the sequence of entity-
1419and character-reference recognition and expansion, as specified in <a href="#entproc"><b>4.4 XML Processor Treatment of Entities and References</b></a>.</p><p>If the DTD contains the declaration</p><div class="exampleInner"><pre>&lt;!ENTITY example "&lt;p&gt;An ampersand (&amp;#38;#38;) may be escaped
1420numerically (&amp;#38;#38;#38;) or with a general entity
1421(&amp;amp;amp;).&lt;/p&gt;" &gt;</pre></div><p>then the XML processor will recognize the character references when it
1422parses the entity declaration, and resolve them before storing the following
1423string as the value of the entity "<code>example</code>":</p><div class="exampleInner"><pre>&lt;p&gt;An ampersand (&amp;#38;) may be escaped
1424numerically (&amp;#38;#38;) or with a general entity
1425(&amp;amp;amp;).&lt;/p&gt;</pre></div><p>A reference in the document to "<code>&amp;example;</code>"
1426will cause the text to be reparsed, at which time the start- and end-tags
1427of the <code>p</code> element will be recognized and the three references will
1428be recognized and expanded, resulting in a <code>p</code> element with the following
1429content (all data, no delimiters or markup):</p><div class="exampleInner"><pre>An ampersand (&amp;) may be escaped
1430numerically (&amp;#38;) or with a general entity
1431(&amp;amp;).</pre></div><p>A more complex example will illustrate the rules and their effects fully.
1432In the following example, the line numbers are solely for reference.</p><div class="exampleInner"><pre>1 &lt;?xml version='1.0'?&gt;
14332 &lt;!DOCTYPE test [
14343 &lt;!ELEMENT test (#PCDATA) &gt;
14354 &lt;!ENTITY % xx '&amp;#37;zz;'&gt;
14365 &lt;!ENTITY % zz '&amp;#60;!ENTITY tricky "error-prone" &gt;' &gt;
14376 %xx;
14387 ]&gt;
14398 &lt;test&gt;This sample shows a &amp;tricky; method.&lt;/test&gt;</pre></div><p>This produces the following:</p><ul><li><p>in line 4, the reference to character 37 is expanded immediately,
1440and the parameter entity "<code>xx</code>" is stored in the symbol
1441table with the value "<code>%zz;</code>". Since the replacement
1442text is not rescanned, the reference to parameter entity "<code>zz</code>"
1443is not recognized. (And it would be an error if it were, since "<code>zz</code>"
1444is not yet declared.)</p></li><li><p>in line 5, the character reference "<code>&amp;#60;</code>"
1445is expanded immediately and the parameter entity "<code>zz</code>"
1446is stored with the replacement text "<code>&lt;!ENTITY tricky "error-prone"
1447&gt;</code>", which is a well-formed entity declaration.</p></li><li><p>in line 6, the reference to "<code>xx</code>" is recognized,
1448and the replacement text of "<code>xx</code>" (namely "<code>%zz;</code>")
1449is parsed. The reference to "<code>zz</code>" is recognized in
1450its turn, and its replacement text ("<code>&lt;!ENTITY tricky "error-prone"
1451&gt;</code>") is parsed. The general entity "<code>tricky</code>"
1452has now been declared, with the replacement text "<code>error-prone</code>".</p></li><li><p>in line 8, the reference to the general entity "<code>tricky</code>"
1453is recognized, and it is expanded, so the full content of the <code>test</code>
1454element is the self-describing (and ungrammatical) string <em>This sample
1455shows a error-prone method.</em></p></li></ul></div><div class="div1"> <h2><a name="determinism" id="determinism" />D Deterministic Content Models (Non-Normative)</h2><p>As
1456noted in <a href="#sec-element-content"><b>3.2.1 Element Content</b></a>, it is required that content
1457models in element type declarations be deterministic. This requirement is <a title="For Compatibility" href="#dt-compat">for compatibility</a> with SGML (which calls deterministic
1458content models "unambiguous"); XML processors built
1459using SGML systems may flag non-deterministic content models as errors.</p><p>For example, the content model <code>((b, c) | (b, d))</code> is non-deterministic,
1460because given an initial <code>b</code> the XML processor
1461cannot know which <code>b</code> in the model is being matched without looking
1462ahead to see which element follows the <code>b</code>. In this case, the two references
1463to <code>b</code> can be collapsed into a single reference, making the model read <code>(b,
1464(c | d))</code>. An initial <code>b</code> now clearly matches only a single name
1465in the content model. The processor doesn't need to look ahead to see what follows; either <code>c</code> or <code>d</code>
1466would be accepted.</p><p>More formally: a finite state automaton may be constructed from the content
1467model using the standard algorithms, e.g. algorithm 3.5 in section 3.9 of
1468Aho, Sethi, and Ullman <a href="#Aho">[Aho/Ullman]</a>. In many such algorithms, a follow
1469set is constructed for each position in the regular expression (i.e., each
1470leaf node in the syntax tree for the regular expression); if any position
1471has a follow set in which more than one following position is labeled with
1472the same element type name, then the content model is in error and may be
1473reported as an error.</p><p>Algorithms exist which allow many but not all non-deterministic content
1474models to be reduced automatically to equivalent deterministic models; see
1475Brüggemann-Klein 1991 <a href="#ABK">[Brüggemann-Klein]</a>.</p></div><div class="div1"> <h2><a name="sec-guessing" id="sec-guessing" />E Autodetection of Character Encodings (Non-Normative)</h2><p>The XML encoding declaration functions as an internal label on each entity,
1476indicating which character encoding is in use. Before an XML processor can
1477read the internal label, however, it apparently has to know what character
1478encoding is in use — which is what the internal label is trying to indicate.
1479In the general case, this is a hopeless situation. It is not entirely hopeless
1480in XML, however, because XML limits the general case in two ways: each implementation
1481is assumed to support only a finite set of character encodings, and the XML
1482encoding declaration is restricted in position and content in order to make
1483it feasible to autodetect the character encoding in use in each entity in
1484normal cases. Also, in many cases other sources of information are available
1485in addition to the XML data stream itself. Two cases may be distinguished,
1486depending on whether the XML entity is presented to the processor without,
1487or with, any accompanying (external) information. We consider the first case
1488first.</p><div class="div2"> <h3><a name="sec-guessing-no-ext-info" id="sec-guessing-no-ext-info" />E.1 Detection Without External Encoding Information</h3><p>Because each XML entity not accompanied by external
1489encoding information and not in UTF-8 or UTF-16 encoding must
1490begin with an XML encoding declaration, in which the first characters must
1491be '<code>&lt;?xml</code>', any conforming processor can detect, after two
1492to four octets of input, which of the following cases apply. In reading this
1493list, it may help to know that in UCS-4, '&lt;' is "<code>#x0000003C</code>"
1494and '?' is "<code>#x0000003F</code>", and the Byte Order Mark
1495required of UTF-16 data streams is "<code>#xFEFF</code>". The notation
1496<var>##</var> is used to denote any byte value except that two consecutive
1497<var>##</var>s cannot be both 00.</p><p>With a Byte Order Mark:</p><table border="1" frame="border" summary="Encoding detection summary"><tbody><tr><td rowspan="1" colspan="1"><code>00 00 FE
1498FF</code></td><td rowspan="1" colspan="1">UCS-4, big-endian machine (1234 order)</td></tr><tr><td rowspan="1" colspan="1"><code>FF
1499FE 00 00</code></td><td rowspan="1" colspan="1">UCS-4, little-endian machine (4321 order)</td></tr><tr><td rowspan="1" colspan="1"><code>00 00 FF FE</code></td><td rowspan="1" colspan="1">UCS-4, unusual octet order (2143)</td></tr><tr><td rowspan="1" colspan="1"><code>FE FF 00 00</code></td><td rowspan="1" colspan="1">UCS-4, unusual octet order (3412)</td></tr><tr><td rowspan="1" colspan="1"><code>FE FF ## ##</code></td><td rowspan="1" colspan="1">UTF-16, big-endian</td></tr><tr><td rowspan="1" colspan="1"><code>FF FE ## ##</code></td><td rowspan="1" colspan="1">UTF-16, little-endian</td></tr><tr><td rowspan="1" colspan="1"><code>EF BB BF</code></td><td rowspan="1" colspan="1">UTF-8</td></tr></tbody></table><p>Without a Byte Order Mark:</p><table border="1" frame="border" summary="Encoding detection summary"><tbody><tr><td rowspan="1" colspan="1"><code>00 00 00 3C</code></td><td rowspan="4" colspan="1">UCS-4 or other encoding with a 32-bit code unit and ASCII
1500characters encoded as ASCII values, in respectively big-endian (1234), little-endian
1501(4321) and two unusual byte orders (2143 and 3412). The encoding declaration
1502must be read to determine which of UCS-4 or other supported 32-bit encodings
1503applies.</td></tr><tr><td rowspan="1" colspan="1"><code>3C 00 00 00</code></td></tr><tr><td rowspan="1" colspan="1"><code>00 00 3C 00</code></td></tr><tr><td rowspan="1" colspan="1"><code>00 3C 00 00</code></td></tr><tr><td rowspan="1" colspan="1"><code>00 3C 00 3F</code></td><td rowspan="1" colspan="1">UTF-16BE or big-endian ISO-10646-UCS-2
1504or other encoding with a 16-bit code unit in big-endian order and ASCII characters
1505encoded as ASCII values (the encoding declaration must be read to determine
1506which)</td></tr><tr><td rowspan="1" colspan="1"><code>3C 00 3F 00</code></td><td rowspan="1" colspan="1">UTF-16LE or little-endian
1507ISO-10646-UCS-2 or other encoding with a 16-bit code unit in little-endian
1508order and ASCII characters encoded as ASCII values (the encoding declaration
1509must be read to determine which)</td></tr><tr><td rowspan="1" colspan="1"><code>3C 3F 78 6D</code></td><td rowspan="1" colspan="1">UTF-8, ISO 646, ASCII, some part of ISO 8859, Shift-JIS, EUC, or any other
15107-bit, 8-bit, or mixed-width encoding which ensures that the characters of
1511ASCII have their normal positions, width, and values; the actual encoding
1512declaration must be read to detect which of these applies, but since all of
1513these encodings use the same bit patterns for the relevant ASCII characters,
1514the encoding declaration itself may be read reliably</td></tr><tr><td rowspan="1" colspan="1"><code>4C
15156F A7 94</code></td><td rowspan="1" colspan="1">EBCDIC (in some flavor; the full encoding declaration
1516must be read to tell which code page is in use)</td></tr><tr><td rowspan="1" colspan="1">Other</td><td rowspan="1" colspan="1">UTF-8 without an encoding declaration, or else the data stream is mislabeled
1517(lacking a required encoding declaration), corrupt, fragmentary, or enclosed
1518in a wrapper of some kind</td></tr></tbody></table><div class="note"><p class="prefix"><b>Note:</b></p><p>In cases above which do not require reading the encoding declaration to
1519determine the encoding, section 4.3.3 still requires that the encoding declaration,
1520if present, be read and that the encoding name be checked to match the actual
1521encoding of the entity. Also, it is possible that new character encodings
1522will be invented that will make it necessary to use the encoding declaration
1523to determine the encoding, in cases where this is not required at present.</p></div><p>This level of autodetection is enough to read the XML encoding declaration
1524and parse the character-encoding identifier, which is still necessary to distinguish
1525the individual members of each family of encodings (e.g. to tell UTF-8 from
15268859, and the parts of 8859 from each other, or to distinguish the specific
1527EBCDIC code page in use, and so on).</p><p>Because the contents of the encoding declaration are restricted to characters
1528from the ASCII repertoire (however encoded),
1529a processor can reliably read the entire encoding declaration as soon as it
1530has detected which family of encodings is in use. Since in practice, all widely
1531used character encodings fall into one of the categories above, the XML encoding
1532declaration allows reasonably reliable in-band labeling of character encodings,
1533even when external sources of information at the operating-system or transport-protocol
1534level are unreliable. Character encodings such as UTF-7
1535that make overloaded usage of ASCII-valued bytes may fail to be reliably detected.</p><p>Once the processor has detected the character encoding in use, it can act
1536appropriately, whether by invoking a separate input routine for each case,
1537or by calling the proper conversion function on each character of input.</p><p>Like any self-labeling system, the XML encoding declaration will not work
1538if any software changes the entity's character set or encoding without updating
1539the encoding declaration. Implementors of character-encoding routines should
1540be careful to ensure the accuracy of the internal and external information
1541used to label the entity.</p></div><div class="div2"> <h3><a name="sec-guessing-with-ext-info" id="sec-guessing-with-ext-info" />E.2 Priorities in the Presence of External Encoding Information</h3><p>The second possible case occurs when the XML entity is accompanied by encoding
1542information, as in some file systems and some network protocols. When multiple
1543sources of information are available, their relative priority and the preferred
1544method of handling conflict should be specified as part of the higher-level
1545protocol used to deliver XML. In particular, please refer
1546to <a href="#rfc2376">[IETF RFC 3023]</a> or its successor, which defines the <code>text/xml</code>
1547and <code>application/xml</code> MIME types and provides some useful guidance.
1548In the interests of interoperability, however, the following rule is recommended.</p><ul><li><p>If an XML entity is in a file, the Byte-Order Mark and encoding declaration are used
1549(if present) to determine the character encoding.</p></li></ul></div></div><div class="div1"> <h2><a name="sec-xml-wg" id="sec-xml-wg" />F W3C XML Working Group (Non-Normative)</h2><p>This specification was prepared and approved for publication by the W3C
1550XML Working Group (WG). WG approval of this specification does not necessarily
1551imply that all WG participants voted for its approval. The current and former members
1552in the XML WG are:</p><ul><li>Jon Bosak, Sun (<i>Chair</i>) </li><li>James Clark (<i>Technical Lead</i>) </li><li>Tim Bray, Textuality and Netscape (<i>XML Co-editor</i>) </li><li>Jean Paoli, Microsoft (<i>XML
1553Co-editor</i>) </li><li>C. M. Sperberg-McQueen, U. of Ill. (<i>XML Co-editor</i>) </li><li>Dan Connolly, W3C (<i>W3C Liaison</i>) </li><li>Paula Angerstein, Texcel</li><li>Steve DeRose, INSO</li><li>Dave Hollander, HP</li><li>Eliot Kimber, ISOGEN</li><li>Eve Maler, ArborText</li><li>Tom Magliery, NCSA</li><li>Murray Maloney, SoftQuad, Grif
1554SA, Muzmo and Veo Systems</li><li>MURATA Makoto (FAMILY Given), Fuji
1555Xerox Information Systems</li><li>Joel Nava, Adobe</li><li>Conleth O'Connell, Vignette</li><li>Peter Sharpe, SoftQuad</li><li>John Tigue, DataChannel</li></ul></div><div class="div1"> <h2><a name="sec-core-wg" id="sec-core-wg" />G W3C XML Core <span>Working</span> Group (Non-Normative)</h2><p>The present edition of this specification was prepared by the W3C XML Core
1556Working Group (WG). The participants in the WG at the time of publication of this
1557edition were:</p><ul><li>Leonid Arbouzov, Sun Microsystems</li><li>Mary Brady</li><li>John Cowan (<i>XML 1.1 First Edition Editor</i>) </li><li>John Evdemon, Microsoft</li><li>Andrew Fang, Arbortext</li><li>Paul Grosso, Arbortext (<i>Co-Chair</i>) </li><li>Arnaud Le Hors, IBM</li><li>Dmitry Lenkov, Oracle</li><li>Anjana Manian, Oracle</li><li>Glenn Marcy, IBM</li><li>Jonathan Marsh, Microsoft</li><li>Sandra Martinez, NIST</li><li>Liam Quin, W3C (<i>Staff Contact</i>) </li><li>Lew Shannon</li><li>Richard Tobin, University of Edinburgh</li><li>Daniel Veillard</li><li>Norman Walsh, Sun Microsystems (<i>Co-Chair</i>) </li><li>François Yergeau</li></ul></div><div class="div1"> <h2><a name="prod-notes" id="prod-notes" />H Production Notes (Non-Normative)</h2><p>This edition was encoded in a
1558slightly modified version of the
1559<a href="http://www.w3.org/2002/xmlspec/dtd/2.5/xmlspec.dtd">XMLspec DTD, 2.5</a>.
1560The XHTML versions were produced with a combination of the
1561<a href="http://www.w3.org/2002/xmlspec/xhtml/1.9/xmlspec.xsl">xmlspec.xsl</a>,
1562<a href="http://www.w3.org/2002/xmlspec/xhtml/1.9/diffspec.xsl">diffspec.xsl</a>,
1563and <a href="REC-xml-3e.xsl">REC-xml-3e.xsl</a>
1564XSLT stylesheets.</p></div><div class="div1"> <h2><a name="sec-suggested-names" id="sec-suggested-names" />I Suggestions for XML Names (Non-Normative)</h2><p>The following suggestions define what is believed to be best
1565practice in the construction of XML names used as element names,
1566attribute names, processing instruction targets, entity names,
1567notation names, and the values of attributes of type ID, and are
1568intended as guidance for document authors and schema designers.
1569All references to Unicode are understood with respect to
1570a particular version of the Unicode Standard greater than or equal
1571to 3.0; which version should be used is left to the discretion of
1572the document author or schema designer.</p><p>The first two suggestions are directly derived from the rules
1573given for identifiers in the Unicode Standard, version 3.0, and
1574exclude all control characters, enclosing nonspacing marks,
1575non-decimal numbers, private-use characters, punctuation characters
1576(with the noted exceptions), symbol characters, unassigned
1577codepoints, and white space characters. The other suggestions
1578are mostly derived from <a href="#XML1.0">[XML-1.0]</a> Appendix B.</p><ol type="1"><li><p>The first character of any name should have a Unicode General
1579Category of Ll, Lu, Lo, Lm, Lt, or Nl, or else be '_' #x5F.</p></li><li><p>Characters other than the first should have a Unicode General
1580Category of Ll, Lu, Lo, Lm, Lt, Mc, Mn, Nl, Nd, Pc, or Cf, or else
1581be one of the following: '-' #x2D, '.' #x2E, ':' #x3A or
1582'·' #xB7 (middle dot). Since Cf characters are not
1583directly visible, they should be employed with caution and only
1584when necessary, to avoid creating names which are distinct to XML
1585processors but look the same to human beings.</p></li><li><p>Ideographic characters which have a canonical decomposition
1586(including those in the ranges [#xF900-#xFAFF] and
1587[#x2F800-#x2FFFD], with 12 exceptions) should not be used in names.
1588</p></li><li><p>Characters which have a compatibility decomposition (those with
1589a "compatibility formatting tag" in field 5 of the Unicode
1590Character Database -- marked by field 5 beginning with a "&lt;")
1591should not be used in names. This suggestion does not apply
1592to #x0E33 THAI CHARACTER SARA AM or #x0EB3 LAO CHARACTER AM, which
1593despite their compatibility decompositions are in regular use in
1594those scripts.</p></li><li><p>Combining characters meant for use with symbols only (including
1595those in the ranges [#x20D0-#x20EF] and [#x1D165-#x1D1AD]) should
1596not be used in names.</p></li><li><p>The interlinear annotation characters ([#xFFF9-#xFFFB) should
1597not be used in names.</p></li><li><p>Variation selector characters should not be used in names.</p></li><li><p>Names which are nonsensical, unpronounceable, hard to read, or
1598easily confusable with other names should not be employed.</p></li></ol></div></div></body></html>
diff --git a/mkincs.sh b/mkincs.sh
new file mode 100755
index 0000000..6f72f89
--- /dev/null
+++ b/mkincs.sh
@@ -0,0 +1,5 @@
1#!/bin/bash
2
3cd src/bu
4rm *
5for i in ../*.h; do ln -s $i; done
diff --git a/src/archival.cpp b/src/archival.cpp
new file mode 100644
index 0000000..79c28f1
--- /dev/null
+++ b/src/archival.cpp
@@ -0,0 +1,10 @@
1#include "archival.h"
2
3Bu::Archival::Archival()
4{
5}
6
7Bu::Archival::~Archival()
8{
9}
10
diff --git a/src/archival.h b/src/archival.h
new file mode 100644
index 0000000..8be3308
--- /dev/null
+++ b/src/archival.h
@@ -0,0 +1,38 @@
1#ifndef BU_ARCHIVAL_H
2#define BU_ARCHIVAL_H
3
4namespace Bu
5{
6 /**
7 * The base class for any class you want to archive. Simply include this as
8 * a base class, implement the purely virtual archive function and you've
9 * got an easily archiveable class.
10 *
11 * Archival: "of or pertaining to archives or valuable records; contained
12 * in or comprising such archives or records."
13 */
14 class Archival
15 {
16 public:
17 /**
18 * Does nothing, here for completeness.
19 */
20 Archival();
21
22 /**
23 * Here to ensure the deconstructor is virtual.
24 */
25 virtual ~Archival();
26
27 /**
28 * This is the main workhorse of the archive system, just override and
29 * you've got a archiveable class. A reference to the Archive
30 * used is passed in as your only parameter, query it to discover if
31 * you are loading or saving.
32 * @param ar A reference to the Archive object to use.
33 */
34 virtual void archive( class Archive &ar )=0;
35 };
36}
37
38#endif
diff --git a/src/archive.cpp b/src/archive.cpp
new file mode 100644
index 0000000..7208bae
--- /dev/null
+++ b/src/archive.cpp
@@ -0,0 +1,386 @@
1#include "archive.h"
2
3Bu::Archive::Archive( Stream &rStream, bool bLoading ) :
4 bLoading( bLoading ),
5 rStream( rStream ),
6 nNextID( 1 )
7{
8}
9
10Bu::Archive::~Archive()
11{
12}
13
14void Bu::Archive::write( const void *pData, int32_t nSize )
15{
16 if( nSize == 0 || pData == NULL )
17 return;
18
19 rStream.write( (const char *)pData, nSize );
20}
21
22void Bu::Archive::read( void *pData, int32_t nSize )
23{
24 if( nSize == 0 || pData == NULL )
25 return;
26
27 rStream.read( (char *)pData, nSize );
28}
29
30void Bu::Archive::close()
31{
32 rStream.close();
33}
34
35bool Bu::Archive::isLoading()
36{
37 return bLoading;
38}
39Bu::Archive &Bu::Archive::operator<<(bool p)
40{
41 write( &p, sizeof(p) );
42 return *this;
43}
44Bu::Archive &Bu::Archive::operator<<(int8_t p)
45{
46 write( &p, sizeof(p) );
47 return *this;
48}
49Bu::Archive &Bu::Archive::operator<<(int16_t p)
50{
51 write( &p, sizeof(p) );
52 return *this;
53}
54Bu::Archive &Bu::Archive::operator<<(int32_t p)
55{
56 write( &p, sizeof(p) );
57 return *this;
58}
59Bu::Archive &Bu::Archive::operator<<(int64_t p)
60{
61 write( &p, sizeof(p) );
62 return *this;
63}
64Bu::Archive &Bu::Archive::operator<<(uint8_t p)
65{
66 write( &p, sizeof(p) );
67 return *this;
68}
69Bu::Archive &Bu::Archive::operator<<(uint16_t p)
70{
71 write( &p, sizeof(p) );
72 return *this;
73}
74Bu::Archive &Bu::Archive::operator<<(uint32_t p)
75{
76 write( &p, sizeof(p) );
77 return *this;
78}
79Bu::Archive &Bu::Archive::operator<<(uint64_t p)
80{
81 write( &p, sizeof(p) );
82 return *this;
83}
84Bu::Archive &Bu::Archive::operator<<(long p)
85{
86 write( &p, sizeof(p) );
87 return *this;
88}
89Bu::Archive &Bu::Archive::operator<<(float p)
90{
91 write( &p, sizeof(p) );
92 return *this;
93}
94Bu::Archive &Bu::Archive::operator<<(double p)
95{
96 write( &p, sizeof(p) );
97 return *this;
98}
99Bu::Archive &Bu::Archive::operator<<(long double p)
100{
101 write( &p, sizeof(p) );
102 return *this;
103}
104
105Bu::Archive &Bu::Archive::operator>>(bool &p)
106{
107 read( &p, sizeof(p) );
108 return *this;
109}
110Bu::Archive &Bu::Archive::operator>>(int8_t &p)
111{
112 read( &p, sizeof(p) );
113 return *this;
114}
115Bu::Archive &Bu::Archive::operator>>(int16_t &p)
116{
117 read( &p, sizeof(p) );
118 return *this;
119}
120Bu::Archive &Bu::Archive::operator>>(int32_t &p)
121{
122 read( &p, sizeof(p) );
123 return *this;
124}
125Bu::Archive &Bu::Archive::operator>>(int64_t &p)
126{
127 read( &p, sizeof(p) );
128 return *this;
129}
130Bu::Archive &Bu::Archive::operator>>(uint8_t &p)
131{
132 read( &p, sizeof(p) );
133 return *this;
134}
135Bu::Archive &Bu::Archive::operator>>(uint16_t &p)
136{
137 read( &p, sizeof(p) );
138 return *this;
139}
140Bu::Archive &Bu::Archive::operator>>(uint32_t &p)
141{
142 read( &p, sizeof(p) );
143 return *this;
144}
145Bu::Archive &Bu::Archive::operator>>(uint64_t &p)
146{
147 read( &p, sizeof(p) );
148 return *this;
149}
150Bu::Archive &Bu::Archive::operator>>(long &p)
151{
152 read( &p, sizeof(p) );
153 return *this;
154}
155Bu::Archive &Bu::Archive::operator>>(float &p)
156{
157 read( &p, sizeof(p) );
158 return *this;
159}
160Bu::Archive &Bu::Archive::operator>>(double &p)
161{
162 read( &p, sizeof(p) );
163 return *this;
164}
165Bu::Archive &Bu::Archive::operator>>(long double &p)
166{
167 read( &p, sizeof(p) );
168 return *this;
169}
170
171Bu::Archive &Bu::Archive::operator&&(bool &p)
172{
173 if (bLoading)
174 {
175 return *this >> p;
176 }
177 else
178 {
179 return *this << p;
180 }
181}
182
183Bu::Archive &Bu::Archive::operator&&(int8_t &p)
184{
185 if (bLoading)
186 {
187 return *this >> p;
188 }
189 else
190 {
191 return *this << p;
192 }
193}
194
195Bu::Archive &Bu::Archive::operator&&(int16_t &p)
196{
197 if (bLoading)
198 {
199 return *this >> p;
200 }
201 else
202 {
203 return *this << p;
204 }
205}
206
207Bu::Archive &Bu::Archive::operator&&(int32_t &p)
208{
209 if (bLoading)
210 {
211 return *this >> p;
212 }
213 else
214 {
215 return *this << p;
216 }
217}
218
219Bu::Archive &Bu::Archive::operator&&(int64_t &p)
220{
221 if (bLoading)
222 {
223 return *this >> p;
224 }
225 else
226 {
227 return *this << p;
228 }
229}
230
231Bu::Archive &Bu::Archive::operator&&(uint8_t &p)
232{
233 if (bLoading)
234 {
235 return *this >> p;
236 }
237 else
238 {
239 return *this << p;
240 }
241}
242
243Bu::Archive &Bu::Archive::operator&&(uint16_t &p)
244{
245 if (bLoading)
246 {
247 return *this >> p;
248 }
249 else
250 {
251 return *this << p;
252 }
253}
254
255Bu::Archive &Bu::Archive::operator&&(uint32_t &p)
256{
257 if (bLoading)
258 {
259 return *this >> p;
260 }
261 else
262 {
263 return *this << p;
264 }
265}
266
267Bu::Archive &Bu::Archive::operator&&(uint64_t &p)
268{
269 if (bLoading)
270 {
271 return *this >> p;
272 }
273 else
274 {
275 return *this << p;
276 }
277}
278
279Bu::Archive &Bu::Archive::operator&&(float &p)
280{
281 if (bLoading)
282 {
283 return *this >> p;
284 }
285 else
286 {
287 return *this << p;
288 }
289}
290
291Bu::Archive &Bu::Archive::operator&&(double &p)
292{
293 if (bLoading)
294 {
295 return *this >> p;
296 }
297 else
298 {
299 return *this << p;
300 }
301}
302
303Bu::Archive &Bu::Archive::operator&&(long double &p)
304{
305 if (bLoading)
306 {
307 return *this >> p;
308 }
309 else
310 {
311 return *this << p;
312 }
313}
314
315
316Bu::Archive &Bu::operator<<(Bu::Archive &s, Bu::Archival &p)
317{
318 p.archive( s );
319 return s;
320}
321
322Bu::Archive &Bu::operator>>(Bu::Archive &s, Bu::Archival &p)
323{
324 p.archive( s );
325 return s;
326}
327
328Bu::Archive &Bu::operator<<( Bu::Archive &ar, std::string &s )
329{
330 ar << (uint32_t)s.length();
331 ar.write( s.c_str(), s.length() );
332
333 return ar;
334}
335
336Bu::Archive &Bu::operator>>( Bu::Archive &ar, std::string &s )
337{
338 uint32_t l;
339 ar >> l;
340 char *tmp = new char[l+1];
341 tmp[l] = '\0';
342 ar.read( tmp, l );
343 s = tmp;
344 delete[] tmp;
345
346 return ar;
347}
348
349uint32_t Bu::Archive::getID( const void *ptr )
350{
351 if( hPtrID.has( (int)ptr ) )
352 return hPtrID.get( (int)ptr );
353 hPtrID.insert( (int)ptr, nNextID );
354 return nNextID++;
355}
356
357void Bu::Archive::assocPtrID( void **ptr, uint32_t id )
358{
359 if( hPtrID.has( id ) )
360 {
361 *ptr = (void *)hPtrID.get( id );
362 return;
363 }
364
365 if( !hPtrDest.has( id ) )
366 hPtrDest.insert( id, List<void **>() );
367
368 hPtrDest[id].value().append( ptr );
369}
370
371void Bu::Archive::readID( const void *ptr, uint32_t id )
372{
373 hPtrID.insert( id, (int)ptr );
374
375 if( hPtrDest.has( id ) )
376 {
377 Bu::List<void **> &l = hPtrDest.get( id );
378 for( Bu::List<void **>::iterator i = l.begin(); i != l.end(); i++ )
379 {
380 *(*i) = (void *)ptr;
381 }
382
383 hPtrDest.erase( id );
384 }
385}
386
diff --git a/src/archive.h b/src/archive.h
new file mode 100644
index 0000000..a2d4c8f
--- /dev/null
+++ b/src/archive.h
@@ -0,0 +1,212 @@
1#ifndef BU_ARCHIVE_H
2#define BU_ARCHIVE_H
3
4#include <stdint.h>
5#include <string>
6#include "bu/archival.h"
7#include "bu/stream.h"
8#include <list>
9#include "bu/hash.h"
10#include "bu/list.h"
11
12namespace Bu
13{
14 /**
15 * Provides a framework for serialization of objects and primitives. The
16 * archive will handle any basic primitive, a few special types, like char *
17 * strings, as well as STL classes and anything that inherits from the
18 * Archival class. Each Archive operates on a Stream, so you can send the
19 * data using an Archive almost anywhere.
20 *
21 * In order to use an Archive to store something to a file, try something
22 * like:
23 *@code
24 * File sOut("output", "wb"); // This is a stream subclass
25 * Archive ar( sOut, Archive::save );
26 * ar << myClass;
27 @endcode
28 * In this example myClass is any class that inherits from Archival. When
29 * the storage operator is called, the Archival::archive() function in the
30 * myClass object is called with a reference to the Archive. This can be
31 * handled in one of two ways:
32 *@code
33 * void MyClass::archive( Archive &ar )
34 * {
35 * ar && sName && nAge && sJob;
36 * }
37 @endcode
38 * Here we don't worry about weather we're loading or saving by using the
39 * smart && operator. This allows us to write very consistent, very simple
40 * archive functions that really do a lot of work. If we wanted to do
41 * something different in the case of loading or saving we would do:
42 *@code
43 * void MyClass::archive( Archive &ar )
44 * {
45 * if( ar.isLoading() )
46 * {
47 * ar >> sName >> nAge >> sJob;
48 * } else
49 * {
50 * ar << sName << nAge << sJob;
51 * }
52 * }
53 @endcode
54 * Archive currently does not provide facility to make fully portable
55 * archives. For example, it will not convert between endianness for you,
56 * nor will it take into account differences between primitive sizes on
57 * different platforms. This, at the moment, is up to the user to ensure.
58 * One way of dealing with the latter problem is to make sure and use
59 * explicit primitive types from the stdint.h header, i.e. int32_t.
60 */
61 class Archive
62 {
63 private:
64 bool bLoading;
65 public:
66 bool isLoading();
67
68 enum
69 {
70 load = true,
71 save = false
72 };
73
74 Archive( Stream &rStream, bool bLoading );
75 virtual ~Archive();
76 virtual void close();
77
78 virtual void write(const void *, int32_t);
79 virtual void read(void *, int32_t);
80
81 virtual Archive &operator<<(bool);
82 virtual Archive &operator<<(int8_t);
83 virtual Archive &operator<<(int16_t);
84 virtual Archive &operator<<(int32_t);
85 virtual Archive &operator<<(int64_t);
86 virtual Archive &operator<<(uint8_t);
87 virtual Archive &operator<<(uint16_t);
88 virtual Archive &operator<<(uint32_t);
89 virtual Archive &operator<<(uint64_t);
90 virtual Archive &operator<<(long);
91 virtual Archive &operator<<(float);
92 virtual Archive &operator<<(double);
93 virtual Archive &operator<<(long double);
94
95 virtual Archive &operator>>(bool &);
96 virtual Archive &operator>>(int8_t &);
97 virtual Archive &operator>>(int16_t &);
98 virtual Archive &operator>>(int32_t &);
99 virtual Archive &operator>>(int64_t &);
100 virtual Archive &operator>>(uint8_t &);
101 virtual Archive &operator>>(uint16_t &);
102 virtual Archive &operator>>(uint32_t &);
103 virtual Archive &operator>>(uint64_t &);
104 virtual Archive &operator>>(long &);
105 virtual Archive &operator>>(float &);
106 virtual Archive &operator>>(double &);
107 virtual Archive &operator>>(long double &);
108
109 virtual Archive &operator&&(bool &);
110 virtual Archive &operator&&(int8_t &);
111 virtual Archive &operator&&(int16_t &);
112 virtual Archive &operator&&(int32_t &);
113 virtual Archive &operator&&(int64_t &);
114 virtual Archive &operator&&(uint8_t &);
115 virtual Archive &operator&&(uint16_t &);
116 virtual Archive &operator&&(uint32_t &);
117 virtual Archive &operator&&(uint64_t &);
118 virtual Archive &operator&&(float &);
119 virtual Archive &operator&&(double &);
120 virtual Archive &operator&&(long double &);
121
122 uint32_t getID( const void *ptr );
123 void assocPtrID( void **ptr, uint32_t id );
124 void readID( const void *ptr, uint32_t id );
125
126 private:
127 Stream &rStream;
128 uint32_t nNextID;
129 Hash<uint32_t,uint32_t> hPtrID;
130 Hash<uint32_t,List<void **> > hPtrDest;
131 };
132
133 Archive &operator<<(Archive &, class Bu::Archival &);
134 Archive &operator>>(Archive &, class Bu::Archival &);
135 //Archive &operator&&(Archive &s, class Bu::Archival &p);
136
137 Archive &operator<<(Archive &, std::string &);
138 Archive &operator>>(Archive &, std::string &);
139 //Archive &operator&&(Archive &, std::string &);
140
141 template<typename T> Archive &operator&&( Archive &ar, T &dat )
142 {
143 if( ar.isLoading() )
144 {
145 return ar >> dat;
146 }
147 else
148 {
149 return ar << dat;
150 }
151 }
152
153 template<typename T> Archive &operator<<( Archive &ar, std::list<T> &l )
154 {
155 typename std::list<T>::size_type num = l.size();
156 ar << num;
157 for( typename std::list<T>::const_iterator i = l.begin(); i != l.end();
158 i++ )
159 {
160 ar << *i;
161 }
162
163 return ar;
164 }
165
166 template<typename T> Archive &operator>>( Archive &ar, std::list<T> &l )
167 {
168 typename std::list<T>::size_type num;
169 ar >> num;
170
171 l.resize( num );
172 for( typename std::list<T>::const_iterator i = l.begin();
173 i != l.end(); i++ )
174 {
175 ar >> *i;
176 }
177
178 return ar;
179 }
180
181 template<typename key, typename value>
182 Archive &operator<<( Archive &ar, Hash<key,value> &h )
183 {
184 ar << h.size();
185 for( typename Hash<key,value>::iterator i = h.begin(); i != h.end(); i++ )
186 {
187 //std::pair<key,value> p = *i;
188 ar << (i.getKey()) << (i.getValue());
189 }
190
191 return ar;
192 }
193
194 template<typename key, typename value>
195 Archive &operator>>( Archive &ar, Hash<key,value> &h )
196 {
197 h.clear();
198 uint32_t nSize;
199 ar >> nSize;
200
201 for( uint32_t j = 0; j < nSize; j++ )
202 {
203 key k; value v;
204 ar >> k >> v;
205 h.insert( k, v );
206 }
207
208 return ar;
209 }
210}
211
212#endif
diff --git a/src/arraylist.cpp b/src/arraylist.cpp
deleted file mode 100644
index ef21426..0000000
--- a/src/arraylist.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
1#include "arraylist.h"
2#include <stdlib.h>
3#include <string.h>
4
5ArrayList::ArrayList( int initSize, int growByFactor )
6{
7 apData = new void *[initSize];
8 nSize = 0;
9 nCapacity = initSize;
10 nGrowByFactor = growByFactor;
11}
12
13ArrayList::~ArrayList( )
14{
15 delete[] apData;
16}
17
18void *ArrayList::getAt( int index )
19{
20 if( index < 0 || index > nSize )
21 return NULL;
22
23 return apData[index];
24}
25
26void ArrayList::append( void *data )
27{
28 insertBefore( data, nSize );
29}
30
31void ArrayList::insertBefore( void *data, int pos )
32{
33 if( pos < 0 || pos > nSize )
34 return;
35
36 checkResize();
37 memmove( &apData[pos+1], &apData[pos], (nSize-pos)*sizeof(void*) );
38 apData[pos] = data;
39 nSize++;
40}
41
42int ArrayList::getSize( )
43{
44 return nSize;
45}
46
47bool ArrayList::isEmpty( )
48{
49 return nSize==0;
50}
51
52void ArrayList::deleteAt( int index )
53{
54 if( index < 0 || index >= nSize )
55 return;
56
57 memmove( &apData[index], &apData[index+1], (nSize-index-1)*sizeof(void *) );
58 nSize--;
59}
60
61void ArrayList::empty()
62{
63 // Probably the easiest as far as things go.
64 nSize = 0;
65}
66
67void ArrayList::resizeTo( int newSize )
68{
69 void **apNew = new void *[newSize];
70 memmove( apNew, apData, nSize*sizeof(void *) );
71 nCapacity = newSize;
72 delete[] apData;
73 apData = apNew;
74}
75
76void ArrayList::checkResize()
77{
78 if( nSize >= nCapacity )
79 {
80 resizeTo( nCapacity + nGrowByFactor );
81 }
82}
83
84void ArrayList::setSize( int newSize )
85{
86 if( newSize < 0 )
87 return;
88
89 nSize = newSize;
90 checkResize();
91}
92
93void ArrayList::setAt( int index, void *data )
94{
95 if( index < 0 || index >= nSize )
96 return;
97
98 apData[index] = data;
99}
100
diff --git a/src/arraylist.h b/src/arraylist.h
deleted file mode 100644
index 0fda34a..0000000
--- a/src/arraylist.h
+++ /dev/null
@@ -1,80 +0,0 @@
1/** \file arraylist.h
2 * Describes the ArrayList class.
3 *@author Mike Buland
4 */
5#ifndef ARRAY_LIST_H
6#define ARRAY_LIST_H
7
8#include "list.h"
9
10/** A simple list which uses an array. This is a great choice if you won't do
11 * a lot of adding and deleting and need a fast random access list. Otherwise
12 * use the LinkedList.
13 *@author Mike Buland
14 */
15class ArrayList : public List
16{
17public:
18 /** Creates an arraylist with some pre-defined specs spelled out.
19 *@param initSize the inital number of elements to allocate.
20 *@param growByFactor How much to increase the size of the array by
21 * each time we run out of room.
22 */
23 ArrayList( int initSize=100, int growByFactor=10 );
24 /**
25 * Destroy the ArrayList
26 */
27 virtual ~ArrayList();
28
29 void *getAt( int nIndex );
30 void append( void *pData );
31 void insertBefore( void *pData, int nPos = 0 );
32 int getSize( );
33 bool isEmpty( );
34 void deleteAt( int nIndex );
35 void empty();
36 void setSize( int nNewSize );
37 void setAt( int nIndex, void *pData );
38
39private:
40 /**
41 * Checks to see if the system needs to be resized, if it does, this will
42 * automatically resize based on your parameters.
43 */
44 void checkResize();
45
46 /**
47 * Resize the system to a specified size. If it is larger, then all data
48 * will be retained, if smaller the elements at the end will be cut off.
49 *@param newSize The number of elements to include after resizing.
50 */
51 void resizeTo( int newSize );
52
53 /**
54 * Actual master array of pointers. This is done to follow the List specs.
55 * All data transactions are performed with pointers or compatable
56 * primitive data-types.
57 */
58 void **apData;
59
60 /**
61 * The number of filled in elements in the array. This is the practical
62 * real size of the ArrayList for all userspace applications.
63 */
64 int nSize;
65
66 /**
67 * The number of elements allocated in memory. Not all of these have to be
68 * filled in, and it is usually larger than nSize so that adding and
69 * deleting elements is fast and easy.
70 */
71 int nCapacity;
72
73 /**
74 * The amount to grow by whenever the array needs resizing.
75 */
76 int nGrowByFactor;
77};
78
79#endif
80
diff --git a/src/atom.cpp b/src/atom.cpp
new file mode 100644
index 0000000..f966bfc
--- /dev/null
+++ b/src/atom.cpp
@@ -0,0 +1 @@
#include "bu/atom.h"
diff --git a/src/atom.h b/src/atom.h
new file mode 100644
index 0000000..fad47eb
--- /dev/null
+++ b/src/atom.h
@@ -0,0 +1,107 @@
1#ifndef BU_ATOM_H
2#define BU_ATOM_H
3
4#include <stdint.h>
5#include <memory>
6#include "bu/exceptions.h"
7
8namespace Bu
9{
10 /**
11 *
12 */
13 template <typename t, typename talloc=std::allocator<t> >
14 class Atom
15 {
16 private:
17 typedef struct Atom<t, talloc> MyType;
18
19 public:
20 Atom() :
21 pData( NULL )
22 {
23 }
24
25 virtual ~Atom()
26 {
27 clear();
28 }
29
30 bool has() const
31 {
32 return (pData != NULL);
33 }
34
35 void set( const t &val )
36 {
37 clear();
38 pData = ta.allocate( 1 );
39 ta.construct( pData, val );
40 }
41
42 t &get()
43 {
44 if( !pData )
45 throw Bu::ExceptionBase("Not set");
46 return *pData;
47 }
48
49 const t &get() const
50 {
51 if( !pData )
52 throw Bu::ExceptionBase("Not set");
53 return *pData;
54 }
55
56 void clear()
57 {
58 if( pData )
59 {
60 ta.destroy( pData );
61 ta.deallocate( pData, 1 );
62 pData = NULL;
63 }
64 }
65
66 operator const t &() const
67 {
68 if( !pData )
69 throw Bu::ExceptionBase("Not set");
70 return *pData;
71 }
72
73 operator t &()
74 {
75 if( !pData )
76 throw Bu::ExceptionBase("Not set");
77 return *pData;
78 }
79
80 MyType &operator =( const t &oth )
81 {
82 set( oth );
83
84 return *this;
85 }
86
87 t *operator ->()
88 {
89 if( !pData )
90 throw Bu::ExceptionBase("Not set");
91 return pData;
92 }
93
94 t &operator *()
95 {
96 if( !pData )
97 throw Bu::ExceptionBase("Not set");
98 return *pData;
99 }
100
101 private:
102 t *pData;
103 talloc ta;
104 };
105}
106
107#endif
diff --git a/src/bzip2.cpp b/src/bzip2.cpp
new file mode 100644
index 0000000..fbe5712
--- /dev/null
+++ b/src/bzip2.cpp
@@ -0,0 +1,196 @@
1#include "bu/bzip2.h"
2#include "bu/exceptions.h"
3
4using namespace Bu;
5
6Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) :
7 Bu::Filter( rNext ),
8 nCompression( nCompression )
9{
10 start();
11}
12
13Bu::BZip2::~BZip2()
14{
15 stop();
16}
17
18void Bu::BZip2::start()
19{
20 bzState.state = NULL;
21 bzState.bzalloc = NULL;
22 bzState.bzfree = NULL;
23 bzState.opaque = NULL;
24
25 nBufSize = 50000;
26 pBuf = new char[nBufSize];
27}
28
29size_t Bu::BZip2::stop()
30{
31 if( bzState.state )
32 {
33 if( bReading )
34 {
35 BZ2_bzDecompressEnd( &bzState );
36 delete[] pBuf;
37 pBuf = NULL;
38 return 0;
39 }
40 else
41 {
42 size_t sTotal = 0;
43 for(;;)
44 {
45 bzState.next_in = NULL;
46 bzState.avail_in = 0;
47 bzState.avail_out = nBufSize;
48 bzState.next_out = pBuf;
49 int res = BZ2_bzCompress( &bzState, BZ_FINISH );
50 if( bzState.avail_out < nBufSize )
51 {
52 sTotal += rNext.write( pBuf, nBufSize-bzState.avail_out );
53 }
54 if( res == BZ_STREAM_END )
55 break;
56 }
57 BZ2_bzCompressEnd( &bzState );
58 delete[] pBuf;
59 pBuf = NULL;
60 return sTotal;
61 }
62 }
63 return 0;
64}
65
66void Bu::BZip2::bzError( int code )
67{
68 switch( code )
69 {
70 case BZ_OK:
71 case BZ_RUN_OK:
72 case BZ_FLUSH_OK:
73 case BZ_FINISH_OK:
74 return;
75
76 case BZ_CONFIG_ERROR:
77 throw ExceptionBase("BZip2: Library configured improperly, reinstall.");
78
79 case BZ_SEQUENCE_ERROR:
80 throw ExceptionBase("BZip2: Functions were called in an invalid sequence.");
81
82 case BZ_PARAM_ERROR:
83 throw ExceptionBase("BZip2: Invalid parameter was passed into a function.");
84
85 case BZ_MEM_ERROR:
86 throw ExceptionBase("BZip2: Couldn't allocate sufficient memory.");
87
88 case BZ_DATA_ERROR:
89 throw ExceptionBase("BZip2: Data was corrupted before decompression.");
90
91 case BZ_DATA_ERROR_MAGIC:
92 throw ExceptionBase("BZip2: Stream does not appear to be bzip2 data.");
93
94 case BZ_IO_ERROR:
95 throw ExceptionBase("BZip2: File couldn't be read from / written to.");
96
97 case BZ_UNEXPECTED_EOF:
98 throw ExceptionBase("BZip2: End of file encountered before end of stream.");
99
100 case BZ_OUTBUFF_FULL:
101 throw ExceptionBase("BZip2: Buffer not large enough to accomidate data.");
102
103 default:
104 throw ExceptionBase("BZip2: Unknown error encountered.");
105
106 }
107}
108
109size_t Bu::BZip2::read( void *pData, size_t nBytes )
110{
111 if( !bzState.state )
112 {
113 bReading = true;
114 BZ2_bzDecompressInit( &bzState, 0, 0 );
115 bzState.next_in = pBuf;
116 bzState.avail_in = 0;
117 }
118 if( bReading == false )
119 throw ExceptionBase("This bzip2 filter is in writing mode, you can't read.");
120
121 int nRead = 0;
122 int nReadTotal = bzState.total_out_lo32;
123 bzState.next_out = (char *)pData;
124 bzState.avail_out = nBytes;
125 for(;;)
126 {
127 int ret = BZ2_bzDecompress( &bzState );
128
129 nReadTotal += nRead-bzState.avail_out;
130
131 if( ret == BZ_STREAM_END )
132 {
133 if( bzState.avail_in > 0 )
134 {
135 if( rNext.isSeekable() )
136 {
137 rNext.seek( -bzState.avail_in );
138 }
139 }
140 return nBytes-bzState.avail_out;
141 }
142 bzError( ret );
143
144 if( bzState.avail_out )
145 {
146 if( bzState.avail_in == 0 )
147 {
148 nRead = rNext.read( pBuf, nBufSize );
149 bzState.next_in = pBuf;
150 bzState.avail_in = nRead;
151 }
152 }
153 else
154 {
155 return nBytes-bzState.avail_out;
156 }
157 }
158 return 0;
159}
160
161size_t Bu::BZip2::write( const void *pData, size_t nBytes )
162{
163 if( !bzState.state )
164 {
165 bReading = false;
166 BZ2_bzCompressInit( &bzState, nCompression, 0, 30 );
167 }
168 if( bReading == true )
169 throw ExceptionBase("This bzip2 filter is in reading mode, you can't write.");
170
171 size_t sTotalOut = 0;
172 bzState.next_in = (char *)pData;
173 bzState.avail_in = nBytes;
174 for(;;)
175 {
176 bzState.avail_out = nBufSize;
177 bzState.next_out = pBuf;
178
179 bzError( BZ2_bzCompress( &bzState, BZ_RUN ) );
180
181 if( bzState.avail_out < nBufSize )
182 {
183 sTotalOut += rNext.write( pBuf, nBufSize-bzState.avail_out );
184 }
185 if( bzState.avail_in == 0 )
186 break;
187 }
188
189 return sTotalOut;
190}
191
192bool Bu::BZip2::isOpen()
193{
194 return (bzState.state != NULL);
195}
196
diff --git a/src/bzip2.h b/src/bzip2.h
new file mode 100644
index 0000000..0a111e8
--- /dev/null
+++ b/src/bzip2.h
@@ -0,0 +1,37 @@
1#ifndef BU_BZIP2_H
2#define BU_BZIP2_H
3
4#include <stdint.h>
5#include <bzlib.h>
6
7#include "bu/filter.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class BZip2 : public Bu::Filter
15 {
16 public:
17 BZip2( Bu::Stream &rNext, int nCompression=9 );
18 virtual ~BZip2();
19
20 virtual void start();
21 virtual size_t stop();
22 virtual size_t read( void *pBuf, size_t nBytes );
23 virtual size_t write( const void *pBuf, size_t nBytes );
24
25 virtual bool isOpen();
26
27 private:
28 void bzError( int code );
29 bz_stream bzState;
30 bool bReading;
31 int nCompression;
32 char *pBuf;
33 uint32_t nBufSize;
34 };
35}
36
37#endif
diff --git a/src/client.cpp b/src/client.cpp
new file mode 100644
index 0000000..8077b3d
--- /dev/null
+++ b/src/client.cpp
@@ -0,0 +1,206 @@
1#include "bu/client.h"
2#include "bu/socket.h"
3#include <stdlib.h>
4#include <errno.h>
5#include "bu/exceptions.h"
6#include "bu/protocol.h"
7
8/** Read buffer size. */
9#define RBS (1024*2)
10
11Bu::Client::Client( Bu::Socket *pSocket ) :
12 pSocket( pSocket ),
13 pProto( NULL ),
14 nRBOffset( 0 )
15{
16}
17
18Bu::Client::~Client()
19{
20}
21
22void Bu::Client::processInput()
23{
24 char buf[RBS];
25 size_t nRead, nTotal=0;
26
27 for(;;)
28 {
29 nRead = pSocket->read( buf, nRead );
30 if( nRead < 0 )
31 {
32 throw Bu::ConnectionException(
33 excodeReadError,
34 "Read error: %s",
35 strerror( errno )
36 );
37 }
38 else if( nRead == 0 )
39 {
40 break;
41 }
42 else
43 {
44 nTotal += nRead;
45 sReadBuf.append( buf, nRead );
46 if( !pSocket->canRead() )
47 break;
48 }
49 }
50
51 if( nTotal == 0 )
52 {
53 pSocket->close();
54 }
55
56 if( pProto && nTotal )
57 {
58 pProto->onNewData( this );
59 }
60}
61
62void Bu::Client::processOutput()
63{
64 if( sWriteBuf.getSize() > 0 )
65 {
66 pSocket->write( sWriteBuf.getStr(), sWriteBuf.getSize() );
67 sWriteBuf.clear();
68 }
69}
70
71void Bu::Client::setProtocol( Protocol *pProto )
72{
73 this->pProto = pProto;
74}
75
76Bu::Protocol *Bu::Client::getProtocol()
77{
78 return pProto;
79}
80
81void Bu::Client::clearProtocol()
82{
83 pProto = NULL;
84}
85
86Bu::FString &Bu::Client::getInput()
87{
88 return sReadBuf;
89}
90
91Bu::FString &Bu::Client::getOutput()
92{
93 return sWriteBuf;
94}
95
96bool Bu::Client::isOpen()
97{
98 if( !pSocket ) return false;
99 return pSocket->isOpen();
100}
101
102void Bu::Client::write( const void *pData, int nBytes )
103{
104 sWriteBuf.append( (const char *)pData, nBytes );
105}
106
107void Bu::Client::write( int8_t nData )
108{
109 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
110}
111
112void Bu::Client::write( int16_t nData )
113{
114 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
115}
116
117void Bu::Client::write( int32_t nData )
118{
119 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
120}
121
122void Bu::Client::write( int64_t nData )
123{
124 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
125}
126
127void Bu::Client::write( uint8_t nData )
128{
129 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
130}
131
132void Bu::Client::write( uint16_t nData )
133{
134 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
135}
136
137void Bu::Client::write( uint32_t nData )
138{
139 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
140}
141
142void Bu::Client::write( uint64_t nData )
143{
144 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
145}
146
147void Bu::Client::read( void *pData, int nBytes )
148{
149 memcpy( pData, sReadBuf.getStr()+nRBOffset, nBytes );
150 nRBOffset += nBytes;
151 if( sReadBuf.getSize()-nRBOffset == 0 )
152 {
153 sReadBuf.clear();
154 nRBOffset = 0;
155 }
156 // This is an experimental threshold, maybe I'll make this configurable
157 // later on.
158 else if(
159 (sReadBuf.getSize() >= 1024 && nRBOffset >= sReadBuf.getSize()/2) ||
160 (nRBOffset >= sReadBuf.getSize()/4)
161 )
162 {
163 sReadBuf.trimFront( nRBOffset );
164 nRBOffset = 0;
165 }
166}
167
168void Bu::Client::peek( void *pData, int nBytes )
169{
170 memcpy( pData, sReadBuf.getStr()+nRBOffset, nBytes );
171}
172
173void Bu::Client::seek( int nBytes )
174{
175 nRBOffset += nBytes;
176 if( sReadBuf.getSize()-nRBOffset == 0 )
177 {
178 sReadBuf.clear();
179 nRBOffset = 0;
180 }
181 // This is an experimental threshold, maybe I'll make this configurable
182 // later on.
183 else if(
184 (sReadBuf.getSize() >= 1024 && nRBOffset >= sReadBuf.getSize()/2) ||
185 (nRBOffset >= sReadBuf.getSize()/4)
186 )
187 {
188 sReadBuf.trimFront( nRBOffset );
189 nRBOffset = 0;
190 }
191}
192
193long Bu::Client::getInputSize()
194{
195 return sReadBuf.getSize()-nRBOffset;
196}
197
198const Bu::Socket *Bu::Client::getSocket() const
199{
200 return pSocket;
201}
202
203void Bu::Client::disconnect()
204{
205}
206
diff --git a/src/client.h b/src/client.h
new file mode 100644
index 0000000..5947521
--- /dev/null
+++ b/src/client.h
@@ -0,0 +1,63 @@
1#ifndef BU_CLIENT_H
2#define BU_CLIENT_H
3
4#include <stdint.h>
5
6#include "bu/fstring.h"
7
8namespace Bu
9{
10 class Protocol;
11 class Socket;
12
13 /**
14 *
15 */
16 class Client
17 {
18 public:
19 Client( Bu::Socket *pSocket );
20 virtual ~Client();
21
22 void processInput();
23 void processOutput();
24
25 Bu::FString &getInput();
26 Bu::FString &getOutput();
27 void write( const void *pData, int nBytes );
28 void write( int8_t nData );
29 void write( int16_t nData );
30 void write( int32_t nData );
31 void write( int64_t nData );
32 void write( uint8_t nData );
33 void write( uint16_t nData );
34 void write( uint32_t nData );
35 void write( uint64_t nData );
36 void read( void *pData, int nBytes );
37 void peek( void *pData, int nBytes );
38 void seek( int nBytes );
39 long getInputSize();
40
41 void setProtocol( Protocol *pProto );
42 Bu::Protocol *getProtocol();
43 void clearProtocol();
44
45 bool isOpen();
46
47 const Bu::Socket *getSocket() const;
48
49 /**
50 *@todo Make this not suck.
51 */
52 void disconnect();
53
54 private:
55 Bu::Socket *pSocket;
56 Bu::Protocol *pProto;
57 Bu::FString sReadBuf;
58 int nRBOffset;
59 Bu::FString sWriteBuf;
60 };
61}
62
63#endif
diff --git a/src/entities/bu-class b/src/entities/bu-class
new file mode 100644
index 0000000..7b25291
--- /dev/null
+++ b/src/entities/bu-class
@@ -0,0 +1,48 @@
1<?xml version="1.1" ?>
2<entity desc="Basic cpp class, with optional parent class. (.cpp+.h)">
3 <param name="name" required="yes" desc="Name of the class"/>
4 <param name="parent" required="no" desc="Name of the parent class"/>
5 <file
6 name="header"
7 filename="{=name:%tolower}.h"
8>#ifndef {=name:%uccsplit:%toupper}_H
9#define {=name:%uccsplit:%toupper}_H
10
11#include &lt;stdint.h&gt;
12
13{?parent:"#include \"bu/{=parent:%tolower}.h\"
14
15"}namespace Bu
16{
17 /**
18 *
19 */
20 class {=name}{?parent:" : public {=parent}"}
21 {
22 public:
23 {=name}();
24 virtual ~{=name}();
25
26 private:
27
28 };
29}
30
31#endif
32</file>
33 <file
34 name="source"
35 filename="{=name:%tolower}.cpp"
36>#include "bu/{=name:%tolower}.h"
37
38using namespace Bu;
39
40Bu::{=name}::{=name}()
41{
42}
43
44Bu::{=name}::~{=name}()
45{
46}
47</file>
48</entity>
diff --git a/src/exceptionbase.cpp b/src/exceptionbase.cpp
index f3d22da..f6ec625 100644
--- a/src/exceptionbase.cpp
+++ b/src/exceptionbase.cpp
@@ -1,7 +1,7 @@
1#include "exceptionbase.h" 1#include "exceptionbase.h"
2#include <stdarg.h> 2#include <stdarg.h>
3 3
4ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() : 4Bu::ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() :
5 nErrorCode( 0 ), 5 nErrorCode( 0 ),
6 sWhat( NULL ) 6 sWhat( NULL )
7{ 7{
@@ -12,7 +12,7 @@ ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() :
12 va_end(ap); 12 va_end(ap);
13} 13}
14 14
15ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() : 15Bu::ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() :
16 nErrorCode( nCode ), 16 nErrorCode( nCode ),
17 sWhat( NULL ) 17 sWhat( NULL )
18{ 18{
@@ -23,13 +23,13 @@ ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() :
23 va_end(ap); 23 va_end(ap);
24} 24}
25 25
26ExceptionBase::ExceptionBase( int nCode ) throw() : 26Bu::ExceptionBase::ExceptionBase( int nCode ) throw() :
27 nErrorCode( nCode ), 27 nErrorCode( nCode ),
28 sWhat( NULL ) 28 sWhat( NULL )
29{ 29{
30} 30}
31 31
32ExceptionBase::~ExceptionBase() throw() 32Bu::ExceptionBase::~ExceptionBase() throw()
33{ 33{
34 if( sWhat ) 34 if( sWhat )
35 { 35 {
@@ -38,7 +38,7 @@ ExceptionBase::~ExceptionBase() throw()
38 } 38 }
39} 39}
40 40
41void ExceptionBase::setWhat( const char *lpFormat, va_list &vargs ) 41void Bu::ExceptionBase::setWhat( const char *lpFormat, va_list &vargs )
42{ 42{
43 if( sWhat ) delete[] sWhat; 43 if( sWhat ) delete[] sWhat;
44 int nSize; 44 int nSize;
@@ -48,7 +48,7 @@ void ExceptionBase::setWhat( const char *lpFormat, va_list &vargs )
48 vsnprintf( sWhat, nSize+1, lpFormat, vargs ); 48 vsnprintf( sWhat, nSize+1, lpFormat, vargs );
49} 49}
50 50
51void ExceptionBase::setWhat( const char *lpText ) 51void Bu::ExceptionBase::setWhat( const char *lpText )
52{ 52{
53 if( sWhat ) delete[] sWhat; 53 if( sWhat ) delete[] sWhat;
54 int nSize; 54 int nSize;
@@ -58,12 +58,12 @@ void ExceptionBase::setWhat( const char *lpText )
58 strcpy( sWhat, lpText ); 58 strcpy( sWhat, lpText );
59} 59}
60 60
61const char *ExceptionBase::what() const throw() 61const char *Bu::ExceptionBase::what() const throw()
62{ 62{
63 return sWhat; 63 return sWhat;
64} 64}
65 65
66int ExceptionBase::getErrorCode() 66int Bu::ExceptionBase::getErrorCode()
67{ 67{
68 return nErrorCode; 68 return nErrorCode;
69} 69}
diff --git a/src/exceptionbase.h b/src/exceptionbase.h
index 6f1eca7..24e4bbf 100644
--- a/src/exceptionbase.h
+++ b/src/exceptionbase.h
@@ -1,75 +1,84 @@
1#ifndef EXCEPTION_BASE_H 1#ifndef BU_EXCEPTION_BASE_H
2#define EXCEPTION_BASE_H 2#define BU_EXCEPTION_BASE_H
3 3
4#include <string> 4#include <string>
5#include <exception> 5#include <exception>
6#include <stdarg.h> 6#include <stdarg.h>
7 7
8/** 8namespace Bu
9 * A generalized Exception base class. This is nice for making general and
10 * flexible child classes that can create new error code classes.
11 */
12class ExceptionBase : public std::exception
13{ 9{
14public:
15 /**
16 * Construct an exception with an error code of zero, but with a
17 * description. The use of this is not reccomended most of the time, it's
18 * generally best to include an error code with the exception so your
19 * program can handle the exception in a better way.
20 * @param sFormat The format of the text. See printf for more info.
21 */
22 ExceptionBase( const char *sFormat, ... ) throw();
23
24 /** 10 /**
11 * A generalized Exception base class. This is nice for making general and
12 * flexible child classes that can create new error code classes.
13 *
14 * In order to create your own exception class use these two lines.
25 * 15 *
26 * @param nCode 16 * in your header: subExceptionDecl( NewClassName );
27 * @param sFormat
28 */
29 ExceptionBase( int nCode, const char *sFormat, ... ) throw();
30
31 /**
32 * 17 *
33 * @param nCode 18 * in your source: subExcpetienDef( NewClassName );
34 * @return
35 */ 19 */
36 ExceptionBase( int nCode=0 ) throw(); 20 class ExceptionBase : public std::exception
37 21 {
38 /** 22 public:
39 * 23 /**
40 * @return 24 * Construct an exception with an error code of zero, but with a
41 */ 25 * description. The use of this is not reccomended most of the time,
42 virtual ~ExceptionBase() throw(); 26 * it's generally best to include an error code with the exception so
27 * your program can handle the exception in a better way.
28 * @param sFormat The format of the text. See printf for more info.
29 */
30 ExceptionBase( const char *sFormat, ... ) throw();
31
32 /**
33 *
34 * @param nCode
35 * @param sFormat
36 */
37 ExceptionBase( int nCode, const char *sFormat, ... ) throw();
38
39 /**
40 *
41 * @param nCode
42 * @return
43 */
44 ExceptionBase( int nCode=0 ) throw();
45
46 /**
47 *
48 * @return
49 */
50 virtual ~ExceptionBase() throw();
43 51
44 /** 52 /**
45 * 53 *
46 * @return 54 * @return
47 */ 55 */
48 virtual const char *what() const throw(); 56 virtual const char *what() const throw();
49 57
50 /** 58 /**
51 * 59 *
52 * @return 60 * @return
53 */ 61 */
54 int getErrorCode(); 62 int getErrorCode();
55 63
56 /** 64 /**
57 * 65 *
58 * @param lpFormat 66 * @param lpFormat
59 * @param vargs 67 * @param vargs
60 */ 68 */
61 void setWhat( const char *lpFormat, va_list &vargs ); 69 void setWhat( const char *lpFormat, va_list &vargs );
62 70
63 /** 71 /**
64 * 72 *
65 * @param lpText 73 * @param lpText
66 */ 74 */
67 void setWhat( const char *lpText ); 75 void setWhat( const char *lpText );
68 76
69private: 77 private:
70 int nErrorCode; /**< The code for the error that occured. */ 78 int nErrorCode; /**< The code for the error that occured. */
71 char *sWhat; /**< The text string telling people what went wrong. */ 79 char *sWhat; /**< The text string telling people what went wrong. */
72}; 80 };
81}
73 82
74#define subExceptionDecl( name ) \ 83#define subExceptionDecl( name ) \
75class name : public ExceptionBase \ 84class name : public ExceptionBase \
diff --git a/src/exceptions.cpp b/src/exceptions.cpp
index ce79a5e..50b95c3 100644
--- a/src/exceptions.cpp
+++ b/src/exceptions.cpp
@@ -1,8 +1,13 @@
1#include "exceptions.h" 1#include "exceptions.h"
2#include <stdarg.h> 2#include <stdarg.h>
3 3
4subExceptionDef( XmlException ) 4namespace Bu
5subExceptionDef( FileException ) 5{
6subExceptionDef( ConnectionException ) 6 subExceptionDef( XmlException )
7subExceptionDef( PluginException ) 7 subExceptionDef( TafException )
8 8 subExceptionDef( FileException )
9 subExceptionDef( SocketException )
10 subExceptionDef( ConnectionException )
11 subExceptionDef( PluginException )
12 subExceptionDef( UnsupportedException )
13}
diff --git a/src/exceptions.h b/src/exceptions.h
index 0ab2b15..b824b91 100644
--- a/src/exceptions.h
+++ b/src/exceptions.h
@@ -1,25 +1,32 @@
1#ifndef EXCEPTIONS_H 1#ifndef BU_EXCEPTIONS_H
2#define EXCEPTIONS_H 2#define BU_EXCEPTIONS_H
3 3
4#include "exceptionbase.h" 4#include "exceptionbase.h"
5#include <stdarg.h> 5#include <stdarg.h>
6 6
7subExceptionDecl( XmlException ) 7namespace Bu
8subExceptionDecl( FileException )
9subExceptionDecl( ConnectionException )
10subExceptionDecl( PluginException )
11
12enum eFileException
13{
14 excodeEOF
15};
16
17enum eConnectionException
18{ 8{
19 excodeReadError, 9 subExceptionDecl( XmlException )
20 excodeBadReadError, 10 subExceptionDecl( TafException )
21 excodeConnectionClosed, 11 subExceptionDecl( FileException )
22 excodeSocketTimeout 12 subExceptionDecl( SocketException )
23}; 13 subExceptionDecl( ConnectionException )
14 subExceptionDecl( PluginException )
15 subExceptionDecl( UnsupportedException )
16
17 enum eFileException
18 {
19 excodeEOF
20 };
21
22 enum eConnectionException
23 {
24 excodeReadError,
25 excodeWriteError,
26 excodeBadReadError,
27 excodeConnectionClosed,
28 excodeSocketTimeout
29 };
30}
24 31
25#endif 32#endif
diff --git a/src/file.cpp b/src/file.cpp
new file mode 100644
index 0000000..1a8bd08
--- /dev/null
+++ b/src/file.cpp
@@ -0,0 +1,158 @@
1#include "file.h"
2#include "exceptions.h"
3#include <errno.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6
7Bu::File::File( const char *sName, const char *sFlags )
8{
9 fh = fopen( sName, sFlags );
10 if( fh == NULL )
11 {
12 throw Bu::FileException( errno, strerror(errno) );
13 }
14}
15
16Bu::File::File( const Bu::FString &sName, const char *sFlags )
17{
18 fh = fopen( sName.getStr(), sFlags );
19 if( fh == NULL )
20 {
21 throw Bu::FileException( errno, strerror(errno) );
22 }
23}
24
25Bu::File::File( int fd, const char *sFlags )
26{
27 fh = fdopen( fd, sFlags );
28}
29
30Bu::File::~File()
31{
32 close();
33}
34
35void Bu::File::close()
36{
37 if( fh )
38 {
39 fclose( fh );
40 fh = NULL;
41 }
42}
43
44size_t Bu::File::read( void *pBuf, size_t nBytes )
45{
46 if( !fh )
47 throw FileException("File not open.");
48
49 int nAmnt = fread( pBuf, 1, nBytes, fh );
50
51 //if( nAmnt == 0 )
52 // throw FileException("End of file.");
53
54 return nAmnt;
55}
56
57size_t Bu::File::write( const void *pBuf, size_t nBytes )
58{
59 if( !fh )
60 throw FileException("File not open.");
61
62 return fwrite( pBuf, 1, nBytes, fh );
63}
64
65long Bu::File::tell()
66{
67 if( !fh )
68 throw FileException("File not open.");
69
70 return ftell( fh );
71}
72
73void Bu::File::seek( long offset )
74{
75 if( !fh )
76 throw FileException("File not open.");
77
78 fseek( fh, offset, SEEK_CUR );
79}
80
81void Bu::File::setPos( long pos )
82{
83 if( !fh )
84 throw FileException("File not open.");
85
86 fseek( fh, pos, SEEK_SET );
87}
88
89void Bu::File::setPosEnd( long pos )
90{
91 if( !fh )
92 throw FileException("File not open.");
93
94 fseek( fh, pos, SEEK_END );
95}
96
97bool Bu::File::isEOS()
98{
99 return feof( fh );
100}
101
102bool Bu::File::canRead()
103{
104 return true;
105}
106
107bool Bu::File::canWrite()
108{
109 return true;
110}
111
112bool Bu::File::isReadable()
113{
114 return true;
115}
116
117bool Bu::File::isWritable()
118{
119 return true;
120}
121
122bool Bu::File::isSeekable()
123{
124 return true;
125}
126
127bool Bu::File::isBlocking()
128{
129 return true;
130}
131
132void Bu::File::setBlocking( bool bBlocking )
133{
134 return;
135}
136
137#ifndef WIN32
138void Bu::File::truncate( long nSize )
139{
140 ftruncate( fileno( fh ), nSize );
141}
142
143void Bu::File::chmod( mode_t t )
144{
145 fchmod( fileno( fh ), t );
146}
147#endif
148
149void Bu::File::flush()
150{
151 fflush( fh );
152}
153
154bool Bu::File::isOpen()
155{
156 return (fh != NULL);
157}
158
diff --git a/src/file.h b/src/file.h
new file mode 100644
index 0000000..d4e43eb
--- /dev/null
+++ b/src/file.h
@@ -0,0 +1,78 @@
1#ifndef BU_FILE_H
2#define BU_FILE_H
3
4#include <stdint.h>
5
6#include "bu/stream.h"
7#include "bu/fstring.h"
8
9namespace Bu
10{
11 class File : public Bu::Stream
12 {
13 public:
14 File( const char *sName, const char *sFlags );
15 File( const Bu::FString &sName, const char *sFlags );
16 File( int fd, const char *sFlags );
17 virtual ~File();
18
19 virtual void close();
20 virtual size_t read( void *pBuf, size_t nBytes );
21 virtual size_t write( const void *pBuf, size_t nBytes );
22
23 virtual long tell();
24 virtual void seek( long offset );
25 virtual void setPos( long pos );
26 virtual void setPosEnd( long pos );
27 virtual bool isEOS();
28 virtual bool isOpen();
29
30 virtual void flush();
31
32 virtual bool canRead();
33 virtual bool canWrite();
34
35 virtual bool isReadable();
36 virtual bool isWritable();
37 virtual bool isSeekable();
38
39 virtual bool isBlocking();
40 virtual void setBlocking( bool bBlocking=true );
41
42 /**
43 * Create a temp file and return its handle
44 *@param sName (Bu::FString) Give in the form: "/tmp/tmpfileXXXXXXXX"
45 * It will alter your (sName) setting the 'X's to random
46 * characters.
47 *@param sFlags (const char *) Standard file flags 'rb'... etc..
48 *@returns (Bu::File) A file object representing your temp file.
49 */
50#ifndef WIN32
51 inline static Bu::File tempFile( Bu::FString &sName, const char *sFlags )
52 {
53 int afh_d = mkstemp( sName.getStr() );
54
55 return Bu::File( afh_d, sFlags );
56 }
57
58 /**
59 * Set the size of the file to (nSize). You can either grow or shrink
60 * the file.
61 *@param nSize (long) The new size of the file.
62 */
63 void truncate( long nSize );
64
65 /**
66 * Change the file access permissions.
67 *@param t (mode_t) The new file access permissions.
68 */
69 void chmod( mode_t t );
70#endif
71
72 private:
73 FILE *fh;
74
75 };
76}
77
78#endif
diff --git a/src/filter.cpp b/src/filter.cpp
new file mode 100644
index 0000000..96a8694
--- /dev/null
+++ b/src/filter.cpp
@@ -0,0 +1,97 @@
1#include "bu/filter.h"
2
3Bu::Filter::Filter( Bu::Stream &rNext ) :
4 rNext( rNext )
5{
6}
7
8Bu::Filter::~Filter()
9{
10 //printf("-> Bu::Filter::~Filter()\n");
11}
12/*
13void Bu::Filter::start()
14{
15 printf("-> Bu::Filter::start()\n");
16}
17
18void Bu::Filter::stop()
19{
20}*/
21
22void Bu::Filter::close()
23{
24 stop();
25 rNext.close();
26}
27
28long Bu::Filter::tell()
29{
30 return rNext.tell();
31}
32
33void Bu::Filter::seek( long offset )
34{
35 rNext.seek( offset );
36}
37
38void Bu::Filter::setPos( long pos )
39{
40 rNext.setPos( pos );
41}
42
43void Bu::Filter::setPosEnd( long pos )
44{
45 rNext.setPosEnd( pos );
46}
47
48bool Bu::Filter::isEOS()
49{
50 return rNext.isEOS();
51}
52
53bool Bu::Filter::isOpen()
54{
55 return rNext.isOpen();
56}
57
58bool Bu::Filter::canRead()
59{
60 return rNext.canRead();
61}
62
63bool Bu::Filter::canWrite()
64{
65 return rNext.canWrite();
66}
67
68bool Bu::Filter::isReadable()
69{
70 return rNext.isReadable();
71}
72
73bool Bu::Filter::isWritable()
74{
75 return rNext.isWritable();
76}
77
78bool Bu::Filter::isSeekable()
79{
80 return rNext.isSeekable();
81}
82
83bool Bu::Filter::isBlocking()
84{
85 return rNext.isBlocking();
86}
87
88void Bu::Filter::setBlocking( bool bBlocking )
89{
90 rNext.setBlocking( bBlocking );
91}
92
93void Bu::Filter::flush()
94{
95 rNext.flush();
96}
97
diff --git a/src/filter.h b/src/filter.h
new file mode 100644
index 0000000..bd557b2
--- /dev/null
+++ b/src/filter.h
@@ -0,0 +1,65 @@
1#ifndef BU_FILTER_H
2#define BU_FILTER_H
3
4#include <stdint.h>
5
6#include "bu/stream.h"
7
8namespace Bu
9{
10 /**
11 * Data filter base class. Each data filter should contain a read and write
12 * section. Effectively, the write applies the filter, the read un-applies
13 * the filter, if possible. For example, BZip2 is a filter that compresses
14 * on write and decompresses on read. All bi-directional filters should
15 * follow: x == read( write( x ) ) (byte-for-byte comparison)
16 *
17 * Also, all returned buffers should be owned by the filter, and deleted
18 * when the filter is deleted. This means that the output of a read or
19 * write operation must be used before the next call to read or write or the
20 * data will be destroyed. Also, the internal buffer may be changed or
21 * recreated between calls, so always get a new pointer from a call to
22 * read or write.
23 *
24 * The close function can also return data, so make sure to check for it,
25 * many filters such as compression filters will buffer data until they have
26 * enough to create a compression block, in these cases the leftover data
27 * will be returned by close.
28 */
29 class Filter : public Bu::Stream
30 {
31 public:
32 Filter( Bu::Stream &rNext );
33 virtual ~Filter();
34
35 virtual void start()=0;
36 virtual size_t stop()=0;
37 virtual void close();
38 virtual long tell();
39 virtual void seek( long offset );
40 virtual void setPos( long pos );
41 virtual void setPosEnd( long pos );
42 virtual bool isEOS();
43 virtual bool isOpen();
44
45 virtual void flush();
46
47 virtual bool canRead();
48 virtual bool canWrite();
49
50 virtual bool isReadable();
51 virtual bool isWritable();
52 virtual bool isSeekable();
53
54 virtual bool isBlocking();
55 virtual void setBlocking( bool bBlocking=true );
56
57 protected:
58 Bu::Stream &rNext;
59
60 private:
61
62 };
63}
64
65#endif
diff --git a/src/fstring.cpp b/src/fstring.cpp
index 82d024d..f71d6c1 100644
--- a/src/fstring.cpp
+++ b/src/fstring.cpp
@@ -1,13 +1,20 @@
1#include "fstring.h" 1#include "fstring.h"
2#include "hash.h" 2#include "hash.h"
3 3
4template<> uint32_t __calcHashCode<FString>( const FString &k ) 4template<> uint32_t Bu::__calcHashCode<Bu::FString>( const Bu::FString &k )
5{ 5{
6 return __calcHashCode( k.c_str() ); 6 return __calcHashCode( k.c_str() );
7} 7}
8 8
9template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ) 9template<> bool Bu::__cmpHashKeys<Bu::FString>(
10 const Bu::FString &a, const Bu::FString &b )
10{ 11{
11 return a == b; 12 return a == b;
12} 13}
13 14
15std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FString &val )
16{
17 os.write( val.getStr(), val.getSize() );
18 return os;
19}
20
diff --git a/src/fstring.h b/src/fstring.h
index c5397cc..1e1fc02 100644
--- a/src/fstring.h
+++ b/src/fstring.h
@@ -1,651 +1,903 @@
1#ifndef F_STRING_H 1#ifndef BU_F_STRING_H
2#define F_STRING_H 2#define BU_F_STRING_H
3 3
4#include <stdint.h> 4#include <stdint.h>
5#include <memory> 5#include <memory>
6#include "serializable.h" 6#include "bu/archival.h"
7#include "serializer.h" 7#include "bu/archive.h"
8#include "bu/hash.h"
8 9
9template< typename chr > 10#define min( a, b ) ((a<b)?(a):(b))
10struct FStringChunk 11
11{ 12namespace Bu
12 long nLength;
13 chr *pData;
14 FStringChunk *pNext;
15};
16
17/**
18 * Flexible String class. This class was designed with string passing and
19 * generation in mind. Like the standard string class you can specify what
20 * datatype to use for each character. Unlike the standard string class,
21 * collection of appended and prepended terms is done lazily, making long
22 * operations that involve many appends very inexpensive. In addition internal
23 * ref-counting means that if you pass strings around between functions there's
24 * almost no overhead in time or memory since a reference is created and no
25 * data is actually copied. This also means that you never need to put any
26 * FBasicString into a ref-counting container class.
27 */
28template< typename chr, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
29class FBasicString : public Serializable
30{ 13{
14 template< typename chr >
15 struct FStringChunk
16 {
17 long nLength;
18 chr *pData;
19 FStringChunk *pNext;
20 };
21
22 /**
23 * Flexible String class. This class was designed with string passing and
24 * generation in mind. Like the standard string class you can specify what
25 * datatype to use for each character. Unlike the standard string class,
26 * collection of appended and prepended terms is done lazily, making long
27 * operations that involve many appends very inexpensive. In addition internal
28 * ref-counting means that if you pass strings around between functions there's
29 * almost no overhead in time or memory since a reference is created and no
30 * data is actually copied. This also means that you never need to put any
31 * FBasicString into a ref-counting container class.
32 *
33 *@param chr (typename) Type of character (i.e. char)
34 *@param nMinSize (int) Chunk size (default: 256)
35 *@param chralloc (typename) Memory Allocator for chr
36 *@param chunkalloc (typename) Memory Allocator for chr chunks
37 */
38 template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
39 class FBasicString : public Archival
40 {
31#ifndef VALTEST 41#ifndef VALTEST
32#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) ) 42#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) )
33#endif 43#endif
34private: 44 private:
35 typedef struct FStringChunk<chr> Chunk; 45 typedef struct FStringChunk<chr> Chunk;
36 typedef struct FBasicString<chr, chralloc, chunkalloc> MyType; 46 typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType;
37 47
38public: 48 public:
39 FBasicString() : 49 FBasicString() :
40 nLength( 0 ), 50 nLength( 0 ),
41 pnRefs( NULL ), 51 pnRefs( NULL ),
42 pFirst( NULL ), 52 pFirst( NULL ),
43 pLast( NULL ) 53 pLast( NULL )
44 { 54 {
45 } 55 }
46 56
47 FBasicString( const chr *pData ) : 57 FBasicString( const chr *pData ) :
48 nLength( 0 ), 58 nLength( 0 ),
49 pnRefs( NULL ), 59 pnRefs( NULL ),
50 pFirst( NULL ), 60 pFirst( NULL ),
51 pLast( NULL ) 61 pLast( NULL )
52 { 62 {
53 append( pData ); 63 append( pData );
54 } 64 }
55
56 FBasicString( const chr *pData, long nLength ) :
57 nLength( 0 ),
58 pnRefs( NULL ),
59 pFirst( NULL ),
60 pLast( NULL )
61 {
62 append( pData, nLength );
63 }
64
65 FBasicString( const MyType &rSrc ) :
66 nLength( 0 ),
67 pnRefs( NULL ),
68 pFirst( NULL ),
69 pLast( NULL )
70 {
71 // Here we have no choice but to copy, since the other guy is a const.
72 // In the case that the source were flat, we could get a reference, it
73 // would make some things faster, but not matter in many other cases.
74
75 joinShare( rSrc );
76 //copyFrom( rSrc );
77 }
78
79 FBasicString( const MyType &rSrc, long nLength ) :
80 nLength( 0 ),
81 pnRefs( NULL ),
82 pFirst( NULL ),
83 pLast( NULL )
84 {
85 append( rSrc.pFirst->pData, nLength );
86 }
87
88 FBasicString( const MyType &rSrc, long nStart, long nLength ) :
89 nLength( 0 ),
90 pnRefs( NULL ),
91 pFirst( NULL ),
92 pLast( NULL )
93 {
94 append( rSrc.pFirst->pData+nStart, nLength );
95 }
96
97 FBasicString( long nSize ) :
98 nLength( nSize ),
99 pnRefs( NULL ),
100 pFirst( NULL ),
101 pLast( NULL )
102 {
103 pFirst = pLast = newChunk( nSize );
104 }
105 65
106 virtual ~FBasicString() 66 FBasicString( const chr *pData, long nLength ) :
107 { 67 nLength( 0 ),
108 clear(); 68 pnRefs( NULL ),
109 } 69 pFirst( NULL ),
70 pLast( NULL )
71 {
72 append( pData, nLength );
73 }
110 74
111 void append( const chr *pData ) 75 FBasicString( const MyType &rSrc ) :
112 { 76 nLength( 0 ),
113 long nLen; 77 pnRefs( NULL ),
114 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); 78 pFirst( NULL ),
115 79 pLast( NULL )
116 Chunk *pNew = newChunk( nLen ); 80 {
117 cpy( pNew->pData, pData, nLen ); 81 // Here we have no choice but to copy, since the other guy is a const.
82 // In the case that the source were flat, we could get a reference, it
83 // would make some things faster, but not matter in many other cases.
118 84
119 appendChunk( pNew ); 85 joinShare( rSrc );
120 } 86 //copyFrom( rSrc );
87 }
121 88
122 void append( const chr *pData, long nLen ) 89 FBasicString( const MyType &rSrc, long nLength ) :
123 { 90 nLength( 0 ),
124 Chunk *pNew = newChunk( nLen ); 91 pnRefs( NULL ),
92 pFirst( NULL ),
93 pLast( NULL )
94 {
95 append( rSrc.pFirst->pData, nLength );
96 }
125 97
126 cpy( pNew->pData, pData, nLen ); 98 FBasicString( const MyType &rSrc, long nStart, long nLength ) :
99 nLength( 0 ),
100 pnRefs( NULL ),
101 pFirst( NULL ),
102 pLast( NULL )
103 {
104 append( rSrc.pFirst->pData+nStart, nLength );
105 }
127 106
128 appendChunk( pNew ); 107 FBasicString( long nSize ) :
129 } 108 nLength( nSize ),
109 pnRefs( NULL ),
110 pFirst( NULL ),
111 pLast( NULL )
112 {
113 pFirst = pLast = newChunk( nSize );
114 }
130 115
131 void prepend( const chr *pData ) 116 virtual ~FBasicString()
132 { 117 {
133 long nLen; 118 clear();
134 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); 119 }
135
136 Chunk *pNew = newChunk( nLen );
137 cpy( pNew->pData, pData, nLen );
138 120
139 prependChunk( pNew ); 121 /**
140 } 122 *@todo void append( const MyType & sData )
123 */
141 124
142 void prepend( const chr *pData, long nLen ) 125 /**
143 { 126 * Append data to your string.
144 Chunk *pNew = newChunk( nLen ); 127 *@param pData (const chr *) The data to append.
145 128 */
146 cpy( pNew->pData, pData, nLen ); 129 void append( const chr *pData )
130 {
131 if( !pData ) return;
132 long nLen;
133 for( nLen = 0; pData[nLen] != (chr)0; nLen++ );
134 if( nLen == 0 )
135 return;
136
137 Chunk *pNew = newChunk( nLen );
138 cpy( pNew->pData, pData, nLen );
147 139
148 prependChunk( pNew ); 140 appendChunk( pNew );
149 } 141 }
150 142
151 void clear() 143 /**
152 { 144 * Append data to your string.
153 realClear(); 145 *@param pData (const chr *) The data to append.
154 } 146 *@param nLen (long) The length of the data to append.
147 */
148 void append( const chr *pData, long nLen )
149 {
150 if( nLen == 0 )
151 return;
155 152
156 void resize( long nNewSize ) 153 Chunk *pNew = newChunk( nLen );
157 { 154
158 if( nLength == nNewSize ) 155 cpy( pNew->pData, pData, nLen );
159 return;
160
161 flatten();
162
163 Chunk *pNew = newChunk( nNewSize );
164 long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength);
165 cpy( pNew->pData, pFirst->pData, nNewLen );
166 pNew->pData[nNewLen] = (chr)0;
167 aChr.deallocate( pFirst->pData, pFirst->nLength+1 );
168 aChunk.deallocate( pFirst, 1 );
169 pFirst = pLast = pNew;
170 nLength = nNewSize;
171 }
172
173 long getSize() const
174 {
175 return nLength;
176 }
177
178 chr *getStr()
179 {
180 if( pFirst == NULL )
181 return NULL;
182
183 flatten();
184 return pFirst->pData;
185 }
186
187 const chr *getStr() const
188 {
189 if( pFirst == NULL )
190 return NULL;
191 156
192 flatten(); 157 appendChunk( pNew );
193 return pFirst->pData; 158 }
194 }
195 159
196 chr *c_str() 160 /**
197 { 161 * Append a single chr to your string.
198 if( pFirst == NULL ) 162 *@param cData (const chr &) The character to append.
199 return NULL; 163 */
200 164 void append( const chr &cData )
201 flatten(); 165 {
202 return pFirst->pData; 166 append( &cData, 1 );
203 } 167 }
204
205 const chr *c_str() const
206 {
207 if( pFirst == NULL )
208 return NULL;
209 168
210 flatten(); 169 /**
211 return pFirst->pData; 170 * Prepend another FString to this one.
212 } 171 *@param sData (MyType &) The FString to prepend.
172 */
173 void prepend( const MyType & sData )
174 {
175 prepend( sData.getStr(), sData.getSize() );
176 }
213 177
214 MyType &operator +=( const chr *pData ) 178 /**
215 { 179 * Prepend data to your string.
216 append( pData ); 180 *@param pData (const chr *) The data to prepend.
181 */
182 void prepend( const chr *pData )
183 {
184 long nLen;
185 for( nLen = 0; pData[nLen] != (chr)0; nLen++ );
186
187 Chunk *pNew = newChunk( nLen );
188 cpy( pNew->pData, pData, nLen );
217 189
218 return (*this); 190 prependChunk( pNew );
219 } 191 }
220
221 MyType &operator +=( const MyType &rSrc )
222 {
223 rSrc.flatten();
224 append( rSrc.pFirst->pData, rSrc.nLength );
225 192
226 return (*this); 193 /**
227 } 194 * Prepend data to your string.
195 *@param pData (const chr *) The data to prepend.
196 *@param nLen (long) The length of the data to prepend.
197 */
198 void prepend( const chr *pData, long nLen )
199 {
200 Chunk *pNew = newChunk( nLen );
201
202 cpy( pNew->pData, pData, nLen );
228 203
229 MyType &operator +=( const chr pData ) 204 prependChunk( pNew );
230 { 205 }
231 chr tmp[2] = { pData, (chr)0 };
232 append( tmp );
233 206
234 return (*this); 207 /**
235 } 208 *@todo void prepend( const chr &cData )
209 */
236 210
237 MyType &operator =( const chr *pData ) 211 /**
238 { 212 * Clear all data from the string.
239 clear(); 213 */
240 append( pData ); 214 void clear()
215 {
216 realClear();
217 }
241 218
242 return (*this); 219 /**
243 } 220 * Force the string to resize
221 *@param nNewSize (long) The new size of the string.
222 */
223 void resize( long nNewSize )
224 {
225 if( nLength == nNewSize )
226 return;
244 227
245 MyType &operator =( const MyType &rSrc ) 228 flatten();
246 { 229
247 //if( rSrc.isFlat() ) 230 Chunk *pNew = newChunk( nNewSize );
248 //{ 231 long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength);
249 joinShare( rSrc ); 232 cpy( pNew->pData, pFirst->pData, nNewLen );
250 //} 233 pNew->pData[nNewLen] = (chr)0;
251 //else 234 aChr.deallocate( pFirst->pData, pFirst->nLength+1 );
252 //{ 235 aChunk.deallocate( pFirst, 1 );
253 // copyFrom( rSrc ); 236 pFirst = pLast = pNew;
254 //} 237 nLength = nNewSize;
255 //
256
257 return (*this);
258 }
259
260 bool operator ==( const chr *pData ) const
261 {
262 if( pFirst == NULL ) {
263 if( pData == NULL )
264 return true;
265 return false;
266 } 238 }
267 239
268 flatten(); 240 /**
269 const chr *a = pData; 241 * Get the current size of the string.
270 chr *b = pFirst->pData; 242 *@returns (long) The current size of the string.
271 for( ; *a!=(chr)0; a++, b++ ) 243 */
244 long getSize() const
272 { 245 {
273 if( *a != *b ) 246 return nLength;
274 return false;
275 } 247 }
248
249 /**
250 * Get a pointer to the string array.
251 *@returns (chr *) The string data.
252 */
253 chr *getStr()
254 {
255 if( pFirst == NULL )
256 return NULL;
276 257
277 return true; 258 flatten();
278 } 259 return pFirst->pData;
279 260 }
280 bool operator ==( const MyType &pData ) const 261
281 { 262 /**
282 if( pFirst == pData.pFirst ) 263 * Get a const pointer to the string array.
283 return true; 264 *@returns (const chr *) The string data.
284 if( pFirst == NULL ) 265 */
285 return false; 266 const chr *getStr() const
267 {
268 if( pFirst == NULL )
269 return NULL;
270
271 flatten();
272 return pFirst->pData;
273 }
286 274
287 flatten(); 275 /**
288 pData.flatten(); 276 * (std::string compatability) Get a pointer to the string array.
289 const chr *a = pData.pFirst->pData; 277 *@returns (chr *) The string data.
290 chr *b = pFirst->pData; 278 */
291 for( ; *a!=(chr)0; a++, b++ ) 279 chr *c_str()
292 { 280 {
293 if( *a != *b ) 281 if( pFirst == NULL )
294 return false; 282 return NULL;
283
284 flatten();
285 return pFirst->pData;
295 } 286 }
287
288 /**
289 * (std::string compatability) Get a const pointer to the string array.
290 *@returns (const chr *) The string data.
291 */
292 const chr *c_str() const
293 {
294 if( pFirst == NULL )
295 return NULL;
296 296
297 return true; 297 flatten();
298 } 298 return pFirst->pData;
299 }
299 300
300 bool operator !=(const chr *pData ) const 301 /**
301 { 302 * Plus equals operator for FString.
302 return !(*this == pData); 303 *@param pData (const chr *) The data to append to your FString.
303 } 304 */
304 305 MyType &operator +=( const chr *pData )
305 bool operator !=(const MyType &pData ) const 306 {
306 { 307 append( pData );
307 return !(*this == pData);
308 }
309 308
310 chr &operator[]( long nIndex ) 309 return (*this);
311 { 310 }
312 flatten(); 311
312 /**
313 * Plus equals operator for FString.
314 *@param pData (const MyType &) The FString to append to your FString.
315 */
316 MyType &operator +=( const MyType &rSrc )
317 {
318 if( rSrc.nLength == 0 )
319 return (*this);
320 rSrc.flatten();
321 append( rSrc.pFirst->pData, rSrc.nLength );
313 322
314 return pFirst->pData[nIndex]; 323 return (*this);
315 } 324 }
316
317 const chr &operator[]( long nIndex ) const
318 {
319 flatten();
320 325
321 return pFirst->pData[nIndex]; 326 /**
322 } 327 * Plus equals operator for FString.
328 *@param pData (const chr) The character to append to your FString.
329 */
330 MyType &operator +=( const chr pData )
331 {
332 append( &pData, 1 );
323 333
324 bool isWS( long nIndex ) const 334 return (*this);
325 { 335 }
326 flatten();
327 336
328 return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t' 337 /**
329 || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n'; 338 * Assignment operator.
330 } 339 *@param pData (const chr *) The character array to append to your
340 * FString.
341 */
342 MyType &operator =( const chr *pData )
343 {
344 clear();
345 append( pData );
331 346
332 bool isAlpha( long nIndex ) const 347 return (*this);
333 { 348 }
334 flatten();
335 349
336 return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z') 350 /**
337 || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z'); 351 * Reset your FString to this character array.
338 } 352 *@param pData (const chr *) The character array to set your FString to.
353 */
354 void set( const chr *pData )
355 {
356 clear();
357 append( pData );
358 }
339 359
340 void toLower() 360 /**
341 { 361 * Reset your FString to this character array.
342 flatten(); 362 *@param pData (const chr *) The character array to set your FString to.
343 unShare(); 363 *@param nSize (long) The length of the inputted character array.
364 */
365 void set( const chr *pData, long nSize )
366 {
367 clear();
368 append( pData, nSize );
369 }
344 370
345 for( long j = 0; j < nLength; j++ ) 371 /**
372 * Assignment operator.
373 *@param rSrc (const MyType &) The FString to set your FString to.
374 */
375 MyType &operator =( const MyType &rSrc )
346 { 376 {
347 if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' ) 377 //if( rSrc.isFlat() )
348 pFirst->pData[j] -= 'A'-'a'; 378 //{
379 joinShare( rSrc );
380 //}
381 //else
382 //{
383 // copyFrom( rSrc );
384 //}
385 //
386
387 return (*this);
349 } 388 }
350 } 389
390 /**
391 * Equals comparison operator.
392 *@param pData (const chr *) The character array to compare your FString
393 * to.
394 */
395 bool operator ==( const chr *pData ) const
396 {
397 if( pFirst == NULL ) {
398 if( pData == NULL )
399 return true;
400 return false;
401 }
351 402
352 void toUpper() 403 flatten();
353 { 404 const chr *a = pData;
354 flatten(); 405 chr *b = pFirst->pData;
355 unShare(); 406 for( ; *a!=(chr)0; a++, b++ )
407 {
408 if( *a != *b )
409 return false;
410 }
356 411
357 for( long j = 0; j < nLength; j++ ) 412 return true;
413 }
414
415 /**
416 * Equals comparison operator.
417 *@param pData (const MyType &) The FString to compare your FString to.
418 */
419 bool operator ==( const MyType &pData ) const
358 { 420 {
359 if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' ) 421 if( pFirst == pData.pFirst )
360 pFirst->pData[j] += 'A'-'a'; 422 return true;
423 if( pFirst == NULL )
424 return false;
425
426 flatten();
427 pData.flatten();
428 const chr *a = pData.pFirst->pData;
429 chr *b = pFirst->pData;
430 for( ; *a!=(chr)0; a++, b++ )
431 {
432 if( *a != *b )
433 return false;
434 }
435
436 return true;
361 } 437 }
362 }
363 438
364 void serialize( class Serializer &ar ) 439 /**
365 { 440 * Not equals comparison operator.
366 if( ar.isLoading() ) 441 *@param pData (const chr *) The character array to compare your FString
442 * to.
443 */
444 bool operator !=(const chr *pData ) const
367 { 445 {
368 clear(); 446 return !(*this == pData);
369 long nLen; 447 }
370 ar >> nLen;
371 448
372 Chunk *pNew = newChunk( nLen ); 449 /**
373 ar.read( pNew->pData, nLen*sizeof(chr) ); 450 * Not equals comparison operator.
374 appendChunk( pNew ); 451 *@param pData (const MyType &) The FString to compare your FString to.
452 */
453 bool operator !=(const MyType &pData ) const
454 {
455 return !(*this == pData);
375 } 456 }
376 else 457
458 /**
459 * Indexing operator
460 *@param nIndex (long) The index of the character you want.
461 *@returns (chr &) The character at position (nIndex).
462 */
463 chr &operator[]( long nIndex )
377 { 464 {
378 flatten(); 465 flatten();
379 466
380 ar << nLength; 467 return pFirst->pData[nIndex];
381 ar.write( pFirst->pData, nLength*sizeof(chr) );
382 } 468 }
383 } 469
470 /**
471 * Const indexing operator
472 *@param nIndex (long) The index of the character you want.
473 *@returns (const chr &) The character at position (nIndex).
474 */
475 const chr &operator[]( long nIndex ) const
476 {
477 flatten();
384 478
385private: 479 return pFirst->pData[nIndex];
386 void flatten() const 480 }
387 { 481/*
388 if( isFlat() ) 482 operator const chr *() const
389 return; 483 {
484 if( !pFirst ) return NULL;
485 flatten();
486 return pFirst->pData;
487 }
488 */
390 489
391 if( pFirst == NULL ) 490 operator bool() const
392 return; 491 {
492 return (pFirst != NULL);
493 }
393 494
394 unShare(); 495 bool isSet() const
496 {
497 return (pFirst != NULL);
498 }
395 499
396 Chunk *pNew = newChunk( nLength ); 500 /**
397 chr *pos = pNew->pData; 501 * Is the character at index (nIndex) white space?
398 Chunk *i = pFirst; 502 *@param nIndex (long) The index of the character you want to check.
399 for(;;) 503 *@returns (bool) Is it white space?
504 */
505 bool isWS( long nIndex ) const
400 { 506 {
401 cpy( pos, i->pData, i->nLength ); 507 flatten();
402 pos += i->nLength; 508
403 i = i->pNext; 509 return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t'
404 if( i == NULL ) 510 || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n';
405 break;
406 } 511 }
407 realClear();
408 512
409 pLast = pFirst = pNew; 513 /**
410 nLength = pNew->nLength; 514 * Is the character at index (nIndex) a letter?
411 } 515 *@param nIndex (long) The index of the character you want to check.
412 516 *@returns (bool) Is it a letter?
413 void realClear() const 517 */
414 { 518 bool isAlpha( long nIndex ) const
415 if( pFirst == NULL ) 519 {
416 return; 520 flatten();
417 521
418 if( isShared() ) 522 return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z')
523 || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z');
524 }
525
526 /**
527 * Convert your alpha characters to lower case.
528 */
529 void toLower()
419 { 530 {
420 decRefs(); 531 flatten();
532 unShare();
533
534 for( long j = 0; j < nLength; j++ )
535 {
536 if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' )
537 pFirst->pData[j] -= 'A'-'a';
538 }
539 }
540
541 /**
542 * Convert your alpha characters to upper case.
543 */
544 void toUpper()
545 {
546 flatten();
547 unShare();
548
549 for( long j = 0; j < nLength; j++ )
550 {
551 if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' )
552 pFirst->pData[j] += 'A'-'a';
553 }
554 }
555
556 /**
557 * Find the index of the first occurrance of (sText)
558 *@param sText (const char *) The string to search for.
559 *@returns (long) The index of the first occurrance. -1 for not found.
560 */
561 long find( const char *sText )
562 {
563 long nTLen = strlen( sText );
564 flatten();
565 for( long j = 0; j < pFirst->nLength-nTLen; j++ )
566 {
567 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
568 return j;
569 }
570 return -1;
571 }
572
573 /**
574 * Do a reverse search for (sText)
575 *@param sText (const char *) The string to search for.
576 *@returns (long) The index of the last occurrance. -1 for not found.
577 */
578 long rfind( const char *sText )
579 {
580 long nTLen = strlen( sText );
581 flatten();
582 for( long j = pFirst->nLength-nTLen-1; j >= 0; j-- )
583 {
584 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
585 return j;
586 }
587 return -1;
588 }
589
590 /**
591 * Remove nAmnt bytes from the front of the string. This function
592 * operates in O(n) time and should be used sparingly.
593 */
594 void trimFront( long nAmnt )
595 {
596 long nNewLen = nLength - nAmnt;
597 flatten();
598 Chunk *pNew = newChunk( nNewLen );
599 cpy( pNew->pData, pFirst->pData, nNewLen );
600 clear();
601 appendChunk( pNew );
602 }
603
604 /**
605 * Function the archiver calls to archive your FString.
606 *@param ar (Archive) The archive which is archiving your FString.
607 */
608 void archive( class Archive &ar )
609 {
610 if( ar.isLoading() )
611 {
612 clear();
613 long nLen;
614 ar >> nLen;
615
616 if( nLen > 0 )
617 {
618 Chunk *pNew = newChunk( nLen );
619 ar.read( pNew->pData, nLen*sizeof(chr) );
620 appendChunk( pNew );
621 }
622 }
623 else
624 {
625 flatten();
626
627 ar << nLength;
628 if( nLength )
629 ar.write( pFirst->pData, nLength*sizeof(chr) );
630 }
421 } 631 }
422 else 632
633 private:
634 void flatten() const
423 { 635 {
636 if( isFlat() )
637 return;
638
639 if( pFirst == NULL )
640 return;
641
642 unShare();
643
644 Chunk *pNew = newChunk( nLength );
645 chr *pos = pNew->pData;
424 Chunk *i = pFirst; 646 Chunk *i = pFirst;
425 for(;;) 647 for(;;)
426 { 648 {
427 Chunk *n = i->pNext; 649 cpy( pos, i->pData, i->nLength );
428 aChr.deallocate( i->pData, i->nLength+1 ); 650 pos += i->nLength;
429 aChunk.deallocate( i, 1 ); 651 i = i->pNext;
430 if( n == NULL ) 652 if( i == NULL )
431 break; 653 break;
432 i = n;
433 } 654 }
434 pFirst = pLast = NULL; 655 realClear();
435 nLength = 0; 656
657 pLast = pFirst = pNew;
658 nLength = pNew->nLength;
436 } 659 }
437 }
438
439 void copyFrom( const FBasicString<chr, chralloc, chunkalloc> &rSrc )
440 {
441 if( rSrc.pFirst == NULL )
442 return;
443 660
444 decRefs(); 661 void realClear() const
445
446 Chunk *pNew = newChunk( rSrc.nLength );
447 chr *pos = pNew->pData;
448 Chunk *i = rSrc.pFirst;
449 for(;;)
450 { 662 {
451 cpy( pos, i->pData, i->nLength ); 663 if( pFirst == NULL )
452 pos += i->nLength; 664 return;
453 i = i->pNext;
454 if( i == NULL )
455 break;
456 }
457 clear();
458 665
459 appendChunk( pNew ); 666 if( isShared() )
460 } 667 {
461 668 decRefs();
462 bool isFlat() const 669 }
463 { 670 else
464 return (pFirst == pLast); 671 {
465 } 672 Chunk *i = pFirst;
466 673 for(;;)
467 bool isShared() const 674 {
468 { 675 Chunk *n = i->pNext;
469 return (pnRefs != NULL); 676 aChr.deallocate( i->pData, i->nLength+1 );
470 } 677 aChunk.deallocate( i, 1 );
678 if( n == NULL )
679 break;
680 i = n;
681 }
682 pFirst = pLast = NULL;
683 nLength = 0;
684 }
685 }
686
687 void copyFrom( const FBasicString<chr, nMinSize, chralloc, chunkalloc> &rSrc )
688 {
689 if( rSrc.pFirst == NULL )
690 return;
691
692 decRefs();
471 693
472 Chunk *newChunk() const 694 Chunk *pNew = newChunk( rSrc.nLength );
473 { 695 chr *pos = pNew->pData;
474 Chunk *pNew = aChunk.allocate( 1 ); 696 Chunk *i = rSrc.pFirst;
475 pNew->pNext = NULL; 697 for(;;)
476 return pNew; 698 {
477 } 699 cpy( pos, i->pData, i->nLength );
478 700 pos += i->nLength;
479 Chunk *newChunk( long nLen ) const 701 i = i->pNext;
480 { 702 if( i == NULL )
481 Chunk *pNew = aChunk.allocate( 1 ); 703 break;
482 pNew->pNext = NULL; 704 }
483 pNew->nLength = nLen; 705 clear();
484 pNew->pData = aChr.allocate( nLen+1 );
485 pNew->pData[nLen] = (chr)0;
486 return pNew;
487 }
488
489 void appendChunk( Chunk *pNewChunk )
490 {
491 unShare();
492 706
493 if( pFirst == NULL ) 707 appendChunk( pNew );
494 pLast = pFirst = pNewChunk; 708 }
495 else 709
710 bool isFlat() const
496 { 711 {
497 pLast->pNext = pNewChunk; 712 return (pFirst == pLast);
498 pLast = pNewChunk;
499 } 713 }
500 714
501 nLength += pNewChunk->nLength; 715 bool isShared() const
502 } 716 {
503 717 return (pnRefs != NULL);
504 void prependChunk( Chunk *pNewChunk ) 718 }
505 {
506 unShare();
507 719
508 if( pFirst == NULL ) 720 Chunk *newChunk() const
509 pLast = pFirst = pNewChunk; 721 {
510 else 722 Chunk *pNew = aChunk.allocate( 1 );
723 pNew->pNext = NULL;
724 return pNew;
725 }
726
727 Chunk *newChunk( long nLen ) const
511 { 728 {
512 pNewChunk->pNext = pFirst; 729 Chunk *pNew = aChunk.allocate( 1 );
513 pFirst = pNewChunk; 730 pNew->pNext = NULL;
731 pNew->nLength = nLen;
732 pNew->pData = aChr.allocate( nLen+1 );
733 pNew->pData[nLen] = (chr)0;
734 return pNew;
514 } 735 }
515 736
516 nLength += pNewChunk->nLength; 737 void appendChunk( Chunk *pNewChunk )
517 } 738 {
739 unShare();
518 740
519 void joinShare( MyType &rSrc ) 741 if( pFirst == NULL )
520 { 742 pLast = pFirst = pNewChunk;
521 clear(); 743 else
744 {
745 pLast->pNext = pNewChunk;
746 pLast = pNewChunk;
747 }
522 748
523 if( !rSrc.isFlat() ) 749 nLength += pNewChunk->nLength;
524 rSrc.flatten(); 750 }
751
752 void prependChunk( Chunk *pNewChunk )
753 {
754 unShare();
525 755
526 rSrc.initCount(); 756 if( pFirst == NULL )
527 pnRefs = rSrc.pnRefs; 757 pLast = pFirst = pNewChunk;
528 (*pnRefs)++; 758 else
529 nLength = rSrc.nLength; 759 {
530 pFirst = rSrc.pFirst; 760 pNewChunk->pNext = pFirst;
531 pLast = rSrc.pLast; 761 pFirst = pNewChunk;
532 } 762 }
533
534 void joinShare( const MyType &rSrc )
535 {
536 clear();
537 763
538 rSrc.flatten(); 764 nLength += pNewChunk->nLength;
765 }
539 766
540 if( !rSrc.isShared() ) 767 void joinShare( MyType &rSrc )
541 { 768 {
542 rSrc.pnRefs = new uint32_t; 769 clear();
543 (*rSrc.pnRefs) = 1; 770
771 if( !rSrc.isFlat() )
772 rSrc.flatten();
773
774 rSrc.initCount();
775 pnRefs = rSrc.pnRefs;
776 (*pnRefs)++;
777 nLength = rSrc.nLength;
778 pFirst = rSrc.pFirst;
779 pLast = rSrc.pLast;
544 } 780 }
545 pnRefs = rSrc.pnRefs; 781
546 (*pnRefs)++; 782 void joinShare( const MyType &rSrc )
547 nLength = rSrc.nLength; 783 {
548 pFirst = rSrc.pFirst; 784 clear();
549 pLast = rSrc.pLast;
550 }
551 785
552 /** 786 rSrc.flatten();
553 * This takes an object that was shared and makes a copy of the base data
554 * that was being shared so that this copy can be changed. This should be
555 * added before any call that will change this object;
556 */
557 void unShare() const
558 {
559 if( isShared() == false )
560 return;
561 787
562 Chunk *pNew = newChunk( nLength ); 788 if( !rSrc.isShared() )
563 chr *pos = pNew->pData; 789 {
564 Chunk *i = pFirst; 790 rSrc.pnRefs = new uint32_t;
565 for(;;) 791 (*rSrc.pnRefs) = 1;
792 }
793 pnRefs = rSrc.pnRefs;
794 (*pnRefs)++;
795 nLength = rSrc.nLength;
796 pFirst = rSrc.pFirst;
797 pLast = rSrc.pLast;
798 }
799
800 /**
801 * This takes an object that was shared and makes a copy of the base data
802 * that was being shared so that this copy can be changed. This should be
803 * added before any call that will change this object;
804 */
805 void unShare() const
566 { 806 {
567 cpy( pos, i->pData, i->nLength ); 807 if( isShared() == false )
568 pos += i->nLength; 808 return;
569 i = i->pNext; 809 if( pFirst == NULL )
570 if( i == NULL ) 810 return;
571 break; 811
812 Chunk *pNew = newChunk( nLength );
813 chr *pos = pNew->pData;
814 Chunk *i = pFirst;
815 for(;;)
816 {
817 cpy( pos, i->pData, i->nLength );
818 pos += i->nLength;
819 i = i->pNext;
820 if( i == NULL )
821 break;
822 }
823 decRefs();
824 pLast = pFirst = pNew;
825 nLength = pNew->nLength;
572 } 826 }
573 decRefs();
574 pLast = pFirst = pNew;
575 nLength = pNew->nLength;
576 }
577 827
578 /** 828 /**
579 * This decrements our ref count and pulls us out of the share. If the ref 829 * This decrements our ref count and pulls us out of the share. If the ref
580 * count hits zero because of this, it destroys the share. This is not 830 * count hits zero because of this, it destroys the share. This is not
581 * safe to call on it's own, it's much better to call unShare. 831 * safe to call on it's own, it's much better to call unShare.
582 */ 832 */
583 void decRefs() const 833 void decRefs() const
584 {
585 if( isShared() )
586 { 834 {
587 (*pnRefs)--; 835 if( isShared() )
588 if( (*pnRefs) == 0 )
589 destroyShare();
590 else
591 { 836 {
592 pnRefs = NULL; 837 (*pnRefs)--;
593 pFirst = NULL; 838 if( (*pnRefs) == 0 )
594 pLast = NULL; 839 destroyShare();
595 nLength = 0; 840 else
841 {
842 pnRefs = NULL;
843 pFirst = NULL;
844 pLast = NULL;
845 nLength = 0;
846 }
596 } 847 }
597 } 848 }
598 }
599 849
600 /** 850 /**
601 * While the unShare function removes an instance from a share, this 851 * While the unShare function removes an instance from a share, this
602 * function destroys the data that was in the share, removing the share 852 * function destroys the data that was in the share, removing the share
603 * itself. This should only be called when the refcount for the share has 853 * itself. This should only be called when the refcount for the share has
604 * or is about to reach zero. 854 * or is about to reach zero.
605 */ 855 */
606 void destroyShare() const 856 void destroyShare() const
607 { 857 {
608 delete pnRefs; 858 delete pnRefs;
609 pnRefs = NULL; 859 pnRefs = NULL;
610 realClear(); 860 realClear();
611 } 861 }
612 862
613#ifdef VALTEST 863#ifdef VALTEST
614 void cpy( chr *dest, const chr *src, long count ) const 864 void cpy( chr *dest, const chr *src, long count ) const
615 {
616 for( int j = 0; j < count; j++ )
617 { 865 {
618 *dest = *src; 866 for( int j = 0; j < count; j++ )
619 dest++; 867 {
620 src++; 868 *dest = *src;
869 dest++;
870 src++;
871 }
621 } 872 }
622 }
623#endif 873#endif
624 874
625 void initCount() const 875 void initCount() const
626 {
627 if( !isShared() )
628 { 876 {
629 pnRefs = new uint32_t; 877 if( !isShared() )
630 (*pnRefs) = 1; 878 {
879 pnRefs = new uint32_t;
880 (*pnRefs) = 1;
881 }
631 } 882 }
632 }
633 883
634private: 884 private:
635 mutable long nLength; 885 mutable long nLength;
636 mutable uint32_t *pnRefs; 886 mutable uint32_t *pnRefs;
637 mutable Chunk *pFirst; 887 mutable Chunk *pFirst;
638 mutable Chunk *pLast; 888 mutable Chunk *pLast;
639 889
640 mutable chralloc aChr; 890 mutable chralloc aChr;
641 mutable chunkalloc aChunk; 891 mutable chunkalloc aChunk;
642}; 892 };
643 893
644typedef FBasicString<char> FString; 894 typedef FBasicString<char> FString;
645 895
646#include "hash.h" 896 template<> uint32_t __calcHashCode<FString>( const FString &k );
647template<> uint32_t __calcHashCode<FString>( const FString &k ); 897 template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b );
648template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ); 898}
649 899
900#include <ostream>
901std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FString &val );
650 902
651#endif 903#endif
diff --git a/src/hash.cpp b/src/hash.cpp
index c52e6b1..a207c29 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -1,29 +1,29 @@
1#include "hash.h" 1#include "hash.h"
2 2
3subExceptionDef( HashException ) 3namespace Bu { subExceptionDef( HashException ) }
4 4
5template<> uint32_t __calcHashCode<int>( const int &k ) 5template<> uint32_t Bu::__calcHashCode<int>( const int &k )
6{ 6{
7 return k; 7 return k;
8} 8}
9 9
10template<> bool __cmpHashKeys<int>( const int &a, const int &b ) 10template<> bool Bu::__cmpHashKeys<int>( const int &a, const int &b )
11{ 11{
12 return a == b; 12 return a == b;
13} 13}
14 14
15template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k ) 15template<> uint32_t Bu::__calcHashCode<unsigned int>( const unsigned int &k )
16{ 16{
17 return k; 17 return k;
18} 18}
19 19
20template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b ) 20template<> bool Bu::__cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b )
21{ 21{
22 return a == b; 22 return a == b;
23} 23}
24 24
25template<> 25template<>
26uint32_t __calcHashCode<const char *>( const char * const &k ) 26uint32_t Bu::__calcHashCode<const char *>( const char * const &k )
27{ 27{
28 if (k == NULL) 28 if (k == NULL)
29 { 29 {
@@ -39,7 +39,7 @@ uint32_t __calcHashCode<const char *>( const char * const &k )
39 return nPos; 39 return nPos;
40} 40}
41 41
42template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b ) 42template<> bool Bu::__cmpHashKeys<const char *>( const char * const &a, const char * const &b )
43{ 43{
44 if( a == b ) 44 if( a == b )
45 return true; 45 return true;
@@ -52,7 +52,7 @@ template<> bool __cmpHashKeys<const char *>( const char * const &a, const char *
52} 52}
53 53
54template<> 54template<>
55uint32_t __calcHashCode<char *>( char * const &k ) 55uint32_t Bu::__calcHashCode<char *>( char * const &k )
56{ 56{
57 if (k == NULL) 57 if (k == NULL)
58 { 58 {
@@ -68,7 +68,7 @@ uint32_t __calcHashCode<char *>( char * const &k )
68 return nPos; 68 return nPos;
69} 69}
70 70
71template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b ) 71template<> bool Bu::__cmpHashKeys<char *>( char * const &a, char * const &b )
72{ 72{
73 if( a == b ) 73 if( a == b )
74 return true; 74 return true;
@@ -80,7 +80,7 @@ template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b )
80 return false; 80 return false;
81} 81}
82 82
83template<> uint32_t __calcHashCode<std::string>( const std::string &k ) 83template<> uint32_t Bu::__calcHashCode<std::string>( const std::string &k )
84{ 84{
85 std::string::size_type j, sz = k.size(); 85 std::string::size_type j, sz = k.size();
86 const char *s = k.c_str(); 86 const char *s = k.c_str();
@@ -94,20 +94,8 @@ template<> uint32_t __calcHashCode<std::string>( const std::string &k )
94 return nPos; 94 return nPos;
95} 95}
96 96
97template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b ) 97template<> bool Bu::__cmpHashKeys<std::string>( const std::string &a, const std::string &b )
98{ 98{
99 return a == b; 99 return a == b;
100} 100}
101 101
102template<> uint32_t __calcHashCode<Hashable>( const Hashable &k )
103{
104 return 0;
105 //return k.getHashCode();
106}
107
108template<> bool __cmpHashKeys<Hashable>( const Hashable &a, const Hashable &b )
109{
110 return false;
111 //return a.compareForHash( b );
112}
113
diff --git a/src/hash.h b/src/hash.h
index a21d651..f183823 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -1,745 +1,1071 @@
1#ifndef HASH_H 1#ifndef BU_HASH_H
2#define HASH_H 2#define BU_HASH_H
3 3
4#include <stddef.h> 4#include <stddef.h>
5#include <string.h> 5#include <string.h>
6#include <memory> 6#include <memory>
7#include <iostream> 7#include <iostream>
8#include <list> 8#include <list>
9#include "exceptionbase.h" 9#include <utility>
10#include "hashable.h" 10#include "bu/exceptionbase.h"
11#include "serializable.h" 11#include "bu/list.h"
12#include "serializer.h" 12///#include "archival.h"
13///#include "archive.h"
13 14
14#define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) 15#define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0))
15 16
16subExceptionDecl( HashException ) 17namespace Bu
17
18enum eHashException
19{ 18{
20 excodeNotFilled 19 subExceptionDecl( HashException )
21};
22
23template<typename T>
24uint32_t __calcHashCode( const T &k );
25
26template<typename T>
27bool __cmpHashKeys( const T &a, const T &b );
28 20
29struct __calcNextTSize_fast 21 enum eHashException
30{
31 uint32_t operator()( uint32_t nCapacity, uint32_t nFill, uint32_t nDeleted ) const
32 { 22 {
33 if( nDeleted >= nCapacity/2 ) 23 excodeNotFilled
34 return nCapacity; 24 };
35 return nCapacity*2+1;
36 }
37};
38 25
39template<typename key, typename value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<value>, typename challoc = std::allocator<uint32_t> > 26 template<typename T>
40class Hash; 27 uint32_t __calcHashCode( const T &k );
41 28
42template< typename key, typename _value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<_value>, typename challoc = std::allocator<uint32_t> > 29 template<typename T>
43struct HashProxy 30 bool __cmpHashKeys( const T &a, const T &b );
44{
45 friend class Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc>;
46private:
47 HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, key *k, uint32_t nPos, uint32_t hash ) :
48 hsh( h ),
49 pKey( k ),
50 nPos( nPos ),
51 hash( hash ),
52 bFilled( false )
53 {
54 }
55 31
56 HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, uint32_t nPos, _value *pValue ) : 32 struct __calcNextTSize_fast
57 hsh( h ),
58 nPos( nPos ),
59 pValue( pValue ),
60 bFilled( true )
61 { 33 {
62 } 34 uint32_t operator()( uint32_t nCapacity, uint32_t nFill, uint32_t nDeleted ) const
35 {
36 if( nDeleted >= nCapacity/2 )
37 return nCapacity;
38 return nCapacity*2+1;
39 }
40 };
63 41
64 Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &hsh; 42 template<typename key, typename value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<value>, typename challoc = std::allocator<uint32_t> >
65 key *pKey; 43 class Hash;
66 uint32_t nPos;
67 _value *pValue;
68 uint32_t hash;
69 bool bFilled;
70 44
71public: 45 template< typename key, typename _value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<_value>, typename challoc = std::allocator<uint32_t> >
72 operator _value &() 46 struct HashProxy
73 { 47 {
74 if( bFilled == false ) 48 friend class Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc>;
75 throw HashException( 49 private:
76 excodeNotFilled, 50 HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, key *k, uint32_t nPos, uint32_t hash ) :
77 "No data assosiated with that key." 51 hsh( h ),
78 ); 52 pKey( k ),
79 return *pValue; 53 nPos( nPos ),
80 } 54 hash( hash ),
55 bFilled( false )
56 {
57 }
81 58
82 _value &value() 59 HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, uint32_t nPos, _value *pValue ) :
83 { 60 hsh( h ),
84 if( bFilled == false ) 61 nPos( nPos ),
85 throw HashException( 62 pValue( pValue ),
86 excodeNotFilled, 63 bFilled( true )
87 "No data assosiated with that key." 64 {
88 ); 65 }
89 return *pValue;
90 }
91 66
92 bool isFilled() 67 Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &hsh;
93 { 68 key *pKey;
94 return bFilled; 69 uint32_t nPos;
95 } 70 _value *pValue;
71 uint32_t hash;
72 bool bFilled;
96 73
97 void erase() 74 public:
98 { 75 /**
99 if( bFilled ) 76 * Cast operator for HashProxy.
77 *@returns (value_type &) The value the HashProxy is pointing to.
78 */
79 operator _value &()
100 { 80 {
101 hsh._erase( nPos ); 81 if( bFilled == false )
102 hsh.onDelete(); 82 throw HashException(
83 excodeNotFilled,
84 "No data assosiated with that key."
85 );
86 return *pValue;
103 } 87 }
104 }
105 88
106 _value operator=( _value nval ) 89 /**
107 { 90 * Direct function for retrieving a value out of the HashProxy.
108 if( bFilled ) 91 *@returns (value_type &) The value pointed to by this HashProxy.
92 */
93 _value &value()
109 { 94 {
110 hsh.va.destroy( pValue ); 95 if( bFilled == false )
111 hsh.va.construct( pValue, nval ); 96 throw HashException(
112 hsh.onUpdate(); 97 excodeNotFilled,
98 "No data assosiated with that key."
99 );
100 return *pValue;
113 } 101 }
114 else 102
103 /**
104 * Whether this HashProxy points to something real or not.
105 */
106 bool isFilled()
115 { 107 {
116 hsh.fill( nPos, *pKey, nval, hash ); 108 return bFilled;
117 hsh.onInsert();
118 } 109 }
119 110
120 return nval; 111 /**
121 } 112 * Erase the data pointed to by this HashProxy.
113 */
114 void erase()
115 {
116 if( bFilled )
117 {
118 hsh._erase( nPos );
119 hsh.onDelete();
120 }
121 }
122 122
123 _value *operator->() 123 /**
124 { 124 * Assign data to this point in the hash table.
125 if( bFilled == false ) 125 *@param nval (value_type) the data to assign.
126 throw HashException( 126 */
127 excodeNotFilled, 127 _value operator=( _value nval )
128 "No data assosiated with that key." 128 {
129 ); 129 if( bFilled )
130 return pValue; 130 {
131 } 131 hsh.va.destroy( pValue );
132}; 132 hsh.va.construct( pValue, nval );
133 hsh.onUpdate();
134 }
135 else
136 {
137 hsh.fill( nPos, *pKey, nval, hash );
138 hsh.onInsert();
139 }
133 140
134template<typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc > 141 return nval;
135class Hash 142 }
136{
137 friend struct HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>;
138public:
139 Hash() :
140 nCapacity( 11 ),
141 nFilled( 0 ),
142 nDeleted( 0 ),
143 bFilled( NULL ),
144 bDeleted( NULL ),
145 aKeys( NULL ),
146 aValues( NULL ),
147 aHashCodes( NULL )
148 {
149 nKeysSize = bitsToBytes( nCapacity );
150 bFilled = ca.allocate( nKeysSize );
151 bDeleted = ca.allocate( nKeysSize );
152 clearBits();
153
154 aHashCodes = ca.allocate( nCapacity );
155 aKeys = ka.allocate( nCapacity );
156 aValues = va.allocate( nCapacity );
157 }
158 143
159 Hash( const Hash &src ) : 144 /**
160 nCapacity( src.nCapacity ), 145 * Pointer extraction operator. Access to members of data pointed to
161 nFilled( 0 ), 146 * by HashProxy.
162 nDeleted( 0 ), 147 *@returns (value_type *)
163 bFilled( NULL ), 148 */
164 bDeleted( NULL ), 149 _value *operator->()
165 aKeys( NULL ), 150 {
166 aValues( NULL ), 151 if( bFilled == false )
167 aHashCodes( NULL ) 152 throw HashException(
168 { 153 excodeNotFilled,
169 nKeysSize = bitsToBytes( nCapacity ); 154 "No data assosiated with that key."
170 bFilled = ca.allocate( nKeysSize ); 155 );
171 bDeleted = ca.allocate( nKeysSize ); 156 return pValue;
172 clearBits(); 157 }
158 };
173 159
174 aHashCodes = ca.allocate( nCapacity ); 160 /**
175 aKeys = ka.allocate( nCapacity ); 161 * Libbu Template Hash Table
176 aValues = va.allocate( nCapacity ); 162 *@param key (typename) The datatype of the hashtable keys
163 *@param value (typename) The datatype of the hashtable data
164 *@param sizecalc (typename) Functor to compute new table size on rehash
165 *@param keyalloc (typename) Memory allocator for hashtable keys
166 *@param valuealloc (typename) Memory allocator for hashtable values
167 *@param challoc (typename) Byte allocator for bitflags
168 */
169 template<typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc >
170 class Hash
171 {
172 friend struct HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>;
173 public:
174 Hash() :
175 nCapacity( 11 ),
176 nFilled( 0 ),
177 nDeleted( 0 ),
178 bFilled( NULL ),
179 bDeleted( NULL ),
180 aKeys( NULL ),
181 aValues( NULL ),
182 aHashCodes( NULL )
183 {
184 nKeysSize = bitsToBytes( nCapacity );
185 bFilled = ca.allocate( nKeysSize );
186 bDeleted = ca.allocate( nKeysSize );
187 clearBits();
188
189 aHashCodes = ca.allocate( nCapacity );
190 aKeys = ka.allocate( nCapacity );
191 aValues = va.allocate( nCapacity );
192 }
177 193
178 for( uint32_t j = 0; j < src.nCapacity; j++ ) 194 Hash( const Hash &src ) :
195 nCapacity( src.nCapacity ),
196 nFilled( 0 ),
197 nDeleted( 0 ),
198 bFilled( NULL ),
199 bDeleted( NULL ),
200 aKeys( NULL ),
201 aValues( NULL ),
202 aHashCodes( NULL )
179 { 203 {
180 if( src.isFilled( j ) ) 204 nKeysSize = bitsToBytes( nCapacity );
205 bFilled = ca.allocate( nKeysSize );
206 bDeleted = ca.allocate( nKeysSize );
207 clearBits();
208
209 aHashCodes = ca.allocate( nCapacity );
210 aKeys = ka.allocate( nCapacity );
211 aValues = va.allocate( nCapacity );
212
213 for( uint32_t j = 0; j < src.nCapacity; j++ )
181 { 214 {
182 insert( src.aKeys[j], src.aValues[j] ); 215 if( src.isFilled( j ) )
216 {
217 insert( src.aKeys[j], src.aValues[j] );
218 }
183 } 219 }
184 } 220 }
185 }
186 221
187 Hash &operator=( const Hash &src ) 222 /**
188 { 223 * Hashtable assignment operator. Clears this hashtable and
189 for( uint32_t j = 0; j < nCapacity; j++ ) 224 * copies RH into it.
225 */
226 Hash &operator=( const Hash &src )
190 { 227 {
191 if( isFilled( j ) ) 228 for( uint32_t j = 0; j < nCapacity; j++ )
192 if( !isDeleted( j ) ) 229 {
230 if( isFilled( j ) )
231 if( !isDeleted( j ) )
232 {
233 va.destroy( &aValues[j] );
234 ka.destroy( &aKeys[j] );
235 }
236 }
237 va.deallocate( aValues, nCapacity );
238 ka.deallocate( aKeys, nCapacity );
239 ca.deallocate( bFilled, nKeysSize );
240 ca.deallocate( bDeleted, nKeysSize );
241 ca.deallocate( aHashCodes, nCapacity );
242
243 nFilled = 0;
244 nDeleted = 0;
245 nCapacity = src.nCapacity;
246 nKeysSize = bitsToBytes( nCapacity );
247 bFilled = ca.allocate( nKeysSize );
248 bDeleted = ca.allocate( nKeysSize );
249 clearBits();
250
251 aHashCodes = ca.allocate( nCapacity );
252 aKeys = ka.allocate( nCapacity );
253 aValues = va.allocate( nCapacity );
254
255 for( uint32_t j = 0; j < src.nCapacity; j++ )
256 {
257 if( src.isFilled( j ) )
193 { 258 {
194 va.destroy( &aValues[j] ); 259 insert( src.aKeys[j], src.aValues[j] );
195 ka.destroy( &aKeys[j] );
196 } 260 }
197 } 261 }
198 va.deallocate( aValues, nCapacity );
199 ka.deallocate( aKeys, nCapacity );
200 ca.deallocate( bFilled, nKeysSize );
201 ca.deallocate( bDeleted, nKeysSize );
202 ca.deallocate( aHashCodes, nCapacity );
203
204 nFilled = 0;
205 nDeleted = 0;
206 nCapacity = src.nCapacity;
207 nKeysSize = bitsToBytes( nCapacity );
208 bFilled = ca.allocate( nKeysSize );
209 bDeleted = ca.allocate( nKeysSize );
210 clearBits();
211 262
212 aHashCodes = ca.allocate( nCapacity ); 263 return *this;
213 aKeys = ka.allocate( nCapacity ); 264 }
214 aValues = va.allocate( nCapacity );
215 265
216 for( uint32_t j = 0; j < src.nCapacity; j++ ) 266 virtual ~Hash()
217 { 267 {
218 if( src.isFilled( j ) ) 268 for( uint32_t j = 0; j < nCapacity; j++ )
219 { 269 {
220 insert( src.aKeys[j], src.aValues[j] ); 270 if( isFilled( j ) )
271 if( !isDeleted( j ) )
272 {
273 va.destroy( &aValues[j] );
274 ka.destroy( &aKeys[j] );
275 }
221 } 276 }
277 va.deallocate( aValues, nCapacity );
278 ka.deallocate( aKeys, nCapacity );
279 ca.deallocate( bFilled, nKeysSize );
280 ca.deallocate( bDeleted, nKeysSize );
281 ca.deallocate( aHashCodes, nCapacity );
222 } 282 }
223 283
224 return *this; 284 /**
225 } 285 * Get the current hash table capacity. (Changes at re-hash)
226 286 *@returns (uint32_t) The current capacity.
227 virtual ~Hash() 287 */
228 { 288 uint32_t getCapacity()
229 for( uint32_t j = 0; j < nCapacity; j++ )
230 { 289 {
231 if( isFilled( j ) ) 290 return nCapacity;
232 if( !isDeleted( j ) )
233 {
234 va.destroy( &aValues[j] );
235 ka.destroy( &aKeys[j] );
236 }
237 } 291 }
238 va.deallocate( aValues, nCapacity );
239 ka.deallocate( aKeys, nCapacity );
240 ca.deallocate( bFilled, nKeysSize );
241 ca.deallocate( bDeleted, nKeysSize );
242 ca.deallocate( aHashCodes, nCapacity );
243 }
244 292
245 uint32_t getCapacity() 293 /**
246 { 294 * Get the number of hash locations spoken for. (Including
247 return nCapacity; 295 * not-yet-cleaned-up deleted items.)
248 } 296 *@returns (uint32_t) The current fill state.
297 */
298 uint32_t getFill()
299 {
300 return nFilled;
301 }
249 302
250 uint32_t getFill() 303 /**
251 { 304 * Get the number of items stored in the hash table.
252 return nFilled; 305 *@returns (uint32_t) The number of items stored in the hash table.
253 } 306 */
307 uint32_t size()
308 {
309 return nFilled-nDeleted;
310 }
254 311
255 uint32_t size() 312 /**
256 { 313 * Get the number of items which have been deleted, but not yet
257 return nFilled-nDeleted; 314 * cleaned up.
258 } 315 *@returns (uint32_t) The number of deleted items.
316 */
317 uint32_t getDeleted()
318 {
319 return nDeleted;
320 }
259 321
260 uint32_t getDeleted() 322 /**
261 { 323 * Hash table index operator
262 return nDeleted; 324 *@param k (key_type) Key of data to be retrieved.
263 } 325 *@returns (HashProxy) Proxy pointing to the data.
326 */
327 virtual HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc> operator[]( key k )
328 {
329 uint32_t hash = __calcHashCode( k );
330 bool bFill;
331 uint32_t nPos = probe( hash, k, bFill );
264 332
265 virtual HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc> operator[]( key k ) 333 if( bFill )
266 { 334 {
267 uint32_t hash = __calcHashCode( k ); 335 return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, nPos, &aValues[nPos] );
268 bool bFill; 336 }
269 uint32_t nPos = probe( hash, k, bFill ); 337 else
338 {
339 return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, &k, nPos, hash );
340 }
341 }
270 342
271 if( bFill ) 343 /**
344 * Insert a value (v) under key (k) into the hash table
345 *@param k (key_type) Key to list the value under.
346 *@param v (value_type) Value to store in the hash table.
347 */
348 virtual void insert( key k, value v )
272 { 349 {
273 return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, nPos, &aValues[nPos] ); 350 uint32_t hash = __calcHashCode( k );
351 bool bFill;
352 uint32_t nPos = probe( hash, k, bFill );
353
354 if( bFill )
355 {
356 va.destroy( &aValues[nPos] );
357 va.construct( &aValues[nPos], v );
358 onUpdate();
359 }
360 else
361 {
362 fill( nPos, k, v, hash );
363 onInsert();
364 }
274 } 365 }
275 else 366
367 /**
368 * Remove a value from the hash table.
369 *@param k (key_type) The data under this key will be erased.
370 */
371 virtual void erase( key k )
276 { 372 {
277 return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, &k, nPos, hash ); 373 uint32_t hash = __calcHashCode( k );
374 bool bFill;
375 uint32_t nPos = probe( hash, k, bFill );
376
377 if( bFill )
378 {
379 _erase( nPos );
380 onDelete();
381 }
278 } 382 }
279 }
280 383
281 virtual void insert( key k, value v ) 384 struct iterator;
282 {
283 uint32_t hash = __calcHashCode( k );
284 bool bFill;
285 uint32_t nPos = probe( hash, k, bFill );
286 385
287 if( bFill ) 386 /**
387 * Remove a value from the hash pointed to from an iterator.
388 *@param i (iterator &) The data to be erased.
389 */
390 virtual void erase( struct iterator &i )
288 { 391 {
289 va.destroy( &aValues[nPos] ); 392 if( this != &i.hsh )
290 va.construct( &aValues[nPos], v ); 393 throw HashException("This iterator didn't come from this Hash.");
291 onUpdate(); 394 if( isFilled( i.nPos ) && !isDeleted( i.nPos ) )
395 {
396 _erase( i.nPos );
397 onDelete();
398 }
292 } 399 }
293 else 400
401 /**
402 * Remove all data from the hash table.
403 */
404 virtual void clear()
294 { 405 {
295 fill( nPos, k, v, hash ); 406 for( uint32_t j = 0; j < nCapacity; j++ )
296 onInsert(); 407 {
408 if( isFilled( j ) )
409 if( !isDeleted( j ) )
410 {
411 va.destroy( &aValues[j] );
412 ka.destroy( &aKeys[j] );
413 onDelete();
414 }
415 }
416
417 clearBits();
297 } 418 }
298 }
299 419
300 virtual void erase( key k ) 420 /**
301 { 421 * Get an item of data from the hash table.
302 uint32_t hash = __calcHashCode( k ); 422 *@param k (key_type) Key pointing to the data to be retrieved.
303 bool bFill; 423 *@returns (value_type &) The data pointed to by (k).
304 uint32_t nPos = probe( hash, k, bFill ); 424 */
425 virtual value &get( key k )
426 {
427 uint32_t hash = __calcHashCode( k );
428 bool bFill;
429 uint32_t nPos = probe( hash, k, bFill );
305 430
306 if( bFill ) 431 if( bFill )
432 {
433 return aValues[nPos];
434 }
435 else
436 {
437 throw HashException(
438 excodeNotFilled,
439 "No data assosiated with that key."
440 );
441 }
442 }
443
444 /**
445 * Get a const item of data from the hash table.
446 *@param k (key_type) Key pointing to the data to be retrieved.
447 *@returns (const value_type &) A const version of the data pointed
448 * to by (k).
449 */
450 virtual const value &get( key k ) const
307 { 451 {
308 _erase( nPos ); 452 uint32_t hash = __calcHashCode( k );
309 onDelete(); 453 bool bFill;
454 uint32_t nPos = probe( hash, k, bFill );
455
456 if( bFill )
457 {
458 return aValues[nPos];
459 }
460 else
461 {
462 throw HashException(
463 excodeNotFilled,
464 "No data assosiated with that key."
465 );
466 }
310 } 467 }
311 }
312 468
313 struct iterator; 469 /**
314 virtual void erase( struct iterator &i ) 470 * Does the hash table contain an item under key (k).
315 { 471 *@param k (key_type) The key to check.
316 if( this != &i.hsh ) 472 *@returns (bool) Whether there was an item in the hash under key (k).
317 throw HashException("This iterator didn't come from this Hash."); 473 */
318 if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) 474 virtual bool has( key k )
319 { 475 {
320 _erase( i.nPos ); 476 bool bFill;
321 onDelete(); 477 probe( __calcHashCode( k ), k, bFill, false );
478
479 return bFill;
322 } 480 }
323 }
324 481
325 virtual void clear() 482 /**
326 { 483 * Iteration structure for iterating through the hash.
327 for( uint32_t j = 0; j < nCapacity; j++ ) 484 */
485 typedef struct iterator
328 { 486 {
329 if( isFilled( j ) ) 487 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>;
330 if( !isDeleted( j ) ) 488 private:
489 iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh ) :
490 hsh( hsh ),
491 nPos( 0 ),
492 bFinished( false )
493 {
494 nPos = hsh.getFirstPos( bFinished );
495 }
496
497 iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh, bool bDone ) :
498 hsh( hsh ),
499 nPos( 0 ),
500 bFinished( bDone )
501 {
502 }
503
504 Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh;
505 uint32_t nPos;
506 bool bFinished;
507
508 public:
509 /**
510 * Iterator incrementation operator. Move the iterator forward.
511 */
512 iterator operator++( int )
513 {
514 if( bFinished == false )
515 nPos = hsh.getNextPos( nPos, bFinished );
516
517 return *this;
518 }
519
520 /**
521 * Iterator incrementation operator. Move the iterator forward.
522 */
523 iterator operator++()
524 {
525 if( bFinished == false )
526 nPos = hsh.getNextPos( nPos, bFinished );
527
528 return *this;
529 }
530
531 /**
532 * Iterator equality comparison operator. Iterators the same?
533 */
534 bool operator==( const iterator &oth )
535 {
536 if( bFinished != oth.bFinished )
537 return false;
538 if( bFinished == true )
331 { 539 {
332 va.destroy( &aValues[j] ); 540 return true;
333 ka.destroy( &aKeys[j] );
334 onDelete();
335 } 541 }
336 } 542 else
337 543 {
338 clearBits(); 544 if( oth.nPos == nPos )
339 } 545 return true;
546 return false;
547 }
548 }
549
550 /**
551 * Iterator not equality comparison operator. Not the same?
552 */
553 bool operator!=( const iterator &oth )
554 {
555 return !(*this == oth );
556 }
340 557
341 virtual value &get( key k ) 558 /**
342 { 559 * Iterator assignment operator.
343 uint32_t hash = __calcHashCode( k ); 560 */
344 bool bFill; 561 iterator operator=( const iterator &oth )
345 uint32_t nPos = probe( hash, k, bFill ); 562 {
563 if( &hsh != &oth.hsh )
564 throw HashException(
565 "Cannot mix iterators from different hash objects.");
566 nPos = oth.nPos;
567 bFinished = oth.bFinished;
568 }
346 569
347 if( bFill ) 570 /**
348 { 571 * Iterator dereference operator... err.. get the value
349 return aValues[nPos]; 572 *@returns (value_type &) The value behind this iterator.
350 } 573 */
351 else 574 value &operator *()
575 {
576 return hsh.getValueAtPos( nPos );
577 }
578
579 /**
580 * Get the key behind this iterator.
581 *@returns (key_type &) The key behind this iterator.
582 */
583 key &getKey()
584 {
585 return hsh.getKeyAtPos( nPos );
586 }
587
588 /**
589 * Get the value behind this iterator.
590 *@returs (value_type &) The value behind this iterator.
591 */
592 value &getValue()
593 {
594 return hsh.getValueAtPos( nPos );
595 }
596 };
597
598 /**
599 * Iteration structure for iterating through the hash (const).
600 */
601 typedef struct const_iterator
352 { 602 {
353 throw HashException( 603 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>;
354 excodeNotFilled, 604 private:
355 "No data assosiated with that key." 605 const_iterator( const Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh ) :
356 ); 606 hsh( hsh ),
357 } 607 nPos( 0 ),
358 } 608 bFinished( false )
609 {
610 nPos = hsh.getFirstPos( bFinished );
611 }
612
613 const_iterator( const Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh, bool bDone ) :
614 hsh( hsh ),
615 nPos( 0 ),
616 bFinished( bDone )
617 {
618 }
359 619
360 virtual bool has( key k ) 620 const Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh;
361 { 621 uint32_t nPos;
362 bool bFill; 622 bool bFinished;
363 probe( __calcHashCode( k ), k, bFill, false );
364 623
365 return bFill; 624 public:
366 } 625 /**
626 * Iterator incrementation operator. Move the iterator forward.
627 */
628 const_iterator operator++( int )
629 {
630 if( bFinished == false )
631 nPos = hsh.getNextPos( nPos, bFinished );
367 632
368 typedef struct iterator 633 return *this;
369 { 634 }
370 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>; 635
371 private: 636 /**
372 iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh ) : 637 * Iterator incrementation operator. Move the iterator forward.
373 hsh( hsh ), 638 */
374 nPos( 0 ), 639 const_iterator operator++()
375 bFinished( false ) 640 {
641 if( bFinished == false )
642 nPos = hsh.getNextPos( nPos, bFinished );
643
644 return *this;
645 }
646
647 /**
648 * Iterator equality comparison operator. Iterators the same?
649 */
650 bool operator==( const const_iterator &oth )
651 {
652 if( bFinished != oth.bFinished )
653 return false;
654 if( bFinished == true )
655 {
656 return true;
657 }
658 else
659 {
660 if( oth.nPos == nPos )
661 return true;
662 return false;
663 }
664 }
665
666 /**
667 * Iterator not equality comparison operator. Not the same?
668 */
669 bool operator!=( const const_iterator &oth )
670 {
671 return !(*this == oth );
672 }
673
674 /**
675 * Iterator assignment operator.
676 */
677 const_iterator operator=( const const_iterator &oth )
678 {
679 if( &hsh != &oth.hsh )
680 throw HashException(
681 "Cannot mix iterators from different hash objects.");
682 nPos = oth.nPos;
683 bFinished = oth.bFinished;
684 }
685
686 /**
687 * Iterator dereference operator... err.. get the value
688 *@returns (value_type &) The value behind this iterator.
689 */
690 const value &operator *() const
691 {
692 return hsh.getValueAtPos( nPos );
693 }
694
695 /**
696 * Get the key behind this iterator.
697 *@returns (key_type &) The key behind this iterator.
698 */
699 const key &getKey() const
700 {
701 return hsh.getKeyAtPos( nPos );
702 }
703
704 /**
705 * Get the value behind this iterator.
706 *@returs (value_type &) The value behind this iterator.
707 */
708 const value &getValue() const
709 {
710 return hsh.getValueAtPos( nPos );
711 }
712 };
713
714 /**
715 * Get an iterator pointing to the first item in the hash table.
716 *@returns (iterator) An iterator pointing to the first item in the
717 * hash table.
718 */
719 iterator begin()
376 { 720 {
377 nPos = hsh.getFirstPos( bFinished ); 721 return iterator( *this );
378 } 722 }
379 723
380 iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh, bool bDone ) : 724 const_iterator begin() const
381 hsh( hsh ),
382 nPos( 0 ),
383 bFinished( bDone )
384 { 725 {
726 return const_iterator( *this );
385 } 727 }
386 728
387 Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh; 729 /**
388 uint32_t nPos; 730 * Get an iterator pointing to a point just past the last item in the
389 bool bFinished; 731 * hash table.
390 732 *@returns (iterator) An iterator pointing to a point just past the
391 public: 733 * last item in the hash table.
392 iterator operator++( int ) 734 */
735 iterator end()
393 { 736 {
394 if( bFinished == false ) 737 return iterator( *this, true );
395 nPos = hsh.getNextPos( nPos, bFinished );
396
397 return *this;
398 } 738 }
399 739
400 iterator operator++() 740 const_iterator end() const
401 { 741 {
402 if( bFinished == false ) 742 return const_iterator( *this, true );
403 nPos = hsh.getNextPos( nPos, bFinished );
404
405 return *this;
406 } 743 }
407 744
408 bool operator==( const iterator &oth ) 745 /**
746 * Get a list of all the keys in the hash table.
747 *@returns (std::list<key_type>) The list of keys in the hash table.
748 */
749 Bu::List<key> getKeys() const
409 { 750 {
410 if( bFinished != oth.bFinished ) 751 Bu::List<key> lKeys;
411 return false; 752
412 if( bFinished == true ) 753 for( uint32_t j = 0; j < nCapacity; j++ )
413 { 754 {
414 return true; 755 if( isFilled( j ) )
756 {
757 if( !isDeleted( j ) )
758 {
759 lKeys.append( aKeys[j] );
760 }
761 }
415 } 762 }
416 else 763
764 return lKeys;
765 }
766
767 protected:
768 virtual void onInsert() {}
769 virtual void onUpdate() {}
770 virtual void onDelete() {}
771 virtual void onReHash() {}
772
773 virtual void clearBits()
774 {
775 for( uint32_t j = 0; j < nKeysSize; j++ )
417 { 776 {
418 if( oth.nPos == nPos ) 777 bFilled[j] = bDeleted[j] = 0;
419 return true;
420 return false;
421 } 778 }
422 } 779 }
423 780
424 bool operator!=( const iterator &oth ) 781 virtual void fill( uint32_t loc, key &k, value &v, uint32_t hash )
425 { 782 {
426 return !(*this == oth ); 783 bFilled[loc/32] |= (1<<(loc%32));
784 va.construct( &aValues[loc], v );
785 ka.construct( &aKeys[loc], k );
786 aHashCodes[loc] = hash;
787 nFilled++;
788 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
789 // nFilled, nDeleted, nCapacity );
427 } 790 }
428 791
429 iterator operator=( const iterator &oth ) 792 virtual void _erase( uint32_t loc )
430 { 793 {
431 if( &hsh != &oth.hsh ) 794 bDeleted[loc/32] |= (1<<(loc%32));
432 throw HashException( 795 va.destroy( &aValues[loc] );
433 "Cannot mix iterators from different hash objects."); 796 ka.destroy( &aKeys[loc] );
434 nPos = oth.nPos; 797 nDeleted++;
435 bFinished = oth.bFinished; 798 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
799 // nFilled, nDeleted, nCapacity );
436 } 800 }
437 801
438 std::pair<key,value> operator *() 802 virtual std::pair<key,value> getAtPos( uint32_t nPos )
803 {
804 return std::pair<key,value>(aKeys[nPos],aValues[nPos]);
805 }
806
807 virtual key &getKeyAtPos( uint32_t nPos )
439 { 808 {
440 return hsh.getAtPos( nPos ); 809 return aKeys[nPos];
441 } 810 }
442 811
443 key &getKey() 812 virtual const key &getKeyAtPos( uint32_t nPos ) const
444 { 813 {
445 return hsh.getKeyAtPos( nPos ); 814 return aKeys[nPos];
815 }
816
817 virtual value &getValueAtPos( uint32_t nPos )
818 {
819 return aValues[nPos];
820 }
821
822 virtual const value &getValueAtPos( uint32_t nPos ) const
823 {
824 return aValues[nPos];
446 } 825 }
447 826
448 value &getValue() 827 virtual uint32_t getFirstPos( bool &bFinished ) const
449 { 828 {
450 return hsh.getValueAtPos( nPos ); 829 for( uint32_t j = 0; j < nCapacity; j++ )
830 {
831 if( isFilled( j ) )
832 if( !isDeleted( j ) )
833 return j;
834 }
835
836 bFinished = true;
837 return 0;
451 } 838 }
452 };
453 839
454 iterator begin() 840 virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const
455 { 841 {
456 return iterator( *this ); 842 for( uint32_t j = nPos+1; j < nCapacity; j++ )
457 } 843 {
458 844 if( isFilled( j ) )
459 iterator end() 845 if( !isDeleted( j ) )
460 { 846 return j;
461 return iterator( *this, true ); 847 }
462 }
463 848
464 std::list<key> getKeys() 849 bFinished = true;
465 { 850 return 0;
466 std::list<key> lKeys; 851 }
467 852
468 for( uint32_t j = 0; j < nCapacity; j++ ) 853 uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true )
469 { 854 {
470 if( isFilled( j ) ) 855 uint32_t nCur = hash%nCapacity;
856
857 // First we scan to see if the key is already there, abort if we
858 // run out of probing room, or we find a non-filled entry
859 for( int8_t j = 0;
860 isFilled( nCur ) && j < 32;
861 nCur = (nCur + (1<<j))%nCapacity, j++
862 )
471 { 863 {
472 if( !isDeleted( j ) ) 864 // Is this the same hash code we were looking for?
865 if( hash == aHashCodes[nCur] )
473 { 866 {
474 lKeys.push_back( aKeys[j] ); 867 // Skip over deleted entries. Deleted entries are also filled,
868 // so we only have to do this check here.
869 if( isDeleted( nCur ) )
870 continue;
871
872 // Is it really the same key? (for safety)
873 if( __cmpHashKeys( aKeys[nCur], k ) == true )
874 {
875 bFill = true;
876 return nCur;
877 }
475 } 878 }
476 } 879 }
477 }
478 880
479 return lKeys; 881 // This is our insurance, if the table is full, then go ahead and
480 } 882 // rehash, then try again.
883 if( isFilled( nCur ) && rehash == true )
884 {
885 reHash( szCalc(getCapacity(), getFill(), getDeleted()) );
481 886
482protected: 887 // This is potentially dangerous, and could cause an infinite loop.
483 virtual void onInsert() {} 888 // Be careful writing probe, eh?
484 virtual void onUpdate() {} 889 return probe( hash, k, bFill );
485 virtual void onDelete() {} 890 }
486 virtual void onReHash() {}
487 891
488 virtual void clearBits() 892 bFill = false;
489 { 893 return nCur;
490 for( uint32_t j = 0; j < nKeysSize; j++ )
491 {
492 bFilled[j] = bDeleted[j] = 0;
493 } 894 }
494 } 895
495 896 uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) const
496 virtual void fill( uint32_t loc, key &k, value &v, uint32_t hash )
497 {
498 bFilled[loc/32] |= (1<<(loc%32));
499 va.construct( &aValues[loc], v );
500 ka.construct( &aKeys[loc], k );
501 aHashCodes[loc] = hash;
502 nFilled++;
503 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
504 // nFilled, nDeleted, nCapacity );
505 }
506
507 virtual void _erase( uint32_t loc )
508 {
509 bDeleted[loc/32] |= (1<<(loc%32));
510 va.destroy( &aValues[loc] );
511 ka.destroy( &aKeys[loc] );
512 nDeleted++;
513 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
514 // nFilled, nDeleted, nCapacity );
515 }
516
517 virtual std::pair<key,value> getAtPos( uint32_t nPos )
518 {
519 return std::pair<key,value>(aKeys[nPos],aValues[nPos]);
520 }
521
522 virtual key &getKeyAtPos( uint32_t nPos )
523 {
524 return aKeys[nPos];
525 }
526
527 virtual value &getValueAtPos( uint32_t nPos )
528 {
529 return aValues[nPos];
530 }
531
532 virtual uint32_t getFirstPos( bool &bFinished )
533 {
534 for( uint32_t j = 0; j < nCapacity; j++ )
535 { 897 {
536 if( isFilled( j ) ) 898 uint32_t nCur = hash%nCapacity;
537 if( !isDeleted( j ) ) 899
538 return j; 900 // First we scan to see if the key is already there, abort if we
539 } 901 // run out of probing room, or we find a non-filled entry
902 for( int8_t j = 0;
903 isFilled( nCur ) && j < 32;
904 nCur = (nCur + (1<<j))%nCapacity, j++
905 )
906 {
907 // Is this the same hash code we were looking for?
908 if( hash == aHashCodes[nCur] )
909 {
910 // Skip over deleted entries. Deleted entries are also filled,
911 // so we only have to do this check here.
912 if( isDeleted( nCur ) )
913 continue;
914
915 // Is it really the same key? (for safety)
916 if( __cmpHashKeys( aKeys[nCur], k ) == true )
917 {
918 bFill = true;
919 return nCur;
920 }
921 }
922 }
540 923
541 bFinished = true; 924 bFill = false;
542 return 0; 925 return nCur;
543 } 926 }
544 927
545 virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) 928 void reHash( uint32_t nNewSize )
546 {
547 for( uint32_t j = nPos+1; j < nCapacity; j++ )
548 { 929 {
549 if( isFilled( j ) ) 930 //printf("---REHASH---");
550 if( !isDeleted( j ) ) 931 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
551 return j; 932 // nFilled, nDeleted, nCapacity );
552 } 933
934 // Save all the old data
935 uint32_t nOldCapacity = nCapacity;
936 uint32_t *bOldFilled = bFilled;
937 uint32_t *aOldHashCodes = aHashCodes;
938 uint32_t nOldKeysSize = nKeysSize;
939 uint32_t *bOldDeleted = bDeleted;
940 value *aOldValues = aValues;
941 key *aOldKeys = aKeys;
942
943 // Calculate new sizes
944 nCapacity = nNewSize;
945 nKeysSize = bitsToBytes( nCapacity );
946
947 // Allocate new memory + prep
948 bFilled = ca.allocate( nKeysSize );
949 bDeleted = ca.allocate( nKeysSize );
950 clearBits();
553 951
554 bFinished = true; 952 aHashCodes = ca.allocate( nCapacity );
555 return 0; 953 aKeys = ka.allocate( nCapacity );
556 } 954 aValues = va.allocate( nCapacity );
557 955
558 uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) 956 nDeleted = nFilled = 0;
559 {
560 uint32_t nCur = hash%nCapacity;
561 957
562 // First we scan to see if the key is already there, abort if we 958 // Re-insert all of the old data (except deleted items)
563 // run out of probing room, or we find a non-filled entry 959 for( uint32_t j = 0; j < nOldCapacity; j++ )
564 for( int8_t j = 0;
565 isFilled( nCur ) && j < 32;
566 nCur = (nCur + (1<<j))%nCapacity, j++
567 )
568 {
569 // Is this the same hash code we were looking for?
570 if( hash == aHashCodes[nCur] )
571 { 960 {
572 // Skip over deleted entries. Deleted entries are also filled, 961 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 &&
573 // so we only have to do this check here. 962 (bOldDeleted[j/32]&(1<<(j%32)))==0 )
574 if( isDeleted( nCur ) ) 963 {
575 continue; 964 insert( aOldKeys[j], aOldValues[j] );
965 }
966 }
576 967
577 // Is it really the same key? (for safety) 968 // Delete all of the old data
578 if( __cmpHashKeys( aKeys[nCur], k ) == true ) 969 for( uint32_t j = 0; j < nOldCapacity; j++ )
970 {
971 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 )
579 { 972 {
580 bFill = true; 973 va.destroy( &aOldValues[j] );
581 return nCur; 974 ka.destroy( &aOldKeys[j] );
582 } 975 }
583 } 976 }
977 va.deallocate( aOldValues, nOldCapacity );
978 ka.deallocate( aOldKeys, nOldCapacity );
979 ca.deallocate( bOldFilled, nOldKeysSize );
980 ca.deallocate( bOldDeleted, nOldKeysSize );
981 ca.deallocate( aOldHashCodes, nOldCapacity );
584 } 982 }
585 983
586 // This is our insurance, if the table is full, then go ahead and 984 virtual bool isFilled( uint32_t loc ) const
587 // rehash, then try again.
588 if( isFilled( nCur ) && rehash == true )
589 { 985 {
590 reHash( szCalc(getCapacity(), getFill(), getDeleted()) ); 986 return (bFilled[loc/32]&(1<<(loc%32)))!=0;
987 }
591 988
592 // This is potentially dangerous, and could cause an infinite loop. 989 virtual bool isDeleted( uint32_t loc ) const
593 // Be careful writing probe, eh? 990 {
594 return probe( hash, k, bFill ); 991 return (bDeleted[loc/32]&(1<<(loc%32)))!=0;
595 } 992 }
596 993
597 bFill = false; 994 protected:
598 return nCur; 995 uint32_t nCapacity;
599 } 996 uint32_t nFilled;
997 uint32_t nDeleted;
998 uint32_t *bFilled;
999 uint32_t *bDeleted;
1000 uint32_t nKeysSize;
1001 key *aKeys;
1002 value *aValues;
1003 uint32_t *aHashCodes;
1004 valuealloc va;
1005 keyalloc ka;
1006 challoc ca;
1007 sizecalc szCalc;
1008 };
600 1009
601 void reHash( uint32_t nNewSize ) 1010 template<> uint32_t __calcHashCode<int>( const int &k );
602 { 1011 template<> bool __cmpHashKeys<int>( const int &a, const int &b );
603 //printf("---REHASH---");
604 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
605 // nFilled, nDeleted, nCapacity );
606
607 // Save all the old data
608 uint32_t nOldCapacity = nCapacity;
609 uint32_t *bOldFilled = bFilled;
610 uint32_t *aOldHashCodes = aHashCodes;
611 uint32_t nOldKeysSize = nKeysSize;
612 uint32_t *bOldDeleted = bDeleted;
613 value *aOldValues = aValues;
614 key *aOldKeys = aKeys;
615
616 // Calculate new sizes
617 nCapacity = nNewSize;
618 nKeysSize = bitsToBytes( nCapacity );
619
620 // Allocate new memory + prep
621 bFilled = ca.allocate( nKeysSize );
622 bDeleted = ca.allocate( nKeysSize );
623 clearBits();
624 1012
625 aHashCodes = ca.allocate( nCapacity ); 1013 template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k );
626 aKeys = ka.allocate( nCapacity ); 1014 template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b );
627 aValues = va.allocate( nCapacity );
628 1015
629 nDeleted = nFilled = 0; 1016 template<> uint32_t __calcHashCode<const char *>( const char * const &k );
1017 template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b );
630 1018
631 // Re-insert all of the old data (except deleted items) 1019 template<> uint32_t __calcHashCode<char *>( char * const &k );
632 for( uint32_t j = 0; j < nOldCapacity; j++ ) 1020 template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b );
633 {
634 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 &&
635 (bOldDeleted[j/32]&(1<<(j%32)))==0 )
636 {
637 insert( aOldKeys[j], aOldValues[j] );
638 }
639 }
640 1021
641 // Delete all of the old data 1022 template<> uint32_t __calcHashCode<std::string>( const std::string &k );
642 for( uint32_t j = 0; j < nOldCapacity; j++ ) 1023 template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b );
1024
1025 /*
1026 template<typename key, typename value>
1027 Archive &operator<<( Archive &ar, Hash<key,value> &h )
1028 {
1029 ar << h.size();
1030 for( typename Hash<key,value>::iterator i = h.begin(); i != h.end(); i++ )
643 { 1031 {
644 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && 1032 std::pair<key,value> p = *i;
645 (bOldDeleted[j/32]&(1<<(j%32)))==0 ) 1033 ar << p.first << p.second;
646 {
647 va.destroy( &aOldValues[j] );
648 ka.destroy( &aOldKeys[j] );
649 }
650 } 1034 }
651 va.deallocate( aOldValues, nOldCapacity );
652 ka.deallocate( aOldKeys, nOldCapacity );
653 ca.deallocate( bOldFilled, nOldKeysSize );
654 ca.deallocate( bOldDeleted, nOldKeysSize );
655 ca.deallocate( aOldHashCodes, nOldCapacity );
656 }
657 1035
658 virtual bool isFilled( uint32_t loc ) const 1036 return ar;
659 {
660 return (bFilled[loc/32]&(1<<(loc%32)))!=0;
661 } 1037 }
662 1038
663 virtual bool isDeleted( uint32_t loc ) 1039 template<typename key, typename value>
1040 Archive &operator>>( Archive &ar, Hash<key,value> &h )
664 { 1041 {
665 return (bDeleted[loc/32]&(1<<(loc%32)))!=0; 1042 h.clear();
666 } 1043 uint32_t nSize;
1044 ar >> nSize;
667 1045
668protected: 1046 for( uint32_t j = 0; j < nSize; j++ )
669 uint32_t nCapacity; 1047 {
670 uint32_t nFilled; 1048 key k; value v;
671 uint32_t nDeleted; 1049 ar >> k >> v;
672 uint32_t *bFilled; 1050 h.insert( k, v );
673 uint32_t *bDeleted; 1051 }
674 uint32_t nKeysSize;
675 key *aKeys;
676 value *aValues;
677 uint32_t *aHashCodes;
678 valuealloc va;
679 keyalloc ka;
680 challoc ca;
681 sizecalc szCalc;
682};
683
684template<> uint32_t __calcHashCode<int>( const int &k );
685template<> bool __cmpHashKeys<int>( const int &a, const int &b );
686
687template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k );
688template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b );
689
690template<> uint32_t __calcHashCode<const char *>( const char * const &k );
691template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b );
692
693template<> uint32_t __calcHashCode<char *>( char * const &k );
694template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b );
695
696template<> uint32_t __calcHashCode<std::string>( const std::string &k );
697template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b );
698
699template<> uint32_t __calcHashCode<Hashable>( const Hashable &k );
700template<> bool __cmpHashKeys<Hashable>( const Hashable &a, const Hashable &b );
701
702template<typename key, typename value>
703Serializer &operator<<( Serializer &ar, Hash<key,value> &h )
704{
705 ar << h.size();
706 for( typename Hash<key,value>::iterator i = h.begin(); i != h.end(); i++ )
707 {
708 std::pair<key,value> p = *i;
709 ar << p.first << p.second;
710 }
711 1052
712 return ar; 1053 return ar;
713} 1054 }*/
714 1055
715template<typename key, typename value> 1056 /*
716Serializer &operator>>( Serializer &ar, Hash<key,value> &h ) 1057 template<typename key, typename value>
717{ 1058 Serializer &operator&&( Serializer &ar, Hash<key,value> &h )
718 h.clear();
719 uint32_t nSize;
720 ar >> nSize;
721
722 for( uint32_t j = 0; j < nSize; j++ )
723 { 1059 {
724 key k; value v; 1060 if( ar.isLoading() )
725 ar >> k >> v; 1061 {
726 h.insert( k, v ); 1062 return ar >> h;
727 } 1063 }
728 1064 else
729 return ar; 1065 {
730} 1066 return ar << h;
731 1067 }
732template<typename key, typename value> 1068 }*/
733Serializer &operator&&( Serializer &ar, Hash<key,value> &h )
734{
735 if( ar.isLoading() )
736 {
737 return ar >> h;
738 }
739 else
740 {
741 return ar << h;
742 }
743} 1069}
744 1070
745#endif 1071#endif
diff --git a/src/hashable.cpp b/src/hashable.cpp
deleted file mode 100644
index 8565956..0000000
--- a/src/hashable.cpp
+++ /dev/null
@@ -1 +0,0 @@
1#include "hashable.h"
diff --git a/src/hashable.h b/src/hashable.h
deleted file mode 100644
index 98643d5..0000000
--- a/src/hashable.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef HASHABLE_H
2#define HASHABLE_H
3
4class Hashable
5{
6public:
7 virtual ~Hashable() {};
8 virtual unsigned long int getHashCode() = 0;
9 virtual bool compareForHash( Hashable &other ) = 0;
10};
11
12#endif
diff --git a/src/hashfunction.cpp b/src/hashfunction.cpp
deleted file mode 100644
index 51f2259..0000000
--- a/src/hashfunction.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
1#include "hashfunction.h"
2
3HashFunction::HashFunction()
4{
5}
6
7HashFunction::~HashFunction()
8{
9}
10
diff --git a/src/hashfunction.h b/src/hashfunction.h
deleted file mode 100644
index cbcf70f..0000000
--- a/src/hashfunction.h
+++ /dev/null
@@ -1,48 +0,0 @@
1#ifndef HASH_FUNCTION
2#define HASH_FUNCTION
3
4/** This represents the shell of a hash function. It must be aggregated in
5 * order to be used. Please read about it's two functions for specificatins
6 * relating to what values will be passed to them and what they should return
7 * for creating your own hash functions.
8 *@author Mike Buland.
9 */
10class HashFunction
11{
12public:
13 /**
14 * Standard Constructor.
15 */
16 HashFunction();
17
18 /**
19 * Standard Deconstructor.
20 */
21 virtual ~HashFunction();
22
23 /** Hashes the value represnted by id. This must return a fairly unique
24 * number in the range of 0-2^32 (or whatever the size of an unsigned long
25 * is on your system) based on the id given. The faster the number changes
26 * the better in a general sence. The return value will be the index
27 * (after probing takes place) to the data assosiated with an id, so this
28 * function should always produce the same number for any given id.
29 *@param id The identifier to use to create a unique numerical identifier.
30 *@returns A mostly unique numerical identifier generated using the given
31 * id.
32 */
33 virtual unsigned long int hash( const void *id ) = 0;
34
35 /** This function must compare two ids in the format that this hashfunction
36 * accepts. For example, if the hash function hashes strings it should
37 * probably { return strcmp( id1, id2 ) == 0 }.
38 *@param id1 One value to use in the comparison
39 *@param id2 Another value to use in the comparison
40 *@returns True if the two values match, otherwise false.
41 */
42 virtual bool cmpIDs( const void *id1, const void *id2 ) = 0;
43
44// virtual void *createPersistantID( const void *id ) = 0;
45// virtual void destroyPersistantID( const void *id ) = 0;
46};
47
48#endif
diff --git a/src/hashfunctioncasestring.cpp b/src/hashfunctioncasestring.cpp
deleted file mode 100644
index 6361f45..0000000
--- a/src/hashfunctioncasestring.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
1#include <stdlib.h>
2#include <string.h>
3#include <ctype.h>
4#include "hashfunctioncasestring.h"
5
6HashFunctionCaseString::HashFunctionCaseString()
7{
8}
9
10HashFunctionCaseString::~HashFunctionCaseString()
11{
12}
13
14unsigned long int HashFunctionCaseString::hash( const void *id )
15{
16 const char *str = (const char *)id;
17 unsigned long int nPos = 0;
18 for( int j = 0; str[j] != '\0'; j++ )
19 {
20 nPos = tolower(str[j]) + (nPos << 6) + (nPos << 16) - nPos;
21// nPos += nPos<<16|(((unsigned long int)tolower(str[j]))<<((j*7)%24));
22 }
23 return nPos;
24}
25
26bool HashFunctionCaseString::cmpIDs( const void *id1, const void *id2 )
27{
28 const char *str1 = (const char *)id1;
29 const char *str2 = (const char *)id2;
30
31 int j;
32 for( j = 0; str1[j] != '\0' && str2[j] != '\0'; j++ )
33 {
34 if( tolower(str1[j]) != tolower(str2[j]) )
35 return false;
36 }
37 return (str1[j]==str2[j]);
38}
39
diff --git a/src/hashfunctioncasestring.h b/src/hashfunctioncasestring.h
deleted file mode 100644
index 7816a1b..0000000
--- a/src/hashfunctioncasestring.h
+++ /dev/null
@@ -1,28 +0,0 @@
1#ifndef HASH_FUNCTION_CASE_STRING
2#define HASH_FUNCTION_CASE_STRING
3
4#include "hashfunction.h"
5
6/** A hash function for string data. This hash function does strings, but is
7 * actually generalized to handle any binary stream of characters terminated
8 * by a null character. This is different than HashFunctionString in that
9 * this does comparisons without regaurd to case.
10 *@author Mike Buland.
11 */
12class HashFunctionCaseString : public HashFunction
13{
14public:
15 /**
16 * Standard Constructor.
17 */
18 HashFunctionCaseString();
19
20 /**
21 * Standard Deconstructor.
22 */
23 virtual ~HashFunctionCaseString();
24 unsigned long int hash( const void *id );
25 bool cmpIDs( const void *id1, const void *id2 );
26};
27
28#endif
diff --git a/src/hashfunctionint.cpp b/src/hashfunctionint.cpp
deleted file mode 100644
index 4bd0feb..0000000
--- a/src/hashfunctionint.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
1#include "hashfunctionint.h"
2
3HashFunctionInt::HashFunctionInt()
4{
5}
6
7HashFunctionInt::~HashFunctionInt()
8{
9}
10
11unsigned long int HashFunctionInt::hash( const void *id )
12{
13 return (unsigned long)(id);
14}
15
16bool HashFunctionInt::cmpIDs( const void *id1, const void *id2 )
17{
18 return (unsigned long)(id1) == (unsigned long)(id2);
19}
20
diff --git a/src/hashfunctionint.h b/src/hashfunctionint.h
deleted file mode 100644
index 0fbc764..0000000
--- a/src/hashfunctionint.h
+++ /dev/null
@@ -1,26 +0,0 @@
1#ifndef HASH_FUNCTION_INT
2#define HASH_FUNCTION_INT
3
4#include "hashfunction.h"
5
6/** A hash function for integer data. Really, this does almost nothing except
7 * ensure we're dealing with positive indicies.
8 *@author Mike Buland.
9 */
10class HashFunctionInt : public HashFunction
11{
12public:
13 /**
14 * Standard Constructor.
15 */
16 HashFunctionInt();
17
18 /**
19 * Standard Deconstructor.
20 */
21 virtual ~HashFunctionInt();
22 unsigned long int hash( const void *id );
23 bool cmpIDs( const void *id1, const void *id2 );
24};
25
26#endif
diff --git a/src/hashfunctionstring.cpp b/src/hashfunctionstring.cpp
deleted file mode 100644
index bd14643..0000000
--- a/src/hashfunctionstring.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
1#include "hashfunctionstring.h"
2#ifndef NULL
3#define NULL ((void *) 0)
4#endif
5
6HashFunctionString::HashFunctionString()
7{
8}
9
10HashFunctionString::~HashFunctionString()
11{
12}
13
14unsigned long int HashFunctionString::hash( const void *id )
15{
16 if (id == NULL)
17 {
18 return 0;
19 }
20
21 unsigned long int nPos = 0;
22 for( const char *s = (const char *)id; *s; s++ )
23 {
24 nPos = *s + (nPos << 6) + (nPos << 16) - nPos;
25 }
26 return nPos;
27}
28
29bool HashFunctionString::cmpIDs( const void *id1, const void *id2 )
30{
31 if (id1 == NULL || id2 == NULL)
32 {
33 return false;
34 }
35 if (id1 == id2)
36 {
37 return true;
38 }
39
40 const char *str1 = (const char *)id1;
41 const char *str2 = (const char *)id2;
42
43 int j;
44 for( j = 0; str1[j] != '\0' && str2[j] != '\0'; j++ )
45 {
46 if( str1[j] != str2[j] )
47 return false;
48 }
49 return (str1[j]==str2[j]);
50}
51
diff --git a/src/hashfunctionstring.h b/src/hashfunctionstring.h
deleted file mode 100644
index 7d2a1a6..0000000
--- a/src/hashfunctionstring.h
+++ /dev/null
@@ -1,27 +0,0 @@
1#ifndef HASH_FUNCTION_STRING
2#define HASH_FUNCTION_STRING
3
4#include "hashfunction.h"
5
6/** A hash function for string data. This hash function does strings, but is
7 * actually generalized to handle any binary stream of characters terminated
8 * by a null character.
9 *@author Mike Buland.
10 */
11class HashFunctionString : public HashFunction
12{
13public:
14 /**
15 * Standard Constructor.
16 */
17 HashFunctionString();
18
19 /**
20 * Standard Deconstructor.
21 */
22 virtual ~HashFunctionString();
23 unsigned long int hash( const void *id );
24 bool cmpIDs( const void *id1, const void *id2 );
25};
26
27#endif
diff --git a/src/hashtable.cpp b/src/hashtable.cpp
deleted file mode 100644
index dbcd964..0000000
--- a/src/hashtable.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
1#include <string.h>
2#include <stdio.h>
3#include <math.h>
4
5#include "hashtable.h"
6
7HashTable::HashTable( HashFunction *hNewFunc, unsigned long int nInitSize, bool bAllowDupes )
8{
9 hFunc = hNewFunc;
10 nTableSize = nextPrime( nInitSize );
11 aTable = new HashNode[nTableSize];
12 //for( int j = 0; j < nTableSize; j++ ) if( aTable[j].id || aTable[j].data || aTable[j].bDeleted ) printf("Unclean entry\n");
13 nSize = 0;
14 nFilled = 0;
15 this->bAllowDupes = bAllowDupes;
16}
17
18HashTable::~HashTable()
19{
20 delete[] aTable;
21 delete hFunc;
22}
23
24void HashTable::set( int j, const void *newID, const void *newData )
25{
26 if( newData == NULL )
27 {
28 printf("Inserting NULL data is indestinguishable from uninserted data!\n");
29 }
30 aTable[j].id = newID;
31 aTable[j].data = newData;
32}
33
34void HashTable::clear()
35{
36 memset( aTable, 0, sizeof(HashNode) * nTableSize );
37}
38
39bool HashTable::isFilled( int j )
40{
41 return (aTable[j].id != NULL)||(aTable[j].bDeleted);
42}
43
44void HashTable::reHash( unsigned long int nNewSize )
45{
46 HashNode *aOldTable = aTable;
47 unsigned long int oldSize = nTableSize;
48
49 // If the table can still be used if we just get rid of deleted items, don't
50 // change the size of the table, otherwise, go ahead and use the number
51 // passed in.
52 if( nSize > nTableSize>>1 )
53 {
54 nTableSize = nextPrime( nNewSize );
55 }
56
57 aTable = newTable( nTableSize );
58 //for( int j = 0; j < nTableSize; j++ ) if( aTable[j].id || aTable[j].data || aTable[j].bDeleted ) printf("Unclean entry\n");
59
60 nSize = 0;
61 nFilled = 0;
62
63 for( unsigned long int j = 0; j < oldSize; j++ )
64 {
65 if( aOldTable[j].id != NULL && aOldTable[j].bDeleted == false )
66 {
67 insert( aOldTable[j].id, aOldTable[j].data );
68 }
69 }
70
71 delete[] aOldTable;
72}
73
74unsigned long int HashTable::probe( unsigned long int nStart, const void *id )
75{
76 int nHash = nStart;
77 nStart = nStart%nTableSize;
78 if( bAllowDupes == true )
79 {
80 for(
81 unsigned long int j=0;
82 isFilled( nStart ) && j < 32;
83 nStart = (nStart+(1<<j))%nTableSize, j++
84 );
85
86 /**
87 * This is an ugly little hack. If the hash table is too full in allow-
88 * dups mode we have to fall back on a linear search, otherwise you can
89 * only get up to 32 entries with the same name.
90 */
91 if( isFilled( nStart ) )
92 {
93 unsigned long int nOldStart = nStart;
94 for(
95 nStart++;
96 isFilled( nStart ) && nStart != nOldStart;
97 nStart = (nStart+1)%nTableSize
98 );
99 }
100 }
101 else
102 {
103 for(
104 unsigned long int j=0;
105 isFilled( nStart ) && j < 32;
106 nStart = (nStart+(1<<j))%nTableSize, j++
107 )
108 {
109 if( isFilled( nStart ) )
110 {
111 if( hFunc->cmpIDs( aTable[nStart].id, id ) == true &&
112 aTable[nStart].bDeleted == false )
113 {
114 return nStart;
115 }
116 }
117 }
118 }
119 // This is our insurance, if the table is full, then go ahead and rehash,
120 // then try again.
121 if( isFilled( nStart ) )
122 {
123 reHash( getCapacity()*2 );
124 return probe( nHash, id );
125 }
126 return nStart;
127}
128
129HashTable::HashNode *HashTable::newTable( unsigned long int nNewSize )
130{
131 return new HashNode[nNewSize];
132}
133
134#ifdef HASH_DEBUG_VIS
135void HashTable::printDebugLine( const char *exData )
136{
137 char *buf = new char[getCapacity()+3];
138 int j;
139 buf[0] = '[';
140 for( j = 0; j < getCapacity(); j++ )
141 {
142 buf[j+1] = (aTable[j].bDeleted)?('X'):((isFilled( j ))?('#'):('-'));
143 }
144 buf[j+1] = ']';
145 buf[j+2] = '\0';
146 printf("%s %s\n", buf, exData );
147 delete[] buf;
148}
149#endif
150
151bool HashTable::insert( const void *id, const void *data )
152{
153 unsigned long int nPos = probe( hFunc->hash( id ), id )%nTableSize;
154
155 if( bAllowDupes == true )
156 {
157 if( aTable[nPos].id == NULL && aTable[nPos].bDeleted == false )
158 {
159 set( nPos, id, data );
160#ifdef HASH_DEBUG_VIS
161 printDebugLine( (const char *)id );
162#endif
163 nSize++;
164 nFilled++;
165 return true;
166 }
167 else
168 {
169 return false;
170 }
171 }
172 else
173 {
174 if( aTable[nPos].id == NULL && aTable[nPos].bDeleted == false )
175 {
176 set( nPos, id, data );
177#ifdef HASH_DEBUG_VIS
178 printDebugLine( (const char *)id );
179#endif
180 nSize++;
181 nFilled++;
182 return true;
183 }
184 else if( hFunc->cmpIDs( aTable[nPos].id, id ) == true )
185 {
186 set( nPos, id, data );
187#ifdef HASH_DEBUG_VIS
188 printDebugLine( (const char *)id );
189#endif
190 return true;
191 }
192 else
193 {
194 return false;
195 }
196 }
197}
198
199const void *HashTable::get( const void *id, unsigned long int nSkip )
200{
201 unsigned long int nPos = hFunc->hash( id )%nTableSize;
202
203 for( unsigned long int j=0; j < 32; nPos = (nPos+(1<<j))%nTableSize, j++ )
204 {
205 if( !isFilled( nPos ) ) return NULL;
206 if( aTable[nPos].bDeleted == false )
207 {
208 if( hFunc->cmpIDs( id, aTable[nPos].id ) )
209 {
210 if( nSkip == 0 )
211 {
212 return aTable[nPos].data;
213 }
214 else
215 {
216 nSkip--;
217 }
218 }
219 }
220 }
221
222 if( bAllowDupes )
223 {
224 unsigned long int nOldPos = nPos;
225 for( nPos++; nPos != nOldPos; nPos=(nPos+1)%nTableSize )
226 {
227 if( !isFilled( nPos ) ) return NULL;
228 if( aTable[nPos].bDeleted == false )
229 {
230 if( hFunc->cmpIDs( id, aTable[nPos].id ) )
231 {
232 if( nSkip == 0 )
233 {
234 return aTable[nPos].data;
235 }
236 else
237 {
238 nSkip--;
239 }
240 }
241 }
242 }
243 }
244
245 return NULL;
246}
247
248const void *HashTable::getKey( const void *id, unsigned long int nSkip )
249{
250 unsigned long int nPos = hFunc->hash( id )%nTableSize;
251
252 for( unsigned long int j=0; j < 32; nPos = (nPos+(1<<j))%nTableSize, j++ )
253 {
254 if( !isFilled( nPos ) ) return NULL;
255 if( aTable[nPos].bDeleted == false )
256 {
257 if( hFunc->cmpIDs( id, aTable[nPos].id ) )
258 {
259 if( nSkip == 0 )
260 {
261 return aTable[nPos].id;
262 }
263 else
264 {
265 nSkip--;
266 }
267 }
268 }
269 }
270
271 if( bAllowDupes )
272 {
273 unsigned long int nOldPos = nPos;
274 for( nPos++; nPos != nOldPos; nPos=(nPos+1)%nTableSize )
275 {
276 if( !isFilled( nPos ) ) return NULL;
277 if( aTable[nPos].bDeleted == false )
278 {
279 if( hFunc->cmpIDs( id, aTable[nPos].id ) )
280 {
281 if( nSkip == 0 )
282 {
283 return aTable[nPos].id;
284 }
285 else
286 {
287 nSkip--;
288 }
289 }
290 }
291 }
292 }
293
294 return NULL;
295}
296
297void *HashTable::getFirstItemPos()
298{
299 HashPos *pos = new HashPos;
300 return pos;
301}
302
303const void *HashTable::getItemData( void *xPos )
304{
305 return aTable[((HashPos *)xPos)->nPos].data;
306}
307
308const void *HashTable::getItemID( void *xPos )
309{
310 return aTable[((HashPos *)xPos)->nPos].id;
311}
312
313void *HashTable::getNextItemPos( void *xPos )
314{
315 HashPos *pos = (HashPos *)xPos;
316 if( pos->bStarted == false )
317 {
318 pos->bStarted = true;
319 pos->nPos = 0;
320 }
321 else
322 {
323 pos->nPos++;
324 }
325 if( pos->nPos < nTableSize )
326 {
327 for( ; pos->nPos < nTableSize; pos->nPos++ )
328 {
329 if( isFilled( pos->nPos ) &&
330 aTable[pos->nPos].bDeleted == false )
331 {
332 return xPos;
333 }
334 }
335 }
336
337 delete pos;
338
339 return NULL;
340}
341
342// Big-O sqrt(n)
343// Change this to be erethpothynies table with a storage
344// lookup later on.
345bool HashTable::isPrime (int num)
346{
347 if (num == 2) // the only even prime
348 return true;
349 else if (num % 2 == 0) // other even numbers are composite
350 return false;
351 else
352 {
353 //bool prime = true;
354 int divisor = 3;
355 int upperLimit = static_cast<int>(sqrt(num) + 1);
356 while (divisor <= upperLimit)
357 {
358 if (num % divisor == 0)
359 return false;
360 // prime = false;
361 divisor +=2;
362 }
363 return true;
364 }
365}
366
367// Big-O n^(3/2)
368int HashTable::nextPrime( int base )
369{
370 int nPrime;
371 for( nPrime = base; isPrime( nPrime ) == false; nPrime++ );
372 return nPrime;
373}
374
375unsigned long int HashTable::getCapacity()
376{
377 return nTableSize;
378}
379
380unsigned long int HashTable::getSize()
381{
382 return nSize;
383}
384
385double HashTable::getLoad()
386{
387 return (double)(nFilled)/(double)(nTableSize);
388}
389
390const void *HashTable::operator[](const void *id)
391{
392 return get( id );
393}
394
395bool HashTable::del( const void *id, int nSkip )
396{
397 unsigned long int nPos = hFunc->hash( id )%nTableSize;
398
399 for( unsigned long int j=0; j < 32; nPos = (nPos+(1<<j))%nTableSize, j++ )
400 {
401 if( !isFilled( nPos ) ) return false;
402 //printf("0x%08X \"%s\" == 0x%08X \"%s\" (%d)\n", id, id, aTable[nPos].id, aTable[nPos].id, nPos );
403 if( hFunc->cmpIDs( id, aTable[nPos].id ) &&
404 aTable[nPos].bDeleted == false )
405 {
406 if( nSkip == 0 )
407 {
408 aTable[nPos].bDeleted = true;
409 nSize--;
410#ifdef HASH_DEBUG_VIS
411 printDebugLine( (const char *)id );
412#endif
413 return true;
414 }
415 else
416 {
417 nSkip--;
418 }
419 }
420 }
421
422 return false;
423}
424
diff --git a/src/hashtable.h b/src/hashtable.h
deleted file mode 100644
index 179b694..0000000
--- a/src/hashtable.h
+++ /dev/null
@@ -1,308 +0,0 @@
1/**\hashtable.h
2 * Describes the HashFunction, HashFunctionString, and HashTable classes. It
3 * was just easier to put them all in one set of files.
4 *@author Mike Buland
5 */
6
7#ifndef HASH_TABLE_H
8#define HASH_TABLE_H
9
10//Uncomment this line to see a cool text-mode visualization of what's going on
11//#define HASH_DEBUG_VIS 1
12
13#include <stdlib.h>
14#include <string.h>
15#include <ctype.h>
16
17#include "hashfunction.h"
18
19/**
20 * A simple yet flexable hash-table. This uses several tricks to help ensure
21 * that the table is always running at maximum efficiency. You no longer have
22 * to specify a "danger fill level" when more space is needed a rehash is
23 * automatically trigered. Deleting elements is fully supported, as well as
24 * duplicate elements. To work with and allow duplicates simple construct your
25 * HashTable the way you normally would, but when deleting or getting elements
26 * you can specify a skip value. This effectively allows you to treat elements
27 * with duplicate ID's as though they were in a zero-based array. The first
28 * element inserted with a given ID would be at skip zero, the next at skip 1
29 * and so on. This allows you to quickly search for elements with duplicate
30 * names, just stop when you get a null for a skip number, i.e.
31 * <pre>
32 * for( int j = 0;; j++ )
33 * {
34 * void *pData = hash.get( myID, j );
35 * if( !pData ) break;
36 * // Do something interesting with pData
37 * }
38 * </pre>
39 * There are new features in this HashTable that also allow for memory saving
40 * when dealing with systems where many elements are being deleted from the
41 * table. In those cases the elements deleted cannot be simply deleted, instead
42 * they have to be marked as deleted and hidden from the user, but maintained in
43 * the table so that future hashing operations don't fail. When rehashing
44 * occurs all elements marked as deleted are quietly removed. In these cases,
45 * if the number of deleted items would free enough space in the table for the
46 * table to be used efficiently without resizing, it is left the same size and
47 * rehashing is performed effectively in place, allowing the deleted items to
48 * be removed.
49 * <br>
50 * For info on adding new hashing algorithms, please see the HashFunction class.
51 *@author Mike Buland
52 *@todo Fix probing for tables that allow duplicates, and delete an item, then
53 * insert an item with the same name.
54 */
55class HashTable
56{
57public:
58 /** Constructs a hash table.
59 *@param hNewFunc A pointer to a hashfunction class to use. If this is
60 * null the default general string type will be used.
61 *@param nInitSize The initial size of the hashtable.
62 *@param bAllowDupes Setting this value to true allows the system to
63 * insert more than one copy of any given key. This can be tricky, and
64 * will require you to use the nSkip parameter on the get function.
65 */
66 HashTable( HashFunction *hNewFunc, unsigned long int nInitSize, bool bAllowDupes=false );
67
68 /**
69 * Destroys the hashtable, cleaning up all internal storage, but not stored
70 * elements. Also deletes the HashFunction passed in in the constructor.
71 */
72 virtual ~HashTable();
73
74 /** Inserts an item into the hashtable. This function will trigger a
75 * rehash if adding another item would force the table's load factor over
76 * the danger level.
77 *@param id used to find the data later.
78 *@param data The data item to insert into the table with the identifier
79 * id
80 *@returns True if insertion was successfull, and false if it failed.
81 */
82 bool insert( const void *id, const void *data );
83
84 /** Gets an item in the hashtable based on the id of that item. If there
85 * is more than one item with the same id you can use the nSkip parameter
86 * to access all of them.
87 *@param id The id of the item you're trying to find.
88 *@param nSkip The number of items with that id to skip before returning
89 * with the requested item.
90 *@returns A pointer to the data stored at the given id.
91 */
92 const void *get( const void *id, unsigned long int nSkip=0 );
93
94 const void *getKey( const void *id, unsigned long int nSkip=0 );
95
96 /** Gets the total capacity of the hashtable. This is actually the number
97 * of total positions available inside the hashtable at the moment. This
98 * will change when the hashtable's load exceeds the danger level.
99 * Please note that this is NOT the actual amount of space available.
100 * In reality you can only access about 45-50 percent of that space.
101 *@returns The total capacity.
102 */
103 unsigned long int getCapacity();
104
105 /** Gets the number of filled in items in the hash table. This is roughly
106 * equivelent to the getSize function assosiated with the Lists.
107 *@returns The number of filled in items in the hash table.
108 */
109 unsigned long int getSize();
110
111 /** Gets the load (percentage) of filled in items in the table. This is
112 * technically the size divided by the capacity, but is definately usefull
113 * since it's required to check if it's time to rehash.
114 *@returns The table load in the range 0.0 to 1.0
115 */
116 double getLoad();
117
118 /** Sets up an xPos object for use indexing the items in the table. Call
119 * this first and follow the directions for getNextItemPos below to
120 * iterate through every item in the table, while avoiding the empty
121 * spaces.
122 *@returns A pointer to a xPos object telling the hashtable where to find
123 * the item you're looking at.
124 */
125 void *getFirstItemPos();
126
127 /** Get the item's data that is being pointed to by xPos. This is only
128 * valid after xPos was created using getFirstItemPos and getNextItemPos
129 * was called at least once.
130 *@param xPos supplied by getFirstItemPos.
131 *@returns The key value that was used to insert the data into the table.
132 */
133 const void *getItemData( void *xPos );
134
135 /** Get the item's ID that is being pointed to by xPos. This is only
136 * valid after xPos was created using getFirstItemPos and getNextItemPos
137 * was called at least once.
138 *@param xPos supplied by getFirstItemPos.
139 *@returns The key value that was used to insert the data into the table.
140 */
141 const void *getItemID( void *xPos );
142
143 /** Used for iterating through a hash table sequentially. This will
144 * update the xPos pointer to point to the next time, all ready to
145 * be accessed with getItemID and getItemData. This must be called at
146 * least once before xPos is meaningful, and will return a NULL when it
147 * has reached the last item.
148 *@param xPos This must be an object created by a call to the function
149 * getFirstItemPos, and is only meaningful to the internal routines.
150 * Aborting a call in the middle (not running to the end of the table)
151 * may result in a memory leak at the moment.
152 *@returns xPos if still iterating through the list, otherwise it will
153 * return NULL when the end has been reached and the xPos variable has
154 * been deleted.
155 */
156 void *getNextItemPos( void *xPos );
157
158 /** A helpful operator to make accessing items easier. Please note that
159 * this simply returns a pointer to the data stored internally, and cannot
160 * be used like the STL operator to store new data, use insert for that.
161 *@param id The identifier used to store the requested item.
162 *@returns The data value assosiated with the given id, or NULL if it
163 * wasn't found in the table.
164 */
165 const void *operator[](const void *id);
166
167 /**
168 * Delete the specified item from the hashtable. This actually keeps the
169 * data and marks it deleted. For all intents and purposes to the user it
170 * is deleted, except that the space is still used until a rehash is forced.
171 * This means that in hashtables where elements are being inserted and
172 * deleted frequently you may run into a higher rate of expansion.
173 *@param id The ID to delete.
174 *@param nSkip The number of similar id's to skip before deleting in a
175 * hashtable that allows duplicates.
176 *@returns True if the element was found and deleted, false otherwise.
177 */
178 bool del( const void *id, int nSkip=0 );
179
180 /**
181 * Deletes every entry in the hash table. See the notes on del to see what
182 * this means, except that since no data is being kept, the entire table is
183 * just marked as usable space.
184 */
185 void clear();
186
187private:
188 /**
189 * Contains info related to a position in the hashtable. Used for
190 * searching through hashtables one item at a time, in order. This class
191 * should never be created by anything but a HashTable, and should never
192 * be referenced directly. Instead the hashtable returns a void pointer,
193 * which is what should be passed back in next time you use a search
194 * function. Always finish a search, since the object is deleted at the
195 * end of the search.
196 *@author Mike Buland
197 */
198 class HashPos
199 {
200 public:
201 /** Create a blank HashPos. */
202 HashPos() { bStarted=false; nPos = 0; };
203 /** Has the search been started? */
204 bool bStarted;
205 /** The position (index) into the backend storage structure. */
206 unsigned long int nPos;
207 };
208
209 /**
210 * All data related to a single element in the hashtable. This should
211 * really only be used and manipulated by the HashTable itself.
212 *@author Mike Buland
213 */
214 typedef struct HashNode
215 {
216 public:
217 /** Create a new, empty HashNode. */
218 HashNode() { id = NULL; data = NULL; bDeleted = false; };
219 /** A pointer to the original ID that was used to key the data. */
220 const void *id;
221 /** A pointer to the data stored along with the above ID. */
222 const void *data;
223 /** Weather or not this data should really...exist */
224 bool bDeleted;
225 } HashNode;
226
227private:
228 /**
229 * Just sets the values in the element to some friendly values.
230 *@param newID The new ID to store.
231 *@param newData The new Data to store.
232 */
233 void set( int j, const void *newID, const void *newData );
234 /**
235 * Tells you if the node is filled or not.
236 *@returns True=an ID has been stored here, False=no ID.
237 */
238 bool isFilled( int j );
239 /**
240 * This actually resizes, but since every resize requires a reHash to go
241 * along with it, that's the name. This actually creates a new buffer for
242 * all of the contained data and then pulls every old element that was in
243 * the old table out and performs the hashing placement calculations again.
244 * This function skips all data that was marked as deleted, so at this
245 * point it really will be.
246 *@param nNewSize The new size to set the table to while re-hashing.
247 *@returns True if the operation was successful, false otherwise.
248 */
249 void reHash( unsigned long int nNewSize );
250
251 /**
252 * Helper function to allocate a new table. Really just does the memory
253 * allocation.
254 *@param nNewSize The size of the table to generate.
255 *@returns A new, blank array of HashNode objects the size you specified.
256 */
257 HashNode *newTable( unsigned long int nNewSize );
258
259 /**
260 * This function is used once an actual hash code is obtained. nStart is
261 * the given hash code, which is then wrapped to the size of the table. If
262 * there is data at that location, tests are performed to see if it's the
263 * right one. If it is, then it is returned, otherwise a series of further
264 * tests based on a 2^n search pattern is performed. The position of the
265 * requested data in the back-end storage is returned if found, otherwise
266 * another less useful value is returned...
267 *@param nStart The initial hashcode of the ID testing for.
268 *@param id A pointer to the id that is being searched for.
269 *@returns The real location of the data requested.
270 */
271 unsigned long int probe( unsigned long int nStart, const void *id );
272
273 /**
274 * Simple helper function to determine if a number is prime or not.
275 * This function runs in sqrt(n) time.
276 *@param num Number to test for prime-hood.
277 *@returns True if the number is prime, false otherwise.
278 */
279 bool isPrime( int num );
280
281 /**
282 * Given any number, this function finds the first number after it that is
283 * prime. Since this number is a multiple internally it's rare that the
284 * starting number would be prime.
285 *@param base The number to start the prime search on.
286 *@returns The first prime after the number given.
287 */
288 int nextPrime( int base );
289
290#ifdef HASH_DEBUG_VIS
291 void printDebugLine( const char *exData );
292#endif
293
294 /** A pointer to the HashFunction subclass instance to use. */
295 HashFunction *hFunc;
296 /** The complete array of HashNode objects to store data in. */
297 HashNode *aTable;
298 /** The actual size of the table, not how many elements are in it. */
299 unsigned long int nTableSize;
300 /** The number of elements that are in the table. */
301 unsigned long int nSize;
302 /** The number of elements that are unavailable now. */
303 unsigned long int nFilled;
304 /** Allow duplicate ID's in the table. */
305 bool bAllowDupes;
306};
307
308#endif
diff --git a/src/inprogress/xmldocument.cpp b/src/inprogress/xmldocument.cpp
new file mode 100644
index 0000000..cb21826
--- /dev/null
+++ b/src/inprogress/xmldocument.cpp
@@ -0,0 +1,9 @@
1#include "xmldocument.h"
2
3Bu::XmlDocument::XmlDocument()
4{
5}
6
7Bu::XmlDocument::~XmlDocument()
8{
9}
diff --git a/src/inprogress/xmldocument.h b/src/inprogress/xmldocument.h
new file mode 100644
index 0000000..e16e3ea
--- /dev/null
+++ b/src/inprogress/xmldocument.h
@@ -0,0 +1,22 @@
1#ifndef XML_DOCUMENT_H
2#define XML_DOCUMENT_H
3
4#include <stdint.h>
5
6namespace Bu
7{
8 /**
9 *
10 */
11 class XmlDocument
12 {
13 public:
14 XmlDocument();
15 virtual ~XmlDocument();
16
17 private:
18
19 };
20}
21
22#endif
diff --git a/src/inprogress/xmlnode.cpp b/src/inprogress/xmlnode.cpp
new file mode 100644
index 0000000..58ef5c5
--- /dev/null
+++ b/src/inprogress/xmlnode.cpp
@@ -0,0 +1,9 @@
1#include "xmlnode.h"
2
3Bu::XmlNode::XmlNode()
4{
5}
6
7Bu::XmlNode::~XmlNode()
8{
9}
diff --git a/src/inprogress/xmlnode.h b/src/inprogress/xmlnode.h
new file mode 100644
index 0000000..cd9961a
--- /dev/null
+++ b/src/inprogress/xmlnode.h
@@ -0,0 +1,22 @@
1#ifndef XML_NODE_H
2#define XML_NODE_H
3
4#include <stdint.h>
5
6namespace Bu
7{
8 /**
9 *
10 */
11 class XmlNode
12 {
13 public:
14 XmlNode();
15 virtual ~XmlNode();
16
17 private:
18
19 };
20}
21
22#endif
diff --git a/src/inprogress/xmlreader.cpp b/src/inprogress/xmlreader.cpp
new file mode 100644
index 0000000..bd241cf
--- /dev/null
+++ b/src/inprogress/xmlreader.cpp
@@ -0,0 +1,267 @@
1#include "xmlreader.h"
2
3Bu::XmlReader::XmlReader( Bu::Stream &sIn ) :
4 sIn( sIn )
5{
6}
7
8Bu::XmlReader::~XmlReader()
9{
10}
11
12const char *Bu::XmlReader::lookahead( int nAmnt )
13{
14 if( sBuf.getSize() >= nAmnt )
15 return sBuf.getStr();
16
17 int nNew = nAmnt - sBuf.getSize();
18 char *buf = new char[nNew];
19 sIn.read( buf, nNew );
20 sBuf.append( buf );
21
22 return sBuf.getStr();
23}
24
25void Bu::XmlReader::burn( int nAmnt )
26{
27 if( sBuf.getSize() < nAmnt )
28 {
29 lookahead( nAmnt );
30 }
31
32 //sBuf.remove( nAmnt );
33}
34
35void Bu::XmlReader::checkString( const char *str, int nLen )
36{
37 if( !strncmp( str, lookahead( nLen ), nLen ) )
38 {
39 burn( nLen );
40 return;
41 }
42
43 throw Bu::ExceptionBase("Expected string '%s'", str );
44}
45
46Bu::XmlNode *Bu::XmlReader::read()
47{
48 prolog();
49}
50
51void Bu::XmlReader::prolog()
52{
53 XMLDecl();
54 Misc();
55}
56
57void Bu::XmlReader::XMLDecl()
58{
59 checkString("<?xml", 5 );
60 S();
61 VersionInfo();
62 EncodingDecl();
63 SDDecl();
64 Sq();
65 checkString("?>", 2 );
66}
67
68void Bu::XmlReader::Misc()
69{
70 for(;;)
71 {
72 S();
73 if( !strncmp("<!--", lookahead( 4 ), 4 ) )
74 {
75 Comment();
76 }
77 else if( !strncmp("<?", lookahead( 2 ), 2 ) )
78 {
79 PI();
80 }
81 else
82 {
83 return;
84 }
85 }
86}
87
88void Bu::XmlReader::Comment()
89{
90 checkString("<!--", 4 );
91 for(;;)
92 {
93 unsigned char c = *lookahead(1);
94 if( c == '-' )
95 {
96 if( lookahead(2)[1] == '-' )
97 {
98 checkString("-->", 3 );
99 return;
100 }
101 }
102 burn( 1 );
103 }
104}
105
106void Bu::XmlReader::PI()
107{
108 checkString("<?", 2 );
109 FString sName = Name();
110 printf("PI: %s\n---\n", sName.getStr() );
111 S();
112 for(int j = 0;; j++ )
113 {
114 if( !strncmp( "?>", lookahead(j+2)+j, 2 ) )
115 {
116 burn( j+2 );
117 return;
118 }
119 }
120}
121
122void Bu::XmlReader::S()
123{
124 for( int j = 0;; j++ )
125 {
126 char c = *lookahead( 1 );
127 if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA )
128 continue;
129 if( j == 0 )
130 throw ExceptionBase("Expected whitespace.");
131 return;
132 }
133}
134
135void Bu::XmlReader::Sq()
136{
137 for(;;)
138 {
139 char c = *lookahead( 1 );
140 if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA )
141 continue;
142 return;
143 }
144}
145
146void Bu::XmlReader::VersionInfo()
147{
148 try
149 {
150 S();
151 checkString("version", 7 );
152 }
153 catch( ExceptionBase &e )
154 {
155 return;
156 }
157 Eq();
158 Bu::FString ver = AttValue();
159 if( ver != "1.1" )
160 throw ExceptionBase("Currently we only support xml version 1.1\n");
161}
162
163void Bu::XmlReader::Eq()
164{
165 Sq();
166 checkString("=", 1 );
167 Sq();
168}
169
170void Bu::XmlReader::EncodingDecl()
171{
172 S();
173 try
174 {
175 checkString("encoding", 8 );
176 }
177 catch( ExceptionBase &e )
178 {
179 return;
180 }
181
182 Eq();
183 AttValue();
184}
185
186void Bu::XmlReader::SDDecl()
187{
188 S();
189 try
190 {
191 checkString("standalone", 10 );
192 }
193 catch( ExceptionBase &e )
194 {
195 return;
196 }
197
198 Eq();
199 AttValue();
200}
201
202Bu::FString Bu::XmlReader::AttValue()
203{
204 char q = *lookahead(1);
205 if( q == '\"' )
206 {
207 for( int j = 2;; j++ )
208 {
209 if( lookahead(j)[j-1] == '\"' )
210 {
211 Bu::FString ret( lookahead(j)+1, j-2 );
212 burn( j );
213 return ret;
214 }
215 }
216 }
217 else if( q == '\'' )
218 {
219 for( int j = 2;; j++ )
220 {
221 if( lookahead(j)[j-1] == '\'' )
222 {
223 Bu::FString ret( lookahead(j)+1, j-2 );
224 burn( j );
225 return ret;
226 }
227 }
228 }
229
230 throw ExceptionBase("Excpected either \' or \".\n");
231}
232
233Bu::FString Bu::XmlReader::Name()
234{
235 unsigned char c = *lookahead( 1 );
236 if( c != ':' && c != '_' &&
237 (c < 'A' || c > 'Z') &&
238 (c < 'a' || c > 'z') &&
239 (c < 0xC0 || c > 0xD6 ) &&
240 (c < 0xD8 || c > 0xF6 ) &&
241 (c < 0xF8))
242 {
243 throw ExceptionBase("Invalid entity name starting character.");
244 }
245
246 for( int j = 1;; j++ )
247 {
248 unsigned char c = lookahead(j+1)[j];
249 if( isS( c ) )
250 {
251 FString ret( lookahead(j+1), j+1 );
252 burn( j+1 );
253 return ret;
254 }
255 if( c != ':' && c != '_' && c != '-' && c != '.' && c != 0xB7 &&
256 (c < 'A' || c > 'Z') &&
257 (c < 'a' || c > 'z') &&
258 (c < '0' || c > '9') &&
259 (c < 0xC0 || c > 0xD6 ) &&
260 (c < 0xD8 || c > 0xF6 ) &&
261 (c < 0xF8))
262 {
263 throw ExceptionBase("Invalid character in name.");
264 }
265 }
266}
267
diff --git a/src/inprogress/xmlreader.h b/src/inprogress/xmlreader.h
new file mode 100644
index 0000000..708a386
--- /dev/null
+++ b/src/inprogress/xmlreader.h
@@ -0,0 +1,121 @@
1#ifndef XML_READER_H
2#define XML_READER_H
3
4#include <stdint.h>
5#include "bu/stream.h"
6#include "bu/fstring.h"
7#include "bu/xmlnode.h"
8
9namespace Bu
10{
11 /**
12 * An Xml 1.1 reader. I've decided to write this, this time, based on the
13 * official W3C reccomendation, now included with the source code. I've
14 * named the productions in the parser states the same as in that document,
15 * which may make them easier to find, etc, although possibly slightly less
16 * optimized than writing my own reduced grammer.
17 *
18 * Below I will list differences between my parser and the official standard
19 * as I come up with them.
20 * - Encoding and Standalone headings are ignored for the moment. (4.3.3,
21 * 2.9)
22 * - The standalone heading attribute can have any standard whitespace
23 * before it (the specs say only spaces, no newlines). (2.9)
24 * - Since standalone is ignored, it is currently allowed to have any
25 * value (should be restricted to "yes" or "no"). (2.9)
26 * - Currently only UTF-8 / ascii are parsed.
27 * - [optional] The content of comments is thrown away. (2.5)
28 * - The content of processing instruction blocks is parsed properly, but
29 * thrown away. (2.6)
30 */
31 class XmlReader
32 {
33 public:
34 XmlReader( Bu::Stream &sIn );
35 virtual ~XmlReader();
36
37 XmlNode *read();
38
39 private:
40 Bu::Stream &sIn;
41 Bu::FString sBuf;
42
43 private: // Helpers
44 const char *lookahead( int nAmnt );
45 void burn( int nAmnt );
46 void checkString( const char *str, int nLen );
47
48 private: // States
49 /**
50 * The headers, etc.
51 */
52 void prolog();
53
54 /**
55 * The xml decleration (version, encoding, etc).
56 */
57 void XMLDecl();
58
59 /**
60 * Misc things, Includes Comments and PIData (Processing Instructions).
61 */
62 void Misc();
63
64 /**
65 * Comments
66 */
67 void Comment();
68
69 /**
70 * Processing Instructions
71 */
72 void PI();
73
74 /**
75 * Whitespace eater.
76 */
77 void S();
78
79 /**
80 * Optional whitespace eater.
81 */
82 void Sq();
83
84 /**
85 * XML Version spec
86 */
87 void VersionInfo();
88
89 /**
90 * Your basic equals sign with surrounding whitespace.
91 */
92 void Eq();
93
94 /**
95 * Read in an attribute value.
96 */
97 FString AttValue();
98
99 /**
100 * Read in the name of something.
101 */
102 FString Name();
103
104 /**
105 * Encoding decleration in the header
106 */
107 void EncodingDecl();
108
109 /**
110 * Standalone decleration in the header
111 */
112 void SDDecl();
113
114 bool isS( unsigned char c )
115 {
116 return ( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA );
117 }
118 };
119}
120
121#endif
diff --git a/src/inprogress/xmlwriter.cpp b/src/inprogress/xmlwriter.cpp
new file mode 100644
index 0000000..23a5175
--- /dev/null
+++ b/src/inprogress/xmlwriter.cpp
@@ -0,0 +1,9 @@
1#include "xmlwriter.h"
2
3Bu::XmlWriter::XmlWriter()
4{
5}
6
7Bu::XmlWriter::~XmlWriter()
8{
9}
diff --git a/src/inprogress/xmlwriter.h b/src/inprogress/xmlwriter.h
new file mode 100644
index 0000000..796d6fb
--- /dev/null
+++ b/src/inprogress/xmlwriter.h
@@ -0,0 +1,22 @@
1#ifndef XML_WRITER_H
2#define XML_WRITER_H
3
4#include <stdint.h>
5
6namespace Bu
7{
8 /**
9 *
10 */
11 class XmlWriter
12 {
13 public:
14 XmlWriter();
15 virtual ~XmlWriter();
16
17 private:
18
19 };
20}
21
22#endif
diff --git a/src/ito.cpp b/src/ito.cpp
new file mode 100644
index 0000000..001ca06
--- /dev/null
+++ b/src/ito.cpp
@@ -0,0 +1,40 @@
1#include "ito.h"
2
3Bu::Ito::Ito()
4{
5}
6
7Bu::Ito::~Ito()
8{
9}
10
11bool Bu::Ito::start()
12{
13 nHandle = pthread_create( &ptHandle, NULL, threadRunner, this );
14
15 return true;
16}
17
18bool Bu::Ito::stop()
19{
20 pthread_exit( &ptHandle );
21
22 return true;
23}
24
25void *Bu::Ito::threadRunner( void *pThread )
26{
27 return ((Ito *)pThread)->run();
28}
29
30bool Bu::Ito::join()
31{
32 pthread_join( ptHandle, NULL );
33 return true;
34}
35
36void Bu::Ito::yield()
37{
38 pthread_yield();
39}
40
diff --git a/src/ito.h b/src/ito.h
new file mode 100644
index 0000000..c062052
--- /dev/null
+++ b/src/ito.h
@@ -0,0 +1,98 @@
1#ifndef BU_ITO_H
2#define BU_ITO_H
3
4#include <pthread.h>
5
6namespace Bu
7{
8 /**
9 * Simple thread class. This wraps the basic pthread (posix threads) system in
10 * an object oriented sort of way. It allows you to create a class with
11 * standard member variables and callable functions that can be run in it's own
12 * thread, one per class instance.
13 *@author Mike Buland
14 */
15 class Ito
16 {
17 public:
18 /**
19 * Construct an Ito thread.
20 */
21 Ito();
22
23 /**
24 * Destroy an Ito thread.
25 */
26 virtual ~Ito();
27
28 /**
29 * Begin thread execution. This will call the overridden run function,
30 * which will simply execute in it's own thread until the function exits,
31 * the thread is killed, or the thread is cancelled (optionally). The
32 * thread started in this manner has access to all of it's class variables,
33 * but be sure to protect possible multiple-access with ItoMutex objects.
34 *@returns True if starting the thread was successful. False if something
35 * went wrong and the thread has not started.
36 */
37 bool start();
38
39 /**
40 * Forcibly kill a thread. This is not generally considered a good thing to
41 * do, but in those rare cases you need it, it's invaluable. The problem
42 * with stopping (or killing) a thread is that it stops it the moment you
43 * call stop, no matter what it's doing. The object oriented approach to
44 * this will help clean up any class variables that were used, but anything
45 * not managed as a member variable will probably create a memory leak type
46 * of situation. Instead of stop, consider using cancel, which can be
47 * handled by the running thread in a graceful manner.
48 *@returns True if the thread was stopped, false otherwise. When this
49 * function returns the thread may not have stopped, to ensure that the
50 * thread has really stopped, call join.
51 */
52 bool stop();
53
54 /**
55 * The workhorse of the Ito class. This is the function that will run in
56 * the thread, when this function exits the thread dies and is cleaned up
57 * by the system. Make sure to read up on ItoMutex, ItoCondition, and
58 * cancel to see how to control and protect everything you do in a safe way
59 * within this function.
60 *@returns I'm not sure right now, but this is the posix standard form.
61 */
62 virtual void *run()=0;
63
64 /**
65 * Join the thread in action. This function performs what is commonly
66 * called a thread join. That is that it effectively makes the calling
67 * thread an the Ito thread contained in the called object one in the same,
68 * and pauses the calling thread until the called thread exits. That is,
69 * when called from, say, your main(), mythread.join() will not return until
70 * the thread mythread has exited. This is very handy at the end of
71 * programs to ensure all of your data was cleaned up.
72 *@returns True if the thread was joined, false if the thread couldn't be
73 * joined, usually because it isn't running to begin with.
74 */
75 bool join();
76
77 private:
78 pthread_t ptHandle; /**< Internal handle to the posix thread. */
79 int nHandle; /**< Numeric handle to the posix thread. */
80
81 protected:
82 /**
83 * This is the hidden-heard of the thread system. While run is what the
84 * user gets to override, and everything said about it is true, this is
85 * the function that actually makes up the thread, it simply calls the
86 * run member function in an OO-friendly way. This is what allows us to
87 * use member variables from within the thread itself.
88 *@param Should always be this.
89 *@returns This is specified by posix, I'm not sure yet.
90 */
91 static void *threadRunner( void *pThread );
92
93 void yield();
94
95 };
96}
97
98#endif
diff --git a/src/itoatom.h b/src/itoatom.h
new file mode 100644
index 0000000..7fc9090
--- /dev/null
+++ b/src/itoatom.h
@@ -0,0 +1,56 @@
1#ifndef BU_ITO_QUEUE_H
2#define BU_ITO_QUEUE_H
3
4#include <pthread.h>
5
6#include "itomutex.h"
7#include "itocondition.h"
8
9/**
10 * A thread-safe wrapper class.
11 *@author Mike Buland
12 */
13template <class T>
14class ItoAtom
15{
16public:
17 /**
18 * Construct an empty queue.
19 */
20 ItoAtom()
21 {
22 }
23
24 ItoAtom( const T &src ) :
25 data( src )
26 {
27 }
28
29 ~ItoQueue()
30 {
31 }
32
33 T get()
34 {
35 mOperate.lock();
36 mOperate.unlock();
37 return data;
38 }
39
40 void set( const T &val )
41 {
42 mOperate.lock();
43 data = val;
44 cBlock.signal();
45 mOperate.unlock();
46 }
47
48private:
49 Item *pStart; /**< The start of the queue, the next element to dequeue. */
50 Item *pEnd; /**< The end of the queue, the last element to dequeue. */
51
52 ItoMutex mOperate; /**< The master mutex, used on all operations. */
53 ItoCondition cBlock; /**< The condition for blocking dequeues. */
54};
55
56#endif
diff --git a/src/itocondition.cpp b/src/itocondition.cpp
new file mode 100644
index 0000000..d8f5375
--- /dev/null
+++ b/src/itocondition.cpp
@@ -0,0 +1,42 @@
1#include <sys/time.h>
2
3#include "itocondition.h"
4
5Bu::ItoCondition::ItoCondition()
6{
7 pthread_cond_init( &cond, NULL );
8}
9
10Bu::ItoCondition::~ItoCondition()
11{
12 pthread_cond_destroy( &cond );
13}
14
15int Bu::ItoCondition::wait()
16{
17 return pthread_cond_wait( &cond, &mutex );
18}
19
20int Bu::ItoCondition::wait( int nSec, int nUSec )
21{
22 struct timeval now;
23 struct timespec timeout;
24 struct timezone tz;
25
26 gettimeofday( &now, &tz );
27 timeout.tv_sec = now.tv_sec + nSec + ((now.tv_usec + nUSec)/1000000);
28 timeout.tv_nsec = ((now.tv_usec + nUSec)%1000000)*1000;
29
30 return pthread_cond_timedwait( &cond, &mutex, &timeout );
31}
32
33int Bu::ItoCondition::signal()
34{
35 return pthread_cond_signal( &cond );
36}
37
38int Bu::ItoCondition::broadcast()
39{
40 return pthread_cond_broadcast( &cond );
41}
42
diff --git a/src/itocondition.h b/src/itocondition.h
new file mode 100644
index 0000000..1793f81
--- /dev/null
+++ b/src/itocondition.h
@@ -0,0 +1,81 @@
1#ifndef BU_ITO_CONDITION_H
2#define BU_ITO_CONDITION_H
3
4#include <pthread.h>
5
6#include "itomutex.h"
7
8namespace Bu
9{
10 /**
11 * Ito condition. This is a fairly simple condition mechanism. As you may
12 * notice this class inherits from the ItoMutex class, this is because all
13 * conditions must be within a locked block. The standard usage of a condition
14 * is to pause one thread, perhaps indefinately, until another thread signals
15 * that it is alright to procede.
16 * <br>
17 * Standard usage for the thread that wants to wait is as follows:
18 * <pre>
19 * ItoCondition cond;
20 * ... // Perform setup and enter your run loop
21 * cond.lock();
22 * while( !isFinished() ) // Could be anything you're waiting for
23 * cond.wait();
24 * ... // Take care of what you have to.
25 * cond.unlock();
26 * </pre>
27 * The usage for the triggering thread is much simpler, when it needs to tell
28 * the others that it's time to grab some data it calls either signal or
29 * broadcast. See both of those functions for the difference.
30 *@author Mike Buland
31 */
32 class ItoCondition : public ItoMutex
33 {
34 public:
35 /**
36 * Create a condition.
37 */
38 ItoCondition();
39
40 /**
41 * Destroy a condition.
42 */
43 ~ItoCondition();
44
45 /**
46 * Wait forever, or until signalled. This has to be called from within a
47 * locked section, i.e. before calling this this object's lock function
48 * should be called.
49 */
50 int wait();
51
52 /**
53 * Wait for a maximum of nSec seconds and nUSec micro-seconds or until
54 * signalled. This is a little more friendly function if you want to
55 * perform other operations in the thrad loop that calls this function.
56 * Like the other wait function, this must be inside a locked section.
57 *@param nSec The seconds to wait.
58 *@param nUSec the micro-seconds to wait.
59 */
60 int wait( int nSec, int nUSec );
61
62 /**
63 * Notify the next thread waiting on this condition that they can go ahead.
64 * This only signals one thread, the next one in the condition queue, that
65 * it is safe to procede with whatever operation was being waited on.
66 */
67 int signal();
68
69 /**
70 * Notify all threads waiting on this condition that they can go ahead now.
71 * This function is slower than signal, but more effective in certain
72 * situations where you may not know how many threads should be activated.
73 */
74 int broadcast();
75
76 private:
77 pthread_cond_t cond; /**< Internal condition reference. */
78 };
79}
80
81#endif
diff --git a/src/itomutex.cpp b/src/itomutex.cpp
new file mode 100644
index 0000000..dc51af9
--- /dev/null
+++ b/src/itomutex.cpp
@@ -0,0 +1,27 @@
1#include "itomutex.h"
2
3Bu::ItoMutex::ItoMutex()
4{
5 pthread_mutex_init( &mutex, NULL );
6}
7
8Bu::ItoMutex::~ItoMutex()
9{
10 pthread_mutex_destroy( &mutex );
11}
12
13int Bu::ItoMutex::lock()
14{
15 return pthread_mutex_lock( &mutex );
16}
17
18int Bu::ItoMutex::unlock()
19{
20 return pthread_mutex_unlock( &mutex );
21}
22
23int Bu::ItoMutex::trylock()
24{
25 return pthread_mutex_trylock( &mutex );
26}
27
diff --git a/src/itomutex.h b/src/itomutex.h
new file mode 100644
index 0000000..9c9d205
--- /dev/null
+++ b/src/itomutex.h
@@ -0,0 +1,61 @@
1#ifndef BU_ITO_MUTEX_H
2#define BU_ITO_MUTEX_H
3
4#include <pthread.h>
5
6namespace Bu
7{
8 /**
9 * Simple mutex wrapper. Currently this doesn't do anything extra for you
10 * except keep all of the functionality together in an OO sorta' way and keep
11 * you from having to worry about cleaning up your mutexes properly, or initing
12 * them.
13 *@author Mike Buland
14 */
15 class ItoMutex
16 {
17 public:
18 /**
19 * Create an unlocked mutex.
20 */
21 ItoMutex();
22
23 /**
24 * Destroy a mutex. This can only be done when a mutex is unlocked.
25 * Failure to unlock before destroying a mutex object could cause it to
26 * wait for the mutex to unlock, the odds of which are usually farily low
27 * at deconstruction time.
28 */
29 ~ItoMutex();
30
31 /**
32 * Lock the mutex. This causes all future calls to lock on this instance
33 * of mutex to block until the first thread that called mutex unlocks it.
34 * At that point the next thread that called lock will get a chance to go
35 * to work. Because of the nature of a mutex lock it is a very bad idea to
36 * do any kind of serious or rather time consuming computation within a
37 * locked section. This can cause thread-deadlock and your program may
38 * hang.
39 */
40 int lock();
41
42 /**
43 * Unlock the mutex. This allows the next thread that asked for a lock to
44 * lock the mutex and continue with execution.
45 */
46 int unlock();
47
48 /**
49 * Try to lock the mutex. This is the option to go with if you cannot avoid
50 * putting lengthy operations within a locked section. trylock will attempt
51 * to lock the mutex, if the mutex is already locked this function returns
52 * immediately with an error code.
53 */
54 int trylock();
55
56 protected:
57 pthread_mutex_t mutex; /**< The internal mutex reference. */
58 };
59}
60
61#endif
diff --git a/src/itoqueue.h b/src/itoqueue.h
new file mode 100644
index 0000000..75a2f27
--- /dev/null
+++ b/src/itoqueue.h
@@ -0,0 +1,231 @@
1#ifndef BU_ITO_QUEUE_H
2#define BU_ITO_QUEUE_H
3
4#include <pthread.h>
5
6#include "itomutex.h"
7#include "itocondition.h"
8
9namespace Bu
10{
11 /**
12 * A thread-safe queue class. This class is a very simple queue with some cool
13 * extra functionality for use with the Ito system. The main extra that it
14 * provides is the option to either dequeue without blocking, with infinite
15 * blocking, or with timed blocking, which will return a value if something is
16 * enqueued within the specified time limit, or NULL if the time limit is
17 * exceded.
18 *@author Mike Buland
19 */
20 template <class T>
21 class ItoQueue
22 {
23 private:
24 /**
25 * Helper struct. Keeps track of linked-list items for the queue data.
26 */
27 typedef struct Item
28 {
29 T pData;
30 Item *pNext;
31 } Item;
32
33 public:
34 /**
35 * Construct an empty queue.
36 */
37 ItoQueue() :
38 pStart( NULL ),
39 pEnd( NULL ),
40 nSize( 0 )
41 {
42 }
43
44 /**
45 * Destroy the queue. This function will simply free all contained
46 * structures. If you stored pointers in the queue, this will lose the
47 * pointers without cleaning up the memory they pointed to. Make sure
48 * you're queue is empty before allowing it to be destroyed!
49 */
50 ~ItoQueue()
51 {
52 Item *pCur = pStart;
53 while( pCur )
54 {
55 Item *pTmp = pCur->pNext;
56 delete pCur;
57 pCur = pTmp;
58 }
59 }
60
61 /**
62 * Enqueue a pieces of data. The new data will go at the end of the queue,
63 * and unless another piece of data is enqueued, will be the last piece of
64 * data to be dequeued.
65 *@param pData The data to enqueue. If this is not a primitive data type
66 * it's probably best to use a pointer type.
67 */
68 void enqueue( T pData )
69 {
70 mOperate.lock();
71
72 if( pStart == NULL )
73 {
74 pStart = pEnd = new Item;
75 pStart->pData = pData;
76 pStart->pNext = NULL;
77 nSize++;
78 }
79 else
80 {
81 pEnd->pNext = new Item;
82 pEnd = pEnd->pNext;
83 pEnd->pData = pData;
84 pEnd->pNext = NULL;
85 nSize++;
86 }
87
88 cBlock.signal();
89
90 mOperate.unlock();
91 }
92
93 /**
94 * Dequeue the first item from the queue. This function can operate in two
95 * different modes, blocking and non-blocking. In non-blocking mode it will
96 * return immediately weather there was data in the queue or not. If there
97 * was data it will remove it from the queue and return it to the caller.
98 * In blocking mode it will block forever wating for data to be enqueued.
99 * When data finally is enqueued this function will return immediately with
100 * the new data. The only way this function should ever return a null in
101 * blocking mode is if the calling thread was cancelled. It's probably a
102 * good idea to check for NULL return values even if you use blocking, just
103 * to be on the safe side.
104 *@param bBlock Set to true to enable blocking, leave as false to work in
105 * non-blocking mode.
106 *@returns The next piece of data in the queue, or NULL if no data was in
107 * the queue.
108 */
109 T dequeue( bool bBlock=false )
110 {
111 mOperate.lock();
112 if( pStart == NULL )
113 {
114 mOperate.unlock();
115
116 if( bBlock )
117 {
118 cBlock.lock();
119
120 while( pStart == NULL )
121 cBlock.wait();
122
123 T tmp = dequeue( false );
124
125 cBlock.unlock();
126 return tmp;
127
128 }
129
130 return NULL;
131 }
132 else
133 {
134 T pTmp = pStart->pData;
135 Item *pDel = pStart;
136 pStart = pStart->pNext;
137 delete pDel;
138 nSize--;
139
140 mOperate.unlock();
141 return pTmp;
142 }
143 }
144
145 /**
146 * Operates just like the other dequeue function in blocking mode with one
147 * twist. This function will block for at most nSec seconds and nUSec
148 * micro-seconds. If the timer is up and no data is available, this will
149 * just return NULL. If data is enqueued before the timeout expires, it
150 * will dequeue and exit immediately.
151 *@param nSec The number of seconds to wait, max.
152 *@param nUSec The number of micro-seconds to wait, max.
153 *@returns The next piece of data in the queue, or NULL if the timeout was
154 * exceeded.
155 */
156 T dequeue( int nSec, int nUSec )
157 {
158 mOperate.lock();
159 if( pStart == NULL )
160 {
161 mOperate.unlock();
162
163 cBlock.lock();
164
165 cBlock.wait( nSec, nUSec );
166
167 if( pStart == NULL )
168 {
169 cBlock.unlock();
170 return NULL;
171 }
172
173 mOperate.lock();
174 T pTmp = pStart->pData;
175 Item *pDel = pStart;
176 pStart = pStart->pNext;
177 delete pDel;
178 nSize--;
179 mOperate.unlock();
180
181 cBlock.unlock();
182 return pTmp;
183 }
184 else
185 {
186 T pTmp = pStart->pData;
187 Item *pDel = pStart;
188 pStart = pStart->pNext;
189 delete pDel;
190 nSize--;
191
192 mOperate.unlock();
193 return pTmp;
194 }
195 }
196
197 /**
198 * Checks to see if the queue has data in it or not. Note that there is no
199 * function to determine the length of the queue. This data isn't kept
200 * track of. If you really need to know, fix this.
201 *@returns True if the queue is empty, false if it has data in it.
202 */
203 bool isEmpty()
204 {
205 mOperate.lock();
206 bool bEmpty = (pStart == NULL );
207 mOperate.unlock();
208
209 return bEmpty;
210 }
211
212 long getSize()
213 {
214 mOperate.lock();
215 long nRet = nSize;
216 mOperate.unlock();
217
218 return nRet;
219 }
220
221 private:
222 Item *pStart; /**< The start of the queue, the next element to dequeue. */
223 Item *pEnd; /**< The end of the queue, the last element to dequeue. */
224 long nSize; /**< The number of items in the queue. */
225
226 ItoMutex mOperate; /**< The master mutex, used on all operations. */
227 ItoCondition cBlock; /**< The condition for blocking dequeues. */
228 };
229}
230
231#endif
diff --git a/src/linkmessage.cpp b/src/linkmessage.cpp
index cf3df42..abe113c 100644
--- a/src/linkmessage.cpp
+++ b/src/linkmessage.cpp
@@ -1,12 +1,11 @@
1#include "linkmessage.h" 1#include "bu/linkmessage.h"
2#include <string.h>
3 2
4LinkMessage::LinkMessage( int nNewMsg ) 3Bu::LinkMessage::LinkMessage( int nNewMsg )
5{ 4{
6 nMsg = nNewMsg; 5 nMsg = nNewMsg;
7} 6}
8 7
9LinkMessage::~LinkMessage() 8Bu::LinkMessage::~LinkMessage()
10{ 9{
11} 10}
12 11
diff --git a/src/linkmessage.h b/src/linkmessage.h
index 6cdfb2f..baa22a6 100644
--- a/src/linkmessage.h
+++ b/src/linkmessage.h
@@ -1,39 +1,42 @@
1/**\file linkmessage.h 1/**\file linkmessage.h
2 */ 2 */
3 3
4#ifndef LINKMESSAGE_H 4#ifndef BU_LINKMESSAGE_H
5#define LINKMESSAGE_H 5#define BU_LINKMESSAGE_H
6 6
7/** 7namespace Bu
8 * A message to be broadcast accross ProgramLinks in a ProgramChain. Generally
9 * one would make a subclass of this in order to transmit more useful
10 * information, but sometimes it isn't necesarry.
11 *@author Mike Buland
12 */
13class LinkMessage
14{ 8{
15public:
16 /** 9 /**
17 * Construct a blank LinkMessage. 10 * A message to be broadcast accross ProgramLinks in a ProgramChain. Generally
11 * one would make a subclass of this in order to transmit more useful
12 * information, but sometimes it isn't necesarry.
13 *@author Mike Buland
18 */ 14 */
19 LinkMessage() {}; 15 class LinkMessage
16 {
17 public:
18 /**
19 * Construct a blank LinkMessage.
20 */
21 LinkMessage() {};
20 22
21 /** 23 /**
22 * Deconstruct a LinkMessage. 24 * Deconstruct a LinkMessage.
23 */ 25 */
24 virtual ~LinkMessage(); 26 virtual ~LinkMessage();
25 27
26 /** 28 /**
27 * Create a LinkMessage object with a specific message assosiated with it 29 * Create a LinkMessage object with a specific message assosiated with it
28 * to start with. 30 * to start with.
29 *@param nNewMsg The message to use in the Message object. 31 *@param nNewMsg The message to use in the Message object.
30 */ 32 */
31 LinkMessage( int nNewMsg ); 33 LinkMessage( int nNewMsg );
32 34
33 /** 35 /**
34 * The message contained in the Message object. 36 * The message contained in the Message object.
35 */ 37 */
36 int nMsg; 38 int nMsg;
37}; 39 };
40}
38 41
39#endif 42#endif
diff --git a/src/list.cpp b/src/list.cpp
index 18f1a66..abe92ad 100644
--- a/src/list.cpp
+++ b/src/list.cpp
@@ -1,10 +1,2 @@
1#include "list.h" 1#include "bu/list.h"
2
3List::List( )
4{
5}
6
7List::~List( )
8{
9}
10 2
diff --git a/src/list.h b/src/list.h
index c71b328..e05ebbc 100644
--- a/src/list.h
+++ b/src/list.h
@@ -1,101 +1,489 @@
1#ifndef LIST_H 1#ifndef BU_LIST_H
2#define LIST_H 2#define BU_LIST_H
3 3
4#include <memory>
5#include "bu/exceptionbase.h"
4 6
5/** The basic List class ADT. This, on it's own, does absolutely nothing, but 7namespace Bu
6 * does define all standard interface functions to access a list.
7 *@author Mike Buland
8 */
9class List
10{ 8{
11public: 9 template<typename value>
12 /** 10 struct ListLink
13 * Construct a list. 11 {
14 */ 12 value *pValue;
15 List(); 13 ListLink *pNext;
14 ListLink *pPrev;
15 };
16 16
17 /** 17 /**
18 * Desconstruct a list. 18 * Linked list template container. This class is similar to the stl list
19 * class except for a few minor changes. First, it doesn't mimic a stack or
20 * queue, use the Stack or Queue clasess for that. Second, when const, all
21 * members are only accessable const. Third, erasing a location does not
22 * invalidate the iterator, it simply points to the next valid location, or
23 * end() if there are no more.
24 *
25 *@param value (typename) The type of data to store in your list
26 *@param valuealloc (typename) Memory Allocator for your value type
27 *@param linkalloc (typename) Memory Allocator for the list links.
19 */ 28 */
20 virtual ~List(); 29 template<typename value, typename valuealloc=std::allocator<value>, typename linkalloc=std::allocator<struct ListLink<value> > >
21 30 class List
22 /** Gets the value at a specified index. 31 {
23 *@param nIndex The index of the item to return. 32 private:
24 *@returns The specified item, or NULL if the index was beyond the range 33 typedef struct ListLink<value> Link;
25 * of the list. 34 typedef class List<value, valuealloc, linkalloc> MyType;
26 *@author Mike Buland
27 */
28 virtual void *getAt( int nIndex ) = 0;
29
30 /** Append the given data to the end of the list. This increases the
31 * size of the list by one.
32 *@param pData The data to append to the list.
33 *@author Mike Buland
34 */
35 virtual void append( void *pData ) = 0;
36
37 /** Inserts an item at the specified position in the list. The
38 * new item takes the index that you specify, and all other items
39 * are moved up one position. The size of the list is increased by
40 * one.
41 *@param pData The value to insert into the list.
42 *@param nPos Where to insert the data into the list.
43 *@author Mike Buland
44 */
45 virtual void insertBefore( void *pData, int nPos = 0 ) = 0;
46
47 /** Determines the size of the list, in elements.
48 *@returns The size of the list.
49 *@author Mike Buland
50 */
51 virtual int getSize( ) = 0;
52
53 /** Determines if the list is empty or not.
54 *@returns True if the list is empty, or false if the list has
55 * data in it (if the size is greater than zero).
56 *@author Mike Buland
57 */
58 virtual bool isEmpty( ) = 0;
59
60 /** Deletes an item at the specified index and moves all other
61 * values down one index. The size of the list is decreased by one.
62 *@param nIndex The index of the item to delete.
63 *@author Mike Buland
64 */
65 virtual void deleteAt( int nIndex ) = 0;
66
67 /** Completely empties the list, and sets the effective size to
68 * zero.
69 *@author Mike Buland
70 */
71 virtual void empty() = 0;
72
73 /** Sets the size of the list. This can be larger or smaller
74 * than what it was previously. If larger, new blank items will
75 * be added to the end of the list. If smaller than the old list
76 * items will be deleted from the end.
77 *@param nNewSize The new size of the list.
78 *@author Mike Buland
79 */
80 virtual void setSize( int nNewSize ) = 0;
81
82 /** Sets a member at a specified location to a new value.
83 * If the member being set is outside of the range of the
84 * current list it should be expanded.
85 *@param nIndex The zero-based index of the item to change.
86 *@param pData The new value for that index.
87 *@author Mike Buland
88 */
89 virtual void setAt( int nIndex, void *pData ) = 0;
90
91 /** Makes the List work like an array. Just say listObj[2] to get
92 * the third element.
93 *@param nIndex The index to access in the list.
94 *@returns A pointer to the data at element index.
95 *@author Mike Buland
96 */
97 void *operator[]( int nIndex ) { return getAt( nIndex ); };
98};
99 35
100#endif 36 public:
37 List() :
38 pFirst( NULL ),
39 pLast( NULL ),
40 nSize( 0 )
41 {
42 }
43
44 List( const MyType &src ) :
45 pFirst( NULL ),
46 pLast( NULL ),
47 nSize( 0 )
48 {
49 for( Link *pCur = src.pFirst; pCur; pCur = pCur->pNext )
50 {
51 append( *pCur->pValue );
52 }
53 }
54
55 ~List()
56 {
57 clear();
58 }
59
60 /**
61 * Assignment operator.
62 *@param src (const MyType &) The list to assign to your list.
63 */
64 MyType &operator=( const MyType &src )
65 {
66 clear();
67 for( Link *pCur = src.pFirst; pCur; pCur = pCur->pNext )
68 {
69 append( *pCur->pValue );
70 }
71 }
72
73 /**
74 * Clear the data from the list.
75 */
76 void clear()
77 {
78 Link *pCur = pFirst;
79 for(;;)
80 {
81 if( pCur == NULL ) break;
82 va.destroy( pCur->pValue );
83 va.deallocate( pCur->pValue, 1 );
84 Link *pTmp = pCur->pNext;
85 la.destroy( pCur );
86 la.deallocate( pCur, 1 );
87 pCur = pTmp;
88 }
89 pFirst = pLast = NULL;
90 nSize = 0;
91 }
92
93 /**
94 * Append a value to the list.
95 *@param v (const value_type &) The value to append.
96 */
97 void append( const value &v )
98 {
99 Link *pNew = la.allocate( 1 );
100 pNew->pValue = va.allocate( 1 );
101 va.construct( pNew->pValue, v );
102 nSize++;
103 if( pFirst == NULL )
104 {
105 // Empty list
106 pFirst = pLast = pNew;
107 pNew->pNext = pNew->pPrev = NULL;
108 }
109 else
110 {
111 pNew->pNext = NULL;
112 pNew->pPrev = pLast;
113 pLast->pNext = pNew;
114 pLast = pNew;
115 }
116 }
117
118 /**
119 * Prepend a value to the list.
120 *@param v (const value_type &) The value to prepend.
121 */
122 void prepend( const value &v )
123 {
124 Link *pNew = la.allocate( 1 );
125 pNew->pValue = va.allocate( 1 );
126 va.construct( pNew->pValue, v );
127 nSize++;
128 if( pFirst == NULL )
129 {
130 // Empty list
131 pFirst = pLast = pNew;
132 pNew->pNext = pNew->pPrev = NULL;
133 }
134 else
135 {
136 pNew->pNext = pFirst;
137 pNew->pPrev = NULL;
138 pFirst->pPrev = pNew;
139 pFirst = pNew;
140 }
141 }
142
143 /**
144 * An iterator to iterate through your list.
145 */
146 typedef struct iterator
147 {
148 friend class List<value, valuealloc, linkalloc>;
149 private:
150 Link *pLink;
151 iterator() :
152 pLink( NULL )
153 {
154 }
155
156 iterator( Link *pLink ) :
157 pLink( pLink )
158 {
159 }
160
161 public:
162 /**
163 * Equals comparison operator.
164 *@param oth (const iterator &) The iterator to compare to.
165 *@returns (bool) Are they equal?
166 */
167 bool operator==( const iterator &oth ) const
168 {
169 return ( pLink == oth.pLink );
170 }
171
172 /**
173 * Equals comparison operator.
174 *@param pOth (const Link *) The link to compare to.
175 *@returns (bool) Are they equal?
176 */
177 bool operator==( const Link *pOth ) const
178 {
179 return ( pLink == pOth );
180 }
181
182 /**
183 * Not equals comparison operator.
184 *@param oth (const iterator &) The iterator to compare to.
185 *@returns (bool) Are they not equal?
186 */
187 bool operator!=( const iterator &oth ) const
188 {
189 return ( pLink != oth.pLink );
190 }
191
192 /**
193 * Not equals comparison operator.
194 *@param pOth (const Link *) The link to compare to.
195 *@returns (bool) Are they not equal?
196 */
197 bool operator!=( const Link *pOth ) const
198 {
199 return ( pLink != pOth );
200 }
201
202 /**
203 * Dereference operator.
204 *@returns (value_type &) The value.
205 */
206 value &operator*()
207 {
208 return *(pLink->pValue);
209 }
210
211 /**
212 * Pointer access operator.
213 *@returns (value_type *) A pointer to the value.
214 */
215 value *operator->()
216 {
217 return pLink->pValue;
218 }
219
220 /**
221 * Increment operator.
222 */
223 iterator &operator++()
224 {
225 if( pLink != NULL )
226 pLink = pLink->pNext;
227 return *this;
228 }
229
230 /**
231 * Decrement operator.
232 */
233 iterator &operator--()
234 {
235 if( pLink != NULL )
236 pLink = pLink->pPrev;
237 return *this;
238 }
239
240 /**
241 * Increment operator.
242 */
243 iterator &operator++( int )
244 {
245 if( pLink != NULL )
246 pLink = pLink->pNext;
247 return *this;
248 }
249
250 /**
251 * Decrement operator.
252 */
253 iterator &operator--( int )
254 {
255 if( pLink != NULL )
256 pLink = pLink->pPrev;
257 return *this;
258 }
259
260 /**
261 * Assignment operator.
262 *@param oth (const iterator &) The other iterator to set this
263 * one to.
264 */
265 iterator &operator=( const iterator &oth )
266 {
267 pLink = oth.pLink;
268 return *this;
269 }
270 };
271
272 /**
273 *@see iterator
274 */
275 typedef struct const_iterator
276 {
277 friend class List<value, valuealloc, linkalloc>;
278 private:
279 Link *pLink;
280 const_iterator() :
281 pLink( NULL )
282 {
283 }
101 284
285 const_iterator( Link *pLink ) :
286 pLink( pLink )
287 {
288 }
289
290 const_iterator( const iterator &i ) :
291 pLink( i.pLink )
292 {
293 }
294
295 public:
296 bool operator==( const const_iterator &oth ) const
297 {
298 return ( pLink == oth.pLink );
299 }
300
301 bool operator==( const Link *pOth ) const
302 {
303 return ( pLink == pOth );
304 }
305
306 bool operator!=( const const_iterator &oth ) const
307 {
308 return ( pLink != oth.pLink );
309 }
310
311 bool operator!=( const Link *pOth ) const
312 {
313 return ( pLink != pOth );
314 }
315
316 const value &operator*()
317 {
318 return *(pLink->pValue);
319 }
320
321 const value *operator->()
322 {
323 return pLink->pValue;
324 }
325
326 const_iterator &operator++()
327 {
328 if( pLink != NULL )
329 pLink = pLink->pNext;
330 return *this;
331 }
332
333 const_iterator &operator--()
334 {
335 if( pLink != NULL )
336 pLink = pLink->pPrev;
337 return *this;
338 }
339
340 const_iterator &operator++( int )
341 {
342 if( pLink != NULL )
343 pLink = pLink->pNext;
344 return *this;
345 }
346
347 const_iterator &operator--( int )
348 {
349 if( pLink != NULL )
350 pLink = pLink->pPrev;
351 return *this;
352 }
353
354 const_iterator &operator=( const iterator &oth )
355 {
356 pLink = oth.pLink;
357 return *this;
358 }
359
360 const_iterator &operator=( const const_iterator &oth )
361 {
362 pLink = oth.pLink;
363 return *this;
364 }
365 };
366
367 /**
368 * Get an iterator pointing to the first item in the list.
369 *@returns (iterator)
370 */
371 iterator begin()
372 {
373 return iterator( pFirst );
374 }
375
376 /**
377 * Get a const iterator pointing to the first item in the list.
378 *@returns (const const_iterator)
379 */
380 const const_iterator begin() const
381 {
382 return const_iterator( pFirst );
383 }
384
385 /**
386 * Get an iterator pointing to a place just past the last item in
387 * the list.
388 *@returns (const Link *)
389 */
390 const Link *end() const
391 {
392 return NULL;
393 }
394
395 /**
396 * Erase an item from the list.
397 *@param i (iterator) The item to erase.
398 */
399 void erase( iterator &i )
400 {
401 Link *pCur = i.pLink;
402 Link *pPrev = pCur->pPrev;
403 if( pPrev == NULL )
404 {
405 va.destroy( pCur->pValue );
406 va.deallocate( pCur->pValue, 1 );
407 pFirst = pCur->pNext;
408 la.destroy( pCur );
409 la.deallocate( pCur, 1 );
410 if( pFirst == NULL )
411 pLast = NULL;
412 nSize--;
413 i.pLink = pFirst;
414 }
415 else
416 {
417 va.destroy( pCur->pValue );
418 va.deallocate( pCur->pValue, 1 );
419 Link *pTmp = pCur->pNext;
420 la.destroy( pCur );
421 la.deallocate( pCur, 1 );
422 pPrev->pNext = pTmp;
423 if( pTmp != NULL )
424 pTmp->pPrev = pPrev;
425 nSize--;
426 i.pLink = pTmp;
427 }
428 }
429
430 /**
431 * Get the current size of the list.
432 *@returns (int) The current size of the list.
433 */
434 int getSize() const
435 {
436 return nSize;
437 }
438
439 /**
440 * Get the first item in the list.
441 *@returns (value_type &) The first item in the list.
442 */
443 value &first()
444 {
445 return *pFirst->pValue;
446 }
447
448 /**
449 * Get the first item in the list.
450 *@returns (const value_type &) The first item in the list.
451 */
452 const value &first() const
453 {
454 return *pFirst->pValue;
455 }
456
457 /**
458 * Get the last item in the list.
459 *@returns (value_type &) The last item in the list.
460 */
461 value &last()
462 {
463 return *pLast->pValue;
464 }
465
466 /**
467 * Get the last item in the list.
468 *@returns (const value_type &) The last item in the list.
469 */
470 const value &last() const
471 {
472 return *pLast->pValue;
473 }
474
475 const bool isEmpty() const
476 {
477 return (nSize == 0);
478 }
479
480 private:
481 Link *pFirst;
482 Link *pLast;
483 linkalloc la;
484 valuealloc va;
485 int nSize;
486 };
487}
488
489#endif
diff --git a/src/logger.cpp b/src/logger.cpp
new file mode 100644
index 0000000..1fc2262
--- /dev/null
+++ b/src/logger.cpp
@@ -0,0 +1,131 @@
1#include "bu/logger.h"
2#include <stdarg.h>
3#include <time.h>
4#include <stdio.h>
5
6Bu::Logger::Logger()
7{
8}
9
10Bu::Logger::~Logger()
11{
12}
13
14void Bu::Logger::log( int nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...)
15{
16 if( (nLevel&nLevelMask) == 0 )
17 return;
18
19 va_list ap;
20 va_start( ap, sFormat );
21 char *text;
22 vasprintf( &text, sFormat, ap );
23 va_end(ap);
24
25 time_t t = time(NULL);
26
27 char *line = NULL;
28 struct tm *pTime;
29 pTime = localtime( &t );
30 asprintf(
31 &line,
32 sLogFormat.getStr(),
33 pTime->tm_year+1900,
34 pTime->tm_mon+1,
35 pTime->tm_mday,
36 pTime->tm_hour,
37 pTime->tm_min,
38 pTime->tm_sec,
39 nLevel,
40 sFile,
41 nLine,
42 text,
43 sFunction
44 );
45 write( fileno(stdout), line, strlen(line) );
46 free( text );
47 free( line );
48}
49
50void Bu::Logger::setFormat( const Bu::FString &str )
51{
52 sLogFormat = "";
53
54 static char fmts[][4]={
55 {'y', 'd', '0', '1'},
56 {'m', 'd', '0', '2'},
57 {'d', 'd', '0', '3'},
58 {'h', 'd', '0', '4'},
59 {'M', 'd', '0', '5'},
60 {'s', 'd', '0', '6'},
61 {'L', 'd', '0', '7'},
62 {'f', 's', '0', '8'},
63 {'l', 'd', '0', '9'},
64 {'t', 's', '1', '0'},
65 {'F', 's', '1', '1'},
66 {'\0', '\0', '\0', '\0'},
67 };
68
69 for( const char *s = str.getStr(); *s; s++ )
70 {
71 if( *s == '%' )
72 {
73 sLogFormat += '%';
74 Bu::FString sBuf;
75 for(;;)
76 {
77 s++;
78 int l;
79 for( l = 0;; l++ )
80 {
81 if( fmts[l][0] == '\0' )
82 {
83 sBuf += *s;
84 break;
85 }
86 else if( *s == fmts[l][0] )
87 {
88 sLogFormat += fmts[l][2];
89 sLogFormat += fmts[l][3];
90 sLogFormat += '$';
91 sLogFormat += sBuf;
92 sLogFormat += fmts[l][1];
93 break;
94 }
95 }
96 if( fmts[l][0] != '\0' )
97 break;
98 }
99 }
100 else
101 {
102 sLogFormat += *s;
103 }
104 }
105 sLogFormat += '\n';
106
107 write( fileno(stdout), sLogFormat.getStr(), sLogFormat.getSize() );
108}
109
110void Bu::Logger::setMask( int n )
111{
112 nLevelMask = n;
113}
114
115void Bu::Logger::setLevel( int n )
116{
117 int j;
118 for( j = 31; j > 0; j-- )
119 {
120 if( (n&(1<<j)) )
121 {
122 for(; j >= 0; j-- )
123 {
124 n |= (1<<j);
125 }
126 nLevelMask = n;
127 return;
128 }
129 }
130}
131
diff --git a/src/logger.h b/src/logger.h
new file mode 100644
index 0000000..f8e1692
--- /dev/null
+++ b/src/logger.h
@@ -0,0 +1,112 @@
1#ifndef BU_LOGGER_H
2#define BU_LOGGER_H
3
4#include "bu/singleton.h"
5#include "bu/fstring.h"
6
7namespace Bu
8{
9 /**
10 * Simple logging facility. All output goes straight to stdout, unlike the
11 * old multi-log system. Generally we expect any program complex enough to
12 * want to use this will have other facilities for processing the logging
13 * output, but if we need it we can add other output methods.
14 *
15 * Currently implemented as a singleton to avoid clutter with globals, you
16 * generally never want to use the logging system directly, it's annoying.
17 * Instead use the handy macros lineLog, setLogMask, setLogFormat, and
18 * setLogLevel. They do all the real work for you.
19 *
20 * In the log format, you can specify extra information that will be written
21 * to the log with every message, and extras in printf style. Use %X flags
22 * where X is one of the following:
23 * - L - Logging level of the log message (not the current mask)
24 * - y - Full year
25 * - m - Month
26 * - d - Day of month
27 * - h - Hour (24-hour format)
28 * - M - Minutes
29 * - s - Seconds
30 * - f - Source file
31 * - l - Line number
32 * - F - function name
33 * - t - Text of message (usually important)
34 *
35 * You can include anything extra that you would like, a newline will always
36 * be added automatically, so no need to worry about that. You can also
37 * include any extra printf style formatting that you would like, for
38 * example: "%h:%02M:%02s" for the time 4:02:09 instead of 4:2:9.
39 *
40 * It's generally handy to create an enum of values you use as levels during
41 * program execution (such as error, warning, info, debug, etc). These
42 * levels should be treated as bitflags, and the most desirable messages,
43 * i.e. serious errors and the like should be low order (0x01), and the much
44 * less desirable messages, like debugging info, should be higher order
45 * (0xF0). During operation you can then set either an explicit mask,
46 * selecting just the levels that you would like to see printed, or set the
47 * mask using the setLevel helper function, which simulates verbosity
48 * levels, enabling every flag lower order than the highest order set bit
49 * passed. I.E. if you had the following enumerated levels:
50 *
51 *@code
52 enum {
53 logError = 0x01,
54 logWarning = 0x02,
55 logInfo = 0x04,
56 logDebug = 0x08
57 };
58 @endcode
59 * And you set the mask with setMask( logInfo ) the only messages you would
60 * see are the ones catagorized logInfo. However, if you used
61 * setLevel( logInfo ) then you would see logInfo, logWarning, and logError
62 * type messages, since they are lower order.
63 */
64 class Logger : public Bu::Singleton<Bu::Logger>
65 {
66 friend class Bu::Singleton<Bu::Logger>;
67 private:
68 Logger();
69 virtual ~Logger();
70
71 public:
72 void log( int nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...);
73
74 void setFormat( const Bu::FString &str );
75 void setMask( int n );
76 void setLevel( int n );
77
78 private:
79 Bu::FString sLogFormat;
80 int nLevelMask;
81 };
82}
83
84/**
85 * Use Bu::Logger to log a message at the given level and with the given message
86 * using printf style formatting, and include extra data such as the current
87 * file, line number, and function.
88 */
89#define lineLog( nLevel, sFrmt, ...) \
90 Bu::Logger::getInstance().log( nLevel, __FILE__, __PRETTY_FUNCTION__, __LINE__, sFrmt, ##__VA_ARGS__ )
91
92/**
93 * Set the Bu::Logger logging mask directly. See Bu::Logger::setMask for
94 * details.
95 */
96#define setLogMask( nLevel ) \
97 Bu::Logger::getInstance().setMask( nLevel )
98
99/**
100 * Set the Bu::Logger format. See Bu::Logger::setFormat for details.
101 */
102#define setLogFormat( sFrmt ) \
103 Bu::Logger::getInstance().setFormat( sFrmt )
104
105/**
106 * Set the Bu::Logger logging mask simulating levels. See Bu::Logger::setLevel
107 * for details.
108 */
109#define setLogLevel( nLevel ) \
110 Bu::Logger::getInstance().setLevel( nLevel )
111
112#endif
diff --git a/src/main.dox b/src/main.dox
new file mode 100644
index 0000000..668d2e3
--- /dev/null
+++ b/src/main.dox
@@ -0,0 +1,14 @@
1/**
2 *@mainpage libbu++ utility library
3 *
4 *@section secIntro Introduction
5 *
6 * Libbu++ is a C++ library of general utility classes and functions. They
7 * cover a wide range of topics from streams and sockets to data structures to
8 * data serialization and xml handling to threading.
9 *
10 */
11
12/**
13 *@namespace Bu The core libbu++ namespace, to ensure things don't get muddied.
14 */
diff --git a/src/membuf.cpp b/src/membuf.cpp
new file mode 100644
index 0000000..45ff5bd
--- /dev/null
+++ b/src/membuf.cpp
@@ -0,0 +1,120 @@
1#include "bu/membuf.h"
2
3using namespace Bu;
4
5Bu::MemBuf::MemBuf() :
6 nPos( 0 )
7{
8}
9
10Bu::MemBuf::MemBuf( const Bu::FString &str ) :
11 sBuf( str ),
12 nPos( 0 )
13{
14}
15
16Bu::MemBuf::~MemBuf()
17{
18}
19
20void Bu::MemBuf::close()
21{
22}
23
24size_t Bu::MemBuf::read( void *pBuf, size_t nBytes )
25{
26 if( (size_t)sBuf.getSize()-(size_t)nPos < nBytes )
27 nBytes = sBuf.getSize()-nPos;
28
29 memcpy( pBuf, sBuf.getStr()+nPos, nBytes );
30 nPos += nBytes;
31
32 return nBytes;
33}
34
35size_t Bu::MemBuf::write( const void *pBuf, size_t nBytes )
36{
37 sBuf.append( (const char *)pBuf, nBytes );
38 nPos += nBytes;
39 return nBytes;
40}
41
42long Bu::MemBuf::tell()
43{
44 return nPos;
45}
46
47void Bu::MemBuf::seek( long offset )
48{
49 nPos += offset;
50 if( nPos < 0 ) nPos = 0;
51 else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize();
52}
53
54void Bu::MemBuf::setPos( long pos )
55{
56 nPos = pos;
57 if( nPos < 0 ) nPos = 0;
58 else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize();
59}
60
61void Bu::MemBuf::setPosEnd( long pos )
62{
63 nPos = sBuf.getSize()-pos;
64 if( nPos < 0 ) nPos = 0;
65 else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize();
66}
67
68bool Bu::MemBuf::isEOS()
69{
70 return (nPos == sBuf.getSize());
71}
72
73bool Bu::MemBuf::isOpen()
74{
75 return true;
76}
77
78void Bu::MemBuf::flush()
79{
80}
81
82bool Bu::MemBuf::canRead()
83{
84 return !isEOS();
85}
86
87bool Bu::MemBuf::canWrite()
88{
89 return isEOS();
90}
91
92bool Bu::MemBuf::isReadable()
93{
94 return true;
95}
96
97bool Bu::MemBuf::isWritable()
98{
99 return true;
100}
101
102bool Bu::MemBuf::isSeekable()
103{
104 return true;
105}
106
107bool Bu::MemBuf::isBlocking()
108{
109 return true;
110}
111
112void Bu::MemBuf::setBlocking( bool bBlocking )
113{
114}
115
116Bu::FString &Bu::MemBuf::getString()
117{
118 return sBuf;
119}
120
diff --git a/src/membuf.h b/src/membuf.h
new file mode 100644
index 0000000..8f53d4b
--- /dev/null
+++ b/src/membuf.h
@@ -0,0 +1,53 @@
1#ifndef BU_MEM_BUF_H
2#define BU_MEM_BUF_H
3
4#include <stdint.h>
5
6#include "bu/stream.h"
7#include "bu/fstring.h"
8
9namespace Bu
10{
11 /**
12 * A memory buffer stream.
13 */
14 class MemBuf : public Stream
15 {
16 public:
17 MemBuf();
18 MemBuf( const Bu::FString &str );
19 virtual ~MemBuf();
20
21 virtual void close();
22 virtual size_t read( void *pBuf, size_t nBytes );
23
24 /**
25 *@todo Allow writes at the current position, not just appending to
26 * the current buffer. This is a silly way to do it, but it covers all
27 * of our bases for now.
28 */
29 virtual size_t write( const void *pBuf, size_t nBytes );
30 virtual long tell();
31 virtual void seek( long offset );
32 virtual void setPos( long pos );
33 virtual void setPosEnd( long pos );
34 virtual bool isEOS();
35 virtual bool isOpen();
36 virtual void flush();
37 virtual bool canRead();
38 virtual bool canWrite();
39 virtual bool isReadable();
40 virtual bool isWritable();
41 virtual bool isSeekable();
42 virtual bool isBlocking();
43 virtual void setBlocking( bool bBlocking=true );
44
45 Bu::FString &getString();
46
47 private:
48 Bu::FString sBuf;
49 long nPos;
50 };
51}
52
53#endif
diff --git a/src/cgi.cpp b/src/old/cgi.cpp
index 1fecbbe..1fecbbe 100644
--- a/src/cgi.cpp
+++ b/src/old/cgi.cpp
diff --git a/src/cgi.h b/src/old/cgi.h
index 01142b5..01142b5 100644
--- a/src/cgi.h
+++ b/src/old/cgi.h
diff --git a/src/configmanagerbase.cpp b/src/old/configmanagerbase.cpp
index ac55fe0..ac55fe0 100644
--- a/src/configmanagerbase.cpp
+++ b/src/old/configmanagerbase.cpp
diff --git a/src/configmanagerbase.h b/src/old/configmanagerbase.h
index 381cc1f..381cc1f 100644
--- a/src/configmanagerbase.h
+++ b/src/old/configmanagerbase.h
diff --git a/src/confpair.cpp b/src/old/confpair.cpp
index 4741401..4741401 100644
--- a/src/confpair.cpp
+++ b/src/old/confpair.cpp
diff --git a/src/confpair.h b/src/old/confpair.h
index 56eb06e..56eb06e 100644
--- a/src/confpair.h
+++ b/src/old/confpair.h
diff --git a/src/confpairbase.cpp b/src/old/confpairbase.cpp
index 1203dc0..1203dc0 100644
--- a/src/confpairbase.cpp
+++ b/src/old/confpairbase.cpp
diff --git a/src/confpairbase.h b/src/old/confpairbase.h
index 2530756..2530756 100644
--- a/src/confpairbase.h
+++ b/src/old/confpairbase.h
diff --git a/src/conftree.cpp b/src/old/conftree.cpp
index d9a3a3f..d9a3a3f 100644
--- a/src/conftree.cpp
+++ b/src/old/conftree.cpp
diff --git a/src/conftree.h b/src/old/conftree.h
index 197b1ef..197b1ef 100644
--- a/src/conftree.h
+++ b/src/old/conftree.h
diff --git a/src/connection.cpp b/src/old/connection.cpp
index efef144..efef144 100644
--- a/src/connection.cpp
+++ b/src/old/connection.cpp
diff --git a/src/connection.h b/src/old/connection.h
index 0e991c7..0e991c7 100644
--- a/src/connection.h
+++ b/src/old/connection.h
diff --git a/src/connectionmanager.cpp b/src/old/connectionmanager.cpp
index ea60b2b..ea60b2b 100644
--- a/src/connectionmanager.cpp
+++ b/src/old/connectionmanager.cpp
diff --git a/src/connectionmanager.h b/src/old/connectionmanager.h
index cff036b..cff036b 100644
--- a/src/connectionmanager.h
+++ b/src/old/connectionmanager.h
diff --git a/src/connectionmonitor.cpp b/src/old/connectionmonitor.cpp
index 4f90ee6..4f90ee6 100644
--- a/src/connectionmonitor.cpp
+++ b/src/old/connectionmonitor.cpp
diff --git a/src/connectionmonitor.h b/src/old/connectionmonitor.h
index 9910556..9910556 100644
--- a/src/connectionmonitor.h
+++ b/src/old/connectionmonitor.h
diff --git a/src/flexbuf.cpp b/src/old/flexbuf.cpp
index 6d55294..6d55294 100644
--- a/src/flexbuf.cpp
+++ b/src/old/flexbuf.cpp
diff --git a/src/flexbuf.h b/src/old/flexbuf.h
index 7d7f11a..7d7f11a 100644
--- a/src/flexbuf.h
+++ b/src/old/flexbuf.h
diff --git a/src/formula.cpp b/src/old/formula.cpp
index cf63cf3..cf63cf3 100644
--- a/src/formula.cpp
+++ b/src/old/formula.cpp
diff --git a/src/formula.h b/src/old/formula.h
index 939eb09..939eb09 100644
--- a/src/formula.h
+++ b/src/old/formula.h
diff --git a/src/http.cpp b/src/old/http.cpp
index df7dafe..df7dafe 100644
--- a/src/http.cpp
+++ b/src/old/http.cpp
diff --git a/src/http.h b/src/old/http.h
index 7e9f9a0..7e9f9a0 100644
--- a/src/http.h
+++ b/src/old/http.h
diff --git a/src/httpget.cpp b/src/old/httpget.cpp
index ee1f29c..ee1f29c 100644
--- a/src/httpget.cpp
+++ b/src/old/httpget.cpp
diff --git a/src/httpget.h b/src/old/httpget.h
index 8272641..8272641 100644
--- a/src/httpget.h
+++ b/src/old/httpget.h
diff --git a/src/linkedlist.cpp b/src/old/linkedlist.cpp
index a9902bc..a9902bc 100644
--- a/src/linkedlist.cpp
+++ b/src/old/linkedlist.cpp
diff --git a/src/linkedlist.h b/src/old/linkedlist.h
index e430108..e430108 100644
--- a/src/linkedlist.h
+++ b/src/old/linkedlist.h
diff --git a/src/linkmessenger.cpp b/src/old/linkmessenger.cpp
index 3bd401a..3bd401a 100644
--- a/src/linkmessenger.cpp
+++ b/src/old/linkmessenger.cpp
diff --git a/src/linkmessenger.h b/src/old/linkmessenger.h
index ed52639..ed52639 100644
--- a/src/linkmessenger.h
+++ b/src/old/linkmessenger.h
diff --git a/src/old/list.cpp b/src/old/list.cpp
new file mode 100644
index 0000000..18f1a66
--- /dev/null
+++ b/src/old/list.cpp
@@ -0,0 +1,10 @@
1#include "list.h"
2
3List::List( )
4{
5}
6
7List::~List( )
8{
9}
10
diff --git a/src/old/list.h b/src/old/list.h
new file mode 100644
index 0000000..c71b328
--- /dev/null
+++ b/src/old/list.h
@@ -0,0 +1,101 @@
1#ifndef LIST_H
2#define LIST_H
3
4
5/** The basic List class ADT. This, on it's own, does absolutely nothing, but
6 * does define all standard interface functions to access a list.
7 *@author Mike Buland
8 */
9class List
10{
11public:
12 /**
13 * Construct a list.
14 */
15 List();
16
17 /**
18 * Desconstruct a list.
19 */
20 virtual ~List();
21
22 /** Gets the value at a specified index.
23 *@param nIndex The index of the item to return.
24 *@returns The specified item, or NULL if the index was beyond the range
25 * of the list.
26 *@author Mike Buland
27 */
28 virtual void *getAt( int nIndex ) = 0;
29
30 /** Append the given data to the end of the list. This increases the
31 * size of the list by one.
32 *@param pData The data to append to the list.
33 *@author Mike Buland
34 */
35 virtual void append( void *pData ) = 0;
36
37 /** Inserts an item at the specified position in the list. The
38 * new item takes the index that you specify, and all other items
39 * are moved up one position. The size of the list is increased by
40 * one.
41 *@param pData The value to insert into the list.
42 *@param nPos Where to insert the data into the list.
43 *@author Mike Buland
44 */
45 virtual void insertBefore( void *pData, int nPos = 0 ) = 0;
46
47 /** Determines the size of the list, in elements.
48 *@returns The size of the list.
49 *@author Mike Buland
50 */
51 virtual int getSize( ) = 0;
52
53 /** Determines if the list is empty or not.
54 *@returns True if the list is empty, or false if the list has
55 * data in it (if the size is greater than zero).
56 *@author Mike Buland
57 */
58 virtual bool isEmpty( ) = 0;
59
60 /** Deletes an item at the specified index and moves all other
61 * values down one index. The size of the list is decreased by one.
62 *@param nIndex The index of the item to delete.
63 *@author Mike Buland
64 */
65 virtual void deleteAt( int nIndex ) = 0;
66
67 /** Completely empties the list, and sets the effective size to
68 * zero.
69 *@author Mike Buland
70 */
71 virtual void empty() = 0;
72
73 /** Sets the size of the list. This can be larger or smaller
74 * than what it was previously. If larger, new blank items will
75 * be added to the end of the list. If smaller than the old list
76 * items will be deleted from the end.
77 *@param nNewSize The new size of the list.
78 *@author Mike Buland
79 */
80 virtual void setSize( int nNewSize ) = 0;
81
82 /** Sets a member at a specified location to a new value.
83 * If the member being set is outside of the range of the
84 * current list it should be expanded.
85 *@param nIndex The zero-based index of the item to change.
86 *@param pData The new value for that index.
87 *@author Mike Buland
88 */
89 virtual void setAt( int nIndex, void *pData ) = 0;
90
91 /** Makes the List work like an array. Just say listObj[2] to get
92 * the third element.
93 *@param nIndex The index to access in the list.
94 *@returns A pointer to the data at element index.
95 *@author Mike Buland
96 */
97 void *operator[]( int nIndex ) { return getAt( nIndex ); };
98};
99
100#endif
101
diff --git a/src/md5.cpp b/src/old/md5.cpp
index c0cacdd..c0cacdd 100644
--- a/src/md5.cpp
+++ b/src/old/md5.cpp
diff --git a/src/md5.h b/src/old/md5.h
index 7f77d83..7f77d83 100644
--- a/src/md5.h
+++ b/src/old/md5.h
diff --git a/src/multilog.cpp b/src/old/multilog.cpp
index 143ee89..143ee89 100644
--- a/src/multilog.cpp
+++ b/src/old/multilog.cpp
diff --git a/src/multilog.h b/src/old/multilog.h
index 692095a..692095a 100644
--- a/src/multilog.h
+++ b/src/old/multilog.h
diff --git a/src/multilogchannel.cpp b/src/old/multilogchannel.cpp
index ee4c9bf..ee4c9bf 100644
--- a/src/multilogchannel.cpp
+++ b/src/old/multilogchannel.cpp
diff --git a/src/multilogchannel.h b/src/old/multilogchannel.h
index d891a65..d891a65 100644
--- a/src/multilogchannel.h
+++ b/src/old/multilogchannel.h
diff --git a/src/multilogtext.cpp b/src/old/multilogtext.cpp
index 4337cc9..4337cc9 100644
--- a/src/multilogtext.cpp
+++ b/src/old/multilogtext.cpp
diff --git a/src/multilogtext.h b/src/old/multilogtext.h
index 197aef1..197aef1 100644
--- a/src/multilogtext.h
+++ b/src/old/multilogtext.h
diff --git a/src/ordhash.cpp b/src/old/ordhash.cpp
index 77cbd61..77cbd61 100644
--- a/src/ordhash.cpp
+++ b/src/old/ordhash.cpp
diff --git a/src/ordhash.h b/src/old/ordhash.h
index e946f95..e946f95 100644
--- a/src/ordhash.h
+++ b/src/old/ordhash.h
diff --git a/src/pqueue.cpp b/src/old/pqueue.cpp
index 1f0b8b5..1f0b8b5 100644
--- a/src/pqueue.cpp
+++ b/src/old/pqueue.cpp
diff --git a/src/pqueue.h b/src/old/pqueue.h
index 8307d56..8307d56 100644
--- a/src/pqueue.h
+++ b/src/old/pqueue.h
diff --git a/src/old/protocol.cpp b/src/old/protocol.cpp
new file mode 100644
index 0000000..78b3ee2
--- /dev/null
+++ b/src/old/protocol.cpp
@@ -0,0 +1,20 @@
1#include "protocol.h"
2
3Protocol::Protocol()
4{
5 pConnection = NULL;
6}
7
8Protocol::~Protocol()
9{
10}
11
12void Protocol::setConnection( Connection *pNewConnection )
13{
14 pConnection = pNewConnection;
15}
16
17Connection *Protocol::getConnection()
18{
19 return pConnection;
20}
diff --git a/src/old/protocol.h b/src/old/protocol.h
new file mode 100644
index 0000000..09e1c98
--- /dev/null
+++ b/src/old/protocol.h
@@ -0,0 +1,62 @@
1#ifndef PROTOCOL_H
2#define PROTOCOL_H
3
4#include "connection.h"
5
6/** This is the template for a class that handles specialized input and output
7 * to connections of different types with different protocols.
8 *@author Mike Buland
9 */
10class Protocol
11{
12public:
13 /** Constructor */
14 Protocol();
15 /** Deconstructor */
16 virtual ~Protocol();
17
18 /**
19 * Function is called every time there is new data on the line. This is
20 * called directly from the Connection class to process data. This is not
21 * called whever there is pending data on the input, but every time new data
22 * is added to the input buffer.
23 *@returns True if processing went alright, false if something went wrong,
24 * I suppose. In truth this value is thrown away right now.
25 *@todo Either make a return value of false mean something, or make these
26 * void.
27 */
28 virtual bool onNewData()=0;
29
30 /**
31 * Function is called when there is a new connection. This should only
32 * happen once per Protocol object, but gives each protocol object a
33 * chance to perform connection handshaking and initialization at a point
34 * where they know that they have a handle to an active Connection.
35 *@returns See onNewData
36 */
37 virtual bool onNewConnection()=0;
38
39 virtual void onNewClientConnection(){};
40
41 virtual void poll(){};
42
43 /**
44 * Sets the Protocol's Connection object. This is rather important, and
45 * handled usually by the ConnectionManager.
46 *@param pNewConnection The Connection object that this protocol will use to
47 * deal with the outside world.
48 */
49 void setConnection( class Connection *pNewConnection );
50
51 /**
52 * Get a pointer to this object's Connection object, or NULL if one was
53 * never set. If used with the ConnectionManager that should never happen.
54 *@returns A pointer to the active Connection.
55 */
56 Connection *getConnection();
57
58private:
59 class Connection *pConnection; /**< The pointer to the Connection. */
60};
61
62#endif
diff --git a/src/protocoltelnet.cpp b/src/old/protocoltelnet.cpp
index b169a51..b169a51 100644
--- a/src/protocoltelnet.cpp
+++ b/src/old/protocoltelnet.cpp
diff --git a/src/protocoltelnet.h b/src/old/protocoltelnet.h
index a6d2e49..a6d2e49 100644
--- a/src/protocoltelnet.h
+++ b/src/old/protocoltelnet.h
diff --git a/src/queue.cpp b/src/old/queue.cpp
index 42999fe..42999fe 100644
--- a/src/queue.cpp
+++ b/src/old/queue.cpp
diff --git a/src/queue.h b/src/old/queue.h
index 692f5d8..692f5d8 100644
--- a/src/queue.h
+++ b/src/old/queue.h
diff --git a/src/ringlist.cpp b/src/old/ringlist.cpp
index 9efbbc4..9efbbc4 100644
--- a/src/ringlist.cpp
+++ b/src/old/ringlist.cpp
diff --git a/src/ringlist.h b/src/old/ringlist.h
index bc069f3..bc069f3 100644
--- a/src/ringlist.h
+++ b/src/old/ringlist.h
diff --git a/src/sbuffer.cpp b/src/old/sbuffer.cpp
index f84f8a3..f84f8a3 100644
--- a/src/sbuffer.cpp
+++ b/src/old/sbuffer.cpp
diff --git a/src/sbuffer.h b/src/old/sbuffer.h
index 65feb71..65feb71 100644
--- a/src/sbuffer.h
+++ b/src/old/sbuffer.h
diff --git a/src/serializerbinary.cpp b/src/old/serializerbinary.cpp
index ea7ed93..ea7ed93 100644
--- a/src/serializerbinary.cpp
+++ b/src/old/serializerbinary.cpp
diff --git a/src/serializerbinary.h b/src/old/serializerbinary.h
index 8510fcd..8510fcd 100644
--- a/src/serializerbinary.h
+++ b/src/old/serializerbinary.h
diff --git a/src/serializerbzip2.cpp b/src/old/serializerbzip2.cpp
index bafabc8..bafabc8 100644
--- a/src/serializerbzip2.cpp
+++ b/src/old/serializerbzip2.cpp
diff --git a/src/serializerbzip2.h b/src/old/serializerbzip2.h
index 4aeb22e..4aeb22e 100644
--- a/src/serializerbzip2.h
+++ b/src/old/serializerbzip2.h
diff --git a/src/serializerconnection.cpp b/src/old/serializerconnection.cpp
index 2934c8b..2934c8b 100644
--- a/src/serializerconnection.cpp
+++ b/src/old/serializerconnection.cpp
diff --git a/src/serializerconnection.h b/src/old/serializerconnection.h
index e8d85c6..e8d85c6 100644
--- a/src/serializerconnection.h
+++ b/src/old/serializerconnection.h
diff --git a/src/serializertext.cpp b/src/old/serializertext.cpp
index 9cf4394..9cf4394 100644
--- a/src/serializertext.cpp
+++ b/src/old/serializertext.cpp
diff --git a/src/serializertext.h b/src/old/serializertext.h
index 01b7f7b..01b7f7b 100644
--- a/src/serializertext.h
+++ b/src/old/serializertext.h
diff --git a/src/sha1.cpp b/src/old/sha1.cpp
index 8270c3b..8270c3b 100644
--- a/src/sha1.cpp
+++ b/src/old/sha1.cpp
diff --git a/src/sha1.h b/src/old/sha1.h
index ab6081d..ab6081d 100644
--- a/src/sha1.h
+++ b/src/old/sha1.h
diff --git a/src/stack.cpp b/src/old/stack.cpp
index 8d9565c..8d9565c 100644
--- a/src/stack.cpp
+++ b/src/old/stack.cpp
diff --git a/src/stack.h b/src/old/stack.h
index 30e2a19..30e2a19 100644
--- a/src/stack.h
+++ b/src/old/stack.h
diff --git a/src/staticstring.cpp b/src/old/staticstring.cpp
index 60f130f..60f130f 100644
--- a/src/staticstring.cpp
+++ b/src/old/staticstring.cpp
diff --git a/src/staticstring.h b/src/old/staticstring.h
index 4c3f7b8..4c3f7b8 100644
--- a/src/staticstring.h
+++ b/src/old/staticstring.h
diff --git a/src/stringrep.cpp b/src/old/stringrep.cpp
index a505f8a..a505f8a 100644
--- a/src/stringrep.cpp
+++ b/src/old/stringrep.cpp
diff --git a/src/stringrep.h b/src/old/stringrep.h
index eaa4a12..eaa4a12 100644
--- a/src/stringrep.h
+++ b/src/old/stringrep.h
diff --git a/src/tests/clistress.cpp b/src/old/tests/clistress.cpp
index 6b0ac66..6b0ac66 100644
--- a/src/tests/clistress.cpp
+++ b/src/old/tests/clistress.cpp
diff --git a/src/tests/confpair.cpp b/src/old/tests/confpair.cpp
index fb1b0d3..fb1b0d3 100644
--- a/src/tests/confpair.cpp
+++ b/src/old/tests/confpair.cpp
diff --git a/src/tests/connect.cpp b/src/old/tests/connect.cpp
index a9fca64..a9fca64 100644
--- a/src/tests/connect.cpp
+++ b/src/old/tests/connect.cpp
diff --git a/src/tests/exception.cpp b/src/old/tests/exception.cpp
index 6417692..6417692 100644
--- a/src/tests/exception.cpp
+++ b/src/old/tests/exception.cpp
diff --git a/src/tests/formula.cpp b/src/old/tests/formula.cpp
index 976b039..976b039 100644
--- a/src/tests/formula.cpp
+++ b/src/old/tests/formula.cpp
diff --git a/src/old/tests/hash.cpp b/src/old/tests/hash.cpp
new file mode 100644
index 0000000..2fc6968
--- /dev/null
+++ b/src/old/tests/hash.cpp
@@ -0,0 +1,116 @@
1#include "hash.h"
2#include "staticstring.h"
3
4int main()
5{
6 const char *names[]={
7 "Homer the Great",
8 "And Maggie Makes Three",
9 "Bart's Comet",
10 "Homie The Clown",
11 "Bart Vs Australia",
12 "Homer vs Patty and Selma",
13 "A star is burns",
14 "Lisa's Wedding",
15 "Two Dozen and One Greyhounds",
16 "The PTA Disbands",
17 "Round Springfield",
18 "The Springfield connection",
19 "Lemon of Troy",
20 "Who Shot Mr. Burns (Pt. 1)",
21 "Who Shot Mr. Burns (pt. 2)",
22 "Radioactive Man",
23 "Home Sweet Homediddly-dum-doodly",
24 "Bart Sells His Soul",
25 "Lisa the Vegetarian",
26 "Treehouse of horror VI",
27 "King Size Homer",
28 "Mother Simpson",
29 "Sideshow Bob's Last Gleaming",
30 "The Simpson's 138th Show Spectacular",
31 "Marge Be Not Proud",
32 "Team Homer",
33 "Two Bad Neighbors",
34 "Scenes From the Class Struggle in Springfield",
35 "Bart the Fink",
36 "Lisa the Iconoclast",
37 "Homer the Smithers",
38 "The Day the Violence Died",
39 "A Fish Called Selma",
40 "Bart on the road",
41 "22 Short Films about Springfield",
42 "The Curse of the Flying Hellfish",
43 "Much Apu about Nothing",
44 "Homerpalooza",
45 "The Summer of 4 Ft 2",
46 "Treehouse of Horror VII",
47 "You Only Move Twice",
48 "The Homer They Fall",
49 "Burns Baby Burns",
50 "Bart After Dark",
51 "A Millhouse Divided",
52 "Lisas Date With Destiny",
53 "Hurricane Neddy",
54 "The Mysterious Voyage of Our Homer",
55 "The Springfield Files",
56 "The Twisted World of Marge Simpson",
57 "Mountain of Madness",
58 NULL
59 };
60
61 Hash<const char *, int> sTest;
62
63 printf("Inserting\n-------------------\n\n");
64 for( int j = 0; j < 33; j++ )
65 {
66 sTest[names[j]] = j;
67 }
68
69 printf("Test1: %d, Test2: %d\n", sTest.has("Lemon of Troy"), sTest.has(std::string("Lemon of Troy").c_str() ) );
70
71 sTest.has(std::string("Lemon of Troy").c_str() );
72
73 printf("Getting\n-------------------\n\n");
74
75 sTest.erase("Homer the Great");
76 sTest["Bart's Comet"].erase();
77
78 for( Hash<const char *, int>::iterator i = sTest.begin();
79 i != sTest.end(); i++ )
80 {
81 Hash<const char *, int>::iterator j = i;
82 printf("%d: %s\n", (*j).second, (*j).first );
83 }
84
85 printf("Testing\n-------------------\n\n");
86 for( int j = 0; j < 33; j++ )
87 {
88 if( sTest.has(names[j]) )
89 {
90 if( sTest[names[j]] != j )
91 {
92 printf("'%s' should be %d, is %d\n",
93 names[j], j,
94 sTest[names[j]].value()
95 );
96 }
97 }
98 else
99 {
100 printf("Missing element %d, '%s'\n", j, names[j] );
101 }
102 }
103
104 printf("Clearing\n-------------------\n\n");
105
106 sTest.clear();
107
108 for( Hash<const char *, int>::iterator i = sTest.begin();
109 i != sTest.end(); i++ )
110 {
111 Hash<const char *, int>::iterator j = i;
112 printf("%d: %s\n", (*j).second, (*j).first );
113 }
114
115}
116
diff --git a/src/tests/hashtest.cpp b/src/old/tests/hashtest.cpp
index eaa84a0..eaa84a0 100644
--- a/src/tests/hashtest.cpp
+++ b/src/old/tests/hashtest.cpp
diff --git a/src/tests/hashtest2.cpp b/src/old/tests/hashtest2.cpp
index 74700fd..74700fd 100644
--- a/src/tests/hashtest2.cpp
+++ b/src/old/tests/hashtest2.cpp
diff --git a/src/tests/httpsrv/httpconnectionmonitor.cpp b/src/old/tests/httpsrv/httpconnectionmonitor.cpp
index 51d82f3..51d82f3 100644
--- a/src/tests/httpsrv/httpconnectionmonitor.cpp
+++ b/src/old/tests/httpsrv/httpconnectionmonitor.cpp
diff --git a/src/tests/httpsrv/httpconnectionmonitor.h b/src/old/tests/httpsrv/httpconnectionmonitor.h
index 30c0afd..30c0afd 100644
--- a/src/tests/httpsrv/httpconnectionmonitor.h
+++ b/src/old/tests/httpsrv/httpconnectionmonitor.h
diff --git a/src/tests/httpsrv/main.cpp b/src/old/tests/httpsrv/main.cpp
index 2f1563c..2f1563c 100644
--- a/src/tests/httpsrv/main.cpp
+++ b/src/old/tests/httpsrv/main.cpp
diff --git a/src/tests/log.cpp b/src/old/tests/log.cpp
index d7cfa0b..d7cfa0b 100644
--- a/src/tests/log.cpp
+++ b/src/old/tests/log.cpp
diff --git a/src/tests/md5test.cpp b/src/old/tests/md5test.cpp
index 6f832df..6f832df 100644
--- a/src/tests/md5test.cpp
+++ b/src/old/tests/md5test.cpp
diff --git a/src/tests/ordhash.cpp b/src/old/tests/ordhash.cpp
index f1d96ec..f1d96ec 100644
--- a/src/tests/ordhash.cpp
+++ b/src/old/tests/ordhash.cpp
diff --git a/src/tests/param.cpp b/src/old/tests/param.cpp
index a4d2824..a4d2824 100644
--- a/src/tests/param.cpp
+++ b/src/old/tests/param.cpp
diff --git a/src/tests/param.h b/src/old/tests/param.h
index 2756b69..2756b69 100644
--- a/src/tests/param.h
+++ b/src/old/tests/param.h
diff --git a/src/tests/plugin/main.cpp b/src/old/tests/plugin/main.cpp
index 51c8390..51c8390 100644
--- a/src/tests/plugin/main.cpp
+++ b/src/old/tests/plugin/main.cpp
diff --git a/src/tests/plugin/plugin.cpp b/src/old/tests/plugin/plugin.cpp
index ea558fd..ea558fd 100644
--- a/src/tests/plugin/plugin.cpp
+++ b/src/old/tests/plugin/plugin.cpp
diff --git a/src/tests/plugin/plugin.h b/src/old/tests/plugin/plugin.h
index f726867..f726867 100644
--- a/src/tests/plugin/plugin.h
+++ b/src/old/tests/plugin/plugin.h
diff --git a/src/tests/qsort.cpp b/src/old/tests/qsort.cpp
index 28c6f03..28c6f03 100644
--- a/src/tests/qsort.cpp
+++ b/src/old/tests/qsort.cpp
diff --git a/src/tests/sbuffer.cpp b/src/old/tests/sbuffer.cpp
index 02798cb..02798cb 100644
--- a/src/tests/sbuffer.cpp
+++ b/src/old/tests/sbuffer.cpp
diff --git a/src/tests/serialize.cpp b/src/old/tests/serialize.cpp
index e233704..e233704 100644
--- a/src/tests/serialize.cpp
+++ b/src/old/tests/serialize.cpp
diff --git a/src/tests/serializetext.cpp b/src/old/tests/serializetext.cpp
index f6be7d3..f6be7d3 100644
--- a/src/tests/serializetext.cpp
+++ b/src/old/tests/serializetext.cpp
diff --git a/src/tests/sha1.cpp b/src/old/tests/sha1.cpp
index df3113c..df3113c 100644
--- a/src/tests/sha1.cpp
+++ b/src/old/tests/sha1.cpp
diff --git a/src/tests/sptr.cpp b/src/old/tests/sptr.cpp
index 252463b..38d3675 100644
--- a/src/tests/sptr.cpp
+++ b/src/old/tests/sptr.cpp
@@ -9,12 +9,12 @@ public:
9 printf("Created.\n"); 9 printf("Created.\n");
10 } 10 }
11 11
12 virtual ~Annoy() 12 ~Annoy()
13 { 13 {
14 printf("Destroyed.\n"); 14 printf("Destroyed.\n");
15 } 15 }
16 16
17 virtual void go() 17 void go()
18 { 18 {
19 printf("%d: I'm annoying.\n", ++nCnt); 19 printf("%d: I'm annoying.\n", ++nCnt);
20 } 20 }
@@ -22,22 +22,6 @@ public:
22 int nCnt; 22 int nCnt;
23}; 23};
24 24
25class Annoy2: public Annoy
26{
27public:
28 Annoy2(){};
29 virtual ~Annoy2(){};
30 virtual void go()
31 {
32 printf("{{I'm Annoy2!!}} ");
33 Annoy::go();
34 }
35 virtual void go2()
36 {
37 printf("This is me, on my own...\n");
38 }
39};
40
41void beAnnoying( SPtr<Annoy> bob ) 25void beAnnoying( SPtr<Annoy> bob )
42{ 26{
43 printf("bob-Count: %d\n", bob.count() ); 27 printf("bob-Count: %d\n", bob.count() );
@@ -46,7 +30,7 @@ void beAnnoying( SPtr<Annoy> bob )
46 30
47int main() 31int main()
48{ 32{
49 SPtr<Annoy> pt( new Annoy2 ); 33 SPtr<Annoy> pt( new Annoy );
50 printf("Count: %d\n", pt.count() ); 34 printf("Count: %d\n", pt.count() );
51 pt->go(); 35 pt->go();
52 36
@@ -63,14 +47,6 @@ int main()
63 pt3->go(); 47 pt3->go();
64 48
65 beAnnoying( pt3 ); 49 beAnnoying( pt3 );
66
67 {
68 SPtr<Annoy2> pt4( SPtrCast<Annoy2>( pt3 ) );
69 printf("Count: %d\n", pt4.count() );
70
71 pt4->go2();
72 }
73 printf("Count: %d\n", pt.count() );
74 } 50 }
75 printf("Count: %d\n", pt.count() ); 51 printf("Count: %d\n", pt.count() );
76 } 52 }
diff --git a/src/tests/srvstress.cpp b/src/old/tests/srvstress.cpp
index d9a9a1c..d9a9a1c 100644
--- a/src/tests/srvstress.cpp
+++ b/src/old/tests/srvstress.cpp
diff --git a/src/tests/strhash.cpp b/src/old/tests/strhash.cpp
index f6528ca..f6528ca 100644
--- a/src/tests/strhash.cpp
+++ b/src/old/tests/strhash.cpp
diff --git a/src/tests/teltest/main.cpp b/src/old/tests/teltest/main.cpp
index 5d3ec26..5d3ec26 100644
--- a/src/tests/teltest/main.cpp
+++ b/src/old/tests/teltest/main.cpp
diff --git a/src/tests/teltest/telnetmonitor.cpp b/src/old/tests/teltest/telnetmonitor.cpp
index 65954eb..65954eb 100644
--- a/src/tests/teltest/telnetmonitor.cpp
+++ b/src/old/tests/teltest/telnetmonitor.cpp
diff --git a/src/tests/teltest/telnetmonitor.h b/src/old/tests/teltest/telnetmonitor.h
index ba5761e..ba5761e 100644
--- a/src/tests/teltest/telnetmonitor.h
+++ b/src/old/tests/teltest/telnetmonitor.h
diff --git a/src/tests/xmlreadtest.cpp b/src/old/tests/xmlreadtest.cpp
index d061810..d061810 100644
--- a/src/tests/xmlreadtest.cpp
+++ b/src/old/tests/xmlreadtest.cpp
diff --git a/src/tests/xmlrepltest.cpp b/src/old/tests/xmlrepltest.cpp
index 9667705..9667705 100644
--- a/src/tests/xmlrepltest.cpp
+++ b/src/old/tests/xmlrepltest.cpp
diff --git a/src/tests/xmlwritetest.cpp b/src/old/tests/xmlwritetest.cpp
index a22d19d..a22d19d 100644
--- a/src/tests/xmlwritetest.cpp
+++ b/src/old/tests/xmlwritetest.cpp
diff --git a/src/tokenstring.cpp b/src/old/tokenstring.cpp
index e57ba69..e57ba69 100644
--- a/src/tokenstring.cpp
+++ b/src/old/tokenstring.cpp
diff --git a/src/tokenstring.h b/src/old/tokenstring.h
index 42f7309..42f7309 100644
--- a/src/tokenstring.h
+++ b/src/old/tokenstring.h
diff --git a/src/tqsort.h b/src/old/tqsort.h
index c836b4f..c836b4f 100644
--- a/src/tqsort.h
+++ b/src/old/tqsort.h
diff --git a/src/unit/hashtable/hashtable.cpp b/src/old/unit/hashtable/hashtable.cpp
index b2e1cf5..b2e1cf5 100644
--- a/src/unit/hashtable/hashtable.cpp
+++ b/src/old/unit/hashtable/hashtable.cpp
diff --git a/src/unit/xml/xml.cpp b/src/old/unit/xml/xml.cpp
index e4d779c..e4d779c 100644
--- a/src/unit/xml/xml.cpp
+++ b/src/old/unit/xml/xml.cpp
diff --git a/src/xmldocument.cpp b/src/old/xmldocument.cpp
index d7867d5..95b9788 100644
--- a/src/xmldocument.cpp
+++ b/src/old/xmldocument.cpp
@@ -1,6 +1,6 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <stdlib.h> 2#include <stdlib.h>
3#include "xmlwriter.h" 3#include "xmldocument.h"
4 4
5XmlDocument::XmlDocument( XmlNode *pRoot ) 5XmlDocument::XmlDocument( XmlNode *pRoot )
6{ 6{
@@ -17,28 +17,23 @@ XmlDocument::~XmlDocument()
17 } 17 }
18} 18}
19 19
20void XmlDocument::addNode( const char *sName, const char *sContent, bool bClose ) 20void XmlDocument::addNode( const Bu::FString &sName )
21{ 21{
22 if( pRoot == NULL ) 22 if( pRoot == NULL )
23 { 23 {
24 // This is the first node, so ignore position and just insert it. 24 // This is the first node, so ignore position and just insert it.
25 pCurrent = pRoot = new XmlNode( sName, NULL, sContent ); 25 pCurrent = pRoot = new XmlNode( sName );
26 } 26 }
27 else 27 else
28 { 28 {
29 pCurrent = pCurrent->addChild( sName, sContent ); 29 pCurrent = pCurrent->addChild( sName );
30 }
31
32 if( bClose )
33 {
34 closeNode();
35 } 30 }
36} 31}
37 32/*
38void XmlDocument::setName( const char *sName ) 33void XmlDocument::setName( const char *sName )
39{ 34{
40 pCurrent->setName( sName ); 35 pCurrent->setName( sName );
41} 36}*/
42 37
43bool XmlDocument::isCompleted() 38bool XmlDocument::isCompleted()
44{ 39{
@@ -143,7 +138,8 @@ void XmlDocument::setContent( const char *sContent )
143{ 138{
144 if( pCurrent ) 139 if( pCurrent )
145 { 140 {
146 pCurrent->setContent( sContent ); 141 printf("XmlDocument::setContent: not yet implemented.\n");
142 //pCurrent->setContent( sContent );
147 } 143 }
148} 144}
149 145
diff --git a/src/xmldocument.h b/src/old/xmldocument.h
index 6671c41..e0c36eb 100644
--- a/src/xmldocument.h
+++ b/src/old/xmldocument.h
@@ -39,13 +39,7 @@ public:
39 * the node and setting the content and name. If this is set to true the 39 * the node and setting the content and name. If this is set to true the
40 * node is appended, but the context node doesn't change. 40 * node is appended, but the context node doesn't change.
41 */ 41 */
42 void addNode( const char *sName=NULL, const char *sContent=NULL, bool bClose=false ); 42 void addNode( const Bu::FString &sName );
43
44 /**
45 * Set the name of the current node context.
46 *@param sName The new name of the node.
47 */
48 void setName( const char *sName );
49 43
50 /** 44 /**
51 * Close the current node context. This will move the current context to 45 * Close the current node context. This will move the current context to
diff --git a/src/xmlfilereader.cpp b/src/old/xmlfilereader.cpp
index ed674a8..ed674a8 100644
--- a/src/xmlfilereader.cpp
+++ b/src/old/xmlfilereader.cpp
diff --git a/src/xmlfilereader.h b/src/old/xmlfilereader.h
index e3e02c2..e3e02c2 100644
--- a/src/xmlfilereader.h
+++ b/src/old/xmlfilereader.h
diff --git a/src/xmlfilewriter.cpp b/src/old/xmlfilewriter.cpp
index 3c6fb41..3c6fb41 100644
--- a/src/xmlfilewriter.cpp
+++ b/src/old/xmlfilewriter.cpp
diff --git a/src/xmlfilewriter.h b/src/old/xmlfilewriter.h
index e328f96..e328f96 100644
--- a/src/xmlfilewriter.h
+++ b/src/old/xmlfilewriter.h
diff --git a/src/xmlnode.cpp b/src/old/xmlnode.cpp
index b1ed9a9..96d5850 100644
--- a/src/xmlnode.cpp
+++ b/src/old/xmlnode.cpp
@@ -1,53 +1,15 @@
1#include "xmlnode.h" 1#include "xmlnode.h"
2#include "hashfunctionstring.h"
3 2
4XmlNode::XmlNode( const char *sName, XmlNode *pParent, const char *sContent ) : 3XmlNode::XmlNode( const Bu::FString &sName, XmlNode *pParent ) :
5 hProperties( new HashFunctionString(), 53, false ), 4 sName( sName ),
6 hChildren( new HashFunctionString(), 53, true ) 5 pParent( pParent )
7{ 6{
8 this->pParent = pParent;
9 if( sName != NULL )
10 {
11 setName( sName );
12 }
13 if( sContent != NULL )
14 {
15 this->sPreContent = new std::string( sContent );
16 }
17 else
18 {
19 this->sPreContent = NULL;
20 }
21 nCurContent = 0;
22} 7}
23 8
24XmlNode::~XmlNode() 9XmlNode::~XmlNode()
25{ 10{
26 for( int j = 0; j < lChildren.getSize(); j++ )
27 {
28 delete (XmlNode *)lChildren[j];
29 }
30 for( int j = 0; j < lPropNames.getSize(); j++ )
31 {
32 delete (std::string *)lPropNames[j];
33 }
34 for( int j = 0; j < lPropValues.getSize(); j++ )
35 {
36 delete (std::string *)lPropValues[j];
37 }
38 for( int j = 0; j < lPostContent.getSize(); j++ )
39 {
40 if( lPostContent[j] != NULL )
41 {
42 delete (std::string *)lPostContent[j];
43 }
44 }
45 if( sPreContent )
46 {
47 delete sPreContent;
48 }
49} 11}
50 12/*
51void XmlNode::setName( const char *sName ) 13void XmlNode::setName( const char *sName )
52{ 14{
53 if( pParent ) 15 if( pParent )
@@ -120,18 +82,18 @@ const char *XmlNode::getContent( int nIndex )
120 } 82 }
121 83
122 return NULL; 84 return NULL;
123} 85}*/
124 86
125XmlNode *XmlNode::addChild( const char *sName, const char *sContent ) 87XmlNode *XmlNode::addChild( const Bu::FString &sName )
126{ 88{
127 return addChild( new XmlNode( sName, this, sContent ) ); 89 return addChild( new XmlNode( sName, this ) );
128} 90}
129 91
130XmlNode *XmlNode::addChild( XmlNode *pNode ) 92XmlNode *XmlNode::addChild( XmlNode *pNode )
131{ 93{
132 lChildren.append( pNode ); 94 Child c = { typeNode };
133 lPostContent.append( NULL ); 95 c.pNode = pNode;
134 nCurContent++; 96 lChildren.append( c );
135 pNode->pParent = this; 97 pNode->pParent = this;
136 98
137 return pNode; 99 return pNode;
@@ -142,21 +104,16 @@ XmlNode *XmlNode::getParent()
142 return pParent; 104 return pParent;
143} 105}
144 106
145void XmlNode::addProperty( const char *sName, const char *sValue ) 107void XmlNode::addProperty( const Bu::FString &sName, const Bu::FString &sValue )
146{ 108{
147 std::string *pName = new std::string( sName ); 109 hProperties.insert( sName, sValue );
148 std::string *pValue = new std::string( sValue );
149
150 hProperties.insert( pName->c_str(), pValue->c_str() );
151 lPropNames.append( pName );
152 lPropValues.append( pValue );
153} 110}
154 111
155int XmlNode::getNumProperties() 112int XmlNode::getNumProperties()
156{ 113{
157 return lPropNames.getSize(); 114 return hProperties.size();
158} 115}
159 116/*
160const char *XmlNode::getPropertyName( int nIndex ) 117const char *XmlNode::getPropertyName( int nIndex )
161{ 118{
162 std::string *tmp = ((std::string *)lPropNames[nIndex]); 119 std::string *tmp = ((std::string *)lPropNames[nIndex]);
@@ -172,15 +129,12 @@ const char *XmlNode::getProperty( int nIndex )
172 return NULL; 129 return NULL;
173 return tmp->c_str(); 130 return tmp->c_str();
174} 131}
175 132*/
176const char *XmlNode::getProperty( const char *sName ) 133Bu::FString XmlNode::getProperty( const Bu::FString &sName )
177{ 134{
178 const char *tmp = (const char *)hProperties[sName]; 135 return hProperties[sName];
179 if( tmp == NULL )
180 return NULL;
181 return tmp;
182} 136}
183 137/*
184void XmlNode::deleteProperty( int nIndex ) 138void XmlNode::deleteProperty( int nIndex )
185{ 139{
186 hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() ); 140 hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() );
@@ -194,29 +148,33 @@ void XmlNode::deleteProperty( int nIndex )
194 148
195bool XmlNode::hasChildren() 149bool XmlNode::hasChildren()
196{ 150{
197 return lChildren.getSize()>0; 151 return hChildren.getSize()>0;
198} 152}*/
199 153
200int XmlNode::getNumChildren() 154int XmlNode::getNumChildren()
201{ 155{
202 return lChildren.getSize(); 156 return lChildren.getSize();
203} 157}
204 158/*
205XmlNode *XmlNode::getChild( int nIndex ) 159XmlNode *XmlNode::getChild( int nIndex )
206{ 160{
207 return (XmlNode *)lChildren[nIndex]; 161 return (XmlNode *)lChildren[nIndex];
208} 162}
209 163*/
210XmlNode *XmlNode::getChild( const char *sName, int nSkip ) 164XmlNode *XmlNode::getChild( const Bu::FString &sName, int nSkip )
211{ 165{
212 return (XmlNode *)hChildren.get( sName, nSkip ); 166 if( !hChildren.has( sName ) )
167 return NULL;
168
169 Bu::List<XmlNode *>::iterator i = hChildren[sName]->begin();
170 return *i;
213} 171}
214 172
215const char *XmlNode::getName() 173Bu::FString XmlNode::getName()
216{ 174{
217 return sName.c_str(); 175 return sName;
218} 176}
219 177/*
220void XmlNode::deleteNode( int nIndex, const char *sReplacementText ) 178void XmlNode::deleteNode( int nIndex, const char *sReplacementText )
221{ 179{
222 XmlNode *xRet = detatchNode( nIndex, sReplacementText ); 180 XmlNode *xRet = detatchNode( nIndex, sReplacementText );
@@ -442,4 +400,4 @@ void XmlNode::deleteNodeKeepChildren( int nIndex )
442void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ) 400void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode )
443{ 401{
444} 402}
445 403*/
diff --git a/src/xmlnode.h b/src/old/xmlnode.h
index 7525306..c895cd8 100644
--- a/src/xmlnode.h
+++ b/src/old/xmlnode.h
@@ -2,8 +2,9 @@
2#define XMLNODE 2#define XMLNODE
3 3
4#include <iostream> 4#include <iostream>
5#include "linkedlist.h" 5#include "bu/list.h"
6#include "hashtable.h" 6#include "bu/hash.h"
7#include "bu/fstring.h"
7 8
8/** 9/**
9 * Maintains all data pertient to an XML node, including sub-nodes and content. 10 * Maintains all data pertient to an XML node, including sub-nodes and content.
@@ -25,9 +26,8 @@ public:
25 *@param sContent The initial content string. 26 *@param sContent The initial content string.
26 */ 27 */
27 XmlNode( 28 XmlNode(
28 const char *sName=NULL, 29 const Bu::FString &sName,
29 XmlNode *pParent = NULL, 30 XmlNode *pParent=NULL
30 const char *sContent=NULL
31 ); 31 );
32 32
33 /** 33 /**
@@ -39,7 +39,7 @@ public:
39 * Change the name of the node. 39 * Change the name of the node.
40 *@param sName The new name of the node. 40 *@param sName The new name of the node.
41 */ 41 */
42 void setName( const char *sName ); 42 //void setName( const char *sName );
43 43
44 /** 44 /**
45 * Construct a new node and add it as a child to this node, also return a 45 * Construct a new node and add it as a child to this node, also return a
@@ -48,7 +48,7 @@ public:
48 *@param sContent The initial content of the new node. 48 *@param sContent The initial content of the new node.
49 *@returns A pointer to the newly created child node. 49 *@returns A pointer to the newly created child node.
50 */ 50 */
51 XmlNode *addChild( const char *sName, const char *sContent=NULL ); 51 XmlNode *addChild( const Bu::FString &sName );
52 52
53 /** 53 /**
54 * Add an already created XmlNode as a child to this node. The new child 54 * Add an already created XmlNode as a child to this node. The new child
@@ -65,7 +65,7 @@ public:
65 * in use will overwrite that property. 65 * in use will overwrite that property.
66 *@param sValue The textual value of the property. 66 *@param sValue The textual value of the property.
67 */ 67 */
68 void addProperty( const char *sName, const char *sValue ); 68 void addProperty( const Bu::FString &sName, const Bu::FString &sValue );
69 69
70 /** 70 /**
71 * Get a pointer to the parent node, if any. 71 * Get a pointer to the parent node, if any.
@@ -86,14 +86,6 @@ public:
86 int getNumChildren(); 86 int getNumChildren();
87 87
88 /** 88 /**
89 * Get a child node at a specific index.
90 *@param nIndex The zero-based index of the child to retreive.
91 *@returns A pointer to the child, or NULL if you requested an invalid
92 * index.
93 */
94 XmlNode *getChild( int nIndex );
95
96 /**
97 * Get a child with the specified name, and possibly skip value. For an 89 * Get a child with the specified name, and possibly skip value. For an
98 * explination of skip values see the HashTable. 90 * explination of skip values see the HashTable.
99 *@param sName The name of the child to find. 91 *@param sName The name of the child to find.
@@ -101,14 +93,14 @@ public:
101 *@returns A pointer to the child, or NULL if no child with that name was 93 *@returns A pointer to the child, or NULL if no child with that name was
102 * found. 94 * found.
103 */ 95 */
104 XmlNode *getChild( const char *sName, int nSkip=0 ); 96 XmlNode *getChild( const Bu::FString &sName, int nSkip=0 );
105 97
106 /** 98 /**
107 * Get a pointer to the name of this node. Do not change this, use setName 99 * Get a pointer to the name of this node. Do not change this, use setName
108 * instead. 100 * instead.
109 *@returns A pointer to the name of this node. 101 *@returns A pointer to the name of this node.
110 */ 102 */
111 const char *getName(); 103 Bu::FString getName();
112 104
113 /** 105 /**
114 * Set the content of this node, optionally at a specific index. Using the 106 * Set the content of this node, optionally at a specific index. Using the
@@ -116,14 +108,7 @@ public:
116 *@param sContent The content string to use. 108 *@param sContent The content string to use.
117 *@param nIndex The index of the content. 109 *@param nIndex The index of the content.
118 */ 110 */
119 void setContent( const char *sContent, int nIndex=-1 ); 111 //void setContent( const char *sContent, int nIndex=-1 );
120
121 /**
122 * Get the content string at a given index, or zero for initial content.
123 *@param nIndex The index of the content.
124 *@returns A pointer to the content at that location.
125 */
126 const char *getContent( int nIndex = 0 );
127 112
128 /** 113 /**
129 * Get the number of properties in this node. 114 * Get the number of properties in this node.
@@ -132,36 +117,12 @@ public:
132 int getNumProperties(); 117 int getNumProperties();
133 118
134 /** 119 /**
135 * Get a property's name by index.
136 *@param nIndex The index of the property to examine.
137 *@returns A pointer to the name of the property specified, or NULL if none
138 * found.
139 */
140 const char *getPropertyName( int nIndex );
141
142 /**
143 * Get a proprty's value by index.
144 *@param nIndex The index of the property to examine.
145 *@returns A pointer to the value of the property specified, or NULL if none
146 * found.
147 */
148 const char *getProperty( int nIndex );
149
150 /**
151 * Get a propery's value by name. 120 * Get a propery's value by name.
152 *@param sName The name of the property to examine. 121 *@param sName The name of the property to examine.
153 *@returns A pointer to the value of the property specified, or NULL if none 122 *@returns A pointer to the value of the property specified, or NULL if none
154 * found. 123 * found.
155 */ 124 */
156 const char *getProperty( const char *sName ); 125 Bu::FString getProperty( const Bu::FString &sName );
157
158 /**
159 * Delete a property by index.
160 *@param nIndex The index of the property to delete.
161 *@returns True if the property was found and deleted, false if it wasn't
162 * found.
163 */
164 void deleteProperty( int nIndex );
165 126
166 /** 127 /**
167 * Delete a child node, possibly replacing it with some text. This actually 128 * Delete a child node, possibly replacing it with some text. This actually
@@ -171,7 +132,7 @@ public:
171 *@returns True of the node was found, and deleted, false if it wasn't 132 *@returns True of the node was found, and deleted, false if it wasn't
172 * found. 133 * found.
173 */ 134 */
174 void deleteNode( int nIndex, const char *sReplacementText = NULL ); 135 //void deleteNode( int nIndex, const char *sReplacementText = NULL );
175 136
176 /** 137 /**
177 * Delete a given node, but move all of it's children and content up to 138 * Delete a given node, but move all of it's children and content up to
@@ -180,7 +141,7 @@ public:
180 *@param nIndex The node to delete. 141 *@param nIndex The node to delete.
181 *@returns True if the node was found and deleted, false if it wasn't. 142 *@returns True if the node was found and deleted, false if it wasn't.
182 */ 143 */
183 void deleteNodeKeepChildren( int nIndex ); 144 //void deleteNodeKeepChildren( int nIndex );
184 145
185 /** 146 /**
186 * Detatch a given child node from this node. This effectively works just 147 * Detatch a given child node from this node. This effectively works just
@@ -192,7 +153,7 @@ public:
192 *@returns A pointer to the newly detatched node, which then passes 153 *@returns A pointer to the newly detatched node, which then passes
193 * ownership to the caller. 154 * ownership to the caller.
194 */ 155 */
195 XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL ); 156 //XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL );
196 157
197 /** 158 /**
198 * Replace a given node with a different node that is not currently owned by 159 * Replace a given node with a different node that is not currently owned by
@@ -201,7 +162,7 @@ public:
201 *@param pNewNode The new node to replace the old node with. 162 *@param pNewNode The new node to replace the old node with.
202 *@returns True if the node was found and replaced, false if it wasn't. 163 *@returns True if the node was found and replaced, false if it wasn't.
203 */ 164 */
204 void replaceNode( int nIndex, XmlNode *pNewNode ); 165 //void replaceNode( int nIndex, XmlNode *pNewNode );
205 166
206 /** 167 /**
207 * Replace a given node with the children and content of a given node. 168 * Replace a given node with the children and content of a given node.
@@ -210,24 +171,34 @@ public:
210 * replace the node specified by nIndex. 171 * replace the node specified by nIndex.
211 *@returns True if the node was found and replaced, false if it wasn't. 172 *@returns True if the node was found and replaced, false if it wasn't.
212 */ 173 */
213 void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ); 174 //void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode );
214 175
215 /** 176 /**
216 * Get a copy of this node and all children. getCopy is recursive, so 177 * Get a copy of this node and all children. getCopy is recursive, so
217 * beware copying large trees of xml. 178 * beware copying large trees of xml.
218 *@returns A newly created copy of this node and all of it's children. 179 *@returns A newly created copy of this node and all of it's children.
219 */ 180 */
220 XmlNode *getCopy(); 181 //XmlNode *getCopy();
182
183 enum ChildType
184 {
185 typeNode,
186 typeContent
187 };
221 188
222private: 189private:
223 std::string sName; /**< The name of the node. */ 190 typedef struct
224 std::string *sPreContent; /**< The content that goes before any node. */ 191 {
225 LinkedList lChildren; /**< The children. */ 192 uint8_t nType;
226 LinkedList lPostContent; /**< The content that comes after children. */ 193 union {
227 HashTable hProperties; /**< Property hashtable. */ 194 XmlNode *pNode;
228 HashTable hChildren; /**< Children hashtable. */ 195 Bu::FString *pContent;
229 LinkedList lPropNames; /**< List of property names. */ 196 };
230 LinkedList lPropValues; /**< List of property values. */ 197 } Child;
198 Bu::FString sName; /**< The name of the node. */
199 Bu::List<Child> lChildren; /**< The children. */
200 Bu::Hash<Bu::FString, Bu::FString> hProperties; /**< Property hashtable. */
201 Bu::Hash<Bu::FString, Bu::List<XmlNode *> > hChildren; /**< Children hashtable. */
231 XmlNode *pParent; /**< A pointer to the parent of this node. */ 202 XmlNode *pParent; /**< A pointer to the parent of this node. */
232 int nCurContent; /**< The current content we're on, for using the -1 on 203 int nCurContent; /**< The current content we're on, for using the -1 on
233 setContent. */ 204 setContent. */
diff --git a/src/xmlreader.cpp b/src/old/xmlreader.cpp
index 18df69c..38cad5f 100644
--- a/src/xmlreader.cpp
+++ b/src/old/xmlreader.cpp
@@ -1,32 +1,49 @@
1#include "xmlreader.h" 1#include "bu/xmlreader.h"
2#include "exceptions.h" 2#include "bu/exceptions.h"
3#include <string.h> 3#include <string.h>
4#include "hashfunctionstring.h"
5 4
6XmlReader::XmlReader( bool bStrip ) : 5XmlReader::XmlReader( Bu::Stream &sIn, bool bStrip ) :
7 bStrip( bStrip ), 6 sIn( sIn ),
8 htEntity( new HashFunctionString(), 11 ) 7 bStrip( bStrip )
9{ 8{
9 buildDoc();
10} 10}
11 11
12XmlReader::~XmlReader() 12XmlReader::~XmlReader()
13{ 13{
14 void *i = htEntity.getFirstItemPos(); 14}
15 while( (i = htEntity.getNextItemPos( i ) ) ) 15
16char XmlReader::getChar( int nIndex )
17{
18 if( sBuf.getSize() <= nIndex )
16 { 19 {
17 free( (char *)(htEntity.getItemID( i )) ); 20 int nInc = nIndex-sBuf.getSize()+1;
18 delete (StaticString *)htEntity.getItemData( i ); 21 char *buf = new char[nInc];
22 sIn.read( buf, nInc );
23 sBuf.append( buf, nInc );
24 delete[] buf;
19 } 25 }
26
27 return sBuf[nIndex];
20} 28}
21 29
22void XmlReader::addEntity( const char *name, const char *value ) 30void XmlReader::usedChar( int nAmnt )
23{ 31{
24 if( htEntity[name] ) return; 32 if( nAmnt >= sBuf.getSize() )
25 33 {
26 char *sName = strdup( name ); 34 sBuf.clear();
27 StaticString *sValue = new StaticString( value ); 35 }
36 else
37 {
38 char *s = sBuf.getStr();
39 memcpy( s, s+nAmnt, sBuf.getSize()-nAmnt );
40 sBuf.resize( sBuf.getSize()-nAmnt );
41 }
42}
28 43
29 htEntity.insert( sName, sValue ); 44void XmlReader::addEntity( const Bu::FString &name, const Bu::FString &value )
45{
46 htEntity[name] = value;
30} 47}
31 48
32#define gcall( x ) if( x == false ) return false; 49#define gcall( x ) if( x == false ) return false;
@@ -99,7 +116,7 @@ void XmlReader::entity()
99 { 116 {
100 usedChar( 2 ); 117 usedChar( 2 );
101 ws(); 118 ws();
102 std::string buf; 119 Bu::FString buf;
103 for(;;) 120 for(;;)
104 { 121 {
105 char chr = getChar(); 122 char chr = getChar();
@@ -111,7 +128,7 @@ void XmlReader::entity()
111 if( strcmp( buf.c_str(), "ENTITY") == 0 ) 128 if( strcmp( buf.c_str(), "ENTITY") == 0 )
112 { 129 {
113 ws(); 130 ws();
114 std::string name; 131 Bu::FString name;
115 for(;;) 132 for(;;)
116 { 133 {
117 char chr = getChar(); 134 char chr = getChar();
@@ -124,21 +141,19 @@ void XmlReader::entity()
124 usedChar(); 141 usedChar();
125 if( quot != '\'' && quot != '\"' ) 142 if( quot != '\'' && quot != '\"' )
126 { 143 {
127 throw XmlException( 144 throw Bu::XmlException(
128 "Only quoted entity values are supported." 145 "Only quoted entity values are supported."
129 ); 146 );
130 } 147 }
131 std::string value; 148 Bu::FString value;
132 for(;;) 149 for(;;)
133 { 150 {
134 char chr = getChar(); 151 char chr = getChar();
135 usedChar(); 152 usedChar();
136 if( chr == '&' ) 153 if( chr == '&' )
137 { 154 {
138 StaticString *tmp = getEscape(); 155 Bu::FString tmp = getEscape();
139 if( tmp == NULL ) throw XmlException("Entity thing"); 156 value += tmp;
140 value += tmp->getString();
141 delete tmp;
142 } 157 }
143 else if( chr == quot ) 158 else if( chr == quot )
144 { 159 {
@@ -158,7 +173,7 @@ void XmlReader::entity()
158 } 173 }
159 else 174 else
160 { 175 {
161 throw XmlException( 176 throw Bu::XmlException(
162 "Malformed ENTITY: unexpected '%c' found.", 177 "Malformed ENTITY: unexpected '%c' found.",
163 getChar() 178 getChar()
164 ); 179 );
@@ -166,7 +181,7 @@ void XmlReader::entity()
166 } 181 }
167 else 182 else
168 { 183 {
169 throw XmlException( 184 throw Bu::XmlException(
170 "Unsupported header symbol: %s", 185 "Unsupported header symbol: %s",
171 buf.c_str() 186 buf.c_str()
172 ); 187 );
@@ -203,12 +218,12 @@ bool XmlReader::node()
203 } 218 }
204 else 219 else
205 { 220 {
206 throw XmlException("Close node in singleNode malformed!"); 221 throw Bu::XmlException("Close node in singleNode malformed!");
207 } 222 }
208 } 223 }
209 else 224 else
210 { 225 {
211 throw XmlException("Close node expected, but not found."); 226 throw Bu::XmlException("Close node expected, but not found.");
212 return false; 227 return false;
213 } 228 }
214 229
@@ -224,7 +239,7 @@ bool XmlReader::startNode()
224 if( getChar() == '/' ) 239 if( getChar() == '/' )
225 { 240 {
226 // Heh, it's actually a close node, go figure 241 // Heh, it's actually a close node, go figure
227 FlexBuf fbName; 242 Bu::FString sName;
228 usedChar(); 243 usedChar();
229 gcall( ws() ); 244 gcall( ws() );
230 245
@@ -235,19 +250,19 @@ bool XmlReader::startNode()
235 { 250 {
236 // Here we actually compare the name we got to the name 251 // Here we actually compare the name we got to the name
237 // we already set, they have to match exactly. 252 // we already set, they have to match exactly.
238 if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) 253 if( getCurrent()->getName() == sName )
239 { 254 {
240 closeNode(); 255 closeNode();
241 break; 256 break;
242 } 257 }
243 else 258 else
244 { 259 {
245 throw XmlException("Got a mismatched node close tag."); 260 throw Bu::XmlException("Got a mismatched node close tag.");
246 } 261 }
247 } 262 }
248 else 263 else
249 { 264 {
250 fbName.appendData( chr ); 265 sName += chr;
251 usedChar(); 266 usedChar();
252 } 267 }
253 } 268 }
@@ -260,13 +275,13 @@ bool XmlReader::startNode()
260 } 275 }
261 else 276 else
262 { 277 {
263 throw XmlException("Got extra junk data instead of node close tag."); 278 throw Bu::XmlException("Got extra junk data instead of node close tag.");
264 } 279 }
265 } 280 }
266 else 281 else
267 { 282 {
268 // We're good, format is consistant 283 // We're good, format is consistant
269 addNode(); 284 //addNode();
270 285
271 // Skip extra whitespace 286 // Skip extra whitespace
272 gcall( ws() ); 287 gcall( ws() );
@@ -278,7 +293,7 @@ bool XmlReader::startNode()
278 } 293 }
279 else 294 else
280 { 295 {
281 throw XmlException("Expected to find node opening char, '<'."); 296 throw Bu::XmlException("Expected to find node opening char, '<'.");
282 } 297 }
283 298
284 return true; 299 return true;
@@ -286,19 +301,19 @@ bool XmlReader::startNode()
286 301
287bool XmlReader::name() 302bool XmlReader::name()
288{ 303{
289 FlexBuf fbName; 304 Bu::FString sName;
290 305
291 while( true ) 306 while( true )
292 { 307 {
293 char chr = getChar(); 308 char chr = getChar();
294 if( isws( chr ) || chr == '>' || chr == '/' ) 309 if( isws( chr ) || chr == '>' || chr == '/' )
295 { 310 {
296 setName( fbName.getData() ); 311 addNode( sName );
297 return true; 312 return true;
298 } 313 }
299 else 314 else
300 { 315 {
301 fbName.appendData( chr ); 316 sName += chr;
302 usedChar(); 317 usedChar();
303 } 318 }
304 } 319 }
@@ -325,7 +340,7 @@ bool XmlReader::paramlist()
325 return true; 340 return true;
326} 341}
327 342
328StaticString *XmlReader::getEscape() 343Bu::FString XmlReader::getEscape()
329{ 344{
330 if( getChar( 1 ) == '#' ) 345 if( getChar( 1 ) == '#' )
331 { 346 {
@@ -349,12 +364,12 @@ StaticString *XmlReader::getEscape()
349 buf[0] = (char)strtol( buf, (char **)NULL, base ); 364 buf[0] = (char)strtol( buf, (char **)NULL, base );
350 buf[1] = '\0'; 365 buf[1] = '\0';
351 366
352 return new StaticString( buf ); 367 return buf;
353 } 368 }
354 else 369 else
355 { 370 {
356 // ...otherwise replace with the appropriate string... 371 // ...otherwise replace with the appropriate string...
357 std::string buf; 372 Bu::FString buf;
358 usedChar(); 373 usedChar();
359 for(;;) 374 for(;;)
360 { 375 {
@@ -364,18 +379,14 @@ StaticString *XmlReader::getEscape()
364 buf += cbuf; 379 buf += cbuf;
365 } 380 }
366 381
367 StaticString *tmp = (StaticString *)htEntity[buf.c_str()]; 382 return htEntity[buf];
368 if( tmp == NULL ) return NULL;
369
370 StaticString *ret = new StaticString( *tmp );
371 return ret;
372 } 383 }
373} 384}
374 385
375bool XmlReader::param() 386bool XmlReader::param()
376{ 387{
377 FlexBuf fbName; 388 Bu::FString sName;
378 FlexBuf fbValue; 389 Bu::FString sValue;
379 390
380 while( true ) 391 while( true )
381 { 392 {
@@ -386,7 +397,7 @@ bool XmlReader::param()
386 } 397 }
387 else 398 else
388 { 399 {
389 fbName.appendData( chr ); 400 sName.append( chr );
390 usedChar(); 401 usedChar();
391 } 402 }
392 } 403 }
@@ -411,21 +422,18 @@ bool XmlReader::param()
411 if( chr == '"' ) 422 if( chr == '"' )
412 { 423 {
413 usedChar(); 424 usedChar();
414 addProperty( fbName.getData(), fbValue.getData() ); 425 addProperty( sName.getStr(), sValue.getStr() );
415 return true; 426 return true;
416 } 427 }
417 else 428 else
418 { 429 {
419 if( chr == '&' ) 430 if( chr == '&' )
420 { 431 {
421 StaticString *tmp = getEscape(); 432 sValue += getEscape();
422 if( tmp == NULL ) return false;
423 fbValue.appendData( tmp->getString() );
424 delete tmp;
425 } 433 }
426 else 434 else
427 { 435 {
428 fbValue.appendData( chr ); 436 sValue += chr;
429 usedChar(); 437 usedChar();
430 } 438 }
431 } 439 }
@@ -439,21 +447,18 @@ bool XmlReader::param()
439 chr = getChar(); 447 chr = getChar();
440 if( isws( chr ) || chr == '/' || chr == '>' ) 448 if( isws( chr ) || chr == '/' || chr == '>' )
441 { 449 {
442 addProperty( fbName.getData(), fbValue.getData() ); 450 addProperty( sName.getStr(), sValue.getStr() );
443 return true; 451 return true;
444 } 452 }
445 else 453 else
446 { 454 {
447 if( chr == '&' ) 455 if( chr == '&' )
448 { 456 {
449 StaticString *tmp = getEscape(); 457 sValue += getEscape();
450 if( tmp == NULL ) return false;
451 fbValue.appendData( tmp->getString() );
452 delete tmp;
453 } 458 }
454 else 459 else
455 { 460 {
456 fbValue.appendData( chr ); 461 sValue += chr;
457 usedChar(); 462 usedChar();
458 } 463 }
459 } 464 }
@@ -462,7 +467,7 @@ bool XmlReader::param()
462 } 467 }
463 else 468 else
464 { 469 {
465 throw XmlException("Expected an equals to seperate the params."); 470 throw Bu::XmlException("Expected an equals to seperate the params.");
466 return false; 471 return false;
467 } 472 }
468 473
@@ -471,7 +476,7 @@ bool XmlReader::param()
471 476
472bool XmlReader::content() 477bool XmlReader::content()
473{ 478{
474 FlexBuf fbContent; 479 Bu::FString sContent;
475 480
476 if( bStrip ) gcall( ws() ); 481 if( bStrip ) gcall( ws() );
477 482
@@ -482,37 +487,37 @@ bool XmlReader::content()
482 { 487 {
483 if( getChar(1) == '/' ) 488 if( getChar(1) == '/' )
484 { 489 {
485 if( fbContent.getLength() > 0 ) 490 if( sContent.getSize() > 0 )
486 { 491 {
487 if( bStrip ) 492 if( bStrip )
488 { 493 {
489 int j; 494 int j;
490 for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); 495 for( j = sContent.getSize()-1; isws(sContent[j]); j-- );
491 ((char *)fbContent.getData())[j+1] = '\0'; 496 sContent[j+1] = '\0';
492 } 497 }
493 setContent( fbContent.getData() ); 498 setContent( sContent.getStr() );
494 } 499 }
495 usedChar( 2 ); 500 usedChar( 2 );
496 gcall( ws() ); 501 gcall( ws() );
497 FlexBuf fbName; 502 Bu::FString sName;
498 while( true ) 503 while( true )
499 { 504 {
500 chr = getChar(); 505 chr = getChar();
501 if( isws( chr ) || chr == '>' ) 506 if( isws( chr ) || chr == '>' )
502 { 507 {
503 if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) 508 if( !strcasecmp( getCurrent()->getName().getStr(), sName.getStr() ) )
504 { 509 {
505 closeNode(); 510 closeNode();
506 break; 511 break;
507 } 512 }
508 else 513 else
509 { 514 {
510 throw XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName(), fbName.getData() ); 515 throw Bu::XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName().getStr(), sName.getStr() );
511 } 516 }
512 } 517 }
513 else 518 else
514 { 519 {
515 fbName.appendData( chr ); 520 sName += chr;
516 usedChar(); 521 usedChar();
517 } 522 }
518 } 523 }
@@ -524,7 +529,7 @@ bool XmlReader::content()
524 } 529 }
525 else 530 else
526 { 531 {
527 throw XmlException("Malformed close tag."); 532 throw Bu::XmlException("Malformed close tag.");
528 } 533 }
529 } 534 }
530 else if( getChar(1) == '!' ) 535 else if( getChar(1) == '!' )
@@ -534,7 +539,7 @@ bool XmlReader::content()
534 getChar(3) != '-' ) 539 getChar(3) != '-' )
535 { 540 {
536 // Not a valid XML comment 541 // Not a valid XML comment
537 throw XmlException("Malformed comment start tag found."); 542 throw Bu::XmlException("Malformed comment start tag found.");
538 } 543 }
539 544
540 usedChar( 4 ); 545 usedChar( 4 );
@@ -549,7 +554,7 @@ bool XmlReader::content()
549 // The next one has to be a '>' now 554 // The next one has to be a '>' now
550 if( getChar( 2 ) != '>' ) 555 if( getChar( 2 ) != '>' )
551 { 556 {
552 throw XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment."); 557 throw Bu::XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment.");
553 } 558 }
554 usedChar( 3 ); 559 usedChar( 3 );
555 break; 560 break;
@@ -569,16 +574,16 @@ bool XmlReader::content()
569 } 574 }
570 else 575 else
571 { 576 {
572 if( fbContent.getLength() > 0 ) 577 if( sContent.getSize() > 0 )
573 { 578 {
574 if( bStrip ) 579 if( bStrip )
575 { 580 {
576 int j; 581 int j;
577 for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); 582 for( j = sContent.getSize()-1; isws(sContent[j]); j-- );
578 ((char *)fbContent.getData())[j+1] = '\0'; 583 sContent[j+1] = '\0';
579 } 584 }
580 setContent( fbContent.getData() ); 585 setContent( sContent.getStr() );
581 fbContent.clearData(); 586 sContent.clear();
582 } 587 }
583 gcall( node() ); 588 gcall( node() );
584 } 589 }
@@ -587,14 +592,11 @@ bool XmlReader::content()
587 } 592 }
588 else if( chr == '&' ) 593 else if( chr == '&' )
589 { 594 {
590 StaticString *tmp = getEscape(); 595 sContent += getEscape();
591 if( tmp == NULL ) return false;
592 fbContent.appendData( tmp->getString() );
593 delete tmp;
594 } 596 }
595 else 597 else
596 { 598 {
597 fbContent.appendData( chr ); 599 sContent += chr;
598 usedChar(); 600 usedChar();
599 } 601 }
600 } 602 }
diff --git a/src/xmlreader.h b/src/old/xmlreader.h
index c8f7202..7c85ddb 100644
--- a/src/xmlreader.h
+++ b/src/old/xmlreader.h
@@ -2,10 +2,10 @@
2#define XMLREADER 2#define XMLREADER
3 3
4#include <stdio.h> 4#include <stdio.h>
5#include "xmldocument.h" 5#include "bu/xmldocument.h"
6#include "flexbuf.h" 6#include "bu/hash.h"
7#include "hashtable.h" 7#include "bu/fstring.h"
8#include "staticstring.h" 8#include "bu/stream.h"
9 9
10/** 10/**
11 * Takes care of reading in xml formatted data from a file. This could/should 11 * Takes care of reading in xml formatted data from a file. This could/should
@@ -32,7 +32,7 @@ public:
32 * in content, a-la html. 32 * in content, a-la html.
33 *@param bStrip Strip out leading and trailing whitespace? 33 *@param bStrip Strip out leading and trailing whitespace?
34 */ 34 */
35 XmlReader( bool bStrip=false ); 35 XmlReader( Bu::Stream &sIn, bool bStrip=false );
36 36
37 /** 37 /**
38 * Destroy this XmlReader. 38 * Destroy this XmlReader.
@@ -54,12 +54,12 @@ private:
54 *@returns A single character at the requested position, or 0 for end of 54 *@returns A single character at the requested position, or 0 for end of
55 * stream. 55 * stream.
56 */ 56 */
57 virtual char getChar( int nIndex = 0 ) = 0; 57 virtual char getChar( int nIndex = 0 );
58 58
59 /** 59 /**
60 * Called to increment the current stream position by a single character. 60 * Called to increment the current stream position by a single character.
61 */ 61 */
62 virtual void usedChar( int nAmnt = 1) = 0; 62 virtual void usedChar( int nAmnt = 1 );
63 63
64 /** 64 /**
65 * Automoton function: is whitespace. 65 * Automoton function: is whitespace.
@@ -108,9 +108,9 @@ private:
108 *@param name The name of the entity 108 *@param name The name of the entity
109 *@param value The value of the entity 109 *@param value The value of the entity
110 */ 110 */
111 void addEntity( const char *name, const char *value ); 111 void addEntity( const Bu::FString &name, const Bu::FString &value );
112 112
113 StaticString *getEscape(); 113 Bu::FString getEscape();
114 114
115 /** 115 /**
116 * Automoton function: paramlist. Processes a list of node params. 116 * Automoton function: paramlist. Processes a list of node params.
@@ -130,12 +130,15 @@ private:
130 */ 130 */
131 bool content(); 131 bool content();
132 132
133 FlexBuf fbContent; /**< buffer for the current node's content. */ 133 Bu::FString sContent; /**< buffer for the current node's content. */
134 FlexBuf fbParamName; /**< buffer for the current param's name. */ 134 Bu::FString sParamName; /**< buffer for the current param's name. */
135 FlexBuf fbParamValue; /**< buffer for the current param's value. */ 135 Bu::FString sParamValue; /**< buffer for the current param's value. */
136 bool bStrip; /**< Are we stripping whitespace? */ 136 Bu::Stream &sIn;
137 bool bStrip; /**< Are we stripping whitespace? */
137 138
138 HashTable htEntity; /**< Entity type definitions. */ 139 Bu::Hash<Bu::FString,Bu::FString> htEntity; /**< Entity type definitions. */
140
141 Bu::FString sBuf;
139}; 142};
140 143
141#endif 144#endif
diff --git a/src/xmlstringreader.cpp b/src/old/xmlstringreader.cpp
index 3956ff3..3956ff3 100644
--- a/src/xmlstringreader.cpp
+++ b/src/old/xmlstringreader.cpp
diff --git a/src/xmlstringreader.h b/src/old/xmlstringreader.h
index 1239ef4..1239ef4 100644
--- a/src/xmlstringreader.h
+++ b/src/old/xmlstringreader.h
diff --git a/src/xmlstringwriter.cpp b/src/old/xmlstringwriter.cpp
index adeed6a..adeed6a 100644
--- a/src/xmlstringwriter.cpp
+++ b/src/old/xmlstringwriter.cpp
diff --git a/src/xmlstringwriter.h b/src/old/xmlstringwriter.h
index 0d567b9..0d567b9 100644
--- a/src/xmlstringwriter.h
+++ b/src/old/xmlstringwriter.h
diff --git a/src/xmlwriter.cpp b/src/old/xmlwriter.cpp
index 56880b6..7dc6ca9 100644
--- a/src/xmlwriter.cpp
+++ b/src/old/xmlwriter.cpp
@@ -2,17 +2,10 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include "xmlwriter.h" 3#include "xmlwriter.h"
4 4
5XmlWriter::XmlWriter( const char *sIndent, XmlNode *pRoot ) : 5XmlWriter::XmlWriter( const Bu::FString &sIndent, XmlNode *pRoot ) :
6 XmlDocument( pRoot ) 6 XmlDocument( pRoot ),
7 sIndent( sIndent )
7{ 8{
8 if( sIndent == NULL )
9 {
10 this->sIndent = "";
11 }
12 else
13 {
14 this->sIndent = sIndent;
15 }
16} 9}
17 10
18XmlWriter::~XmlWriter() 11XmlWriter::~XmlWriter()
@@ -24,7 +17,7 @@ void XmlWriter::write()
24 write( getRoot(), sIndent.c_str() ); 17 write( getRoot(), sIndent.c_str() );
25} 18}
26 19
27void XmlWriter::write( XmlNode *pRoot, const char *sIndent ) 20void XmlWriter::write( XmlNode *pRoot, const Bu::FString &sIndent )
28{ 21{
29 writeNode( pRoot, 0, sIndent ); 22 writeNode( pRoot, 0, sIndent );
30} 23}
@@ -39,7 +32,7 @@ void XmlWriter::closeNode()
39 } 32 }
40} 33}
41 34
42void XmlWriter::writeIndent( int nIndent, const char *sIndent ) 35void XmlWriter::writeIndent( int nIndent, const Bu::FString &sIndent )
43{ 36{
44 if( sIndent == NULL ) return; 37 if( sIndent == NULL ) return;
45 for( int j = 0; j < nIndent; j++ ) 38 for( int j = 0; j < nIndent; j++ )
@@ -48,26 +41,27 @@ void XmlWriter::writeIndent( int nIndent, const char *sIndent )
48 } 41 }
49} 42}
50 43
51std::string XmlWriter::escape( std::string sIn ) 44Bu::FString XmlWriter::escape( const Bu::FString &sIn )
52{ 45{
53 std::string sOut; 46 Bu::FString sOut;
54 47
55 std::string::const_iterator i; 48 int nMax = sIn.getSize();
56 for( i = sIn.begin(); i != sIn.end(); i++ ) 49 for( int j = 0; j < nMax; j++ )
57 { 50 {
58 if( ((*i >= ' ' && *i <= '9') || 51 char c = sIn[j];
59 (*i >= 'a' && *i <= 'z') || 52 if( ((c >= ' ' && c <= '9') ||
60 (*i >= 'A' && *i <= 'Z') ) && 53 (c >= 'a' && c <= 'z') ||
61 (*i != '\"' && *i != '\'' && *i != '&') 54 (c >= 'A' && c <= 'Z') ) &&
55 (c != '\"' && c != '\'' && c != '&')
62 ) 56 )
63 { 57 {
64 sOut += *i; 58 sOut += c;
65 } 59 }
66 else 60 else
67 { 61 {
68 sOut += "&#"; 62 sOut += "&#";
69 char buf[4]; 63 char buf[4];
70 sprintf( buf, "%u", (unsigned char)*i ); 64 sprintf( buf, "%u", (unsigned char)c );
71 sOut += buf; 65 sOut += buf;
72 sOut += ';'; 66 sOut += ';';
73 } 67 }
@@ -76,19 +70,19 @@ std::string XmlWriter::escape( std::string sIn )
76 return sOut; 70 return sOut;
77} 71}
78 72
79void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ) 73void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent )
80{ 74{
81 for( int j = 0; j < pNode->getNumProperties(); j++ ) 75 for( int j = 0; j < pNode->getNumProperties(); j++ )
82 { 76 {
83 writeString(" "); 77 writeString(" ");
84 writeString( pNode->getPropertyName( j ) ); 78 //writeString( pNode->getPropertyName( j ) );
85 writeString("=\""); 79 writeString("=\"");
86 writeString( escape( pNode->getProperty( j ) ).c_str() ); 80 //writeString( escape( pNode->getProperty( j ) ).c_str() );
87 writeString("\""); 81 writeString("\"");
88 } 82 }
89} 83}
90 84
91void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) 85void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent )
92{ 86{
93 if( pNode->hasChildren() ) 87 if( pNode->hasChildren() )
94 { 88 {
@@ -96,15 +90,15 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
96 writeString("<"); 90 writeString("<");
97 writeString( pNode->getName() ); 91 writeString( pNode->getName() );
98 writeNodeProps( pNode, nIndent, sIndent ); 92 writeNodeProps( pNode, nIndent, sIndent );
99 if( sIndent ) 93 if( sIndent != "" )
100 writeString(">\n"); 94 writeString(">\n");
101 else 95 else
102 writeString(">"); 96 writeString(">");
103 97/*
104 if( pNode->getContent( 0 ) ) 98 if( pNode->getContent( 0 ) )
105 { 99 {
106 writeIndent( nIndent+1, sIndent ); 100 writeIndent( nIndent+1, sIndent );
107 if( sIndent ) 101 if( sIndent != "" )
108 { 102 {
109 writeString( pNode->getContent( 0 ) ); 103 writeString( pNode->getContent( 0 ) );
110 writeString("\n"); 104 writeString("\n");
@@ -129,9 +123,9 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
129 writeString( pNode->getContent( j+1 ) ); 123 writeString( pNode->getContent( j+1 ) );
130 } 124 }
131 } 125 }
132 126*/
133 writeIndent( nIndent, sIndent ); 127 writeIndent( nIndent, sIndent );
134 if( sIndent ) 128 if( sIndent != "" )
135 { 129 {
136 writeString("</"); 130 writeString("</");
137 writeString( pNode->getName() ); 131 writeString( pNode->getName() );
@@ -143,7 +137,7 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
143 writeString( pNode->getName() ); 137 writeString( pNode->getName() );
144 writeString(">"); 138 writeString(">");
145 } 139 }
146 } 140 }/*
147 else if( pNode->getContent() ) 141 else if( pNode->getContent() )
148 { 142 {
149 writeIndent( nIndent, sIndent ); 143 writeIndent( nIndent, sIndent );
@@ -157,14 +151,14 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
157 writeString(">"); 151 writeString(">");
158 if( sIndent ) 152 if( sIndent )
159 writeString("\n"); 153 writeString("\n");
160 } 154 }*/
161 else 155 else
162 { 156 {
163 writeIndent( nIndent, sIndent ); 157 writeIndent( nIndent, sIndent );
164 writeString("<"); 158 writeString("<");
165 writeString( pNode->getName() ); 159 writeString( pNode->getName() );
166 writeNodeProps( pNode, nIndent, sIndent ); 160 writeNodeProps( pNode, nIndent, sIndent );
167 if( sIndent ) 161 if( sIndent != "" )
168 writeString("/>\n"); 162 writeString("/>\n");
169 else 163 else
170 writeString("/>"); 164 writeString("/>");
diff --git a/src/xmlwriter.h b/src/old/xmlwriter.h
index c48e810..7e3c876 100644
--- a/src/xmlwriter.h
+++ b/src/old/xmlwriter.h
@@ -31,7 +31,7 @@ public:
31 * this to a tab or some spaces it will never effect the content of your 31 * this to a tab or some spaces it will never effect the content of your
32 * file. 32 * file.
33 */ 33 */
34 XmlWriter( const char *sIndent=NULL, XmlNode *pRoot=NULL ); 34 XmlWriter( const Bu::FString &sIndent="", XmlNode *pRoot=NULL );
35 35
36 /** 36 /**
37 * Destroy the writer. 37 * Destroy the writer.
@@ -49,16 +49,16 @@ public:
49 void write(); 49 void write();
50 50
51private: 51private:
52 std::string sIndent; /**< The indent string */ 52 Bu::FString sIndent; /**< The indent string */
53 53
54 std::string escape( std::string sIn ); 54 Bu::FString escape( const Bu::FString &sIn );
55 55
56 /** 56 /**
57 * Write the file. 57 * Write the file.
58 *@param pNode The root node 58 *@param pNode The root node
59 *@param sIndent The indent text. 59 *@param sIndent The indent text.
60 */ 60 */
61 void write( XmlNode *pNode, const char *sIndent=NULL ); 61 void write( XmlNode *pNode, const Bu::FString &sIndent );
62 62
63 /** 63 /**
64 * Write a node in the file, including children. 64 * Write a node in the file, including children.
@@ -66,7 +66,7 @@ private:
66 *@param nIndent The indent level (the number of times to include sIndent) 66 *@param nIndent The indent level (the number of times to include sIndent)
67 *@param sIndent The indent text. 67 *@param sIndent The indent text.
68 */ 68 */
69 void writeNode( XmlNode *pNode, int nIndent, const char *sIndent ); 69 void writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent );
70 70
71 /** 71 /**
72 * Write the properties of a node. 72 * Write the properties of a node.
@@ -74,14 +74,14 @@ private:
74 *@param nIndent The indent level of the containing node 74 *@param nIndent The indent level of the containing node
75 *@param sIndent The indent text. 75 *@param sIndent The indent text.
76 */ 76 */
77 void writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ); 77 void writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent );
78 78
79 /** 79 /**
80 * Called to write the actual indent. 80 * Called to write the actual indent.
81 *@param nIndent The indent level. 81 *@param nIndent The indent level.
82 *@param sIndent The indent text. 82 *@param sIndent The indent text.
83 */ 83 */
84 void writeIndent( int nIndent, const char *sIndent ); 84 void writeIndent( int nIndent, const Bu::FString &sIndent );
85 85
86 /** 86 /**
87 * This is the function that must be overridden in order to use this class. 87 * This is the function that must be overridden in order to use this class.
@@ -90,7 +90,7 @@ private:
90 * will break the XML formatting. 90 * will break the XML formatting.
91 *@param sString The string data to write to the output. 91 *@param sString The string data to write to the output.
92 */ 92 */
93 virtual void writeString( const char *sString ) = 0; 93 virtual void writeString( const Bu::FString &sString ) = 0;
94}; 94};
95 95
96#endif 96#endif
diff --git a/src/paramproc.cpp b/src/paramproc.cpp
index a352e66..34e973e 100644
--- a/src/paramproc.cpp
+++ b/src/paramproc.cpp
@@ -2,10 +2,10 @@
2#include <stdio.h> 2#include <stdio.h>
3 3
4#define ptrtype( iitype, iiname ) \ 4#define ptrtype( iitype, iiname ) \
5 ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ 5 Bu::ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \
6 type( vt ##iiname ) { val.iiname = iiname; } 6 type( vt ##iiname ) { val.iiname = iiname; }
7 7
8ParamProc::ParamPtr::ParamPtr() 8Bu::ParamProc::ParamPtr::ParamPtr()
9{ 9{
10 val.str = NULL; 10 val.str = NULL;
11 type = vtunset; 11 type = vtunset;
@@ -25,7 +25,7 @@ ptrtype( double, float64 );
25ptrtype( long double, float96 ); 25ptrtype( long double, float96 );
26ptrtype( bool, bln ); 26ptrtype( bool, bln );
27 27
28ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) 28Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr )
29{ 29{
30 val = ptr.val; 30 val = ptr.val;
31 type = ptr.type; 31 type = ptr.type;
@@ -33,12 +33,12 @@ ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr )
33 return *this; 33 return *this;
34} 34}
35 35
36bool ParamProc::ParamPtr::isSet() 36bool Bu::ParamProc::ParamPtr::isSet()
37{ 37{
38 return type != vtunset; 38 return type != vtunset;
39} 39}
40 40
41ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( const char *str ) 41Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( const char *str )
42{ 42{
43 if( !isSet() ) return *this; 43 if( !isSet() ) return *this;
44 switch( type ) 44 switch( type )
@@ -107,11 +107,11 @@ ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( const char *str )
107 return *this; 107 return *this;
108} 108}
109 109
110ParamProc::ParamProc() 110Bu::ParamProc::ParamProc()
111{ 111{
112} 112}
113 113
114ParamProc::~ParamProc() 114Bu::ParamProc::~ParamProc()
115{ 115{
116 for( std::list<ArgSpec *>::iterator i = lArg.begin(); 116 for( std::list<ArgSpec *>::iterator i = lArg.begin();
117 i != lArg.end(); i++ ) 117 i != lArg.end(); i++ )
@@ -127,14 +127,14 @@ ParamProc::~ParamProc()
127 127
128} 128}
129/* 129/*
130void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) 130void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val )
131{ 131{
132 printf("Calling callback...\n"); 132 printf("Calling callback...\n");
133 val = "Hello there, this is set in the ParamProc"; 133 val = "Hello there, this is set in the ParamProc";
134 (this->*proc)(); 134 (this->*proc)();
135}*/ 135}*/
136 136
137void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, 137void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc,
138 ParamPtr val, const char *lpDesc, const char *lpExtra, 138 ParamPtr val, const char *lpDesc, const char *lpExtra,
139 const char *lpValue ) 139 const char *lpValue )
140{ 140{
@@ -161,63 +161,63 @@ void ParamProc::addParam( const char *lpWord, char cChar, Proc proc,
161 } 161 }
162} 162}
163 163
164void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, 164void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc,
165 const char *lpDesc, const char *lpExtra, 165 const char *lpDesc, const char *lpExtra,
166 const char *lpValue ) 166 const char *lpValue )
167{ 167{
168 addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); 168 addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue );
169} 169}
170 170
171void ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, 171void Bu::ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val,
172 const char *lpDesc, const char *lpExtra, 172 const char *lpDesc, const char *lpExtra,
173 const char *lpValue ) 173 const char *lpValue )
174{ 174{
175 addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); 175 addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue );
176} 176}
177 177
178void ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, 178void Bu::ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val,
179 const char *lpDesc, const char *lpExtra, 179 const char *lpDesc, const char *lpExtra,
180 const char *lpValue ) 180 const char *lpValue )
181{ 181{
182 addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); 182 addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue );
183} 183}
184 184
185void ParamProc::addParam( const char *lpWord, Proc proc, 185void Bu::ParamProc::addParam( const char *lpWord, Proc proc,
186 const char *lpDesc, const char *lpExtra, 186 const char *lpDesc, const char *lpExtra,
187 const char *lpValue ) 187 const char *lpValue )
188{ 188{
189 addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); 189 addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue );
190} 190}
191 191
192void ParamProc::addParam( const char *lpWord, ParamPtr val, 192void Bu::ParamProc::addParam( const char *lpWord, ParamPtr val,
193 const char *lpDesc, const char *lpExtra, 193 const char *lpDesc, const char *lpExtra,
194 const char *lpValue ) 194 const char *lpValue )
195{ 195{
196 addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); 196 addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue );
197} 197}
198 198
199void ParamProc::addParam( char cChar, Proc proc, ParamPtr val, 199void Bu::ParamProc::addParam( char cChar, Proc proc, ParamPtr val,
200 const char *lpDesc, const char *lpExtra, 200 const char *lpDesc, const char *lpExtra,
201 const char *lpValue ) 201 const char *lpValue )
202{ 202{
203 addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); 203 addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue );
204} 204}
205 205
206void ParamProc::addParam( char cChar, Proc proc, 206void Bu::ParamProc::addParam( char cChar, Proc proc,
207 const char *lpDesc, const char *lpExtra, 207 const char *lpDesc, const char *lpExtra,
208 const char *lpValue ) 208 const char *lpValue )
209{ 209{
210 addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); 210 addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue );
211} 211}
212 212
213void ParamProc::addParam( char cChar, ParamPtr val, 213void Bu::ParamProc::addParam( char cChar, ParamPtr val,
214 const char *lpDesc, const char *lpExtra, 214 const char *lpDesc, const char *lpExtra,
215 const char *lpValue ) 215 const char *lpValue )
216{ 216{
217 addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); 217 addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue );
218} 218}
219 219
220void ParamProc::process( int argc, char *argv[] ) 220void Bu::ParamProc::process( int argc, char *argv[] )
221{ 221{
222 for( int arg = 1; arg < argc; arg++ ) 222 for( int arg = 1; arg < argc; arg++ )
223 { 223 {
@@ -229,23 +229,23 @@ void ParamProc::process( int argc, char *argv[] )
229 ArgSpec *s = checkWord( argv[arg]+2 ); 229 ArgSpec *s = checkWord( argv[arg]+2 );
230 if( s ) 230 if( s )
231 { 231 {
232 if( argv[arg][s->sWord.getLength()+2] == '=' ) 232 if( argv[arg][s->sWord.getSize()+2] == '=' )
233 { 233 {
234 if( s->val.isSet() ) 234 if( s->val.isSet() )
235 { 235 {
236 if( s->sValue.getString() == NULL ) 236 if( s->sValue.getStr() == NULL )
237 { 237 {
238 s->val = argv[arg]+s->sWord.getLength()+3; 238 s->val = argv[arg]+s->sWord.getSize()+3;
239 } 239 }
240 else 240 else
241 { 241 {
242 s->val = s->sValue.getString(); 242 s->val = s->sValue.getStr();
243 } 243 }
244 } 244 }
245 if( s->proc ) 245 if( s->proc )
246 { 246 {
247 char **tmp = new char*[argc-arg]; 247 char **tmp = new char*[argc-arg];
248 tmp[0] = argv[arg]+s->sWord.getLength()+3; 248 tmp[0] = argv[arg]+s->sWord.getSize()+3;
249 for( int k = 1; k < argc-arg; k++ ) 249 for( int k = 1; k < argc-arg; k++ )
250 tmp[k] = argv[arg+k]; 250 tmp[k] = argv[arg+k];
251 int ret = (this->*s->proc)( argc-arg, tmp ); 251 int ret = (this->*s->proc)( argc-arg, tmp );
@@ -261,7 +261,7 @@ void ParamProc::process( int argc, char *argv[] )
261 int add = 0; 261 int add = 0;
262 if( s->val.isSet() ) 262 if( s->val.isSet() )
263 { 263 {
264 if( s->sValue.getString() == NULL ) 264 if( s->sValue.getStr() == NULL )
265 { 265 {
266 if( arg+1 >= argc ) 266 if( arg+1 >= argc )
267 { 267 {
@@ -272,7 +272,7 @@ void ParamProc::process( int argc, char *argv[] )
272 } 272 }
273 else 273 else
274 { 274 {
275 s->val = s->sValue.getString(); 275 s->val = s->sValue.getStr();
276 } 276 }
277 } 277 }
278 if( s->proc ) 278 if( s->proc )
@@ -307,14 +307,14 @@ void ParamProc::process( int argc, char *argv[] )
307 bool bUsed = false; 307 bool bUsed = false;
308 if( s->val.isSet() ) 308 if( s->val.isSet() )
309 { 309 {
310 if( s->sValue.getString() == NULL ) 310 if( s->sValue.getStr() == NULL )
311 { 311 {
312 s->val = argv[arg]+chr+1; 312 s->val = argv[arg]+chr+1;
313 bUsed = true; 313 bUsed = true;
314 } 314 }
315 else 315 else
316 { 316 {
317 s->val = s->sValue.getString(); 317 s->val = s->sValue.getStr();
318 } 318 }
319 } 319 }
320 if( s->proc ) 320 if( s->proc )
@@ -342,14 +342,14 @@ void ParamProc::process( int argc, char *argv[] )
342 bool bUsed = false; 342 bool bUsed = false;
343 if( s->val.isSet() ) 343 if( s->val.isSet() )
344 { 344 {
345 if( s->sValue.getString() == NULL ) 345 if( s->sValue.getStr() == NULL )
346 { 346 {
347 s->val = argv[arg+1]; 347 s->val = argv[arg+1];
348 bUsed = true; 348 bUsed = true;
349 } 349 }
350 else 350 else
351 { 351 {
352 s->val = s->sValue.getString(); 352 s->val = s->sValue.getStr();
353 } 353 }
354 } 354 }
355 if( s->proc ) 355 if( s->proc )
@@ -384,22 +384,22 @@ void ParamProc::process( int argc, char *argv[] )
384 } 384 }
385} 385}
386 386
387ParamProc::ArgSpec *ParamProc::checkWord( const char *arg ) 387Bu::ParamProc::ArgSpec *Bu::ParamProc::checkWord( const char *arg )
388{ 388{
389 //printf("Checking \"%s\"...\n", arg ); 389 //printf("Checking \"%s\"...\n", arg );
390 std::list<ArgSpec *>::const_iterator i; 390 std::list<ArgSpec *>::const_iterator i;
391 for( i = lArg.begin(); i != lArg.end(); i++ ) 391 for( i = lArg.begin(); i != lArg.end(); i++ )
392 { 392 {
393 if( (*i)->sWord.getString() == NULL ) 393 if( (*i)->sWord.getStr() == NULL )
394 continue; 394 continue;
395 395
396 if( !strcmp( (*i)->sWord, arg ) ) 396 if( !strcmp( (*i)->sWord.getStr(), arg ) )
397 return *i; 397 return *i;
398 398
399 if( (*i)->val.isSet() ) 399 if( (*i)->val.isSet() )
400 { 400 {
401 if( !strncmp( (*i)->sWord, arg, (*i)->sWord.getLength() ) && 401 if( !strncmp( (*i)->sWord.getStr(), arg, (*i)->sWord.getSize() ) &&
402 arg[(*i)->sWord.getLength()] == '=' ) 402 arg[(*i)->sWord.getSize()] == '=' )
403 { 403 {
404 return *i; 404 return *i;
405 } 405 }
@@ -409,7 +409,7 @@ ParamProc::ArgSpec *ParamProc::checkWord( const char *arg )
409 return NULL; 409 return NULL;
410} 410}
411 411
412ParamProc::ArgSpec *ParamProc::checkLetr( const char arg ) 412Bu::ParamProc::ArgSpec *Bu::ParamProc::checkLetr( const char arg )
413{ 413{
414 //printf("Checking \'%c\'...\n", arg ); 414 //printf("Checking \'%c\'...\n", arg );
415 std::list<ArgSpec *>::const_iterator i; 415 std::list<ArgSpec *>::const_iterator i;
@@ -427,27 +427,27 @@ ParamProc::ArgSpec *ParamProc::checkLetr( const char arg )
427 return NULL; 427 return NULL;
428} 428}
429 429
430int ParamProc::cmdParam( int argc, char *argv[] ) 430int Bu::ParamProc::cmdParam( int argc, char *argv[] )
431{ 431{
432 printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); 432 printf("Unhandled command parameter \"%s\" found!\n", argv[0] );
433 return 0; 433 return 0;
434} 434}
435 435
436int ParamProc::unknownParam( int argc, char *argv[] ) 436int Bu::ParamProc::unknownParam( int argc, char *argv[] )
437{ 437{
438 printf("Unknown parameter \"%s\" found!\n", argv[0] ); 438 printf("Unknown parameter \"%s\" found!\n", argv[0] );
439 return 0; 439 return 0;
440} 440}
441 441
442int ParamProc::help( int argc, char *argv[] ) 442int Bu::ParamProc::help( int argc, char *argv[] )
443{ 443{
444 std::list<Banner *>::const_iterator b = lBan.begin(); 444 std::list<Banner *>::const_iterator b = lBan.begin();
445 std::list<ArgSpec *>::const_iterator i; 445 std::list<ArgSpec *>::const_iterator i;
446 int len=0; 446 int len=0;
447 for( i = lArg.begin(); i != lArg.end(); i++ ) 447 for( i = lArg.begin(); i != lArg.end(); i++ )
448 { 448 {
449 if( len < (*i)->sWord.getLength() + (*i)->sExtra.getLength() ) 449 if( len < (*i)->sWord.getSize() + (*i)->sExtra.getSize() )
450 len = (*i)->sWord.getLength() + (*i)->sExtra.getLength(); 450 len = (*i)->sWord.getSize() + (*i)->sExtra.getSize();
451 } 451 }
452 char fmt[10]; 452 char fmt[10];
453 sprintf( fmt, "%%-%ds ", len ); 453 sprintf( fmt, "%%-%ds ", len );
@@ -458,14 +458,14 @@ int ParamProc::help( int argc, char *argv[] )
458 { 458 {
459 if( (*b)->pBefore == (*i) ) 459 if( (*b)->pBefore == (*i) )
460 { 460 {
461 printf( (*b)->sBanner.getString() ); 461 printf( (*b)->sBanner.getStr() );
462 b++; 462 b++;
463 } 463 }
464 } 464 }
465 printf(" "); 465 printf(" ");
466 if( (*i)->cChar ) 466 if( (*i)->cChar )
467 { 467 {
468 if( (*i)->sWord.getString() ) 468 if( (*i)->sWord.getStr() )
469 { 469 {
470 printf("-%c, ", (*i)->cChar ); 470 printf("-%c, ", (*i)->cChar );
471 } 471 }
@@ -478,12 +478,12 @@ int ParamProc::help( int argc, char *argv[] )
478 { 478 {
479 printf(" "); 479 printf(" ");
480 } 480 }
481 if( (*i)->sWord.getString() ) 481 if( (*i)->sWord.getStr() )
482 { 482 {
483 printf("--"); 483 printf("--");
484 std::string sTmp = (*i)->sWord.getString(); 484 std::string sTmp = (*i)->sWord.getStr();
485 if( (*i)->sExtra.getString() ) 485 if( (*i)->sExtra.getStr() )
486 sTmp += (*i)->sExtra.getString(); 486 sTmp += (*i)->sExtra.getStr();
487 printf( fmt, sTmp.c_str() ); 487 printf( fmt, sTmp.c_str() );
488 } 488 }
489 else 489 else
@@ -491,20 +491,20 @@ int ParamProc::help( int argc, char *argv[] )
491 printf(" "); 491 printf(" ");
492 printf(fmt, "" ); 492 printf(fmt, "" );
493 } 493 }
494 printf("%s\n", (*i)->sDesc.getString() ); 494 printf("%s\n", (*i)->sDesc.getStr() );
495 } 495 }
496 if( b != lBan.end() ) 496 if( b != lBan.end() )
497 { 497 {
498 if( (*b)->pBefore == NULL ) 498 if( (*b)->pBefore == NULL )
499 { 499 {
500 printf( (*b)->sBanner.getString() ); 500 printf( (*b)->sBanner.getStr() );
501 } 501 }
502 } 502 }
503 503
504 exit( 0 ); 504 exit( 0 );
505} 505}
506 506
507void ParamProc::addHelpBanner( const char *sHelpBanner ) 507void Bu::ParamProc::addHelpBanner( const char *sHelpBanner )
508{ 508{
509 Banner *pBan = new Banner; 509 Banner *pBan = new Banner;
510 pBan->sBanner = sHelpBanner; 510 pBan->sBanner = sHelpBanner;
diff --git a/src/paramproc.h b/src/paramproc.h
index d857193..2bca588 100644
--- a/src/paramproc.h
+++ b/src/paramproc.h
@@ -1,153 +1,156 @@
1#ifndef PARAM_PROC_H 1#ifndef BU_PARAM_PROC_H
2#define PARAM_PROC_H 2#define BU_PARAM_PROC_H
3 3
4#include <stdint.h> 4#include <stdint.h>
5#include <string> 5#include <string>
6#include <list> 6#include <list>
7#include "staticstring.h" 7#include "bu/fstring.h"
8 8
9class ParamProc 9namespace Bu
10{ 10{
11public: 11 class ParamProc
12 class ParamPtr
13 { 12 {
14 public: 13 public:
15 ParamPtr(); 14 class ParamPtr
16 ParamPtr( std::string *str );
17 ParamPtr( uint64_t *uint64 );
18 ParamPtr( uint32_t *uint32 );
19 ParamPtr( uint16_t *uint16 );
20 ParamPtr( uint8_t *uint8 );
21 ParamPtr( int64_t *int64 );
22 ParamPtr( int32_t *int32 );
23 ParamPtr( int16_t *int16 );
24 ParamPtr( int8_t *int8 );
25 ParamPtr( float *float32 );
26 ParamPtr( double *float64 );
27 ParamPtr( long double *float96 );
28 ParamPtr( bool *bln );
29
30 enum
31 { 15 {
32 vtunset, 16 public:
33 vtstr, 17 ParamPtr();
34 vtuint64, 18 ParamPtr( std::string *str );
35 vtuint32, 19 ParamPtr( uint64_t *uint64 );
36 vtuint16, 20 ParamPtr( uint32_t *uint32 );
37 vtuint8, 21 ParamPtr( uint16_t *uint16 );
38 vtint64, 22 ParamPtr( uint8_t *uint8 );
39 vtint32, 23 ParamPtr( int64_t *int64 );
40 vtint16, 24 ParamPtr( int32_t *int32 );
41 vtint8, 25 ParamPtr( int16_t *int16 );
42 vtfloat32, 26 ParamPtr( int8_t *int8 );
43 vtfloat64, 27 ParamPtr( float *float32 );
44 vtfloat96, 28 ParamPtr( double *float64 );
45 vtbln, 29 ParamPtr( long double *float96 );
46 }; 30 ParamPtr( bool *bln );
47 ParamPtr &operator=( ParamPtr &ptr );
48 ParamPtr &operator=( const char *str );
49 31
50 bool isSet(); 32 enum
33 {
34 vtunset,
35 vtstr,
36 vtuint64,
37 vtuint32,
38 vtuint16,
39 vtuint8,
40 vtint64,
41 vtint32,
42 vtint16,
43 vtint8,
44 vtfloat32,
45 vtfloat64,
46 vtfloat96,
47 vtbln,
48 };
49 ParamPtr &operator=( ParamPtr &ptr );
50 ParamPtr &operator=( const char *str );
51 51
52 private: 52 bool isSet();
53 int type; 53
54 union 54 private:
55 { 55 int type;
56 std::string *str; 56 union
57 uint64_t *uint64; 57 {
58 uint32_t *uint32; 58 std::string *str;
59 uint16_t *uint16; 59 uint64_t *uint64;
60 uint8_t *uint8; 60 uint32_t *uint32;
61 int64_t *int64; 61 uint16_t *uint16;
62 int32_t *int32; 62 uint8_t *uint8;
63 int16_t *int16; 63 int64_t *int64;
64 int8_t *int8; 64 int32_t *int32;
65 float *float32; 65 int16_t *int16;
66 double *float64; 66 int8_t *int8;
67 long double *float96; 67 float *float32;
68 bool *bln; 68 double *float64;
69 } val; 69 long double *float96;
70 }; 70 bool *bln;
71 } val;
72 };
71 73
72 typedef int (ParamProc::*Proc)( int, char *[] ); 74 typedef int (ParamProc::*Proc)( int, char *[] );
73 75
74 typedef struct ArgSpec 76 typedef struct ArgSpec
75 { 77 {
76 uint8_t nFlags; 78 uint8_t nFlags;
77 StaticString sWord; 79 Bu::FString sWord;
78 char cChar; 80 char cChar;
79 Proc proc; 81 Proc proc;
80 ParamProc::ParamPtr val; 82 ParamProc::ParamPtr val;
81 StaticString sExtra; 83 Bu::FString sExtra;
82 StaticString sDesc; 84 Bu::FString sDesc;
83 StaticString sValue; 85 Bu::FString sValue;
84 } ArgSpec; 86 } ArgSpec;
85 87
86public: 88 public:
87 ParamProc(); 89 ParamProc();
88 virtual ~ParamProc(); 90 virtual ~ParamProc();
89 91
90 void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, 92 void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val,
91 const char *lpDesc=NULL, const char *lpExtra=NULL, 93 const char *lpDesc=NULL, const char *lpExtra=NULL,
92 const char *lpValue=NULL 94 const char *lpValue=NULL
93 ); 95 );
94 void addParam( const char *lpWord, char cChar, Proc proc, 96 void addParam( const char *lpWord, char cChar, Proc proc,
95 const char *lpDesc=NULL, const char *lpExtra=NULL, 97 const char *lpDesc=NULL, const char *lpExtra=NULL,
96 const char *lpValue=NULL 98 const char *lpValue=NULL
97 ); 99 );
98 void addParam( const char *lpWord, char cChar, ParamPtr val, 100 void addParam( const char *lpWord, char cChar, ParamPtr val,
99 const char *lpDesc=NULL, const char *lpExtra=NULL, 101 const char *lpDesc=NULL, const char *lpExtra=NULL,
100 const char *lpValue=NULL 102 const char *lpValue=NULL
101 ); 103 );
102 104
103 void addParam( const char *lpWord, Proc proc, ParamPtr val, 105 void addParam( const char *lpWord, Proc proc, ParamPtr val,
104 const char *lpDesc=NULL, const char *lpExtra=NULL, 106 const char *lpDesc=NULL, const char *lpExtra=NULL,
105 const char *lpValue=NULL 107 const char *lpValue=NULL
106 ); 108 );
107 void addParam( const char *lpWord, Proc proc, 109 void addParam( const char *lpWord, Proc proc,
108 const char *lpDesc=NULL, const char *lpExtra=NULL, 110 const char *lpDesc=NULL, const char *lpExtra=NULL,
109 const char *lpValue=NULL 111 const char *lpValue=NULL
110 ); 112 );
111 void addParam( const char *lpWord, ParamPtr val, 113 void addParam( const char *lpWord, ParamPtr val,
112 const char *lpDesc=NULL, const char *lpExtra=NULL, 114 const char *lpDesc=NULL, const char *lpExtra=NULL,
113 const char *lpValue=NULL 115 const char *lpValue=NULL
114 ); 116 );
115 117
116 void addParam( char cChar, Proc proc, ParamPtr val, 118 void addParam( char cChar, Proc proc, ParamPtr val,
117 const char *lpDesc=NULL, const char *lpExtra=NULL, 119 const char *lpDesc=NULL, const char *lpExtra=NULL,
118 const char *lpValue=NULL 120 const char *lpValue=NULL
119 ); 121 );
120 void addParam( char cChar, Proc proc, 122 void addParam( char cChar, Proc proc,
121 const char *lpDesc=NULL, const char *lpExtra=NULL, 123 const char *lpDesc=NULL, const char *lpExtra=NULL,
122 const char *lpValue=NULL 124 const char *lpValue=NULL
123 ); 125 );
124 void addParam( char cChar, ParamPtr val, 126 void addParam( char cChar, ParamPtr val,
125 const char *lpDesc=NULL, const char *lpExtra=NULL, 127 const char *lpDesc=NULL, const char *lpExtra=NULL,
126 const char *lpValue=NULL 128 const char *lpValue=NULL
127 ); 129 );
128 130
129 void process( int argc, char *argv[] ); 131 void process( int argc, char *argv[] );
130 void addHelpBanner( const char *sHelpBanner ); 132 void addHelpBanner( const char *sHelpBanner );
131 133
132private: 134 private:
133 ArgSpec *checkWord( const char *arg ); 135 ArgSpec *checkWord( const char *arg );
134 ArgSpec *checkLetr( const char arg ); 136 ArgSpec *checkLetr( const char arg );
135 137
136public: 138 public:
137 virtual int cmdParam( int argc, char *argv[] ); 139 virtual int cmdParam( int argc, char *argv[] );
138 virtual int unknownParam( int argc, char *argv[] ); 140 virtual int unknownParam( int argc, char *argv[] );
139 virtual int help( int argc, char *argv[] ); 141 virtual int help( int argc, char *argv[] );
140 142
141private: 143 private:
142 typedef struct Banner 144 typedef struct Banner
143 { 145 {
144 StaticString sBanner; 146 Bu::FString sBanner;
145 ArgSpec *pBefore; 147 ArgSpec *pBefore;
146 } Banner; 148 } Banner;
147 std::list<Banner *> lBan; 149 std::list<Banner *> lBan;
148 std::list<ArgSpec *> lArg; 150 std::list<ArgSpec *> lArg;
149}; 151 };
152}
150 153
151#define mkproc( cls ) static_cast<int (ParamProc::*)( int, char *[])>(&cls) 154#define mkproc( cls ) static_cast<int (Bu::ParamProc::*)( int, char *[])>(&cls)
152 155
153#endif 156#endif
diff --git a/src/plugger.h b/src/plugger.h
index d92f194..2124b7a 100644
--- a/src/plugger.h
+++ b/src/plugger.h
@@ -1,198 +1,198 @@
1#ifndef PLUGGER_H 1#ifndef BU_PLUGGER_H
2#define PLUGGER_H 2#define BU_PLUGGER_H
3 3
4 4
5#include "hashtable.h" 5#include "bu/hash.h"
6#include "list" 6#include "bu/list.h"
7#include "hashfunctionstring.h" 7#include <dlfcn.h>
8#include "hashfunctionint.h" 8#include "bu/exceptions.h"
9#include "dlfcn.h" 9#include "bu/fstring.h"
10#include "exceptions.h"
11 10
12typedef struct PluginInfo 11namespace Bu
13{ 12{
14 const char *sID; 13 typedef struct PluginInfo
15 const char *sAuthor; 14 {
16 unsigned short nVersion; 15 const char *sID;
17 unsigned short nRevision; 16 const char *sAuthor;
18 void *(*createPlugin)(); 17 unsigned short nVersion;
19 void (*destroyPlugin)( void * ); 18 unsigned short nRevision;
20} PluginInfo; 19 void *(*createPlugin)();
21 20 void (*destroyPlugin)( void * );
22typedef struct PluginReg 21 } PluginInfo;
23{ 22
24 bool bBuiltin; 23 typedef struct PluginReg
25 void *dlHandle; 24 {
26 PluginInfo *pInfo; 25 bool bBuiltin;
27} PluginReg; 26 void *dlHandle;
27 PluginInfo *pInfo;
28 } PluginReg;
28 29
29#define PluginInterface( classname, baseclass, name, ver, rev ) \ 30#define PluginInterface( classname, baseclass, name, ver, rev ) \
30extern "C" { \ 31 extern "C" { \
31 baseclass *create ##classname() \ 32 baseclass *create ##classname() \
32 { \ 33 { \
33 return new classname(); \ 34 return new classname(); \
34 } \ 35 } \
35 void destroy ##classname( baseclass *pCls ) \ 36 void destroy ##classname( baseclass *pCls ) \
36 { \ 37 { \
37 delete pCls; \ 38 delete pCls; \
38 } \ 39 } \
39 PluginInfo classname = { \ 40 Bu::PluginInfo classname = { \
40 #classname, name, ver, rev, \ 41 #classname, name, ver, rev, \
41 create ##classname, destroy ##classname }; \ 42 create ##classname, destroy ##classname }; \
42} 43 }
43 44
44#define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \ 45#define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \
45extern "C" { \ 46 extern "C" { \
46 baseclass *create ##classname() \ 47 baseclass *create ##classname() \
47 { \ 48 { \
48 return new classname(); \ 49 return new classname(); \
49 } \ 50 } \
50 void destroy ##classname( baseclass *pCls ) \ 51 void destroy ##classname( baseclass *pCls ) \
51 { \ 52 { \
52 delete pCls; \ 53 delete pCls; \
53 } \ 54 } \
54 PluginInfo pluginname = { \ 55 Bu::PluginInfo pluginname = { \
55 #pluginname, name, ver, rev, \ 56 #pluginname, name, ver, rev, \
56 (void *(*)())(create ##classname), \ 57 (void *(*)())(create ##classname), \
57 (void (*)( void * ))(destroy ##classname) }; \ 58 (void (*)( void * ))(destroy ##classname) }; \
58} 59 }
59 60
60#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \ 61#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \
61extern "C" { \ 62 extern "C" { \
62 baseclass *create ##classname() \ 63 baseclass *create ##classname() \
63 { \ 64 { \
64 return new classname(); \ 65 return new classname(); \
65 } \ 66 } \
66 void destroy ##classname( baseclass *pCls ) \ 67 void destroy ##classname( baseclass *pCls ) \
67 { \ 68 { \
68 delete pCls; \ 69 delete pCls; \
69 } \ 70 } \
70 PluginInfo structname = { \ 71 Bu::PluginInfo structname = { \
71 #pluginname, name, ver, rev, \ 72 #pluginname, name, ver, rev, \
72 (void *(*)())(create ##classname), \ 73 (void *(*)())(create ##classname), \
73 (void (*)( void * ))(destroy ##classname) }; \ 74 (void (*)( void * ))(destroy ##classname) }; \
74}
75
76template<class T>
77class Plugger
78{
79public:
80
81public:
82 Plugger() :
83 hPlugin( new HashFunctionString(), 11 ),
84 hObj( new HashFunctionInt(), 11 )
85 {
86 } 75 }
87 76
88 virtual ~Plugger() 77 template<class T>
78 class Plugger
89 { 79 {
90 void *pos = hObj.getFirstItemPos(); 80 public:
91 while( (pos = hObj.getNextItemPos( pos )) ) 81 typedef Bu::Hash<Bu::FString, PluginReg *> PluginHash;
82 typedef Bu::Hash<int, void *> InstHash;
83
84 public:
85 Plugger()
92 { 86 {
93 T *pPlug = (T *)hObj.getItemID( pos );
94 PluginReg *pReg = (PluginReg *)hObj.getItemData( pos );
95 pReg->pInfo->destroyPlugin( pPlug );
96 } 87 }
97 88
98 std::list<PluginReg *>::iterator i; 89 virtual ~Plugger()
99 for( i = lPlugin.begin(); i != lPlugin.end(); i++ )
100 { 90 {
101 if( (*i)->bBuiltin == false ) 91 for( InstHash::iterator i = hObj.begin(); i != hObj.end(); i++ )
102 { 92 {
103 dlclose( (*i)->dlHandle ); 93 T *pPlug = (T *)i.getKey();
94 PluginReg *pReg = (PluginReg *)*i;
95 pReg->pInfo->destroyPlugin( pPlug );
104 } 96 }
105 delete (*i);
106 }
107 }
108 97
109 void registerBuiltinPlugin( PluginInfo *pInfo ) 98 for( PluginHash::iterator i = hPlugin.begin();
110 { 99 i != hPlugin.end(); i++ )
111 PluginReg *pReg = new PluginReg; 100 {
112 pReg->bBuiltin = true; 101 if( (*i)->bBuiltin == false )
113 pReg->pInfo = pInfo; 102 {
114 lPlugin.insert( lPlugin.end(), pReg ); 103 dlclose( (*i)->dlHandle );
115 hPlugin.insert( pInfo->sID, pReg ); 104 }
116 } 105 delete (*i);
106 }
107 }
117 108
118 void registerExternalPlugin( const char *sFName, const char *sPluginName ) 109 void registerBuiltinPlugin( PluginInfo *pInfo )
119 {
120 PluginReg *pReg = (PluginReg *)hPlugin[sPluginName];
121 if( pReg != NULL )
122 { 110 {
123 hPlugin.del( sPluginName ); 111 PluginReg *pReg = new PluginReg;
124 dlclose( pReg->dlHandle ); 112 pReg->bBuiltin = true;
125 delete pReg; 113 pReg->pInfo = pInfo;
126 pReg = NULL; 114 hPlugin.insert( pInfo->sID, pReg );
127 } 115 }
128 116
129 pReg = new PluginReg; 117 void registerExternalPlugin( const char *sFName, const char *sPluginName )
130
131 pReg->bBuiltin = false;
132 pReg->dlHandle = dlopen( sFName, RTLD_NOW );
133 if( pReg->dlHandle == NULL )
134 { 118 {
135 throw PluginException( 1, "Error on %s: %s", sFName, dlerror() ); 119 PluginReg *pReg;
120 try {
121 pReg = (PluginReg *)hPlugin[sPluginName];
122 hPlugin.erase( sPluginName );
123 dlclose( pReg->dlHandle );
124 delete pReg;
125 pReg = NULL;
126 } catch( Bu::HashException &e )
127 {
128 }
129
130 pReg = new PluginReg;
131
132 pReg->bBuiltin = false;
133 pReg->dlHandle = dlopen( sFName, RTLD_NOW );
134 if( pReg->dlHandle == NULL )
135 {
136 throw PluginException( 1, "Error on %s: %s", sFName, dlerror() );
137 }
138 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, sPluginName );
139 if( pReg->pInfo == NULL )
140 {
141 throw PluginException( 2, "Error on %s: %s", sFName, dlerror() );
142 }
143 hPlugin.insert( pReg->pInfo->sID, pReg );
136 } 144 }
137 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, sPluginName ); 145
138 if( pReg->pInfo == NULL ) 146 T *instantiate( const char *lpName )
139 { 147 {
140 throw PluginException( 2, "Error on %s: %s", sFName, dlerror() ); 148 PluginReg *pReg = (PluginReg *)hPlugin[lpName];
149 if( pReg == NULL )
150 return NULL;
151
152 T *p = (T *)pReg->pInfo->createPlugin();
153 hObj.insert( (int )p, pReg );
154 //printf("pReg: %08X, pPlug: %08X\n", pReg, p );
155
156 return p;
141 } 157 }
142 hPlugin.insert( pReg->pInfo->sID, pReg );
143 lPlugin.insert( lPlugin.end(), pReg );
144 }
145
146 T *instantiate( const char *lpName )
147 {
148 PluginReg *pReg = (PluginReg *)hPlugin[lpName];
149 if( pReg == NULL )
150 return NULL;
151
152 T *p = (T *)pReg->pInfo->createPlugin();
153 hObj.insert( p, pReg );
154 //printf("pReg: %08X, pPlug: %08X\n", pReg, p );
155
156 return p;
157 }
158 158
159 bool hasPlugin( const char *lpName ) 159 bool hasPlugin( const char *lpName )
160 { 160 {
161 if( hPlugin[lpName] == NULL ) 161 if( hPlugin[lpName] == NULL )
162 return false; 162 return false;
163 return true; 163 return true;
164 } 164 }
165 165
166 void destroy( T *pPlug ) 166 void destroy( T *pPlug )
167 { 167 {
168 PluginReg *pReg = (PluginReg *)hObj[pPlug]; 168 PluginReg *pReg = (PluginReg *)hObj.get((int)pPlug);
169 //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug ); 169 //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug );
170 if( pReg == NULL ) 170 if( pReg == NULL )
171 return; 171 return;
172 172
173 pReg->pInfo->destroyPlugin( pPlug ); 173 pReg->pInfo->destroyPlugin( pPlug );
174 174
175 hObj.del( pPlug ); 175 hObj.erase( (int)pPlug );
176 } 176 }
177 177
178 void unloadAll() 178 void unloadAll()
179 {
180 std::list<PluginReg *>::iterator i;
181 for( i = lPlugin.begin(); i != lPlugin.end(); i++ )
182 { 179 {
183 if( (*i)->bBuiltin == false ) 180 for( PluginHash::iterator i = hPlugin.begin();
181 i != hPlugin.end(); i++ )
184 { 182 {
185 dlclose( (*i)->dlHandle ); 183 if( (*i)->bBuiltin == false )
184 {
185 dlclose( (*i)->dlHandle );
186 }
187 delete (*i);
186 } 188 }
187 delete (*i); 189 hPlugin.clear();
188 } 190 }
189 hPlugin.clear();
190 }
191 191
192private: 192 private:
193 std::list<PluginReg *> lPlugin; 193 PluginHash hPlugin;
194 HashTable hPlugin; 194 InstHash hObj;
195 HashTable hObj; 195 };
196}; 196}
197 197
198#endif 198#endif
diff --git a/src/programchain.cpp b/src/programchain.cpp
index 6120d58..0bb7a77 100644
--- a/src/programchain.cpp
+++ b/src/programchain.cpp
@@ -1,17 +1,18 @@
1#include <stdlib.h> 1#include <stdlib.h>
2#include "programchain.h" 2#include "bu/programchain.h"
3#include "bu/programlink.h"
3 4
4ProgramChain::ProgramChain() : 5using namespace Bu;
5 xLog( MultiLog::getInstance() ) 6
7Bu::ProgramChain::ProgramChain()
6{ 8{
7 xLog.LineLog( MultiLog::LStatus, "Program Chain Initialized." );
8} 9}
9 10
10ProgramChain::~ProgramChain() 11Bu::ProgramChain::~ProgramChain()
11{ 12{
12} 13}
13 14
14bool ProgramChain::addLink( ProgramLink *pLink ) 15bool Bu::ProgramChain::addLink( ProgramLink *pLink )
15{ 16{
16 if( pLink->init() == false ) 17 if( pLink->init() == false )
17 { 18 {
@@ -26,26 +27,25 @@ bool ProgramChain::addLink( ProgramLink *pLink )
26 return true; 27 return true;
27} 28}
28 29
29ProgramLink *ProgramChain::getLink( const char *lpName ) 30ProgramLink *Bu::ProgramChain::getLink( const char *lpName )
30{ 31{
31 char a; 32 char a;
32 a = lpName[0]; 33 a = lpName[0];
33 return NULL; 34 return NULL;
34} 35}
35 36
36ProgramLink *ProgramChain::getBaseLink() 37ProgramLink *Bu::ProgramChain::getBaseLink()
37{ 38{
38 return NULL; 39 return NULL;
39} 40}
40 41
41bool ProgramChain::execChainOnce() 42bool Bu::ProgramChain::execChainOnce()
42{ 43{
43 int nLen = lLink.getSize(); 44 for( Bu::List<Bu::ProgramLink *>::iterator i = lLink.begin();
44 for( int j = 0; j < nLen; j++ ) 45 i != lLink.end(); i++ )
45 { 46 {
46 if( ((ProgramLink *)lLink[j])->timeSlice() == false ) 47 if( (*i)->timeSlice() == false )
47 { 48 {
48 xLog.LineLog( MultiLog::LInfo, "Shutting down due to signal from link #%d", j );
49 emergencyShutdown(); 49 emergencyShutdown();
50 return false; 50 return false;
51 } 51 }
@@ -54,7 +54,7 @@ bool ProgramChain::execChainOnce()
54 return true; 54 return true;
55} 55}
56 56
57bool ProgramChain::enterChainLoop() 57bool Bu::ProgramChain::enterChainLoop()
58{ 58{
59 for(;;) 59 for(;;)
60 { 60 {
@@ -67,23 +67,23 @@ bool ProgramChain::enterChainLoop()
67 return true; 67 return true;
68} 68}
69 69
70void ProgramChain::emergencyShutdown() 70void Bu::ProgramChain::emergencyShutdown()
71{ 71{
72 int nLen = lLink.getSize(); 72 for( Bu::List<Bu::ProgramLink *>::iterator i = lLink.begin();
73 for( int j = 0; j < nLen; j++ ) 73 i != lLink.end(); i++ )
74 { 74 {
75 ((ProgramLink *)lLink[j])->deInit(); 75 (*i)->deInit();
76 delete (ProgramLink *)lLink[j]; 76 delete *i;
77 } 77 }
78 lLink.empty(); 78 lLink.clear();
79} 79}
80 80
81LinkMessage *ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ) 81LinkMessage *Bu::ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender )
82{ 82{
83 int nLen = lLink.getSize(); 83 for( Bu::List<Bu::ProgramLink *>::iterator i = lLink.begin();
84 for( int j = 0; j < nLen; j++ ) 84 i != lLink.end(); i++ )
85 { 85 {
86 LinkMessage *pMsg = ((ProgramLink *)lLink[j])->processIRM( pMsgOut ); 86 LinkMessage *pMsg = (*i)->processIRM( pMsgOut );
87 if( pMsg != NULL ) 87 if( pMsg != NULL )
88 { 88 {
89 delete pMsgOut; 89 delete pMsgOut;
@@ -94,3 +94,4 @@ LinkMessage *ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSen
94 delete pMsgOut; 94 delete pMsgOut;
95 return NULL; 95 return NULL;
96} 96}
97
diff --git a/src/programchain.h b/src/programchain.h
index 2bdfeee..336a9f1 100644
--- a/src/programchain.h
+++ b/src/programchain.h
@@ -1,95 +1,98 @@
1#ifndef PROGRAMCHAIN_H 1#ifndef BU_PROGRAMCHAIN_H
2#define PROGRAMCHAIN_H 2#define BU_PROGRAMCHAIN_H
3 3
4#include "linkedlist.h" 4#include "bu/list.h"
5#include "multilog.h" 5#include "bu/linkmessage.h"
6#include "programlink.h"
7 6
8/** 7namespace Bu
9 * The Program Chain links together program "chunks" to more easily facilitate
10 * a generalized program loop with modular extensions.
11 *@author Mike Buland
12 */
13class ProgramChain
14{ 8{
15public: 9 class ProgramLink;
16 /** 10 /**
17 * Construct an empty chain. 11 * The Program Chain links together program "chunks" to more easily facilitate
12 * a generalized program loop with modular extensions.
13 *@author Mike Buland
18 */ 14 */
19 ProgramChain(); 15 class ProgramChain
16 {
17 public:
18 /**
19 * Construct an empty chain.
20 */
21 ProgramChain();
20 22
21 /** 23 /**
22 * Destroy your chain. 24 * Destroy your chain.
23 */ 25 */
24 virtual ~ProgramChain(); 26 virtual ~ProgramChain();
25 27
26 /** 28 /**
27 * Adds a link to the end of the chain. 29 * Adds a link to the end of the chain.
28 *@param pLink A pointer to the link to add to the chain. 30 *@param pLink A pointer to the link to add to the chain.
29 *@returns True if adding the link was successful, otherwise false 31 *@returns True if adding the link was successful, otherwise false
30 *@author Mike Buland 32 *@author Mike Buland
31 */ 33 */
32 bool addLink( ProgramLink *pLink ); 34 bool addLink( Bu::ProgramLink *pLink );
33 35
34 /** 36 /**
35 * Gets a link by name. 37 * Gets a link by name.
36 *@param lpName The name of the link you're looking for. Every link has a 38 *@param lpName The name of the link you're looking for. Every link has a
37 * name, apparently. 39 * name, apparently.
38 *@returns A pointer to the specified ProgramLink, or NULL if none were 40 *@returns A pointer to the specified ProgramLink, or NULL if none were
39 * found matching your criteria. 41 * found matching your criteria.
40 *@author Mike Buland 42 *@author Mike Buland
41 */ 43 */
42 class ProgramLink *getLink( const char *lpName ); 44 class ProgramLink *getLink( const char *lpName );
43 45
44 /** 46 /**
45 * Gets the very first link in the chain. 47 * Gets the very first link in the chain.
46 *@returns A pointer to the first link in the chain. 48 *@returns A pointer to the first link in the chain.
47 *@author Mike Buland 49 *@author Mike Buland
48 */ 50 */
49 class ProgramLink *getBaseLink(); 51 class ProgramLink *getBaseLink();
50 52
51 /** 53 /**
52 * Runs through the chain once. Useful if you want to have more control 54 * Runs through the chain once. Useful if you want to have more control
53 * over the operation of the chain. 55 * over the operation of the chain.
54 *@returns true if every link returned true. If at least one link returns 56 *@returns true if every link returned true. If at least one link returns
55 * false, then returns false. 57 * false, then returns false.
56 *@author Mike Buland 58 *@author Mike Buland
57 */ 59 */
58 bool execChainOnce(); 60 bool execChainOnce();
59 61
60 /** 62 /**
61 * Enters the master chain loop, looping over the entire chain and 63 * Enters the master chain loop, looping over the entire chain and
62 * executing every link's TimeSlice routine in order, over and over, until 64 * executing every link's TimeSlice routine in order, over and over, until
63 * a link returns a false value. 65 * a link returns a false value.
64 *@returns False, always. It returns true unless a link returned false, 66 *@returns False, always. It returns true unless a link returned false,
65 * but loops until a link does return false. 67 * but loops until a link does return false.
66 *@author Mike Buland 68 *@author Mike Buland
67 **/ 69 **/
68 bool enterChainLoop(); 70 bool enterChainLoop();
69 71
70 /** 72 /**
71 * Broadcasts an Immediate Response Message to all active links, save the 73 * Broadcasts an Immediate Response Message to all active links, save the
72 * sender. Whatever link first responds with a non-null response message 74 * sender. Whatever link first responds with a non-null response message
73 * will have it's messages sent back to the broadcasting link as the returns 75 * will have it's messages sent back to the broadcasting link as the returns
74 * of this function call. Therefore it is very important that all message 76 * of this function call. Therefore it is very important that all message
75 * processing code is handled in a fairly timely fasion. 77 * processing code is handled in a fairly timely fasion.
76 *@param pMsgOut The message to broadcast in hopes of a response. 78 *@param pMsgOut The message to broadcast in hopes of a response.
77 *@param pSender The message that sent out the message and doesn't want to 79 *@param pSender The message that sent out the message and doesn't want to
78 * receive it's own message. This should always just be "this". 80 * receive it's own message. This should always just be "this".
79 *@returns The message that was returned by the first link to return a 81 *@returns The message that was returned by the first link to return a
80 * non-null response. If all messages return null responses then this also 82 * non-null response. If all messages return null responses then this also
81 * returns null. Please note that whoever calls this will be responsible 83 * returns null. Please note that whoever calls this will be responsible
82 * for deleting the message returned by it, if non-null. 84 * for deleting the message returned by it, if non-null.
83 */ 85 */
84 class LinkMessage *broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ); 86 class LinkMessage *broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender );
87
88 private:
89 /**
90 * Shuts down all operation no matter what point in the operation we were.
91 */
92 void emergencyShutdown();
93 Bu::List<Bu::ProgramLink *> lLink; /**< The linked list that contains all of the links. */
94 };
95}
85 96
86private:
87 /**
88 * Shuts down all operation no matter what point in the operation we were.
89 */
90 void emergencyShutdown();
91 MultiLog &xLog; /**< A reference to the log. */
92 LinkedList lLink; /**< The linked list that contains all of the links. */
93};
94 97
95#endif 98#endif
diff --git a/src/programlink.cpp b/src/programlink.cpp
index 21c6fe4..e5c624c 100644
--- a/src/programlink.cpp
+++ b/src/programlink.cpp
@@ -1,20 +1,22 @@
1#include "programlink.h" 1#include "bu/programlink.h"
2#include "programchain.h" 2#include "bu/programchain.h"
3 3
4ProgramLink::ProgramLink() 4using namespace Bu;
5
6Bu::ProgramLink::ProgramLink()
5{ 7{
6} 8}
7 9
8ProgramLink::~ProgramLink() 10Bu::ProgramLink::~ProgramLink()
9{ 11{
10} 12}
11 13
12LinkMessage *ProgramLink::sendIRM( LinkMessage *pMsgOut ) 14LinkMessage *Bu::ProgramLink::sendIRM( LinkMessage *pMsgOut )
13{ 15{
14 return pChain->broadcastIRM( pMsgOut, this ); 16 return pChain->broadcastIRM( pMsgOut, this );
15} 17}
16 18
17void ProgramLink::setChain( ProgramChain *pNewChain ) 19void Bu::ProgramLink::setChain( ProgramChain *pNewChain )
18{ 20{
19 pChain = pNewChain; 21 pChain = pNewChain;
20} 22}
diff --git a/src/programlink.h b/src/programlink.h
index f93edcc..07d7489 100644
--- a/src/programlink.h
+++ b/src/programlink.h
@@ -1,99 +1,100 @@
1#ifndef PROGRAMLINK_H 1#ifndef BU_PROGRAMLINK_H
2#define PROGRAMLINK_H 2#define BU_PROGRAMLINK_H
3 3
4class ProgramLink; 4#include "bu/linkmessage.h"
5#include "queue.h" 5#include "bu/programchain.h"
6#include "linkmessage.h"
7#include "programchain.h"
8 6
9/** 7namespace Bu
10 * Program Link is the base class for any object that will be a piece of the
11 * main program chain loop.
12 *@author Mike Buland
13 */
14class ProgramLink
15{ 8{
16friend class ProgramChain;
17public:
18 /** 9 /**
19 * Construct a program link. 10 * Program Link is the base class for any object that will be a piece of the
11 * main program chain loop.
12 *@author Mike Buland
20 */ 13 */
21 ProgramLink(); 14 class ProgramLink
15 {
16 friend class Bu::ProgramChain;
17 public:
18 /**
19 * Construct a program link.
20 */
21 ProgramLink();
22 22
23 /** 23 /**
24 * Deconstruct. 24 * Deconstruct.
25 */ 25 */
26 virtual ~ProgramLink(); 26 virtual ~ProgramLink();
27 27
28 /** 28 /**
29 * Initialization code required for a link that wasn't performed in the 29 * Initialization code required for a link that wasn't performed in the
30 * constructor. 30 * constructor.
31 *@returns true if initialization was successful. A false value will halt 31 *@returns true if initialization was successful. A false value will halt
32 * the chain. 32 * the chain.
33 */ 33 */
34 virtual bool init()=0; 34 virtual bool init()=0;
35 35
36 /** 36 /**
37 * DeInitialization code that should happen, but doesn't belong in the 37 * DeInitialization code that should happen, but doesn't belong in the
38 * destructor. 38 * destructor.
39 *@returns true means everything worked, false means failure, but is 39 *@returns true means everything worked, false means failure, but is
40 * meaningless. 40 * meaningless.
41 */ 41 */
42 virtual bool deInit()=0; 42 virtual bool deInit()=0;
43 43
44 /** 44 /**
45 * Executed once per link per chain pass. Contains the guts of the program. 45 * Executed once per link per chain pass. Contains the guts of the program.
46 *@returns true if everything went well. A false value will halt the chain. 46 *@returns true if everything went well. A false value will halt the chain.
47 */ 47 */
48 virtual bool timeSlice()=0; 48 virtual bool timeSlice()=0;
49 49
50 /** 50 /**
51 * This must be handled in order to process Instant Response Messages. 51 * This must be handled in order to process Instant Response Messages.
52 * This function should return null on all messages that it doesn't 52 * This function should return null on all messages that it doesn't
53 * understand how to handle, and construct new messages to return to sender 53 * understand how to handle, and construct new messages to return to sender
54 * in the cases where it does understand. 54 * in the cases where it does understand.
55 *@param pMsgIn The message that must be processed. 55 *@param pMsgIn The message that must be processed.
56 *@returns Either a new message in cases where a response is required, 56 *@returns Either a new message in cases where a response is required,
57 * or null if nothing needs to be done by this link. 57 * or null if nothing needs to be done by this link.
58 */ 58 */
59 virtual LinkMessage *processIRM( LinkMessage *pMsgIn ) = 0; 59 virtual LinkMessage *processIRM( LinkMessage *pMsgIn ) = 0;
60 60
61 /** 61 /**
62 * Broadcast a LinkMessage to all other links in the system. Each other 62 * Broadcast a LinkMessage to all other links in the system. Each other
63 * link will get a call of their processIRM function. If the message gets 63 * link will get a call of their processIRM function. If the message gets
64 * a response then you will regain control immediately, otherwise the system 64 * a response then you will regain control immediately, otherwise the system
65 * will give all other Links a chance to respond before returning NULL. 65 * will give all other Links a chance to respond before returning NULL.
66 *@param pMsgOut The message to broadcast. 66 *@param pMsgOut The message to broadcast.
67 *@returns The message response, or NULL if no Link understood your message. 67 *@returns The message response, or NULL if no Link understood your message.
68 */ 68 */
69 LinkMessage *sendIRM( LinkMessage *pMsgOut ); 69 LinkMessage *sendIRM( LinkMessage *pMsgOut );
70 70
71private: 71 private:
72 /** 72 /**
73 * Set which chain we're assosiated with. This is how IRM messages make 73 * Set which chain we're assosiated with. This is how IRM messages make
74 * it out to the rest of the world. 74 * it out to the rest of the world.
75 *@param pNewChain A pointer to the containing program chain. 75 *@param pNewChain A pointer to the containing program chain.
76 */ 76 */
77 void setChain( class ProgramChain *pNewChain ); 77 void setChain( class ProgramChain *pNewChain );
78 78
79 /** 79 /**
80 * The pointer to the containing chain. 80 * The pointer to the containing chain.
81 */ 81 */
82 class ProgramChain *pChain; 82 class ProgramChain *pChain;
83/* 83 /*
84 void postMessage( LinkMessage *pMsg, int nLvl ); 84 void postMessage( LinkMessage *pMsg, int nLvl );
85 LinkMessage *getMessage( int nLvl ); 85 LinkMessage *getMessage( int nLvl );
86 86
87 enum 87 enum
88 { 88 {
89 msgToChain, 89 msgToChain,
90 msgToLink 90 msgToLink
91 }; 91 };
92 92
93private: 93 private:
94 Queue qMsgToChain; 94 Queue qMsgToChain;
95 Queue qMsgToLink; 95 Queue qMsgToLink;
96*/ 96 */
97}; 97 };
98}
98 99
99#endif 100#endif
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 78b3ee2..0976b3b 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -1,20 +1,12 @@
1#include "protocol.h" 1#include "bu/protocol.h"
2 2
3Protocol::Protocol() 3using namespace Bu;
4{
5 pConnection = NULL;
6}
7 4
8Protocol::~Protocol() 5Bu::Protocol::Protocol()
9{ 6{
10} 7}
11 8
12void Protocol::setConnection( Connection *pNewConnection ) 9Bu::Protocol::~Protocol()
13{ 10{
14 pConnection = pNewConnection;
15} 11}
16 12
17Connection *Protocol::getConnection()
18{
19 return pConnection;
20}
diff --git a/src/protocol.h b/src/protocol.h
index 09e1c98..bca337f 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,62 +1,27 @@
1#ifndef PROTOCOL_H 1#ifndef BU_PROTOCOL_H
2#define PROTOCOL_H 2#define BU_PROTOCOL_H
3 3
4#include "connection.h" 4#include <stdint.h>
5 5
6/** This is the template for a class that handles specialized input and output 6namespace Bu
7 * to connections of different types with different protocols.
8 *@author Mike Buland
9 */
10class Protocol
11{ 7{
12public: 8 class Client;
13 /** Constructor */
14 Protocol();
15 /** Deconstructor */
16 virtual ~Protocol();
17 9
18 /** 10 /**
19 * Function is called every time there is new data on the line. This is 11 *
20 * called directly from the Connection class to process data. This is not
21 * called whever there is pending data on the input, but every time new data
22 * is added to the input buffer.
23 *@returns True if processing went alright, false if something went wrong,
24 * I suppose. In truth this value is thrown away right now.
25 *@todo Either make a return value of false mean something, or make these
26 * void.
27 */ 12 */
28 virtual bool onNewData()=0; 13 class Protocol
14 {
15 public:
16 Protocol();
17 virtual ~Protocol();
29 18
30 /** 19 virtual void onNewConnection( Bu::Client *pClient )=0;
31 * Function is called when there is a new connection. This should only 20 virtual void onNewData( Bu::Client *pClient )=0;
32 * happen once per Protocol object, but gives each protocol object a
33 * chance to perform connection handshaking and initialization at a point
34 * where they know that they have a handle to an active Connection.
35 *@returns See onNewData
36 */
37 virtual bool onNewConnection()=0;
38
39 virtual void onNewClientConnection(){};
40 21
41 virtual void poll(){}; 22 private:
42
43 /**
44 * Sets the Protocol's Connection object. This is rather important, and
45 * handled usually by the ConnectionManager.
46 *@param pNewConnection The Connection object that this protocol will use to
47 * deal with the outside world.
48 */
49 void setConnection( class Connection *pNewConnection );
50
51 /**
52 * Get a pointer to this object's Connection object, or NULL if one was
53 * never set. If used with the ConnectionManager that should never happen.
54 *@returns A pointer to the active Connection.
55 */
56 Connection *getConnection();
57 23
58private: 24 };
59 class Connection *pConnection; /**< The pointer to the Connection. */ 25}
60};
61 26
62#endif 27#endif
diff --git a/src/ringbuffer.cpp b/src/ringbuffer.cpp
new file mode 100644
index 0000000..feb9bc7
--- /dev/null
+++ b/src/ringbuffer.cpp
@@ -0,0 +1,2 @@
1#include "bu/ringbuffer.h"
2
diff --git a/src/ringbuffer.h b/src/ringbuffer.h
new file mode 100644
index 0000000..be80e2f
--- /dev/null
+++ b/src/ringbuffer.h
@@ -0,0 +1,97 @@
1#ifndef BU_RING_BUFFER_H
2#define BU_RING_BUFFER_H
3
4#include <memory>
5#include "bu/exceptionbase.h"
6
7namespace Bu
8{
9 template<typename value, typename valuealloc=std::allocator<value> >
10 class RingBuffer
11 {
12 public:
13 RingBuffer( int nCapacity ) :
14 nCapacity( nCapacity ),
15 nStart( -1 ),
16 nEnd( -2 )
17 {
18 aData = va.allocate( nCapacity );
19 }
20
21 virtual ~RingBuffer()
22 {
23 for( int j = nStart; j < nEnd; j=(j+1%nCapacity) )
24 {
25 va.destroy( &aData[j] );
26 }
27 va.deallocate( aData, nCapacity );
28 }
29
30 int getCapacity()
31 {
32 return nCapacity;
33 }
34
35 bool isFilled()
36 {
37 return (nStart == nEnd);
38 }
39
40 bool isEmpty()
41 {
42 return (nStart == -1);
43 }
44
45 void enqueue( const value &v )
46 {
47 if( nStart == -1 )
48 {
49 nStart = 0;
50 nEnd = 1;
51 va.construct( &aData[0], v );
52 }
53 else if( nStart == nEnd )
54 {
55 throw ExceptionBase("Hey, it's full!");
56 }
57 else
58 {
59 va.construct( &aData[nEnd], v );
60 nEnd = (nEnd+1)%nCapacity;
61 }
62 }
63
64 value dequeue()
65 {
66 if( nStart == -1 )
67 {
68 throw ExceptionBase("No data");
69 }
70 else
71 {
72 value &v = aData[nStart];
73 va.destroy( &aData[nStart] );
74 nStart = (nStart+1)%nCapacity;
75 if( nStart == nEnd )
76 {
77 nStart = -1;
78 nEnd = -2;
79 }
80 return v;
81 }
82 }
83
84 value &operator[]( int nIndex )
85 {
86 return aData[(nIndex+nStart)%nCapacity];
87 }
88
89 private:
90 int nCapacity;
91 value *aData;
92 valuealloc va;
93 int nStart, nEnd;
94 };
95}
96
97#endif
diff --git a/src/serializable.cpp b/src/serializable.cpp
deleted file mode 100644
index fd50943..0000000
--- a/src/serializable.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
1#include "serializable.h"
2
3Serializable::Serializable()
4{
5}
6Serializable::~Serializable()
7{
8}
diff --git a/src/serializable.h b/src/serializable.h
deleted file mode 100644
index 06def29..0000000
--- a/src/serializable.h
+++ /dev/null
@@ -1,34 +0,0 @@
1#ifndef SERIALIZER_H
2#define SERIALIZER_H
3
4//#include "serializer.h"
5
6/**
7 * The base class for any class you want to serialize. Simply include this as
8 * a base class, implement the purely virtual serialize function and you've got
9 * an easily serializable class.
10 */
11class Serializable
12{
13public:
14 /**
15 * Does nothing, here for completeness.
16 */
17 Serializable();
18
19 /**
20 * Here to ensure the deconstructor is virtual.
21 */
22 virtual ~Serializable();
23
24 /**
25 * This is the main workhorse of the serialization system, just override and
26 * you've got a serializable class. A reference to the Serializer archive
27 * used is passed in as your only parameter, query it to discover if you are
28 * loading or saving.
29 * @param ar A reference to the Serializer object to use.
30 */
31 virtual void serialize( class Serializer &ar )=0;
32};
33
34#endif
diff --git a/src/serializer.cpp b/src/serializer.cpp
deleted file mode 100644
index 636224e..0000000
--- a/src/serializer.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
1#include "serializer.h"
2#include "serializable.h"
3#include <list>
4
5Serializer::Serializer(bool bLoading):
6 bLoading(bLoading)
7{
8}
9Serializer::~Serializer()
10{
11}
12
13bool Serializer::isLoading()
14{
15 return bLoading;
16}
17Serializer &Serializer::operator<<(bool p)
18{
19 write( &p, sizeof(p) );
20 return *this;
21}
22Serializer &Serializer::operator<<(int8_t p)
23{
24 write( &p, sizeof(p) );
25 return *this;
26}
27Serializer &Serializer::operator<<(int16_t p)
28{
29 write( &p, sizeof(p) );
30 return *this;
31}
32Serializer &Serializer::operator<<(int32_t p)
33{
34 write( &p, sizeof(p) );
35 return *this;
36}
37Serializer &Serializer::operator<<(int64_t p)
38{
39 write( &p, sizeof(p) );
40 return *this;
41}
42Serializer &Serializer::operator<<(uint8_t p)
43{
44 write( &p, sizeof(p) );
45 return *this;
46}
47Serializer &Serializer::operator<<(uint16_t p)
48{
49 write( &p, sizeof(p) );
50 return *this;
51}
52Serializer &Serializer::operator<<(uint32_t p)
53{
54 write( &p, sizeof(p) );
55 return *this;
56}
57Serializer &Serializer::operator<<(uint64_t p)
58{
59 write( &p, sizeof(p) );
60 return *this;
61}
62Serializer &Serializer::operator<<(long p)
63{
64 write( &p, sizeof(p) );
65 return *this;
66}
67Serializer &Serializer::operator<<(float p)
68{
69 write( &p, sizeof(p) );
70 return *this;
71}
72Serializer &Serializer::operator<<(double p)
73{
74 write( &p, sizeof(p) );
75 return *this;
76}
77Serializer &Serializer::operator<<(long double p)
78{
79 write( &p, sizeof(p) );
80 return *this;
81}
82
83Serializer &Serializer::operator>>(bool &p)
84{
85 read( &p, sizeof(p) );
86 return *this;
87}
88Serializer &Serializer::operator>>(int8_t &p)
89{
90 read( &p, sizeof(p) );
91 return *this;
92}
93Serializer &Serializer::operator>>(int16_t &p)
94{
95 read( &p, sizeof(p) );
96 return *this;
97}
98Serializer &Serializer::operator>>(int32_t &p)
99{
100 read( &p, sizeof(p) );
101 return *this;
102}
103Serializer &Serializer::operator>>(int64_t &p)
104{
105 read( &p, sizeof(p) );
106 return *this;
107}
108Serializer &Serializer::operator>>(uint8_t &p)
109{
110 read( &p, sizeof(p) );
111 return *this;
112}
113Serializer &Serializer::operator>>(uint16_t &p)
114{
115 read( &p, sizeof(p) );
116 return *this;
117}
118Serializer &Serializer::operator>>(uint32_t &p)
119{
120 read( &p, sizeof(p) );
121 return *this;
122}
123Serializer &Serializer::operator>>(uint64_t &p)
124{
125 read( &p, sizeof(p) );
126 return *this;
127}
128Serializer &Serializer::operator>>(long &p)
129{
130 read( &p, sizeof(p) );
131 return *this;
132}
133Serializer &Serializer::operator>>(float &p)
134{
135 read( &p, sizeof(p) );
136 return *this;
137}
138Serializer &Serializer::operator>>(double &p)
139{
140 read( &p, sizeof(p) );
141 return *this;
142}
143Serializer &Serializer::operator>>(long double &p)
144{
145 read( &p, sizeof(p) );
146 return *this;
147}
148
149Serializer &Serializer::operator&&(bool &p)
150{
151 if (bLoading)
152 {
153 return *this >> p;
154 }
155 else
156 {
157 return *this << p;
158 }
159}
160
161Serializer &Serializer::operator&&(int8_t &p)
162{
163 if (bLoading)
164 {
165 return *this >> p;
166 }
167 else
168 {
169 return *this << p;
170 }
171}
172
173Serializer &Serializer::operator&&(int16_t &p)
174{
175 if (bLoading)
176 {
177 return *this >> p;
178 }
179 else
180 {
181 return *this << p;
182 }
183}
184
185Serializer &Serializer::operator&&(int32_t &p)
186{
187 if (bLoading)
188 {
189 return *this >> p;
190 }
191 else
192 {
193 return *this << p;
194 }
195}
196
197Serializer &Serializer::operator&&(int64_t &p)
198{
199 if (bLoading)
200 {
201 return *this >> p;
202 }
203 else
204 {
205 return *this << p;
206 }
207}
208
209Serializer &Serializer::operator&&(uint8_t &p)
210{
211 if (bLoading)
212 {
213 return *this >> p;
214 }
215 else
216 {
217 return *this << p;
218 }
219}
220
221Serializer &Serializer::operator&&(uint16_t &p)
222{
223 if (bLoading)
224 {
225 return *this >> p;
226 }
227 else
228 {
229 return *this << p;
230 }
231}
232
233Serializer &Serializer::operator&&(uint32_t &p)
234{
235 if (bLoading)
236 {
237 return *this >> p;
238 }
239 else
240 {
241 return *this << p;
242 }
243}
244
245Serializer &Serializer::operator&&(uint64_t &p)
246{
247 if (bLoading)
248 {
249 return *this >> p;
250 }
251 else
252 {
253 return *this << p;
254 }
255}
256
257Serializer &Serializer::operator&&(float &p)
258{
259 if (bLoading)
260 {
261 return *this >> p;
262 }
263 else
264 {
265 return *this << p;
266 }
267}
268
269Serializer &Serializer::operator&&(double &p)
270{
271 if (bLoading)
272 {
273 return *this >> p;
274 }
275 else
276 {
277 return *this << p;
278 }
279}
280
281Serializer &Serializer::operator&&(long double &p)
282{
283 if (bLoading)
284 {
285 return *this >> p;
286 }
287 else
288 {
289 return *this << p;
290 }
291}
292
293
294Serializer &operator<<(Serializer &s, Serializable &p)
295{
296 p.serialize( s );
297 return s;
298}
299
300Serializer &operator>>(Serializer &s, Serializable &p)
301{
302 p.serialize( s );
303 return s;
304}
305
306Serializer &operator&&(Serializer &s, Serializable &p)
307{
308 if (s.isLoading())
309 {
310 return s >> p;
311 }
312 else
313 {
314 return s << p;
315 }
316}
317
318Serializer &operator<<( Serializer &ar, std::string &s )
319{
320 ar << (uint32_t)s.length();
321 ar.write( s.c_str(), s.length() );
322
323 return ar;
324}
325
326Serializer &operator>>( Serializer &ar, std::string &s )
327{
328 uint32_t l;
329 ar >> l;
330 char *tmp = new char[l+1];
331 tmp[l] = '\0';
332 ar.read( tmp, l );
333 s = tmp;
334 delete[] tmp;
335
336 return ar;
337}
338
diff --git a/src/serializer.h b/src/serializer.h
deleted file mode 100644
index 3af489c..0000000
--- a/src/serializer.h
+++ /dev/null
@@ -1,80 +0,0 @@
1#ifndef SERIALIZABLE_H
2#define SERIALIZABLE_H
3
4#include <stdint.h>
5#include <string>
6#include <list>
7//#include "serializable.h"
8
9class Serializer
10{
11private:
12 bool bLoading;
13public:
14 bool isLoading();
15
16 enum
17 {
18 load = true,
19 save = false
20 };
21
22 Serializer(bool bLoading);
23 virtual ~Serializer();
24 virtual void close()=0;
25
26 virtual void write(const void *, int32_t)=0;
27 virtual void read(void *, int32_t)=0;
28
29 virtual Serializer &operator<<(bool);
30 virtual Serializer &operator<<(int8_t);
31 virtual Serializer &operator<<(int16_t);
32 virtual Serializer &operator<<(int32_t);
33 virtual Serializer &operator<<(int64_t);
34 virtual Serializer &operator<<(uint8_t);
35 virtual Serializer &operator<<(uint16_t);
36 virtual Serializer &operator<<(uint32_t);
37 virtual Serializer &operator<<(uint64_t);
38 virtual Serializer &operator<<(long);
39 virtual Serializer &operator<<(float);
40 virtual Serializer &operator<<(double);
41 virtual Serializer &operator<<(long double);
42
43 virtual Serializer &operator>>(bool &);
44 virtual Serializer &operator>>(int8_t &);
45 virtual Serializer &operator>>(int16_t &);
46 virtual Serializer &operator>>(int32_t &);
47 virtual Serializer &operator>>(int64_t &);
48 virtual Serializer &operator>>(uint8_t &);
49 virtual Serializer &operator>>(uint16_t &);
50 virtual Serializer &operator>>(uint32_t &);
51 virtual Serializer &operator>>(uint64_t &);
52 virtual Serializer &operator>>(long &);
53 virtual Serializer &operator>>(float &);
54 virtual Serializer &operator>>(double &);
55 virtual Serializer &operator>>(long double &);
56
57 virtual Serializer &operator&&(bool &);
58 virtual Serializer &operator&&(int8_t &);
59 virtual Serializer &operator&&(int16_t &);
60 virtual Serializer &operator&&(int32_t &);
61 virtual Serializer &operator&&(int64_t &);
62 virtual Serializer &operator&&(uint8_t &);
63 virtual Serializer &operator&&(uint16_t &);
64 virtual Serializer &operator&&(uint32_t &);
65 virtual Serializer &operator&&(uint64_t &);
66 virtual Serializer &operator&&(float &);
67 virtual Serializer &operator&&(double &);
68 virtual Serializer &operator&&(long double &);
69
70 //virtual Serializer &operator&(Serializable &);
71};
72
73Serializer &operator<<(Serializer &, class Serializable &);
74Serializer &operator>>(Serializer &, class Serializable &);
75Serializer &operator&&(Serializer &s, class Serializable &p);
76
77Serializer &operator<<(Serializer &, std::string &);
78Serializer &operator>>(Serializer &, std::string &);
79
80#endif
diff --git a/src/server.cpp b/src/server.cpp
new file mode 100644
index 0000000..d07a597
--- /dev/null
+++ b/src/server.cpp
@@ -0,0 +1,96 @@
1#include "bu/server.h"
2#include <errno.h>
3#include "bu/serversocket.h"
4#include "bu/client.h"
5#include "bu/socket.h"
6
7Bu::Server::Server() :
8 nTimeoutSec( 0 ),
9 nTimeoutUSec( 0 )
10{
11 FD_ZERO( &fdActive );
12}
13
14Bu::Server::~Server()
15{
16}
17
18void Bu::Server::addPort( int nPort, int nPoolSize )
19{
20 ServerSocket *s = new ServerSocket( nPort, nPoolSize );
21 int nSocket = s->getSocket();
22 FD_SET( nSocket, &fdActive );
23 hServers.insert( nSocket, s );
24}
25
26void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize )
27{
28 ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize );
29 int nSocket = s->getSocket();
30 FD_SET( nSocket, &fdActive );
31 hServers.insert( nSocket, s );
32}
33
34void Bu::Server::setTimeout( int nTimeoutSec, int nTimeoutUSec )
35{
36 this->nTimeoutSec = nTimeoutSec;
37 this->nTimeoutUSec = nTimeoutUSec;
38}
39
40void Bu::Server::scan()
41{
42 struct timeval xTimeout = { nTimeoutSec, nTimeoutUSec };
43
44 fd_set fdRead = fdActive;
45 fd_set fdWrite = fdActive;
46 fd_set fdException = fdActive;
47
48 if( TEMP_FAILURE_RETRY( select( FD_SETSIZE, &fdRead, NULL, &fdException, &xTimeout ) ) < 0 )
49 {
50 throw ExceptionBase("Error attempting to scan open connections.");
51 }
52
53 for( int j = 0; j < FD_SETSIZE; j++ )
54 {
55 if( FD_ISSET( j, &fdRead ) )
56 {
57 if( hServers.has( j ) )
58 {
59 ServerSocket *pSrv = hServers.get( j );
60 addClient( pSrv->accept(), pSrv->getPort() );
61 }
62 else
63 {
64 Client *pClient = hClients.get( j );
65 pClient->processInput();
66 if( !pClient->isOpen() )
67 {
68 onClosedConnection( pClient );
69 hClients.erase( j );
70 FD_CLR( j, &fdActive );
71 }
72 }
73 }
74 }
75
76 // Now we just try to write all the pending data on all the sockets.
77 // this could be done better eventually, if we care about the socket
78 // wanting to accept writes (using a select).
79 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
80 {
81 (*i)->processOutput();
82 }
83}
84
85void Bu::Server::addClient( int nSocket, int nPort )
86{
87 FD_SET( nSocket, &fdActive );
88
89 Client *c = new Client(
90 new Bu::Socket( nSocket )
91 );
92 hClients.insert( nSocket, c );
93
94 onNewConnection( c, nPort );
95}
96
diff --git a/src/server.h b/src/server.h
new file mode 100644
index 0000000..302b6e3
--- /dev/null
+++ b/src/server.h
@@ -0,0 +1,61 @@
1#ifndef BU_SERVER_H
2#define BU_SERVER_H
3
4#include <stdint.h>
5
6#include "bu/fstring.h"
7#include "bu/list.h"
8
9namespace Bu
10{
11 class ServerSocket;
12 class Socket;
13 class Client;
14
15 /**
16 * Core of a network server. This class is distinct from a ServerSocket in
17 * that a ServerSocket is one listening socket, nothing more. Socket will
18 * manage a pool of both ServerSockets and connected Sockets along with
19 * their protocols and buffers.
20 *
21 * To start serving on a new port, use the addPort functions. Each call to
22 * addPort creates a new ServerSocket, starts it listening, and adds it to
23 * the server pool.
24 *
25 * All of the real work is done by scan, which will wait for up
26 * to the timeout set by setTimeout before returning if there is no data
27 * pending. scan should probably be called in some sort of tight
28 * loop, possibly in it's own thread, or in the main control loop.
29 *
30 * In order to use a Server you must subclass it and implement the pure
31 * virtual functions. These allow you to receive notification of events
32 * happening within the server itself, and actually makes it useful.
33 */
34 class Server
35 {
36 public:
37 Server();
38 virtual ~Server();
39
40 void addPort( int nPort, int nPoolSize=40 );
41 void addPort( const FString &sAddr, int nPort, int nPoolSize=40 );
42
43 void scan();
44 void setTimeout( int nTimeoutSec, int nTimeoutUSec=0 );
45
46 void addClient( int nSocket, int nPort );
47
48 virtual void onNewConnection( Client *pClient, int nPort )=0;
49 virtual void onClosedConnection( Client *pClient )=0;
50
51 private:
52 int nTimeoutSec;
53 int nTimeoutUSec;
54 fd_set fdActive;
55 Hash<int,ServerSocket *> hServers;
56 typedef Hash<int,Client *> ClientHash;
57 ClientHash hClients;
58 };
59}
60
61#endif
diff --git a/src/serversocket.cpp b/src/serversocket.cpp
new file mode 100644
index 0000000..1424630
--- /dev/null
+++ b/src/serversocket.cpp
@@ -0,0 +1,158 @@
1#include <time.h>
2#include <string.h>
3#include <stdio.h>
4#include <errno.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <sys/types.h>
8#include <sys/socket.h>
9#include <termios.h>
10#include <netinet/in.h>
11#include <netdb.h>
12#include <arpa/inet.h>
13#include <fcntl.h>
14#include "serversocket.h"
15#include "exceptions.h"
16
17Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) :
18 nPort( nPort )
19{
20 /* Create the socket and set it up to accept connections. */
21 struct sockaddr_in name;
22
23 /* Give the socket a name. */
24 name.sin_family = AF_INET;
25 name.sin_port = htons( nPort );
26
27 // I think this specifies who we will accept connections from,
28 // a good thing to make configurable later on
29 name.sin_addr.s_addr = htonl( INADDR_ANY );
30
31 startServer( name, nPoolSize );
32}
33
34Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) :
35 nPort( nPort )
36{
37 /* Create the socket and set it up to accept connections. */
38 struct sockaddr_in name;
39
40 /* Give the socket a name. */
41 name.sin_family = AF_INET;
42 name.sin_port = htons( nPort );
43
44 inet_aton( sAddr.getStr(), &name.sin_addr );
45
46 startServer( name, nPoolSize );
47}
48
49Bu::ServerSocket::~ServerSocket()
50{
51}
52
53void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize )
54{
55 /* Create the socket. */
56 nServer = socket( PF_INET, SOCK_STREAM, 0 );
57 if( nServer < 0 )
58 {
59 throw Bu::SocketException("Couldn't create a listen socket.");
60 }
61
62 int opt = 1;
63 setsockopt(
64 nServer,
65 SOL_SOCKET,
66 SO_REUSEADDR,
67 (char *)&opt,
68 sizeof( opt )
69 );
70
71 if( bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 )
72 {
73 throw Bu::SocketException("Couldn't bind to the listen socket.");
74 }
75
76 if( listen( nServer, nPoolSize ) < 0 )
77 {
78 throw Bu::SocketException(
79 "Couldn't begin listening to the server socket."
80 );
81 }
82
83 FD_ZERO( &fdActive );
84 /* Initialize the set of active sockets. */
85 FD_SET( nServer, &fdActive );
86}
87
88int Bu::ServerSocket::getSocket()
89{
90 return nServer;
91}
92
93int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec )
94{
95 fd_set fdRead = fdActive;
96
97 struct timeval xT;
98
99 xT.tv_sec = nTimeoutSec;
100 xT.tv_usec = nTimeoutUSec;
101
102 if( TEMP_FAILURE_RETRY(select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 )
103 {
104 throw SocketException(
105 "Error scanning for new connections: %s", strerror( errno )
106 );
107 }
108
109 if( FD_ISSET( nServer, &fdRead ) )
110 {
111 struct sockaddr_in clientname;
112 size_t size;
113 int nClient;
114
115 size = sizeof( clientname );
116#ifdef __CYGWIN__
117 nClient = ::accept( nServer, (struct sockaddr *)&clientname,
118 (int *)&size
119 );
120#else
121 nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size );
122#endif
123 if( nClient < 0 )
124 {
125 throw SocketException(
126 "Error accepting a new connection: %s", strerror( errno )
127 );
128 }
129 char tmpa[20];
130 inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 );
131 //"New connection from host %s, port %hd.",
132 // tmpa, ntohs (clientname.sin_port) );
133
134 {
135 int flags;
136
137 flags = fcntl( nClient, F_GETFL, 0 );
138 flags |= O_NONBLOCK;
139 if( fcntl( nClient, F_SETFL, flags ) < 0)
140 {
141 throw SocketException(
142 "Error setting option on client socket: %s",
143 strerror( errno )
144 );
145 }
146 }
147
148 return nClient;
149 }
150
151 return -1;
152}
153
154int Bu::ServerSocket::getPort()
155{
156 return nPort;
157}
158
diff --git a/src/serversocket.h b/src/serversocket.h
new file mode 100644
index 0000000..b4ee247
--- /dev/null
+++ b/src/serversocket.h
@@ -0,0 +1,39 @@
1#ifndef BU_SERVER_SOCKET_H
2#define BU_SERVER_SOCKET_H
3
4#include <stdint.h>
5#include "bu/fstring.h"
6
7namespace Bu
8{
9 /**
10 * A single tcp/ip server socket. When created the server socket will bind
11 * to the specified interface and port, and immediately begin listening for
12 * connections. When connections come in they are pooled by the networking
13 * drivers in the kernel until they are accepted, this means that failure
14 * to keep space in the connection pool will result in connection refusals.
15 *
16 * Although the accept function returns an integral file descriptor, it is
17 * designed to be used with the Socket class.
18 */
19 class ServerSocket
20 {
21 public:
22 ServerSocket( int nPort, int nPoolSize=40 );
23 ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 );
24 virtual ~ServerSocket();
25
26 int accept( int nTimeoutSec=0, int nTimeoutUSec=0 );
27 int getSocket();
28 int getPort();
29
30 private:
31 void startServer( struct sockaddr_in &name, int nPoolSize );
32
33 fd_set fdActive;
34 int nServer;
35 int nPort;
36 };
37}
38
39#endif
diff --git a/src/sfile.cpp b/src/sfile.cpp
deleted file mode 100644
index f1de03c..0000000
--- a/src/sfile.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
1#include "sfile.h"
2#include "exceptions.h"
3
4SFile::SFile( const char *sName, const char *sFlags )
5{
6 fh = fopen( sName, sFlags );
7}
8
9SFile::~SFile()
10{
11}
12
13void SFile::close()
14{
15 if( fh )
16 {
17 fclose( fh );
18 fh = NULL;
19 }
20}
21
22size_t SFile::read( char *pBuf, size_t nBytes )
23{
24 if( !fh )
25 throw FileException("File not open.");
26
27 return fread( pBuf, 1, nBytes, fh );
28}
29
30size_t SFile::write( const char *pBuf, size_t nBytes )
31{
32 if( !fh )
33 throw FileException("File not open.");
34
35 return fwrite( pBuf, 1, nBytes, fh );
36}
37
38long SFile::tell()
39{
40 if( !fh )
41 throw FileException("File not open.");
42
43 return ftell( fh );
44}
45
46void SFile::seek( long offset )
47{
48 if( !fh )
49 throw FileException("File not open.");
50
51 fseek( fh, offset, SEEK_CUR );
52}
53
54void SFile::setPos( long pos )
55{
56 if( !fh )
57 throw FileException("File not open.");
58
59 fseek( fh, pos, SEEK_SET );
60}
61
62void SFile::setPosEnd( long pos )
63{
64 if( !fh )
65 throw FileException("File not open.");
66
67 fseek( fh, pos, SEEK_END );
68}
69
70bool SFile::isEOS()
71{
72 return feof( fh );
73}
74
diff --git a/src/sfile.h b/src/sfile.h
deleted file mode 100644
index b51e5bc..0000000
--- a/src/sfile.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef SFILE_H
2#define SFILE_H
3
4#include <stdint.h>
5
6#include "stream.h"
7
8class SFile : public Stream
9{
10public:
11 SFile( const char *sName, const char *sFlags );
12 virtual ~SFile();
13
14 virtual void close();
15 virtual size_t read( char *pBuf, size_t nBytes );
16 virtual size_t write( const char *pBuf, size_t nBytes );
17
18 virtual long tell();
19 virtual void seek( long offset );
20 virtual void setPos( long pos );
21 virtual void setPosEnd( long pos );
22 virtual bool isEOS();
23
24private:
25 FILE *fh;
26
27};
28
29#endif
diff --git a/src/singleton.h b/src/singleton.h
index 47adbd5..c43d71b 100644
--- a/src/singleton.h
+++ b/src/singleton.h
@@ -1,59 +1,62 @@
1#ifndef SINGLETON_H 1#ifndef BU_SINGLETON_H
2#define SINGLETON_H 2#define BU_SINGLETON_H
3 3
4#include <stdio.h> 4#include <stdio.h>
5 5
6/** 6namespace Bu
7 * Provides singleton functionality in a modular sort of way. Make this the
8 * base class of any other class and you immediately gain singleton
9 * functionality. Be sure to make your constructor and various functions use
10 * intellegent scoping. Cleanup and instantiation are performed automatically
11 * for you at first use and program exit. There are two things that you must
12 * do when using this template, first is to inherit from it with the name of
13 * your class filling in for T and then make this class a friend of your class.
14 *@code
15 * // Making the Single Singleton:
16 * class Single : public Singleton<Single>
17 * {
18 * friend class Singleton<Single>;
19 * protected:
20 * Single();
21 * ...
22 * };
23 @endcode
24 * You can still add public functions and variables to your new Singleton child
25 * class, but your constructor should be protected (hence the need for the
26 * friend decleration).
27 *@author Mike Buland
28 */
29template <class T>
30class Singleton
31{ 7{
32protected:
33 /** 8 /**
34 * Private constructor. This constructor is empty but has a body so that 9 * Provides singleton functionality in a modular sort of way. Make this the
35 * you can make your own override of it. Be sure that you're override is 10 * base class of any other class and you immediately gain singleton
36 * also protected. 11 * functionality. Be sure to make your constructor and various functions use
12 * intellegent scoping. Cleanup and instantiation are performed automatically
13 * for you at first use and program exit. There are two things that you must
14 * do when using this template, first is to inherit from it with the name of
15 * your class filling in for T and then make this class a friend of your class.
16 *@code
17 * // Making the Single Singleton:
18 * class Single : public Singleton<Single>
19 * {
20 * friend class Singleton<Single>;
21 * protected:
22 * Single();
23 * ...
24 * };
25 @endcode
26 * You can still add public functions and variables to your new Singleton child
27 * class, but your constructor should be protected (hence the need for the
28 * friend decleration).
29 *@author Mike Buland
37 */ 30 */
38 Singleton() {}; 31 template <class T>
32 class Singleton
33 {
34 protected:
35 /**
36 * Private constructor. This constructor is empty but has a body so that
37 * you can make your own override of it. Be sure that you're override is
38 * also protected.
39 */
40 Singleton() {};
39 41
40private: 42 private:
41 /** 43 /**
42 * Copy constructor, defined so that you could write your own as well. 44 * Copy constructor, defined so that you could write your own as well.
43 */ 45 */
44 Singleton( const Singleton& ); 46 Singleton( const Singleton& );
45 47
46public: 48 public:
47 /** 49 /**
48 * Get a handle to the contained instance of the contained class. It is 50 * Get a handle to the contained instance of the contained class. It is
49 * a reference. 51 * a reference.
50 *@returns A reference to the contained object. 52 *@returns A reference to the contained object.
51 */ 53 */
52 static T &getInstance() 54 static T &getInstance()
53 { 55 {
54 static T i; 56 static T i;
55 return i; 57 return i;
56 } 58 }
57}; 59 };
60}
58 61
59#endif 62#endif
diff --git a/src/socket.cpp b/src/socket.cpp
new file mode 100644
index 0000000..e567061
--- /dev/null
+++ b/src/socket.cpp
@@ -0,0 +1,294 @@
1#include <string.h>
2#include <stdio.h>
3#include <errno.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <sys/types.h>
7#include <sys/socket.h>
8#include <sys/time.h>
9#include <netinet/in.h>
10#include <netdb.h>
11#include <arpa/inet.h>
12#include <errno.h>
13#include <fcntl.h>
14#include "socket.h"
15#include "exceptions.h"
16
17#define RBS (1024*2)
18
19Bu::Socket::Socket( int nSocket ) :
20 nSocket( nSocket ),
21 bActive( true )
22{
23}
24
25Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout )
26{
27 struct sockaddr_in xServerName;
28 bActive = false;
29
30 /* Create the socket. */
31 nSocket = socket( PF_INET, SOCK_STREAM, 0 );
32
33 if( nSocket < 0 )
34 {
35 throw ExceptionBase("Couldn't create socket.\n");
36 }
37
38 // These lines set the socket to non-blocking, a good thing?
39 int flags;
40 flags = fcntl(nSocket, F_GETFL, 0);
41 flags |= O_NONBLOCK;
42 if (fcntl(nSocket, F_SETFL, flags) < 0)
43 {
44 throw ExceptionBase("Couldn't set socket options.\n");
45 }
46
47 /* Connect to the server. */
48 //printf("Resolving hostname (%s)...\n", sAddr );
49 {
50 struct hostent *hostinfo;
51
52 xServerName.sin_family = AF_INET;
53 xServerName.sin_port = htons( nPort );
54 hostinfo = gethostbyname( sAddr.getStr() );
55 if (hostinfo == NULL)
56 {
57 throw ExceptionBase("Couldn't resolve hostname.\n");
58 }
59 xServerName.sin_addr = *(struct in_addr *) hostinfo->h_addr;
60 }
61
62 //printf("Making actual connection...");
63 //fflush( stdout );
64 connect(
65 nSocket,
66 (struct sockaddr *)&xServerName,
67 sizeof(xServerName)
68 );
69 //printf("Connected.\n");
70
71 bActive = true;
72
73 if( nTimeout > 0 )
74 {
75 fd_set rfds, wfds, efds;
76 int retval;
77
78 FD_ZERO(&rfds);
79 FD_SET(nSocket, &rfds);
80 FD_ZERO(&wfds);
81 FD_SET(nSocket, &wfds);
82 FD_ZERO(&efds);
83 FD_SET(nSocket, &efds);
84
85 struct timeval tv;
86 tv.tv_sec = nTimeout;
87 tv.tv_usec = 0;
88
89 retval = select( nSocket+1, &rfds, &wfds, &efds, &tv );
90
91 if( retval == 0 )
92 {
93 close();
94 throw ExceptionBase("Connection timeout.\n");
95 }
96
97 }
98}
99
100Bu::Socket::~Socket()
101{
102}
103
104void Bu::Socket::close()
105{
106 if( bActive )
107 {
108 fsync( nSocket );
109 ::close( nSocket );
110 }
111 bActive = false;
112}
113
114/*
115void Bu::Socket::read()
116{
117 char buffer[RBS];
118 int nbytes;
119 int nTotalRead=0;
120
121 for(;;)
122 {
123 //memset( buffer, 0, RBS );
124
125 nbytes = ::read( nSocket, buffer, RBS );
126 if( nbytes < 0 && errno != 0 && errno != EAGAIN )
127 {
128 //printf("errno: %d, %s\n", errno, strerror( errno ) );
129 //perror("readInput");
130 throw ConnectionException(
131 excodeReadError,
132 "Read error: %s",
133 strerror( errno )
134 );
135 }
136 else
137 {
138 if( nbytes <= 0 )
139 break;
140 nTotalRead += nbytes;
141 sReadBuf.append( buffer, nbytes );
142 if( nbytes < RBS )
143 {
144 break;
145 }
146
147 // New test, if data is divisible by RBS bytes on some libs the
148 // read could block, this keeps it from happening.
149 {
150 fd_set rfds;
151 FD_ZERO(&rfds);
152 FD_SET(nSocket, &rfds);
153 struct timeval tv = { 0, 0 };
154 int retval = select( nSocket+1, &rfds, NULL, NULL, &tv );
155 if( retval == -1 )
156 throw ConnectionException(
157 excodeBadReadError,
158 "Bad Read error"
159 );
160 if( !FD_ISSET( nSocket, &rfds ) )
161 break;
162 }
163 }
164 }
165}*/
166
167size_t Bu::Socket::read( void *pBuf, size_t nBytes )
168{
169 int nRead = TEMP_FAILURE_RETRY( ::read( nSocket, pBuf, nBytes ) );
170 if( nRead < 0 )
171 {
172 throw ConnectionException( excodeReadError, strerror(errno) );
173 }
174 return nRead;
175}
176
177//size_t Bu::Socket::read( void *pBuf, size_t nBytes, uint32_t nTimeout )
178//{
179//}
180
181size_t Bu::Socket::write( const void *pBuf, size_t nBytes )
182{
183 int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) );
184 if( nWrote < 0 )
185 {
186 throw ConnectionException( excodeWriteError, strerror(errno) );
187 }
188 return nWrote;
189}
190
191long Bu::Socket::tell()
192{
193 throw UnsupportedException();
194}
195
196void Bu::Socket::seek( long offset )
197{
198 throw UnsupportedException();
199}
200
201void Bu::Socket::setPos( long pos )
202{
203 throw UnsupportedException();
204}
205
206void Bu::Socket::setPosEnd( long pos )
207{
208 throw UnsupportedException();
209}
210
211bool Bu::Socket::isEOS()
212{
213 return !bActive;
214}
215
216bool Bu::Socket::canRead()
217{
218 fd_set rfds;
219 FD_ZERO(&rfds);
220 FD_SET(nSocket, &rfds);
221 struct timeval tv = { 0, 0 };
222 int retval = select( nSocket+1, &rfds, NULL, NULL, &tv );
223 if( retval == -1 )
224 throw ConnectionException(
225 excodeBadReadError,
226 "Bad Read error"
227 );
228 if( !FD_ISSET( nSocket, &rfds ) )
229 return false;
230 return true;
231}
232
233bool Bu::Socket::canWrite()
234{
235 fd_set wfds;
236 FD_ZERO(&wfds);
237 FD_SET(nSocket, &wfds);
238 struct timeval tv = { 0, 0 };
239 int retval = select( nSocket+1, NULL, &wfds, NULL, &tv );
240 if( retval == -1 )
241 throw ConnectionException(
242 excodeBadReadError,
243 "Bad Read error"
244 );
245 if( !FD_ISSET( nSocket, &wfds ) )
246 return false;
247 return true;
248}
249
250bool Bu::Socket::isReadable()
251{
252 return true;
253}
254
255bool Bu::Socket::isWritable()
256{
257 return true;
258}
259
260bool Bu::Socket::isSeekable()
261{
262 return false;
263}
264
265bool Bu::Socket::isBlocking()
266{
267 return false;
268}
269
270void Bu::Socket::setBlocking( bool bBlocking )
271{
272}
273
274void Bu::Socket::flush()
275{
276}
277
278bool Bu::Socket::isOpen()
279{
280 return bActive;
281}
282
283Bu::FString Bu::Socket::getAddress() const
284{
285 struct sockaddr_in addr;
286 socklen_t len = sizeof(addr);
287 addr.sin_family = AF_INET;
288 getsockname( nSocket, (sockaddr *)(&addr), &len );
289 char buf[150];
290 sprintf( buf, "%s", inet_ntoa( addr.sin_addr ) );
291
292 return buf;
293}
294
diff --git a/src/socket.h b/src/socket.h
new file mode 100644
index 0000000..c291549
--- /dev/null
+++ b/src/socket.h
@@ -0,0 +1,55 @@
1#ifndef BU_SOCKET_H
2#define BU_SOCKET_H
3
4#include <stdint.h>
5
6#include "stream.h"
7#include "fstring.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class Socket : public Stream
15 {
16 public:
17 Socket( int nSocket );
18 Socket( const FString &sAddr, int nPort, int nTimeout=30 );
19 virtual ~Socket();
20
21 virtual void close();
22 //virtual void read();
23 virtual size_t read( void *pBuf, size_t nBytes );
24 virtual size_t read( void *pBuf, size_t nBytes, uint32_t nTimeout );
25 virtual size_t write( const void *pBuf, size_t nBytes );
26
27 virtual long tell();
28 virtual void seek( long offset );
29 virtual void setPos( long pos );
30 virtual void setPosEnd( long pos );
31 virtual bool isEOS();
32 virtual bool isOpen();
33
34 virtual void flush();
35
36 virtual bool canRead();
37 virtual bool canWrite();
38
39 virtual bool isReadable();
40 virtual bool isWritable();
41 virtual bool isSeekable();
42
43 virtual bool isBlocking();
44 virtual void setBlocking( bool bBlocking=true );
45
46 Bu::FString getAddress() const;
47
48 private:
49 int nSocket;
50 bool bActive;
51 FString sReadBuf;
52 };
53}
54
55#endif
diff --git a/src/sptr.cpp b/src/sptr.cpp
index 7f5e894..8ea7f8f 100644
--- a/src/sptr.cpp
+++ b/src/sptr.cpp
@@ -1 +1 @@
#include "sptr.h" #include "bu/sptr.h"
diff --git a/src/sptr.h b/src/sptr.h
index a3e6dc7..75851a6 100644
--- a/src/sptr.h
+++ b/src/sptr.h
@@ -1,144 +1,192 @@
1#ifndef SPTR_H 1#ifndef BU_SPTR_H
2#define SPTR_H 2#define BU_SPTR_H
3 3
4#include <stdint.h> 4#include <stdint.h>
5#include <stdio.h> 5#include <stdio.h>
6 6
7template<typename T> class SPtr; 7namespace Bu
8template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src );
9
10template<typename T>
11class SPtr
12{ 8{
13 template<typename Tb, typename Ta> 9 template<typename T> class SPtr;
14 friend SPtr<Tb> SPtrCast( SPtr<Ta> pt ); 10 template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src );
15public: 11
16 SPtr() : 12 template<typename T>
17 pRefCnt( NULL ), 13 class SPtr
18 pData( NULL ) 14 {
19 { 15 template<typename Tb, typename Ta>
20 } 16 friend SPtr<Tb> SPtrCast( SPtr<Ta> pt );
17 public:
18 SPtr() :
19 pRefCnt( NULL ),
20 pData( NULL )
21 {
22 }
21 23
22 ~SPtr() 24 ~SPtr()
23 { 25 {
24 decCount(); 26 decCount();
25 } 27 }
26 28
27 SPtr( const SPtr<T> &src ) : 29 SPtr( const SPtr<T> &src ) :
28 pRefCnt( src.pRefCnt ), 30 pRefCnt( src.pRefCnt ),
29 pData( src.pData ) 31 pData( src.pData )
30 { 32 {
31 if( pRefCnt ) 33 if( pRefCnt )
32 (*pRefCnt) += 1; 34 (*pRefCnt) += 1;
33 } 35 }
34 36
35 SPtr( T *pSrc ) : 37 SPtr( T *pSrc ) :
36 pRefCnt( NULL ), 38 pRefCnt( NULL ),
37 pData( pSrc ) 39 pData( pSrc )
38 {
39 if( pData )
40 { 40 {
41 pRefCnt = new int32_t; 41 if( pData )
42 (*pRefCnt) = 1; 42 {
43 pRefCnt = new int32_t;
44 (*pRefCnt) = 1;
45 }
43 } 46 }
44 }
45 47
46 int32_t count() const 48 /**
47 { 49 * Get the number of references to this pointer.
48 return *pRefCnt; 50 *@returns (int32_t) The number of references to this pointer.
49 } 51 */
52 int32_t count() const
53 {
54 return *pRefCnt;
55 }
50 56
51 const T *operator->() const 57 /**
52 { 58 * Pointer access operator.
53 return pData; 59 *@returns (const T *)
54 } 60 */
61 const T *operator->() const
62 {
63 return pData;
64 }
55 65
56 const T &operator*() const 66 /**
57 { 67 * Dereference operator.
58 return *pData; 68 *@returns (const T &) The value at the end of the pointer.
59 } 69 */
60 70 const T &operator*() const
61 T *operator->() 71 {
62 { 72 return *pData;
63 return pData; 73 }
64 } 74
75 /**
76 * Pointer access operator.
77 *@returns (T *)
78 */
79 T *operator->()
80 {
81 return pData;
82 }
65 83
66 T &operator*() 84 /**
67 { 85 * Dereference operator.
68 return *pData; 86 *@returns (T &) The value at the end of the pointer.
69 } 87 */
88 T &operator*()
89 {
90 return *pData;
91 }
70 92
71 SPtr<T> operator=( const SPtr<T> &src ) 93 /**
72 { 94 * Assignment operator.
73 decCount(); 95 *@param src (const SPtr<T> &)
74 pRefCnt = src.pRefCnt; 96 */
75 pData = src.pData; 97 SPtr<T> operator=( const SPtr<T> &src )
76 if( pRefCnt ) 98 {
77 (*pRefCnt) += 1; 99 decCount();
100 pRefCnt = src.pRefCnt;
101 pData = src.pData;
102 if( pRefCnt )
103 (*pRefCnt) += 1;
78 104
79 return *this; 105 return *this;
80 } 106 }
81 107
82 const SPtr<T> operator=( const SPtr<T> &src ) const 108 /**
83 { 109 * Assignment operator.
84 decCount(); 110 *@param src (const SPtr<T> &)
85 pRefCnt = src.pRefCnt; 111 */
86 pData = src.pData; 112 const SPtr<T> operator=( const SPtr<T> &src ) const
87 if( pRefCnt ) 113 {
88 (*pRefCnt) += 1; 114 decCount();
115 pRefCnt = src.pRefCnt;
116 pData = src.pData;
117 if( pRefCnt )
118 (*pRefCnt) += 1;
89 119
90 return *this; 120 return *this;
91 } 121 }
92 122
93 bool operator==( const SPtr<T> &src ) const 123 /**
94 { 124 * Equals comparison operator.
95 return pData == src.pData; 125 *@param src (const SPtr<T> &) The SPtr to compare to.
96 } 126 *@returns (bool) Are the equal?
127 */
128 bool operator==( const SPtr<T> &src ) const
129 {
130 return pData == src.pData;
131 }
97 132
98 bool operator==( const T *src ) const 133 /**
99 { 134 * Equals comparison operator.
100 return pData == src; 135 *@param src (const T *) The pointer to compare to.
101 } 136 *@returns (bool) Are the equal?
137 */
138 bool operator==( const T *src ) const
139 {
140 return pData == src;
141 }
102 142
103 operator bool() const 143 /**
104 { 144 * Boolean cast operator. Do we have a pointer?
105 return pRefCnt != NULL; 145 */
106 } 146 operator bool() const
147 {
148 return pRefCnt != NULL;
149 }
107 150
108 bool isSet() const 151 /**
109 { 152 * Do we have a pointer?
110 return pRefCnt != NULL; 153 *@returns (bool) Do we have a pointer?
111 } 154 */
155 bool isSet() const
156 {
157 return pRefCnt != NULL;
158 }
112 159
113private: 160 private:
114 void decCount() const 161 void decCount() const
115 {
116 if( pRefCnt )
117 { 162 {
118 (*pRefCnt) -= 1; 163 if( pRefCnt )
119 //printf("Decrementing ref-count to %d\n", *pRefCnt );
120 if( (*pRefCnt) == 0 )
121 { 164 {
122 delete pRefCnt; 165 (*pRefCnt) -= 1;
123 delete pData; 166 //printf("Decrementing ref-count to %d\n", *pRefCnt );
124 pRefCnt = NULL; 167 if( (*pRefCnt) == 0 )
125 pData = NULL; 168 {
169 delete pRefCnt;
170 delete pData;
171 pRefCnt = NULL;
172 pData = NULL;
173 }
126 } 174 }
127 } 175 }
128 }
129 176
130 mutable int32_t *pRefCnt; 177 mutable int32_t *pRefCnt;
131 mutable T *pData; 178 mutable T *pData;
132}; 179 };
133 180
134template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src ) 181 template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src )
135{ 182 {
136 SPtr<Tb> ret; 183 SPtr<Tb> ret;
137 ret.pRefCnt = src.pRefCnt; 184 ret.pRefCnt = src.pRefCnt;
138 ret.pData = dynamic_cast<Tb *>(src.pData); 185 ret.pData = dynamic_cast<Tb *>(src.pData);
139 if( ret.pRefCnt ) 186 if( ret.pRefCnt )
140 (*(ret.pRefCnt)) += 1; 187 (*(ret.pRefCnt)) += 1;
141 return ret; 188 return ret;
189 }
142} 190}
143 191
144#endif 192#endif
diff --git a/src/stream.cpp b/src/stream.cpp
index 856a58d..267a7d1 100644
--- a/src/stream.cpp
+++ b/src/stream.cpp
@@ -1,10 +1,10 @@
1#include "stream.h" 1#include "stream.h"
2 2
3Stream::Stream() 3Bu::Stream::Stream()
4{ 4{
5} 5}
6 6
7Stream::~Stream() 7Bu::Stream::~Stream()
8{ 8{
9} 9}
10 10
diff --git a/src/stream.h b/src/stream.h
index e086e28..1e236a6 100644
--- a/src/stream.h
+++ b/src/stream.h
@@ -1,27 +1,143 @@
1#ifndef STREAM_H 1#ifndef BU_STREAM_H
2#define STREAM_H 2#define BU_STREAM_H
3 3
4#include <stdint.h> 4#include <stdint.h>
5#include <stdio.h> 5#include <stdio.h>
6 6
7class Stream 7namespace Bu
8{ 8{
9public: 9 /**
10 Stream(); 10 * The basis for a completely general data transport mechanism. Anything
11 virtual ~Stream(); 11 * that inherits from this should provide at least the basic read and/or
12 * write functions, and very probably the close function. Any functions
13 * that aren't supported should throw an exception if called.
14 *
15 * The constructor of a child class should pretty much universally be used
16 * to open the stream. I can't think of anything that should require an
17 * exception.
18 */
19 class Stream
20 {
21 public:
22 Stream();
23 virtual ~Stream();
12 24
13 virtual void close() = 0; 25 /**
14 virtual size_t read( char *pBuf, size_t nBytes ) = 0; 26 * Close the stream.
15 virtual size_t write( const char *pBuf, size_t nBytes ) = 0; 27 */
28 virtual void close() = 0;
16 29
17 virtual long tell() = 0; 30 /**
18 virtual void seek( long offset ) = 0; 31 * Read data from the stream into a buffer.
19 virtual void setPos( long pos ) = 0; 32 *@param pBuf (void *) Buffer which will be filled.
20 virtual void setPosEnd( long pos ) = 0; 33 *@param nBytes (size_t) Max data to read.
21 virtual bool isEOS() = 0; 34 *@returns (size_t) Amount of data read.
35 */
36 virtual size_t read( void *pBuf, size_t nBytes ) = 0;
22 37
23private: 38 /**
39 * Write data to the stream.
40 *@param pBuf (const void *) The data to be written.
41 *@param nBytes (size_t) Amount of data to write from pBuf.
42 *@returns (size_t) Amount of data actually written.
43 */
44 virtual size_t write( const void *pBuf, size_t nBytes ) = 0;
24 45
25}; 46 /**
47 * Get the current position in the stream.
48 *@returns (long) The current position in the stream.
49 */
50 virtual long tell() = 0;
51
52 /**
53 * Seek to a position in the stream relative to the current position.
54 *@param offset (long) Offset from current position to seek to.
55 */
56 virtual void seek( long offset ) = 0;
57
58 /**
59 * Set position in the stream relative to the start of the stream.
60 *@param pos (long) The position.
61 */
62 virtual void setPos( long pos ) = 0;
63
64 /**
65 * Set position in the stream relative to the end of the stream.
66 *@param pos (long) The position.
67 */
68 virtual void setPosEnd( long pos ) = 0;
69
70 /**
71 * Are we at the end of the stream?
72 *@returns (bool) Are we at the end of the stream?
73 */
74 virtual bool isEOS() = 0;
75
76 /**
77 * Is the stream open?
78 *@returns (bool) Is the stream open?
79 */
80 virtual bool isOpen() = 0;
81
82 /**
83 * Flush any data still held in buffers.
84 */
85 virtual void flush() = 0;
86
87 /**
88 * In non-blocking streams this indicates if a read operation will
89 * return data at the moment or not. In blocking streams this should
90 * return the same value as isEOS().
91 */
92 virtual bool canRead() = 0;
93
94 /**
95 * In non-blocking streams this indicates if a write operation will
96 * succeed or fail. In some cases writing is not allowed (e.g.
97 * internal buffers are full) temporarilly. In blocking streams this
98 * should return the same value as isWritable.
99 */
100 virtual bool canWrite() = 0;
101
102 /**
103 * Indicates if the stream is capable of read operations. This does not
104 * indicate if such operations will return useful data, see canRead for
105 * that.
106 */
107 virtual bool isReadable() = 0;
108
109 /**
110 * Indicates if the stream is capable of write operations. This does
111 * not indicate if such operations will succeed or fail, see canWrite
112 * for that.
113 */
114 virtual bool isWritable() = 0;
115
116 /**
117 * Indicates if the stream is capable of seek operations. This is
118 * generally false for non-blocking streams. Some buffered streams may
119 * support limited in-buffer seeking.
120 */
121 virtual bool isSeekable() = 0;
122
123 /**
124 * Are we currently set to block mode?
125 *@returns (bool)
126 */
127 virtual bool isBlocking() = 0;
128
129 /**
130 * Set stream to blocking or non-blocking mode.
131 *@param bBlocking (bool) Whether we should block or not.
132 */
133 virtual void setBlocking( bool bBlocking=true ) = 0;
134
135 public: // Filters
136
137
138 private:
139
140 };
141}
26 142
27#endif 143#endif
diff --git a/src/tafnode.cpp b/src/tafnode.cpp
new file mode 100644
index 0000000..53b782e
--- /dev/null
+++ b/src/tafnode.cpp
@@ -0,0 +1,165 @@
1#include "tafnode.h"
2
3Bu::TafNode::TafNode( NodeType eType ) :
4 eType( eType )
5{
6}
7
8Bu::TafNode::~TafNode()
9{
10}
11
12const Bu::TafNode::NodeType Bu::TafNode::getType() const
13{
14 return eType;
15}
16
17/*
18const Bu::TafNode::PropList &Bu::TafNode::getProperties( const Bu::FString &sName ) const
19{
20 return hProp.get( sName );
21}
22
23const Bu::TafNode::NodeList &Bu::TafNode::getChildren( const Bu::FString &sName ) const
24{
25 return hChildren.get( sName );
26}
27
28const Bu::FString &Bu::TafNode::getProperty( const Bu::FString &sName ) const
29{
30 return getProperties( sName ).first();
31}
32
33const Bu::TafNode *Bu::TafNode::getChild( const Bu::FString &sName ) const
34{
35 return getChildren( sName ).first();
36}
37*/
38
39Bu::TafGroup::TafGroup( const Bu::FString &sName ) :
40 TafNode( typeGroup ),
41 sName( sName )
42{
43}
44
45Bu::TafGroup::~TafGroup()
46{
47 //printf("Entering Bu::TafNode::~TafNode() \"%s\"\n", sName.getStr() );
48 for( NodeList::iterator i = lChildren.begin(); i != lChildren.end(); i++ )
49 {
50 delete (*i);
51 }
52}
53
54const Bu::FString &Bu::TafGroup::getName() const
55{
56 return sName;
57}
58
59Bu::TafNode *Bu::TafGroup::addChild( Bu::TafNode *pNode )
60{
61 switch( pNode->getType() )
62 {
63 case typeGroup:
64 addChild( (Bu::TafGroup *)pNode );
65 break;
66
67 case typeProperty:
68 addChild( (Bu::TafProperty *)pNode );
69 break;
70
71 case typeComment:
72 addChild( (Bu::TafComment *)pNode );
73 break;
74 }
75
76 return pNode;
77}
78
79Bu::TafGroup *Bu::TafGroup::addChild( TafGroup *pNode )
80{
81 TafGroup *pGroup = (TafGroup *)pNode;
82 if( !hChildren.has( pGroup->getName() ) )
83 hChildren.insert( pGroup->getName(), GroupList() );
84 hChildren.get( pGroup->getName() ).append( pGroup );
85 lChildren.append( pNode );
86 return pNode;
87}
88
89Bu::TafProperty *Bu::TafGroup::addChild( TafProperty *pNode )
90{
91 TafProperty *pProperty = (TafProperty *)pNode;
92 if( !hProp.has( pProperty->getName() ) )
93 hProp.insert( pProperty->getName(), PropList() );
94 hProp.get( pProperty->getName() ).append( pProperty->getValue() );
95 lChildren.append( pNode );
96 return pNode;
97}
98
99Bu::TafComment *Bu::TafGroup::addChild( TafComment *pNode )
100{
101 lChildren.append( pNode );
102 return pNode;
103}
104
105const Bu::TafGroup::GroupList &Bu::TafGroup::getChildren( const Bu::FString &sName ) const
106{
107 return hChildren.get( sName );
108}
109
110const Bu::TafGroup::NodeList &Bu::TafGroup::getChildren() const
111{
112 return lChildren;
113}
114
115const Bu::TafGroup *Bu::TafGroup::getChild( const Bu::FString &sName ) const
116{
117 return hChildren.get( sName ).first();
118}
119
120const Bu::TafGroup::PropList &Bu::TafGroup::getProperties( const Bu::FString &sName ) const
121{
122 return hProp.get( sName );
123}
124
125const Bu::FString &Bu::TafGroup::getProperty( const Bu::FString &sName ) const
126{
127 return hProp.get( sName ).first();
128}
129
130Bu::TafProperty::TafProperty( const Bu::FString &sName, const Bu::FString &sValue ) :
131 TafNode( typeProperty ),
132 sName( sName ),
133 sValue( sValue )
134{
135}
136
137Bu::TafProperty::~TafProperty()
138{
139}
140
141const Bu::FString &Bu::TafProperty::getName() const
142{
143 return sName;
144}
145
146const Bu::FString &Bu::TafProperty::getValue() const
147{
148 return sValue;
149}
150
151Bu::TafComment::TafComment( const Bu::FString &sText ) :
152 TafNode( typeComment ),
153 sText( sText )
154{
155}
156
157Bu::TafComment::~TafComment()
158{
159}
160
161const Bu::FString &Bu::TafComment::getText() const
162{
163 return sText;
164}
165
diff --git a/src/tafnode.h b/src/tafnode.h
new file mode 100644
index 0000000..cb4093f
--- /dev/null
+++ b/src/tafnode.h
@@ -0,0 +1,94 @@
1#ifndef BU_TAF_NODE_H
2#define BU_TAF_NODE_H
3
4#include <stdint.h>
5#include "bu/fstring.h"
6#include "bu/hash.h"
7#include "bu/list.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class TafNode
15 {
16 public:
17 enum NodeType
18 {
19 typeGroup,
20 typeProperty,
21 typeComment
22 };
23
24 public:
25 TafNode( NodeType eType );
26 virtual ~TafNode();
27
28 const NodeType getType() const;
29
30 private:
31 NodeType eType;
32 };
33
34 class TafProperty;
35 class TafComment;
36 class TafGroup : public TafNode
37 {
38 public:
39 typedef Bu::List<Bu::FString> PropList;
40 typedef Bu::Hash<Bu::FString, PropList> PropHash;
41 typedef Bu::List<class Bu::TafGroup *> GroupList;
42 typedef Bu::Hash<Bu::FString, GroupList> GroupHash;
43 typedef Bu::List<class Bu::TafNode *> NodeList;
44
45 TafGroup( const Bu::FString &sName );
46 virtual ~TafGroup();
47
48 const Bu::FString &getName() const;
49
50 const Bu::FString &getProperty( const Bu::FString &sName ) const;
51 const PropList &getProperties( const Bu::FString &sName ) const;
52 const TafGroup *getChild( const Bu::FString &sName ) const;
53 const GroupList &getChildren( const Bu::FString &sName ) const;
54 TafNode *addChild( TafNode *pNode );
55 TafGroup *addChild( TafGroup *pNode );
56 TafProperty *addChild( TafProperty *pNode );
57 TafComment *addChild( TafComment *pNode );
58 const NodeList &getChildren() const;
59
60 private:
61 Bu::FString sName;
62 PropHash hProp;
63 GroupHash hChildren;
64 NodeList lChildren;
65 };
66
67 class TafProperty : public TafNode
68 {
69 public:
70 TafProperty( const Bu::FString &sName, const Bu::FString &sValue );
71 virtual ~TafProperty();
72
73 const Bu::FString &getName() const;
74 const Bu::FString &getValue() const;
75
76 private:
77 Bu::FString sName;
78 Bu::FString sValue;
79 };
80
81 class TafComment : public TafNode
82 {
83 public:
84 TafComment( const Bu::FString &sText );
85 virtual ~TafComment();
86
87 const Bu::FString &getText() const;
88
89 private:
90 Bu::FString sText;
91 };
92}
93
94#endif
diff --git a/src/tafreader.cpp b/src/tafreader.cpp
new file mode 100644
index 0000000..db465e9
--- /dev/null
+++ b/src/tafreader.cpp
@@ -0,0 +1,155 @@
1#include "bu/tafreader.h"
2#include "bu/exceptions.h"
3#include "bu/fstring.h"
4
5using namespace Bu;
6
7Bu::TafReader::TafReader( Bu::Stream &sIn ) :
8 c( 0 ),
9 sIn( sIn )
10{
11 next(); next();
12}
13
14Bu::TafReader::~TafReader()
15{
16
17}
18
19Bu::TafGroup *Bu::TafReader::readGroup()
20{
21 ws();
22 if( c != '{' )
23 throw TafException("Expected '{'");
24 next();
25 ws();
26 FString sName = readStr();
27 TafGroup *pGroup = new TafGroup( sName );
28 next();
29 //printf("Node[%s]:\n", sName.getStr() );
30
31 groupContent( pGroup );
32
33 if( c != '}' )
34 throw TafException("Expected '}'");
35
36 next();
37
38 return pGroup;
39}
40
41void Bu::TafReader::groupContent( Bu::TafGroup *pGroup )
42{
43 for(;;)
44 {
45 ws();
46 if( c == '{' )
47 pGroup->addChild( readGroup() );
48 else if( c == '}' )
49 return;
50 else if( c == '/' && la == '*' )
51 pGroup->addChild( readComment() );
52 else
53 pGroup->addChild( readProperty() );
54 }
55}
56
57Bu::TafProperty *Bu::TafReader::readProperty()
58{
59 FString sName = readStr();
60 ws();
61 if( c != '=' )
62 {
63 //printf(" %s (true)\n", sName.getStr() );
64 return new Bu::TafProperty( sName, "" );
65 }
66 next();
67 FString sValue = readStr();
68 return new Bu::TafProperty( sName, sValue );
69 //printf(" %s = %s\n", sName.getStr(), sValue.getStr() );
70}
71
72Bu::TafComment *Bu::TafReader::readComment()
73{
74 next();
75 FString sCmnt;
76 for(;;)
77 {
78 next();
79 if( c == '*' && la == '/' )
80 break;
81 sCmnt += c;
82 }
83
84 return new TafComment( sCmnt );
85}
86
87Bu::FString Bu::TafReader::readStr()
88{
89 ws();
90 FString s;
91 if( c == '"' )
92 {
93 next();
94 for(;;)
95 {
96 if( c == '\\' )
97 {
98 next();
99 if( c == 'x' )
100 {
101 char code[3]={'\0','\0','\0'};
102 next();
103 code[0] = c;
104 next();
105 code[1] = c;
106 c = (unsigned char)strtol( code, NULL, 16 );
107 }
108 else if( c == '"' )
109 c = '"';
110 else
111 throw TafException("Invalid escape sequence.");
112 }
113 else if( c == '"' )
114 break;
115 s += c;
116 next();
117 }
118 next();
119 }
120 else
121 {
122 for(;;)
123 {
124 if( isws() || c == '}' || c == '{' || c == ':' || c == '=' )
125 break;
126 s += c;
127 next();
128 }
129 }
130
131 return s;
132}
133
134void Bu::TafReader::ws()
135{
136 for(;;)
137 {
138 if( !isws() )
139 return;
140
141 next();
142 }
143}
144
145bool Bu::TafReader::isws()
146{
147 return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
148}
149
150void Bu::TafReader::next()
151{
152 c = la;
153 sIn.read( &la, 1 );
154}
155
diff --git a/src/tafreader.h b/src/tafreader.h
new file mode 100644
index 0000000..eeaafb3
--- /dev/null
+++ b/src/tafreader.h
@@ -0,0 +1,35 @@
1#ifndef BU_TAF_READER_H
2#define BU_TAF_READER_H
3
4#include <stdint.h>
5#include "bu/tafnode.h"
6#include "bu/stream.h"
7#include "bu/fstring.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class TafReader
15 {
16 public:
17 TafReader( Bu::Stream &sIn );
18 virtual ~TafReader();
19
20 Bu::TafGroup *readGroup();
21
22 private:
23 void groupContent( Bu::TafGroup *pNode );
24 Bu::TafProperty *readProperty();
25 Bu::TafComment *readComment();
26 void ws();
27 bool isws();
28 void next();
29 Bu::FString readStr();
30 char c, la;
31 Bu::Stream &sIn;
32 };
33}
34
35#endif
diff --git a/src/tafwriter.cpp b/src/tafwriter.cpp
new file mode 100644
index 0000000..6b505ef
--- /dev/null
+++ b/src/tafwriter.cpp
@@ -0,0 +1,70 @@
1#include "tafwriter.h"
2
3Bu::TafWriter::TafWriter( Bu::Stream &sOut ) :
4 sOut( sOut )
5{
6}
7
8Bu::TafWriter::~TafWriter()
9{
10}
11
12void Bu::TafWriter::writeGroup( const Bu::TafGroup *pRoot )
13{
14 sOut.write("{", 1 );
15 writeString( pRoot->getName() );
16 sOut.write(": ", 2 );
17 const Bu::TafGroup::NodeList &nl = pRoot->getChildren();
18 for( Bu::TafGroup::NodeList::const_iterator i = nl.begin(); i != nl.end(); i++ )
19 {
20 switch( (*i)->getType() )
21 {
22 case Bu::TafNode::typeGroup:
23 writeGroup( (Bu::TafGroup *)(*i) );
24 break;
25
26 case Bu::TafNode::typeProperty:
27 writeProperty( (Bu::TafProperty *)(*i) );
28 break;
29
30 case Bu::TafNode::typeComment:
31 writeComment( (Bu::TafComment *)(*i) );
32 break;
33 }
34 }
35 sOut.write("}", 1 );
36}
37
38void Bu::TafWriter::writeProperty( const Bu::TafProperty *pProp )
39{
40 writeString( pProp->getName() );
41 if( pProp->getValue().getStr() != NULL )
42 {
43 sOut.write("=", 1 );
44 writeString( pProp->getValue() );
45 }
46 sOut.write(" ", 1 );
47}
48
49void Bu::TafWriter::writeComment( const Bu::TafComment *pComment )
50{
51 sOut.write("/*", 2 );
52 sOut.write( pComment->getText().getStr(), pComment->getText().getSize() );
53 sOut.write("*/ ", 3 );
54}
55
56void Bu::TafWriter::writeString( const Bu::FString &str )
57{
58 if( str.getStr() == NULL )
59 return;
60 sOut.write("\"", 1 );
61 for( const char *s = str.getStr(); *s; s++ )
62 {
63 if( *s == '\"' )
64 sOut.write("\\\"", 2 );
65 else
66 sOut.write( s, 1 );
67 }
68 sOut.write("\"", 1 );
69}
70
diff --git a/src/tafwriter.h b/src/tafwriter.h
new file mode 100644
index 0000000..5f80504
--- /dev/null
+++ b/src/tafwriter.h
@@ -0,0 +1,30 @@
1#ifndef BU_TAF_WRITER_H
2#define BU_TAF_WRITER_H
3
4#include <stdint.h>
5#include "bu/tafnode.h"
6#include "bu/stream.h"
7#include "bu/fstring.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class TafWriter
15 {
16 public:
17 TafWriter( Bu::Stream &sOut );
18 virtual ~TafWriter();
19
20 void writeGroup( const Bu::TafGroup *pRoot );
21
22 private:
23 void writeProperty( const Bu::TafProperty *pProp );
24 void writeComment( const Bu::TafComment *pComment );
25 void writeString( const Bu::FString &str );
26 Bu::Stream &sOut;
27 };
28}
29
30#endif
diff --git a/src/tests/archive.cpp b/src/tests/archive.cpp
new file mode 100644
index 0000000..2035aa6
--- /dev/null
+++ b/src/tests/archive.cpp
@@ -0,0 +1,16 @@
1#include "archive.h"
2#include "file.h"
3
4using namespace Bu;
5
6int main()
7{
8 File f("test.dat", "wb");
9 Archive ar( f, Archive::save );
10
11 std::string s("Hello there");
12 ar << s;
13
14 return 0;
15}
16
diff --git a/src/tests/atom.cpp b/src/tests/atom.cpp
new file mode 100644
index 0000000..2077bfd
--- /dev/null
+++ b/src/tests/atom.cpp
@@ -0,0 +1,25 @@
1#include "bu/atom.h"
2#include <stdio.h>
3#include <stdlib.h>
4
5typedef struct bob
6{
7 int a, b;
8} bob;
9int main()
10{
11 Bu::Atom<int> aInt;
12 Bu::Atom<char *> aStr;
13 Bu::Atom<bob> aBob;
14
15 aBob = bob();
16 aBob->a = 5;
17
18 aStr.set("Hey there, dude");
19 aInt.set( 55 );
20 int me = aInt;
21 aInt = 12;
22 printf("%d, %d\n", aInt.get(), me );
23 printf("%s\n", aStr.get() );
24}
25
diff --git a/src/tests/bzip2.cpp b/src/tests/bzip2.cpp
new file mode 100644
index 0000000..683d3d7
--- /dev/null
+++ b/src/tests/bzip2.cpp
@@ -0,0 +1,23 @@
1#include "bu/bzip2.h"
2#include "bu/file.h"
3
4int main( int argc, char *argv[] )
5{
6 char buf[1024];
7 size_t nRead;
8
9 Bu::File f( "test.bz2", "wb" );
10 Bu::BZip2 bz2( f );
11
12 Bu::File fin( argv[1], "rb");
13
14 for(;;)
15 {
16 nRead = fin.read( buf, 1024 );
17 if( nRead > 0 )
18 bz2.write( buf, nRead );
19 if( fin.isEOS() )
20 break;
21 }
22}
23
diff --git a/src/tests/constsptr.cpp b/src/tests/constsptr.cpp
deleted file mode 100644
index e6f87c7..0000000
--- a/src/tests/constsptr.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
1#include <stdio.h>
2#include "sptr.h"
3
4template <typename T>
5class DataBase
6{
7public:
8 DataBase():
9 _bHas(false)
10 {
11 }
12
13 virtual ~DataBase()
14 {
15 clr();
16 }
17
18 virtual bool has() const
19 {
20 return _bHas;
21 }
22
23 virtual void clr()
24 {
25 _bHas = false;
26 }
27
28 virtual void set(T d)
29 {
30 _tVal = d;
31 _bHas = true;
32 }
33
34 virtual T const &get() const
35 {
36 if(!has())
37 throw "no data";
38 return _tVal;
39 }
40
41 virtual T &get()
42 {
43 if(!has())
44 throw "no data";
45 return _tVal;
46 }
47
48protected:
49 bool _bHas;
50 T _tVal;
51};
52
53
54class Test
55{
56public:
57 Test(){};
58 virtual ~Test(){};
59
60 void set(int i)
61 {
62 _i = i;
63 }
64
65 int get() const
66 {
67 return _i;
68 }
69
70private:
71 int _i;
72};
73
74int main()
75{
76 typedef SPtr<Test> TestPtr;
77
78 TestPtr t1(new Test);
79 t1->set(42);
80
81 printf("t1: %d.\n", t1->get());
82
83 const TestPtr t2 = t1;
84
85 printf("t2: %d.\n", t2->get());
86
87 typedef DataBase<const TestPtr> DBTP;
88
89 DBTP db;
90 db.set(t1);
91
92 printf("dbt1: %d.\n", db.get()->get());
93}
94
diff --git a/src/tests/constsptr2.cpp b/src/tests/constsptr2.cpp
deleted file mode 100644
index 8ccb20c..0000000
--- a/src/tests/constsptr2.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
1#include "sptr.h"
2
3void nonsptr()
4{
5 int a = 5;
6 int b = 10;
7 const int *p = &a;
8 p = &b;
9 printf("p = %d\n", (*p) );
10 //(*p)++;
11}
12
13void sptr()
14{
15 int a = 5;
16 int b = 10;
17 const SPtr<int> p = new int(a);
18 p = new int(b);
19 printf("p = %d\n", (*p) );
20 //(*p)++;
21}
22
23int main()
24{
25 printf("Non-sptr:\n");
26 nonsptr();
27 printf("sptr:\n");
28 sptr();
29}
30
diff --git a/src/tests/fstring.cpp b/src/tests/fstring.cpp
index 271738c..48dfc5f 100644
--- a/src/tests/fstring.cpp
+++ b/src/tests/fstring.cpp
@@ -1,9 +1,28 @@
1#include "hash.h" 1#include "bu/hash.h"
2#include "fstring.h" 2#include "bu/fstring.h"
3#include <sys/time.h>
4#include <string>
3 5
4FString genThing() 6#ifndef WIN32
7inline double getTime()
5{ 8{
6 FString bob; 9 struct timeval tv;
10 gettimeofday( &tv, NULL );
11 return ((double)tv.tv_sec) + ((double)tv.tv_usec/1000000.0);
12}
13#else
14#include "windows.h"
15#include "winbase.h"
16inline double getTime()
17{
18 uint32_t t = (uint32_t) GetTickCount();
19 return (double) t / 1000.0;
20}
21#endif
22
23Bu::FString genThing()
24{
25 Bu::FString bob;
7 bob.append("ab "); 26 bob.append("ab ");
8 bob += "cd "; 27 bob += "cd ";
9 bob += "efg"; 28 bob += "efg";
@@ -12,20 +31,91 @@ FString genThing()
12 return bob; 31 return bob;
13} 32}
14 33
15void thing( FString str ) 34void thing( Bu::FString str )
16{ 35{
17 printf("Hey: %s\n", str.c_str() ); 36 printf("Hey: %s\n", str.c_str() );
18} 37}
19 38
39void copyfunc( std::string temp )
40{
41 temp += "Hi";
42}
43
44void copyfunc( Bu::FString temp )
45{
46 temp += "Hi";
47}
48
49void doTimings()
50{
51 Bu::FString fs1, fs2;
52 std::string ss1, ss2;
53 double dStart, dEnd, tfs1, tfs2, tfs3, tss1, tss2, tss3;
54 int nChars = 500000, nChunks=5000, nCopies=5000000, nChunkSize=1024*4;
55 char *buf = new char[nChunkSize];
56 memset( buf, '!', nChunkSize );
57
58 printf("Timing Bu::FString single chars...\n");
59 dStart = getTime();
60 for( int j = 0; j < nChars; j++ ) fs1 += (char)('a'+(j%26));
61 fs1.getStr();
62 dEnd = getTime();
63 tfs1 = dEnd-dStart;
64
65 printf("Timing std::string single chars...\n");
66 dStart = getTime();
67 for( int j = 0; j < nChars; j++ ) ss1 += (char)('a'+(j%26));
68 ss1.c_str();
69 dEnd = getTime();
70 tss1 = dEnd-dStart;
71
72 printf("Timing Bu::FString %d char chunks...\n", nChunkSize);
73 dStart = getTime();
74 for( int j = 0; j < nChunks; j++ ) fs2.append(buf, nChunkSize);
75 fs2.getStr();
76 dEnd = getTime();
77 tfs2 = dEnd-dStart;
78
79 printf("Timing std::string %d char chunks...\n", nChunkSize);
80 dStart = getTime();
81 for( int j = 0; j < nChunks; j++ ) ss2.append(buf, nChunkSize);
82 ss2.c_str();
83 dEnd = getTime();
84 tss2 = dEnd-dStart;
85
86 fs2 = "Hello there.";
87 ss2 = "Hello there.";
88 printf("Timing Bu::FString copies...\n");
89 dStart = getTime();
90 for( int j = 0; j < nCopies; j++ ) Bu::FString stmp = fs2;
91 dEnd = getTime();
92 tfs3 = dEnd-dStart;
93
94 printf("Timing std::string copies...\n");
95 dStart = getTime();
96 for( int j = 0; j < nCopies; j++ ) std::string stpm = ss2;
97 dEnd = getTime();
98 tss3 = dEnd-dStart;
99
100 printf(
101 "Results: singles: chunks: copies:\n"
102 "Bu::FString %10.2f/s %10.2f/s %10.2f/s\n"
103 "std::string %10.2f/s %10.2f/s %10.2f/s\n",
104 nChars/tfs1, nChunks/tfs2, nCopies/tfs3,
105 nChars/tss1, nChunks/tss2, nCopies/tss3 );
106
107 delete[] buf;
108}
109
20#define pem printf("---------\n%08X: %s\n%08X: %s\n", (unsigned int)str.c_str(), str.c_str(), (unsigned int)str2.c_str(), str2.c_str() ); 110#define pem printf("---------\n%08X: %s\n%08X: %s\n", (unsigned int)str.c_str(), str.c_str(), (unsigned int)str2.c_str(), str2.c_str() );
21int main( int argc, char *argv ) 111int main( int argc, char *argv )
22{ 112{
23 FString str("th"); 113 Bu::FString str("th");
24 114
25 str.prepend("Hello "); 115 str.prepend("Hello ");
26 str.append("ere."); 116 str.append("ere.");
27 117
28 FString str2( str ); 118 Bu::FString str2( str );
29 pem; 119 pem;
30 str += " What's up?"; 120 str += " What's up?";
31 pem; 121 pem;
@@ -43,6 +133,8 @@ int main( int argc, char *argv )
43 thing( str2 ); 133 thing( str2 );
44 thing("test."); 134 thing("test.");
45 135
46 printf("%d == %d\n", __calcHashCode( str ), __calcHashCode( str.c_str() ) ); 136 printf("%d == %d\n", Bu::__calcHashCode( str ), Bu::__calcHashCode( str.c_str() ) );
137
138 doTimings();
47} 139}
48 140
diff --git a/src/tests/hash.cpp b/src/tests/hash.cpp
index 2fc6968..73cfb27 100644
--- a/src/tests/hash.cpp
+++ b/src/tests/hash.cpp
@@ -1,116 +1,24 @@
1#include "hash.h" 1#include "bu/hash.h"
2#include "staticstring.h" 2#include "bu/sptr.h"
3 3
4int main() 4typedef struct Bob
5{ 5{
6 const char *names[]={ 6 int nID;
7 "Homer the Great", 7} Bob;
8 "And Maggie Makes Three",
9 "Bart's Comet",
10 "Homie The Clown",
11 "Bart Vs Australia",
12 "Homer vs Patty and Selma",
13 "A star is burns",
14 "Lisa's Wedding",
15 "Two Dozen and One Greyhounds",
16 "The PTA Disbands",
17 "Round Springfield",
18 "The Springfield connection",
19 "Lemon of Troy",
20 "Who Shot Mr. Burns (Pt. 1)",
21 "Who Shot Mr. Burns (pt. 2)",
22 "Radioactive Man",
23 "Home Sweet Homediddly-dum-doodly",
24 "Bart Sells His Soul",
25 "Lisa the Vegetarian",
26 "Treehouse of horror VI",
27 "King Size Homer",
28 "Mother Simpson",
29 "Sideshow Bob's Last Gleaming",
30 "The Simpson's 138th Show Spectacular",
31 "Marge Be Not Proud",
32 "Team Homer",
33 "Two Bad Neighbors",
34 "Scenes From the Class Struggle in Springfield",
35 "Bart the Fink",
36 "Lisa the Iconoclast",
37 "Homer the Smithers",
38 "The Day the Violence Died",
39 "A Fish Called Selma",
40 "Bart on the road",
41 "22 Short Films about Springfield",
42 "The Curse of the Flying Hellfish",
43 "Much Apu about Nothing",
44 "Homerpalooza",
45 "The Summer of 4 Ft 2",
46 "Treehouse of Horror VII",
47 "You Only Move Twice",
48 "The Homer They Fall",
49 "Burns Baby Burns",
50 "Bart After Dark",
51 "A Millhouse Divided",
52 "Lisas Date With Destiny",
53 "Hurricane Neddy",
54 "The Mysterious Voyage of Our Homer",
55 "The Springfield Files",
56 "The Twisted World of Marge Simpson",
57 "Mountain of Madness",
58 NULL
59 };
60
61 Hash<const char *, int> sTest;
62
63 printf("Inserting\n-------------------\n\n");
64 for( int j = 0; j < 33; j++ )
65 {
66 sTest[names[j]] = j;
67 }
68
69 printf("Test1: %d, Test2: %d\n", sTest.has("Lemon of Troy"), sTest.has(std::string("Lemon of Troy").c_str() ) );
70
71 sTest.has(std::string("Lemon of Troy").c_str() );
72
73 printf("Getting\n-------------------\n\n");
74
75 sTest.erase("Homer the Great");
76 sTest["Bart's Comet"].erase();
77 8
78 for( Hash<const char *, int>::iterator i = sTest.begin(); 9int main()
79 i != sTest.end(); i++ ) 10{
80 { 11 Bu::Hash<int, Bu::SPtr<const Bob> > lb;
81 Hash<const char *, int>::iterator j = i; 12 for( int j = 0; j < 10; j++ )
82 printf("%d: %s\n", (*j).second, (*j).first );
83 }
84
85 printf("Testing\n-------------------\n\n");
86 for( int j = 0; j < 33; j++ )
87 { 13 {
88 if( sTest.has(names[j]) ) 14 Bob *b = new Bob;
89 { 15 b->nID = j;
90 if( sTest[names[j]] != j ) 16 lb.insert( j, b );
91 {
92 printf("'%s' should be %d, is %d\n",
93 names[j], j,
94 sTest[names[j]].value()
95 );
96 }
97 }
98 else
99 {
100 printf("Missing element %d, '%s'\n", j, names[j] );
101 }
102 } 17 }
103 18
104 printf("Clearing\n-------------------\n\n"); 19 for( int j = 0; j < 10; j++ )
105
106 sTest.clear();
107
108 for( Hash<const char *, int>::iterator i = sTest.begin();
109 i != sTest.end(); i++ )
110 { 20 {
111 Hash<const char *, int>::iterator j = i; 21 printf("%d\n", lb[j].value()->nID );
112 printf("%d: %s\n", (*j).second, (*j).first );
113 } 22 }
114
115} 23}
116 24
diff --git a/src/tests/itoqueue1.cpp b/src/tests/itoqueue1.cpp
new file mode 100644
index 0000000..f73f4d3
--- /dev/null
+++ b/src/tests/itoqueue1.cpp
@@ -0,0 +1,110 @@
1#include <string>
2#include "bu/ito.h"
3#include "bu/itoqueue.h"
4
5class Reader : public Bu::Ito
6{
7public:
8 Reader( Bu::ItoQueue<std::string *> &q, int id ) :
9 q( q ),
10 id( id )
11 {
12 }
13
14 void *run()
15 {
16 for( int i = 0; i < 10; i++ )
17 {
18 std::string *pStr = q.dequeue( true );
19 if( pStr == NULL )
20 {
21 printf("Null received...\n");
22 }
23 else
24 {
25 printf("[%d] read: %s\n", id, pStr->c_str() );
26 delete pStr;
27 }
28 usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) );
29 }
30
31 return NULL;
32 }
33
34private:
35 Bu::ItoQueue<std::string *> &q;
36 int id;
37};
38
39class Writer : public Bu::Ito
40{
41public:
42 Writer( Bu::ItoQueue<std::string *> &q, int id, const char *strbase ) :
43 q( q ),
44 strbase( strbase ),
45 id( id )
46 {
47 }
48
49 void *run()
50 {
51 for( int i = 0; i < 11; i++ )
52 {
53 usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) );
54 q.enqueue( new std::string( strbase ) );
55 printf("[%d] write: %s\n", id, strbase );
56 }
57
58 return NULL;
59 }
60
61private:
62 Bu::ItoQueue<std::string *> &q;
63 const char *strbase;
64 int id;
65};
66
67int main()
68{
69 Writer *wr[5];
70 Reader *rd[5];
71 const char bob[][7]={
72 {"Test 1"},
73 {"Test 2"},
74 {"Test 3"},
75 {"Test 4"},
76 {"Test 5"}
77 };
78
79 Bu::ItoQueue<std::string *> q;
80
81 for( int j = 0; j < 5; j++ )
82 {
83 wr[j] = new Writer( q, j, bob[j] );
84 rd[j] = new Reader( q, j );
85 }
86
87 for( int j = 0; j < 5; j++ )
88 {
89 rd[j]->start();
90 }
91
92 for( int j = 0; j < 5; j++ )
93 {
94 wr[j]->start();
95 }
96
97 for( int j = 0; j < 5; j++ )
98 {
99 rd[j]->join();
100 }
101
102 for( int j = 0; j < 5; j++ )
103 {
104 delete wr[j];
105 delete rd[j];
106 }
107
108 return 0;
109}
110
diff --git a/src/tests/itoqueue2.cpp b/src/tests/itoqueue2.cpp
new file mode 100644
index 0000000..f4b5e19
--- /dev/null
+++ b/src/tests/itoqueue2.cpp
@@ -0,0 +1,83 @@
1#include <string>
2#include "bu/ito.h"
3#include "bu/itoqueue.h"
4#include <errno.h>
5
6class Reader : public Bu::Ito
7{
8public:
9 Reader( Bu::ItoQueue<std::string *> &q, int id ) :
10 q( q ),
11 id( id )
12 {
13 }
14
15 void *run()
16 {
17 for( int i = 0; i < 10; i++ )
18 {
19 std::string *pStr = q.dequeue( 0, 500000 );
20 if( pStr == NULL )
21 {
22 printf("Null received...\n");
23 i--;
24 }
25 else
26 {
27 printf("[%d] read: %s\n", id, pStr->c_str() );
28 delete pStr;
29 }
30 }
31
32 return NULL;
33 }
34
35private:
36 Bu::ItoQueue<std::string *> &q;
37 int id;
38};
39
40class Writer : public Bu::Ito
41{
42public:
43 Writer( Bu::ItoQueue<std::string *> &q, int id, const char *strbase ) :
44 q( q ),
45 strbase( strbase ),
46 id( id )
47 {
48 }
49
50 void *run()
51 {
52 for( int i = 0; i < 11; i++ )
53 {
54 sleep( 2 );
55 printf("[%d] write: %s\n", id, strbase );
56 q.enqueue( new std::string( strbase ) );
57 }
58
59 return NULL;
60 }
61
62private:
63 Bu::ItoQueue<std::string *> &q;
64 const char *strbase;
65 int id;
66};
67
68int main()
69{
70 printf("ETIMEDOUT: %d\n", ETIMEDOUT );
71 Bu::ItoQueue<std::string *> q;
72 Writer wr( q, 0, "writer" );
73 Reader rd( q, 0 );
74
75 rd.start();
76 wr.start();
77
78 rd.join();
79 wr.join();
80
81 return 0;
82}
83
diff --git a/src/tests/list.cpp b/src/tests/list.cpp
new file mode 100644
index 0000000..12807a5
--- /dev/null
+++ b/src/tests/list.cpp
@@ -0,0 +1,53 @@
1#include "bu/list.h"
2#include <list>
3
4typedef struct Bob
5{
6 int nID;
7} Bob;
8
9int main()
10{
11 Bu::List<int> l;
12
13 l.append( 0 );
14
15 for( int j = 3; j <= 21; j += 3 )
16 {
17 l.append( j );
18 l.prepend( -j );
19 }
20
21 for( Bu::List<int>::iterator i = l.begin(); i != l.end(); i++ )
22 {
23 printf("%d ", *i );
24 }
25 printf("\n");
26 for( Bu::List<int>::iterator i = l.begin(); i != l.end(); i++ )
27 {
28 l.erase( i );
29 if( i != l.end() )
30 printf("%d ", *i );
31 }
32
33 printf("\n\n");
34
35 Bu::List<Bob> lb;
36 for( int j = 0; j < 10; j++ )
37 {
38 Bob b;
39 b.nID = j;
40 lb.append( b );
41 }
42
43 const Bu::List<Bob> rb = lb;
44
45 for( Bu::List<Bob>::const_iterator i = rb.begin(); i != rb.end(); i++ )
46 {
47 //i->nID += 2;
48 //(*i).nID = 4;
49 printf("%d ", i->nID );
50 }
51 printf("\n\n");
52}
53
diff --git a/src/tests/logger.cpp b/src/tests/logger.cpp
new file mode 100644
index 0000000..290f479
--- /dev/null
+++ b/src/tests/logger.cpp
@@ -0,0 +1,28 @@
1#include "bu/logger.h"
2#include <errno.h>
3#include <stdlib.h>
4
5class Thing
6{
7 public:
8 Thing()
9 {
10 lineLog( 2, "Want a thing?");
11 }
12
13 void go( int i )
14 {
15 lineLog( 1, "GO!!!!");
16 }
17};
18
19int main()
20{
21 setLogLevel( 4 );
22 setLogFormat("%L: %y-%02m-%02d %h:%02M:%02s %f:%l:%F: %t");
23 lineLog( 5, "Hey, error: %s", strerror( errno ) );
24
25 Thing gh;
26 gh.go( 6);
27}
28
diff --git a/src/tests/ringbuffer.cpp b/src/tests/ringbuffer.cpp
new file mode 100644
index 0000000..259ec1f
--- /dev/null
+++ b/src/tests/ringbuffer.cpp
@@ -0,0 +1,29 @@
1#include "bu/ringbuffer.h"
2#include <stdlib.h>
3
4int main()
5{
6 Bu::RingBuffer<uint32_t> ibuf( 10 );
7
8 for( int k = 0; k < 2; k++ )
9 {
10 int j = 1;
11 for(; j < 7; j++ )
12 {
13 ibuf.enqueue( j );
14 }
15
16 for(; j < 20; j++ )
17 {
18 ibuf.enqueue( j );
19 printf("- %d\n", ibuf.dequeue() );
20 }
21
22 for(;;)
23 {
24 if( ibuf.isEmpty() ) break;
25 printf(". %d\n", ibuf.dequeue() );
26 }
27 }
28}
29
diff --git a/src/tests/taf.cpp b/src/tests/taf.cpp
new file mode 100644
index 0000000..e3da120
--- /dev/null
+++ b/src/tests/taf.cpp
@@ -0,0 +1,24 @@
1#include "bu/tafreader.h"
2#include "bu/tafwriter.h"
3#include "bu/file.h"
4
5int main()
6{
7 Bu::File f("test.taf", "rb");
8 Bu::TafReader tr( f );
9
10 Bu::TafGroup *pGroup = tr.readGroup();
11
12 const Bu::TafGroup *pStats = pGroup->getChild("stats");
13 printf("%s\n", pStats->getName().getStr() );
14 printf(" str = %s\n", pStats->getProperty("str").getStr() );
15
16 {
17 Bu::File fo("out.taf", "wb");
18 Bu::TafWriter tw( fo );
19 tw.writeGroup( pGroup );
20 }
21
22 delete pGroup;
23}
24
diff --git a/src/unit/entities/unit b/src/unit/entities/unit
new file mode 100644
index 0000000..28db45f
--- /dev/null
+++ b/src/unit/entities/unit
@@ -0,0 +1,30 @@
1<?xml version="1.1" ?>
2<entity desc="Unit test framework">
3 <param name="name" required="yes" desc="Name of the class"/>
4 <file
5 name="source"
6 filename="{=name:%tolower}.cpp"
7>#include "bu/unitsuite.h"
8
9class Unit : public Bu::UnitSuite
10{
11public:
12 Unit()
13 {
14 setName("{=name}");
15 addTest( Unit::test01 );
16 }
17
18 virtual ~Unit()
19 {
20 }
21
22 void test01()
23 {
24 unitTest( 0 == 5 );
25 }
26};
27
28int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); }
29</file>
30</entity>
diff --git a/src/unit/file.cpp b/src/unit/file.cpp
new file mode 100644
index 0000000..1eaaf36
--- /dev/null
+++ b/src/unit/file.cpp
@@ -0,0 +1,111 @@
1#include "unitsuite.h"
2#include "file.h"
3#include "exceptions.h"
4
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8
9class Unit : public Bu::UnitSuite
10{
11public:
12 Unit()
13 {
14 setName("File");
15 addTest( Unit::writeFull );
16 addTest( Unit::readBlocks );
17 addTest( Unit::readError1 );
18 addTest( Unit::readError2 );
19 }
20
21 virtual ~Unit() { }
22
23 //
24 // Tests go here
25 //
26 void writeFull()
27 {
28 Bu::File sf("testfile1", "wb");
29 for( int c = 0; c < 256; c++ )
30 {
31 unsigned char ch = (unsigned char)c;
32 sf.write( &ch, 1 );
33 unitTest( sf.tell() == c+1 );
34 }
35 //unitTest( sf.canRead() == false );
36 //unitTest( sf.canWrite() == true );
37 //unitTest( sf.canSeek() == true );
38 sf.close();
39 struct stat sdat;
40 stat("testfile1", &sdat );
41 unitTest( sdat.st_size == 256 );
42 }
43
44 void readBlocks()
45 {
46 Bu::File sf("testfile1", "rb");
47 unsigned char buf[50];
48 size_t total = 0;
49 for(;;)
50 {
51 size_t s = sf.read( buf, 50 );
52 for( size_t c = 0; c < s; c++ )
53 {
54 unitTest( buf[c] == (unsigned char)(c+total) );
55 }
56 total += s;
57 if( s < 50 )
58 {
59 unitTest( total == 256 );
60 unitTest( sf.isEOS() == true );
61 break;
62 }
63 }
64 sf.close();
65 }
66
67 void readError1()
68 {
69 try
70 {
71 Bu::File sf("doesn'texist", "rb");
72 unitFailed("No exception thrown");
73 }
74 catch( Bu::FileException &e )
75 {
76 return;
77 }
78 }
79
80 void readError2()
81 {
82 Bu::File sf("testfile1", "rb");
83 char buf[256];
84 int r = sf.read( buf, 256 );
85 unitTest( r == 256 );
86 // You have to read past the end to set the EOS flag.
87 unitTest( sf.isEOS() == false );
88 try
89 {
90 if( sf.read( buf, 5 ) > 0 )
91 {
92 unitFailed("Non-zero read result");
93 }
94 else
95 {
96 sf.close();
97 }
98 }
99 catch( Bu::FileException &e )
100 {
101 sf.close();
102 return;
103 }
104 }
105};
106
107int main( int argc, char *argv[] )
108{
109 return Unit().run( argc, argv );
110}
111
diff --git a/src/unit/fstring.cpp b/src/unit/fstring.cpp
new file mode 100644
index 0000000..72755eb
--- /dev/null
+++ b/src/unit/fstring.cpp
@@ -0,0 +1,28 @@
1#include "fstring.h"
2#include "unitsuite.h"
3
4class Unit : public Bu::UnitSuite
5{
6public:
7 Unit()
8 {
9 setName("FString");
10 addTest( Unit::test1 );
11 }
12
13 virtual ~Unit()
14 {
15 }
16
17 void test1()
18 {
19 unitTest( 1 == 1 );
20 unitTest( 1 == 0 );
21 }
22};
23
24int main( int argc, char *argv[] )
25{
26 return Unit().run( argc, argv );
27}
28
diff --git a/src/unit/hash.cpp b/src/unit/hash.cpp
new file mode 100644
index 0000000..9ea933f
--- /dev/null
+++ b/src/unit/hash.cpp
@@ -0,0 +1,40 @@
1#include "bu/fstring.h"
2#include "bu/hash.h"
3#include "bu/unitsuite.h"
4
5#include <stdio.h>
6
7class Unit : public Bu::UnitSuite
8{
9private:
10 typedef Bu::Hash<Bu::FString, int> StrIntHash;
11public:
12 Unit()
13 {
14 setName("Hash");
15 addTest( Unit::test_probe );
16 }
17
18 virtual ~Unit()
19 {
20 }
21
22 void test_probe()
23 {
24 StrIntHash h;
25 char buf[20];
26 for(int i=1;i<10000;i++)
27 {
28 sprintf(buf,"%d",i);
29 Bu::FString sTmp(buf);
30 h[sTmp] = i;
31 unitTest( h.has(sTmp) );
32 }
33 }
34};
35
36int main( int argc, char *argv[] )
37{
38 return Unit().run( argc, argv );
39}
40
diff --git a/src/unit/membuf.cpp b/src/unit/membuf.cpp
new file mode 100644
index 0000000..65ba82a
--- /dev/null
+++ b/src/unit/membuf.cpp
@@ -0,0 +1,37 @@
1#include "bu/unitsuite.h"
2#include "bu/membuf.h"
3
4class Unit : public Bu::UnitSuite
5{
6public:
7 Unit()
8 {
9 setName("MemBuf");
10 addTest( Unit::testWriteRead01 );
11 }
12
13 virtual ~Unit()
14 {
15 }
16
17 void testWriteRead01()
18 {
19 Bu::MemBuf mb;
20 unitTest( mb.write("ab", 2 ) == 2 );
21 unitTest( mb.write("cde", 3 ) == 3 );
22 unitTest( mb.write("FG", 2 ) == 2 );
23
24 mb.setPos( 0 );
25
26 char buf[8];
27 buf[7] = '\0';
28 unitTest( mb.read( buf, 7 ) == 7 );
29 unitTest( !strncmp( buf, "abcdeFG", 7 ) );
30 unitTest( mb.read( buf, 7 ) == 0 );
31 mb.seek( -3 );
32 unitTest( mb.read( buf, 7 ) == 3 );
33 unitTest( !strncmp( buf, "eFG", 3 ) );
34 }
35};
36
37int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); }
diff --git a/src/unit/taf.cpp b/src/unit/taf.cpp
new file mode 100644
index 0000000..5e0e914
--- /dev/null
+++ b/src/unit/taf.cpp
@@ -0,0 +1,48 @@
1#include "unitsuite.h"
2#include "file.h"
3#include "tafreader.h"
4
5#include <string.h>
6#include <unistd.h>
7
8class Unit : public Bu::UnitSuite
9{
10public:
11 Unit()
12 {
13 setName("taf");
14 addTest( Unit::read1 );
15 }
16
17 virtual ~Unit()
18 {
19 }
20
21 void read1()
22 {
23#define FN_TMP ("/tmp/tmpXXXXXXXX")
24 Bu::FString sFnTmp(FN_TMP);
25 Bu::File fOut = Bu::File::tempFile( sFnTmp, "wb" );
26 const char *data =
27"{test: name=\"Bob\"}"
28;
29 fOut.write(data,strlen(data));
30 fOut.close();
31
32 Bu::File fIn(sFnTmp.c_str(), "rb");
33 Bu::TafReader tr(fIn);
34
35 Bu::TafGroup *tn = tr.readGroup();
36 unitTest( !strcmp("Bob", tn->getProperty("name").c_str()) );
37 delete tn;
38
39 unlink(sFnTmp.c_str());
40#undef FN_TMP
41 }
42};
43
44int main( int argc, char *argv[] )
45{
46 return Unit().run( argc, argv );
47}
48
diff --git a/src/unitsuite.cpp b/src/unitsuite.cpp
new file mode 100644
index 0000000..2a28eb5
--- /dev/null
+++ b/src/unitsuite.cpp
@@ -0,0 +1,67 @@
1#include "unitsuite.h"
2
3Bu::UnitSuite::UnitSuite()
4{
5}
6
7Bu::UnitSuite::~UnitSuite()
8{
9}
10
11int Bu::UnitSuite::run( int argc, char *argv[] )
12{
13 for( TestList::iterator i = lTests.begin(); i != lTests.end(); i++ )
14 {
15 printf("%s: ", i->sName.getStr() );
16 fflush( stdout );
17 try
18 {
19 (this->*(i->fTest))();
20 printf("passed.\n");
21 }
22 catch( Failed &e )
23 {
24 if( e.bFile )
25 {
26 printf("unitTest(%s) failed. (%s:%d)\n",
27 e.str.getStr(),
28 e.sFile.getStr(),
29 e.nLine
30 );
31 }
32 else
33 {
34 printf("unitTest(%s) failed.\n",
35 e.str.getStr()
36 );
37 }
38 }
39 catch( ... )
40 {
41 printf("failed with external exception.\n");
42 }
43 }
44
45 return 0;
46}
47
48void Bu::UnitSuite::add( Test fTest, Bu::FString sName )
49{
50 TestInfo ti;
51 ti.sName = sName;
52 long index = ti.sName.rfind("::");
53 if( index != -1 )
54 {
55 FString tmp = sSuiteName;
56 tmp += ti.sName.getStr()+index;
57 ti.sName = tmp;
58 }
59 ti.fTest = fTest;
60 lTests.push_back( ti );
61}
62
63void Bu::UnitSuite::setName( const FString &sName )
64{
65 sSuiteName = sName;
66}
67
diff --git a/src/unitsuite.h b/src/unitsuite.h
new file mode 100644
index 0000000..578b4cc
--- /dev/null
+++ b/src/unitsuite.h
@@ -0,0 +1,96 @@
1#ifndef BU_UNIT_SUITE_H
2#define BU_UNIT_SUITE_H
3
4#include <stdint.h>
5#include <list>
6#include "fstring.h"
7
8namespace Bu
9{
10 /**
11 * Provides a unit testing framework. This is pretty easy to use, probably
12 * the best way to get started is to use ch to generate a template, or use
13 * the code below with appropriate tweaks:
14 *@code
15 * #include "unitsuite.h"
16 *
17 * class Unit : public Bu::UnitSuite
18 * {
19 * public:
20 * Unit()
21 * {
22 * setName("Example");
23 * addTest( Unit::test );
24 * }
25 *
26 * virtual ~Unit() { }
27 *
28 * //
29 * // Tests go here
30 * //
31 * void test()
32 * {
33 * unitTest( 1 == 1 );
34 * }
35 * };
36 *
37 * int main( int argc, char *argv[] )
38 * {
39 * return Unit().run( argc, argv );
40 * }
41 *
42 @endcode
43 * The main function can contain other things, but using this one exactly
44 * makes all of the test suites work exactly the same. Using the optional
45 * setName at the top of the constructor replaces the class name with the
46 * chosen name when printing out stats and info.
47 */
48 class UnitSuite
49 {
50 public:
51 UnitSuite();
52 virtual ~UnitSuite();
53
54 int run( int argc=0, char *argv[]=NULL );
55
56 typedef void (UnitSuite::*Test)();
57
58 class Failed
59 {
60 public:
61 Failed() : str(""), bFile( false ) { }
62 Failed( const FString &s ) : str( s ), bFile( false ) { }
63 Failed( const FString &s, const FString &sFile, int nLine ) :
64 str( s ), sFile( sFile ), nLine( nLine ), bFile( true ) { }
65
66 FString str;
67 FString sFile;
68 int nLine;
69 bool bFile;
70 };
71
72 protected:
73 void add( Test fTest, Bu::FString sName );
74 void setName( const FString &sName );
75
76 private:
77 typedef struct TestInfo
78 {
79 FString sName;
80 Test fTest;
81 } TestInfo;
82
83 typedef std::list<TestInfo> TestList;
84 TestList lTests;
85 FString sSuiteName;
86 };
87}
88
89#define addTest( fn ) add( static_cast<Bu::UnitSuite::Test>(&fn), #fn )
90#define unitTest( tst ) if( !(tst) ) \
91{ \
92 throw Bu::UnitSuite::Failed( #tst, __FILE__, __LINE__ ); \
93}
94#define unitFailed( msg ) throw Bu::UnitSuite::Failed(msg, __FILE__, __LINE__);
95
96#endif
diff --git a/test.taf b/test.taf
new file mode 100644
index 0000000..1d4e7d1
--- /dev/null
+++ b/test.taf
@@ -0,0 +1,7 @@
1{"player": "password"="aoeuaoeuao" "userclass"="implementor" "species"="human" "sex"="male" "active" "startroom"="Salourn::Xagafinelle's Room" {"stats": "str"="14" "dex"="12" "spd"="12" "enr"="7" "rea"="12" "wil"="10" "int"="13" "cha"="14" }{"hp": "cur"="100" "max"="100" }{"en": "cur"="100" "max"="100" }"attackrate"="30" "gold"="0"
2
3 /* Hey, the inventory is next...isn't that cool? Oooooh yeah! */
4
5{"inventory": {: "count"="1" "id"="Salourn::Dark Blade" }{: "count"="1" "id"="Salourn::Dark Suit" }{: "count"="3" "id"="Salourn::Small Fig" }}{"aliases": {: "key"="." "value"="say" }{: "key"="," "value"="yell" }{: "key"="li" "value"="lightning" }}"description"="They appear to be rather average looking, not particularly
6 tall or short, with facial features that are difficult to remember even
7 seconds after witnessing them." }
diff --git a/tests/comments.xml b/tests/comments.xml
deleted file mode 100644
index df05b3b..0000000
--- a/tests/comments.xml
+++ /dev/null
@@ -1,12 +0,0 @@
1<?xml version="1.0"?>
2<test>
3 <!----><stuff/><guy>
4 <!-- euntaho esutnaho .rucaho. u
5 ao.rcuh aor uasrcoh
6 rohaor
7 c.uha
8 orchu
9 aroch.ua.
10 -->Aaaugh!
11 </guy>
12</test>
diff --git a/tests/guy.cpp b/tests/guy.cpp
deleted file mode 100644
index 6510771..0000000
--- a/tests/guy.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
1#include "stdio.h"
2#include "plugin.h"
3#include "plugger.h"
4
5class Guy : public Plugin
6{
7public:
8 Guy()
9 {
10 printf("I'm guy!\n");
11 }
12
13 virtual ~Guy()
14 {
15 printf("Guy is dead...\n");
16 }
17
18private:
19};
20
21PluginInterface( Guy, Plugin, "Mike", 0, 1 )
22
diff --git a/tests/makeplugin.sh b/tests/makeplugin.sh
deleted file mode 100755
index 086fefd..0000000
--- a/tests/makeplugin.sh
+++ /dev/null
@@ -1,3 +0,0 @@
1#!/bin/sh
2
3g++ -fPIC -shared -Wl,-soname,guy.so -o guy.so -I../src -I../src/test/plugin guy.cpp ../src/test/plugin/plugin.cpp