diff options
-rw-r--r-- | Doxyfile | 4 | ||||
l--------- | bu | 1 | ||||
-rw-r--r-- | build.conf | 38 | ||||
-rw-r--r-- | fstringtest.dev | 59 | ||||
-rw-r--r-- | libbu++.dev | 209 | ||||
-rw-r--r-- | misc/taf | 26 | ||||
-rw-r--r-- | misc/w3c-xml-1.1.html | 1598 | ||||
-rwxr-xr-x | mkincs.sh | 5 | ||||
-rw-r--r-- | src/archival.cpp | 10 | ||||
-rw-r--r-- | src/archival.h | 38 | ||||
-rw-r--r-- | src/archive.cpp | 386 | ||||
-rw-r--r-- | src/archive.h | 212 | ||||
-rw-r--r-- | src/arraylist.cpp | 100 | ||||
-rw-r--r-- | src/arraylist.h | 80 | ||||
-rw-r--r-- | src/atom.cpp | 1 | ||||
-rw-r--r-- | src/atom.h | 107 | ||||
-rw-r--r-- | src/bzip2.cpp | 196 | ||||
-rw-r--r-- | src/bzip2.h | 37 | ||||
-rw-r--r-- | src/client.cpp | 206 | ||||
-rw-r--r-- | src/client.h | 63 | ||||
-rw-r--r-- | src/entities/bu-class | 48 | ||||
-rw-r--r-- | src/exceptionbase.cpp | 16 | ||||
-rw-r--r-- | src/exceptionbase.h | 127 | ||||
-rw-r--r-- | src/exceptions.cpp | 15 | ||||
-rw-r--r-- | src/exceptions.h | 43 | ||||
-rw-r--r-- | src/file.cpp | 158 | ||||
-rw-r--r-- | src/file.h | 78 | ||||
-rw-r--r-- | src/filter.cpp | 97 | ||||
-rw-r--r-- | src/filter.h | 65 | ||||
-rw-r--r-- | src/fstring.cpp | 11 | ||||
-rw-r--r-- | src/fstring.h | 1304 | ||||
-rw-r--r-- | src/hash.cpp | 34 | ||||
-rw-r--r-- | src/hash.h | 1488 | ||||
-rw-r--r-- | src/hashable.cpp | 1 | ||||
-rw-r--r-- | src/hashable.h | 12 | ||||
-rw-r--r-- | src/hashfunction.cpp | 10 | ||||
-rw-r--r-- | src/hashfunction.h | 48 | ||||
-rw-r--r-- | src/hashfunctioncasestring.cpp | 39 | ||||
-rw-r--r-- | src/hashfunctioncasestring.h | 28 | ||||
-rw-r--r-- | src/hashfunctionint.cpp | 20 | ||||
-rw-r--r-- | src/hashfunctionint.h | 26 | ||||
-rw-r--r-- | src/hashfunctionstring.cpp | 51 | ||||
-rw-r--r-- | src/hashfunctionstring.h | 27 | ||||
-rw-r--r-- | src/hashtable.cpp | 424 | ||||
-rw-r--r-- | src/hashtable.h | 308 | ||||
-rw-r--r-- | src/inprogress/xmldocument.cpp | 9 | ||||
-rw-r--r-- | src/inprogress/xmldocument.h | 22 | ||||
-rw-r--r-- | src/inprogress/xmlnode.cpp | 9 | ||||
-rw-r--r-- | src/inprogress/xmlnode.h | 22 | ||||
-rw-r--r-- | src/inprogress/xmlreader.cpp | 267 | ||||
-rw-r--r-- | src/inprogress/xmlreader.h | 121 | ||||
-rw-r--r-- | src/inprogress/xmlwriter.cpp | 9 | ||||
-rw-r--r-- | src/inprogress/xmlwriter.h | 22 | ||||
-rw-r--r-- | src/ito.cpp | 40 | ||||
-rw-r--r-- | src/ito.h | 98 | ||||
-rw-r--r-- | src/itoatom.h | 56 | ||||
-rw-r--r-- | src/itocondition.cpp | 42 | ||||
-rw-r--r-- | src/itocondition.h | 81 | ||||
-rw-r--r-- | src/itomutex.cpp | 27 | ||||
-rw-r--r-- | src/itomutex.h | 61 | ||||
-rw-r--r-- | src/itoqueue.h | 231 | ||||
-rw-r--r-- | src/linkmessage.cpp | 7 | ||||
-rw-r--r-- | src/linkmessage.h | 59 | ||||
-rw-r--r-- | src/list.cpp | 10 | ||||
-rw-r--r-- | src/list.h | 574 | ||||
-rw-r--r-- | src/logger.cpp | 131 | ||||
-rw-r--r-- | src/logger.h | 112 | ||||
-rw-r--r-- | src/main.dox | 14 | ||||
-rw-r--r-- | src/membuf.cpp | 120 | ||||
-rw-r--r-- | src/membuf.h | 53 | ||||
-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.cpp | 10 | ||||
-rw-r--r-- | src/old/list.h | 101 | ||||
-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.cpp | 20 | ||||
-rw-r--r-- | src/old/protocol.h | 62 | ||||
-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.cpp | 116 | ||||
-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.cpp | 98 | ||||
-rw-r--r-- | src/paramproc.h | 265 | ||||
-rw-r--r-- | src/plugger.h | 316 | ||||
-rw-r--r-- | src/programchain.cpp | 49 | ||||
-rw-r--r-- | src/programchain.h | 163 | ||||
-rw-r--r-- | src/programlink.cpp | 14 | ||||
-rw-r--r-- | src/programlink.h | 165 | ||||
-rw-r--r-- | src/protocol.cpp | 16 | ||||
-rw-r--r-- | src/protocol.h | 67 | ||||
-rw-r--r-- | src/ringbuffer.cpp | 2 | ||||
-rw-r--r-- | src/ringbuffer.h | 97 | ||||
-rw-r--r-- | src/serializable.cpp | 8 | ||||
-rw-r--r-- | src/serializable.h | 34 | ||||
-rw-r--r-- | src/serializer.cpp | 338 | ||||
-rw-r--r-- | src/serializer.h | 80 | ||||
-rw-r--r-- | src/server.cpp | 96 | ||||
-rw-r--r-- | src/server.h | 61 | ||||
-rw-r--r-- | src/serversocket.cpp | 158 | ||||
-rw-r--r-- | src/serversocket.h | 39 | ||||
-rw-r--r-- | src/sfile.cpp | 74 | ||||
-rw-r--r-- | src/sfile.h | 29 | ||||
-rw-r--r-- | src/singleton.h | 101 | ||||
-rw-r--r-- | src/socket.cpp | 294 | ||||
-rw-r--r-- | src/socket.h | 55 | ||||
-rw-r--r-- | src/sptr.cpp | 2 | ||||
-rw-r--r-- | src/sptr.h | 272 | ||||
-rw-r--r-- | src/stream.cpp | 4 | ||||
-rw-r--r-- | src/stream.h | 148 | ||||
-rw-r--r-- | src/tafnode.cpp | 165 | ||||
-rw-r--r-- | src/tafnode.h | 94 | ||||
-rw-r--r-- | src/tafreader.cpp | 155 | ||||
-rw-r--r-- | src/tafreader.h | 35 | ||||
-rw-r--r-- | src/tafwriter.cpp | 70 | ||||
-rw-r--r-- | src/tafwriter.h | 30 | ||||
-rw-r--r-- | src/tests/archive.cpp | 16 | ||||
-rw-r--r-- | src/tests/atom.cpp | 25 | ||||
-rw-r--r-- | src/tests/bzip2.cpp | 23 | ||||
-rw-r--r-- | src/tests/constsptr.cpp | 94 | ||||
-rw-r--r-- | src/tests/constsptr2.cpp | 30 | ||||
-rw-r--r-- | src/tests/fstring.cpp | 108 | ||||
-rw-r--r-- | src/tests/hash.cpp | 120 | ||||
-rw-r--r-- | src/tests/itoqueue1.cpp | 110 | ||||
-rw-r--r-- | src/tests/itoqueue2.cpp | 83 | ||||
-rw-r--r-- | src/tests/list.cpp | 53 | ||||
-rw-r--r-- | src/tests/logger.cpp | 28 | ||||
-rw-r--r-- | src/tests/ringbuffer.cpp | 29 | ||||
-rw-r--r-- | src/tests/taf.cpp | 24 | ||||
-rw-r--r-- | src/unit/entities/unit | 30 | ||||
-rw-r--r-- | src/unit/file.cpp | 111 | ||||
-rw-r--r-- | src/unit/fstring.cpp | 28 | ||||
-rw-r--r-- | src/unit/hash.cpp | 40 | ||||
-rw-r--r-- | src/unit/membuf.cpp | 37 | ||||
-rw-r--r-- | src/unit/taf.cpp | 48 | ||||
-rw-r--r-- | src/unitsuite.cpp | 67 | ||||
-rw-r--r-- | src/unitsuite.h | 96 | ||||
-rw-r--r-- | test.taf | 7 | ||||
-rw-r--r-- | tests/comments.xml | 12 | ||||
-rw-r--r-- | tests/guy.cpp | 22 | ||||
-rwxr-xr-x | tests/makeplugin.sh | 3 |
251 files changed, 11269 insertions, 4473 deletions
@@ -74,9 +74,9 @@ QUIET = NO | |||
74 | WARNINGS = YES | 74 | WARNINGS = YES |
75 | WARN_IF_UNDOCUMENTED = YES | 75 | WARN_IF_UNDOCUMENTED = YES |
76 | WARN_IF_DOC_ERROR = YES | 76 | WARN_IF_DOC_ERROR = YES |
77 | WARN_NO_PARAMDOC = NO | 77 | WARN_NO_PARAMDOC = YES |
78 | WARN_FORMAT = "$file:$line: $text" | 78 | WARN_FORMAT = "$file:$line: $text" |
79 | WARN_LOGFILE = | 79 | WARN_LOGFILE = Doxywarn |
80 | #--------------------------------------------------------------------------- | 80 | #--------------------------------------------------------------------------- |
81 | # configuration options related to the input files | 81 | # configuration options related to the input files |
82 | #--------------------------------------------------------------------------- | 82 | #--------------------------------------------------------------------------- |
@@ -0,0 +1 @@ | |||
src/bu/ \ No newline at end of file | |||
@@ -1,13 +1,20 @@ | |||
1 | # This is a build file for libbu++ | 1 | # This is a build file for libbu++ |
2 | 2 | ||
3 | default action: check "libbu++.a" | 3 | default 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 | ||
9 | set "CXXFLAGS" += "-ggdb -Wall" | 7 | set "CXXFLAGS" += "-ggdb -Wall" |
10 | 8 | ||
9 | #set "CXXFLAGS" += "-pg" | ||
10 | #set "LDFLAGS" += "-pg" | ||
11 | |||
12 | filesIn("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" | |||
17 | directoriesIn("src/tests","tests/"): | 24 | directoriesIn("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/"): | |||
25 | filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"): | 33 | filesIn("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 | |||
44 | filesIn("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 | |||
35 | rule "exe": | 57 | rule "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 | |||
73 | rule "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] | ||
2 | FileName=fstringtest.dev | ||
3 | Name=fstringtest | ||
4 | UnitCount=1 | ||
5 | Type=1 | ||
6 | Ver=1 | ||
7 | ObjFiles= | ||
8 | Includes=z:\home\neonphog\wine_documents\libbu++\src\bu | ||
9 | Libs= | ||
10 | PrivateResource= | ||
11 | ResourceIncludes= | ||
12 | MakeIncludes= | ||
13 | Compiler= | ||
14 | CppCompiler=_@@_ | ||
15 | Linker=libbu++.a_@@_ | ||
16 | IsCpp=1 | ||
17 | Icon= | ||
18 | ExeOutput= | ||
19 | ObjectOutput= | ||
20 | OverrideOutput=0 | ||
21 | OverrideOutputName=fstringtest.exe | ||
22 | HostApplication= | ||
23 | Folders= | ||
24 | CommandLine= | ||
25 | UseCustomMakefile=0 | ||
26 | CustomMakefile= | ||
27 | IncludeVersionInfo=0 | ||
28 | SupportXPThemes=0 | ||
29 | CompilerSet=0 | ||
30 | CompilerSettings=0000000000000000000000 | ||
31 | |||
32 | [VersionInfo] | ||
33 | Major=0 | ||
34 | Minor=1 | ||
35 | Release=1 | ||
36 | Build=1 | ||
37 | LanguageID=1033 | ||
38 | CharsetID=1252 | ||
39 | CompanyName= | ||
40 | FileVersion= | ||
41 | FileDescription=Developed using the Dev-C++ IDE | ||
42 | InternalName= | ||
43 | LegalCopyright= | ||
44 | LegalTrademarks= | ||
45 | OriginalFilename= | ||
46 | ProductName= | ||
47 | ProductVersion= | ||
48 | AutoIncBuildNr=0 | ||
49 | |||
50 | [Unit1] | ||
51 | FileName=src\tests\fstring.cpp | ||
52 | CompileCpp=1 | ||
53 | Folder=fstringtest | ||
54 | Compile=1 | ||
55 | Link=1 | ||
56 | Priority=1000 | ||
57 | OverrideBuildCmd=0 | ||
58 | BuildCmd= | ||
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] | ||
2 | FileName=libbu++.dev | ||
3 | Name=libbu++ | ||
4 | UnitCount=16 | ||
5 | Type=2 | ||
6 | Ver=1 | ||
7 | ObjFiles= | ||
8 | Includes=z:\home\neonphog\wine_documents\libbu++\src\bu | ||
9 | Libs= | ||
10 | PrivateResource= | ||
11 | ResourceIncludes= | ||
12 | MakeIncludes= | ||
13 | Compiler= | ||
14 | CppCompiler= | ||
15 | Linker= | ||
16 | IsCpp=1 | ||
17 | Icon= | ||
18 | ExeOutput= | ||
19 | ObjectOutput= | ||
20 | OverrideOutput=0 | ||
21 | OverrideOutputName=libbu++.a | ||
22 | HostApplication= | ||
23 | Folders= | ||
24 | CommandLine= | ||
25 | UseCustomMakefile=0 | ||
26 | CustomMakefile= | ||
27 | IncludeVersionInfo=0 | ||
28 | SupportXPThemes=0 | ||
29 | CompilerSet=0 | ||
30 | CompilerSettings=0000000000000000000000 | ||
31 | |||
32 | [Unit1] | ||
33 | FileName=src\stream.cpp | ||
34 | CompileCpp=1 | ||
35 | Folder=libbu++ | ||
36 | Compile=1 | ||
37 | Link=1 | ||
38 | Priority=1000 | ||
39 | OverrideBuildCmd=0 | ||
40 | BuildCmd= | ||
41 | |||
42 | [VersionInfo] | ||
43 | Major=0 | ||
44 | Minor=1 | ||
45 | Release=1 | ||
46 | Build=1 | ||
47 | LanguageID=1033 | ||
48 | CharsetID=1252 | ||
49 | CompanyName= | ||
50 | FileVersion= | ||
51 | FileDescription=Developed using the Dev-C++ IDE | ||
52 | InternalName= | ||
53 | LegalCopyright= | ||
54 | LegalTrademarks= | ||
55 | OriginalFilename= | ||
56 | ProductName= | ||
57 | ProductVersion= | ||
58 | AutoIncBuildNr=0 | ||
59 | |||
60 | [Unit2] | ||
61 | FileName=src\stream.h | ||
62 | CompileCpp=1 | ||
63 | Folder=libbu++ | ||
64 | Compile=1 | ||
65 | Link=1 | ||
66 | Priority=1000 | ||
67 | OverrideBuildCmd=0 | ||
68 | BuildCmd= | ||
69 | |||
70 | [Unit3] | ||
71 | FileName=src\file.cpp | ||
72 | CompileCpp=1 | ||
73 | Folder=libbu++ | ||
74 | Compile=1 | ||
75 | Link=1 | ||
76 | Priority=1000 | ||
77 | OverrideBuildCmd=0 | ||
78 | BuildCmd= | ||
79 | |||
80 | [Unit4] | ||
81 | FileName=src\file.h | ||
82 | CompileCpp=1 | ||
83 | Folder=libbu++ | ||
84 | Compile=1 | ||
85 | Link=1 | ||
86 | Priority=1000 | ||
87 | OverrideBuildCmd=0 | ||
88 | BuildCmd= | ||
89 | |||
90 | [Unit5] | ||
91 | FileName=src\fstring.h | ||
92 | CompileCpp=1 | ||
93 | Folder=libbu++ | ||
94 | Compile=1 | ||
95 | Link=1 | ||
96 | Priority=1000 | ||
97 | OverrideBuildCmd=0 | ||
98 | BuildCmd= | ||
99 | |||
100 | [Unit6] | ||
101 | FileName=src\fstring.cpp | ||
102 | CompileCpp=1 | ||
103 | Folder=libbu++ | ||
104 | Compile=1 | ||
105 | Link=1 | ||
106 | Priority=1000 | ||
107 | OverrideBuildCmd=0 | ||
108 | BuildCmd= | ||
109 | |||
110 | [Unit7] | ||
111 | FileName=src\archival.cpp | ||
112 | CompileCpp=1 | ||
113 | Folder=libbu++ | ||
114 | Compile=1 | ||
115 | Link=1 | ||
116 | Priority=1000 | ||
117 | OverrideBuildCmd=0 | ||
118 | BuildCmd= | ||
119 | |||
120 | [Unit8] | ||
121 | FileName=src\archival.h | ||
122 | CompileCpp=1 | ||
123 | Folder=libbu++ | ||
124 | Compile=1 | ||
125 | Link=1 | ||
126 | Priority=1000 | ||
127 | OverrideBuildCmd=0 | ||
128 | BuildCmd= | ||
129 | |||
130 | [Unit9] | ||
131 | FileName=src\archive.cpp | ||
132 | CompileCpp=1 | ||
133 | Folder=libbu++ | ||
134 | Compile=1 | ||
135 | Link=1 | ||
136 | Priority=1000 | ||
137 | OverrideBuildCmd=0 | ||
138 | BuildCmd= | ||
139 | |||
140 | [Unit10] | ||
141 | FileName=src\archive.h | ||
142 | CompileCpp=1 | ||
143 | Folder=libbu++ | ||
144 | Compile=1 | ||
145 | Link=1 | ||
146 | Priority=1000 | ||
147 | OverrideBuildCmd=0 | ||
148 | BuildCmd= | ||
149 | |||
150 | [Unit11] | ||
151 | FileName=src\hash.h | ||
152 | CompileCpp=1 | ||
153 | Folder=libbu++ | ||
154 | Compile=1 | ||
155 | Link=1 | ||
156 | Priority=1000 | ||
157 | OverrideBuildCmd=0 | ||
158 | BuildCmd= | ||
159 | |||
160 | [Unit12] | ||
161 | FileName=src\hash.cpp | ||
162 | CompileCpp=1 | ||
163 | Folder=libbu++ | ||
164 | Compile=1 | ||
165 | Link=1 | ||
166 | Priority=1000 | ||
167 | OverrideBuildCmd=0 | ||
168 | BuildCmd= | ||
169 | |||
170 | [Unit13] | ||
171 | FileName=src\exceptionbase.cpp | ||
172 | CompileCpp=1 | ||
173 | Folder=libbu++ | ||
174 | Compile=1 | ||
175 | Link=1 | ||
176 | Priority=1000 | ||
177 | OverrideBuildCmd=0 | ||
178 | BuildCmd= | ||
179 | |||
180 | [Unit14] | ||
181 | FileName=src\exceptionbase.h | ||
182 | CompileCpp=1 | ||
183 | Folder=libbu++ | ||
184 | Compile=1 | ||
185 | Link=1 | ||
186 | Priority=1000 | ||
187 | OverrideBuildCmd=0 | ||
188 | BuildCmd= | ||
189 | |||
190 | [Unit15] | ||
191 | FileName=src\list.cpp | ||
192 | CompileCpp=1 | ||
193 | Folder=libbu++ | ||
194 | Compile=1 | ||
195 | Link=1 | ||
196 | Priority=1000 | ||
197 | OverrideBuildCmd=0 | ||
198 | BuildCmd= | ||
199 | |||
200 | [Unit16] | ||
201 | FileName=src\list.h | ||
202 | CompileCpp=1 | ||
203 | Folder=libbu++ | ||
204 | Compile=1 | ||
205 | Link=1 | ||
206 | Priority=1000 | ||
207 | OverrideBuildCmd=0 | ||
208 | BuildCmd= | ||
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"> | ||
2 | code { font-family: monospace; } | ||
3 | |||
4 | div.constraint, | ||
5 | div.issue, | ||
6 | div.note, | ||
7 | div.notice { margin-left: 2em; } | ||
8 | |||
9 | li p { margin-top: 0.3em; | ||
10 | margin-bottom: 0.3em; } | ||
11 | |||
12 | div.exampleInner pre { margin-left: 1em; | ||
13 | margin-top: 0em; margin-bottom: 0em} | ||
14 | div.exampleOuter {border: 4px double gray; | ||
15 | margin: 0em; padding: 0em} | ||
16 | div.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 } | ||
24 | div.exampleWrapper { margin: 4px } | ||
25 | div.exampleHeader { font-weight: bold; | ||
26 | margin: 4px} | ||
27 | |||
28 | em.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"><tbray@textuality.com></a></dd><dd>Jean Paoli, Microsoft <a href="mailto:jeanpa@microsoft.com"><jeanpa@microsoft.com></a></dd><dd>C. M. Sperberg-McQueen, W3C <a href="mailto:cmsmcq@w3.org"><cmsmcq@w3.org></a></dd><dd>Eve Maler, Sun Microsystems, Inc. <a href="mailto:elm@east.sun.com"><eve.maler@east.sun.com></a></dd><dd>François Yergeau <a href="mailto:fyergeau@alis.com"><fyergeau@alis.com></a></dd><dd>John Cowan <a href="mailto:cowan@ccil.org"><cowan@ccil.org></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 | ||
35 | described in this document. Its goal is to enable generic SGML to be served, | ||
36 | received, and processed on the Web in the way that is now possible with HTML. | ||
37 | XML has been designed for ease of implementation and for interoperability | ||
38 | with 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. | ||
39 | It has been reviewed by W3C Members and other interested parties, and has | ||
40 | been 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 | ||
41 | Recommendation is to draw attention to the specification and to promote its widespread deployment. | ||
42 | This enhances the functionality and interoperability of the Web.</p><p>This document specifies a syntax created by subsetting an existing, widely | ||
43 | used international text processing standard (Standard Generalized Markup Language, | ||
44 | ISO 8879:1986(E) as amended and corrected) for use on the World Wide Web. | ||
45 | It 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 | ||
50 | missing spaces to <a | ||
51 | href="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, | ||
55 | for 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 | ||
57 | may 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 | ||
59 | at <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 | ||
60 | objects called <a title="XML Document" href="#dt-xml-doc">XML documents</a> and partially | ||
61 | describes the behavior of computer programs which process them. XML is an | ||
62 | application profile or restricted form of SGML, the Standard Generalized Markup | ||
63 | Language <a href="#ISO8879">[ISO 8879]</a>. By construction, XML documents are conforming | ||
64 | SGML documents.</p><p>XML documents are made up of storage units called <a title="Entity" href="#dt-entity">entities</a>, | ||
65 | which 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 | ||
66 | data</a>, and some of which form <a title="Markup" href="#dt-markup">markup</a>. | ||
67 | Markup encodes a description of the document's storage layout and logical | ||
68 | structure. XML provides a mechanism to impose constraints on the storage layout | ||
69 | and logical structure.</p><p>[<a name="dt-xml-proc" id="dt-xml-proc" title="XML Processor">Definition</a>: A software module called | ||
70 | an <b>XML processor</b> is used to read XML documents and provide access | ||
71 | to their content and structure.] [<a name="dt-app" id="dt-app" title="Application">Definition</a>: It | ||
72 | is assumed that an XML processor is doing its work on behalf of another module, | ||
73 | called the <b>application</b>.] This specification describes | ||
74 | the required behavior of an XML processor in terms of how it must read XML | ||
75 | data 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 | ||
76 | Editorial 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 | ||
78 | participation of an XML Special Interest Group (previously known as the SGML | ||
79 | Working Group) also organized by the W3C. The membership of the XML Working | ||
80 | Group is given in an appendix. Dan Connolly served as the Working Group's contact with | ||
81 | the 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 | ||
82 | minimum, 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> | ||
84 | for characters, Internet RFC 3066 <a href="#RFC1766">[IETF RFC 3066]</a> for | ||
85 | language identification tags, ISO 639 <a href="#ISO639">[ISO 639]</a> | ||
86 | for language name codes, and ISO 3166 <a href="#ISO3166">[ISO 3166]</a> for | ||
87 | country name codes), provides all the information necessary to | ||
88 | understand XML Version 1.1 and construct computer | ||
89 | programs to process it.</p><p>This version of the XML specification may be distributed freely, as long as | ||
90 | all 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 | ||
91 | this 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 | ||
92 | those 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; | ||
93 | results 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 | ||
94 | and <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. | ||
95 | After encountering a fatal error, the processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> continue processing the | ||
96 | data to search for further errors and <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> report such errors to the application. | ||
97 | In order to support correction of errors, the processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> make unprocessed | ||
98 | data from the document (with intermingled character data and markup) available | ||
99 | to 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 | ||
101 | data and information about the document's logical structure to the application | ||
102 | in 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; | ||
104 | if it does, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> provide users a means to enable or disable the behavior | ||
105 | described.]</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 | ||
106 | all <a title="Validity" href="#dt-valid">valid</a> XML documents. Violations of validity | ||
107 | constraints 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 | ||
108 | to all <a title="Well-Formed" href="#dt-wellformed">well-formed</a> XML documents. Violations | ||
109 | of 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 | ||
110 | or names being compared <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be identical. Characters with multiple possible | ||
111 | representations in Unicode (e.g. characters with both precomposed and | ||
112 | base+diacritic forms) match only if they have the same representation in both | ||
113 | strings. No | ||
114 | case folding is performed. (Of strings and rules in the grammar:) A string | ||
115 | matches a grammatical production if it belongs to the language generated by | ||
116 | that production. (Of content and content models:) An element matches its declaration | ||
117 | when 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 | ||
118 | a sentence describing a feature of XML included solely to ensure | ||
119 | that 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 | ||
120 | a sentence describing a non-binding recommendation included to increase | ||
121 | the chances that XML documents can be processed by the existing installed | ||
122 | base 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 | ||
123 | despite the issuance of many errata culminating in a Third Edition | ||
124 | of 2004, has remained (by intention) unchanged with respect to what | ||
125 | is well-formed XML and what is not. This stability has been | ||
126 | extremely useful for interoperability. However, the Unicode | ||
127 | Standard on which XML 1.0 relies for character specifications has | ||
128 | not remained static, evolving from version 2.0 to version 4.0 and | ||
129 | beyond. Characters not present in Unicode 2.0 may already be used | ||
130 | in XML 1.0 character data. However, they are not allowed in XML | ||
131 | names such as element type names, attribute names, enumerated | ||
132 | attribute values, processing instruction targets, and so on. In | ||
133 | addition, some characters that should have been permitted in XML | ||
134 | names were not, due to oversights and inconsistencies in Unicode | ||
135 | 2.0.</p><p>The overall philosophy of names has changed since XML 1.0. | ||
136 | Whereas XML 1.0 provided a rigid definition of names, wherein | ||
137 | everything that was not permitted was forbidden, XML 1.1 names are | ||
138 | designed so that everything that is not forbidden (for a specific | ||
139 | reason) is permitted. Since Unicode will continue to grow past | ||
140 | version 4.0, further changes to XML can be avoided by allowing | ||
141 | almost any character, including those not yet assigned, in | ||
142 | names.</p><p>In addition, XML 1.0 attempts to adapt to the line-end | ||
143 | conventions of various modern operating systems, but discriminates | ||
144 | against the conventions used on IBM and IBM-compatible mainframes. | ||
145 | As a result, XML documents on mainframes are not plain text files | ||
146 | according to the local conventions. XML 1.0 documents generated on | ||
147 | mainframes must either violate the local line-end conventions, or | ||
148 | employ otherwise unnecessary translation phases before parsing and | ||
149 | after generation. Allowing straightforward interoperability is | ||
150 | particularly important when data stores are shared between | ||
151 | mainframe and non-mainframe systems (as opposed to being copied | ||
152 | from one to the other). Therefore XML 1.1 adds NEL (#x85) to the | ||
153 | list of line-end characters. For completeness, the Unicode line | ||
154 | separator character, #x2028, is also supported. | ||
155 | </p><p>Finally, there is considerable demand to define a standard representation | ||
156 | of arbitrary Unicode characters in XML documents. Therefore, XML 1.1 | ||
157 | allows 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, | ||
159 | however, these characters still cannot be used directly in documents. In | ||
160 | order to improve the robustness of character encoding detection, the additional | ||
161 | control characters #x7F through #x9F, which were freely allowed in XML 1.0 | ||
162 | documents, now must also appear only as character references. (Whitespace | ||
163 | characters are of course exempt.) The minor sacrifice of backward compatibility | ||
164 | is 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 | ||
167 | normalization" 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 | ||
170 | ensures that identity comparisons of names, attribute values, and | ||
171 | character content can be made correctly by simple binary comparison of | ||
172 | Unicode strings.</p><p>A new XML version, rather than a set of errata to XML 1.0, is | ||
173 | being created because the changes affect the definition of | ||
174 | well-formed documents. XML 1.0 processors must continue to reject | ||
175 | documents that contain new characters in XML names, new line-end | ||
176 | conventions, and references to control characters. The distinction between XML 1.0 and XML 1.1 documents | ||
177 | is indicated by the version number information in the XML | ||
178 | declaration 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 | ||
180 | document</b> if it is <a title="Well-Formed" href="#dt-wellformed">well-formed</a>, | ||
181 | as defined in this specification. A well-formed XML document <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> in addition | ||
182 | be <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, | ||
183 | the document is composed of units called <a title="Entity" href="#dt-entity">entities</a>. | ||
184 | An 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 | ||
185 | cause their inclusion in the document. A document begins in a "root" | ||
186 | or <a title="Document Entity" href="#dt-docent">document entity</a>. Logically, the document | ||
187 | is composed of declarations, elements, comments, character references, and | ||
188 | processing instructions, all of which are indicated in the document by explicit | ||
189 | markup. The logical and physical structures <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> nest properly, as described | ||
190 | in <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> | ||
191 | XML 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> | ||
192 | which is referenced directly or indirectly within the document is <a | ||
193 | title="Well-Formed" | ||
194 | href="#dt-wellformed">well-formed</a>.</p></li></ol> <h5><a | ||
195 | name="document" id="document" />Document</h5><table class="scrap" | ||
196 | summary="Scrap"><tbody><tr valign="baseline"><td><a name="NT-document" | ||
197 | id="NT-document" | ||
198 | />[1]Â Â Â </td><td><code>document</code></td><td>Â Â Â ::=Â Â Â </td><td><code><a | ||
199 | href="#NT-prolog">prolog</a> <a href="#NT-element">element</a> <a | ||
200 | href="#NT-Misc">Misc</a>* - <a href="#NT-Char">Char</a>* <a | ||
201 | href="#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, | ||
202 | called the <b>root</b>, or document element, no part of which appears | ||
203 | in the <a title="Content" href="#dt-content">content</a> of any other element.] For | ||
204 | all other elements, if the <a title="Start-Tag" href="#dt-stag">start-tag</a> is in | ||
205 | the content of another element, the <a title="End Tag" href="#dt-etag">end-tag</a> | ||
206 | is in the content of the same element. More simply stated, the elements, | ||
207 | delimited 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, | ||
208 | for each non-root element <code>C</code> in the document, there is one other element <code>P</code> | ||
209 | in the document such that <code>C</code> is in the content of <code>P</code>, but | ||
210 | is not in the content of any other element that is in the content of <code>P</code>. <code>P</code> | ||
211 | is referred to as the <b>parent</b> of <code>C</code>, and <code>C</code> as | ||
212 | a <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>, | ||
213 | a sequence of <a title="Character" href="#dt-character">characters</a>, which may | ||
214 | represent markup or character data.] [<a name="dt-character" id="dt-character" title="Character">Definition</a>: A <b>character</b> | ||
215 | is 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 | ||
216 | return, line feed, and the legal characters | ||
217 | of Unicode and ISO/IEC 10646. The | ||
218 | versions of these standards cited in <a href="#sec-existing-stds"><b>A.1 Normative References</b></a> were | ||
219 | current at the time this document was prepared. New characters may be added | ||
220 | to 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> | ||
222 | vary 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 | ||
223 | encodings of <span> Unicode | ||
224 | <a href="#Unicode">[Unicode]</a></span>; | ||
225 | the mechanisms for signaling which of the two is in use, | ||
226 | or 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 | ||
228 | in Unicode <a href="#Unicode">[Unicode]</a>. | ||
229 | The characters defined in the following ranges are also | ||
230 | discouraged. They are either control characters or permanently undefined Unicode | ||
231 | characters:</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) | ||
239 | characters, 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 | ||
240 | maintained purely for backward compatibility with the | ||
241 | <a href="http://www.w3.org/TR/1998/REC-xml-19980210">First Edition</a>. | ||
242 | As explained in <a href="#sec-line-ends"><b>2.11 End-of-Line Handling</b></a>, | ||
243 | all #xD characters literally present in an XML document | ||
244 | are either removed or replaced by #xA characters before | ||
245 | any other processing is done. The only way to get a #xD character to match this production is to | ||
246 | use 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 | ||
247 | with a letter or one of a few punctuation characters, and continuing with | ||
248 | letters, digits, hyphens, underscores, colons, or full stops, together known | ||
249 | as name characters.] Names beginning with the string "<code>xml</code>", | ||
250 | or <span>with</span> any string which would match <code>(('X'|'x') ('M'|'m') ('L'|'l'))</code>, | ||
251 | are reserved for standardization in this or future versions of this specification.</p><div class="note"><p class="prefix"><b>Note:</b></p><p>The | ||
252 | Namespaces in XML Recommendation <a href="#xml-names">[XML Names]</a> assigns a meaning | ||
253 | to names containing colon characters. Therefore, authors should not use the | ||
254 | colon in XML names except for namespace purposes, but XML processors must | ||
255 | accept the colon as a name character.</p></div><p>An <a href="#NT-Nmtoken">Nmtoken</a> (name token) is any mixture of name | ||
256 | characters.</p><p>The first character of a Name <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be a NameStartChar, and any | ||
257 | other characters <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be NameChars; this mechanism is used to | ||
258 | prevent names from beginning with European (ASCII) digits or with | ||
259 | basic combining characters. Almost all characters are permitted in | ||
260 | names, except those which either are or reasonably could be used as | ||
261 | delimiters. The intention is to be inclusive rather than exclusive, | ||
262 | so that writing systems not yet encoded in Unicode can be used in | ||
263 | XML names. See <a href="#sec-suggested-names"><b>I Suggestions for XML Names</b></a> for suggestions on the creation of | ||
264 | names.</p><p>Document authors are encouraged to use names which are | ||
265 | meaningful words or combinations of words in natural languages, and | ||
266 | to avoid symbolic or white space characters in names. Note that | ||
267 | COLON, HYPHEN-MINUS, FULL STOP (period), LOW LINE (underscore), and | ||
268 | MIDDLE DOT are explicitly permitted.</p><p>The ASCII symbols and punctuation marks, along with a fairly | ||
269 | large group of Unicode symbol characters, are excluded from names | ||
270 | because they are more useful as delimiters in contexts where XML | ||
271 | names are used outside XML documents; providing this group gives | ||
272 | those contexts hard guarantees about what <em>cannot</em> be part of | ||
273 | an XML name. The character #x037E, GREEK QUESTION MARK, is excluded | ||
274 | because when normalized it becomes a semicolon, which could change | ||
275 | the 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> | ||
276 | and <a href="#NT-Nmtokens">Nmtokens</a> productions are used to define the validity | ||
277 | of 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 | ||
278 | as a delimiter for that string. Literals are used for specifying the content | ||
279 | of internal entities (<a href="#NT-EntityValue">EntityValue</a>), the values | ||
280 | of 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> | ||
282 | can 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>'"' ([^%&"] | <a href="#NT-PEReference">PEReference</a> | ||
283 | | <a href="#NT-Reference">Reference</a>)* '"' </code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>|Â "'" ([^%&'] | <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>'"' ([^<&"] | <a href="#NT-Reference">Reference</a>)* | ||
284 | '"' </code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>|Â "'" ([^<&'] | <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 | ||
287 | the <a href="#NT-EntityValue">EntityValue</a> production allows the definition | ||
288 | of a general entity consisting of a single explicit <code><</code> in the literal | ||
289 | (e.g., <code><!ENTITY mylt "<"></code>), it is strongly advised to avoid | ||
290 | this practice since any reference to that entity will cause a well-formedness | ||
291 | error.</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 | ||
292 | references</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 | ||
293 | type 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>, | ||
294 | and any white space that is at the top level of the document entity (that | ||
295 | is, 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 | ||
296 | constitutes the <b>character data</b> of the document.]</p><p>The ampersand character (&) and the left angle bracket (<) <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> appear | ||
297 | in their literal form<span class="mustard">, except</span> when used as markup delimiters, or | ||
298 | within a <a title="Comment" href="#dt-comment">comment</a>, a <a title="Processing instruction" href="#dt-pi">processing | ||
299 | instruction</a>, or a <a title="CDATA Section" href="#dt-cdsection">CDATA section</a>. | ||
300 | |||
301 | If 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> | ||
302 | using either <a title="Character Reference" href="#dt-charref">numeric character references</a> | ||
303 | or the strings "<code>&amp;</code>" and "<code>&lt;</code>" | ||
304 | respectively. The right angle bracket (>) <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be represented using the string "<code>&gt;</code>", | ||
305 | and <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>, <a title="For Compatibility" href="#dt-compat">for compatibility</a>, be escaped | ||
306 | using <span>either</span> "<code>&gt;</code>" or a character reference when it | ||
307 | appears in the string "<code>]]></code>" in content, when | ||
308 | that string is not marking the end of a <a title="CDATA Section" href="#dt-cdsection">CDATA | ||
309 | section</a>.</p><p>In the content of elements, character data is any string of characters | ||
310 | which does not contain the start-delimiter of any markup or the | ||
311 | CDATA-section-close delimiter, | ||
312 | "<code>]]></code>". | ||
313 | In a CDATA section, | ||
314 | character data is any string of characters not including the CDATA-section-close | ||
315 | delimiter.</p><p>To allow attribute values to contain both single and double quotes, the | ||
316 | apostrophe or single-quote character (') <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be represented as "<code>&apos;</code>", | ||
317 | and the double-quote character (") as "<code>&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>[^<&]* - ([^<&]* ']]>' [^<&]*)</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 | ||
318 | anywhere in a document outside other <a title="Markup" href="#dt-markup">markup</a>; | ||
319 | in addition, they <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> appear within the document type declaration at places | ||
320 | allowed by the grammar. They are not part of the document's <a title="Character Data" href="#dt-chardata">character | ||
321 | data</a>; an XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>, but need not, make it possible for an | ||
322 | application to retrieve the text of comments. <a title="For Compatibility" href="#dt-compat">For | ||
323 | compatibility</a>, the string "<code>--</code>" (double-hyphen) | ||
324 | <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> occur within comments.] Parameter | ||
325 | entity 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>'<!--' ((<a href="#NT-Char">Char</a> - '-') | ('-' | ||
326 | (<a href="#NT-Char">Char</a> - '-')))* '-->'</code></td></tr></tbody></table><p>An example of a comment:</p><div class="exampleInner"><pre><!-- declarations for <head> & <body> --></pre></div><p>Note | ||
327 | that the grammar does not allow a comment ending in <code>---></code>. The | ||
328 | following example is <em>not</em> well-formed.</p><div class="exampleInner"><pre><!-- B+, B, or B---></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>'<?' <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>* '?>' <a href="#NT-Char">Char</a>*)))? '?>'</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 | ||
332 | data</a>, but <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be passed through to the application. The PI begins | ||
333 | with a target (<a href="#NT-PITarget">PITarget</a>) used to identify the application | ||
334 | to which the instruction is directed. The target names "<code>XML</code>", "<code>xml</code>", | ||
335 | and so on are reserved for standardization in this or future versions of this | ||
336 | specification. 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 | ||
338 | entity 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 | ||
339 | of text containing characters which would otherwise be recognized as markup. | ||
340 | CDATA sections begin with the string "<code><![CDATA[</code>" | ||
341 | and end with the string "<code>]]></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>'<![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 | ']]>' <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>']]>'</code></td></tr></tbody></table><p>Within a CDATA section, only the <a href="#NT-CDEnd">CDEnd</a> string is | ||
343 | recognized as markup, so that left angle brackets and ampersands may occur | ||
344 | in their literal form; they need not (and cannot) be escaped using "<code>&lt;</code>" | ||
345 | and "<code>&amp;</code>". CDATA sections cannot nest.</p><p>An example of a CDATA section, in which "<code><greeting></code>" | ||
346 | and "<code></greeting></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><![CDATA[<greeting>Hello, world!</greeting>]]> </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> | ||
347 | begin with an <b>XML declaration</b> which specifies the version of | ||
348 | XML 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><?xml version="1.1"?> | ||
349 | <greeting>Hello, world!</greeting> </pre></div><p>but the following is an XML 1.0 document because it | ||
350 | does not have an XML declaration:</p><div class="exampleInner"><pre><greeting>Hello, world!</greeting></pre></div><p>The function of the markup in an XML document is to describe its storage and | ||
351 | logical structure and to associate <span>attribute | ||
352 | name-value</span> pairs with its logical structures. XML provides a mechanism, the | ||
353 | <a title="Document Type Declaration" href="#dt-doctype">document | ||
354 | type declaration</a>, to define constraints on the logical structure | ||
355 | and 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 | ||
356 | document type declaration and if the document complies with the constraints | ||
357 | expressed 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> | ||
358 | in 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>'<?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>?'?>'</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 | ||
363 | type declaration</b> contains or points to <a title="markup declaration" href="#dt-markupdecl">markup | ||
364 | declarations</a> that provide a grammar for a class of documents. This | ||
365 | grammar is known as a document type definition, or <b>DTD</b>. The document | ||
366 | type declaration can point to an external subset (a special kind of <a title="External Entity" href="#dt-extent">external entity</a>) containing markup declarations, | ||
367 | or can contain the markup declarations directly in an internal subset, or | ||
368 | can 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> | ||
369 | is 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 | ||
370 | declaration</a>, or a <a title="Notation Declaration" href="#dt-notdecl">notation declaration</a>.] | ||
371 | These 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 | ||
372 | entities</a>, as described in the well-formedness and validity constraints | ||
373 | below. For further | ||
374 | information, 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>'<!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>?)? '>'</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 | ||
378 | that it is possible to construct a well-formed document containing a <a href="#NT-doctypedecl">doctypedecl</a> | ||
379 | that 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 | ||
380 | entities</a>. The productions later in this specification for individual | ||
381 | nonterminals (<a href="#NT-elementdecl">elementdecl</a>, <a href="#NT-AttlistDecl">AttlistDecl</a>, | ||
382 | and so on) describe the declarations <em>after</em> all the parameter | ||
383 | entities have been <a title="Include" href="#dt-include">included</a>.</p><p>Parameter | ||
384 | entity references are recognized anywhere in the DTD (internal and external | ||
385 | subsets and external parameter entities), except in literals, processing instructions, | ||
386 | comments, and the contents of ignored conditional sections (see <a href="#sec-condition-sect"><b>3.4 Conditional Sections</b></a>). | ||
387 | They are also recognized in entity value literals. The use of parameter entities | ||
388 | in 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> | ||
389 | in 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 | ||
390 | the first character or the last character of a markup declaration (<a href="#NT-markupdecl">markupdecl</a> | ||
391 | above) is contained in the replacement text for a <a title="Parameter-entity reference" href="#dt-PERef">parameter-entity | ||
392 | reference</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 | ||
393 | the 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 | ||
395 | or 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 | ||
396 | in 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 | ||
397 | entities referenced | ||
398 | in a <a href="#NT-DeclSep">DeclSep</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> consist of a series of | ||
399 | complete 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 | ||
400 | the contents of the external subset or of these | ||
401 | external 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 | ||
402 | allowed in the internal subset<span> but is | ||
403 | allowed 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 | ||
404 | internal subset in that in them, <a title="Parameter-entity reference" href="#dt-PERef">parameter-entity | ||
405 | references</a> are permitted <em>within</em> markup declarations, | ||
406 | not only <em>between</em> markup declarations.</p><p>An example of an XML document with a document type declaration:</p><div class="exampleInner"><pre><?xml version="1.1"?> | ||
407 | <!DOCTYPE greeting SYSTEM "hello.dtd"> | ||
408 | <greeting>Hello, world!</greeting> </pre></div><p>The <a title="System Identifier" href="#dt-sysid">system identifier</a> "<code>hello.dtd</code>" | ||
409 | gives 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><?xml version="1.1" encoding="UTF-8" ?> | ||
410 | <!DOCTYPE greeting [ | ||
411 | <!ELEMENT greeting (#PCDATA)> | ||
412 | ]> | ||
413 | <greeting>Hello, world!</greeting></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. | ||
415 | This has the effect that entity and attribute-list declarations in the internal | ||
416 | subset 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 | ||
417 | documents as well. If a document is well-formed or valid XML 1.0, and provided it | ||
418 | does not contain any control characters | ||
419 | in the range [#x7F-#x9F] other than as character escapes, it may be | ||
420 | made well-formed or valid XML 1.1 respectively simply by changing the | ||
421 | version 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 | ||
422 | an <a title="XML Processor" href="#dt-xml-proc">XML processor</a> to an application; examples | ||
423 | are attribute defaults and entity declarations. The standalone document declaration, | ||
424 | which <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> appear as a component of the XML declaration, signals whether or | ||
425 | not there are such declarations which appear external to the <a title="Document Entity" href="#dt-docent">document | ||
426 | entity</a> | ||
427 | or in parameter entities. [<a name="dt-extmkpdecl" id="dt-extmkpdecl" title="External Markup Declaration">Definition</a>: An <b>external | ||
428 | markup declaration</b> is defined as a markup declaration occurring in | ||
429 | the external subset or in a parameter entity (external or internal, the latter | ||
430 | being included because non-validating processors are not required to read | ||
431 | them).]</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 | ||
433 | that there are no <a title="External Markup Declaration" href="#dt-extmkpdecl">external markup declarations</a> which | ||
434 | affect the information passed from the XML processor to the application. The | ||
435 | value "no" indicates that there are or may be such external | ||
436 | markup declarations. Note that the standalone document declaration only denotes | ||
437 | the presence of external <em>declarations</em>; the presence, in a document, | ||
438 | of references to external <em>entities</em>, when those entities are internally | ||
439 | declared, does not change its standalone status.</p><p>If there are no external markup declarations, the standalone document declaration | ||
440 | has no meaning. If there are external markup declarations but there is no | ||
441 | standalone document declaration, the value "no" is assumed.</p><p>Any XML document for which <code>standalone="no"</code> holds can be converted | ||
442 | algorithmically to a standalone document, which may be desirable for some | ||
443 | network 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 | ||
444 | standalone document declaration <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> have the value "no" if | ||
445 | any external markup declarations contain declarations of:</p><ul><li><p>attributes with <a title="Attribute Default" href="#dt-default">default</a> values, | ||
446 | if elements to which these attributes apply appear in the document without | ||
447 | specifications 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> | ||
452 | to those entities appear in the document, or</p></li><li><p>attributes with | ||
453 | tokenized types, where the | ||
454 | attribute appears in the document with a value such that | ||
455 | <a href="#AVNormalize"><cite>normalization</cite></a> | ||
456 | will produce a different value from that which would be produced | ||
457 | in the absence of the declaration, or</p></li><li><p>element types with <a title="Element content" href="#dt-elemcontent">element content</a>, | ||
458 | if 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><?xml version="1.1" standalone='yes'?></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) | ||
460 | to set apart the markup for greater readability. Such white space is typically | ||
461 | not intended for inclusion in the delivered version of the document. On the | ||
462 | other hand, "significant" white space that should be preserved | ||
463 | in 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 | ||
464 | all characters in a document that are not markup through to the application. | ||
465 | A <a title="Validating Processor" href="#dt-validating"> validating XML processor</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> also | ||
466 | inform the application which of these characters constitute white space appearing | ||
467 | in <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, | ||
468 | white space should be preserved by applications. In valid documents, this | ||
469 | 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> | ||
470 | if 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
Values" href="#dt-enumerated">enumerated | ||
471 | type</a> whose values | ||
472 | are one or both of "default" and "preserve". | ||
473 | For example:</p><div class="exampleInner"><pre><!ATTLIST poem xml:space (default|preserve) 'preserve'> | ||
474 | <!ATTLIST pre xml:space (preserve) #FIXED 'preserve'></pre></div><p>The value "default" signals that applications' default white-space | ||
475 | processing modes are acceptable for this element; the value "preserve" | ||
476 | indicates the intent that applications preserve all the white space. This | ||
477 | declared intent is considered to apply to all elements within the content | ||
478 | of the element where it is specified, unless <span>overridden</span> with | ||
479 | another 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 | ||
480 | to have signaled no intentions as regards application space handling, unless | ||
481 | it provides a value for this attribute or the attribute is declared with a | ||
482 | default 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 | ||
483 | in computer files which, for editing convenience, are organized into lines. | ||
484 | These lines are typically separated by some combination of the characters | ||
485 | CARRIAGE RETURN (#xD) and LINE FEED (#xA).</p><p>To | ||
486 | simplify the tasks of <a title="Application" href="#dt-app">applications</a>, the | ||
487 | <span><a title="XML Processor" href="#dt-xml-proc">XML | ||
488 | processor</a> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> behave as if it</span> normalized all line breaks in external parsed | ||
489 | entities (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 | ||
492 | translated until an entity's encoding declaration (if present) has | ||
493 | been read. Therefore, it is a fatal error to use them within the XML | ||
494 | declaration 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 | ||
496 | language in which the content is written. A special <a title="Attribute" href="#dt-attr">attribute</a> | ||
497 | named <code>xml:lang</code> <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be inserted in documents to specify the language | ||
498 | used in the contents and attribute values of any element in an XML document. | ||
499 | In 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> | ||
500 | if it is used. The | ||
501 | values of the attribute are language identifiers as defined by <a href="#RFC1766">[IETF RFC 3066]</a>, <cite>Tags | ||
502 | for 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><p xml:lang="en">The quick brown fox jumps over the lazy dog.</p> | ||
503 | <p xml:lang="en-GB">What colour is it?</p> | ||
504 | <p xml:lang="en-US">What color is it?</p> | ||
505 | <sp who="Faust" desc='leise' xml:lang="de"> | ||
506 | <l>Habe nun, ach! Philosophie,</l> | ||
507 | <l>Juristerei, und Medizin</l> | ||
508 | <l>und leider auch Theologie</l> | ||
509 | <l>durchaus studiert mit hei&#xDF;em Bem&#xFC;h'n.</l> | ||
510 | </sp></pre></div><p>The intent declared with <code>xml:lang</code> is considered to apply to | ||
511 | all attributes and content of the element where it is specified, unless overridden | ||
512 | with 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 | ||
513 | MIME). When available, this information may be used by XML applications, but the more local | ||
514 | information 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 | ||
516 | of French poems for English students, with glosses and notes in English, the <code>xml:lang</code> | ||
517 | attribute might be declared this way:</p><div class="exampleInner"><pre><!ATTLIST poem xml:lang <span>CDATA</span> 'fr'> | ||
518 | <!ATTLIST gloss xml:lang <span>CDATA</span> 'en'> | ||
519 | <!ATTLIST note xml:lang <span>CDATA</span> 'en'></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 | ||
520 | entities</a> (including <a title="Document Entity" href="#dt-docent"> document | ||
521 | entities</a>) <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be <a title="fully normalized" href="#dt-fullnorm">fully | ||
522 | normalized</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"> | ||
525 | replacement text</a> of all <a title="Text Entity" href="#dt-parsedent">parsed | ||
526 | entities</a></p></li><li><p>All text matching, in context, one of the following | ||
527 | productions:</p><ol type="a"><li><p><a href="#NT-CData"> | ||
528 | CData</a></p></li><li><p><a href="#NT-CharData"> | ||
529 | CharData</a></p></li><li><p><a href="#NT-content"> | ||
530 | content</a></p></li><li><p><a href="#NT-Name"> Name</a></p></li><li><p><a href="#NT-Nmtoken"> | ||
531 | Nmtoken</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>. | ||
533 | XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> provide a user option to verify that the document being | ||
534 | processed is in <a title="fully normalized" href="#dt-fullnorm">fully normalized</a> form, and report to the application whether | ||
535 | it is or not. The option to not verify <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be chosen only when the | ||
536 | input text is <a title="certified" href="#dt-certified">certified</a>, | ||
537 | as 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 | ||
538 | first verifying that the entity is in <a title="include-normalized" href="#dt-inclnorm">include-normalized</a> | ||
539 | form as defined by <a href="#sec-CharNorm"><b>B Definitions for Character Normalization</b></a> and by then verifying that none of the relevant | ||
540 | constructs listed above begins (after character references are | ||
541 | expanded) 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>. | ||
543 | Non-validating processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> ignore possible | ||
544 | denormalizations that would be caused by inclusion of external | ||
545 | entities 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 | ||
546 | Unicode characters of non-zero combining class, plus a small number | ||
547 | of class-zero characters that nevertheless take part as a | ||
548 | non-initial character in certain Unicode canonical | ||
549 | decompositions. Since these characters are meant to follow | ||
550 | base characters, restricting relevant constructs (including | ||
551 | content) from beginning with a <a title="composing character" href="#dt-compchar">composing character</a> does not | ||
552 | meaningfully diminish the expressiveness of XML.</p></div><p>If, while verifying full normalization, a processor encounters | ||
553 | characters for which it cannot determine the normalization | ||
554 | properties (i.e., characters introduced in a version of Unicode <a href="#Unicode">[Unicode]</a> | ||
555 | later than the one used in the implementation of the processor), | ||
556 | then the processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>, at user option, ignore any possible | ||
557 | denormalizations caused by these characters. The option to ignore | ||
558 | those denormalizations <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD NOT</em> be chosen by applications when | ||
559 | reliability 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. | ||
561 | XML applications that create XML 1.1 output | ||
562 | from either XML 1.1 or XML 1.0 input <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> ensure that the output | ||
563 | is <a title="fully normalized" href="#dt-fullnorm">fully normalized</a>; it is not necessary for internal processing | ||
564 | forms to be <a title="fully normalized" href="#dt-fullnorm">fully normalized</a>.</p><p>The purpose of this section is to strongly encourage XML | ||
565 | processors to ensure that the creators of XML documents have | ||
566 | properly normalized them, so that XML applications can make tests | ||
567 | such as identity comparisons of strings without having to worry | ||
568 | about the different possible "spellings" of strings which | ||
569 | Unicode allows. | ||
570 | </p><p>When entities are in a non-Unicode encoding, if the processor | ||
571 | transcodes 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 | ||
573 | document</a> contains one or more <b>elements</b>, the boundaries | ||
574 | of which are either delimited by <a title="Start-Tag" href="#dt-stag">start-tags</a> | ||
575 | and <a title="End Tag" href="#dt-etag">end-tags</a>, or, for <a title="Empty" href="#dt-empty">empty</a> | ||
576 | elements, by an <a title="empty-element tag" href="#dt-eetag">empty-element tag</a>. Each | ||
577 | element has a type, identified by name, sometimes called its "generic | ||
578 | identifier" (GI), and <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> have a set of attribute specifications.] | ||
579 | Each attribute specification has a <a title="Attribute Name" href="#dt-attrname">name</a> | ||
580 | and 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) | ||
581 | names of the element types and attributes, except that names beginning with | ||
582 | a match to <code>(('X'|'x')('M'|'m')('L'|'l'))</code> are reserved for standardization | ||
583 | in 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> | ||
584 | in 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 | ||
585 | if there is a declaration matching <a href="#NT-elementdecl">elementdecl</a> | ||
586 | where the <a href="#NT-Name">Name</a> matches the element type, and one of | ||
587 | the 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 | ||
588 | references, comments, PIs or white space)</span>.</p></li><li><p>The declaration matches <a href="#NT-children">children</a> and the | ||
589 | sequence of <a title="Parent/Child" href="#dt-parentchild">child elements</a> belongs | ||
590 | to the language generated by the regular expression in the content model, | ||
591 | with optional white space<span>, comments and | ||
592 | PIs (i.e. markup matching production [27] <a href="#NT-Misc">Misc</a>)</span> between the | ||
593 | start-tag and the first child element, between child elements, or between | ||
594 | the last child element and the end-tag. Note that a CDATA section containing | ||
595 | only white space <span>or a reference | ||
596 | to an entity whose replacement text is character references expanding to white | ||
597 | space</span> <span>do</span> not | ||
598 | match the nonterminal <a href="#NT-S">S</a>, and | ||
599 | hence cannot appear in these positions<span>; however, a | ||
600 | reference to an internal entity with a literal value consisting of character | ||
601 | references expanding to white space does match <a href="#NT-S">S</a>, since its | ||
602 | replacement text is the white space resulting from expansion of the character | ||
603 | references</span>.</p></li><li><p>The declaration matches <a href="#NT-Mixed">Mixed</a> and the content | ||
604 | <span>(after replacing | ||
605 | any 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 | ||
608 | content model.</p></li><li><p>The declaration matches <b>ANY</b>, and the | ||
609 | <span>content | ||
610 | <span>(after replacing | ||
611 | any entity references with their replacement text)</span> | ||
612 | consists of character data and <a title="Parent/Child" href="#dt-parentchild">child elements</a> | ||
613 | whose types</span> | ||
614 | have 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 | ||
615 | XML 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>'<' <a href="#NT-Name">Name</a> (<a href="#NT-S">S</a> <a href="#NT-Attribute">Attribute</a>)* <a href="#NT-S">S</a>? '>'</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 < 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> | ||
616 | pairs are referred to as the <b>attribute specifications</b> of the | ||
617 | element], [<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>] | ||
618 | and [<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> | ||
619 | delimiters) as the <b>attribute value</b>.] Note | ||
620 | that the order of attribute specifications in a start-tag or empty-element | ||
621 | tag 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> | ||
623 | have been declared; the value <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be of the type declared for it. (For attribute | ||
624 | types, 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 | ||
625 | values <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><</code> in Attribute Values</b></p><p>The <a title="Replacement Text" href="#dt-repltext">replacement text</a> of any entity | ||
626 | referred to directly or indirectly in an attribute value <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> contain a <code><</code>.</p></div><p>An example of a start-tag:</p><div class="exampleInner"><pre><termdef id="dt-dog" term="dog"></pre></div><p>[<a name="dt-etag" id="dt-etag" title="End Tag">Definition</a>: The end of every element that begins | ||
627 | with 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 | ||
628 | that 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>'</' <a href="#NT-Name">Name</a> <a href="#NT-S">S</a>? | ||
629 | '>'</code></td></tr></tbody></table><p>An example of an end-tag:</p><div class="exampleInner"><pre></termdef></pre></div><p>[<a name="dt-content" id="dt-content" title="Content">Definition</a>: The <a title="Text" href="#dt-text">text</a> | ||
630 | between 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 | ||
633 | with no <a href="#NT-content">content</a> is said to be <b>empty</b>.] The representation | ||
634 | of an empty element is either a start-tag immediately followed by an end-tag, | ||
635 | or an empty-element tag. [<a name="dt-eetag" id="dt-eetag" title="empty-element tag">Definition</a>: An <b>empty-element | ||
636 | tag</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>'<' <a href="#NT-Name">Name</a> (<a href="#NT-S">S</a> <a href="#NT-Attribute">Attribute</a>)* <a href="#NT-S">S</a>? '/>'</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 | ||
637 | or not it is declared using the keyword <b>EMPTY</b>. <a title="For interoperability" href="#dt-interop">For | ||
638 | interoperability</a>, the empty-element tag <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> | ||
639 | be used, and <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> only be used, for elements which are declared | ||
640 | EMPTY.</p><p>Examples of empty elements:</p><div class="exampleInner"><pre><IMG align="left" | ||
641 | src="http://www.w3.org/Icons/WWW/w3c_home" /> | ||
642 | <br></br> | ||
643 | <br/></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> | ||
644 | purposes, be constrained using element type and attribute-list declarations. | ||
645 | An 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 | ||
646 | as <a title="Parent/Child" href="#dt-parentchild">children</a> of the element. At user | ||
647 | option, an XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> issue a warning when a declaration mentions an | ||
648 | element 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 | ||
649 | type 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>'<!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 | '>'</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 | ||
652 | type <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><!ELEMENT br EMPTY> | ||
653 | <!ELEMENT p (#PCDATA|emph)* > | ||
654 | <!ELEMENT %name.para; %content.para; > | ||
655 | <!ELEMENT container ANY></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 | ||
656 | of that type <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> contain only <a title="Parent/Child" href="#dt-parentchild">child</a> | ||
657 | elements (no character data), optionally separated by white space (characters | ||
658 | matching 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 | ||
659 | model</b>, a simple grammar governing the allowed types of the | ||
660 | child elements and the order in which they are allowed to appear.] | ||
661 | The grammar is built on content particles (<a href="#NT-cp">cp</a>s), which | ||
662 | consist of names, choice lists of content particles, or sequence lists of | ||
663 | content 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 | ||
667 | particle 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 | ||
668 | content</a> at the location where the choice list appears in the grammar; | ||
669 | content 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. | ||
670 | The optional character following a name or list governs whether the element | ||
671 | or the content particles in the list may occur one or more (<code>+</code>), | ||
672 | zero or more (<code>*</code>), or zero or one times (<code>?</code>). The | ||
673 | absence of such an operator means that the element or content particle <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> | ||
674 | appear exactly once. This syntax and meaning are identical to those used in | ||
675 | the productions in this specification.</p><p>The content of an element matches a content model if and only if it is | ||
676 | possible to trace out a path through the content model, obeying the sequence, | ||
677 | choice, and repetition operators and matching each element in the content | ||
678 | against an element type in the content model. <a title="For Compatibility" href="#dt-compat">For | ||
679 | compatibility</a>, it is an error if <span>the content model | ||
680 | allows an element to match more than one occurrence of an element type in the | ||
681 | content 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 | ||
682 | groups. That is to say, if either of the opening or closing parentheses in | ||
683 | a <a href="#NT-choice">choice</a>, <a href="#NT-seq">seq</a>, or <a href="#NT-Mixed">Mixed</a> | ||
684 | construct is contained in the replacement text for a <a title="Parameter-entity reference" href="#dt-PERef">parameter | ||
685 | entity</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 | ||
686 | appears 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 | ||
687 | least one non-blank character, and neither the first nor last non-blank character | ||
688 | of 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><!ELEMENT spec (front, body, back?)> | ||
689 | <!ELEMENT div1 (head, (p | list | note)*, div2*)> | ||
690 | <!ELEMENT dictionary-body (%div.mix; | %dict.mix;)*></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> | ||
691 | has <b>mixed content</b> when elements of that type <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> contain character | ||
692 | data, optionally interspersed with <a title="Parent/Child" href="#dt-parentchild">child</a> | ||
693 | elements.] In this case, the types of the child elements <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be constrained, | ||
694 | but 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 | ||
697 | may appear as children. The | ||
698 | keyword <b>#PCDATA</b> derives historically from the term "parsed | ||
699 | character 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 | ||
700 | same 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><!ELEMENT p (#PCDATA|a|ul|b|i|em)*> | ||
701 | <!ELEMENT p (#PCDATA | %font; | %phrase; | %special; | %form;)* > | ||
702 | <!ELEMENT b (#PCDATA)></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 | ||
703 | pairs 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 | ||
705 | recognize 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 | ||
707 | attributes.</p></li></ul><p>[<a name="dt-attdecl" id="dt-attdecl" title="Attribute-List Declaration">Definition</a>: <b>Attribute-list | ||
708 | declarations</b> specify the name, data type, and default value (if any) | ||
709 | of 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>'<!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>? '>'</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> | ||
710 | rule is the type of an element. At user option, an XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> issue | ||
711 | a warning if attributes are declared for an element type not itself declared, | ||
712 | but this is not an error. The <a href="#NT-Name">Name</a> in the <a href="#NT-AttDef">AttDef</a> | ||
713 | rule is the name of the attribute.</p><p>When more than one <a href="#NT-AttlistDecl">AttlistDecl</a> is provided | ||
714 | for a given element type, the contents of all those provided are merged. When | ||
715 | more than one definition is provided for the same attribute of a given element | ||
716 | type, 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 | ||
717 | to provide at most one attribute-list declaration for a given element type, | ||
718 | at most one attribute definition for a given attribute name in an attribute-list | ||
719 | declaration, and at least one attribute definition in each attribute-list | ||
720 | declaration. For interoperability, an XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> at user option | ||
721 | issue a warning when more than one attribute-list declaration is provided | ||
722 | for a given element type, or more than one attribute definition is provided | ||
723 | for 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 | ||
724 | types, and enumerated types. The string type may take any literal string as | ||
725 | a value; the tokenized types have varying lexical and semantic constraints. | ||
726 | The validity constraints noted in the grammar are applied after the attribute | ||
727 | value 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 | ||
729 | in 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 | ||
730 | identify 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 | ||
731 | type <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> | ||
733 | match 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; | ||
734 | i.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> | ||
735 | declared 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
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 | ||
736 | provided 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 | ||
738 | Tokens]</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 | ||
740 | Tokens]</a></td></tr></tbody></table><p>A <b>NOTATION</b> attribute identifies a <a title="Notation" href="#dt-notation">notation</a>, | ||
741 | declared in the DTD with associated system and/or public identifiers, to be | ||
742 | used 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 | ||
744 | included in the declaration; all notation names in the declaration <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be | ||
745 | declared.</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> | ||
746 | attribute 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>, | ||
747 | an attribute of type <b>NOTATION</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em> be declared on an element | ||
748 | declared <b>EMPTY</b>.</p></div><div class="constraint"><p class="prefix"><a name="NoDuplicateTokens" id="NoDuplicateTokens" /><b>Validity constraint: No Duplicate | ||
749 | Tokens</b></p><p>The notation names in a single <a href="#NT-NotationType">NotationType</a> | ||
750 | attribute 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 | ||
752 | one 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 | ||
753 | attribute 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 | ||
754 | on 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 | ||
756 | to</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 | ||
757 | Default Value Syntactically Correct]</a></td></tr><tr valign="baseline"><td /><td /><td /><td /><td><a href="#CleanAttrVals">[WFC: No < 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 | ||
760 | the declaration is neither <b>#REQUIRED</b> nor <b>#IMPLIED</b>, then | ||
761 | the <a href="#NT-AttValue">AttValue</a> value contains the declared <b>default</b> | ||
762 | value; the <b>#FIXED</b> keyword states that the attribute <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> always have | ||
763 | the default value. | ||
764 | When an XML processor encounters | ||
765 | an <span>element | ||
766 | without a specification for an attribute for which it has read a default | ||
767 | value declaration, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> report the attribute with the declared default | ||
768 | value 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 | ||
769 | declaration is the keyword <b>#REQUIRED</b>, then the attribute <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be | ||
770 | specified 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 | ||
771 | Default 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> | ||
772 | constraints of the declared attribute type.</p><p>Note that only the | ||
773 | syntactic constraints of the type are required here; other constraints (e.g. | ||
774 | that the value be the name of a declared unparsed entity, for an attribute of | ||
775 | type 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 | ||
777 | has a default value declared with the <b>#FIXED</b> keyword, instances of | ||
778 | that 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><!ATTLIST termdef | ||
779 | id ID #REQUIRED | ||
780 | name CDATA #IMPLIED> | ||
781 | <!ATTLIST list | ||
782 | type (bullets|ordered|glossary) "ordered"> | ||
783 | <!ATTLIST form | ||
784 | method CDATA #FIXED "POST"></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 | ||
785 | for validity, the XML processor <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> normalize the attribute value by applying | ||
786 | the algorithm below, or by using some other method such that the value passed | ||
787 | to 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 | ||
788 | in <a href="#sec-line-ends"><b>2.11 End-of-Line Handling</b></a>, so the rest of this algorithm operates | ||
789 | on 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 | ||
790 | unnormalized attribute value, beginning with the first and continuing to the | ||
791 | last, do the following:</p><ul><li><p>For a character reference, append the referenced character to the | ||
792 | normalized value.</p></li><li><p>For an entity reference, recursively apply step 3 of this algorithm | ||
793 | to the replacement text of the entity.</p></li><li><p>For a white space character (#x20, #xD, #xA, #x9), append a space | ||
794 | character (#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 | ||
795 | process the normalized attribute value by discarding any leading and trailing | ||
796 | space (#x20) characters, and by replacing sequences of space (#x20) characters | ||
797 | by a single space (#x20) character.</p><p>Note that if the unnormalized attribute value contains a character reference | ||
798 | to a white space character other than space (#x20), the normalized value contains | ||
799 | the referenced character itself (#xD, #xA or #x9). This contrasts with the | ||
800 | case where the unnormalized value contains a white space character (not a | ||
801 | reference), which is replaced with a space character (#x20) in the normalized | ||
802 | value and also contrasts with the case where the unnormalized value contains | ||
803 | an entity reference whose replacement text contains a white space character; | ||
804 | being recursively processed, the white space character is replaced with a | ||
805 | space 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 | ||
806 | by a non-validating processor as if declared <b>CDATA</b>.</p><p>It | ||
807 | is an error if an | ||
808 | <span><a title="Attribute Value" href="#dt-attrval">attribute | ||
809 | value</a> contains a <a title="Entity Reference" href="#dt-entref">reference</a> to an | ||
810 | entity for which no declaration has been read.</span></p><p>Following are examples of attribute normalization. Given the following | ||
811 | declarations:</p><div class="exampleInner"><pre><!ENTITY d "&#xD;"> | ||
812 | <!ENTITY a "&#xA;"> | ||
813 | <!ENTITY da "&#xD;&#xA;"></pre></div><p>the attribute specifications in the left column below would be normalized | ||
814 | to the character sequences of the middle column if the attribute <code>a</code> | ||
815 | is declared <b>NMTOKENS</b> and to those of the right columns if <code>a</code> | ||
816 | is 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=" | ||
817 | xyz"</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="&d;&d;A&a;<span>&#x20;</span>&a;B&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 | "&#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><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> | ||
819 | is 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 | ||
820 | sections</b> are portions of the <a title="Document Type Declaration" href="#dt-doctype">document type | ||
821 | declaration external subset</a> <span>or | ||
822 | of external parameter entities </span>which are included in, or excluded from, | ||
823 | the 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>'<![' S? 'INCLUDE' S? '[' <a href="#NT-extSubsetDecl">extSubsetDecl</a> | ||
824 | ']]>' </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>'<![' S? 'IGNORE' S? '[' <a href="#NT-ignoreSectContents">ignoreSectContents</a>* | ||
825 | ']]>'</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> ('<![' <a href="#NT-ignoreSectContents">ignoreSectContents</a> ']]>' <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 | ('<![' | ']]>') <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><![</code>", | ||
827 | "<code>[</code>", or "<code>]]></code>" of a conditional section is contained | ||
828 | in the replacement text for a parameter-entity reference, all of them <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> | ||
829 | be contained in the same replacement text.</p></div><p>Like the internal and external DTD subsets, a conditional section may contain | ||
830 | one or more complete declarations, comments, processing instructions, or nested | ||
831 | conditional sections, intermingled with white space.</p><p>If the keyword of the conditional section is <b>INCLUDE</b>, then the | ||
832 | contents 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 | ||
833 | the conditional section is <b>IGNORE</b>, then the contents of the conditional | ||
834 | section <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be considered as</span> not logically part of the DTD. | ||
835 | If a conditional section with a keyword of <b>INCLUDE</b> occurs within | ||
836 | a larger conditional section with a keyword of <b>IGNORE</b>, both the outer | ||
837 | and the inner conditional sections <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be</span> ignored. The contents | ||
838 | of 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 | ||
839 | the "<code>[</code>" following the keyword, except conditional section starts | ||
840 | "<code><![</code>" and ends "<code>]]></code>", until the matching conditional | ||
841 | section 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 | ||
842 | process.</p><p>If the keyword of the conditional section is a parameter-entity reference, | ||
843 | the parameter entity <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be replaced by its content before the processor | ||
844 | decides whether to include or ignore the conditional section.</p><p>An example:</p><div class="exampleInner"><pre><!ENTITY % draft 'INCLUDE' > | ||
845 | <!ENTITY % final 'IGNORE' > | ||
846 | <![%draft;[ | ||
847 | <!ELEMENT book (comments*, title, body, supplements?)> | ||
848 | ]]> | ||
849 | <![%final;[ | ||
850 | <!ELEMENT book (title, body, supplements?)> | ||
851 | ]]></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 | ||
852 | or many storage units. These | ||
853 | are called <b>entities</b>; they all have <b>content</b> and are | ||
854 | all (except for the <a title="Document Entity" href="#dt-docent">document entity</a> and | ||
855 | the <a title="Document Type Declaration" href="#dt-doctype">external DTD subset</a>) identified by | ||
856 | entity <b>name</b>.] Each XML document has one entity | ||
857 | called the <a title="Document Entity" href="#dt-docent">document entity</a>, which serves | ||
858 | as the starting point for the <a title="XML Processor" href="#dt-xml-proc">XML processor</a> | ||
859 | and 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 | ||
860 | entity</b> are referred to as its <a title="Replacement Text" href="#dt-repltext">replacement | ||
861 | text</a>; this <a title="Text" href="#dt-text">text</a> is considered an | ||
862 | integral part of the document.]</p><p>[<a name="dt-unparsed" id="dt-unparsed" title="Unparsed Entity">Definition</a>: An <b>unparsed entity</b> | ||
863 | is a resource whose contents may or may not be <a title="Text" href="#dt-text">text</a>, | ||
864 | and if text, may | ||
865 | be other than XML. Each unparsed entity has an associated <a title="Notation" href="#dt-notation">notation</a>, identified by name. Beyond a requirement | ||
866 | that an XML processor make the identifiers for the entity and notation available | ||
867 | to the application, XML places no constraints on the contents of unparsed | ||
868 | entities.]</p><p>Parsed entities are invoked by name using entity references; unparsed entities | ||
869 | by 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> | ||
870 | are entities for use within the document content. In this specification, general | ||
871 | entities are sometimes referred to with the unqualified term <em>entity</em> | ||
872 | when this leads to no ambiguity.] [<a name="dt-PE" id="dt-PE" title="Parameter entity">Definition</a>: <b>Parameter | ||
873 | entities</b> are parsed entities for use within the DTD.] | ||
874 | These two types of entities use different forms of reference and are recognized | ||
875 | in different contexts. Furthermore, they occupy different namespaces; a parameter | ||
876 | entity 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 | ||
877 | reference</b> refers to a specific character in the ISO/IEC 10646 character | ||
878 | set, 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>'&#' [0-9]+ ';' </code></td></tr><tr valign="baseline"><td /><td /><td /><td><code>| '&#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 | ||
879 | to 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>&#x</code>", | ||
880 | the digits and letters up to the terminating <code>;</code> provide a hexadecimal | ||
881 | representation of the character's code point in ISO/IEC 10646. If it begins | ||
882 | just with "<code>&#</code>", the digits up to the terminating <code>;</code> | ||
883 | provide 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> | ||
884 | refers 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 | ||
885 | ampersand (<code>&</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> | ||
886 | use 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>'&' <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 | ||
887 | without any DTD, a document with only an internal DTD subset which contains | ||
888 | no parameter entity references, or a document with "<code>standalone='yes'</code>", for | ||
889 | an entity reference that does not occur within the external subset or a parameter | ||
890 | entity, 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 | ||
891 | declaration</cite></a> that does not occur within the external subset or a | ||
892 | parameter entity, except that well-formed documents need not declare | ||
893 | any of the following entities: <code>amp</code>, | ||
894 | <code>lt</code>, | ||
895 | <code>gt</code>, | ||
896 | <code>apos</code>, | ||
897 | <code>quot</code>. The | ||
898 | declaration of a general entity <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> precede any reference to it which appears | ||
899 | in a default value in an attribute-list declaration.</p><p><span>Note | ||
900 | that non-validating processors are <a href="#include-if-valid"><cite>not | ||
901 | obligated to</cite></a> to read and process entity declarations occurring in parameter entities or in | ||
902 | the external subset</span>; for such documents, | ||
903 | the rule that an entity must be declared is a well-formedness constraint only | ||
904 | if <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 | ||
905 | an external subset or external parameter entities with "<code>standalone='no'</code>", | ||
906 | 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 | ||
907 | declaration</cite></a>. For interoperability, valid documents <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> declare | ||
908 | the 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>. | ||
913 | The declaration of a parameter entity <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> precede any reference to it. Similarly, | ||
914 | the declaration of a general entity <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> precede any attribute-list | ||
915 | declaration containing a default value with a direct or indirect reference | ||
916 | to 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 | ||
917 | NOT</em> contain the name of an <a title="Unparsed Entity" href="#dt-unparsed">unparsed entity</a>. | ||
918 | Unparsed entities may be referred to only in <a title="Attribute Value" href="#dt-attrval">attribute | ||
919 | values</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> | ||
920 | the <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 <key>less-than</key> (&#x3C;) to save options. | ||
921 | This document was prepared on &docdate; and | ||
922 | is classified &security-level;.</pre></div><p>Example of a parameter-entity reference:</p><div class="exampleInner"><pre><!-- declare the parameter entity "ISOLat2"... --> | ||
923 | <!ENTITY % ISOLat2 | ||
924 | SYSTEM "http://www.xml.com/iso/isolat2-xml.entities" > | ||
925 | <!-- ... now reference it. --> | ||
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 | ||
927 | thus:]</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>'<!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 | '>'</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>'<!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>? '>'</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 | ||
929 | reference</a> or, in the case of an unparsed entity, in the value of | ||
930 | an <b>ENTITY</b> or <b>ENTITIES</b> attribute. If the same entity is declared | ||
931 | more than once, the first declaration encountered is binding; at user option, | ||
932 | an 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 | ||
933 | entity definition is an <a href="#NT-EntityValue">EntityValue</a>, the defined | ||
934 | entity is called an <b>internal entity</b>. There is no separate physical | ||
935 | storage object, and the content of the entity is given in the declaration.] | ||
936 | Note 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 | ||
937 | the 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><!ENTITY Pub-Status "This is a pre-release of the | ||
938 | specification."></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, | ||
939 | it 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 | ||
940 | identifier</b>. It is <span>meant to be | ||
941 | converted 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 | ||
944 | process of dereferencing it</span> to obtain input for the XML processor to construct the | ||
945 | entity'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. | ||
947 | Unless 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 | ||
949 | instruction defined by a particular application specification), relative URIs | ||
950 | are relative to the location of the resource within which the entity declaration | ||
951 | occurs. <span>This is defined to | ||
952 | be the external entity containing the '<' which starts the declaration, at the | ||
953 | point when it is parsed as a declaration.</span> | ||
954 | A URI might thus be relative to the <a title="Document Entity" href="#dt-docent">document | ||
955 | entity</a>, to the entity containing the <a title="Document Type Declaration" href="#dt-doctype">external | ||
956 | DTD subset</a>, or to some other <a title="External Entity" href="#dt-extent">external parameter | ||
957 | entity</a>. <span>Attempts to | ||
958 | retrieve the resource identified by a URI <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be redirected at the parser | ||
959 | level (for example, in an entity resolver) or below (at the protocol level, | ||
960 | for example, via an HTTP <code>Location:</code> header). In the absence of additional | ||
961 | information outside the scope of this specification within the resource, | ||
962 | the base URI of a resource is always the URI of the actual resource returned. | ||
963 | In other words, it is the URI of the resource retrieved after all redirection | ||
964 | has occurred.</span></p><p>System | ||
965 | identifiers (and other XML strings meant to be used as URI references) <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> contain | ||
966 | characters that, according to <a href="#rfc2396">[IETF RFC 2396]</a> and <a href="#rfc2732">[IETF RFC 2732]</a>, | ||
967 | must be escaped before a URI can be used to retrieve the referenced resource. The | ||
968 | characters to be escaped are the control characters #x0 to #x1F and #x7F (most of | ||
969 | which cannot appear in XML), space #x20, the delimiters '<' #x3C, '>' #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 | ||
972 | reversible process, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be performed only when absolutely necessary and as late | ||
973 | as possible in a processing chain. In particular, neither the process of converting | ||
974 | a relative URI to an absolute one nor the process of passing a URI reference to a | ||
975 | process or software component responsible for dereferencing it <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> trigger escaping. | ||
976 | When 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 | ||
977 | character <span>to be escaped</span> | ||
978 | is <span>represented in</span> | ||
979 | UTF-8 <span><a href="#Unicode">[Unicode]</a></span> | ||
980 | as one or more bytes.</p></li><li><p><span>The resulting bytes</span> | ||
981 | are escaped with | ||
982 | the URI escaping mechanism (that is, converted to <code>%</code><var>HH</var>, | ||
983 | where 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 | ||
984 | identifier, an external identifier <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> include a <b>public identifier</b>.] | ||
985 | An 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 | ||
987 | the public and system identifiers as well as additional information outside the | ||
988 | scope of this specification</span> to try to generate an alternative URI reference. | ||
989 | If the processor is unable to do so, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> use the URI | ||
990 | reference specified in the system literal. Before a match is attempted, | ||
991 | all strings of white space in the public identifier <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be normalized to | ||
992 | single space characters (#x20), and leading and trailing white space <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> | ||
993 | be removed.</p><p>Examples of external entity declarations:</p><div class="exampleInner"><pre><!ENTITY open-hatch | ||
994 | SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml"> | ||
995 | <!ENTITY open-hatch | ||
996 | PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" | ||
997 | "http://www.textuality.com/boilerplate/OpenHatch.xml"> | ||
998 | <!ENTITY hatch-pic | ||
999 | SYSTEM "../grafix/OpenHatch.gif" | ||
1000 | NDATA gif ></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>'<?xml' <a href="#NT-VersionInfo">VersionInfo</a>? <a href="#NT-EncodingDecl">EncodingDecl</a> <a href="#NT-S">S</a>? '?>'</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 | ||
1001 | to 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 | ||
1003 | position other than the beginning of an external parsed entity. The text declaration | ||
1004 | in 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 | ||
1005 | if it matches the production labeled <a href="#NT-extParsedEnt">extParsedEnt</a>. All | ||
1006 | external 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 | ||
1007 | matches the production labeled <a href="#NT-content">content</a>. All internal | ||
1008 | parameter entities are well-formed by definition.</p><p>A consequence of well-formedness in <span>general</span> | ||
1009 | entities is that the logical and physical | ||
1010 | structures 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 | ||
1011 | reference</a>, or <a title="Entity Reference" href="#dt-entref">entity reference</a> | ||
1012 | can 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 | ||
1013 | for its characters. All XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be able to read entities in both | ||
1014 | the UTF-8 and UTF-16 encodings. The terms "UTF-8" | ||
1015 | and "UTF-16" in this specification do not apply to character | ||
1016 | encodings with any other labels, even if the encodings or labels are very | ||
1017 | similar 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 | ||
1018 | encoded in UTF-8 <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em></span> begin with the Byte Order Mark described in | ||
1019 | ISO/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, | ||
1021 | not part of either the markup or the character data of the XML document. XML | ||
1022 | processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be able to use this character to differentiate between UTF-8 | ||
1023 | and UTF-16 encoded documents.</p><p>Although an XML processor is required to read only entities in the UTF-8 | ||
1024 | and UTF-16 encodings, it is recognized that other encodings are used around | ||
1025 | the world, and it may be desired for XML processors to read entities that | ||
1026 | use them. In | ||
1027 | the absence of external character encoding information (such as MIME headers), | ||
1028 | parsed 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 | ||
1030 | an 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 | ||
1033 | name contains only Latin characters */</i></td></tr></tbody></table><p>In the <a title="Document Entity" href="#dt-docent">document entity</a>, the encoding | ||
1034 | declaration is part of the <a title="XML Declaration" href="#dt-xmldecl">XML declaration</a>. | ||
1035 | The <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 | ||
1037 | for the various encodings and transformations of Unicode / ISO/IEC 10646, | ||
1038 | the values "<code>ISO-8859-1</code>", "<code>ISO-8859-2</code>", | ||
1039 | ... "<code>ISO-8859-</code><var>n</var>" (where <var>n</var> | ||
1040 | is the part number) <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be used for the parts of ISO 8859, and | ||
1041 | the values "<code>ISO-2022-JP</code>", "<code>Shift_JIS</code>", | ||
1042 | and "<code>EUC-JP</code>" <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> be used for the various encoded | ||
1043 | forms of JIS X-0208-1997. It | ||
1044 | is <em class="rfc2119" title="Keyword in RFC 2119 context">RECOMMENDED</em> that character encodings registered (as <em>charset</em>s) | ||
1045 | with the Internet Assigned Numbers Authority <a href="#IANA">[IANA-CHARSETS]</a>, | ||
1046 | other than those just listed, be referred to using their registered names; | ||
1047 | other encodings <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> use names starting with an "x-" prefix. | ||
1048 | XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> match character encoding names in a case-insensitive | ||
1049 | way and <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> either interpret an IANA-registered name as the encoding registered | ||
1050 | at IANA for that name or treat it as unknown (processors are, of course, not | ||
1051 | required 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 | ||
1053 | an entity including an encoding declaration to be presented to the XML processor | ||
1054 | in an encoding other than that named in the declaration, or for an entity which | ||
1055 | begins with neither a Byte Order Mark | ||
1056 | nor an encoding declaration to use an encoding other than UTF-8. Note that | ||
1057 | since ASCII is a subset of UTF-8, ordinary ASCII entities do not strictly | ||
1058 | need 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 | ||
1059 | than 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 | ||
1060 | encounters an entity with an encoding that it is unable to process. It | ||
1061 | is a <a title="Fatal Error" href="#dt-fatal">fatal error</a> if an XML entity is determined (via default, encoding declaration, | ||
1062 | or higher-level protocol) to be in a certain encoding but contains <span>byte</span> | ||
1063 | sequences that are not legal in that encoding. <span>Specifically, it is a | ||
1064 | fatal error if an entity encoded in UTF-8 contains any irregular code unit sequences, | ||
1065 | as defined in Unicode <a href="#Unicode">[Unicode]</a>.</span> <span>Unless an encoding | ||
1066 | is 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 | ||
1067 | contains 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><?xml encoding='UTF-8'?> | ||
1068 | <?xml encoding='EUC-JP'?></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>, | ||
1069 | can be separately | ||
1070 | declared as XML 1.0 or XML 1.1. The version declaration appearing | ||
1071 | in the document entity determines the version of the document as a | ||
1072 | whole. An XML 1.1 document may invoke XML 1.0 external entities, so | ||
1073 | that otherwise duplicated versions of external entities, | ||
1074 | particularly DTD external subsets, need not be maintained. However, | ||
1075 | in such a case the rules of XML 1.1 are applied to the entire | ||
1076 | document.</p><p> If an entity (including the document entity) is not labeled | ||
1077 | with a version number, it is treated as if labeled as version | ||
1078 | 1.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, | ||
1079 | entity 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> | ||
1081 | in 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> | ||
1082 | and before the <a title="End Tag" href="#dt-etag">end-tag</a> of an element; corresponds | ||
1083 | to 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>, | ||
1084 | or a default value in an <a title="Attribute-List Declaration" href="#dt-attdecl">attribute declaration</a>; | ||
1085 | corresponds 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 | ||
1086 | the value of an attribute which has been declared as type <b>ENTITY</b>, | ||
1087 | or as one of the space-separated tokens in the value of an attribute which | ||
1088 | has 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 | ||
1089 | entity 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>, | ||
1090 | or 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 | ||
1091 | Type</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 | ||
1092 | General</td><td rowspan="1" colspan="1">Unparsed</td></tr><tr align="center" valign="middle"><td align="right" rowspan="1" colspan="1">Reference | ||
1093 | in 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 | ||
1094 | if 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 | ||
1095 | in 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 | ||
1096 | Value</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; | ||
1097 | thus, what would be parameter entity references in the DTD are not recognized | ||
1098 | as markup in <a href="#NT-content">content</a>. Similarly, the names of unparsed | ||
1099 | entities are not recognized except when they appear in the value of an appropriately | ||
1100 | declared 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> | ||
1101 | when its <a title="Replacement Text" href="#dt-repltext">replacement text</a> is retrieved | ||
1102 | and processed, in place of the reference itself, as though it were part of | ||
1103 | the document at the location the reference was recognized.] The replacement | ||
1104 | text <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> contain both <a title="Character Data" href="#dt-chardata">character data</a> | ||
1105 | and (except for parameter entities) <a title="Markup" href="#dt-markup">markup</a>, | ||
1106 | which <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be recognized in the usual way. (The string "<code>AT&amp;T;</code>" | ||
1107 | expands to "<code>AT&T;</code>" and the remaining ampersand | ||
1108 | is not recognized as an entity-reference delimiter.) A character reference | ||
1109 | is <b>included</b> when the indicated character is processed in place | ||
1110 | of 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 | ||
1111 | to <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 | ||
1113 | the entity is external, and the processor is not attempting to validate the | ||
1114 | XML document, the processor <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em>, but need | ||
1115 | not, include the entity's replacement text. If a non-validating processor | ||
1116 | does not include the replacement text, it <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> inform the application that | ||
1117 | it recognized, but did not read, the entity.</p><p>This rule is based on the recognition that the automatic inclusion provided | ||
1118 | by the SGML and XML entity mechanism, primarily designed to support modularity | ||
1119 | in authoring, is not necessarily appropriate for other applications, in particular | ||
1120 | document browsing. Browsers, for example, when encountering an external parsed | ||
1121 | entity reference, might choose to provide a visual indication of the entity's | ||
1122 | presence 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 | ||
1123 | errors</a>:</p><ul><li><p>the appearance of a reference to an <a title="Unparsed Entity" href="#dt-unparsed">unparsed | ||
1124 | entity</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 | ||
1126 | DTD 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 | ||
1127 | an attribute value, or a parameter entity reference appears in a literal entity | ||
1128 | value, 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 | ||
1129 | in place of the reference itself as though it were part of the document at | ||
1130 | the location the reference was recognized, except that a single or double | ||
1131 | quote 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 | ||
1132 | character 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><!ENTITY % YN '"Yes"' > | ||
1133 | <!ENTITY WhatHeSaid "He said %YN;" ></pre></div><p>while this is not:</p><div class="exampleInner"><pre><!ENTITY EndAttr "27'" > | ||
1134 | <element attribute='a-&EndAttr;></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> | ||
1135 | appears as a token in the value of an attribute of declared type <b>ENTITY</b> | ||
1136 | or <b>ENTITIES</b>, a validating processor <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> inform the application of | ||
1137 | the <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> | ||
1139 | in 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 | ||
1140 | reference is recognized in the DTD and included, its <a title="Replacement Text" href="#dt-repltext">replacement | ||
1141 | text</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 | ||
1142 | space (#x20) character; the intent is to constrain the replacement text of | ||
1143 | parameter entities to contain an integral number of grammatical tokens in | ||
1144 | the DTD. This | ||
1145 | behavior <span class="mustard"><em class="rfc2119" title="Keyword in RFC 2119 context">MUST NOT</em></span> apply to parameter entity references within entity values; | ||
1146 | these 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 | ||
1147 | an unparsed entity to appear in the <a href="#NT-EntityValue">EntityValue</a> in an | ||
1148 | entity 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 | ||
1149 | two forms of the entity's value. | ||
1150 | [<a name="dt-litentval" id="dt-litentval" title="Literal Entity Value">Definition</a>: <span>For an | ||
1151 | internal entity, </span>the <b>literal | ||
1152 | entity value</b> is the quoted string actually present in the entity declaration, | ||
1153 | corresponding 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 | ||
1154 | entity 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 | ||
1155 | internal entity, </span>the <b>replacement text</b> | ||
1156 | is the content of the entity, after replacement of character references and | ||
1157 | parameter-entity references.] [<a name="dt-extrepltext" id="dt-extrepltext" title="Replacement Text">Definition</a>: For | ||
1158 | an external entity, the <b>replacement text</b> is the content of the entity, | ||
1159 | after stripping the text declaration (leaving any surrounding white space) if there | ||
1160 | is one but without any replacement of character references or parameter-entity | ||
1161 | references.]</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, | ||
1162 | and general-entity references. Such references <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be contained entirely | ||
1163 | within 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 | ||
1165 | text</em> of any parameter entities referred to, and <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> contain the character | ||
1166 | referred to, in place of any character references in the literal entity value; | ||
1167 | however, general-entity references <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be left as-is, unexpanded. For example, | ||
1168 | given the following declarations:</p><div class="exampleInner"><pre><!ENTITY % pub "&#xc9;ditions Gallimard" > | ||
1169 | <!ENTITY rights "All rights reserved" > | ||
1170 | <!ENTITY book "La Peste: Albert Camus, | ||
1171 | &#xA9; 1947 %pub;. &rights;" ></pre></div><p>then the replacement text for the entity "<code>book</code>" | ||
1172 | is:</p><div class="exampleInner"><pre>La Peste: Albert Camus, | ||
1173 | © 1947 Éditions Gallimard. &rights;</pre></div><p>The general-entity reference "<code>&rights;</code>" would | ||
1174 | be expanded should the reference "<code>&book;</code>" appear | ||
1175 | in the document's content or an attribute value.</p><p>These simple rules may have complex interactions; for a detailed discussion | ||
1176 | of 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> | ||
1177 | both be used to <b>escape</b> the left angle bracket, ampersand, and | ||
1178 | other 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 | ||
1183 | this purpose. Numeric character references <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> also be used; they are expanded | ||
1184 | immediately when recognized and <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be treated as character data, so the | ||
1185 | numeric character references "<code>&#60;</code>" and "<code>&#38;</code>" <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> be used to escape <code><</code> and <code>&</code> when they occur | ||
1186 | in 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 | ||
1187 | or not. <a title="For interoperability" href="#dt-interop">For interoperability</a>, valid XML | ||
1188 | documents <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> declare these entities, like any others, before using them. If | ||
1189 | the entities <code>lt</code> or <code>amp</code> are declared, they <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be | ||
1190 | declared as internal entities whose replacement text is a character reference | ||
1191 | to the respective | ||
1192 | character (less-than sign or ampersand) being escaped; the double | ||
1193 | escaping is <em class="rfc2119" title="Keyword in RFC 2119 context">REQUIRED</em> for these entities so that references to them produce | ||
1194 | a well-formed result. If the entities <code>gt</code>, <code>apos</code>, | ||
1195 | or <code>quot</code> are declared, they <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> be declared as internal entities | ||
1196 | whose replacement text is the single character being escaped (or a character | ||
1197 | reference 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). | ||
1198 | For example:</p><div class="exampleInner"><pre><!ENTITY lt "&#38;#60;"> | ||
1199 | <!ENTITY gt "&#62;"> | ||
1200 | <!ENTITY amp "&#38;#38;"> | ||
1201 | <!ENTITY apos "&#39;"> | ||
1202 | <!ENTITY quot "&#34;"></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 | ||
1203 | by name the format of <a title="External Entity" href="#dt-extent">unparsed entities</a>, | ||
1204 | the format of elements which bear a notation attribute, or the application | ||
1205 | to 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> | ||
1206 | provide a name for the notation, for use in entity and attribute-list declarations | ||
1207 | and in attribute specifications, and an external identifier for the notation | ||
1208 | which may allow an XML processor or its client application to locate a helper | ||
1209 | application 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>'<!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>? '>'</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) | ||
1210 | of any notation declared and referred to in an attribute value, attribute | ||
1211 | definition, or entity declaration. They <em class="rfc2119" title="Keyword in RFC 2119 context">MAY</em> additionally resolve the external | ||
1212 | identifier into the <a title="System Identifier" href="#dt-sysid">system identifier</a>, file | ||
1213 | name, or other information needed to allow the application to call a processor | ||
1214 | for data in the notation described. (It is not an error, however, for XML | ||
1215 | documents to declare and refer to notations for which notation-specific applications | ||
1216 | are not available on the system where the XML processor or application is | ||
1217 | running.)</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> | ||
1218 | serves 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 | ||
1219 | not specify how the document entity is to be located by an XML processor; | ||
1220 | unlike other entities, the document entity has no name and might well appear | ||
1221 | on 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 | ||
1222 | two 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 | ||
1223 | this 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 | ||
1224 | entities</a> that they read.</p><p>[<a name="dt-validating" id="dt-validating" title="Validating Processor">Definition</a>: <b>Validating | ||
1225 | processors</b> <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em>, | ||
1226 | at user option, report violations of the constraints expressed by | ||
1227 | the declarations in the <a title="Document Type Declaration" href="#dt-doctype">DTD</a>, and failures | ||
1228 | to fulfill the validity constraints given in this specification.] | ||
1229 | To accomplish this, validating XML processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> read and process the entire | ||
1230 | DTD 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 | ||
1231 | entity</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 | ||
1232 | to check the document for validity, they are <em class="rfc2119" title="Keyword in RFC 2119 context">REQUIRED</em> to <b>process</b> | ||
1233 | all the declarations they read in the internal DTD subset and in any parameter | ||
1234 | entity that they read, up to the first reference to a parameter entity that | ||
1235 | they do <em>not</em> read; that is to say, they <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> use the information | ||
1236 | in those declarations to <a href="#AVNormalize"><cite>normalize</cite></a> | ||
1237 | attribute values, <a href="#included"><cite>include</cite></a> the replacement | ||
1238 | text of internal entities, and supply <a href="#sec-attr-defaults"><cite>default | ||
1239 | attribute 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 | ||
1241 | declarations</a> or <a title="Attribute-List Declaration" href="#dt-attdecl">attribute-list declarations</a> | ||
1242 | encountered after a reference to a parameter entity that is not read, since | ||
1243 | the entity may have contained overriding declarations<span>; when <code>standalone="yes"</code>, processors <em class="rfc2119" title="Keyword in RFC 2119 context">MUST</em> | ||
1244 | process these declarations</span>.</p><p>Note | ||
1245 | that when processing invalid documents with a non-validating | ||
1246 | processor the application may not be presented with consistent | ||
1247 | information. For example, several requirements for uniqueness | ||
1248 | within the document may not be met, including more than one element | ||
1249 | with the same id, duplicate declarations of elements or notations | ||
1250 | with the same name, etc. In these cases the behavior of the parser | ||
1251 | with respect to reporting such information to the application is | ||
1252 | undefined.</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 | ||
1253 | and XML 1.1 documents. Programs which generate XML <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD</em> | ||
1254 | generate 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 | ||
1255 | read every piece of a document and report all well-formedness and validity | ||
1256 | violations. Less is required of a non-validating processor; it need not read | ||
1257 | any part of the document other than the document entity. This has two effects | ||
1258 | that may be important to users of XML processors:</p><ul><li><p>Certain well-formedness errors, specifically those that require reading | ||
1259 | external entities, <span>may fail to</span> be detected by a non-validating processor. Examples | ||
1260 | include 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 | ||
1261 | Recursion</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 | ||
1262 | vary, depending on whether the processor reads parameter and external entities. | ||
1263 | For example, a non-validating processor <span>may fail to</span> <a href="#AVNormalize"><cite>normalize</cite></a> | ||
1264 | attribute values, <a href="#included"><cite>include</cite></a> the replacement | ||
1265 | text of internal entities, or supply <a href="#sec-attr-defaults"><cite>default | ||
1266 | attribute values</cite></a>, where doing so depends on having read declarations | ||
1267 | in external or parameter entities.</p></li></ul><p>For maximum reliability in interoperating between different XML processors, | ||
1268 | applications which use non-validating processors <em class="rfc2119" title="Keyword in RFC 2119 context">SHOULD NOT</em> rely on any behaviors | ||
1269 | not required of such processors. Applications which require DTD facilities | ||
1270 | not related to validation (such | ||
1271 | as the declaration of default attributes and internal entities that are | ||
1272 | or may be specified in | ||
1273 | external 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 | ||
1274 | Extended Backus-Naur Form (EBNF) notation. Each rule in the grammar defines | ||
1275 | one 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 | ||
1276 | start symbol of a regular language, otherwise with an initial lowercase | ||
1277 | letter. Literal strings are quoted.</p><p>Within the expression on the right-hand side of a rule, the following expressions | ||
1278 | are 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> | ||
1281 | form 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 | ||
1282 | enumerated. 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 | ||
1283 | indicated.</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 | ||
1284 | and 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 | ||
1285 | given 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 | ||
1286 | given inside the single quotes.</p></dd></dl><p> These symbols may be combined to match more complex patterns as follows, | ||
1287 | where <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 | ||
1288 | in 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 | ||
1289 | operator has higher precedence than alternation; thus <code>A B | C D</code> | ||
1290 | is 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 | ||
1291 | has higher precedence than alternation; thus <code>A+ | B+</code> is identical | ||
1292 | to <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 | ||
1293 | has higher precedence than alternation; thus <code>A* | B*</code> is identical | ||
1294 | to <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> | ||
1295 | documents 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 | ||
1296 | Assigned Numbers Authority) <a href="http://www.iana.org/assignments/character-sets"><cite>Official Names for Character Sets</cite></a>, | ||
1297 | ed. 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>. | ||
1299 | Scott 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. | ||
1302 | 1998. (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 | ||
1304 | IPv6 Addresses in URL's</cite></a>. R. Hinden, B. Carpenter, L. Masinter. | ||
1305 | 1999. (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 | ||
1307 | of 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 | ||
1308 | Organization for Standardization). <cite>ISO/IEC 10646-1:2000. Information | ||
1309 | technology — Universal Multiple-Octet Coded Character Set (UCS) — | ||
1310 | Part 1: Architecture and Basic Multilingual Plane</cite> and <cite>ISO/IEC 10646-2:2001. | ||
1311 | Information technology — Universal Multiple-Octet Coded Character Set (UCS) — Part 2: | ||
1312 | Supplementary Planes</cite>, as, from time to time, amended, replaced by a new edition or | ||
1313 | expanded 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 | ||
1315 | Standard, Version 4.0.</em> Reading, Mass.: Addison-Wesley, | ||
1316 | 2003, | ||
1317 | as updated from time to time by the publication of new versions. (See | ||
1318 | <a href="http://www.unicode.org/unicode/standard/versions"> | ||
1319 | http://www.unicode.org/unicode/standard/versions</a> for the latest version | ||
1320 | and additional information on versions of the standard and of the Unicode | ||
1321 | Character 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 | ||
1322 | Edition)</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. | ||
1324 | Ullman. <cite>Compilers: Principles, Techniques, and Tools</cite>. | ||
1325 | Reading: Addison-Wesley, 1986, rpt. corr. 1988.</dd><dt class="label"><a name="ABK" id="ABK" />Brüggemann-Klein</dt><dd>Brüggemann-Klein, | ||
1326 | Anne. <a href="ftp://ftp.informatik.uni-freiburg.de/documents/papers/brueggem/habil.ps"><cite>Formal Models in Document Processing</cite></a>. Habilitationsschrift. Faculty | ||
1327 | of 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, | ||
1328 | Anne, and Derick Wood. <cite>Deterministic Regular Languages</cite>. | ||
1329 | Universität Freiburg, Institut für Informatik, Bericht 38, Oktober 1991. Extended | ||
1330 | abstract in A. Finkel, M. Jantzen, Hrsg., STACS 1992, S. 173-184. Springer-Verlag, | ||
1331 | Berlin 1992. Lecture Notes in Computer Science 577. Full version titled <cite>One-Unambiguous | ||
1332 | Regular Languages</cite> in Information and Computation 140 (2): 229-253, | ||
1333 | February 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 | |||
1337 | Martin 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 | ||
1339 | Assigned Numbers Authority) <a href="http://www.iana.org/assignments/language-tags"><cite>Registry of Language Tags</cite></a>, | ||
1340 | ed. 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. | ||
1342 | R. 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>. | ||
1344 | eds. 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 | ||
1346 | of 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). | ||
1348 | Code for the representation of names of languages.</cite> [Geneva]: International | ||
1349 | Organization 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 — | ||
1352 | Part 1: Country codes</cite> [Geneva]: International Organization for | ||
1353 | Standardization, 1997.</dd><dt class="label"><a name="ISO8879" id="ISO8879" />ISO 8879</dt><dd>ISO (International Organization for Standardization). <cite>ISO | ||
1354 | 8879:1986(E). Information processing — Text and Office Systems — | ||
1355 | Standard Generalized Markup Language (SGML).</cite> First edition — | ||
1356 | 1986-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 | ||
1357 | Standardization). <cite>ISO/IEC 10744-1992 (E). Information technology — | ||
1358 | Hypermedia/Time-based Structuring Language (HyTime). </cite> [Geneva]: | ||
1359 | International Organization for Standardization, 1992. <em>Extended Facilities | ||
1360 | Annexe.</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 | ||
1362 | TC2. 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, | ||
1364 | Dave Hollander, and Andrew Layman, editors. <a href="http://www.w3.org/TR/REC-xml-names/"><cite>Namespaces in XML</cite></a>. | ||
1365 | Textuality, 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. | ||
1366 | For 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 | ||
1368 | in a <b>Unicode encoding form</b> if it is encoded in | ||
1369 | UTF-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> | ||
1371 | is 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 | ||
1376 | ensures 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> | ||
1378 | is a syntactic device defined in a markup or programming language that allows | ||
1379 | one or more of:]</p><ol type="1"><li><p>expressing syntax-significant characters while disregarding | ||
1380 | their significance in the syntax of the language, or</p></li><li><p>expressing characters not representable in the character encoding | ||
1381 | chosen for an instance of the language, or</p></li><li><p>expressing characters in general, without use of the corresponding | ||
1382 | character codes.</p></li></ol><p> | ||
1383 | [<a name="dt-certified" id="dt-certified" title="certified">Definition</a>: <b>Certified</b> text | ||
1384 | is 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 | ||
1385 | is in normalized form</p></li><li><p>the source text-processing component is identified | ||
1386 | and 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 | ||
1388 | this 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 | ||
1390 | Unicode Normalization Form C, according to a version of Unicode Standard Annex #15: | ||
1391 | Unicode Normalization Forms <a href="#Unicode">[Unicode]</a> at least as recent as the | ||
1392 | oldest version of the Unicode Standard that contains all the characters | ||
1393 | actually present in the text, but no earlier | ||
1394 | than 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> | ||
1397 | and does not contain any <a title="character escape" href="#dt-charesc">character escapes</a> | ||
1398 | or <a title="Include" href="#dt-include">includes</a> whose expansion would | ||
1399 | cause the text to become no longer <a title="Unicode-normalized" href="#dt-uninorm">Unicode-normalized</a>; | ||
1400 | or</p></li><li><p>the text is in a <a title="legacy encoding" href="#dt-legacyenc">legacy encoding</a> and, if it were transcoded | ||
1401 | to 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 | ||
1403 | text 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> | ||
1405 | is 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 | ||
1406 | some 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 | ||
1410 | form</a>, is <a title="include-normalized" href="#dt-inclnorm">include-normalized</a> and | ||
1411 | none of the <a title="" href="#dt-relconst"><span>relevant</span> | ||
1412 | constructs</a> comprising the text begin with a | ||
1413 | <a title="composing character" href="#dt-compchar">composing character</a> or a | ||
1414 | character 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, | ||
1416 | if it were transcoded to a <a title="Unicode encoding form" href="#dt-Uni-encform">Unicode encoding form</a> | ||
1417 | by a <a title="normalizing transcoder" href="#dt-normtransc">normalizing transcoder</a>, the resulting text | ||
1418 | would 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- | ||
1419 | and 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><!ENTITY example "<p>An ampersand (&#38;#38;) may be escaped | ||
1420 | numerically (&#38;#38;#38;) or with a general entity | ||
1421 | (&amp;amp;).</p>" ></pre></div><p>then the XML processor will recognize the character references when it | ||
1422 | parses the entity declaration, and resolve them before storing the following | ||
1423 | string as the value of the entity "<code>example</code>":</p><div class="exampleInner"><pre><p>An ampersand (&#38;) may be escaped | ||
1424 | numerically (&#38;#38;) or with a general entity | ||
1425 | (&amp;amp;).</p></pre></div><p>A reference in the document to "<code>&example;</code>" | ||
1426 | will cause the text to be reparsed, at which time the start- and end-tags | ||
1427 | of the <code>p</code> element will be recognized and the three references will | ||
1428 | be recognized and expanded, resulting in a <code>p</code> element with the following | ||
1429 | content (all data, no delimiters or markup):</p><div class="exampleInner"><pre>An ampersand (&) may be escaped | ||
1430 | numerically (&#38;) or with a general entity | ||
1431 | (&amp;).</pre></div><p>A more complex example will illustrate the rules and their effects fully. | ||
1432 | In the following example, the line numbers are solely for reference.</p><div class="exampleInner"><pre>1 <?xml version='1.0'?> | ||
1433 | 2 <!DOCTYPE test [ | ||
1434 | 3 <!ELEMENT test (#PCDATA) > | ||
1435 | 4 <!ENTITY % xx '&#37;zz;'> | ||
1436 | 5 <!ENTITY % zz '&#60;!ENTITY tricky "error-prone" >' > | ||
1437 | 6 %xx; | ||
1438 | 7 ]> | ||
1439 | 8 <test>This sample shows a &tricky; method.</test></pre></div><p>This produces the following:</p><ul><li><p>in line 4, the reference to character 37 is expanded immediately, | ||
1440 | and the parameter entity "<code>xx</code>" is stored in the symbol | ||
1441 | table with the value "<code>%zz;</code>". Since the replacement | ||
1442 | text is not rescanned, the reference to parameter entity "<code>zz</code>" | ||
1443 | is not recognized. (And it would be an error if it were, since "<code>zz</code>" | ||
1444 | is not yet declared.)</p></li><li><p>in line 5, the character reference "<code>&#60;</code>" | ||
1445 | is expanded immediately and the parameter entity "<code>zz</code>" | ||
1446 | is stored with the replacement text "<code><!ENTITY tricky "error-prone" | ||
1447 | ></code>", which is a well-formed entity declaration.</p></li><li><p>in line 6, the reference to "<code>xx</code>" is recognized, | ||
1448 | and the replacement text of "<code>xx</code>" (namely "<code>%zz;</code>") | ||
1449 | is parsed. The reference to "<code>zz</code>" is recognized in | ||
1450 | its turn, and its replacement text ("<code><!ENTITY tricky "error-prone" | ||
1451 | ></code>") is parsed. The general entity "<code>tricky</code>" | ||
1452 | has 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>" | ||
1453 | is recognized, and it is expanded, so the full content of the <code>test</code> | ||
1454 | element is the self-describing (and ungrammatical) string <em>This sample | ||
1455 | shows 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 | ||
1456 | noted in <a href="#sec-element-content"><b>3.2.1 Element Content</b></a>, it is required that content | ||
1457 | models in element type declarations be deterministic. This requirement is <a title="For Compatibility" href="#dt-compat">for compatibility</a> with SGML (which calls deterministic | ||
1458 | content models "unambiguous"); XML processors built | ||
1459 | using 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, | ||
1460 | because given an initial <code>b</code> the XML processor | ||
1461 | cannot know which <code>b</code> in the model is being matched without looking | ||
1462 | ahead to see which element follows the <code>b</code>. In this case, the two references | ||
1463 | to <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 | ||
1465 | in the content model. The processor doesn't need to look ahead to see what follows; either <code>c</code> or <code>d</code> | ||
1466 | would be accepted.</p><p>More formally: a finite state automaton may be constructed from the content | ||
1467 | model using the standard algorithms, e.g. algorithm 3.5 in section 3.9 of | ||
1468 | Aho, Sethi, and Ullman <a href="#Aho">[Aho/Ullman]</a>. In many such algorithms, a follow | ||
1469 | set is constructed for each position in the regular expression (i.e., each | ||
1470 | leaf node in the syntax tree for the regular expression); if any position | ||
1471 | has a follow set in which more than one following position is labeled with | ||
1472 | the same element type name, then the content model is in error and may be | ||
1473 | reported as an error.</p><p>Algorithms exist which allow many but not all non-deterministic content | ||
1474 | models to be reduced automatically to equivalent deterministic models; see | ||
1475 | Brü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, | ||
1476 | indicating which character encoding is in use. Before an XML processor can | ||
1477 | read the internal label, however, it apparently has to know what character | ||
1478 | encoding is in use — which is what the internal label is trying to indicate. | ||
1479 | In the general case, this is a hopeless situation. It is not entirely hopeless | ||
1480 | in XML, however, because XML limits the general case in two ways: each implementation | ||
1481 | is assumed to support only a finite set of character encodings, and the XML | ||
1482 | encoding declaration is restricted in position and content in order to make | ||
1483 | it feasible to autodetect the character encoding in use in each entity in | ||
1484 | normal cases. Also, in many cases other sources of information are available | ||
1485 | in addition to the XML data stream itself. Two cases may be distinguished, | ||
1486 | depending on whether the XML entity is presented to the processor without, | ||
1487 | or with, any accompanying (external) information. We consider the first case | ||
1488 | first.</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 | ||
1489 | encoding information and not in UTF-8 or UTF-16 encoding must | ||
1490 | begin with an XML encoding declaration, in which the first characters must | ||
1491 | be '<code><?xml</code>', any conforming processor can detect, after two | ||
1492 | to four octets of input, which of the following cases apply. In reading this | ||
1493 | list, it may help to know that in UCS-4, '<' is "<code>#x0000003C</code>" | ||
1494 | and '?' is "<code>#x0000003F</code>", and the Byte Order Mark | ||
1495 | required 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 | ||
1498 | FF</code></td><td rowspan="1" colspan="1">UCS-4, big-endian machine (1234 order)</td></tr><tr><td rowspan="1" colspan="1"><code>FF | ||
1499 | FE 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 | ||
1500 | characters encoded as ASCII values, in respectively big-endian (1234), little-endian | ||
1501 | (4321) and two unusual byte orders (2143 and 3412). The encoding declaration | ||
1502 | must be read to determine which of UCS-4 or other supported 32-bit encodings | ||
1503 | applies.</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 | ||
1504 | or other encoding with a 16-bit code unit in big-endian order and ASCII characters | ||
1505 | encoded as ASCII values (the encoding declaration must be read to determine | ||
1506 | which)</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 | ||
1507 | ISO-10646-UCS-2 or other encoding with a 16-bit code unit in little-endian | ||
1508 | order and ASCII characters encoded as ASCII values (the encoding declaration | ||
1509 | must 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 | ||
1510 | 7-bit, 8-bit, or mixed-width encoding which ensures that the characters of | ||
1511 | ASCII have their normal positions, width, and values; the actual encoding | ||
1512 | declaration must be read to detect which of these applies, but since all of | ||
1513 | these encodings use the same bit patterns for the relevant ASCII characters, | ||
1514 | the encoding declaration itself may be read reliably</td></tr><tr><td rowspan="1" colspan="1"><code>4C | ||
1515 | 6F A7 94</code></td><td rowspan="1" colspan="1">EBCDIC (in some flavor; the full encoding declaration | ||
1516 | must 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 | ||
1518 | in 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 | ||
1519 | determine the encoding, section 4.3.3 still requires that the encoding declaration, | ||
1520 | if present, be read and that the encoding name be checked to match the actual | ||
1521 | encoding of the entity. Also, it is possible that new character encodings | ||
1522 | will be invented that will make it necessary to use the encoding declaration | ||
1523 | to 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 | ||
1524 | and parse the character-encoding identifier, which is still necessary to distinguish | ||
1525 | the individual members of each family of encodings (e.g. to tell UTF-8 from | ||
1526 | 8859, and the parts of 8859 from each other, or to distinguish the specific | ||
1527 | EBCDIC code page in use, and so on).</p><p>Because the contents of the encoding declaration are restricted to characters | ||
1528 | from the ASCII repertoire (however encoded), | ||
1529 | a processor can reliably read the entire encoding declaration as soon as it | ||
1530 | has detected which family of encodings is in use. Since in practice, all widely | ||
1531 | used character encodings fall into one of the categories above, the XML encoding | ||
1532 | declaration allows reasonably reliable in-band labeling of character encodings, | ||
1533 | even when external sources of information at the operating-system or transport-protocol | ||
1534 | level are unreliable. Character encodings such as UTF-7 | ||
1535 | that 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 | ||
1536 | appropriately, whether by invoking a separate input routine for each case, | ||
1537 | or 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 | ||
1538 | if any software changes the entity's character set or encoding without updating | ||
1539 | the encoding declaration. Implementors of character-encoding routines should | ||
1540 | be careful to ensure the accuracy of the internal and external information | ||
1541 | used 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 | ||
1542 | information, as in some file systems and some network protocols. When multiple | ||
1543 | sources of information are available, their relative priority and the preferred | ||
1544 | method of handling conflict should be specified as part of the higher-level | ||
1545 | protocol used to deliver XML. In particular, please refer | ||
1546 | to <a href="#rfc2376">[IETF RFC 3023]</a> or its successor, which defines the <code>text/xml</code> | ||
1547 | and <code>application/xml</code> MIME types and provides some useful guidance. | ||
1548 | In 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 | ||
1550 | XML Working Group (WG). WG approval of this specification does not necessarily | ||
1551 | imply that all WG participants voted for its approval. The current and former members | ||
1552 | in 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 | ||
1553 | Co-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 | ||
1554 | SA, Muzmo and Veo Systems</li><li>MURATA Makoto (FAMILY Given), Fuji | ||
1555 | Xerox 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 | ||
1556 | Working Group (WG). The participants in the WG at the time of publication of this | ||
1557 | edition 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 | ||
1558 | slightly modified version of the | ||
1559 | <a href="http://www.w3.org/2002/xmlspec/dtd/2.5/xmlspec.dtd">XMLspec DTD, 2.5</a>. | ||
1560 | The 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>, | ||
1563 | and <a href="REC-xml-3e.xsl">REC-xml-3e.xsl</a> | ||
1564 | XSLT 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 | ||
1565 | practice in the construction of XML names used as element names, | ||
1566 | attribute names, processing instruction targets, entity names, | ||
1567 | notation names, and the values of attributes of type ID, and are | ||
1568 | intended as guidance for document authors and schema designers. | ||
1569 | All references to Unicode are understood with respect to | ||
1570 | a particular version of the Unicode Standard greater than or equal | ||
1571 | to 3.0; which version should be used is left to the discretion of | ||
1572 | the document author or schema designer.</p><p>The first two suggestions are directly derived from the rules | ||
1573 | given for identifiers in the Unicode Standard, version 3.0, and | ||
1574 | exclude all control characters, enclosing nonspacing marks, | ||
1575 | non-decimal numbers, private-use characters, punctuation characters | ||
1576 | (with the noted exceptions), symbol characters, unassigned | ||
1577 | codepoints, and white space characters. The other suggestions | ||
1578 | are 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 | ||
1579 | Category 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 | ||
1580 | Category of Ll, Lu, Lo, Lm, Lt, Mc, Mn, Nl, Nd, Pc, or Cf, or else | ||
1581 | be one of the following: '-' #x2D, '.' #x2E, ':' #x3A or | ||
1582 | '·' #xB7 (middle dot). Since Cf characters are not | ||
1583 | directly visible, they should be employed with caution and only | ||
1584 | when necessary, to avoid creating names which are distinct to XML | ||
1585 | processors 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 | ||
1589 | a "compatibility formatting tag" in field 5 of the Unicode | ||
1590 | Character Database -- marked by field 5 beginning with a "<") | ||
1591 | should not be used in names. This suggestion does not apply | ||
1592 | to #x0E33 THAI CHARACTER SARA AM or #x0EB3 LAO CHARACTER AM, which | ||
1593 | despite their compatibility decompositions are in regular use in | ||
1594 | those scripts.</p></li><li><p>Combining characters meant for use with symbols only (including | ||
1595 | those in the ranges [#x20D0-#x20EF] and [#x1D165-#x1D1AD]) should | ||
1596 | not be used in names.</p></li><li><p>The interlinear annotation characters ([#xFFF9-#xFFFB) should | ||
1597 | not 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 | ||
1598 | easily 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 | |||
3 | cd src/bu | ||
4 | rm * | ||
5 | for 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 | |||
3 | Bu::Archival::Archival() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::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 | |||
4 | namespace 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 | |||
3 | Bu::Archive::Archive( Stream &rStream, bool bLoading ) : | ||
4 | bLoading( bLoading ), | ||
5 | rStream( rStream ), | ||
6 | nNextID( 1 ) | ||
7 | { | ||
8 | } | ||
9 | |||
10 | Bu::Archive::~Archive() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | void 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 | |||
22 | void 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 | |||
30 | void Bu::Archive::close() | ||
31 | { | ||
32 | rStream.close(); | ||
33 | } | ||
34 | |||
35 | bool Bu::Archive::isLoading() | ||
36 | { | ||
37 | return bLoading; | ||
38 | } | ||
39 | Bu::Archive &Bu::Archive::operator<<(bool p) | ||
40 | { | ||
41 | write( &p, sizeof(p) ); | ||
42 | return *this; | ||
43 | } | ||
44 | Bu::Archive &Bu::Archive::operator<<(int8_t p) | ||
45 | { | ||
46 | write( &p, sizeof(p) ); | ||
47 | return *this; | ||
48 | } | ||
49 | Bu::Archive &Bu::Archive::operator<<(int16_t p) | ||
50 | { | ||
51 | write( &p, sizeof(p) ); | ||
52 | return *this; | ||
53 | } | ||
54 | Bu::Archive &Bu::Archive::operator<<(int32_t p) | ||
55 | { | ||
56 | write( &p, sizeof(p) ); | ||
57 | return *this; | ||
58 | } | ||
59 | Bu::Archive &Bu::Archive::operator<<(int64_t p) | ||
60 | { | ||
61 | write( &p, sizeof(p) ); | ||
62 | return *this; | ||
63 | } | ||
64 | Bu::Archive &Bu::Archive::operator<<(uint8_t p) | ||
65 | { | ||
66 | write( &p, sizeof(p) ); | ||
67 | return *this; | ||
68 | } | ||
69 | Bu::Archive &Bu::Archive::operator<<(uint16_t p) | ||
70 | { | ||
71 | write( &p, sizeof(p) ); | ||
72 | return *this; | ||
73 | } | ||
74 | Bu::Archive &Bu::Archive::operator<<(uint32_t p) | ||
75 | { | ||
76 | write( &p, sizeof(p) ); | ||
77 | return *this; | ||
78 | } | ||
79 | Bu::Archive &Bu::Archive::operator<<(uint64_t p) | ||
80 | { | ||
81 | write( &p, sizeof(p) ); | ||
82 | return *this; | ||
83 | } | ||
84 | Bu::Archive &Bu::Archive::operator<<(long p) | ||
85 | { | ||
86 | write( &p, sizeof(p) ); | ||
87 | return *this; | ||
88 | } | ||
89 | Bu::Archive &Bu::Archive::operator<<(float p) | ||
90 | { | ||
91 | write( &p, sizeof(p) ); | ||
92 | return *this; | ||
93 | } | ||
94 | Bu::Archive &Bu::Archive::operator<<(double p) | ||
95 | { | ||
96 | write( &p, sizeof(p) ); | ||
97 | return *this; | ||
98 | } | ||
99 | Bu::Archive &Bu::Archive::operator<<(long double p) | ||
100 | { | ||
101 | write( &p, sizeof(p) ); | ||
102 | return *this; | ||
103 | } | ||
104 | |||
105 | Bu::Archive &Bu::Archive::operator>>(bool &p) | ||
106 | { | ||
107 | read( &p, sizeof(p) ); | ||
108 | return *this; | ||
109 | } | ||
110 | Bu::Archive &Bu::Archive::operator>>(int8_t &p) | ||
111 | { | ||
112 | read( &p, sizeof(p) ); | ||
113 | return *this; | ||
114 | } | ||
115 | Bu::Archive &Bu::Archive::operator>>(int16_t &p) | ||
116 | { | ||
117 | read( &p, sizeof(p) ); | ||
118 | return *this; | ||
119 | } | ||
120 | Bu::Archive &Bu::Archive::operator>>(int32_t &p) | ||
121 | { | ||
122 | read( &p, sizeof(p) ); | ||
123 | return *this; | ||
124 | } | ||
125 | Bu::Archive &Bu::Archive::operator>>(int64_t &p) | ||
126 | { | ||
127 | read( &p, sizeof(p) ); | ||
128 | return *this; | ||
129 | } | ||
130 | Bu::Archive &Bu::Archive::operator>>(uint8_t &p) | ||
131 | { | ||
132 | read( &p, sizeof(p) ); | ||
133 | return *this; | ||
134 | } | ||
135 | Bu::Archive &Bu::Archive::operator>>(uint16_t &p) | ||
136 | { | ||
137 | read( &p, sizeof(p) ); | ||
138 | return *this; | ||
139 | } | ||
140 | Bu::Archive &Bu::Archive::operator>>(uint32_t &p) | ||
141 | { | ||
142 | read( &p, sizeof(p) ); | ||
143 | return *this; | ||
144 | } | ||
145 | Bu::Archive &Bu::Archive::operator>>(uint64_t &p) | ||
146 | { | ||
147 | read( &p, sizeof(p) ); | ||
148 | return *this; | ||
149 | } | ||
150 | Bu::Archive &Bu::Archive::operator>>(long &p) | ||
151 | { | ||
152 | read( &p, sizeof(p) ); | ||
153 | return *this; | ||
154 | } | ||
155 | Bu::Archive &Bu::Archive::operator>>(float &p) | ||
156 | { | ||
157 | read( &p, sizeof(p) ); | ||
158 | return *this; | ||
159 | } | ||
160 | Bu::Archive &Bu::Archive::operator>>(double &p) | ||
161 | { | ||
162 | read( &p, sizeof(p) ); | ||
163 | return *this; | ||
164 | } | ||
165 | Bu::Archive &Bu::Archive::operator>>(long double &p) | ||
166 | { | ||
167 | read( &p, sizeof(p) ); | ||
168 | return *this; | ||
169 | } | ||
170 | |||
171 | Bu::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 | |||
183 | Bu::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 | |||
195 | Bu::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 | |||
207 | Bu::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 | |||
219 | Bu::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 | |||
231 | Bu::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 | |||
243 | Bu::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 | |||
255 | Bu::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 | |||
267 | Bu::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 | |||
279 | Bu::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 | |||
291 | Bu::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 | |||
303 | Bu::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 | |||
316 | Bu::Archive &Bu::operator<<(Bu::Archive &s, Bu::Archival &p) | ||
317 | { | ||
318 | p.archive( s ); | ||
319 | return s; | ||
320 | } | ||
321 | |||
322 | Bu::Archive &Bu::operator>>(Bu::Archive &s, Bu::Archival &p) | ||
323 | { | ||
324 | p.archive( s ); | ||
325 | return s; | ||
326 | } | ||
327 | |||
328 | Bu::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 | |||
336 | Bu::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 | |||
349 | uint32_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 | |||
357 | void 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 | |||
371 | void 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 | |||
12 | namespace 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 | |||
5 | ArrayList::ArrayList( int initSize, int growByFactor ) | ||
6 | { | ||
7 | apData = new void *[initSize]; | ||
8 | nSize = 0; | ||
9 | nCapacity = initSize; | ||
10 | nGrowByFactor = growByFactor; | ||
11 | } | ||
12 | |||
13 | ArrayList::~ArrayList( ) | ||
14 | { | ||
15 | delete[] apData; | ||
16 | } | ||
17 | |||
18 | void *ArrayList::getAt( int index ) | ||
19 | { | ||
20 | if( index < 0 || index > nSize ) | ||
21 | return NULL; | ||
22 | |||
23 | return apData[index]; | ||
24 | } | ||
25 | |||
26 | void ArrayList::append( void *data ) | ||
27 | { | ||
28 | insertBefore( data, nSize ); | ||
29 | } | ||
30 | |||
31 | void 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 | |||
42 | int ArrayList::getSize( ) | ||
43 | { | ||
44 | return nSize; | ||
45 | } | ||
46 | |||
47 | bool ArrayList::isEmpty( ) | ||
48 | { | ||
49 | return nSize==0; | ||
50 | } | ||
51 | |||
52 | void 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 | |||
61 | void ArrayList::empty() | ||
62 | { | ||
63 | // Probably the easiest as far as things go. | ||
64 | nSize = 0; | ||
65 | } | ||
66 | |||
67 | void 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 | |||
76 | void ArrayList::checkResize() | ||
77 | { | ||
78 | if( nSize >= nCapacity ) | ||
79 | { | ||
80 | resizeTo( nCapacity + nGrowByFactor ); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | void ArrayList::setSize( int newSize ) | ||
85 | { | ||
86 | if( newSize < 0 ) | ||
87 | return; | ||
88 | |||
89 | nSize = newSize; | ||
90 | checkResize(); | ||
91 | } | ||
92 | |||
93 | void 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 | */ | ||
15 | class ArrayList : public List | ||
16 | { | ||
17 | public: | ||
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 | |||
39 | private: | ||
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 | |||
8 | namespace 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 | |||
4 | using namespace Bu; | ||
5 | |||
6 | Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) : | ||
7 | Bu::Filter( rNext ), | ||
8 | nCompression( nCompression ) | ||
9 | { | ||
10 | start(); | ||
11 | } | ||
12 | |||
13 | Bu::BZip2::~BZip2() | ||
14 | { | ||
15 | stop(); | ||
16 | } | ||
17 | |||
18 | void 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 | |||
29 | size_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 | |||
66 | void 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 | |||
109 | size_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 | |||
161 | size_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 | |||
192 | bool 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 | |||
9 | namespace 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 | |||
11 | Bu::Client::Client( Bu::Socket *pSocket ) : | ||
12 | pSocket( pSocket ), | ||
13 | pProto( NULL ), | ||
14 | nRBOffset( 0 ) | ||
15 | { | ||
16 | } | ||
17 | |||
18 | Bu::Client::~Client() | ||
19 | { | ||
20 | } | ||
21 | |||
22 | void 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 | |||
62 | void Bu::Client::processOutput() | ||
63 | { | ||
64 | if( sWriteBuf.getSize() > 0 ) | ||
65 | { | ||
66 | pSocket->write( sWriteBuf.getStr(), sWriteBuf.getSize() ); | ||
67 | sWriteBuf.clear(); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | void Bu::Client::setProtocol( Protocol *pProto ) | ||
72 | { | ||
73 | this->pProto = pProto; | ||
74 | } | ||
75 | |||
76 | Bu::Protocol *Bu::Client::getProtocol() | ||
77 | { | ||
78 | return pProto; | ||
79 | } | ||
80 | |||
81 | void Bu::Client::clearProtocol() | ||
82 | { | ||
83 | pProto = NULL; | ||
84 | } | ||
85 | |||
86 | Bu::FString &Bu::Client::getInput() | ||
87 | { | ||
88 | return sReadBuf; | ||
89 | } | ||
90 | |||
91 | Bu::FString &Bu::Client::getOutput() | ||
92 | { | ||
93 | return sWriteBuf; | ||
94 | } | ||
95 | |||
96 | bool Bu::Client::isOpen() | ||
97 | { | ||
98 | if( !pSocket ) return false; | ||
99 | return pSocket->isOpen(); | ||
100 | } | ||
101 | |||
102 | void Bu::Client::write( const void *pData, int nBytes ) | ||
103 | { | ||
104 | sWriteBuf.append( (const char *)pData, nBytes ); | ||
105 | } | ||
106 | |||
107 | void Bu::Client::write( int8_t nData ) | ||
108 | { | ||
109 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
110 | } | ||
111 | |||
112 | void Bu::Client::write( int16_t nData ) | ||
113 | { | ||
114 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
115 | } | ||
116 | |||
117 | void Bu::Client::write( int32_t nData ) | ||
118 | { | ||
119 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
120 | } | ||
121 | |||
122 | void Bu::Client::write( int64_t nData ) | ||
123 | { | ||
124 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
125 | } | ||
126 | |||
127 | void Bu::Client::write( uint8_t nData ) | ||
128 | { | ||
129 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
130 | } | ||
131 | |||
132 | void Bu::Client::write( uint16_t nData ) | ||
133 | { | ||
134 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
135 | } | ||
136 | |||
137 | void Bu::Client::write( uint32_t nData ) | ||
138 | { | ||
139 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
140 | } | ||
141 | |||
142 | void Bu::Client::write( uint64_t nData ) | ||
143 | { | ||
144 | sWriteBuf.append( (const char *)&nData, sizeof(nData) ); | ||
145 | } | ||
146 | |||
147 | void 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 | |||
168 | void Bu::Client::peek( void *pData, int nBytes ) | ||
169 | { | ||
170 | memcpy( pData, sReadBuf.getStr()+nRBOffset, nBytes ); | ||
171 | } | ||
172 | |||
173 | void 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 | |||
193 | long Bu::Client::getInputSize() | ||
194 | { | ||
195 | return sReadBuf.getSize()-nRBOffset; | ||
196 | } | ||
197 | |||
198 | const Bu::Socket *Bu::Client::getSocket() const | ||
199 | { | ||
200 | return pSocket; | ||
201 | } | ||
202 | |||
203 | void 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 | |||
8 | namespace 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 <stdint.h> | ||
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 | |||
38 | using namespace Bu; | ||
39 | |||
40 | Bu::{=name}::{=name}() | ||
41 | { | ||
42 | } | ||
43 | |||
44 | Bu::{=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 | ||
4 | ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() : | 4 | Bu::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 | ||
15 | ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() : | 15 | Bu::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 | ||
26 | ExceptionBase::ExceptionBase( int nCode ) throw() : | 26 | Bu::ExceptionBase::ExceptionBase( int nCode ) throw() : |
27 | nErrorCode( nCode ), | 27 | nErrorCode( nCode ), |
28 | sWhat( NULL ) | 28 | sWhat( NULL ) |
29 | { | 29 | { |
30 | } | 30 | } |
31 | 31 | ||
32 | ExceptionBase::~ExceptionBase() throw() | 32 | Bu::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 | ||
41 | void ExceptionBase::setWhat( const char *lpFormat, va_list &vargs ) | 41 | void 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 | ||
51 | void ExceptionBase::setWhat( const char *lpText ) | 51 | void 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 | ||
61 | const char *ExceptionBase::what() const throw() | 61 | const char *Bu::ExceptionBase::what() const throw() |
62 | { | 62 | { |
63 | return sWhat; | 63 | return sWhat; |
64 | } | 64 | } |
65 | 65 | ||
66 | int ExceptionBase::getErrorCode() | 66 | int 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 | /** | 8 | namespace 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 | */ | ||
12 | class ExceptionBase : public std::exception | ||
13 | { | 9 | { |
14 | public: | ||
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 | ||
69 | private: | 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 ) \ |
75 | class name : public ExceptionBase \ | 84 | class 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 | ||
4 | subExceptionDef( XmlException ) | 4 | namespace Bu |
5 | subExceptionDef( FileException ) | 5 | { |
6 | subExceptionDef( ConnectionException ) | 6 | subExceptionDef( XmlException ) |
7 | subExceptionDef( 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 | ||
7 | subExceptionDecl( XmlException ) | 7 | namespace Bu |
8 | subExceptionDecl( FileException ) | ||
9 | subExceptionDecl( ConnectionException ) | ||
10 | subExceptionDecl( PluginException ) | ||
11 | |||
12 | enum eFileException | ||
13 | { | ||
14 | excodeEOF | ||
15 | }; | ||
16 | |||
17 | enum 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 | |||
7 | Bu::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 | |||
16 | Bu::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 | |||
25 | Bu::File::File( int fd, const char *sFlags ) | ||
26 | { | ||
27 | fh = fdopen( fd, sFlags ); | ||
28 | } | ||
29 | |||
30 | Bu::File::~File() | ||
31 | { | ||
32 | close(); | ||
33 | } | ||
34 | |||
35 | void Bu::File::close() | ||
36 | { | ||
37 | if( fh ) | ||
38 | { | ||
39 | fclose( fh ); | ||
40 | fh = NULL; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | size_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 | |||
57 | size_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 | |||
65 | long Bu::File::tell() | ||
66 | { | ||
67 | if( !fh ) | ||
68 | throw FileException("File not open."); | ||
69 | |||
70 | return ftell( fh ); | ||
71 | } | ||
72 | |||
73 | void Bu::File::seek( long offset ) | ||
74 | { | ||
75 | if( !fh ) | ||
76 | throw FileException("File not open."); | ||
77 | |||
78 | fseek( fh, offset, SEEK_CUR ); | ||
79 | } | ||
80 | |||
81 | void Bu::File::setPos( long pos ) | ||
82 | { | ||
83 | if( !fh ) | ||
84 | throw FileException("File not open."); | ||
85 | |||
86 | fseek( fh, pos, SEEK_SET ); | ||
87 | } | ||
88 | |||
89 | void Bu::File::setPosEnd( long pos ) | ||
90 | { | ||
91 | if( !fh ) | ||
92 | throw FileException("File not open."); | ||
93 | |||
94 | fseek( fh, pos, SEEK_END ); | ||
95 | } | ||
96 | |||
97 | bool Bu::File::isEOS() | ||
98 | { | ||
99 | return feof( fh ); | ||
100 | } | ||
101 | |||
102 | bool Bu::File::canRead() | ||
103 | { | ||
104 | return true; | ||
105 | } | ||
106 | |||
107 | bool Bu::File::canWrite() | ||
108 | { | ||
109 | return true; | ||
110 | } | ||
111 | |||
112 | bool Bu::File::isReadable() | ||
113 | { | ||
114 | return true; | ||
115 | } | ||
116 | |||
117 | bool Bu::File::isWritable() | ||
118 | { | ||
119 | return true; | ||
120 | } | ||
121 | |||
122 | bool Bu::File::isSeekable() | ||
123 | { | ||
124 | return true; | ||
125 | } | ||
126 | |||
127 | bool Bu::File::isBlocking() | ||
128 | { | ||
129 | return true; | ||
130 | } | ||
131 | |||
132 | void Bu::File::setBlocking( bool bBlocking ) | ||
133 | { | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | #ifndef WIN32 | ||
138 | void Bu::File::truncate( long nSize ) | ||
139 | { | ||
140 | ftruncate( fileno( fh ), nSize ); | ||
141 | } | ||
142 | |||
143 | void Bu::File::chmod( mode_t t ) | ||
144 | { | ||
145 | fchmod( fileno( fh ), t ); | ||
146 | } | ||
147 | #endif | ||
148 | |||
149 | void Bu::File::flush() | ||
150 | { | ||
151 | fflush( fh ); | ||
152 | } | ||
153 | |||
154 | bool 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 | |||
9 | namespace 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 | |||
3 | Bu::Filter::Filter( Bu::Stream &rNext ) : | ||
4 | rNext( rNext ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | Bu::Filter::~Filter() | ||
9 | { | ||
10 | //printf("-> Bu::Filter::~Filter()\n"); | ||
11 | } | ||
12 | /* | ||
13 | void Bu::Filter::start() | ||
14 | { | ||
15 | printf("-> Bu::Filter::start()\n"); | ||
16 | } | ||
17 | |||
18 | void Bu::Filter::stop() | ||
19 | { | ||
20 | }*/ | ||
21 | |||
22 | void Bu::Filter::close() | ||
23 | { | ||
24 | stop(); | ||
25 | rNext.close(); | ||
26 | } | ||
27 | |||
28 | long Bu::Filter::tell() | ||
29 | { | ||
30 | return rNext.tell(); | ||
31 | } | ||
32 | |||
33 | void Bu::Filter::seek( long offset ) | ||
34 | { | ||
35 | rNext.seek( offset ); | ||
36 | } | ||
37 | |||
38 | void Bu::Filter::setPos( long pos ) | ||
39 | { | ||
40 | rNext.setPos( pos ); | ||
41 | } | ||
42 | |||
43 | void Bu::Filter::setPosEnd( long pos ) | ||
44 | { | ||
45 | rNext.setPosEnd( pos ); | ||
46 | } | ||
47 | |||
48 | bool Bu::Filter::isEOS() | ||
49 | { | ||
50 | return rNext.isEOS(); | ||
51 | } | ||
52 | |||
53 | bool Bu::Filter::isOpen() | ||
54 | { | ||
55 | return rNext.isOpen(); | ||
56 | } | ||
57 | |||
58 | bool Bu::Filter::canRead() | ||
59 | { | ||
60 | return rNext.canRead(); | ||
61 | } | ||
62 | |||
63 | bool Bu::Filter::canWrite() | ||
64 | { | ||
65 | return rNext.canWrite(); | ||
66 | } | ||
67 | |||
68 | bool Bu::Filter::isReadable() | ||
69 | { | ||
70 | return rNext.isReadable(); | ||
71 | } | ||
72 | |||
73 | bool Bu::Filter::isWritable() | ||
74 | { | ||
75 | return rNext.isWritable(); | ||
76 | } | ||
77 | |||
78 | bool Bu::Filter::isSeekable() | ||
79 | { | ||
80 | return rNext.isSeekable(); | ||
81 | } | ||
82 | |||
83 | bool Bu::Filter::isBlocking() | ||
84 | { | ||
85 | return rNext.isBlocking(); | ||
86 | } | ||
87 | |||
88 | void Bu::Filter::setBlocking( bool bBlocking ) | ||
89 | { | ||
90 | rNext.setBlocking( bBlocking ); | ||
91 | } | ||
92 | |||
93 | void 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 | |||
8 | namespace 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 | ||
4 | template<> uint32_t __calcHashCode<FString>( const FString &k ) | 4 | template<> 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 | ||
9 | template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ) | 9 | template<> 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 | ||
15 | std::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 | ||
9 | template< typename chr > | 10 | #define min( a, b ) ((a<b)?(a):(b)) |
10 | struct FStringChunk | 11 | |
11 | { | 12 | namespace 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 | */ | ||
28 | template< typename chr, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > > | ||
29 | class 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 |
34 | private: | 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 | ||
38 | public: | 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 | ||
385 | private: | 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 | ||
634 | private: | 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 | ||
644 | typedef FBasicString<char> FString; | 894 | typedef FBasicString<char> FString; |
645 | 895 | ||
646 | #include "hash.h" | 896 | template<> uint32_t __calcHashCode<FString>( const FString &k ); |
647 | template<> uint32_t __calcHashCode<FString>( const FString &k ); | 897 | template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ); |
648 | template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ); | 898 | } |
649 | 899 | ||
900 | #include <ostream> | ||
901 | std::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 | ||
3 | subExceptionDef( HashException ) | 3 | namespace Bu { subExceptionDef( HashException ) } |
4 | 4 | ||
5 | template<> uint32_t __calcHashCode<int>( const int &k ) | 5 | template<> uint32_t Bu::__calcHashCode<int>( const int &k ) |
6 | { | 6 | { |
7 | return k; | 7 | return k; |
8 | } | 8 | } |
9 | 9 | ||
10 | template<> bool __cmpHashKeys<int>( const int &a, const int &b ) | 10 | template<> bool Bu::__cmpHashKeys<int>( const int &a, const int &b ) |
11 | { | 11 | { |
12 | return a == b; | 12 | return a == b; |
13 | } | 13 | } |
14 | 14 | ||
15 | template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k ) | 15 | template<> uint32_t Bu::__calcHashCode<unsigned int>( const unsigned int &k ) |
16 | { | 16 | { |
17 | return k; | 17 | return k; |
18 | } | 18 | } |
19 | 19 | ||
20 | template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b ) | 20 | template<> 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 | ||
25 | template<> | 25 | template<> |
26 | uint32_t __calcHashCode<const char *>( const char * const &k ) | 26 | uint32_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 | ||
42 | template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b ) | 42 | template<> 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 | ||
54 | template<> | 54 | template<> |
55 | uint32_t __calcHashCode<char *>( char * const &k ) | 55 | uint32_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 | ||
71 | template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b ) | 71 | template<> 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 | ||
83 | template<> uint32_t __calcHashCode<std::string>( const std::string &k ) | 83 | template<> 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 | ||
97 | template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b ) | 97 | template<> 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 | ||
102 | template<> uint32_t __calcHashCode<Hashable>( const Hashable &k ) | ||
103 | { | ||
104 | return 0; | ||
105 | //return k.getHashCode(); | ||
106 | } | ||
107 | |||
108 | template<> bool __cmpHashKeys<Hashable>( const Hashable &a, const Hashable &b ) | ||
109 | { | ||
110 | return false; | ||
111 | //return a.compareForHash( b ); | ||
112 | } | ||
113 | |||
@@ -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 | ||
16 | subExceptionDecl( HashException ) | 17 | namespace Bu |
17 | |||
18 | enum eHashException | ||
19 | { | 18 | { |
20 | excodeNotFilled | 19 | subExceptionDecl( HashException ) |
21 | }; | ||
22 | |||
23 | template<typename T> | ||
24 | uint32_t __calcHashCode( const T &k ); | ||
25 | |||
26 | template<typename T> | ||
27 | bool __cmpHashKeys( const T &a, const T &b ); | ||
28 | 20 | ||
29 | struct __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 | ||
39 | 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> > | 26 | template<typename T> |
40 | class Hash; | 27 | uint32_t __calcHashCode( const T &k ); |
41 | 28 | ||
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> > | 29 | template<typename T> |
43 | struct HashProxy | 30 | bool __cmpHashKeys( const T &a, const T &b ); |
44 | { | ||
45 | friend class Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc>; | ||
46 | private: | ||
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 | ||
71 | public: | 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 | ||
134 | template<typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc > | 141 | return nval; |
135 | class Hash | 142 | } |
136 | { | ||
137 | friend struct HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>; | ||
138 | public: | ||
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 | ||
482 | protected: | 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 | ||
668 | protected: | 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 | |||
684 | template<> uint32_t __calcHashCode<int>( const int &k ); | ||
685 | template<> bool __cmpHashKeys<int>( const int &a, const int &b ); | ||
686 | |||
687 | template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k ); | ||
688 | template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b ); | ||
689 | |||
690 | template<> uint32_t __calcHashCode<const char *>( const char * const &k ); | ||
691 | template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b ); | ||
692 | |||
693 | template<> uint32_t __calcHashCode<char *>( char * const &k ); | ||
694 | template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b ); | ||
695 | |||
696 | template<> uint32_t __calcHashCode<std::string>( const std::string &k ); | ||
697 | template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b ); | ||
698 | |||
699 | template<> uint32_t __calcHashCode<Hashable>( const Hashable &k ); | ||
700 | template<> bool __cmpHashKeys<Hashable>( const Hashable &a, const Hashable &b ); | ||
701 | |||
702 | template<typename key, typename value> | ||
703 | Serializer &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 | ||
715 | template<typename key, typename value> | 1056 | /* |
716 | Serializer &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 | } | |
732 | template<typename key, typename value> | 1068 | }*/ |
733 | Serializer &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 | |||
4 | class Hashable | ||
5 | { | ||
6 | public: | ||
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 | |||
3 | HashFunction::HashFunction() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | HashFunction::~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 | */ | ||
10 | class HashFunction | ||
11 | { | ||
12 | public: | ||
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 | |||
6 | HashFunctionCaseString::HashFunctionCaseString() | ||
7 | { | ||
8 | } | ||
9 | |||
10 | HashFunctionCaseString::~HashFunctionCaseString() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | unsigned 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 | |||
26 | bool 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 | */ | ||
12 | class HashFunctionCaseString : public HashFunction | ||
13 | { | ||
14 | public: | ||
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 | |||
3 | HashFunctionInt::HashFunctionInt() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | HashFunctionInt::~HashFunctionInt() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | unsigned long int HashFunctionInt::hash( const void *id ) | ||
12 | { | ||
13 | return (unsigned long)(id); | ||
14 | } | ||
15 | |||
16 | bool 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 | */ | ||
10 | class HashFunctionInt : public HashFunction | ||
11 | { | ||
12 | public: | ||
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 | |||
6 | HashFunctionString::HashFunctionString() | ||
7 | { | ||
8 | } | ||
9 | |||
10 | HashFunctionString::~HashFunctionString() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | unsigned 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 | |||
29 | bool 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 | */ | ||
11 | class HashFunctionString : public HashFunction | ||
12 | { | ||
13 | public: | ||
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 | |||
7 | HashTable::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 | |||
18 | HashTable::~HashTable() | ||
19 | { | ||
20 | delete[] aTable; | ||
21 | delete hFunc; | ||
22 | } | ||
23 | |||
24 | void 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 | |||
34 | void HashTable::clear() | ||
35 | { | ||
36 | memset( aTable, 0, sizeof(HashNode) * nTableSize ); | ||
37 | } | ||
38 | |||
39 | bool HashTable::isFilled( int j ) | ||
40 | { | ||
41 | return (aTable[j].id != NULL)||(aTable[j].bDeleted); | ||
42 | } | ||
43 | |||
44 | void 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 | |||
74 | unsigned 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 | |||
129 | HashTable::HashNode *HashTable::newTable( unsigned long int nNewSize ) | ||
130 | { | ||
131 | return new HashNode[nNewSize]; | ||
132 | } | ||
133 | |||
134 | #ifdef HASH_DEBUG_VIS | ||
135 | void 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 | |||
151 | bool 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 | |||
199 | const 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 | |||
248 | const 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 | |||
297 | void *HashTable::getFirstItemPos() | ||
298 | { | ||
299 | HashPos *pos = new HashPos; | ||
300 | return pos; | ||
301 | } | ||
302 | |||
303 | const void *HashTable::getItemData( void *xPos ) | ||
304 | { | ||
305 | return aTable[((HashPos *)xPos)->nPos].data; | ||
306 | } | ||
307 | |||
308 | const void *HashTable::getItemID( void *xPos ) | ||
309 | { | ||
310 | return aTable[((HashPos *)xPos)->nPos].id; | ||
311 | } | ||
312 | |||
313 | void *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. | ||
345 | bool 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) | ||
368 | int HashTable::nextPrime( int base ) | ||
369 | { | ||
370 | int nPrime; | ||
371 | for( nPrime = base; isPrime( nPrime ) == false; nPrime++ ); | ||
372 | return nPrime; | ||
373 | } | ||
374 | |||
375 | unsigned long int HashTable::getCapacity() | ||
376 | { | ||
377 | return nTableSize; | ||
378 | } | ||
379 | |||
380 | unsigned long int HashTable::getSize() | ||
381 | { | ||
382 | return nSize; | ||
383 | } | ||
384 | |||
385 | double HashTable::getLoad() | ||
386 | { | ||
387 | return (double)(nFilled)/(double)(nTableSize); | ||
388 | } | ||
389 | |||
390 | const void *HashTable::operator[](const void *id) | ||
391 | { | ||
392 | return get( id ); | ||
393 | } | ||
394 | |||
395 | bool 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 | */ | ||
55 | class HashTable | ||
56 | { | ||
57 | public: | ||
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 | |||
187 | private: | ||
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 | |||
227 | private: | ||
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 | |||
3 | Bu::XmlDocument::XmlDocument() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::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 | |||
6 | namespace 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 | |||
3 | Bu::XmlNode::XmlNode() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::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 | |||
6 | namespace 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 | |||
3 | Bu::XmlReader::XmlReader( Bu::Stream &sIn ) : | ||
4 | sIn( sIn ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | Bu::XmlReader::~XmlReader() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | const 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 | |||
25 | void Bu::XmlReader::burn( int nAmnt ) | ||
26 | { | ||
27 | if( sBuf.getSize() < nAmnt ) | ||
28 | { | ||
29 | lookahead( nAmnt ); | ||
30 | } | ||
31 | |||
32 | //sBuf.remove( nAmnt ); | ||
33 | } | ||
34 | |||
35 | void 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 | |||
46 | Bu::XmlNode *Bu::XmlReader::read() | ||
47 | { | ||
48 | prolog(); | ||
49 | } | ||
50 | |||
51 | void Bu::XmlReader::prolog() | ||
52 | { | ||
53 | XMLDecl(); | ||
54 | Misc(); | ||
55 | } | ||
56 | |||
57 | void Bu::XmlReader::XMLDecl() | ||
58 | { | ||
59 | checkString("<?xml", 5 ); | ||
60 | S(); | ||
61 | VersionInfo(); | ||
62 | EncodingDecl(); | ||
63 | SDDecl(); | ||
64 | Sq(); | ||
65 | checkString("?>", 2 ); | ||
66 | } | ||
67 | |||
68 | void 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 | |||
88 | void 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 | |||
106 | void 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 | |||
122 | void 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 | |||
135 | void 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 | |||
146 | void 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 | |||
163 | void Bu::XmlReader::Eq() | ||
164 | { | ||
165 | Sq(); | ||
166 | checkString("=", 1 ); | ||
167 | Sq(); | ||
168 | } | ||
169 | |||
170 | void 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 | |||
186 | void 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 | |||
202 | Bu::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 | |||
233 | Bu::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 | |||
9 | namespace 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 | |||
3 | Bu::XmlWriter::XmlWriter() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::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 | |||
6 | namespace 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 | |||
3 | Bu::Ito::Ito() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::Ito::~Ito() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | bool Bu::Ito::start() | ||
12 | { | ||
13 | nHandle = pthread_create( &ptHandle, NULL, threadRunner, this ); | ||
14 | |||
15 | return true; | ||
16 | } | ||
17 | |||
18 | bool Bu::Ito::stop() | ||
19 | { | ||
20 | pthread_exit( &ptHandle ); | ||
21 | |||
22 | return true; | ||
23 | } | ||
24 | |||
25 | void *Bu::Ito::threadRunner( void *pThread ) | ||
26 | { | ||
27 | return ((Ito *)pThread)->run(); | ||
28 | } | ||
29 | |||
30 | bool Bu::Ito::join() | ||
31 | { | ||
32 | pthread_join( ptHandle, NULL ); | ||
33 | return true; | ||
34 | } | ||
35 | |||
36 | void 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 | |||
6 | namespace 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 | */ | ||
13 | template <class T> | ||
14 | class ItoAtom | ||
15 | { | ||
16 | public: | ||
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 | |||
48 | private: | ||
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 | |||
5 | Bu::ItoCondition::ItoCondition() | ||
6 | { | ||
7 | pthread_cond_init( &cond, NULL ); | ||
8 | } | ||
9 | |||
10 | Bu::ItoCondition::~ItoCondition() | ||
11 | { | ||
12 | pthread_cond_destroy( &cond ); | ||
13 | } | ||
14 | |||
15 | int Bu::ItoCondition::wait() | ||
16 | { | ||
17 | return pthread_cond_wait( &cond, &mutex ); | ||
18 | } | ||
19 | |||
20 | int 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 | |||
33 | int Bu::ItoCondition::signal() | ||
34 | { | ||
35 | return pthread_cond_signal( &cond ); | ||
36 | } | ||
37 | |||
38 | int 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 | |||
8 | namespace 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 | |||
3 | Bu::ItoMutex::ItoMutex() | ||
4 | { | ||
5 | pthread_mutex_init( &mutex, NULL ); | ||
6 | } | ||
7 | |||
8 | Bu::ItoMutex::~ItoMutex() | ||
9 | { | ||
10 | pthread_mutex_destroy( &mutex ); | ||
11 | } | ||
12 | |||
13 | int Bu::ItoMutex::lock() | ||
14 | { | ||
15 | return pthread_mutex_lock( &mutex ); | ||
16 | } | ||
17 | |||
18 | int Bu::ItoMutex::unlock() | ||
19 | { | ||
20 | return pthread_mutex_unlock( &mutex ); | ||
21 | } | ||
22 | |||
23 | int 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 | |||
6 | namespace 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 | |||
9 | namespace 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 | ||
4 | LinkMessage::LinkMessage( int nNewMsg ) | 3 | Bu::LinkMessage::LinkMessage( int nNewMsg ) |
5 | { | 4 | { |
6 | nMsg = nNewMsg; | 5 | nMsg = nNewMsg; |
7 | } | 6 | } |
8 | 7 | ||
9 | LinkMessage::~LinkMessage() | 8 | Bu::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 | /** | 7 | namespace 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 | */ | ||
13 | class LinkMessage | ||
14 | { | 8 | { |
15 | public: | ||
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 | |||
3 | List::List( ) | ||
4 | { | ||
5 | } | ||
6 | |||
7 | List::~List( ) | ||
8 | { | ||
9 | } | ||
10 | 2 | ||
@@ -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 | 7 | namespace Bu |
6 | * does define all standard interface functions to access a list. | ||
7 | *@author Mike Buland | ||
8 | */ | ||
9 | class List | ||
10 | { | 8 | { |
11 | public: | 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 | |||
6 | Bu::Logger::Logger() | ||
7 | { | ||
8 | } | ||
9 | |||
10 | Bu::Logger::~Logger() | ||
11 | { | ||
12 | } | ||
13 | |||
14 | void 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 | |||
50 | void 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 | |||
110 | void Bu::Logger::setMask( int n ) | ||
111 | { | ||
112 | nLevelMask = n; | ||
113 | } | ||
114 | |||
115 | void 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 | |||
7 | namespace 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 | |||
3 | using namespace Bu; | ||
4 | |||
5 | Bu::MemBuf::MemBuf() : | ||
6 | nPos( 0 ) | ||
7 | { | ||
8 | } | ||
9 | |||
10 | Bu::MemBuf::MemBuf( const Bu::FString &str ) : | ||
11 | sBuf( str ), | ||
12 | nPos( 0 ) | ||
13 | { | ||
14 | } | ||
15 | |||
16 | Bu::MemBuf::~MemBuf() | ||
17 | { | ||
18 | } | ||
19 | |||
20 | void Bu::MemBuf::close() | ||
21 | { | ||
22 | } | ||
23 | |||
24 | size_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 | |||
35 | size_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 | |||
42 | long Bu::MemBuf::tell() | ||
43 | { | ||
44 | return nPos; | ||
45 | } | ||
46 | |||
47 | void 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 | |||
54 | void 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 | |||
61 | void 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 | |||
68 | bool Bu::MemBuf::isEOS() | ||
69 | { | ||
70 | return (nPos == sBuf.getSize()); | ||
71 | } | ||
72 | |||
73 | bool Bu::MemBuf::isOpen() | ||
74 | { | ||
75 | return true; | ||
76 | } | ||
77 | |||
78 | void Bu::MemBuf::flush() | ||
79 | { | ||
80 | } | ||
81 | |||
82 | bool Bu::MemBuf::canRead() | ||
83 | { | ||
84 | return !isEOS(); | ||
85 | } | ||
86 | |||
87 | bool Bu::MemBuf::canWrite() | ||
88 | { | ||
89 | return isEOS(); | ||
90 | } | ||
91 | |||
92 | bool Bu::MemBuf::isReadable() | ||
93 | { | ||
94 | return true; | ||
95 | } | ||
96 | |||
97 | bool Bu::MemBuf::isWritable() | ||
98 | { | ||
99 | return true; | ||
100 | } | ||
101 | |||
102 | bool Bu::MemBuf::isSeekable() | ||
103 | { | ||
104 | return true; | ||
105 | } | ||
106 | |||
107 | bool Bu::MemBuf::isBlocking() | ||
108 | { | ||
109 | return true; | ||
110 | } | ||
111 | |||
112 | void Bu::MemBuf::setBlocking( bool bBlocking ) | ||
113 | { | ||
114 | } | ||
115 | |||
116 | Bu::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 | |||
9 | namespace 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 | |||
3 | List::List( ) | ||
4 | { | ||
5 | } | ||
6 | |||
7 | List::~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 | */ | ||
9 | class List | ||
10 | { | ||
11 | public: | ||
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 | |||
3 | Protocol::Protocol() | ||
4 | { | ||
5 | pConnection = NULL; | ||
6 | } | ||
7 | |||
8 | Protocol::~Protocol() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | void Protocol::setConnection( Connection *pNewConnection ) | ||
13 | { | ||
14 | pConnection = pNewConnection; | ||
15 | } | ||
16 | |||
17 | Connection *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 | */ | ||
10 | class Protocol | ||
11 | { | ||
12 | public: | ||
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 | |||
58 | private: | ||
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 | |||
4 | int 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 | ||
25 | class Annoy2: public Annoy | ||
26 | { | ||
27 | public: | ||
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 | |||
41 | void beAnnoying( SPtr<Annoy> bob ) | 25 | void 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 | ||
47 | int main() | 31 | int 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 | ||
5 | XmlDocument::XmlDocument( XmlNode *pRoot ) | 5 | XmlDocument::XmlDocument( XmlNode *pRoot ) |
6 | { | 6 | { |
@@ -17,28 +17,23 @@ XmlDocument::~XmlDocument() | |||
17 | } | 17 | } |
18 | } | 18 | } |
19 | 19 | ||
20 | void XmlDocument::addNode( const char *sName, const char *sContent, bool bClose ) | 20 | void 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 | /* | |
38 | void XmlDocument::setName( const char *sName ) | 33 | void XmlDocument::setName( const char *sName ) |
39 | { | 34 | { |
40 | pCurrent->setName( sName ); | 35 | pCurrent->setName( sName ); |
41 | } | 36 | }*/ |
42 | 37 | ||
43 | bool XmlDocument::isCompleted() | 38 | bool 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 | ||
4 | XmlNode::XmlNode( const char *sName, XmlNode *pParent, const char *sContent ) : | 3 | XmlNode::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 | ||
24 | XmlNode::~XmlNode() | 9 | XmlNode::~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 | /* | |
51 | void XmlNode::setName( const char *sName ) | 13 | void 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 | ||
125 | XmlNode *XmlNode::addChild( const char *sName, const char *sContent ) | 87 | XmlNode *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 | ||
130 | XmlNode *XmlNode::addChild( XmlNode *pNode ) | 92 | XmlNode *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 | ||
145 | void XmlNode::addProperty( const char *sName, const char *sValue ) | 107 | void 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 | ||
155 | int XmlNode::getNumProperties() | 112 | int XmlNode::getNumProperties() |
156 | { | 113 | { |
157 | return lPropNames.getSize(); | 114 | return hProperties.size(); |
158 | } | 115 | } |
159 | 116 | /* | |
160 | const char *XmlNode::getPropertyName( int nIndex ) | 117 | const 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 | */ | |
176 | const char *XmlNode::getProperty( const char *sName ) | 133 | Bu::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 | /* | |
184 | void XmlNode::deleteProperty( int nIndex ) | 138 | void 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 | ||
195 | bool XmlNode::hasChildren() | 149 | bool XmlNode::hasChildren() |
196 | { | 150 | { |
197 | return lChildren.getSize()>0; | 151 | return hChildren.getSize()>0; |
198 | } | 152 | }*/ |
199 | 153 | ||
200 | int XmlNode::getNumChildren() | 154 | int XmlNode::getNumChildren() |
201 | { | 155 | { |
202 | return lChildren.getSize(); | 156 | return lChildren.getSize(); |
203 | } | 157 | } |
204 | 158 | /* | |
205 | XmlNode *XmlNode::getChild( int nIndex ) | 159 | XmlNode *XmlNode::getChild( int nIndex ) |
206 | { | 160 | { |
207 | return (XmlNode *)lChildren[nIndex]; | 161 | return (XmlNode *)lChildren[nIndex]; |
208 | } | 162 | } |
209 | 163 | */ | |
210 | XmlNode *XmlNode::getChild( const char *sName, int nSkip ) | 164 | XmlNode *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 | ||
215 | const char *XmlNode::getName() | 173 | Bu::FString XmlNode::getName() |
216 | { | 174 | { |
217 | return sName.c_str(); | 175 | return sName; |
218 | } | 176 | } |
219 | 177 | /* | |
220 | void XmlNode::deleteNode( int nIndex, const char *sReplacementText ) | 178 | void 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 ) | |||
442 | void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ) | 400 | void 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 | ||
222 | private: | 189 | private: |
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 | ||
6 | XmlReader::XmlReader( bool bStrip ) : | 5 | XmlReader::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 | ||
12 | XmlReader::~XmlReader() | 12 | XmlReader::~XmlReader() |
13 | { | 13 | { |
14 | void *i = htEntity.getFirstItemPos(); | 14 | } |
15 | while( (i = htEntity.getNextItemPos( i ) ) ) | 15 | |
16 | char 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 | ||
22 | void XmlReader::addEntity( const char *name, const char *value ) | 30 | void 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 ); | 44 | void 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 | ||
287 | bool XmlReader::name() | 302 | bool 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 | ||
328 | StaticString *XmlReader::getEscape() | 343 | Bu::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 | ||
375 | bool XmlReader::param() | 386 | bool 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 | ||
472 | bool XmlReader::content() | 477 | bool 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 | ||
5 | XmlWriter::XmlWriter( const char *sIndent, XmlNode *pRoot ) : | 5 | XmlWriter::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 | ||
18 | XmlWriter::~XmlWriter() | 11 | XmlWriter::~XmlWriter() |
@@ -24,7 +17,7 @@ void XmlWriter::write() | |||
24 | write( getRoot(), sIndent.c_str() ); | 17 | write( getRoot(), sIndent.c_str() ); |
25 | } | 18 | } |
26 | 19 | ||
27 | void XmlWriter::write( XmlNode *pRoot, const char *sIndent ) | 20 | void 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 | ||
42 | void XmlWriter::writeIndent( int nIndent, const char *sIndent ) | 35 | void 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 | ||
51 | std::string XmlWriter::escape( std::string sIn ) | 44 | Bu::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 | ||
79 | void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ) | 73 | void 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 | ||
91 | void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) | 85 | void 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 | ||
51 | private: | 51 | private: |
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 | ||
8 | ParamProc::ParamPtr::ParamPtr() | 8 | Bu::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 ); | |||
25 | ptrtype( long double, float96 ); | 25 | ptrtype( long double, float96 ); |
26 | ptrtype( bool, bln ); | 26 | ptrtype( bool, bln ); |
27 | 27 | ||
28 | ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) | 28 | Bu::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 | ||
36 | bool ParamProc::ParamPtr::isSet() | 36 | bool Bu::ParamProc::ParamPtr::isSet() |
37 | { | 37 | { |
38 | return type != vtunset; | 38 | return type != vtunset; |
39 | } | 39 | } |
40 | 40 | ||
41 | ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( const char *str ) | 41 | Bu::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 | ||
110 | ParamProc::ParamProc() | 110 | Bu::ParamProc::ParamProc() |
111 | { | 111 | { |
112 | } | 112 | } |
113 | 113 | ||
114 | ParamProc::~ParamProc() | 114 | Bu::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 | /* |
130 | void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) | 130 | void 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 | ||
137 | void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, | 137 | void 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 | ||
164 | void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, | 164 | void 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 | ||
171 | void ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, | 171 | void 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 | ||
178 | void ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, | 178 | void 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 | ||
185 | void ParamProc::addParam( const char *lpWord, Proc proc, | 185 | void 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 | ||
192 | void ParamProc::addParam( const char *lpWord, ParamPtr val, | 192 | void 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 | ||
199 | void ParamProc::addParam( char cChar, Proc proc, ParamPtr val, | 199 | void 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 | ||
206 | void ParamProc::addParam( char cChar, Proc proc, | 206 | void 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 | ||
213 | void ParamProc::addParam( char cChar, ParamPtr val, | 213 | void 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 | ||
220 | void ParamProc::process( int argc, char *argv[] ) | 220 | void 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 | ||
387 | ParamProc::ArgSpec *ParamProc::checkWord( const char *arg ) | 387 | Bu::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 | ||
412 | ParamProc::ArgSpec *ParamProc::checkLetr( const char arg ) | 412 | Bu::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 | ||
430 | int ParamProc::cmdParam( int argc, char *argv[] ) | 430 | int 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 | ||
436 | int ParamProc::unknownParam( int argc, char *argv[] ) | 436 | int 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 | ||
442 | int ParamProc::help( int argc, char *argv[] ) | 442 | int 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 | ||
507 | void ParamProc::addHelpBanner( const char *sHelpBanner ) | 507 | void 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 | ||
9 | class ParamProc | 9 | namespace Bu |
10 | { | 10 | { |
11 | public: | 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 | ||
86 | public: | 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 | ||
132 | private: | 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 | ||
136 | public: | 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 | ||
141 | private: | 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 | ||
12 | typedef struct PluginInfo | 11 | namespace 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 * ); | |
22 | typedef 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 ) \ |
30 | extern "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 ) \ |
45 | extern "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 ) \ |
61 | extern "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 | |||
76 | template<class T> | ||
77 | class Plugger | ||
78 | { | ||
79 | public: | ||
80 | |||
81 | public: | ||
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 | ||
192 | private: | 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 | ||
4 | ProgramChain::ProgramChain() : | 5 | using namespace Bu; |
5 | xLog( MultiLog::getInstance() ) | 6 | |
7 | Bu::ProgramChain::ProgramChain() | ||
6 | { | 8 | { |
7 | xLog.LineLog( MultiLog::LStatus, "Program Chain Initialized." ); | ||
8 | } | 9 | } |
9 | 10 | ||
10 | ProgramChain::~ProgramChain() | 11 | Bu::ProgramChain::~ProgramChain() |
11 | { | 12 | { |
12 | } | 13 | } |
13 | 14 | ||
14 | bool ProgramChain::addLink( ProgramLink *pLink ) | 15 | bool 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 | ||
29 | ProgramLink *ProgramChain::getLink( const char *lpName ) | 30 | ProgramLink *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 | ||
36 | ProgramLink *ProgramChain::getBaseLink() | 37 | ProgramLink *Bu::ProgramChain::getBaseLink() |
37 | { | 38 | { |
38 | return NULL; | 39 | return NULL; |
39 | } | 40 | } |
40 | 41 | ||
41 | bool ProgramChain::execChainOnce() | 42 | bool 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 | ||
57 | bool ProgramChain::enterChainLoop() | 57 | bool 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 | ||
70 | void ProgramChain::emergencyShutdown() | 70 | void 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 | ||
81 | LinkMessage *ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ) | 81 | LinkMessage *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 | /** | 7 | namespace 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 | */ | ||
13 | class ProgramChain | ||
14 | { | 8 | { |
15 | public: | 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 | ||
86 | private: | ||
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 | ||
4 | ProgramLink::ProgramLink() | 4 | using namespace Bu; |
5 | |||
6 | Bu::ProgramLink::ProgramLink() | ||
5 | { | 7 | { |
6 | } | 8 | } |
7 | 9 | ||
8 | ProgramLink::~ProgramLink() | 10 | Bu::ProgramLink::~ProgramLink() |
9 | { | 11 | { |
10 | } | 12 | } |
11 | 13 | ||
12 | LinkMessage *ProgramLink::sendIRM( LinkMessage *pMsgOut ) | 14 | LinkMessage *Bu::ProgramLink::sendIRM( LinkMessage *pMsgOut ) |
13 | { | 15 | { |
14 | return pChain->broadcastIRM( pMsgOut, this ); | 16 | return pChain->broadcastIRM( pMsgOut, this ); |
15 | } | 17 | } |
16 | 18 | ||
17 | void ProgramLink::setChain( ProgramChain *pNewChain ) | 19 | void 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 | ||
4 | class 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 | /** | 7 | namespace 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 | */ | ||
14 | class ProgramLink | ||
15 | { | 8 | { |
16 | friend class ProgramChain; | ||
17 | public: | ||
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 | ||
71 | private: | 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 | ||
93 | private: | 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 | ||
3 | Protocol::Protocol() | 3 | using namespace Bu; |
4 | { | ||
5 | pConnection = NULL; | ||
6 | } | ||
7 | 4 | ||
8 | Protocol::~Protocol() | 5 | Bu::Protocol::Protocol() |
9 | { | 6 | { |
10 | } | 7 | } |
11 | 8 | ||
12 | void Protocol::setConnection( Connection *pNewConnection ) | 9 | Bu::Protocol::~Protocol() |
13 | { | 10 | { |
14 | pConnection = pNewConnection; | ||
15 | } | 11 | } |
16 | 12 | ||
17 | Connection *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 | 6 | namespace Bu |
7 | * to connections of different types with different protocols. | ||
8 | *@author Mike Buland | ||
9 | */ | ||
10 | class Protocol | ||
11 | { | 7 | { |
12 | public: | 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 | ||
58 | private: | 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 | |||
7 | namespace 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 | |||
3 | Serializable::Serializable() | ||
4 | { | ||
5 | } | ||
6 | Serializable::~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 | */ | ||
11 | class Serializable | ||
12 | { | ||
13 | public: | ||
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 | |||
5 | Serializer::Serializer(bool bLoading): | ||
6 | bLoading(bLoading) | ||
7 | { | ||
8 | } | ||
9 | Serializer::~Serializer() | ||
10 | { | ||
11 | } | ||
12 | |||
13 | bool Serializer::isLoading() | ||
14 | { | ||
15 | return bLoading; | ||
16 | } | ||
17 | Serializer &Serializer::operator<<(bool p) | ||
18 | { | ||
19 | write( &p, sizeof(p) ); | ||
20 | return *this; | ||
21 | } | ||
22 | Serializer &Serializer::operator<<(int8_t p) | ||
23 | { | ||
24 | write( &p, sizeof(p) ); | ||
25 | return *this; | ||
26 | } | ||
27 | Serializer &Serializer::operator<<(int16_t p) | ||
28 | { | ||
29 | write( &p, sizeof(p) ); | ||
30 | return *this; | ||
31 | } | ||
32 | Serializer &Serializer::operator<<(int32_t p) | ||
33 | { | ||
34 | write( &p, sizeof(p) ); | ||
35 | return *this; | ||
36 | } | ||
37 | Serializer &Serializer::operator<<(int64_t p) | ||
38 | { | ||
39 | write( &p, sizeof(p) ); | ||
40 | return *this; | ||
41 | } | ||
42 | Serializer &Serializer::operator<<(uint8_t p) | ||
43 | { | ||
44 | write( &p, sizeof(p) ); | ||
45 | return *this; | ||
46 | } | ||
47 | Serializer &Serializer::operator<<(uint16_t p) | ||
48 | { | ||
49 | write( &p, sizeof(p) ); | ||
50 | return *this; | ||
51 | } | ||
52 | Serializer &Serializer::operator<<(uint32_t p) | ||
53 | { | ||
54 | write( &p, sizeof(p) ); | ||
55 | return *this; | ||
56 | } | ||
57 | Serializer &Serializer::operator<<(uint64_t p) | ||
58 | { | ||
59 | write( &p, sizeof(p) ); | ||
60 | return *this; | ||
61 | } | ||
62 | Serializer &Serializer::operator<<(long p) | ||
63 | { | ||
64 | write( &p, sizeof(p) ); | ||
65 | return *this; | ||
66 | } | ||
67 | Serializer &Serializer::operator<<(float p) | ||
68 | { | ||
69 | write( &p, sizeof(p) ); | ||
70 | return *this; | ||
71 | } | ||
72 | Serializer &Serializer::operator<<(double p) | ||
73 | { | ||
74 | write( &p, sizeof(p) ); | ||
75 | return *this; | ||
76 | } | ||
77 | Serializer &Serializer::operator<<(long double p) | ||
78 | { | ||
79 | write( &p, sizeof(p) ); | ||
80 | return *this; | ||
81 | } | ||
82 | |||
83 | Serializer &Serializer::operator>>(bool &p) | ||
84 | { | ||
85 | read( &p, sizeof(p) ); | ||
86 | return *this; | ||
87 | } | ||
88 | Serializer &Serializer::operator>>(int8_t &p) | ||
89 | { | ||
90 | read( &p, sizeof(p) ); | ||
91 | return *this; | ||
92 | } | ||
93 | Serializer &Serializer::operator>>(int16_t &p) | ||
94 | { | ||
95 | read( &p, sizeof(p) ); | ||
96 | return *this; | ||
97 | } | ||
98 | Serializer &Serializer::operator>>(int32_t &p) | ||
99 | { | ||
100 | read( &p, sizeof(p) ); | ||
101 | return *this; | ||
102 | } | ||
103 | Serializer &Serializer::operator>>(int64_t &p) | ||
104 | { | ||
105 | read( &p, sizeof(p) ); | ||
106 | return *this; | ||
107 | } | ||
108 | Serializer &Serializer::operator>>(uint8_t &p) | ||
109 | { | ||
110 | read( &p, sizeof(p) ); | ||
111 | return *this; | ||
112 | } | ||
113 | Serializer &Serializer::operator>>(uint16_t &p) | ||
114 | { | ||
115 | read( &p, sizeof(p) ); | ||
116 | return *this; | ||
117 | } | ||
118 | Serializer &Serializer::operator>>(uint32_t &p) | ||
119 | { | ||
120 | read( &p, sizeof(p) ); | ||
121 | return *this; | ||
122 | } | ||
123 | Serializer &Serializer::operator>>(uint64_t &p) | ||
124 | { | ||
125 | read( &p, sizeof(p) ); | ||
126 | return *this; | ||
127 | } | ||
128 | Serializer &Serializer::operator>>(long &p) | ||
129 | { | ||
130 | read( &p, sizeof(p) ); | ||
131 | return *this; | ||
132 | } | ||
133 | Serializer &Serializer::operator>>(float &p) | ||
134 | { | ||
135 | read( &p, sizeof(p) ); | ||
136 | return *this; | ||
137 | } | ||
138 | Serializer &Serializer::operator>>(double &p) | ||
139 | { | ||
140 | read( &p, sizeof(p) ); | ||
141 | return *this; | ||
142 | } | ||
143 | Serializer &Serializer::operator>>(long double &p) | ||
144 | { | ||
145 | read( &p, sizeof(p) ); | ||
146 | return *this; | ||
147 | } | ||
148 | |||
149 | Serializer &Serializer::operator&&(bool &p) | ||
150 | { | ||
151 | if (bLoading) | ||
152 | { | ||
153 | return *this >> p; | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | return *this << p; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | Serializer &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 | |||
173 | Serializer &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 | |||
185 | Serializer &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 | |||
197 | Serializer &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 | |||
209 | Serializer &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 | |||
221 | Serializer &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 | |||
233 | Serializer &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 | |||
245 | Serializer &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 | |||
257 | Serializer &Serializer::operator&&(float &p) | ||
258 | { | ||
259 | if (bLoading) | ||
260 | { | ||
261 | return *this >> p; | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | return *this << p; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | Serializer &Serializer::operator&&(double &p) | ||
270 | { | ||
271 | if (bLoading) | ||
272 | { | ||
273 | return *this >> p; | ||
274 | } | ||
275 | else | ||
276 | { | ||
277 | return *this << p; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | Serializer &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 | |||
294 | Serializer &operator<<(Serializer &s, Serializable &p) | ||
295 | { | ||
296 | p.serialize( s ); | ||
297 | return s; | ||
298 | } | ||
299 | |||
300 | Serializer &operator>>(Serializer &s, Serializable &p) | ||
301 | { | ||
302 | p.serialize( s ); | ||
303 | return s; | ||
304 | } | ||
305 | |||
306 | Serializer &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 | |||
318 | Serializer &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 | |||
326 | Serializer &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 | |||
9 | class Serializer | ||
10 | { | ||
11 | private: | ||
12 | bool bLoading; | ||
13 | public: | ||
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 | |||
73 | Serializer &operator<<(Serializer &, class Serializable &); | ||
74 | Serializer &operator>>(Serializer &, class Serializable &); | ||
75 | Serializer &operator&&(Serializer &s, class Serializable &p); | ||
76 | |||
77 | Serializer &operator<<(Serializer &, std::string &); | ||
78 | Serializer &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 | |||
7 | Bu::Server::Server() : | ||
8 | nTimeoutSec( 0 ), | ||
9 | nTimeoutUSec( 0 ) | ||
10 | { | ||
11 | FD_ZERO( &fdActive ); | ||
12 | } | ||
13 | |||
14 | Bu::Server::~Server() | ||
15 | { | ||
16 | } | ||
17 | |||
18 | void 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 | |||
26 | void 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 | |||
34 | void Bu::Server::setTimeout( int nTimeoutSec, int nTimeoutUSec ) | ||
35 | { | ||
36 | this->nTimeoutSec = nTimeoutSec; | ||
37 | this->nTimeoutUSec = nTimeoutUSec; | ||
38 | } | ||
39 | |||
40 | void 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 | |||
85 | void 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 | |||
9 | namespace 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 | |||
17 | Bu::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 | |||
34 | Bu::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 | |||
49 | Bu::ServerSocket::~ServerSocket() | ||
50 | { | ||
51 | } | ||
52 | |||
53 | void 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 | |||
88 | int Bu::ServerSocket::getSocket() | ||
89 | { | ||
90 | return nServer; | ||
91 | } | ||
92 | |||
93 | int 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 | |||
154 | int 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 | |||
7 | namespace 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 | |||
4 | SFile::SFile( const char *sName, const char *sFlags ) | ||
5 | { | ||
6 | fh = fopen( sName, sFlags ); | ||
7 | } | ||
8 | |||
9 | SFile::~SFile() | ||
10 | { | ||
11 | } | ||
12 | |||
13 | void SFile::close() | ||
14 | { | ||
15 | if( fh ) | ||
16 | { | ||
17 | fclose( fh ); | ||
18 | fh = NULL; | ||
19 | } | ||
20 | } | ||
21 | |||
22 | size_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 | |||
30 | size_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 | |||
38 | long SFile::tell() | ||
39 | { | ||
40 | if( !fh ) | ||
41 | throw FileException("File not open."); | ||
42 | |||
43 | return ftell( fh ); | ||
44 | } | ||
45 | |||
46 | void SFile::seek( long offset ) | ||
47 | { | ||
48 | if( !fh ) | ||
49 | throw FileException("File not open."); | ||
50 | |||
51 | fseek( fh, offset, SEEK_CUR ); | ||
52 | } | ||
53 | |||
54 | void SFile::setPos( long pos ) | ||
55 | { | ||
56 | if( !fh ) | ||
57 | throw FileException("File not open."); | ||
58 | |||
59 | fseek( fh, pos, SEEK_SET ); | ||
60 | } | ||
61 | |||
62 | void SFile::setPosEnd( long pos ) | ||
63 | { | ||
64 | if( !fh ) | ||
65 | throw FileException("File not open."); | ||
66 | |||
67 | fseek( fh, pos, SEEK_END ); | ||
68 | } | ||
69 | |||
70 | bool 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 | |||
8 | class SFile : public Stream | ||
9 | { | ||
10 | public: | ||
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 | |||
24 | private: | ||
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 | /** | 6 | namespace 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 | */ | ||
29 | template <class T> | ||
30 | class Singleton | ||
31 | { | 7 | { |
32 | protected: | ||
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 | ||
40 | private: | 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 | ||
46 | public: | 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 | |||
19 | Bu::Socket::Socket( int nSocket ) : | ||
20 | nSocket( nSocket ), | ||
21 | bActive( true ) | ||
22 | { | ||
23 | } | ||
24 | |||
25 | Bu::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 | |||
100 | Bu::Socket::~Socket() | ||
101 | { | ||
102 | } | ||
103 | |||
104 | void Bu::Socket::close() | ||
105 | { | ||
106 | if( bActive ) | ||
107 | { | ||
108 | fsync( nSocket ); | ||
109 | ::close( nSocket ); | ||
110 | } | ||
111 | bActive = false; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | void 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 | |||
167 | size_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 | |||
181 | size_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 | |||
191 | long Bu::Socket::tell() | ||
192 | { | ||
193 | throw UnsupportedException(); | ||
194 | } | ||
195 | |||
196 | void Bu::Socket::seek( long offset ) | ||
197 | { | ||
198 | throw UnsupportedException(); | ||
199 | } | ||
200 | |||
201 | void Bu::Socket::setPos( long pos ) | ||
202 | { | ||
203 | throw UnsupportedException(); | ||
204 | } | ||
205 | |||
206 | void Bu::Socket::setPosEnd( long pos ) | ||
207 | { | ||
208 | throw UnsupportedException(); | ||
209 | } | ||
210 | |||
211 | bool Bu::Socket::isEOS() | ||
212 | { | ||
213 | return !bActive; | ||
214 | } | ||
215 | |||
216 | bool 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 | |||
233 | bool 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 | |||
250 | bool Bu::Socket::isReadable() | ||
251 | { | ||
252 | return true; | ||
253 | } | ||
254 | |||
255 | bool Bu::Socket::isWritable() | ||
256 | { | ||
257 | return true; | ||
258 | } | ||
259 | |||
260 | bool Bu::Socket::isSeekable() | ||
261 | { | ||
262 | return false; | ||
263 | } | ||
264 | |||
265 | bool Bu::Socket::isBlocking() | ||
266 | { | ||
267 | return false; | ||
268 | } | ||
269 | |||
270 | void Bu::Socket::setBlocking( bool bBlocking ) | ||
271 | { | ||
272 | } | ||
273 | |||
274 | void Bu::Socket::flush() | ||
275 | { | ||
276 | } | ||
277 | |||
278 | bool Bu::Socket::isOpen() | ||
279 | { | ||
280 | return bActive; | ||
281 | } | ||
282 | |||
283 | Bu::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 | |||
9 | namespace 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" | ||
@@ -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 | ||
7 | template<typename T> class SPtr; | 7 | namespace Bu |
8 | template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src ); | ||
9 | |||
10 | template<typename T> | ||
11 | class 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 ); |
15 | public: | 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 | ||
113 | private: | 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 | ||
134 | template< 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 | ||
3 | Stream::Stream() | 3 | Bu::Stream::Stream() |
4 | { | 4 | { |
5 | } | 5 | } |
6 | 6 | ||
7 | Stream::~Stream() | 7 | Bu::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 | ||
7 | class Stream | 7 | namespace Bu |
8 | { | 8 | { |
9 | public: | 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 | ||
23 | private: | 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 | |||
3 | Bu::TafNode::TafNode( NodeType eType ) : | ||
4 | eType( eType ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | Bu::TafNode::~TafNode() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | const Bu::TafNode::NodeType Bu::TafNode::getType() const | ||
13 | { | ||
14 | return eType; | ||
15 | } | ||
16 | |||
17 | /* | ||
18 | const Bu::TafNode::PropList &Bu::TafNode::getProperties( const Bu::FString &sName ) const | ||
19 | { | ||
20 | return hProp.get( sName ); | ||
21 | } | ||
22 | |||
23 | const Bu::TafNode::NodeList &Bu::TafNode::getChildren( const Bu::FString &sName ) const | ||
24 | { | ||
25 | return hChildren.get( sName ); | ||
26 | } | ||
27 | |||
28 | const Bu::FString &Bu::TafNode::getProperty( const Bu::FString &sName ) const | ||
29 | { | ||
30 | return getProperties( sName ).first(); | ||
31 | } | ||
32 | |||
33 | const Bu::TafNode *Bu::TafNode::getChild( const Bu::FString &sName ) const | ||
34 | { | ||
35 | return getChildren( sName ).first(); | ||
36 | } | ||
37 | */ | ||
38 | |||
39 | Bu::TafGroup::TafGroup( const Bu::FString &sName ) : | ||
40 | TafNode( typeGroup ), | ||
41 | sName( sName ) | ||
42 | { | ||
43 | } | ||
44 | |||
45 | Bu::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 | |||
54 | const Bu::FString &Bu::TafGroup::getName() const | ||
55 | { | ||
56 | return sName; | ||
57 | } | ||
58 | |||
59 | Bu::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 | |||
79 | Bu::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 | |||
89 | Bu::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 | |||
99 | Bu::TafComment *Bu::TafGroup::addChild( TafComment *pNode ) | ||
100 | { | ||
101 | lChildren.append( pNode ); | ||
102 | return pNode; | ||
103 | } | ||
104 | |||
105 | const Bu::TafGroup::GroupList &Bu::TafGroup::getChildren( const Bu::FString &sName ) const | ||
106 | { | ||
107 | return hChildren.get( sName ); | ||
108 | } | ||
109 | |||
110 | const Bu::TafGroup::NodeList &Bu::TafGroup::getChildren() const | ||
111 | { | ||
112 | return lChildren; | ||
113 | } | ||
114 | |||
115 | const Bu::TafGroup *Bu::TafGroup::getChild( const Bu::FString &sName ) const | ||
116 | { | ||
117 | return hChildren.get( sName ).first(); | ||
118 | } | ||
119 | |||
120 | const Bu::TafGroup::PropList &Bu::TafGroup::getProperties( const Bu::FString &sName ) const | ||
121 | { | ||
122 | return hProp.get( sName ); | ||
123 | } | ||
124 | |||
125 | const Bu::FString &Bu::TafGroup::getProperty( const Bu::FString &sName ) const | ||
126 | { | ||
127 | return hProp.get( sName ).first(); | ||
128 | } | ||
129 | |||
130 | Bu::TafProperty::TafProperty( const Bu::FString &sName, const Bu::FString &sValue ) : | ||
131 | TafNode( typeProperty ), | ||
132 | sName( sName ), | ||
133 | sValue( sValue ) | ||
134 | { | ||
135 | } | ||
136 | |||
137 | Bu::TafProperty::~TafProperty() | ||
138 | { | ||
139 | } | ||
140 | |||
141 | const Bu::FString &Bu::TafProperty::getName() const | ||
142 | { | ||
143 | return sName; | ||
144 | } | ||
145 | |||
146 | const Bu::FString &Bu::TafProperty::getValue() const | ||
147 | { | ||
148 | return sValue; | ||
149 | } | ||
150 | |||
151 | Bu::TafComment::TafComment( const Bu::FString &sText ) : | ||
152 | TafNode( typeComment ), | ||
153 | sText( sText ) | ||
154 | { | ||
155 | } | ||
156 | |||
157 | Bu::TafComment::~TafComment() | ||
158 | { | ||
159 | } | ||
160 | |||
161 | const 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 | |||
9 | namespace 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 | |||
5 | using namespace Bu; | ||
6 | |||
7 | Bu::TafReader::TafReader( Bu::Stream &sIn ) : | ||
8 | c( 0 ), | ||
9 | sIn( sIn ) | ||
10 | { | ||
11 | next(); next(); | ||
12 | } | ||
13 | |||
14 | Bu::TafReader::~TafReader() | ||
15 | { | ||
16 | |||
17 | } | ||
18 | |||
19 | Bu::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 | |||
41 | void 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 | |||
57 | Bu::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 | |||
72 | Bu::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 | |||
87 | Bu::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 | |||
134 | void Bu::TafReader::ws() | ||
135 | { | ||
136 | for(;;) | ||
137 | { | ||
138 | if( !isws() ) | ||
139 | return; | ||
140 | |||
141 | next(); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | bool Bu::TafReader::isws() | ||
146 | { | ||
147 | return (c == ' ' || c == '\t' || c == '\n' || c == '\r'); | ||
148 | } | ||
149 | |||
150 | void 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 | |||
9 | namespace 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 | |||
3 | Bu::TafWriter::TafWriter( Bu::Stream &sOut ) : | ||
4 | sOut( sOut ) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | Bu::TafWriter::~TafWriter() | ||
9 | { | ||
10 | } | ||
11 | |||
12 | void 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 | |||
38 | void 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 | |||
49 | void 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 | |||
56 | void 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 | |||
9 | namespace 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 | |||
4 | using namespace Bu; | ||
5 | |||
6 | int 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 | |||
5 | typedef struct bob | ||
6 | { | ||
7 | int a, b; | ||
8 | } bob; | ||
9 | int 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 | |||
4 | int 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 | |||
4 | template <typename T> | ||
5 | class DataBase | ||
6 | { | ||
7 | public: | ||
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 | |||
48 | protected: | ||
49 | bool _bHas; | ||
50 | T _tVal; | ||
51 | }; | ||
52 | |||
53 | |||
54 | class Test | ||
55 | { | ||
56 | public: | ||
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 | |||
70 | private: | ||
71 | int _i; | ||
72 | }; | ||
73 | |||
74 | int 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 | |||
3 | void 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 | |||
13 | void 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 | |||
23 | int 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 | ||
4 | FString genThing() | 6 | #ifndef WIN32 |
7 | inline 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" | ||
16 | inline double getTime() | ||
17 | { | ||
18 | uint32_t t = (uint32_t) GetTickCount(); | ||
19 | return (double) t / 1000.0; | ||
20 | } | ||
21 | #endif | ||
22 | |||
23 | Bu::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 | ||
15 | void thing( FString str ) | 34 | void 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 | ||
39 | void copyfunc( std::string temp ) | ||
40 | { | ||
41 | temp += "Hi"; | ||
42 | } | ||
43 | |||
44 | void copyfunc( Bu::FString temp ) | ||
45 | { | ||
46 | temp += "Hi"; | ||
47 | } | ||
48 | |||
49 | void 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() ); |
21 | int main( int argc, char *argv ) | 111 | int 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 | ||
4 | int main() | 4 | typedef 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(); | 9 | int 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 | |||
5 | class Reader : public Bu::Ito | ||
6 | { | ||
7 | public: | ||
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 | |||
34 | private: | ||
35 | Bu::ItoQueue<std::string *> &q; | ||
36 | int id; | ||
37 | }; | ||
38 | |||
39 | class Writer : public Bu::Ito | ||
40 | { | ||
41 | public: | ||
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 | |||
61 | private: | ||
62 | Bu::ItoQueue<std::string *> &q; | ||
63 | const char *strbase; | ||
64 | int id; | ||
65 | }; | ||
66 | |||
67 | int 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 | |||
6 | class Reader : public Bu::Ito | ||
7 | { | ||
8 | public: | ||
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 | |||
35 | private: | ||
36 | Bu::ItoQueue<std::string *> &q; | ||
37 | int id; | ||
38 | }; | ||
39 | |||
40 | class Writer : public Bu::Ito | ||
41 | { | ||
42 | public: | ||
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 | |||
62 | private: | ||
63 | Bu::ItoQueue<std::string *> &q; | ||
64 | const char *strbase; | ||
65 | int id; | ||
66 | }; | ||
67 | |||
68 | int 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 | |||
4 | typedef struct Bob | ||
5 | { | ||
6 | int nID; | ||
7 | } Bob; | ||
8 | |||
9 | int 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 | |||
5 | class 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 | |||
19 | int 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 | |||
4 | int 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 | |||
5 | int 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 | |||
9 | class Unit : public Bu::UnitSuite | ||
10 | { | ||
11 | public: | ||
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 | |||
28 | int 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 | |||
9 | class Unit : public Bu::UnitSuite | ||
10 | { | ||
11 | public: | ||
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 | |||
107 | int 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 | |||
4 | class Unit : public Bu::UnitSuite | ||
5 | { | ||
6 | public: | ||
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 | |||
24 | int 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 | |||
7 | class Unit : public Bu::UnitSuite | ||
8 | { | ||
9 | private: | ||
10 | typedef Bu::Hash<Bu::FString, int> StrIntHash; | ||
11 | public: | ||
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 | |||
36 | int 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 | |||
4 | class Unit : public Bu::UnitSuite | ||
5 | { | ||
6 | public: | ||
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 | |||
37 | int 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 | |||
8 | class Unit : public Bu::UnitSuite | ||
9 | { | ||
10 | public: | ||
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 | |||
44 | int 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 | |||
3 | Bu::UnitSuite::UnitSuite() | ||
4 | { | ||
5 | } | ||
6 | |||
7 | Bu::UnitSuite::~UnitSuite() | ||
8 | { | ||
9 | } | ||
10 | |||
11 | int 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 | |||
48 | void 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 | |||
63 | void 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 | |||
8 | namespace 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 | |||
5 | class Guy : public Plugin | ||
6 | { | ||
7 | public: | ||
8 | Guy() | ||
9 | { | ||
10 | printf("I'm guy!\n"); | ||
11 | } | ||
12 | |||
13 | virtual ~Guy() | ||
14 | { | ||
15 | printf("Guy is dead...\n"); | ||
16 | } | ||
17 | |||
18 | private: | ||
19 | }; | ||
20 | |||
21 | PluginInterface( 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 | |||
3 | g++ -fPIC -shared -Wl,-soname,guy.so -o guy.so -I../src -I../src/test/plugin guy.cpp ../src/test/plugin/plugin.cpp | ||