summaryrefslogtreecommitdiff
path: root/src/stable
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2012-03-25 20:00:08 +0000
committerMike Buland <eichlan@xagasoft.com>2012-03-25 20:00:08 +0000
commit469bbcf0701e1eb8a6670c23145b0da87357e178 (patch)
treeb5b062a16e46a6c5d3410b4e574cd0cc09057211 /src/stable
parentee1b79396076edc4e30aefb285fada03bb45e80d (diff)
downloadlibbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.tar.gz
libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.tar.bz2
libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.tar.xz
libbu++-469bbcf0701e1eb8a6670c23145b0da87357e178.zip
Code is all reorganized. We're about ready to release. I should write up a
little explenation of the arrangement.
Diffstat (limited to 'src/stable')
-rw-r--r--src/stable/archival.cpp35
-rw-r--r--src/stable/archival.h52
-rw-r--r--src/stable/archive.cpp89
-rw-r--r--src/stable/archive.h138
-rw-r--r--src/stable/archivebase.cpp197
-rw-r--r--src/stable/archivebase.h75
-rw-r--r--src/stable/array.cpp10
-rw-r--r--src/stable/array.h703
-rw-r--r--src/stable/atom.cpp8
-rw-r--r--src/stable/atom.h147
-rw-r--r--src/stable/base64.cpp219
-rw-r--r--src/stable/base64.h59
-rw-r--r--src/stable/buffer.cpp168
-rw-r--r--src/stable/buffer.h58
-rw-r--r--src/stable/bzip2.cpp233
-rw-r--r--src/stable/bzip2.h49
-rw-r--r--src/stable/client.cpp320
-rw-r--r--src/stable/client.h133
-rw-r--r--src/stable/clientlink.cpp17
-rw-r--r--src/stable/clientlink.h25
-rw-r--r--src/stable/clientlinkfactory.cpp17
-rw-r--r--src/stable/clientlinkfactory.h26
-rw-r--r--src/stable/condition.cpp49
-rw-r--r--src/stable/condition.h90
-rw-r--r--src/stable/conduit.cpp233
-rw-r--r--src/stable/conduit.h64
-rw-r--r--src/stable/crypt.cpp47
-rw-r--r--src/stable/crypt.h19
-rw-r--r--src/stable/cryptohash.cpp38
-rw-r--r--src/stable/cryptohash.h33
-rw-r--r--src/stable/csvreader.cpp130
-rw-r--r--src/stable/csvreader.h45
-rw-r--r--src/stable/csvwriter.cpp81
-rw-r--r--src/stable/csvwriter.h45
-rw-r--r--src/stable/deflate.cpp253
-rw-r--r--src/stable/deflate.h66
-rw-r--r--src/stable/exceptionbase.cpp93
-rw-r--r--src/stable/exceptionbase.h190
-rw-r--r--src/stable/extratypes.h30
-rw-r--r--src/stable/file.cpp305
-rw-r--r--src/stable/file.h106
-rw-r--r--src/stable/filter.cpp113
-rw-r--r--src/stable/filter.h83
-rw-r--r--src/stable/fmt.h92
-rw-r--r--src/stable/formatter.cpp547
-rw-r--r--src/stable/formatter.h303
-rw-r--r--src/stable/formula.cpp14
-rw-r--r--src/stable/formula.h430
-rw-r--r--src/stable/hash.cpp69
-rw-r--r--src/stable/hash.h1306
-rw-r--r--src/stable/heap.cpp10
-rw-r--r--src/stable/heap.h612
-rw-r--r--src/stable/hex.cpp69
-rw-r--r--src/stable/hex.h57
-rw-r--r--src/stable/list.cpp9
-rw-r--r--src/stable/list.h1014
-rw-r--r--src/stable/logger.cpp209
-rw-r--r--src/stable/logger.h125
-rw-r--r--src/stable/lzma.cpp248
-rw-r--r--src/stable/lzma.h59
-rw-r--r--src/stable/md5.cpp246
-rw-r--r--src/stable/md5.h54
-rw-r--r--src/stable/membuf.cpp177
-rw-r--r--src/stable/membuf.h68
-rw-r--r--src/stable/minicron.cpp477
-rw-r--r--src/stable/minicron.h336
-rw-r--r--src/stable/multiserver.cpp55
-rw-r--r--src/stable/multiserver.h57
-rw-r--r--src/stable/mutex.cpp34
-rw-r--r--src/stable/mutex.h68
-rw-r--r--src/stable/mutexlocker.cpp24
-rw-r--r--src/stable/mutexlocker.h21
-rw-r--r--src/stable/nullstream.cpp127
-rw-r--r--src/stable/nullstream.h67
-rw-r--r--src/stable/optparser.cpp492
-rw-r--r--src/stable/optparser.h223
-rw-r--r--src/stable/pearsonhash.cpp66
-rw-r--r--src/stable/pearsonhash.h46
-rw-r--r--src/stable/plugger.cpp11
-rw-r--r--src/stable/plugger.h289
-rw-r--r--src/stable/process.cpp441
-rw-r--r--src/stable/process.h153
-rw-r--r--src/stable/protocol.cpp35
-rw-r--r--src/stable/protocol.h38
-rw-r--r--src/stable/protocolhttp.cpp353
-rw-r--r--src/stable/protocolhttp.h106
-rw-r--r--src/stable/protocoltelnet.cpp620
-rw-r--r--src/stable/protocoltelnet.h220
-rw-r--r--src/stable/queue.cpp8
-rw-r--r--src/stable/queue.h40
-rw-r--r--src/stable/queuebuf.cpp278
-rw-r--r--src/stable/queuebuf.h66
-rw-r--r--src/stable/ringbuffer.cpp9
-rw-r--r--src/stable/ringbuffer.h228
-rw-r--r--src/stable/server.cpp214
-rw-r--r--src/stable/server.h108
-rw-r--r--src/stable/sha1.cpp194
-rw-r--r--src/stable/sha1.h53
-rw-r--r--src/stable/sharedcore.cpp9
-rw-r--r--src/stable/sharedcore.h193
-rw-r--r--src/stable/signals.cpp10
-rw-r--r--src/stable/singleton.h68
-rw-r--r--src/stable/sio.cpp35
-rw-r--r--src/stable/sio.h26
-rw-r--r--src/stable/sptr.cpp8
-rw-r--r--src/stable/sptr.h229
-rw-r--r--src/stable/stack.cpp8
-rw-r--r--src/stable/stack.h85
-rw-r--r--src/stable/staticmembuf.cpp135
-rw-r--r--src/stable/staticmembuf.h65
-rw-r--r--src/stable/stdstream.cpp117
-rw-r--r--src/stable/stdstream.h50
-rw-r--r--src/stable/stream.cpp53
-rw-r--r--src/stable/stream.h205
-rw-r--r--src/stable/streamstack.cpp234
-rw-r--r--src/stable/streamstack.h144
-rw-r--r--src/stable/strfilter.h124
-rw-r--r--src/stable/string.cpp1470
-rw-r--r--src/stable/string.h1053
-rw-r--r--src/stable/substream.cpp109
-rw-r--r--src/stable/substream.h63
-rw-r--r--src/stable/synchroatom.h63
-rw-r--r--src/stable/synchrocounter.cpp8
-rw-r--r--src/stable/synchrocounter.h49
-rw-r--r--src/stable/synchroheap.cpp9
-rw-r--r--src/stable/synchroheap.h151
-rw-r--r--src/stable/synchroqueue.h240
-rw-r--r--src/stable/taf.h18
-rw-r--r--src/stable/tafcomment.cpp37
-rw-r--r--src/stable/tafcomment.h36
-rw-r--r--src/stable/tafgroup.cpp224
-rw-r--r--src/stable/tafgroup.h71
-rw-r--r--src/stable/tafnode.cpp25
-rw-r--r--src/stable/tafnode.h44
-rw-r--r--src/stable/tafproperty.cpp37
-rw-r--r--src/stable/tafproperty.h36
-rw-r--r--src/stable/tafreader.cpp252
-rw-r--r--src/stable/tafreader.h49
-rw-r--r--src/stable/tafwriter.cpp114
-rw-r--r--src/stable/tafwriter.h45
-rw-r--r--src/stable/tcpserversocket.cpp249
-rw-r--r--src/stable/tcpserversocket.h64
-rw-r--r--src/stable/tcpsocket.cpp478
-rw-r--r--src/stable/tcpsocket.h126
-rw-r--r--src/stable/thread.cpp55
-rw-r--r--src/stable/thread.h107
-rw-r--r--src/stable/trace.cpp67
-rw-r--r--src/stable/trace.h187
-rw-r--r--src/stable/unitsuite.cpp255
-rw-r--r--src/stable/unitsuite.h139
-rw-r--r--src/stable/util.cpp65
-rw-r--r--src/stable/util.h187
-rw-r--r--src/stable/variant.cpp99
-rw-r--r--src/stable/variant.h236
154 files changed, 24481 insertions, 0 deletions
diff --git a/src/stable/archival.cpp b/src/stable/archival.cpp
new file mode 100644
index 0000000..687e8a3
--- /dev/null
+++ b/src/stable/archival.cpp
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/archival.h"
9
10Bu::Archival::Archival()
11{
12}
13
14Bu::Archival::~Archival()
15{
16}
17
18Bu::ArchiveBase &Bu::operator<<(Bu::ArchiveBase &s, const Bu::Archival &p)
19{
20 const_cast<Bu::Archival &>(p).archive( s );
21 return s;
22}
23
24Bu::ArchiveBase &Bu::operator<<(Bu::ArchiveBase &s, Bu::Archival &p)
25{
26 p.archive( s );
27 return s;
28}
29
30Bu::ArchiveBase &Bu::operator>>(Bu::ArchiveBase &s, Bu::Archival &p)
31{
32 p.archive( s );
33 return s;
34}
35
diff --git a/src/stable/archival.h b/src/stable/archival.h
new file mode 100644
index 0000000..946167a
--- /dev/null
+++ b/src/stable/archival.h
@@ -0,0 +1,52 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_ARCHIVAL_H
9#define BU_ARCHIVAL_H
10
11#include "bu/archivebase.h"
12
13namespace Bu
14{
15 /**
16 * The base class for any class you want to archive. Simply include this as
17 * a base class, implement the purely virtual archive function and you've
18 * got an easily archiveable class.
19 *
20 * Archival: "of or pertaining to archives or valuable records; contained
21 * in or comprising such archives or records."
22 */
23 class Archival
24 {
25 public:
26 /**
27 * Does nothing, here for completeness.
28 */
29 Archival();
30
31 /**
32 * Here to ensure the deconstructor is virtual.
33 */
34 virtual ~Archival();
35
36 /**
37 * This is the main workhorse of the archive system, just override and
38 * you've got a archiveable class. A reference to the Archive
39 * used is passed in as your only parameter, query it to discover if
40 * you are loading or saving.
41 * @param ar A reference to the Archive object to use.
42 */
43 virtual void archive( class ArchiveBase &ar )=0;
44 };
45
46 ArchiveBase &operator<<(ArchiveBase &, const class Bu::Archival &);
47 ArchiveBase &operator<<(ArchiveBase &, class Bu::Archival &);
48 ArchiveBase &operator>>(ArchiveBase &, class Bu::Archival &);
49
50}
51
52#endif
diff --git a/src/stable/archive.cpp b/src/stable/archive.cpp
new file mode 100644
index 0000000..d300a87
--- /dev/null
+++ b/src/stable/archive.cpp
@@ -0,0 +1,89 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/archive.h"
9#include "bu/stream.h"
10#include "bu/archival.h"
11
12#include "bu/sio.h"
13
14Bu::Archive::Archive( Stream &rStream, bool bLoading ) :
15 bLoading( bLoading ),
16 rStream( rStream ),
17 nNextID( 1 )
18{
19}
20
21Bu::Archive::~Archive()
22{
23}
24
25void Bu::Archive::write( const void *pData, size_t nSize )
26{
27 if( nSize == 0 || pData == NULL )
28 return;
29
30 rStream.write( (const char *)pData, nSize );
31}
32
33void Bu::Archive::read( void *pData, size_t nSize )
34{
35 if( nSize == 0 || pData == NULL )
36 return;
37
38 if( rStream.read( (char *)pData, nSize ) < nSize )
39 throw Bu::ExceptionBase("Insufficient data to unarchive object.");
40}
41
42void Bu::Archive::close()
43{
44 rStream.close();
45}
46
47bool Bu::Archive::isLoading()
48{
49 return bLoading;
50}
51
52uint32_t Bu::Archive::getID( const void *ptr )
53{
54 if( hPtrID.has( (ptrdiff_t)ptr ) )
55 return hPtrID.get( (ptrdiff_t)ptr );
56 hPtrID.insert( (ptrdiff_t)ptr, nNextID );
57 return nNextID++;
58}
59
60void Bu::Archive::assocPtrID( void **ptr, uint32_t id )
61{
62 if( hPtrID.has( id ) )
63 {
64 *ptr = (void *)hPtrID.get( id );
65 return;
66 }
67
68 if( !hPtrDest.has( id ) )
69 hPtrDest.insert( id, List<void **>() );
70
71 hPtrDest[id].getValue().append( ptr );
72}
73
74void Bu::Archive::readID( const void *ptr, uint32_t id )
75{
76 hPtrID.insert( id, (ptrdiff_t)ptr );
77
78 if( hPtrDest.has( id ) )
79 {
80 Bu::List<void **> &l = hPtrDest.get( id );
81 for( Bu::List<void **>::iterator i = l.begin(); i != l.end(); i++ )
82 {
83 *(*i) = (void *)ptr;
84 }
85
86 hPtrDest.erase( id );
87 }
88}
89
diff --git a/src/stable/archive.h b/src/stable/archive.h
new file mode 100644
index 0000000..61474a4
--- /dev/null
+++ b/src/stable/archive.h
@@ -0,0 +1,138 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_ARCHIVE_H
9#define BU_ARCHIVE_H
10
11#include <stdint.h>
12#include "bu/archivebase.h"
13#include "bu/hash.h"
14#include "bu/util.h"
15#include "bu/variant.h"
16
17namespace Bu
18{
19 class Archival;
20 class Stream;
21
22 /**
23 * Provides a framework for serialization of objects and primitives. The
24 * archive will handle any basic primitive, a few special types, like char *
25 * strings, as well as STL classes and anything that inherits from the
26 * Archival class. Each Archive operates on a Stream, so you can send the
27 * data using an Archive almost anywhere.
28 *
29 * In order to use an Archive to store something to a file, try something
30 * like:
31 *@code
32 * File sOut("output", "wb"); // This is a stream subclass
33 * Archive ar( sOut, Archive::save );
34 * ar << myClass;
35 @endcode
36 * In this example myClass is any class that inherits from Archival. When
37 * the storage operator is called, the Archival::archive() function in the
38 * myClass object is called with a reference to the Archive. This can be
39 * handled in one of two ways:
40 *@code
41 * void MyClass::archive( Archive &ar )
42 * {
43 * ar && sName && nAge && sJob;
44 * }
45 @endcode
46 * Here we don't worry about weather we're loading or saving by using the
47 * smart && operator. This allows us to write very consistent, very simple
48 * archive functions that really do a lot of work. If we wanted to do
49 * something different in the case of loading or saving we would do:
50 *@code
51 * void MyClass::archive( Archive &ar )
52 * {
53 * if( ar.isLoading() )
54 * {
55 * ar >> sName >> nAge >> sJob;
56 * } else
57 * {
58 * ar << sName << nAge << sJob;
59 * }
60 * }
61 @endcode
62 * Archive currently does not provide facility to make fully portable
63 * archives. For example, it will not convert between endianness for you,
64 * nor will it take into account differences between primitive sizes on
65 * different platforms. This, at the moment, is up to the user to ensure.
66 * One way of dealing with the latter problem is to make sure and use
67 * explicit primitive types from the stdint.h header, i.e. int32_t.
68 */
69 class Archive : public ArchiveBase
70 {
71 private:
72 bool bLoading;
73 public:
74 bool isLoading();
75
76 enum
77 {
78 load = true,
79 save = false
80 };
81
82 Archive( Stream &rStream, bool bLoading );
83 virtual ~Archive();
84 virtual void close();
85
86 virtual void write( const void *pData, size_t iSize );
87 virtual void read( void *pData, size_t iSize );
88
89 /**
90 * For storage, get an ID for the pointer to the object you're going to
91 * write.
92 */
93 uint32_t getID( const void *ptr );
94
95 /**
96 * For loading. Assosiates an empty pointer with an id. When you wind
97 * up loading an id reference to a pointer for an object that may or
98 * may not have loaded yet, call this with the id, if it has been loaded
99 * already, you'll immediately get a pointer, if not, it will write one
100 * for you when the time comes.
101 */
102 void assocPtrID( void **ptr, uint32_t id );
103
104 /**
105 * For loading. Call this when you load an object that other things may
106 * have pointers to. It will assosiate every pointer that's been
107 * registered with assocPtrID to the pointer passed in, and id passed
108 * in. It will also set things up so future calls to assocPtrID will
109 * automatically succeed immediately.
110 */
111 void readID( const void *ptr, uint32_t id );
112
113 template<typename t>
114 void setProp( const Bu::String &sId, const t &val )
115 {
116 if( !hProps.has( sId ) )
117 {
118 hProps.insert( sId, Variant() );
119 }
120 hProps.get( sId ) = val;
121 }
122
123 template<typename t>
124 t getProp( const Bu::String &sId )
125 {
126 return hProps.get( sId );
127 }
128
129 private:
130 Stream &rStream;
131 uint32_t nNextID;
132 Hash<uint32_t,uint32_t> hPtrID;
133 Hash<uint32_t,List<void **> > hPtrDest;
134 Hash<Bu::String, Variant> hProps;
135 };
136}
137
138#endif
diff --git a/src/stable/archivebase.cpp b/src/stable/archivebase.cpp
new file mode 100644
index 0000000..d00b1a5
--- /dev/null
+++ b/src/stable/archivebase.cpp
@@ -0,0 +1,197 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/archivebase.h"
9
10Bu::ArchiveBase::ArchiveBase()
11{
12}
13
14Bu::ArchiveBase::~ArchiveBase()
15{
16}
17
18Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, bool p)
19{
20 ar.write( &p, sizeof(p) );
21 return ar;
22}
23
24Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, char p)
25{
26 ar.write( &p, sizeof(p) );
27 return ar;
28}
29
30Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, signed char p)
31{
32 ar.write( &p, sizeof(p) );
33 return ar;
34}
35
36Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, unsigned char p)
37{
38 ar.write( &p, sizeof(p) );
39 return ar;
40}
41
42Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, signed short p)
43{
44 ar.write( &p, sizeof(p) );
45 return ar;
46}
47
48Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, unsigned short p)
49{
50 ar.write( &p, sizeof(p) );
51 return ar;
52}
53
54Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, signed int p)
55{
56 ar.write( &p, sizeof(p) );
57 return ar;
58}
59
60Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, unsigned int p)
61{
62 ar.write( &p, sizeof(p) );
63 return ar;
64}
65
66Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, signed long p)
67{
68 ar.write( &p, sizeof(p) );
69 return ar;
70}
71
72Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, unsigned long p)
73{
74 ar.write( &p, sizeof(p) );
75 return ar;
76}
77
78Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, signed long long p)
79{
80 ar.write( &p, sizeof(p) );
81 return ar;
82}
83
84Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, unsigned long long p)
85{
86 ar.write( &p, sizeof(p) );
87 return ar;
88}
89
90Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, float p)
91{
92 ar.write( &p, sizeof(p) );
93 return ar;
94}
95
96Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, double p)
97{
98 ar.write( &p, sizeof(p) );
99 return ar;
100}
101
102Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, long double p)
103{
104 ar.write( &p, sizeof(p) );
105 return ar;
106}
107
108Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, bool &p)
109{
110 ar.read( &p, sizeof(p) );
111 return ar;
112}
113
114Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, char &p)
115{
116 ar.read( &p, sizeof(p) );
117 return ar;
118}
119
120Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, signed char &p)
121{
122 ar.read( &p, sizeof(p) );
123 return ar;
124}
125
126Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, unsigned char &p)
127{
128 ar.read( &p, sizeof(p) );
129 return ar;
130}
131
132Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, signed short &p)
133{
134 ar.read( &p, sizeof(p) );
135 return ar;
136}
137
138Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, unsigned short &p)
139{
140 ar.read( &p, sizeof(p) );
141 return ar;
142}
143
144Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, signed int &p)
145{
146 ar.read( &p, sizeof(p) );
147 return ar;
148}
149
150Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, unsigned int &p)
151{
152 ar.read( &p, sizeof(p) );
153 return ar;
154}
155
156Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, signed long &p)
157{
158 ar.read( &p, sizeof(p) );
159 return ar;
160}
161
162Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, unsigned long &p)
163{
164 ar.read( &p, sizeof(p) );
165 return ar;
166}
167
168Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, signed long long &p)
169{
170 ar.read( &p, sizeof(p) );
171 return ar;
172}
173
174Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, unsigned long long &p)
175{
176 ar.read( &p, sizeof(p) );
177 return ar;
178}
179
180Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, float &p)
181{
182 ar.read( &p, sizeof(p) );
183 return ar;
184}
185
186Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, double &p)
187{
188 ar.read( &p, sizeof(p) );
189 return ar;
190}
191
192Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, long double &p)
193{
194 ar.read( &p, sizeof(p) );
195 return ar;
196}
197
diff --git a/src/stable/archivebase.h b/src/stable/archivebase.h
new file mode 100644
index 0000000..4745d91
--- /dev/null
+++ b/src/stable/archivebase.h
@@ -0,0 +1,75 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_ARCHIVE_BASE_H
9#define BU_ARCHIVE_BASE_H
10
11#include <stdint.h>
12#include <unistd.h>
13
14namespace Bu
15{
16 class ArchiveBase
17 {
18 public:
19 ArchiveBase();
20 virtual ~ArchiveBase();
21
22 virtual void close()=0;
23 virtual void write( const void *pData, size_t iLength )=0;
24 virtual void read( void *pData, size_t iLength )=0;
25 virtual bool isLoading()=0;
26 };
27
28 template<typename T> ArchiveBase &operator&&( ArchiveBase &ar, T &dat )
29 {
30 if( ar.isLoading() )
31 {
32 return ar >> dat;
33 }
34 else
35 {
36 return ar << dat;
37 }
38 }
39
40 ArchiveBase &operator<<( ArchiveBase &ar, bool p );
41 ArchiveBase &operator<<( ArchiveBase &ar, char p );
42 ArchiveBase &operator<<( ArchiveBase &ar, signed char p );
43 ArchiveBase &operator<<( ArchiveBase &ar, unsigned char p );
44 ArchiveBase &operator<<( ArchiveBase &ar, signed short p );
45 ArchiveBase &operator<<( ArchiveBase &ar, unsigned short p );
46 ArchiveBase &operator<<( ArchiveBase &ar, signed int p );
47 ArchiveBase &operator<<( ArchiveBase &ar, unsigned int p );
48 ArchiveBase &operator<<( ArchiveBase &ar, signed long p );
49 ArchiveBase &operator<<( ArchiveBase &ar, unsigned long p );
50 ArchiveBase &operator<<( ArchiveBase &ar, signed long long p );
51 ArchiveBase &operator<<( ArchiveBase &ar, unsigned long long p );
52 ArchiveBase &operator<<( ArchiveBase &ar, float p );
53 ArchiveBase &operator<<( ArchiveBase &ar, double p );
54 ArchiveBase &operator<<( ArchiveBase &ar, long double p );
55
56 ArchiveBase &operator>>( ArchiveBase &ar, bool &p );
57 ArchiveBase &operator>>( ArchiveBase &ar, char &p );
58 ArchiveBase &operator>>( ArchiveBase &ar, signed char &p );
59 ArchiveBase &operator>>( ArchiveBase &ar, unsigned char &p );
60 ArchiveBase &operator>>( ArchiveBase &ar, signed short &p );
61 ArchiveBase &operator>>( ArchiveBase &ar, unsigned short &p );
62 ArchiveBase &operator>>( ArchiveBase &ar, signed int &p );
63 ArchiveBase &operator>>( ArchiveBase &ar, unsigned int &p );
64 ArchiveBase &operator>>( ArchiveBase &ar, signed long &p );
65 ArchiveBase &operator>>( ArchiveBase &ar, unsigned long &p );
66 ArchiveBase &operator>>( ArchiveBase &ar, signed long long &p );
67 ArchiveBase &operator>>( ArchiveBase &ar, unsigned long long &p );
68 ArchiveBase &operator>>( ArchiveBase &ar, float &p );
69 ArchiveBase &operator>>( ArchiveBase &ar, double &p );
70 ArchiveBase &operator>>( ArchiveBase &ar, long double &p );
71
72
73};
74
75#endif
diff --git a/src/stable/array.cpp b/src/stable/array.cpp
new file mode 100644
index 0000000..b776fed
--- /dev/null
+++ b/src/stable/array.cpp
@@ -0,0 +1,10 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/array.h"
9
10namespace Bu { subExceptionDef( ArrayException ) }
diff --git a/src/stable/array.h b/src/stable/array.h
new file mode 100644
index 0000000..fcd800e
--- /dev/null
+++ b/src/stable/array.h
@@ -0,0 +1,703 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_ARRAY_H
9#define BU_ARRAY_H
10
11#include <memory>
12#include "bu/exceptionbase.h"
13#include "bu/archivebase.h"
14#include "bu/sharedcore.h"
15
16namespace Bu
17{
18 subExceptionDecl( ArrayException )
19
20 template<typename value, int inc, typename valuealloc>
21 class Array;
22
23 /** @cond DEVEL */
24 template<typename value, int inc, typename valuealloc>
25 class ArrayCore
26 {
27 friend class Array<value, inc, valuealloc>;
28 friend class SharedCore<
29 Array<value, inc, valuealloc>,
30 ArrayCore<value, inc, valuealloc>
31 >;
32 private:
33 ArrayCore() :
34 pData( NULL ),
35 iSize( 0 ),
36 iCapacity( 0 )
37 { }
38
39 void setCapacity( int iNewLen )
40 {
41 //clear();
42 //iCapacity = iCapacity;
43 //pData = va.allocate( iCapacity );
44 if( iNewLen <= iCapacity ) return;
45 value *pNewData = va.allocate( iNewLen );
46 if( pData )
47 {
48 for( int j = 0; j < iSize; j++ )
49 {
50 va.construct( &pNewData[j], pData[j] );
51 va.destroy( &pData[j] );
52 }
53 va.deallocate( pData, iCapacity );
54 }
55 pData = pNewData;
56 iCapacity = iNewLen;
57 }
58
59 virtual ~ArrayCore()
60 {
61 clear();
62 }
63
64 void clear()
65 {
66 if( pData )
67 {
68 for( int j = 0; j < iSize; j++ )
69 {
70 va.destroy( &pData[j] );
71 }
72 va.deallocate( pData, iCapacity );
73 pData = NULL;
74 }
75 iSize = 0;
76 iCapacity = 0;
77 }
78
79 void erase( int iPos )
80 {
81 for( int j = iPos; j < iSize; j++ )
82 {
83 va.destroy( &pData[j] );
84 if( j == iSize-1 )
85 {
86 iSize--;
87 return;
88 }
89 va.construct( &pData[j], pData[j+1] );
90 }
91 }
92
93 void swapErase( int iPos )
94 {
95 if( iPos == iSize-1 )
96 {
97 erase( iPos );
98 return;
99 }
100 va.destroy( &pData[iPos] );
101 va.construct( &pData[iPos], pData[iSize-1] );
102 va.destroy( &pData[iSize-1] );
103 iSize--;
104 }
105
106 valuealloc va;
107 value *pData;
108 long iSize;
109 long iCapacity;
110 };
111 /** @endcond */
112
113 /**
114 * Array type container, just like a normal array only flexible and keeps
115 * track of your memory for you.
116 *
117 *@param value (typename) The type of data to store in your list
118 *@param valuealloc (typename) Memory Allocator for your value type
119 *@param linkalloc (typename) Memory Allocator for the list links.
120 *@ingroup Containers
121 */
122 template<typename value, int inc=10, typename valuealloc=std::allocator<value> >
123 class Array : public SharedCore<
124 Array<value, inc, valuealloc>,
125 ArrayCore<value, inc, valuealloc>
126 >
127 {
128 private:
129 typedef class Array<value, inc, valuealloc> MyType;
130 typedef class ArrayCore<value, inc, valuealloc> Core;
131
132 protected:
133 using SharedCore<MyType, Core>::core;
134 using SharedCore<MyType, Core>::_hardCopy;
135 using SharedCore<MyType, Core>::_resetCore;
136 using SharedCore<MyType, Core>::_allocateCore;
137
138 public:
139 struct const_iterator;
140 struct iterator;
141
142 Array()
143 {
144 }
145
146 Array( const MyType &src ) :
147 SharedCore<MyType, Core >( src )
148 {
149 }
150
151 Array( long iSetCap )
152 {
153 setCapacity( iSetCap );
154 }
155
156 ~Array()
157 {
158 }
159
160 bool operator==( const MyType &src ) const
161 {
162 if( core == src.core )
163 return true;
164 if( core->iSize != src.core->iSize )
165 return false;
166
167 for( int j = 0; j < core->iSize; j++ )
168 {
169 if( core->pData[j] != src.core->pData[j] )
170 return false;
171 }
172 return true;
173 }
174
175 bool operator!=( const MyType &src ) const
176 {
177 return !(*this == src);
178 }
179
180 /**
181 * Clear the array.
182 */
183 void clear()
184 {
185 _resetCore();
186 }
187
188 MyType &append( const value &rVal )
189 {
190 _hardCopy();
191 if( core->iSize == core->iCapacity )
192 {
193 core->setCapacity( core->iCapacity + inc );
194 }
195
196 core->va.construct( &core->pData[core->iSize++], rVal );
197
198 return *this;
199 }
200
201 MyType &append( const MyType &rVal )
202 {
203 _hardCopy();
204
205 if( core->iSize + rVal.core->iSize > core->iCapacity )
206 {
207 core->setCapacity( core->iSize + rVal.core->iSize + inc );
208 }
209
210 for( int j = 0; j < rVal.core->iSize; j++ )
211 {
212 core->va.construct(
213 &core->pData[core->iSize++],
214 rVal.core->pData[j]
215 );
216 }
217
218 return *this;
219 }
220
221 //operator
222 value &operator[]( long iIndex )
223 {
224 _hardCopy();
225 if( iIndex < 0 || iIndex >= core->iSize )
226 throw ArrayException(
227 "Index %d out of range 0:%d", iIndex, core->iSize );
228
229 return core->pData[iIndex];
230 }
231
232 const value &operator[]( long iIndex ) const
233 {
234 if( iIndex < 0 || iIndex >= core->iSize )
235 throw ArrayException(
236 "Index %d out of range 0:%d", iIndex, core->iSize );
237
238 return core->pData[iIndex];
239 }
240
241 value &get( long iIndex )
242 {
243 _hardCopy();
244 if( iIndex < 0 || iIndex >= core->iSize )
245 throw ArrayException(
246 "Index %d out of range 0:%d", iIndex, core->iSize );
247
248 return core->pData[iIndex];
249 }
250
251 const value &get( long iIndex ) const
252 {
253 if( iIndex < 0 || iIndex >= core->iSize )
254 throw ArrayException(
255 "Index %d out of range 0:%d", iIndex, core->iSize );
256
257 return core->pData[iIndex];
258 }
259
260 value &first()
261 {
262 _hardCopy();
263 return core->pData[0];
264 }
265
266 const value &first() const
267 {
268 return core->pData[0];
269 }
270
271 value &last()
272 {
273 _hardCopy();
274 return core->pData[core->iSize-1];
275 }
276
277 const value &last() const
278 {
279 return core->pData[core->iSize-1];
280 }
281
282 /**
283 * Get the current size of the array.
284 *@returns The current size of the array.
285 */
286 long getSize() const
287 {
288 return core->iSize;
289 }
290
291 /**
292 * Get the capacity of the array. This number will grow as data is
293 * added, and is mainly for the curious, it doesn't really determine
294 * much for the end user.
295 *@returns The current capacity of the array.
296 */
297 long getCapacity() const
298 {
299 return core->iCapacity;
300 }
301
302 /**
303 * Change the capacity of the array, very useful if you know you'll be
304 * adding a large amount of already counted items to the array, makes
305 * the appending much faster afterwords.
306 *@param iNewLen The new capacity of the array.
307 *@todo Set this up so it can reduce the size of the array as well as
308 * make it bigger.
309 */
310 void setCapacity( long iNewLen )
311 {
312 _hardCopy();
313 core->setCapacity( iNewLen );
314 }
315
316 typedef struct iterator
317 {
318 friend class Array<value, inc, valuealloc>;
319 private:
320 iterator( MyType &src, long iPos=0 ) :
321 src( src ),
322 iPos( iPos )
323 {
324 if( this->iPos >= src.getSize() )
325 this->iPos = -1;
326 }
327
328 MyType &src;
329 long iPos;
330
331 public:
332 iterator operator++( int )
333 {
334 if( iPos < 0 )
335 throw ArrayException(
336 "Cannot increment iterator past end of array.");
337 iPos++;
338 if( iPos >= src.getSize() )
339 iPos = -1;
340 return *this;
341 }
342
343 iterator operator++()
344 {
345 if( iPos >= 0 )
346 iPos++;
347 if( iPos >= src.getSize() )
348 iPos = -1;
349 return *this;
350 }
351
352 iterator operator+( int iAmnt )
353 {
354 if( iPos < 0 )
355 throw ArrayException(
356 "Cannot increment iterator past end of array.");
357 iPos += iAmnt;
358 if( iPos >= src.getSize() )
359 iPos = -1;
360 return *this;
361 }
362
363 iterator operator--( int )
364 {
365 if( iPos < 0 )
366 throw ArrayException(
367 "Cannot increment iterator past end of array.");
368 iPos--;
369 if( iPos < 0 )
370 iPos = -1;
371 return *this;
372 }
373
374 iterator operator--()
375 {
376 if( iPos < src.getSize() )
377 iPos--;
378 if( iPos <= 0 )
379 iPos = -1;
380 return *this;
381 }
382
383 iterator operator-( int iAmnt )
384 {
385 if( iPos < src.getSize() )
386 iPos -= iAmnt;
387 if( iPos <= 0 )
388 iPos = -1;
389 return *this;
390 }
391
392 bool operator==( const iterator &oth ) const
393 {
394 return iPos == oth.iPos;
395 }
396
397 bool operator!=( const iterator &oth ) const
398 {
399 return iPos != oth.iPos;
400 }
401
402 iterator operator=( const iterator &oth )
403 {
404 if( &src != &oth.src )
405 throw ArrayException(
406 "Cannot mix iterators from different array objects.");
407 iPos = oth.iPos;
408 }
409
410 value &operator*()
411 {
412 if( iPos < 0 )
413 throw ArrayException(
414 "Cannot dereference finished iterator.");
415 return src[iPos];
416 }
417
418 long getIndex() const
419 {
420 return iPos;
421 }
422
423 operator bool() const
424 {
425 return iPos >= 0;
426 }
427
428 bool isValid() const
429 {
430 return iPos >= 0;
431 }
432 } iterator;
433
434 typedef struct const_iterator
435 {
436 friend class Array<value, inc, valuealloc>;
437 private:
438 const_iterator( const MyType &src, long iPos=0 ) :
439 src( src ),
440 iPos( iPos )
441 {
442 if( this->iPos >= src.getSize() )
443 this->iPos = -1;
444 }
445
446 const MyType &src;
447 long iPos;
448
449 public:
450 const_iterator( iterator &rSrc ) :
451 src( rSrc.src ),
452 iPos( rSrc.iPos )
453 {
454 }
455 const_iterator operator++( int )
456 {
457 if( iPos < 0 )
458 throw ArrayException(
459 "Cannot increment iterator past end of array.");
460 iPos++;
461 if( iPos >= src.getSize() )
462 iPos = -1;
463 return *this;
464 }
465
466 const_iterator operator++()
467 {
468 if( iPos >= 0 )
469 iPos++;
470 if( iPos >= src.getSize() )
471 iPos = -1;
472 return *this;
473 }
474
475 const_iterator operator--( int )
476 {
477 if( iPos < 0 )
478 throw ArrayException(
479 "Cannot increment iterator past end of array.");
480 iPos--;
481 if( iPos < 0 )
482 iPos = -1;
483 return *this;
484 }
485
486 const_iterator operator--()
487 {
488 if( iPos < src.getSize() )
489 iPos--;
490 if( iPos <= 0 )
491 iPos = -1;
492 return *this;
493 }
494
495 bool operator==( const const_iterator &oth ) const
496 {
497 return iPos == oth.iPos;
498 }
499
500 bool operator!=( const const_iterator &oth ) const
501 {
502 return iPos != oth.iPos;
503 }
504
505 const_iterator operator=( const const_iterator &oth )
506 {
507 if( &src != &oth.src )
508 throw ArrayException(
509 "Cannot mix iterators from different array objects.");
510 iPos = oth.iPos;
511 }
512
513 const value &operator*() const
514 {
515 if( iPos < 0 )
516 throw ArrayException(
517 "Cannot dereference finished iterator.");
518 return src[iPos];
519 }
520
521 long getIndex() const
522 {
523 return iPos;
524 }
525
526 operator bool() const
527 {
528 return iPos >= 0;
529 }
530
531 bool isValid() const
532 {
533 return iPos >= 0;
534 }
535 } const_iterator;
536
537 iterator begin()
538 {
539 return iterator( *this );
540 }
541
542 const_iterator begin() const
543 {
544 return const_iterator( *this );
545 }
546
547 iterator end()
548 {
549 return iterator( *this, -1 );
550 }
551
552 const_iterator end() const
553 {
554 return const_iterator( *this, -1 );
555 }
556
557 MyType &insert( iterator i, const value &rVal )
558 {
559 if( i.iPos == -1 )
560 {
561 append( rVal );
562 return *this;
563 }
564
565 _hardCopy();
566 if( core->iSize == core->iCapacity )
567 {
568 core->setCapacity( core->iCapacity + inc );
569 }
570 core->iSize++;
571
572 core->va.construct(
573 &core->pData[core->iSize-1],
574 core->pData[core->iSize-2]
575 );
576 for( int iPos = core->iSize-2; iPos > i.iPos; iPos-- )
577 {
578 core->va.destroy( &core->pData[iPos] );
579 core->va.construct( &core->pData[iPos], core->pData[iPos-1] );
580 }
581 core->va.destroy( &core->pData[i.iPos] );
582 core->va.construct( &core->pData[i.iPos], rVal );
583
584 return *this;
585 }
586
587 /**
588 * If order is important, use this. It will delete the suggested item
589 * and move the rest of the data up a spot. This is a time O(n)
590 * operation. If the order isn't important, check swapErase
591 */
592 void erase( iterator i )
593 {
594 _hardCopy();
595 core->erase( i.iPos );
596 }
597
598 void erase( const value &v )
599 {
600 _hardCopy();
601 for( int j = 0; j < core->iSize; j++ )
602 {
603 if( core->pData[j] == v )
604 {
605 core->erase( j );
606 return;
607 }
608 }
609 }
610
611 void eraseLast()
612 {
613 _hardCopy();
614 core->erase( core->iSize-1 );
615 }
616
617 void eraseFirst()
618 {
619 _hardCopy();
620 core->erase( 0 );
621 }
622
623 /**
624 * In order to make swapErase faster, what it does is swap the given
625 * item in the array with the last item, then make the array shorter
626 * by one. It changes the order of the elements in the array, so it
627 * should be used carefully, but it is time O(1) instead of O(n) like
628 * erase.
629 */
630 void swapErase( iterator i )
631 {
632 _hardCopy();
633 core->swapErase( i.iPos );
634 }
635
636 protected:
637 virtual Core *_copyCore( Core *src )
638 {
639 Core *pRet = _allocateCore();
640 pRet->setCapacity( src->iCapacity );
641 pRet->iSize = src->iSize;
642 for( int j = 0; j < src->iSize; j++ )
643 {
644 pRet->va.construct( &pRet->pData[j], src->pData[j] );
645 }
646 return pRet;
647 }
648
649 private:
650 };
651
652 class Formatter;
653 Formatter &operator<<( Formatter &rOut, char *sStr );
654 Formatter &operator<<( Formatter &rOut, signed char c );
655 template<typename value>
656 Formatter &operator<<( Formatter &f, const Bu::Array<value> &a )
657 {
658 f << '[';
659 for( typename Bu::Array<value>::const_iterator i = a.begin(); i; i++ )
660 {
661 if( i != a.begin() )
662 f << ", ";
663 f << *i;
664 }
665 f << ']';
666
667 return f;
668 }
669
670 template<typename value, int inc, typename valuealloc>
671 ArchiveBase &operator<<( ArchiveBase &ar,
672 const Array<value, inc, valuealloc> &h )
673 {
674 ar << h.getSize();
675 for( typename Array<value, inc, valuealloc>::const_iterator i =
676 h.begin(); i != h.end(); i++ )
677 {
678 ar << (*i);
679 }
680
681 return ar;
682 }
683
684 template<typename value, int inc, typename valuealloc>
685 ArchiveBase &operator>>(ArchiveBase &ar, Array<value, inc, valuealloc> &h )
686 {
687 h.clear();
688 long nSize;
689 ar >> nSize;
690
691 h.setCapacity( nSize );
692 for( long j = 0; j < nSize; j++ )
693 {
694 value v;
695 ar >> v;
696 h.append( v );
697 }
698 return ar;
699 }
700
701}
702
703#endif
diff --git a/src/stable/atom.cpp b/src/stable/atom.cpp
new file mode 100644
index 0000000..3c77b90
--- /dev/null
+++ b/src/stable/atom.cpp
@@ -0,0 +1,8 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/atom.h"
diff --git a/src/stable/atom.h b/src/stable/atom.h
new file mode 100644
index 0000000..fd88f2d
--- /dev/null
+++ b/src/stable/atom.h
@@ -0,0 +1,147 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_ATOM_H
9#define BU_ATOM_H
10
11#include <stdint.h>
12#include <memory>
13#include "bu/config.h"
14#include "bu/exceptionbase.h"
15
16namespace Bu
17{
18 /**
19 *
20 *@ingroup Containers
21 */
22 template <typename t, typename talloc=std::allocator<t> >
23 class Atom
24 {
25 private:
26 typedef struct Atom<t, talloc> MyType;
27
28 public:
29 Atom() :
30 pData( NULL )
31 {
32 }
33
34 Atom( const MyType &oth ) :
35 pData( NULL )
36 {
37 if( oth.pData )
38 set( *oth.pData );
39 }
40
41 Atom( const t &oth ) :
42 pData( NULL )
43 {
44 set( oth );
45 }
46
47 virtual ~Atom()
48 {
49 clear();
50 }
51
52 bool has() const
53 {
54 return (pData != NULL);
55 }
56
57 void set( const t &val )
58 {
59 clear();
60 pData = ta.allocate( 1 );
61 ta.construct( pData, val );
62 }
63
64 t &get()
65 {
66 if( !pData )
67 throw Bu::ExceptionBase("Not set");
68 return *pData;
69 }
70
71 const t &get() const
72 {
73 if( !pData )
74 throw Bu::ExceptionBase("Not set");
75 return *pData;
76 }
77
78 void clear()
79 {
80 if( pData )
81 {
82 ta.destroy( pData );
83 ta.deallocate( pData, 1 );
84 pData = NULL;
85 }
86 }
87
88 operator const t &() const
89 {
90 if( !pData )
91 throw Bu::ExceptionBase("Not set");
92 return *pData;
93 }
94
95 operator t &()
96 {
97 if( !pData )
98 throw Bu::ExceptionBase("Not set");
99 return *pData;
100 }
101
102 MyType &operator =( const t &oth )
103 {
104 set( oth );
105
106 return *this;
107 }
108
109 MyType &operator =( const MyType &oth )
110 {
111 if( oth.pData )
112 set( *oth.pData );
113
114 return *this;
115 }
116
117 bool operator ==( const MyType &oth )
118 {
119 return (*pData) == (*oth.pData);
120 }
121
122 bool operator ==( const t &oth )
123 {
124 return (*pData) == oth;
125 }
126
127 t *operator ->()
128 {
129 if( !pData )
130 throw Bu::ExceptionBase("Not set");
131 return pData;
132 }
133
134 t &operator *()
135 {
136 if( !pData )
137 throw Bu::ExceptionBase("Not set");
138 return *pData;
139 }
140
141 private:
142 t *pData;
143 talloc ta;
144 };
145}
146
147#endif
diff --git a/src/stable/base64.cpp b/src/stable/base64.cpp
new file mode 100644
index 0000000..4d659f0
--- /dev/null
+++ b/src/stable/base64.cpp
@@ -0,0 +1,219 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/base64.h"
9
10namespace Bu { subExceptionDef( Base64Exception ) }
11
12const char Bu::Base64::tblEnc[65] = {
13 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
14};
15
16Bu::Base64::Base64( Bu::Stream &rNext, int iChunkSize ) :
17 Bu::Filter( rNext ),
18 iBPos( 0 ),
19 iBuf( 0 ),
20 iRPos( 0 ),
21 iChars( 0 ),
22 bEosIn( false ),
23 iTotalIn( 0 ),
24 iTotalOut( 0 ),
25 eMode( Nothing ),
26 iChunkSize( iChunkSize ),
27 iCurChunk( 0 )
28{
29 start();
30
31 memset( tblDec, 0, 80 );
32 for( int j = 0; j < 64; j++ )
33 {
34 tblDec[tblEnc[j]-'+'] = j;
35 // printf("'%c' = %d\n", tblEnc[j], j );
36 }
37 /*
38 for( int j = 0; j < 64; j++ )
39 {
40 printf("'%c' = '%c' (%d = %d)\n",
41 tblEnc[j], tblEnc[tblDec[tblEnc[j]-'+']],
42 j, tblDec[tblEnc[j]-'+'] );
43 }*/
44
45 // The following is used to compute the table size for the decoding table.
46 /*
47 char low='A', high='A';
48 for( int j = 0; j < 64; j++ )
49 {
50 if( tblEnc[j] < low )
51 low = tblEnc[j];
52 if( tblEnc[j] > high )
53 high = tblEnc[j];
54 }
55
56 printf("'%c' - '%c' (%d - %d) (%d)\n", low, high, low, high, high-low );
57 */
58}
59
60Bu::Base64::~Base64()
61{
62 stop();
63}
64
65void Bu::Base64::start()
66{
67 iCurChunk = 0;
68}
69
70Bu::size Bu::Base64::stop()
71{
72 if( eMode == Encode )
73 {
74 char outBuf[4];
75 int iBUsed = 4-(3-iBPos);
76 if( iBPos == 0 )
77 return iTotalOut;
78 for( int k = 0; k < 4; k++ )
79 {
80 outBuf[3-k] = tblEnc[(iBuf>>(6*k))&0x3f];
81 }
82 for( int k = iBUsed; k < 4; k++ )
83 {
84 outBuf[k] = '=';
85 }
86 iCurChunk += 4;
87 if( iChunkSize && iCurChunk >= iChunkSize )
88 {
89 iCurChunk = iCurChunk-iChunkSize;
90 iTotalOut += rNext.write( outBuf, 4-iCurChunk );
91 iTotalOut += rNext.write("\r\n", 2 );
92 iTotalOut += rNext.write( outBuf+(4-iCurChunk), iCurChunk );
93 }
94 else
95 iTotalOut += rNext.write( outBuf, 4 );
96 return iTotalOut;
97 }
98 else
99 {
100 return iTotalIn;
101 }
102}
103
104Bu::size Bu::Base64::read( void *pBuf, Bu::size nBytes )
105{
106 if( eMode == Encode )
107 throw Bu::Base64Exception("Cannot read from an output stream.");
108 eMode = Decode;
109
110 if( bEosIn == true && iRPos == iChars )
111 return 0;
112 Bu::size sIn = 0;
113 char buf[4];
114 while( sIn < nBytes )
115 {
116 for(; iRPos < iChars && sIn < nBytes; iRPos++, sIn++ )
117 {
118 ((unsigned char *)pBuf)[sIn] = (iBuf>>(8*(2-iRPos)))&0xFF;
119 }
120 if( iRPos == iChars )
121 {
122 if( bEosIn == true )
123 return sIn;
124 else
125 iRPos = 0;
126 }
127 else if( sIn == nBytes )
128 return sIn;
129 //if( rNext.read( buf, 4 ) == 0 )
130 // return sIn;
131 for( int j = 0; j < 4; j++ )
132 {
133 if( rNext.read( &buf[j], 1 ) == 0 )
134 {
135 if( rNext.isEos() )
136 {
137 if( iRPos == 0 )
138 iRPos = iChars;
139 bEosIn = true;
140 if( j != 0 )
141 {
142 throw Base64Exception(
143 "Premature end of stream detected while "
144 "decoding Base64 data."
145 );
146 }
147 }
148 return sIn;
149 }
150 if( buf[j] == ' ' || buf[j] == '\t' ||
151 buf[j] == '\n' || buf[j] == '\r' )
152 {
153 j--;
154 }
155 }
156 iChars = 3;
157 iBuf = 0;
158 for( int j = 0; j < 4; j++ )
159 {
160 if( buf[j] == '=' )
161 {
162 iChars--;
163 bEosIn = true;
164 }
165 else
166 iBuf |= (tblDec[buf[j]-'+']&0x3f)<<((3-j)*6);
167 //printf("%d: %06X (%02X)\n", j, iBuf, (tblDec[buf[j]-'+']&0x3f) );
168 }
169 }
170
171 return sIn;
172}
173
174Bu::size Bu::Base64::write( const void *pBuf, Bu::size nBytes )
175{
176 if( eMode == Decode )
177 throw Bu::Base64Exception("Cannot write to an input stream.");
178 eMode = Encode;
179
180 Bu::size sOut = 0;
181 char outBuf[4];
182 for( Bu::size j = 0; j < nBytes; j++ )
183 {
184 iBuf |= (((uint8_t *)pBuf)[j])<<((2-iBPos++)*8);
185 if( iBPos == 3 )
186 {
187 for( int k = 0; k < 4; k++ )
188 {
189 outBuf[3-k] = tblEnc[(iBuf>>(6*k))&0x3f];
190 }
191 iCurChunk += 4;
192 if( iChunkSize && iCurChunk >= iChunkSize )
193 {
194 iCurChunk = iCurChunk-iChunkSize;
195 sOut += rNext.write( outBuf, 4-iCurChunk );
196 sOut += rNext.write("\r\n", 2 );
197 sOut += rNext.write( outBuf+(4-iCurChunk), iCurChunk );
198 }
199 else
200 sOut += rNext.write( outBuf, 4 );
201 iBPos = iBuf = 0;
202 }
203 }
204 iTotalOut += sOut;
205 return sOut;
206}
207
208bool Bu::Base64::isOpen()
209{
210 return true;
211}
212
213bool Bu::Base64::isEos()
214{
215 if( bEosIn == true && iRPos == iChars )
216 return true;
217 return false;
218}
219
diff --git a/src/stable/base64.h b/src/stable/base64.h
new file mode 100644
index 0000000..c081ac1
--- /dev/null
+++ b/src/stable/base64.h
@@ -0,0 +1,59 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_BASE64_H
9#define BU_BASE64_H
10
11#include "bu/filter.h"
12#include "bu/exceptionbase.h"
13
14namespace Bu
15{
16 subExceptionDecl( Base64Exception );
17
18 /**
19 *
20 *@ingroup Streams
21 */
22 class Base64 : public Bu::Filter
23 {
24 public:
25 Base64( Bu::Stream &rNext, int iChunkSize=0 );
26 virtual ~Base64();
27
28 virtual void start();
29 virtual Bu::size stop();
30 virtual Bu::size read( void *pBuf, Bu::size nBytes );
31 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
32
33 virtual bool isOpen();
34
35 virtual bool isEos();
36
37 private:
38 int iBPos;
39 int iBuf;
40 int iRPos;
41 int iChars;
42 bool bEosIn;
43 Bu::size iTotalIn;
44 Bu::size iTotalOut;
45 static const char tblEnc[65];
46 char tblDec[80];
47 enum Mode
48 {
49 Nothing = 0x00,
50 Encode = 0x01,
51 Decode = 0x02,
52 };
53 Mode eMode;
54 int iChunkSize;
55 int iCurChunk;
56 };
57};
58
59#endif
diff --git a/src/stable/buffer.cpp b/src/stable/buffer.cpp
new file mode 100644
index 0000000..47fab70
--- /dev/null
+++ b/src/stable/buffer.cpp
@@ -0,0 +1,168 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/buffer.h"
9
10Bu::Buffer::Buffer( Bu::Stream &rNext, int iWhat, int iBufSize ) :
11 Bu::Filter( rNext ),
12 sSoFar( 0 ),
13 iBufSize( iBufSize ),
14 sReadBuf( NULL ),
15 sWriteBuf( NULL ),
16 iReadBufFill( 0 ),
17 iReadPos( 0 ),
18 iWriteBufFill( 0 ),
19 iWritePos( 0 ),
20 iWhat( iWhat )
21{
22 sReadBuf = new char[iBufSize];
23 sWriteBuf = new char[iBufSize];
24}
25
26Bu::Buffer::~Buffer()
27{
28 delete[] sReadBuf;
29 delete[] sWriteBuf;
30}
31
32void Bu::Buffer::start()
33{
34}
35
36Bu::size Bu::Buffer::stop()
37{
38 iReadBufFill = iReadPos = iWriteBufFill = iWritePos = 0;
39 return sSoFar;
40}
41
42void Bu::Buffer::fillReadBuf()
43{
44 if( iReadBufFill+iReadPos < iBufSize )
45 {
46 iReadBufFill += rNext.read(
47 sReadBuf+iReadPos+iReadBufFill,
48 iBufSize-iReadBufFill-iReadPos
49 );
50 }
51}
52
53Bu::size Bu::Buffer::read( void *pBuf, Bu::size nBytes )
54{
55 if( (iWhat&Read) == 0 )
56 return rNext.read( pBuf, nBytes );
57
58 if( nBytes <= 0 )
59 {
60 fillReadBuf();
61 return 0;
62 }
63
64 Bu::size nTotRead = 0;
65// fillReadBuf();
66
67 do
68 {
69 int iAmnt = nBytes-nTotRead;
70 if( iAmnt > iReadBufFill )
71 {
72 iAmnt = iReadBufFill;
73 }
74 if( iAmnt > 0 )
75 {
76 memcpy( ((char *)pBuf)+nTotRead, sReadBuf+iReadPos, iAmnt );
77 iReadPos += iAmnt;
78 nTotRead += iAmnt;
79 iReadBufFill -= iAmnt;
80 }
81 if( iReadBufFill == 0 )
82 {
83 iReadPos = 0;
84 fillReadBuf();
85 }
86 }
87 while( nTotRead < nBytes && iReadBufFill > 0 );
88
89 //printf("Buffer: %db returned, %db remain in buffer.\n", nTotRead, iReadBufFill );
90
91 return nTotRead;
92}
93
94Bu::size Bu::Buffer::write( const void *pBuf, Bu::size nBytes )
95{
96 if( (iWhat&Write) == 0 )
97 return rNext.write( pBuf, nBytes );
98
99 Bu::size nTotWrote = 0;
100
101 do
102 {
103 int iAmnt = nBytes-nTotWrote;
104 if( iAmnt > iBufSize-iWritePos-iWriteBufFill )
105 {
106 iAmnt = iBufSize-iWritePos-iWriteBufFill;
107 }
108 if( iAmnt > 0 )
109 {
110 memcpy(
111 sWriteBuf+iWritePos+iWriteBufFill,
112 ((char *)pBuf)+nTotWrote,
113 iAmnt
114 );
115 nTotWrote += iAmnt;
116 iWriteBufFill += iAmnt;
117 //printf("Buffer: Moved %db to write buffer, %db filled now.\n",
118 //iAmnt, iWriteBufFill );
119 }
120 while( iWritePos+iWriteBufFill == iBufSize )
121 {
122 //printf("iWritePos = %d\n", iWritePos );
123 int iWr = rNext.write( sWriteBuf+iWritePos, iWriteBufFill );
124 //printf("Buffer: Wrote %db from buffer to stream, %db filled now.\n", iWr, iWriteBufFill-iWr );
125 if( iWr == 0 )
126 {
127 return nTotWrote;
128 }
129 else if( iWr == iWriteBufFill )
130 {
131 iWritePos = iWriteBufFill = 0;
132 }
133 else
134 {
135 iWritePos += iWr;
136 iWriteBufFill -= iWr;
137 }
138 }
139 }
140 while( nTotWrote < nBytes && iWriteBufFill < iBufSize+iWritePos );
141
142 return nTotWrote;
143}
144
145void Bu::Buffer::flush()
146{
147 if( (iWhat&Write) == 0 )
148 return rNext.flush();
149
150 if( iWriteBufFill > 0 )
151 {
152 //printf("Buffer: Flushing remaining data, %db.\n", iWriteBufFill );
153 int iWr = 0;
154 do
155 {
156 iWr = rNext.write( sWriteBuf+iWritePos, iWriteBufFill );
157 //printf("Buffer: %db written to stream.\n", iWr );
158 iWritePos += iWr;
159 iWriteBufFill -= iWr;
160 } while( iWriteBufFill > 0 && iWr > 0 );
161 }
162}
163
164bool Bu::Buffer::isEos()
165{
166 return (iReadPos >= (iReadBufFill-1)) && (rNext.isEos());
167}
168
diff --git a/src/stable/buffer.h b/src/stable/buffer.h
new file mode 100644
index 0000000..91ec9c2
--- /dev/null
+++ b/src/stable/buffer.h
@@ -0,0 +1,58 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_BUFFER_H
9#define BU_BUFFER_H
10
11#include "bu/filter.h"
12
13namespace Bu
14{
15 class Buffer : public Bu::Filter
16 {
17 public:
18 Buffer( Bu::Stream &rNext, int iWhat=Both, int iBufSize=4096 );
19 virtual ~Buffer();
20
21 enum
22 {
23 Write = 1,
24 Read = 2,
25 Both = 3
26 };
27
28 virtual void start();
29 virtual Bu::size stop();
30
31 virtual Bu::size read( void *pBuf, Bu::size nBytes );
32 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
33 using Stream::write;
34
35 Bu::size getReadFill() { return iReadBufFill; }
36 bool isWritePending() { return iWriteBufFill > 0; }
37
38 virtual void flush();
39
40 virtual bool isEos();
41
42 private:
43 void fillReadBuf();
44
45 private:
46 Bu::size sSoFar;
47 int iBufSize;
48 char *sReadBuf;
49 char *sWriteBuf;
50 int iReadBufFill;
51 int iReadPos;
52 int iWriteBufFill;
53 int iWritePos;
54 int iWhat;
55 };
56};
57
58#endif
diff --git a/src/stable/bzip2.cpp b/src/stable/bzip2.cpp
new file mode 100644
index 0000000..ca007b0
--- /dev/null
+++ b/src/stable/bzip2.cpp
@@ -0,0 +1,233 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/bzip2.h"
9#include "bu/trace.h"
10
11#include <bzlib.h>
12
13#define pState ((bz_stream *)prState)
14
15using namespace Bu;
16
17Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) :
18 Bu::Filter( rNext ),
19 prState( NULL ),
20 nCompression( nCompression ),
21 sTotalOut( 0 )
22{
23 TRACE( nCompression );
24 start();
25}
26
27Bu::BZip2::~BZip2()
28{
29 TRACE();
30 stop();
31}
32
33void Bu::BZip2::start()
34{
35 TRACE();
36
37 prState = new bz_stream;
38 pState->state = NULL;
39 pState->bzalloc = NULL;
40 pState->bzfree = NULL;
41 pState->opaque = NULL;
42
43 nBufSize = 64*1024;
44 pBuf = new char[nBufSize];
45}
46
47Bu::size Bu::BZip2::stop()
48{
49 TRACE();
50 if( pState->state )
51 {
52 if( bReading )
53 {
54 BZ2_bzDecompressEnd( pState );
55 delete[] pBuf;
56 pBuf = NULL;
57 delete pState;
58 prState = NULL;
59 return 0;
60 }
61 else
62 {
63// Bu::size sTotal = 0;
64 for(;;)
65 {
66 pState->next_in = NULL;
67 pState->avail_in = 0;
68 pState->avail_out = nBufSize;
69 pState->next_out = pBuf;
70 int res = BZ2_bzCompress( pState, BZ_FINISH );
71 if( pState->avail_out < nBufSize )
72 {
73 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
74 }
75 if( res == BZ_STREAM_END )
76 break;
77 }
78 BZ2_bzCompressEnd( pState );
79 delete[] pBuf;
80 pBuf = NULL;
81 delete pState;
82 prState = NULL;
83 return sTotalOut;
84 }
85 }
86 return 0;
87}
88
89void Bu::BZip2::bzError( int code )
90{
91 TRACE( code );
92 switch( code )
93 {
94 case BZ_OK:
95 case BZ_RUN_OK:
96 case BZ_FLUSH_OK:
97 case BZ_FINISH_OK:
98 return;
99
100 case BZ_CONFIG_ERROR:
101 throw ExceptionBase("BZip2: Library configured improperly, reinstall.");
102
103 case BZ_SEQUENCE_ERROR:
104 throw ExceptionBase("BZip2: Functions were called in an invalid sequence.");
105
106 case BZ_PARAM_ERROR:
107 throw ExceptionBase("BZip2: Invalid parameter was passed into a function.");
108
109 case BZ_MEM_ERROR:
110 throw ExceptionBase("BZip2: Couldn't allocate sufficient memory.");
111
112 case BZ_DATA_ERROR:
113 throw ExceptionBase("BZip2: Data was corrupted before decompression.");
114
115 case BZ_DATA_ERROR_MAGIC:
116 throw ExceptionBase("BZip2: Stream does not appear to be bzip2 data.");
117
118 case BZ_IO_ERROR:
119 throw ExceptionBase("BZip2: File couldn't be read from / written to.");
120
121 case BZ_UNEXPECTED_EOF:
122 throw ExceptionBase("BZip2: End of file encountered before end of stream.");
123
124 case BZ_OUTBUFF_FULL:
125 throw ExceptionBase("BZip2: Buffer not large enough to accomidate data.");
126
127 default:
128 throw ExceptionBase("BZip2: Unknown error encountered.");
129
130 }
131}
132
133Bu::size Bu::BZip2::read( void *pData, Bu::size nBytes )
134{
135 TRACE( pData, nBytes );
136 if( !pState->state )
137 {
138 bReading = true;
139 BZ2_bzDecompressInit( pState, 0, 0 );
140 pState->next_in = pBuf;
141 pState->avail_in = 0;
142 }
143 if( bReading == false )
144 throw ExceptionBase("This bzip2 filter is in writing mode, you can't read.");
145
146 int nRead = 0;
147 int nReadTotal = pState->total_out_lo32;
148 pState->next_out = (char *)pData;
149 pState->avail_out = nBytes;
150 for(;;)
151 {
152 int ret = BZ2_bzDecompress( pState );
153
154 nReadTotal += nRead-pState->avail_out;
155
156 if( ret == BZ_STREAM_END )
157 {
158 if( pState->avail_in > 0 )
159 {
160 if( rNext.isSeekable() )
161 {
162 rNext.seek( -pState->avail_in );
163 }
164 }
165 return nBytes-pState->avail_out;
166 }
167 bzError( ret );
168
169 if( pState->avail_out )
170 {
171 if( pState->avail_in == 0 )
172 {
173 nRead = rNext.read( pBuf, nBufSize );
174 if( nRead == 0 && rNext.isEos() )
175 {
176 throw Bu::ExceptionBase("Premature end of underlying "
177 "stream found reading bzip2 stream.");
178 }
179 pState->next_in = pBuf;
180 pState->avail_in = nRead;
181 }
182 }
183 else
184 {
185 return nBytes-pState->avail_out;
186 }
187 }
188 return 0;
189}
190
191Bu::size Bu::BZip2::write( const void *pData, Bu::size nBytes )
192{
193 TRACE( pData, nBytes );
194 if( !pState->state )
195 {
196 bReading = false;
197 BZ2_bzCompressInit( pState, nCompression, 0, 30 );
198 }
199 if( bReading == true )
200 throw ExceptionBase("This bzip2 filter is in reading mode, you can't write.");
201
202// Bu::size sTotalOut = 0;
203 pState->next_in = (char *)pData;
204 pState->avail_in = nBytes;
205 for(;;)
206 {
207 pState->avail_out = nBufSize;
208 pState->next_out = pBuf;
209
210 bzError( BZ2_bzCompress( pState, BZ_RUN ) );
211
212 if( pState->avail_out < nBufSize )
213 {
214 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
215 }
216 if( pState->avail_in == 0 )
217 break;
218 }
219
220 return nBytes;
221}
222
223bool Bu::BZip2::isOpen()
224{
225 TRACE();
226 return (pState->state != NULL);
227}
228
229Bu::size Bu::BZip2::getCompressedSize()
230{
231 return sTotalOut;
232}
233
diff --git a/src/stable/bzip2.h b/src/stable/bzip2.h
new file mode 100644
index 0000000..9a8d172
--- /dev/null
+++ b/src/stable/bzip2.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_BZIP2_H
9#define BU_BZIP2_H
10
11#include <stdint.h>
12
13#include "bu/filter.h"
14
15namespace Bu
16{
17 /**
18 * Provides BZip2 type compression and decompression.
19 *
20 *@ingroup Streams
21 *@ingroup Compression
22 */
23 class BZip2 : public Bu::Filter
24 {
25 public:
26 BZip2( Bu::Stream &rNext, int nCompression=9 );
27 virtual ~BZip2();
28
29 virtual void start();
30 virtual Bu::size stop();
31 virtual Bu::size read( void *pBuf, Bu::size nBytes );
32 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
33
34 virtual bool isOpen();
35
36 Bu::size getCompressedSize();
37
38 private:
39 void bzError( int code );
40 void *prState;
41 bool bReading;
42 int nCompression;
43 char *pBuf;
44 uint32_t nBufSize;
45 Bu::size sTotalOut;
46 };
47}
48
49#endif
diff --git a/src/stable/client.cpp b/src/stable/client.cpp
new file mode 100644
index 0000000..75f6158
--- /dev/null
+++ b/src/stable/client.cpp
@@ -0,0 +1,320 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/client.h"
9#include "bu/tcpsocket.h"
10#include <stdlib.h>
11#include <errno.h>
12#include "bu/protocol.h"
13#include "bu/clientlink.h"
14#include "bu/clientlinkfactory.h"
15
16/** Read buffer size. */
17#define RBS (2000) // 1500 is the nominal MTU for ethernet, it's a good guess
18
19Bu::Client::Client( Bu::TcpSocket *pSocket,
20 class Bu::ClientLinkFactory *pfLink ) :
21 pTopStream( pSocket ),
22 pSocket( pSocket ),
23 pProto( NULL ),
24 bWantsDisconnect( false ),
25 pfLink( pfLink )
26{
27 lFilts.prepend( pSocket );
28}
29
30Bu::Client::~Client()
31{
32 for( FilterList::iterator i = lFilts.begin(); i; i++ )
33 {
34 delete *i;
35 }
36 pTopStream = pSocket = NULL;
37 delete pfLink;
38}
39
40void Bu::Client::processInput()
41{
42 char buf[RBS];
43 Bu::size nRead, nTotal=0;
44
45 for(;;)
46 {
47 try
48 {
49 nRead = pTopStream->read( buf, RBS );
50
51 if( nRead == 0 )
52 {
53 break;
54 }
55 else
56 {
57 nTotal += nRead;
58 qbRead.write( buf, nRead );
59 if( !pTopStream->canRead() )
60 break;
61 }
62 }
63 catch( Bu::TcpSocketException &e )
64 {
65 pTopStream->close();
66 bWantsDisconnect = true;
67 break;
68 }
69 }
70
71 if( nTotal == 0 )
72 {
73 pTopStream->close();
74 bWantsDisconnect = true;
75 }
76
77 if( pProto && nTotal )
78 {
79 pProto->onNewData( this );
80 }
81}
82
83void Bu::Client::processOutput()
84{
85 char buf[RBS];
86 if( qbWrite.getSize() > 0 )
87 {
88 int nAmnt = RBS;
89 nAmnt = qbWrite.peek( buf, nAmnt );
90 int nReal = pTopStream->write( buf, nAmnt );
91 qbWrite.seek( nReal );
92 pTopStream->flush();
93 }
94}
95
96void Bu::Client::setProtocol( Protocol *pProto )
97{
98 this->pProto = pProto;
99 this->pProto->onNewConnection( this );
100}
101
102Bu::Protocol *Bu::Client::getProtocol()
103{
104 return pProto;
105}
106
107void Bu::Client::clearProtocol()
108{
109 pProto = NULL;
110}
111/*
112Bu::String &Bu::Client::getInput()
113{
114 return sReadBuf;
115}
116
117Bu::String &Bu::Client::getOutput()
118{
119 return sWriteBuf;
120}
121*/
122
123bool Bu::Client::isOpen()
124{
125 if( !pTopStream ) return false;
126 return pTopStream->isOpen();
127}
128
129Bu::size Bu::Client::write( const Bu::String &sData )
130{
131 return qbWrite.write( sData.getStr(), sData.getSize() );
132}
133
134Bu::size Bu::Client::write( const void *pData, Bu::size nBytes )
135{
136 return qbWrite.write( pData, nBytes );
137}
138
139Bu::size Bu::Client::write( int8_t nData )
140{
141 return qbWrite.write( (const char *)&nData, sizeof(nData) );
142}
143
144Bu::size Bu::Client::write( int16_t nData )
145{
146 return qbWrite.write( (const char *)&nData, sizeof(nData) );
147}
148
149Bu::size Bu::Client::write( int32_t nData )
150{
151 return qbWrite.write( (const char *)&nData, sizeof(nData) );
152}
153
154Bu::size Bu::Client::write( int64_t nData )
155{
156 return qbWrite.write( (const char *)&nData, sizeof(nData) );
157}
158
159Bu::size Bu::Client::write( uint8_t nData )
160{
161 return qbWrite.write( (const char *)&nData, sizeof(nData) );
162}
163
164Bu::size Bu::Client::write( uint16_t nData )
165{
166 return qbWrite.write( (const char *)&nData, sizeof(nData) );
167}
168
169Bu::size Bu::Client::write( uint32_t nData )
170{
171 return qbWrite.write( (const char *)&nData, sizeof(nData) );
172}
173
174Bu::size Bu::Client::write( uint64_t nData )
175{
176 return qbWrite.write( (const char *)&nData, sizeof(nData) );
177}
178
179Bu::size Bu::Client::read( void *pData, Bu::size nBytes )
180{
181 return qbRead.read( pData, nBytes );
182}
183
184Bu::size Bu::Client::peek( void *pData, int nBytes, int nOffset )
185{
186 return qbRead.peek( pData, nBytes, nOffset );
187}
188
189Bu::size Bu::Client::getInputSize()
190{
191 return qbRead.getSize();
192}
193
194Bu::size Bu::Client::getOutputSize()
195{
196 return qbWrite.getSize();
197}
198
199const Bu::TcpSocket *Bu::Client::getSocket() const
200{
201 return pSocket;
202}
203
204void Bu::Client::disconnect()
205{
206 bWantsDisconnect = true;
207}
208
209bool Bu::Client::wantsDisconnect()
210{
211 return bWantsDisconnect;
212}
213
214void Bu::Client::close()
215{
216 pTopStream->close();
217}
218
219Bu::ClientLink *Bu::Client::getLink()
220{
221 return pfLink->createLink( this );
222}
223
224void Bu::Client::onMessage( const Bu::String &sMsg )
225{
226 if( pProto )
227 pProto->onMessage( this, sMsg );
228}
229
230void Bu::Client::tick()
231{
232 if( pProto )
233 pProto->onTick( this );
234}
235
236Bu::size Bu::Client::tell()
237{
238 return 0;
239}
240
241void Bu::Client::seek( Bu::size offset )
242{
243 return qbRead.seek( offset );
244}
245
246void Bu::Client::setPos( Bu::size )
247{
248 throw Bu::ExceptionBase();
249}
250
251void Bu::Client::setPosEnd( Bu::size )
252{
253 throw Bu::ExceptionBase();
254}
255
256bool Bu::Client::isEos()
257{
258 return true;
259}
260
261void Bu::Client::flush()
262{
263 processOutput();
264}
265
266bool Bu::Client::canRead()
267{
268 return qbRead.getSize() > 0;
269}
270
271bool Bu::Client::canWrite()
272{
273 return true;
274}
275
276bool Bu::Client::isReadable()
277{
278 return true;
279}
280
281bool Bu::Client::isWritable()
282{
283 return true;
284}
285
286bool Bu::Client::isSeekable()
287{
288 return false;
289}
290
291bool Bu::Client::isBlocking()
292{
293 return false;
294}
295
296void Bu::Client::setBlocking( bool )
297{
298 throw Bu::ExceptionBase();
299}
300
301void Bu::Client::setSize( Bu::size )
302{
303 throw Bu::ExceptionBase();
304}
305
306Bu::size Bu::Client::getSize() const
307{
308 return 0;
309}
310
311Bu::size Bu::Client::getBlockSize() const
312{
313 return pSocket->getBlockSize();
314}
315
316Bu::String Bu::Client::getLocation() const
317{
318 return pSocket->getLocation();
319}
320
diff --git a/src/stable/client.h b/src/stable/client.h
new file mode 100644
index 0000000..119c2c1
--- /dev/null
+++ b/src/stable/client.h
@@ -0,0 +1,133 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_CLIENT_H
9#define BU_CLIENT_H
10
11#include <stdint.h>
12
13#include "bu/config.h"
14#include "bu/string.h"
15#include "bu/queuebuf.h"
16
17namespace Bu
18{
19 class Protocol;
20 class Stream;
21 class TcpSocket;
22 class ClientLinkFactory;
23
24 /**
25 *@ingroup Serving
26 */
27 class Client : public Bu::Stream
28 {
29 public:
30 Client( Bu::TcpSocket *pSocket, Bu::ClientLinkFactory *pfLink );
31 virtual ~Client();
32
33 void processInput();
34 void processOutput();
35
36 //Bu::String &getInput();
37 //Bu::String &getOutput();
38 Bu::size write( const Bu::String &sData );
39 Bu::size write( const void *pData, Bu::size nBytes );
40 Bu::size write( int8_t nData );
41 Bu::size write( int16_t nData );
42 Bu::size write( int32_t nData );
43 Bu::size write( int64_t nData );
44 Bu::size write( uint8_t nData );
45 Bu::size write( uint16_t nData );
46 Bu::size write( uint32_t nData );
47 Bu::size write( uint64_t nData );
48 Bu::size read( void *pData, Bu::size nBytes );
49 Bu::size peek( void *pData, int nBytes, int nOffset=0 );
50// void seek( int nBytes );
51 Bu::size getInputSize();
52 Bu::size getOutputSize();
53
54 void setProtocol( Protocol *pProto );
55 Bu::Protocol *getProtocol();
56 void clearProtocol();
57
58 bool isOpen();
59 void close();
60 void tick();
61
62 const Bu::TcpSocket *getSocket() const;
63
64 void disconnect();
65 bool wantsDisconnect();
66
67 class ClientLink *getLink();
68
69 void onMessage( const Bu::String &sMsg );
70
71 bool hasOutput() { return qbWrite.getSize() > 0; }
72 bool hasInput() { return qbRead.getSize() > 0; }
73
74 template<typename filter>
75 void pushFilter()
76 {
77 filter *pFlt = new filter( *pTopStream );
78 pTopStream = pFlt;
79 lFilts.prepend( pFlt );
80 }
81
82 template<typename filter, typename p1t>
83 void pushFilter( p1t p1 )
84 {
85 filter *pFlt = new filter( *pTopStream, p1 );
86 pTopStream = pFlt;
87 lFilts.prepend( pFlt );
88 }
89
90 template<typename filter, typename p1t, typename p2t>
91 void pushFilter( p1t p1, p2t p2 )
92 {
93 filter *pFlt = new filter( *pTopStream, p1, p2 );
94 pTopStream = pFlt;
95 lFilts.prepend( pFlt );
96 }
97
98 /*
99 * These are required to qualify as a stream, I dunno how many will
100 * be implemented.
101 */
102 virtual Bu::size tell();
103 virtual void seek( Bu::size offset );
104 virtual void setPos( Bu::size pos );
105 virtual void setPosEnd( Bu::size pos );
106 virtual bool isEos();
107 virtual void flush();
108 virtual bool canRead();
109 virtual bool canWrite();
110 virtual bool isReadable();
111 virtual bool isWritable();
112 virtual bool isSeekable();
113 virtual bool isBlocking();
114 virtual void setBlocking( bool bBlocking=true );
115 virtual void setSize( Bu::size iSize );
116 virtual size getSize() const;
117 virtual size getBlockSize() const;
118 virtual Bu::String getLocation() const;
119
120 private:
121 typedef Bu::List<Bu::Stream *> FilterList;
122 FilterList lFilts;
123 Bu::Stream *pTopStream;
124 Bu::TcpSocket *pSocket;
125 Bu::Protocol *pProto;
126 Bu::QueueBuf qbRead;
127 Bu::QueueBuf qbWrite;
128 bool bWantsDisconnect;
129 class Bu::ClientLinkFactory *pfLink;
130 };
131}
132
133#endif
diff --git a/src/stable/clientlink.cpp b/src/stable/clientlink.cpp
new file mode 100644
index 0000000..ce8b2cb
--- /dev/null
+++ b/src/stable/clientlink.cpp
@@ -0,0 +1,17 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/clientlink.h"
9
10Bu::ClientLink::ClientLink()
11{
12}
13
14Bu::ClientLink::~ClientLink()
15{
16}
17
diff --git a/src/stable/clientlink.h b/src/stable/clientlink.h
new file mode 100644
index 0000000..e4618e7
--- /dev/null
+++ b/src/stable/clientlink.h
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_CLIENT_LINK_H
9#define BU_CLIENT_LINK_H
10
11#include "bu/string.h"
12
13namespace Bu
14{
15 class ClientLink
16 {
17 public:
18 ClientLink();
19 virtual ~ClientLink();
20
21 virtual void sendMessage( const Bu::String &sMsg )=0;
22 };
23};
24
25#endif
diff --git a/src/stable/clientlinkfactory.cpp b/src/stable/clientlinkfactory.cpp
new file mode 100644
index 0000000..f48e11e
--- /dev/null
+++ b/src/stable/clientlinkfactory.cpp
@@ -0,0 +1,17 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/clientlinkfactory.h"
9
10Bu::ClientLinkFactory::ClientLinkFactory()
11{
12}
13
14Bu::ClientLinkFactory::~ClientLinkFactory()
15{
16}
17
diff --git a/src/stable/clientlinkfactory.h b/src/stable/clientlinkfactory.h
new file mode 100644
index 0000000..21d3363
--- /dev/null
+++ b/src/stable/clientlinkfactory.h
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_CLIENT_LINK_FACTORY_H
9#define BU_CLIENT_LINK_FACTORY_H
10
11namespace Bu
12{
13 class Client;
14 class ClientLink;
15
16 class ClientLinkFactory
17 {
18 public:
19 ClientLinkFactory();
20 virtual ~ClientLinkFactory();
21
22 virtual Bu::ClientLink *createLink( Bu::Client *pClient )=0;
23 };
24};
25
26#endif
diff --git a/src/stable/condition.cpp b/src/stable/condition.cpp
new file mode 100644
index 0000000..2f55ce2
--- /dev/null
+++ b/src/stable/condition.cpp
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include <sys/time.h>
9
10#include "bu/condition.h"
11
12Bu::Condition::Condition()
13{
14 pthread_cond_init( &cond, NULL );
15}
16
17Bu::Condition::~Condition()
18{
19 pthread_cond_destroy( &cond );
20}
21
22int Bu::Condition::wait()
23{
24 return pthread_cond_wait( &cond, &mutex );
25}
26
27int Bu::Condition::wait( int nSec, int nUSec )
28{
29 struct timeval now;
30 struct timespec timeout;
31 struct timezone tz;
32
33 gettimeofday( &now, &tz );
34 timeout.tv_sec = now.tv_sec + nSec + ((now.tv_usec + nUSec)/1000000);
35 timeout.tv_nsec = ((now.tv_usec + nUSec)%1000000)*1000;
36
37 return pthread_cond_timedwait( &cond, &mutex, &timeout );
38}
39
40int Bu::Condition::signal()
41{
42 return pthread_cond_signal( &cond );
43}
44
45int Bu::Condition::broadcast()
46{
47 return pthread_cond_broadcast( &cond );
48}
49
diff --git a/src/stable/condition.h b/src/stable/condition.h
new file mode 100644
index 0000000..71634f5
--- /dev/null
+++ b/src/stable/condition.h
@@ -0,0 +1,90 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_CONDITION_H
9#define BU_CONDITION_H
10
11#include <pthread.h>
12
13#include "bu/mutex.h"
14
15namespace Bu
16{
17 /**
18 * Ito condition. This is a fairly simple condition mechanism. As you may
19 * notice this class inherits from the Mutex class, this is because all
20 * conditions must be within a locked block. The standard usage of a
21 * condition is to pause one thread, perhaps indefinately, until another
22 * thread signals that it is alright to procede.
23 * <br>
24 * Standard usage for the thread that wants to wait is as follows:
25 * <pre>
26 * Condition cond;
27 * ... // Perform setup and enter your run loop
28 * cond.lock();
29 * while( !isFinished() ) // Could be anything you're waiting for
30 * cond.wait();
31 * ... // Take care of what you have to.
32 * cond.unlock();
33 * </pre>
34 * The usage for the triggering thread is much simpler, when it needs to
35 * tell the others that it's time to grab some data it calls either signal
36 * or broadcast. See both of those functions for the difference.
37 *@ingroup Threading
38 */
39 class Condition : public Mutex
40 {
41 public:
42 /**
43 * Create a condition.
44 */
45 Condition();
46
47 /**
48 * Destroy a condition.
49 */
50 ~Condition();
51
52 /**
53 * Wait forever, or until signalled. This has to be called from within
54 * a locked section, i.e. before calling this this object's lock
55 * function should be called.
56 */
57 int wait();
58
59 /**
60 * Wait for a maximum of nSec seconds and nUSec micro-seconds or until
61 * signalled. This is a little more friendly function if you want to
62 * perform other operations in the thrad loop that calls this function.
63 * Like the other wait function, this must be inside a locked section.
64 *@param nSec The seconds to wait.
65 *@param nUSec the micro-seconds to wait.
66 */
67 int wait( int nSec, int nUSec );
68
69 /**
70 * Notify the next thread waiting on this condition that they can go
71 * ahead. This only signals one thread, the next one in the condition
72 * queue, that it is safe to procede with whatever operation was being
73 * waited on.
74 */
75 int signal();
76
77 /**
78 * Notify all threads waiting on this condition that they can go ahead
79 * now. This function is slower than signal, but more effective in
80 * certain situations where you may not know how many threads should be
81 * activated.
82 */
83 int broadcast();
84
85 private:
86 pthread_cond_t cond; /**< Internal condition reference. */
87 };
88}
89
90#endif
diff --git a/src/stable/conduit.cpp b/src/stable/conduit.cpp
new file mode 100644
index 0000000..c9ccdc4
--- /dev/null
+++ b/src/stable/conduit.cpp
@@ -0,0 +1,233 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/conduit.h"
9
10Bu::Conduit::Conduit( int iBlockSize ) :
11 qb( iBlockSize ),
12 bBlocking( true ),
13 bOpen( true )
14{
15}
16
17Bu::Conduit::~Conduit()
18{
19}
20
21void Bu::Conduit::close()
22{
23 im.lock();
24// qb.close();
25 bOpen = false;
26
27 cBlock.signal();
28 im.unlock();
29}
30
31#include <stdio.h>
32Bu::size Bu::Conduit::read( void *pBuf, Bu::size nBytes )
33{
34 if( !isOpen() )
35 {
36 return 0;
37 }
38 im.lock();
39 if( bBlocking )
40 {
41 im.unlock();
42 cBlock.lock();
43 for(;;)
44 {
45 im.lock();
46 if( qb.getSize() == 0 && bOpen == false )
47 {
48 im.unlock();
49 cBlock.unlock();
50 return 0;
51 }
52 else if( qb.getSize() > 0 )
53 {
54 im.unlock();
55 break;
56 }
57 im.unlock();
58
59 cBlock.wait();
60 }
61
62 im.lock();
63 Bu::size iRet = qb.read( pBuf, nBytes );
64 im.unlock();
65
66 cBlock.unlock();
67 return iRet;
68 }
69 else
70 {
71 Bu::size iRet = qb.read( pBuf, nBytes );
72 im.unlock();
73
74 return iRet;
75 }
76}
77
78Bu::size Bu::Conduit::peek( void *pBuf, Bu::size nBytes )
79{
80 im.lock();
81 Bu::size iRet = qb.peek( pBuf, nBytes );
82 im.unlock();
83
84 return iRet;
85}
86
87Bu::size Bu::Conduit::peek( void *pBuf, Bu::size nBytes, Bu::size nSkip )
88{
89 im.lock();
90 Bu::size iRet = qb.peek( pBuf, nBytes, nSkip );
91 im.unlock();
92
93 return iRet;
94}
95
96Bu::size Bu::Conduit::write( const void *pBuf, Bu::size nBytes )
97{
98 im.lock();
99 if( bOpen == false )
100 {
101 im.unlock();
102 return 0;
103 }
104 Bu::size sRet = qb.write( pBuf, nBytes );
105 cBlock.signal();
106 im.unlock();
107
108 return sRet;
109}
110
111Bu::size Bu::Conduit::tell()
112{
113 im.lock();
114 Bu::size sRet = qb.tell();
115 im.unlock();
116 return sRet;
117}
118
119void Bu::Conduit::seek( Bu::size )
120{
121}
122
123void Bu::Conduit::setPos( Bu::size )
124{
125}
126
127void Bu::Conduit::setPosEnd( Bu::size )
128{
129}
130
131bool Bu::Conduit::isEos()
132{
133 im.lock();
134 bool bRet = qb.isEos();
135 im.unlock();
136 return bRet;
137}
138
139bool Bu::Conduit::isOpen()
140{
141 im.lock();
142 bool bRet = bOpen || (qb.getSize() > 0);
143 im.unlock();
144 return bRet;
145}
146
147void Bu::Conduit::flush()
148{
149}
150
151bool Bu::Conduit::canRead()
152{
153 im.lock();
154 bool bRet = qb.canRead();
155 im.unlock();
156 return bRet;
157}
158
159bool Bu::Conduit::canWrite()
160{
161 im.lock();
162 bool bRet = qb.canWrite();
163 im.unlock();
164 return bRet;
165}
166
167bool Bu::Conduit::isReadable()
168{
169 im.lock();
170 bool bRet = qb.isReadable();
171 im.unlock();
172 return bRet;
173}
174
175bool Bu::Conduit::isWritable()
176{
177 im.lock();
178 bool bRet = qb.isWritable();
179 im.unlock();
180 return bRet;
181}
182
183bool Bu::Conduit::isSeekable()
184{
185 im.lock();
186 bool bRet = qb.isSeekable();
187 im.unlock();
188 return bRet;
189}
190
191bool Bu::Conduit::isBlocking()
192{
193 im.lock();
194 bool bRet = bBlocking;
195 im.unlock();
196 return bRet;
197}
198
199void Bu::Conduit::setBlocking( bool bBlocking )
200{
201 im.lock();
202 this->bBlocking = bBlocking;
203 im.unlock();
204}
205
206void Bu::Conduit::setSize( Bu::size )
207{
208}
209
210Bu::size Bu::Conduit::getSize() const
211{
212 im.lock();
213 Bu::size sRet = qb.getSize();
214 im.unlock();
215 return sRet;
216}
217
218Bu::size Bu::Conduit::getBlockSize() const
219{
220 im.lock();
221 Bu::size sRet = qb.getBlockSize();
222 im.unlock();
223 return sRet;
224}
225
226Bu::String Bu::Conduit::getLocation() const
227{
228 im.lock();
229 Bu::String sRet = qb.getLocation();
230 im.unlock();
231 return sRet;
232}
233
diff --git a/src/stable/conduit.h b/src/stable/conduit.h
new file mode 100644
index 0000000..9babaaf
--- /dev/null
+++ b/src/stable/conduit.h
@@ -0,0 +1,64 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_CONDUIT_H
9#define BU_CONDUIT_H
10
11#include "bu/stream.h"
12#include "bu/string.h"
13#include "bu/queuebuf.h"
14#include "bu/mutex.h"
15#include "bu/condition.h"
16
17namespace Bu
18{
19 /**
20 * Simple inter-thread communication stream. This acts like a pair of
21 * pipes for stream communication between any two things, but without the
22 * use of pipes, making this a bad choice for IPC.
23 */
24 class Conduit : public Stream
25 {
26 public:
27 Conduit( int iBlockSize=256 );
28 virtual ~Conduit();
29
30 virtual void close();
31 virtual Bu::size read( void *pBuf, Bu::size nBytes );
32 virtual Bu::size peek( void *pBuf, Bu::size nBytes );
33 virtual Bu::size peek( void *pBuf, Bu::size nBytes, Bu::size nSkip );
34 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
35 virtual Bu::size tell();
36 virtual void seek( Bu::size offset );
37 virtual void setPos( Bu::size pos );
38 virtual void setPosEnd( Bu::size pos );
39 virtual bool isEos();
40 virtual bool isOpen();
41 virtual void flush();
42 virtual bool canRead();
43 virtual bool canWrite();
44 virtual bool isReadable();
45 virtual bool isWritable();
46 virtual bool isSeekable();
47 virtual bool isBlocking();
48 virtual void setBlocking( bool bBlocking=true );
49 virtual void setSize( Bu::size iSize );
50
51 virtual size getSize() const;
52 virtual size getBlockSize() const;
53 virtual Bu::String getLocation() const;
54
55 private:
56 QueueBuf qb;
57 mutable Mutex im;
58 Condition cBlock;
59 bool bBlocking;
60 bool bOpen;
61 };
62}
63
64#endif
diff --git a/src/stable/crypt.cpp b/src/stable/crypt.cpp
new file mode 100644
index 0000000..eb87479
--- /dev/null
+++ b/src/stable/crypt.cpp
@@ -0,0 +1,47 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/crypt.h"
9#include "bu/md5.h"
10#include "bu/base64.h"
11#include "bu/membuf.h"
12#include "bu/file.h"
13
14Bu::String Bu::cryptPass( const Bu::String &sPass, const Bu::String &sSalt )
15{
16 Bu::Md5 md5;
17 Bu::MemBuf mbOut;
18 Bu::Base64 b64Out( mbOut );
19
20 Bu::String::const_iterator i = sSalt.find('$');
21 Bu::String sSaltSml = sSalt.getSubStr( sSalt.begin(), i );
22
23 md5.addData( sPass );
24 md5.addData( sSaltSml );
25 md5.writeResult( b64Out );
26
27 b64Out.stop();
28
29 return sSaltSml + "$" + mbOut.getString();
30}
31
32Bu::String Bu::cryptPass( const Bu::String &sPass )
33{
34 Bu::MemBuf mbSalt;
35 Bu::Base64 b64Salt( mbSalt );
36 Bu::File fRand("/dev/urandom", Bu::File::Read );
37
38#define STR 6
39 char buf[STR];
40 fRand.read( buf, STR );
41 b64Salt.write( buf, STR );
42
43 b64Salt.stop();
44
45 return cryptPass( sPass, mbSalt.getString() );
46}
47
diff --git a/src/stable/crypt.h b/src/stable/crypt.h
new file mode 100644
index 0000000..a94402a
--- /dev/null
+++ b/src/stable/crypt.h
@@ -0,0 +1,19 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_CRYPT_H
9#define BU_CRYPT_H
10
11#include "bu/string.h"
12
13namespace Bu
14{
15 String cryptPass( const Bu::String &sPass, const Bu::String &sSalt );
16 String cryptPass( const Bu::String &sPass );
17};
18
19#endif
diff --git a/src/stable/cryptohash.cpp b/src/stable/cryptohash.cpp
new file mode 100644
index 0000000..ddd293c
--- /dev/null
+++ b/src/stable/cryptohash.cpp
@@ -0,0 +1,38 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/cryptohash.h"
9
10Bu::CryptoHash::CryptoHash()
11{
12}
13
14Bu::CryptoHash::~CryptoHash()
15{
16}
17
18void Bu::CryptoHash::addData( const Bu::String &sData )
19{
20 addData( sData.getStr(), sData.getSize() );
21}
22
23Bu::String Bu::CryptoHash::getHexResult()
24{
25 Bu::String sResult = getResult();
26 Bu::String sRet( 2*sResult.getSize() );
27 static const char hex_tab[] = {"0123456789abcdef"};
28
29 int k = 0;
30 for( int i = 0; i < sResult.getSize(); i++ )
31 {
32 sRet[k++] = hex_tab[(((unsigned char)sResult[i])>>4) & 0xF];
33 sRet[k++] = hex_tab[((unsigned char)sResult[i]) & 0xF];
34 }
35
36 return sRet;
37}
38
diff --git a/src/stable/cryptohash.h b/src/stable/cryptohash.h
new file mode 100644
index 0000000..bc5435f
--- /dev/null
+++ b/src/stable/cryptohash.h
@@ -0,0 +1,33 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_CRYPTO_HASH_H
9#define BU_CRYPTO_HASH_H
10
11#include "bu/string.h"
12
13namespace Bu
14{
15 class Stream;
16
17 class CryptoHash
18 {
19 public:
20 CryptoHash();
21 virtual ~CryptoHash();
22
23 virtual void reset() = 0;
24 virtual void setSalt( const Bu::String &sSalt ) = 0;
25 virtual void addData( const void *sData, int iSize ) = 0;
26 virtual void addData( const Bu::String &sData );
27 virtual String getResult() = 0;
28 virtual void writeResult( Stream &sOut ) = 0;
29 virtual Bu::String getHexResult();
30 };
31};
32
33#endif
diff --git a/src/stable/csvreader.cpp b/src/stable/csvreader.cpp
new file mode 100644
index 0000000..4da7883
--- /dev/null
+++ b/src/stable/csvreader.cpp
@@ -0,0 +1,130 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/csvreader.h"
9#include "bu/stream.h"
10
11#include "bu/sio.h"
12using namespace Bu;
13
14Bu::CsvReader::CsvReader( Bu::Stream &sIn, Bu::CsvReader::Style eStyle ) :
15 sIn( sIn )
16{
17 switch( eStyle )
18 {
19 case styleExcel:
20 sDecode = Bu::slot( &decodeExcel );
21 break;
22
23 case styleC:
24 sDecode = Bu::slot( &decodeC );
25 break;
26 }
27}
28
29Bu::CsvReader::CsvReader( Bu::Stream &sIn,
30 Bu::CsvReader::DecodeSignal sDecode ) :
31 sIn( sIn ),
32 sDecode( sDecode )
33{
34}
35
36Bu::CsvReader::~CsvReader()
37{
38}
39
40Bu::StrArray Bu::CsvReader::readLine()
41{
42 Bu::StrArray aVals;
43
44 Bu::String sLine = sIn.readLine();
45
46 if( !sLine.isSet() )
47 return Bu::StrArray();
48
49 Bu::String::iterator i = sLine.begin();
50
51 aVals.append( sDecode( i ) );
52
53 while( i )
54 {
55 if( *i == ',' )
56 {
57 i++;
58 if( !i )
59 {
60 aVals.append("");
61 break;
62 }
63 aVals.append( sDecode( i ) );
64 }
65 else
66 {
67 // Blanks and stuff?
68 sio << "Out of bound: '" << *i << "'" << sio.nl;
69 i++;
70 }
71 }
72
73 return aVals;
74}
75
76Bu::String Bu::CsvReader::decodeExcel( Bu::String::iterator &i )
77{
78 Bu::String sRet;
79
80 for(; i && (*i == ' ' || *i == '\t'); i++ ) { }
81
82 if( !i )
83 return sRet;
84
85 if( *i == '\"' )
86 {
87 for( i++ ; i; i++ )
88 {
89 if( *i == '\"' )
90 {
91 i++;
92 if( !i )
93 {
94 return sRet;
95 }
96 else if( *i == '\"' )
97 {
98 sRet += *i;
99 }
100 else
101 {
102 return sRet;
103 }
104 }
105 else
106 {
107 sRet += *i;
108 }
109 }
110 }
111 else
112 {
113 for( ; i; i++ )
114 {
115 if( *i == ',' )
116 {
117 return sRet;
118 }
119 sRet += *i;
120 }
121 }
122
123 return sRet;
124}
125
126Bu::String Bu::CsvReader::decodeC( Bu::String::iterator & )
127{
128 return "";
129}
130
diff --git a/src/stable/csvreader.h b/src/stable/csvreader.h
new file mode 100644
index 0000000..2e9e7b0
--- /dev/null
+++ b/src/stable/csvreader.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_CSV_READER_H
9#define BU_CSV_READER_H
10
11#include "bu/string.h"
12#include "bu/array.h"
13#include "bu/signals.h"
14
15namespace Bu
16{
17 class Stream;
18 typedef Bu::Array<Bu::String> StrArray;
19
20 class CsvReader
21 {
22 public:
23 typedef Bu::Signal1<Bu::String, Bu::String::iterator &> DecodeSignal;
24 enum Style
25 {
26 styleExcel, ///< Excel style quotes around things that need em
27 styleC ///< Escape things that need it C-style
28 };
29
30 CsvReader( Stream &sIn, Style eStyle=styleExcel );
31 CsvReader( Stream &sIn, DecodeSignal sDecode );
32 virtual ~CsvReader();
33
34 StrArray readLine();
35
36 private:
37 Stream &sIn;
38 DecodeSignal sDecode;
39
40 static Bu::String decodeExcel( Bu::String::iterator &i );
41 static Bu::String decodeC( Bu::String::iterator &i );
42 };
43};
44
45#endif
diff --git a/src/stable/csvwriter.cpp b/src/stable/csvwriter.cpp
new file mode 100644
index 0000000..d8910aa
--- /dev/null
+++ b/src/stable/csvwriter.cpp
@@ -0,0 +1,81 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/csvwriter.h"
9#include "bu/stream.h"
10
11Bu::CsvWriter::CsvWriter( Bu::Stream &sOut, Bu::CsvWriter::Style eStyle ) :
12 sOut( sOut )
13{
14 switch( eStyle )
15 {
16 case styleExcel:
17 sEncode = Bu::slot( &encodeExcel );
18 break;
19
20 case styleC:
21 sEncode = Bu::slot( &encodeExcel );
22 break;
23 }
24}
25
26Bu::CsvWriter::CsvWriter( Bu::Stream &sOut,
27 Bu::CsvWriter::EncodeSignal sEncode ) :
28 sOut( sOut ),
29 sEncode( sEncode )
30{
31}
32
33Bu::CsvWriter::~CsvWriter()
34{
35}
36
37void Bu::CsvWriter::writeLine( const StrArray &aStrs )
38{
39 Bu::String sBuf;
40 for( StrArray::const_iterator i = aStrs.begin(); i; i++ )
41 {
42 if( i != aStrs.begin() )
43 sBuf += ",";
44 sBuf += sEncode( *i );
45 }
46 sBuf += "\n";
47
48 sOut.write( sBuf );
49}
50
51Bu::String Bu::CsvWriter::encodeExcel( const Bu::String &sIn )
52{
53 if( sIn.find('\"') || sIn.find(',') )
54 {
55 Bu::String sOut = "\"";
56 for( Bu::String::const_iterator i = sIn.begin(); i; i++ )
57 {
58 if( *i == '\"' )
59 sOut += "\"\"";
60 else
61 sOut += *i;
62 }
63 sOut += '\"';
64 return sOut;
65 }
66 return sIn;
67}
68
69Bu::String Bu::CsvWriter::encodeC( const Bu::String &sIn )
70{
71 Bu::String sOut = "";
72 for( Bu::String::const_iterator i = sIn.begin(); i; i++ )
73 {
74 if( *i == ',' )
75 sOut += "\\,";
76 else
77 sOut += *i;
78 }
79 return sOut;
80}
81
diff --git a/src/stable/csvwriter.h b/src/stable/csvwriter.h
new file mode 100644
index 0000000..4291ed5
--- /dev/null
+++ b/src/stable/csvwriter.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_CSV_WRITER_H
9#define BU_CSV_WRITER_H
10
11#include "bu/string.h"
12#include "bu/array.h"
13#include "bu/signals.h"
14
15namespace Bu
16{
17 class Stream;
18 typedef Bu::Array<Bu::String> StrArray;
19
20 class CsvWriter
21 {
22 public:
23 typedef Bu::Signal1<Bu::String, const Bu::String &> EncodeSignal;
24 enum Style
25 {
26 styleExcel, ///< Excel style quotes around things that need em
27 styleC ///< Escape things that need it C-style
28 };
29
30 CsvWriter( Stream &sOut, Style eStyle=styleExcel );
31 CsvWriter( Stream &sOut, EncodeSignal sEncode );
32 virtual ~CsvWriter();
33
34 void writeLine( const StrArray &aStrs );
35
36 private:
37 Stream &sOut;
38 EncodeSignal sEncode;
39
40 static Bu::String encodeExcel( const Bu::String &sIn );
41 static Bu::String encodeC( const Bu::String &sIn );
42 };
43};
44
45#endif
diff --git a/src/stable/deflate.cpp b/src/stable/deflate.cpp
new file mode 100644
index 0000000..704d172
--- /dev/null
+++ b/src/stable/deflate.cpp
@@ -0,0 +1,253 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/deflate.h"
9#include "bu/trace.h"
10
11#include <zlib.h>
12
13#define pState ((z_stream *)prState)
14
15using namespace Bu;
16
17Bu::Deflate::Deflate( Bu::Stream &rNext, int nCompression, Format eFmt ) :
18 Bu::Filter( rNext ),
19 prState( NULL ),
20 nCompression( nCompression ),
21 sTotalOut( 0 ),
22 eFmt( eFmt ),
23 bEos( false )
24{
25 TRACE( nCompression );
26 start();
27}
28
29Bu::Deflate::~Deflate()
30{
31 TRACE();
32 stop();
33}
34
35void Bu::Deflate::start()
36{
37 TRACE();
38 prState = new z_stream;
39 pState->zalloc = NULL;
40 pState->zfree = NULL;
41 pState->opaque = NULL;
42 pState->state = NULL;
43
44 nBufSize = 64*1024;
45 pBuf = new char[nBufSize];
46}
47
48Bu::size Bu::Deflate::stop()
49{
50 TRACE();
51 if( pState && pState->state )
52 {
53 if( bReading )
54 {
55 inflateEnd( pState );
56 delete[] pBuf;
57 pBuf = NULL;
58 delete pState;
59 prState = NULL;
60 return 0;
61 }
62 else
63 {
64 for(;;)
65 {
66 pState->next_in = NULL;
67 pState->avail_in = 0;
68 pState->avail_out = nBufSize;
69 pState->next_out = (Bytef *)pBuf;
70 int res = deflate( pState, Z_FINISH );
71 if( pState->avail_out < nBufSize )
72 {
73 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
74 }
75 if( res == Z_STREAM_END )
76 break;
77 }
78 deflateEnd( pState );
79 delete[] pBuf;
80 pBuf = NULL;
81 delete pState;
82 prState = NULL;
83 return sTotalOut;
84 }
85 }
86 return 0;
87}
88
89void Bu::Deflate::zError( int code )
90{
91 TRACE( code );
92 switch( code )
93 {
94 case Z_OK:
95 case Z_STREAM_END:
96 case Z_NEED_DICT:
97 return;
98
99 case Z_ERRNO:
100 throw ExceptionBase("Deflate: Errno - %s", pState->msg );
101
102 case Z_STREAM_ERROR:
103 throw ExceptionBase("Deflate: Stream Error - %s", pState->msg );
104
105 case Z_DATA_ERROR:
106 throw ExceptionBase("Deflate: Data Error - %s", pState->msg );
107
108 case Z_MEM_ERROR:
109 throw ExceptionBase("Deflate: Mem Error - %s", pState->msg );
110
111 case Z_BUF_ERROR:
112 throw ExceptionBase("Deflate: Buf Error - %s", pState->msg );
113
114 case Z_VERSION_ERROR:
115 throw ExceptionBase("Deflate: Version Error - %s", pState->msg );
116
117 default:
118 throw ExceptionBase("Deflate: Unknown error encountered - %s.", pState->msg );
119
120 }
121}
122
123Bu::size Bu::Deflate::read( void *pData, Bu::size nBytes )
124{
125 TRACE( pData, nBytes );
126 if( nBytes <= 0 )
127 return 0;
128 if( !pState->state )
129 {
130 bReading = true;
131 if( eFmt&AutoDetect )
132 inflateInit2( pState, 32+15 ); // Auto-detect, large window
133 else if( eFmt == Raw )
134 inflateInit2( pState, -15 ); // Raw
135 else if( eFmt == Zlib )
136 inflateInit2( pState, 15 ); // Zlib
137 else if( eFmt == Gzip )
138 inflateInit2( pState, 16+15 ); // GZip
139 else
140 throw Bu::ExceptionBase("Format mode for deflate read.");
141 pState->next_in = (Bytef *)pBuf;
142 pState->avail_in = 0;
143 }
144 if( bReading == false )
145 throw ExceptionBase("This deflate filter is in writing mode, you can't read.");
146
147 int nRead = 0;
148 int nReadTotal = pState->total_out;
149 pState->next_out = (Bytef *)pData;
150 pState->avail_out = nBytes;
151 for(;;)
152 {
153 int ret = inflate( pState, Z_NO_FLUSH );
154 nReadTotal += nRead-pState->avail_out;
155
156 if( ret == Z_STREAM_END )
157 {
158 bEos = true;
159 if( pState->avail_in > 0 )
160 {
161 if( rNext.isSeekable() )
162 {
163 rNext.seek( -pState->avail_in );
164 }
165 }
166 return nBytes-pState->avail_out;
167 }
168 if( ret != Z_BUF_ERROR )
169 zError( ret );
170
171 if( pState->avail_out )
172 {
173 if( pState->avail_in == 0 )
174 {
175 nRead = rNext.read( pBuf, nBufSize );
176 if( nRead == 0 && rNext.isEos() )
177 {
178 throw Bu::ExceptionBase("Premature end of underlying "
179 "stream found reading deflate stream.");
180 }
181 pState->next_in = (Bytef *)pBuf;
182 pState->avail_in = nRead;
183 }
184 }
185 else
186 {
187 return nBytes-pState->avail_out;
188 }
189 }
190 return 0;
191}
192
193Bu::size Bu::Deflate::write( const void *pData, Bu::size nBytes )
194{
195 TRACE( pData, nBytes );
196 if( nBytes <= 0 )
197 return 0;
198 if( !pState->state )
199 {
200 bReading = false;
201 int iFmt = eFmt&Gzip;
202 if( iFmt == Raw )
203 deflateInit2( pState, nCompression, Z_DEFLATED, -15, 9,
204 Z_DEFAULT_STRATEGY );
205 else if( iFmt == Zlib )
206 deflateInit2( pState, nCompression, Z_DEFLATED, 15, 9,
207 Z_DEFAULT_STRATEGY );
208 else if( iFmt == Gzip )
209 deflateInit2( pState, nCompression, Z_DEFLATED, 16+15, 9,
210 Z_DEFAULT_STRATEGY );
211 else
212 throw Bu::ExceptionBase("Invalid format for deflate.");
213 }
214 if( bReading == true )
215 throw ExceptionBase("This deflate filter is in reading mode, you can't write.");
216
217 pState->next_in = (Bytef *)pData;
218 pState->avail_in = nBytes;
219 for(;;)
220 {
221 pState->avail_out = nBufSize;
222 pState->next_out = (Bytef *)pBuf;
223
224 zError( deflate( pState, Z_NO_FLUSH ) );
225
226 if( pState->avail_out < nBufSize )
227 {
228 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
229 }
230 if( pState->avail_in == 0 )
231 break;
232 }
233
234 return nBytes;
235}
236
237bool Bu::Deflate::isOpen()
238{
239 TRACE();
240 return (pState != NULL && pState->state != NULL);
241}
242
243bool Bu::Deflate::isEos()
244{
245 TRACE();
246 return bEos;
247}
248
249Bu::size Bu::Deflate::getCompressedSize()
250{
251 return sTotalOut;
252}
253
diff --git a/src/stable/deflate.h b/src/stable/deflate.h
new file mode 100644
index 0000000..f835cfc
--- /dev/null
+++ b/src/stable/deflate.h
@@ -0,0 +1,66 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_DEFLATE_H
9#define BU_DEFLATE_H
10
11#include <stdint.h>
12
13#include "bu/filter.h"
14
15namespace Bu
16{
17 /**
18 * Provides Deflate (LZ77) support via zlib. This provides zlib, raw, and
19 * gzip stream types. By default it will autodetect the input type and
20 * encode into a raw deflate stream.
21 *
22 *@ingroup Streams
23 *@ingroup Compression
24 */
25 class Deflate : public Bu::Filter
26 {
27 public:
28 enum Format
29 {
30 Raw = 0x01,
31 Zlib = 0x02,
32 Gzip = 0x03,
33 AutoDetect = 0x04,
34
35 AutoRaw = 0x04|0x01,
36 AutoZlib = 0x04|0x02,
37 AutoGzip = 0x04|0x03
38 };
39
40 Deflate( Bu::Stream &rNext, int nCompression=-1, Format eFmt=AutoZlib );
41 virtual ~Deflate();
42
43 virtual void start();
44 virtual Bu::size stop();
45 virtual Bu::size read( void *pBuf, Bu::size nBytes );
46 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
47
48 virtual bool isOpen();
49 virtual bool isEos();
50
51 Bu::size getCompressedSize();
52
53 private:
54 void zError( int code );
55 void *prState;
56 bool bReading;
57 int nCompression;
58 char *pBuf;
59 uint32_t nBufSize;
60 Bu::size sTotalOut;
61 Format eFmt;
62 bool bEos;
63 };
64}
65
66#endif
diff --git a/src/stable/exceptionbase.cpp b/src/stable/exceptionbase.cpp
new file mode 100644
index 0000000..13a98db
--- /dev/null
+++ b/src/stable/exceptionbase.cpp
@@ -0,0 +1,93 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/exceptionbase.h"
9#include <stdarg.h>
10#include <string.h>
11#include <stdio.h>
12
13Bu::ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() :
14 nErrorCode( 0 ),
15 sWhat( NULL )
16{
17 va_list ap;
18
19 va_start(ap, lpFormat);
20 setWhat( lpFormat, ap );
21 va_end(ap);
22}
23
24Bu::ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() :
25 nErrorCode( nCode ),
26 sWhat( NULL )
27{
28 va_list ap;
29
30 va_start(ap, lpFormat);
31 setWhat( lpFormat, ap );
32 va_end(ap);
33}
34
35Bu::ExceptionBase::ExceptionBase( int nCode ) throw() :
36 nErrorCode( nCode ),
37 sWhat( NULL )
38{
39}
40
41Bu::ExceptionBase::ExceptionBase( const ExceptionBase &e ) throw () :
42 std::exception( e ),
43 nErrorCode( e.nErrorCode ),
44 sWhat( NULL )
45{
46 setWhat( e.sWhat );
47}
48
49Bu::ExceptionBase::~ExceptionBase() throw()
50{
51 delete[] sWhat;
52 sWhat = NULL;
53}
54
55void Bu::ExceptionBase::setWhat( const char *lpFormat, va_list &vargs )
56{
57 if( sWhat ) delete[] sWhat;
58 int nSize;
59
60 va_list vargs2;
61 va_copy( vargs2, vargs );
62 nSize = vsnprintf( NULL, 0, lpFormat, vargs2 );
63 va_end( vargs2 );
64 sWhat = new char[nSize+1];
65 vsnprintf( sWhat, nSize+1, lpFormat, vargs );
66}
67
68void Bu::ExceptionBase::setWhat( const char *lpText )
69{
70 if( sWhat ) delete[] sWhat;
71 int nSize;
72
73 nSize = strlen( lpText );
74 sWhat = new char[nSize+1];
75 strcpy( sWhat, lpText );
76}
77
78const char *Bu::ExceptionBase::what() const throw()
79{
80 return sWhat;
81}
82
83int Bu::ExceptionBase::getErrorCode()
84{
85 return nErrorCode;
86}
87
88Bu::UnsupportedException::UnsupportedException() throw() :
89 ExceptionBase( 0 )
90{
91 setWhat("An unsupperted operation was attempted.");
92}
93
diff --git a/src/stable/exceptionbase.h b/src/stable/exceptionbase.h
new file mode 100644
index 0000000..b6ad9ca
--- /dev/null
+++ b/src/stable/exceptionbase.h
@@ -0,0 +1,190 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_EXCEPTION_BASE_H
9#define BU_EXCEPTION_BASE_H
10
11#include <exception>
12#include <stdarg.h>
13
14// This shouldn't normally be defined here, I don't think it's all that portable
15// and it also changes the class interface, we should find out how much of
16// an issue that is, we could just put in an empty getBacktrace() function for
17// when you don't have support for it...
18
19namespace Bu
20{
21 /**
22 * A generalized Exception base class. This is nice for making general and
23 * flexible child classes that can create new error code classes.
24 *
25 * In order to create your own exception class use these two lines.
26 *
27 * in your header: subExceptionDecl( NewClassName );
28 *
29 * in your source: subExcpetienDef( NewClassName );
30 */
31 class ExceptionBase : public std::exception
32 {
33 public:
34 /**
35 * Construct an exception with an error code of zero, but with a
36 * description. The use of this is not reccomended most of the time,
37 * it's generally best to include an error code with the exception so
38 * your program can handle the exception in a better way.
39 * @param sFormat The format of the text. See printf for more info.
40 */
41 ExceptionBase( const char *sFormat, ... ) throw();
42
43 /**
44 *
45 * @param nCode
46 * @param sFormat
47 */
48 ExceptionBase( int nCode, const char *sFormat, ... ) throw();
49
50 /**
51 *
52 * @param nCode
53 * @return
54 */
55 ExceptionBase( int nCode=0 ) throw();
56
57 ExceptionBase( const ExceptionBase &e ) throw ();
58
59 /**
60 *
61 * @return
62 */
63 virtual ~ExceptionBase() throw();
64
65 /**
66 *
67 * @return
68 */
69 virtual const char *what() const throw();
70
71 /**
72 *
73 * @return
74 */
75 int getErrorCode();
76
77 /**
78 *
79 * @param lpFormat
80 * @param vargs
81 */
82 void setWhat( const char *lpFormat, va_list &vargs );
83
84 /**
85 *
86 * @param lpText
87 */
88 void setWhat( const char *lpText );
89
90 private:
91 int nErrorCode; /**< The code for the error that occured. */
92 char *sWhat; /**< The text string telling people what went wrong. */
93 };
94}
95
96#define subExceptionDecl( name ) \
97class name : public Bu::ExceptionBase \
98{ \
99 public: \
100 name( const char *sFormat, ... ) throw (); \
101 name( int nCode, const char *sFormat, ... ) throw(); \
102 name( int nCode=0 ) throw (); \
103 name( const name &e ) throw (); \
104};
105
106#define subExceptionDeclChild( name, parent ) \
107class name : public parent \
108{ \
109 public: \
110 name( const char *sFormat, ... ) throw (); \
111 name( int nCode, const char *sFormat, ... ) throw(); \
112 name( int nCode=0 ) throw (); \
113 name( const name &e ) throw (); \
114};
115
116#define subExceptionDeclBegin( name ) \
117class name : public Bu::ExceptionBase \
118{ \
119 public: \
120 name( const char *sFormat, ... ) throw (); \
121 name( int nCode, const char *sFormat, ... ) throw(); \
122 name( int nCode=0 ) throw (); \
123 name( const name &e ) throw ();
124
125#define subExceptionDeclEnd() \
126};
127
128#define subExceptionDef( name ) \
129name::name( const char *lpFormat, ... ) throw() : \
130 ExceptionBase( 0 ) \
131{ \
132 va_list ap; \
133 va_start( ap, lpFormat ); \
134 setWhat( lpFormat, ap ); \
135 va_end( ap ); \
136} \
137name::name( int nCode, const char *lpFormat, ... ) throw() : \
138 ExceptionBase( nCode ) \
139{ \
140 va_list ap; \
141 va_start( ap, lpFormat ); \
142 setWhat( lpFormat, ap ); \
143 va_end( ap ); \
144} \
145name::name( int nCode ) throw() : \
146 ExceptionBase( nCode ) \
147{ \
148} \
149name::name( const name &e ) throw() : \
150 ExceptionBase( e ) \
151{ \
152}
153
154#define subExceptionDefChild( name, parent ) \
155name::name( const char *lpFormat, ... ) throw() : \
156 parent( 0 ) \
157{ \
158 va_list ap; \
159 va_start( ap, lpFormat ); \
160 setWhat( lpFormat, ap ); \
161 va_end( ap ); \
162} \
163name::name( int nCode, const char *lpFormat, ... ) throw() : \
164 parent( nCode ) \
165{ \
166 va_list ap; \
167 va_start( ap, lpFormat ); \
168 setWhat( lpFormat, ap ); \
169 va_end( ap ); \
170} \
171name::name( int nCode ) throw() : \
172 parent( nCode ) \
173{ \
174} \
175name::name( const name &e ) throw() : \
176 ExceptionBase( e ) \
177{ \
178}
179
180namespace Bu
181{
182 // Exceptions that are so general they could be used anywhere go here.
183 class UnsupportedException : public Bu::ExceptionBase
184 {
185 public:
186 UnsupportedException() throw ();
187 };
188}
189
190#endif
diff --git a/src/stable/extratypes.h b/src/stable/extratypes.h
new file mode 100644
index 0000000..656cd6d
--- /dev/null
+++ b/src/stable/extratypes.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef EXTRA_TYPES_H
9#define EXTRA_TYPES_H
10
11#include "bu/config.h"
12
13#include <stdint.h>
14
15#ifndef NULL
16#define NULL 0
17#endif
18
19namespace Bu
20{
21#ifdef USE_64BIT_IO
22 typedef int64_t size;
23 typedef uint64_t usize;
24#else
25 typedef int32_t size;
26 typedef uint32_t usize;
27#endif
28};
29
30#endif
diff --git a/src/stable/file.cpp b/src/stable/file.cpp
new file mode 100644
index 0000000..8c8f540
--- /dev/null
+++ b/src/stable/file.cpp
@@ -0,0 +1,305 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/file.h"
9#include <errno.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <fcntl.h>
13#include <unistd.h>
14#include <time.h>
15
16#include "bu/config.h"
17
18namespace Bu { subExceptionDef( FileException ) }
19
20Bu::File::File( const Bu::String &sName, int iFlags ) :
21 fd( -1 ),
22 bEos( true )
23{
24#ifdef USE_64BIT_IO
25 fd = ::open64( sName.getStr(), getPosixFlags( iFlags ), 0666 );
26#else
27 fd = ::open( sName.getStr(), getPosixFlags( iFlags ), 0666 );
28#endif
29 if( fd < 0 )
30 {
31 throw Bu::FileException( errno, "%s: %s",
32 strerror(errno), sName.getStr() );
33 }
34 bEos = false;
35}
36
37Bu::File::File( int fd ) :
38 fd( fd )
39{
40 bEos = false;
41}
42
43Bu::File::~File()
44{
45 close();
46}
47
48void Bu::File::close()
49{
50 if( fd >= 0 )
51 {
52 if( ::close( fd ) )
53 {
54 throw Bu::FileException( errno, "%s",
55 strerror(errno) );
56 }
57 fd = -1;
58 bEos = true;
59 }
60}
61
62Bu::size Bu::File::read( void *pBuf, Bu::size nBytes )
63{
64 if( fd < 0 )
65 throw FileException("File not open.");
66
67 Bu::size iRead = ::read( fd, pBuf, nBytes );
68 if( iRead == 0 )
69 bEos = true;
70 else if( iRead == -1 && errno == EAGAIN )
71 return 0;
72 else if( iRead < 0 )
73 throw FileException( errno, "%s", strerror( errno ) );
74 return iRead;
75}
76
77Bu::size Bu::File::write( const void *pBuf, Bu::size nBytes )
78{
79 if( fd < 0 )
80 throw FileException("File not open.");
81
82 Bu::size iWrote = ::write( fd, pBuf, nBytes );
83 if( iWrote < 0 )
84 throw FileException( errno, "%s", strerror( errno ) );
85 return iWrote;
86}
87
88Bu::size Bu::File::tell()
89{
90 if( fd < 0 )
91 throw FileException("File not open.");
92
93 return lseek( fd, 0, SEEK_CUR );
94}
95
96void Bu::File::seek( Bu::size offset )
97{
98 if( fd < 0 )
99 throw FileException("File not open.");
100
101 lseek( fd, offset, SEEK_CUR );
102 bEos = false;
103}
104
105void Bu::File::setPos( Bu::size pos )
106{
107 if( fd < 0 )
108 throw FileException("File not open.");
109
110 lseek( fd, pos, SEEK_SET );
111 bEos = false;
112}
113
114void Bu::File::setPosEnd( Bu::size pos )
115{
116 if( fd < 0 )
117 throw FileException("File not open.");
118
119 lseek( fd, pos, SEEK_END );
120 bEos = false;
121}
122
123bool Bu::File::isEos()
124{
125 return bEos;
126}
127
128bool Bu::File::canRead()
129{
130#ifdef WIN32
131 return true;
132#else
133 int iMode = fcntl( fd, F_GETFL, 0 )&O_ACCMODE;
134 if( iMode == O_RDONLY || iMode == O_RDWR )
135 return true;
136 return false;
137#endif
138}
139
140bool Bu::File::canWrite()
141{
142#ifdef WIN32
143 return true;
144#else
145 int iMode = fcntl( fd, F_GETFL, 0 )&O_ACCMODE;
146 if( iMode == O_WRONLY || iMode == O_RDWR )
147 return true;
148 return false;
149#endif
150}
151
152bool Bu::File::isReadable()
153{
154 return true;
155}
156
157bool Bu::File::isWritable()
158{
159 return true;
160}
161
162bool Bu::File::isSeekable()
163{
164 return true;
165}
166
167bool Bu::File::isBlocking()
168{
169 return true;
170}
171
172void Bu::File::setBlocking( bool bBlocking )
173{
174#ifdef WIN32
175 fprintf(stderr, "STUB: Bu::File::setBlocking\n");
176#else
177 if( bBlocking )
178 fcntl(
179 fd,
180 F_SETFL, fcntl( fd, F_GETFL, 0 )&(~O_NONBLOCK)
181 );
182 else
183 fcntl(
184 fd,
185 F_SETFL, fcntl( fd, F_GETFL, 0 )|O_NONBLOCK
186 );
187#endif
188}
189
190Bu::File Bu::File::tempFile( Bu::String &sName )
191{
192 uint32_t iX;
193 iX = time( NULL ) + getpid();
194 int iXes;
195 for( iXes = sName.getSize()-1; iXes >= 0; iXes-- )
196 {
197 if( sName[iXes] != 'X' )
198 break;
199 }
200 iXes++;
201 if( iXes == sName.getSize() )
202 throw Bu::ExceptionBase("Invalid temporary filename template.");
203 for( int iter = 0; iter < 100; iter++ )
204 {
205 for( int j = iXes; j < sName.getSize(); j++ )
206 {
207 iX = (1103515245 * iX + 12345);
208 sName[j] = ('A'+(iX%26)) | ((iX&0x1000)?(0x20):(0));
209 }
210
211 try
212 {
213 return Bu::File( sName, Bu::File::Read|Bu::File::Write
214 |Bu::File::Create|Bu::File::Exclusive );
215 } catch(...) { }
216 }
217 throw Bu::FileException("Failed to create unique temporary file after 100"
218 " iterations.");
219}
220
221void Bu::File::setSize( Bu::size iSize )
222{
223#ifdef WIN32
224 chsize( fd, iSize );
225#else
226 ftruncate( fd, iSize );
227#endif
228}
229
230Bu::size Bu::File::getSize() const
231{
232 struct stat st;
233 fstat( fd, &st );
234 return st.st_size;
235}
236
237Bu::size Bu::File::getBlockSize() const
238{
239#ifdef WIN32
240 return 4096;
241#else
242 struct stat st;
243 fstat( fd, &st );
244 return st.st_blksize;
245#endif
246}
247
248Bu::String Bu::File::getLocation() const
249{
250 return "to be implemented";
251}
252
253#ifndef WIN32
254void Bu::File::chmod( mode_t t )
255{
256 fchmod( fd, t );
257}
258#endif
259
260void Bu::File::flush()
261{
262 // There is no flushing with direct I/O...
263 //fflush( fh );
264}
265
266bool Bu::File::isOpen()
267{
268 return (fd > -1);
269}
270
271int Bu::File::getPosixFlags( int iFlags )
272{
273 int iRet = 0;
274 switch( (iFlags&ReadWrite) )
275 {
276 // According to posix, O_RDWR is not necesarilly O_RDONLY|O_WRONLY, so
277 // lets be proper and use the right value in the right place.
278 case Read: iRet = O_RDONLY; break;
279 case Write: iRet = O_WRONLY; break;
280 case ReadWrite: iRet = O_RDWR; break;
281 default:
282 throw FileException(
283 "You must specify Read, Write, or both when opening a file.");
284 }
285
286 if( (iFlags&Create) )
287 iRet |= O_CREAT;
288 if( (iFlags&Append) )
289 iRet |= O_APPEND;
290 if( (iFlags&Truncate) )
291 iRet |= O_TRUNC;
292#ifndef WIN32
293 if( (iFlags&NonBlock) )
294 iRet |= O_NONBLOCK;
295#endif
296 if( (iFlags&Exclusive) == Exclusive )
297 iRet |= O_EXCL;
298
299#ifdef O_BINARY
300 iRet |= O_BINARY;
301#endif
302
303 return iRet;
304}
305
diff --git a/src/stable/file.h b/src/stable/file.h
new file mode 100644
index 0000000..e3225fa
--- /dev/null
+++ b/src/stable/file.h
@@ -0,0 +1,106 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_FILE_H
9#define BU_FILE_H
10
11#include <stdint.h>
12#include <sys/types.h>
13
14#include "bu/stream.h"
15#include "bu/string.h"
16#include "bu/exceptionbase.h"
17
18namespace Bu
19{
20 subExceptionDecl( FileException );
21
22 /**
23 * A file stream.
24 *@ingroup Streams
25 */
26 class File : public Bu::Stream
27 {
28 public:
29 File( const Bu::String &sName, int iFlags );
30 File( int fd );
31 virtual ~File();
32
33 virtual void close();
34 virtual Bu::size read( void *pBuf, Bu::size nBytes );
35 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
36 using Stream::write;
37
38 virtual Bu::size tell();
39 virtual void seek( Bu::size offset );
40 virtual void setPos( Bu::size pos );
41 virtual void setPosEnd( Bu::size 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 enum {
58 // Flags
59 Read = 0x01, ///< Open file for reading
60 Write = 0x02, ///< Open file for writing
61 Create = 0x04, ///< Create file if it doesn't exist
62 Truncate = 0x08, ///< Truncate file if it does exist
63 Append = 0x10, ///< Always append on every write
64 NonBlock = 0x20, ///< Open file in non-blocking mode
65 Exclusive = 0x44, ///< Create file, if it exists then fail
66
67 // Helpful mixes
68 ReadWrite = 0x03, ///< Open for reading and writing
69 WriteNew = 0x0E ///< Create a file (or truncate) for writing.
70 /// Same as Write|Create|Truncate
71 };
72
73 virtual void setSize( Bu::size iSize );
74
75 virtual size getSize() const;
76 virtual size getBlockSize() const;
77 virtual Bu::String getLocation() const;
78
79 /**
80 * Create a temp file and return its handle. The file is opened
81 * Read/Write.
82 *@param sName (Bu::String) Give in the form: "/tmp/tmpfileXXXXXXXX"
83 * It will alter your (sName) setting the 'X's to random
84 * characters.
85 *@returns (Bu::File) A file object representing your temp file.
86 */
87 static Bu::File tempFile( Bu::String &sName );
88
89#ifndef WIN32
90 /**
91 * Change the file access permissions.
92 *@param t (mode_t) The new file access permissions.
93 */
94 void chmod( mode_t t );
95#endif
96
97 private:
98 int getPosixFlags( int iFlags );
99
100 private:
101 int fd;
102 bool bEos;
103 };
104}
105
106#endif
diff --git a/src/stable/filter.cpp b/src/stable/filter.cpp
new file mode 100644
index 0000000..3fe8f0e
--- /dev/null
+++ b/src/stable/filter.cpp
@@ -0,0 +1,113 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/filter.h"
9
10Bu::Filter::Filter( Bu::Stream &rNext ) :
11 rNext( rNext )
12{
13}
14
15Bu::Filter::~Filter()
16{
17}
18
19void Bu::Filter::close()
20{
21 stop();
22 rNext.close();
23}
24
25Bu::size Bu::Filter::tell()
26{
27 return rNext.tell();
28}
29
30void Bu::Filter::seek( Bu::size offset )
31{
32 rNext.seek( offset );
33}
34
35void Bu::Filter::setPos( Bu::size pos )
36{
37 rNext.setPos( pos );
38}
39
40void Bu::Filter::setPosEnd( Bu::size pos )
41{
42 rNext.setPosEnd( pos );
43}
44
45bool Bu::Filter::isEos()
46{
47 return rNext.isEos();
48}
49
50bool Bu::Filter::isOpen()
51{
52 return rNext.isOpen();
53}
54
55bool Bu::Filter::canRead()
56{
57 return rNext.canRead();
58}
59
60bool Bu::Filter::canWrite()
61{
62 return rNext.canWrite();
63}
64
65bool Bu::Filter::isReadable()
66{
67 return rNext.isReadable();
68}
69
70bool Bu::Filter::isWritable()
71{
72 return rNext.isWritable();
73}
74
75bool Bu::Filter::isSeekable()
76{
77 return rNext.isSeekable();
78}
79
80bool Bu::Filter::isBlocking()
81{
82 return rNext.isBlocking();
83}
84
85void Bu::Filter::setBlocking( bool bBlocking )
86{
87 rNext.setBlocking( bBlocking );
88}
89
90void Bu::Filter::setSize( Bu::size )
91{
92}
93
94void Bu::Filter::flush()
95{
96 rNext.flush();
97}
98
99Bu::size Bu::Filter::getSize() const
100{
101 return rNext.getSize();
102}
103
104Bu::size Bu::Filter::getBlockSize() const
105{
106 return rNext.getBlockSize();
107}
108
109Bu::String Bu::Filter::getLocation() const
110{
111 return rNext.getLocation();
112}
113
diff --git a/src/stable/filter.h b/src/stable/filter.h
new file mode 100644
index 0000000..2c57805
--- /dev/null
+++ b/src/stable/filter.h
@@ -0,0 +1,83 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_FILTER_H
9#define BU_FILTER_H
10
11#include <stdint.h>
12
13#include "bu/stream.h"
14
15namespace Bu
16{
17 /**
18 * Data filter base class. Each data filter should contain a read and write
19 * section. Effectively, the write applies the filter, the read un-applies
20 * the filter, if possible. For example, BZip2 is a filter that compresses
21 * on write and decompresses on read. All bi-directional filters should
22 * follow: x == read( write( x ) ) (byte-for-byte comparison)
23 *
24 * Also, all returned buffers should be owned by the filter, and deleted
25 * when the filter is deleted. This means that the output of a read or
26 * write operation must be used before the next call to read or write or the
27 * data will be destroyed. Also, the internal buffer may be changed or
28 * recreated between calls, so always get a new pointer from a call to
29 * read or write.
30 *
31 * The close function can also return data, so make sure to check for it,
32 * many filters such as compression filters will buffer data until they have
33 * enough to create a compression block, in these cases the leftover data
34 * will be returned by close.
35 *@ingroup Streams
36 */
37 class Filter : public Bu::Stream
38 {
39 public:
40 Filter( Bu::Stream &rNext );
41 virtual ~Filter();
42
43 virtual void start()=0;
44 virtual Bu::size stop()=0;
45 virtual void close();
46 virtual Bu::size tell();
47 virtual void seek( Bu::size offset );
48 virtual void setPos( Bu::size pos );
49 virtual void setPosEnd( Bu::size pos );
50 virtual bool isEos();
51 virtual bool isOpen();
52
53 virtual void flush();
54
55 virtual bool canRead();
56 virtual bool canWrite();
57
58 virtual bool isReadable();
59 virtual bool isWritable();
60 virtual bool isSeekable();
61
62 virtual bool isBlocking();
63 virtual void setBlocking( bool bBlocking=true );
64
65 /**
66 * Most filters won't re-implement this, it doesn't make a lot of sense
67 * for filters, in general.
68 */
69 virtual void setSize( Bu::size iSize );
70
71 virtual size getSize() const;
72 virtual size getBlockSize() const;
73 virtual Bu::String getLocation() const;
74
75 protected:
76 Bu::Stream &rNext;
77
78 private:
79
80 };
81}
82
83#endif
diff --git a/src/stable/fmt.h b/src/stable/fmt.h
new file mode 100644
index 0000000..15d8efc
--- /dev/null
+++ b/src/stable/fmt.h
@@ -0,0 +1,92 @@
1#ifndef BU_FMT_H
2#define BU_FMT_H
3
4namespace Bu
5{
6 typedef struct Fmt
7 {
8 enum Alignment
9 {
10 Left = 0,
11 Center = 1,
12 Right = 2
13 };
14 Fmt() :
15 uMinWidth( 0 ),
16 cFillChar(' '),
17 uRadix( 10 ),
18 uAlign( Right ),
19 bPlus( false ),
20 bCaps( true ),
21 bTokenize( true )
22 {
23 }
24
25 Fmt( unsigned int uMinWidth, unsigned int uRadix=10,
26 Alignment a=Right, bool bPlus=false, bool bCaps=true,
27 char cFill=' ') :
28 uMinWidth( uMinWidth ),
29 cFillChar(cFill),
30 uRadix( uRadix ),
31 uAlign( a ),
32 bPlus( bPlus ),
33 bCaps( bCaps ),
34 bTokenize( true )
35 {
36 }
37 Fmt( unsigned int uMinWidth, Alignment a,
38 unsigned int uRadix=10, bool bPlus=false, bool bCaps=true,
39 char cFill=' ') :
40 uMinWidth( uMinWidth ),
41 cFillChar(cFill),
42 uRadix( uRadix ),
43 uAlign( a ),
44 bPlus( bPlus ),
45 bCaps( bCaps ),
46 bTokenize( true )
47 {
48 }
49
50 static Fmt hex( unsigned int uWidth=0, bool bCaps=true )
51 {
52 return Fmt( uWidth, 16, Right, false, bCaps, '0' );
53 }
54
55 static Fmt oct( unsigned int uWidth=0 )
56 {
57 return Fmt( uWidth, 8, Right, false, false, '0' );
58 }
59
60 static Fmt bin( unsigned int uWidth=0 )
61 {
62 return Fmt( uWidth, 1, Right, false, false, '0' );
63 }
64
65 static Fmt ptr( bool bCaps=true )
66 {
67 return Fmt( sizeof(ptrdiff_t)*2, 16, Right, false, bCaps, '0' );
68 }
69
70 Fmt &width( unsigned int uWidth );
71 Fmt &fill( char cFill='0' );
72 Fmt &radix( unsigned int uRadix );
73 Fmt &align( Alignment eAlign );
74 Fmt &plus( bool bPlus=true );
75 Fmt &caps( bool bCaps=true );
76 Fmt &tokenize( bool bTokenize=true );
77
78 Fmt &left();
79 Fmt &right();
80 Fmt &center();
81
82 unsigned char uMinWidth;
83 char cFillChar;
84 unsigned short uRadix : 6;
85 unsigned short uAlign : 2;
86 unsigned short bPlus : 1;
87 unsigned short bCaps : 1;
88 unsigned short bTokenize : 1;
89 } Fmt;
90};
91
92#endif
diff --git a/src/stable/formatter.cpp b/src/stable/formatter.cpp
new file mode 100644
index 0000000..f275d71
--- /dev/null
+++ b/src/stable/formatter.cpp
@@ -0,0 +1,547 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/formatter.h"
9
10#include "bu/stream.h"
11#include <string.h>
12
13template<> float Bu::tlog( float x )
14{
15 return logf( x );
16}
17
18template<> double Bu::tlog( double x )
19{
20 return log( x );
21}
22
23template<> long double Bu::tlog( long double x )
24{
25 return logl( x );
26}
27
28template<> float Bu::tfloor( float x )
29{
30 return floorf( x );
31}
32
33template<> double Bu::tfloor( double x )
34{
35 return floor( x );
36}
37
38template<> long double Bu::tfloor( long double x )
39{
40 return floorl( x );
41}
42
43template<> float Bu::tpow( float x, float y )
44{
45 return powf( x, y );
46}
47
48template<> double Bu::tpow( double x, double y )
49{
50 return pow( x, y );
51}
52
53template<> long double Bu::tpow( long double x, long double y )
54{
55 return powl( x, y );
56}
57
58Bu::Formatter::Formatter( Stream &rStream ) :
59 rStream( rStream ),
60 bTempFmt( false ),
61 uIndent( 0 ),
62 cIndent( '\t' )
63{
64}
65
66Bu::Formatter::~Formatter()
67{
68}
69
70void Bu::Formatter::write( const Bu::String &sStr )
71{
72 rStream.write( sStr );
73}
74
75void Bu::Formatter::write( const void *sStr, int iLen )
76{
77 rStream.write( sStr, iLen );
78}
79
80void Bu::Formatter::writeAligned( const Bu::String &sStr )
81{
82 int iLen = sStr.getSize();
83 if( iLen > fLast.uMinWidth )
84 {
85 write( sStr );
86 }
87 else
88 {
89 int iRem = fLast.uMinWidth - iLen;
90 switch( fLast.uAlign )
91 {
92 case Fmt::Right:
93 for( int k = 0; k < iRem; k++ )
94 write( &fLast.cFillChar, 1 );
95 write( sStr );
96 break;
97
98 case Fmt::Center:
99 {
100 int iHlf = iRem/2;
101 for( int k = 0; k < iHlf; k++ )
102 write( &fLast.cFillChar, 1 );
103 write( sStr );
104 iHlf = iRem-iHlf;;
105 for( int k = 0; k < iHlf; k++ )
106 write( &fLast.cFillChar, 1 );
107 }
108 break;
109
110 case Fmt::Left:
111 write( sStr );
112 for( int k = 0; k < iRem; k++ )
113 write( &fLast.cFillChar, 1 );
114 break;
115 }
116 }
117
118 usedFormat();
119}
120
121void Bu::Formatter::writeAligned( const char *sStr, int iLen )
122{
123 if( iLen > fLast.uMinWidth )
124 {
125 write( sStr, iLen );
126 }
127 else
128 {
129 int iRem = fLast.uMinWidth - iLen;
130 switch( fLast.uAlign )
131 {
132 case Fmt::Right:
133 for( int k = 0; k < iRem; k++ )
134 write( &fLast.cFillChar, 1 );
135 write( sStr, iLen );
136 break;
137
138 case Fmt::Center:
139 {
140 int iHlf = iRem/2;
141 for( int k = 0; k < iHlf; k++ )
142 write( &fLast.cFillChar, 1 );
143 write( sStr, iLen );
144 iHlf = iRem-iHlf;;
145 for( int k = 0; k < iHlf; k++ )
146 write( &fLast.cFillChar, 1 );
147 }
148 break;
149
150 case Fmt::Left:
151 write( sStr, iLen );
152 for( int k = 0; k < iRem; k++ )
153 write( &fLast.cFillChar, 1 );
154 break;
155 }
156 }
157
158 usedFormat();
159}
160
161void Bu::Formatter::read( void *sStr, int iLen )
162{
163 rStream.read( sStr, iLen );
164}
165
166Bu::String Bu::Formatter::readToken()
167{
168 Bu::String sRet;
169 if( fLast.bTokenize )
170 {
171 for(;;)
172 {
173 char buf;
174 int iRead = rStream.read( &buf, 1 );
175 if( iRead == 0 )
176 return sRet;
177 if( buf == ' ' || buf == '\t' || buf == '\n' || buf == '\r' )
178 continue;
179 else
180 {
181 sRet += buf;
182 break;
183 }
184 }
185 for(;;)
186 {
187 char buf;
188 int iRead = rStream.read( &buf, 1 );
189 if( iRead == 0 )
190 return sRet;
191 if( buf == ' ' || buf == '\t' || buf == '\n' || buf == '\r' )
192 return sRet;
193 else
194 sRet += buf;
195 }
196 }
197 else
198 {
199 for(;;)
200 {
201 char buf;
202 int iRead = rStream.read( &buf, 1 );
203 if( iRead == 0 )
204 return sRet;
205 else
206 sRet += buf;
207 }
208 }
209}
210
211void Bu::Formatter::incIndent()
212{
213 if( uIndent < 0xFFU )
214 uIndent++;
215}
216
217void Bu::Formatter::decIndent()
218{
219 if( uIndent > 0 )
220 uIndent--;
221}
222
223void Bu::Formatter::setIndent( uint8_t uLevel )
224{
225 uIndent = uLevel;
226}
227
228void Bu::Formatter::clearIndent()
229{
230 uIndent = 0;
231}
232
233void Bu::Formatter::setIndentChar( char cIndent )
234{
235 this->cIndent = cIndent;
236}
237
238void Bu::Formatter::doFlush()
239{
240 rStream.flush();
241}
242
243Bu::Fmt &Bu::Fmt::width( unsigned int uWidth )
244{
245 this->uMinWidth = uWidth;
246 return *this;
247}
248
249Bu::Fmt &Bu::Fmt::fill( char cFill )
250{
251 this->cFillChar = (unsigned char)cFill;
252 return *this;
253}
254
255Bu::Fmt &Bu::Fmt::radix( unsigned int uRadix )
256{
257 this->uRadix = uRadix;
258 return *this;
259}
260
261Bu::Fmt &Bu::Fmt::align( Alignment eAlign )
262{
263 this->uAlign = eAlign;
264 return *this;
265}
266
267Bu::Fmt &Bu::Fmt::left()
268{
269 this->uAlign = Fmt::Left;
270 return *this;
271}
272
273Bu::Fmt &Bu::Fmt::center()
274{
275 this->uAlign = Fmt::Center;
276 return *this;
277}
278
279Bu::Fmt &Bu::Fmt::right()
280{
281 this->uAlign = Fmt::Right;
282 return *this;
283}
284
285Bu::Fmt &Bu::Fmt::plus( bool bPlus )
286{
287 this->bPlus = bPlus;
288 return *this;
289}
290
291Bu::Fmt &Bu::Fmt::caps( bool bCaps )
292{
293 this->bCaps = bCaps;
294 return *this;
295}
296
297Bu::Fmt &Bu::Fmt::tokenize( bool bTokenize )
298{
299 this->bTokenize = bTokenize;
300 return *this;
301}
302
303Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Fmt &fmt )
304{
305 f.setTempFormat( fmt );
306 return f;
307}
308
309Bu::Formatter &Bu::operator<<( Bu::Formatter &f, Bu::Formatter::Special s )
310{
311 switch( s )
312 {
313 case Formatter::nl:
314 {
315#ifdef WIN32
316 f.write("\r\n", 2 );
317#else
318 f.write("\n", 1 );
319#endif
320 char ci = f.getIndentChar();
321 for( int j = 0; j < f.getIndent(); j++ )
322 f.write( &ci, 1 );
323 f.doFlush();
324 }
325 break;
326
327 case Formatter::flush:
328 f.doFlush();
329 break;
330 }
331 return f;
332}
333
334Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const char *sStr )
335{
336 f.writeAligned( sStr, strlen( sStr ) );
337 return f;
338}
339
340Bu::Formatter &Bu::operator<<( Bu::Formatter &f, char *sStr )
341{
342 f.writeAligned( sStr, strlen( sStr ) );
343 return f;
344}
345
346Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::String &sStr )
347{
348 f.writeAligned( sStr );
349 return f;
350}
351
352Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed char c )
353{
354 f.ifmt<signed char>( c );
355 //f.write( (char *)&c, 1 );
356 return f;
357}
358
359Bu::Formatter &Bu::operator<<( Bu::Formatter &f, char c )
360{
361 f.write( (char *)&c, 1 );
362 return f;
363}
364
365Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned char c )
366{
367 f.ufmt<unsigned char>( c );
368 //f.write( (char *)&c, 1 );
369 return f;
370}
371
372Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed short i )
373{
374 f.ifmt<signed short>( i );
375 return f;
376}
377
378Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned short i )
379{
380 f.ufmt<unsigned short>( i );
381 return f;
382}
383
384Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed int i )
385{
386 f.ifmt<signed int>( i );
387 return f;
388}
389
390Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned int i )
391{
392 f.ufmt<unsigned int>( i );
393 return f;
394}
395
396Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed long i )
397{
398 f.ifmt<signed long>( i );
399 return f;
400}
401
402Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned long i )
403{
404 f.ufmt<unsigned long>( i );
405 return f;
406}
407
408Bu::Formatter &Bu::operator<<( Bu::Formatter &f, signed long long i )
409{
410 f.ifmt<signed long long>( i );
411 return f;
412}
413
414Bu::Formatter &Bu::operator<<( Bu::Formatter &f, unsigned long long i )
415{
416 f.ufmt<unsigned long long>( i );
417 return f;
418}
419
420Bu::Formatter &Bu::operator<<( Bu::Formatter &f, float flt )
421{
422 f.ffmt<float>( flt );
423 return f;
424}
425
426Bu::Formatter &Bu::operator<<( Bu::Formatter &f, double flt )
427{
428 f.ffmt<double>( flt );
429 return f;
430}
431
432Bu::Formatter &Bu::operator<<( Bu::Formatter &f, long double flt )
433{
434 f.ffmt<long double>( flt );
435 return f;
436}
437
438Bu::Formatter &Bu::operator<<( Bu::Formatter &f, bool b )
439{
440 f.writeAligned( b?("true"):("false") );
441 return f;
442}
443
444Bu::Formatter &Bu::operator>>( Bu::Formatter &f, Bu::String &sStr )
445{
446 sStr = f.readToken();
447 return f;
448}
449
450Bu::Formatter &Bu::operator>>( Bu::Formatter &f, signed char &c )
451{
452 f.read( &c, 1 );
453 return f;
454}
455
456Bu::Formatter &Bu::operator>>( Bu::Formatter &f, char &c )
457{
458 f.read( &c, 1 );
459 return f;
460}
461
462Bu::Formatter &Bu::operator>>( Bu::Formatter &f, unsigned char &c )
463{
464 f.read( &c, 1 );
465 return f;
466}
467
468Bu::Formatter &Bu::operator>>( Bu::Formatter &f, signed short &i )
469{
470 f.iparse( i, f.readToken() );
471 return f;
472}
473
474Bu::Formatter &Bu::operator>>( Bu::Formatter &f, unsigned short &i )
475{
476 f.uparse( i, f.readToken() );
477 return f;
478}
479
480Bu::Formatter &Bu::operator>>( Bu::Formatter &f, signed int &i )
481{
482 f.iparse( i, f.readToken() );
483 return f;
484}
485
486Bu::Formatter &Bu::operator>>( Bu::Formatter &f, unsigned int &i )
487{
488 f.uparse( i, f.readToken() );
489 return f;
490}
491
492Bu::Formatter &Bu::operator>>( Bu::Formatter &f, signed long &i )
493{
494 f.iparse( i, f.readToken() );
495 return f;
496}
497
498Bu::Formatter &Bu::operator>>( Bu::Formatter &f, unsigned long &i )
499{
500 f.uparse( i, f.readToken() );
501 return f;
502}
503
504Bu::Formatter &Bu::operator>>( Bu::Formatter &f, signed long long &i )
505{
506 f.iparse( i, f.readToken() );
507 return f;
508}
509
510Bu::Formatter &Bu::operator>>( Bu::Formatter &f, unsigned long long &i )
511{
512 f.uparse( i, f.readToken() );
513 return f;
514}
515
516Bu::Formatter &Bu::operator>>( Bu::Formatter &f, float &flt )
517{
518 f.fparse( flt, f.readToken() );
519 return f;
520}
521
522Bu::Formatter &Bu::operator>>( Bu::Formatter &f, double &flt )
523{
524 f.fparse( flt, f.readToken() );
525 return f;
526}
527
528Bu::Formatter &Bu::operator>>( Bu::Formatter &f, long double &flt )
529{
530 f.fparse( flt, f.readToken() );
531 return f;
532}
533
534Bu::Formatter &Bu::operator>>( Bu::Formatter &f, bool &b )
535{
536 Bu::String sStr = f.readToken();
537 if( !sStr.isSet() )
538 return f;
539 char c = *sStr.begin();
540 if( c == 'y' || c == 'Y' || c == 't' || c == 'T' )
541 b = true;
542 else if( c == 'n' || c == 'N' || c == 'f' || c == 'F' )
543 b = false;
544
545 return f;
546}
547
diff --git a/src/stable/formatter.h b/src/stable/formatter.h
new file mode 100644
index 0000000..a440ec3
--- /dev/null
+++ b/src/stable/formatter.h
@@ -0,0 +1,303 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_FORMATTER_H
9#define BU_FORMATTER_H
10
11#include "bu/string.h"
12#include "bu/fmt.h"
13
14#include <math.h>
15
16namespace Bu
17{
18 class Stream;
19
20 template<typename t> t tlog( t x );
21 template<> float tlog( float x );
22 template<> double tlog( double x );
23 template<> long double tlog( long double x );
24
25 template<typename t> t tfloor( t x );
26 template<> float tfloor( float x );
27 template<> double tfloor( double x );
28 template<> long double tfloor( long double x );
29
30 template<typename t> t tpow( t x, t y );
31 template<> float tpow( float x, float y );
32 template<> double tpow( double x, double y );
33 template<> long double tpow( long double x, long double y );
34
35 class Formatter
36 {
37 public:
38 Formatter( Stream &rStream );
39 virtual ~Formatter();
40
41 void write( const Bu::String &sStr );
42 void write( const void *sStr, int iLen );
43 void writeAligned( const Bu::String &sStr );
44 void writeAligned( const char *sStr, int iLen );
45
46 void read( void *sStr, int iLen );
47 Bu::String readToken();
48
49 void incIndent();
50 void decIndent();
51 void setIndent( uint8_t uLevel );
52 void clearIndent();
53 uint8_t getIndent() const { return uIndent; }
54 void setIndentChar( char cIndent );
55 char getIndentChar() const { return cIndent; }
56
57 void setFormat( const Fmt &f )
58 {
59 fLast = f;
60 bTempFmt = false;
61 }
62
63 void setTempFormat( const Fmt &f )
64 {
65 fLast = f;
66 bTempFmt = true;
67 }
68
69 void usedFormat()
70 {
71 if( bTempFmt )
72 fLast = Fmt();
73 }
74
75 template<typename type>
76 void ifmt( type i )
77 {
78 // This code is taken from Nango, hopefully we can make it better.
79 bool bNeg = i<0;
80 char cBase = fLast.bCaps?'A':'a';
81 char buf[sizeof(type)*8+1];
82 if( bNeg ) i = -i;
83 if( fLast.uRadix < 2 || fLast.uRadix > 36 )
84 {
85 usedFormat();
86 return;
87 }
88
89 for( int j = sizeof(type)*8; j >= 0; j-- )
90 {
91 int c = i%fLast.uRadix;
92 i /= fLast.uRadix;
93 buf[j] = (char)((c<10)?('0'+c):(cBase+c-10));
94 if( i == 0 )
95 {
96 if( bNeg ) buf[--j] = '-';
97 else if( fLast.bPlus ) buf[--j] = '+';
98 writeAligned( buf+j, sizeof(type)*8-j+1 );
99
100 return;
101 }
102 }
103 usedFormat();
104 }
105
106 template<typename type>
107 void ufmt( type i )
108 {
109 // This code is taken from Nango, hopefully we can make it better.
110 char buf[sizeof(type)*8+1];
111 char cBase = fLast.bCaps?'A':'a';
112 if( fLast.uRadix < 2 || fLast.uRadix > 36 )
113 {
114 usedFormat();
115 return;
116 }
117
118 for( int j = sizeof(type)*8; j >= 0; j-- )
119 {
120 int c = i%fLast.uRadix;
121 i /= fLast.uRadix;
122 buf[j] = (char)((c<10)?('0'+c):(cBase+c-10));
123 if( i == 0 )
124 {
125 if( fLast.bPlus ) buf[--j] = '+';
126 writeAligned( buf+j, sizeof(type)*8-j+1 );
127
128 return;
129 }
130 }
131 usedFormat();
132 }
133
134 template<typename type>
135 void ffmt( type f )
136 {
137 Bu::String fTmp;
138 char cBase = fLast.bCaps?'A':'a';
139 if( fLast.uRadix < 2 || fLast.uRadix > 36 )
140 {
141 usedFormat();
142 return;
143 }
144
145 if( signbit(f) )
146 {
147 f = -f;
148 fTmp += "-";
149 }
150 int iScale = tfloor(tlog( f ) / tlog( (type)fLast.uRadix ));
151 f /= tpow( (type)fLast.uRadix, (type)iScale );
152
153 if( iScale < 0 )
154 {
155 fTmp += "0.";
156 for( int j = 1; j < -iScale; j++ )
157 fTmp += '0';
158 }
159 int c = f;
160 fTmp += (char)((c<10)?('0'+c):(cBase+c-10));
161 f -= (int)f;
162 int j;
163 for( j = 0; j < 8 && f; j++ )
164 {
165 if( iScale - j == 0 )
166 fTmp += '.';
167 f = f*fLast.uRadix;
168 int c = f;
169 fTmp += (char)((c<10)?('0'+c):(cBase+c-10));
170 f -= (int)f;
171 }
172 if( iScale >= j )
173 {
174 for( int k = j; k < iScale; k++ )
175 fTmp += '0';
176 fTmp += ".0";
177 }
178
179 writeAligned( fTmp );
180 usedFormat();
181 }
182
183 template<typename type>
184 void iparse( type &i, const Bu::String &sBuf )
185 {
186 if( !sBuf.isSet() )
187 return;
188 if( sBuf[0] != '+' && sBuf[0] != '-' &&
189 (sBuf[0] < '0' && sBuf[0] > '9') )
190 return;
191 int j = 1;
192 int iMax = sBuf.getSize();
193 for(; j < iMax && (sBuf[j] >= '0' && sBuf[j] <= '9'); j++ ) { }
194 i = 0;
195 type iPos = 1;
196 for(j--; j >= 0; j-- )
197 {
198 if( sBuf[j] == '+' || sBuf[j] == '-' )
199 continue;
200 i += (sBuf[j]-'0')*iPos;
201 iPos *= fLast.uRadix;
202 }
203 if( sBuf[0] == '-' )
204 i = -i;
205
206 usedFormat();
207 }
208
209 template<typename type>
210 void uparse( type &i, const Bu::String &sBuf )
211 {
212 if( !sBuf.isSet() )
213 return;
214 if( sBuf[0] != '+' &&
215 (sBuf[0] < '0' && sBuf[0] > '9') )
216 return;
217 int j = 1;
218 int iMax = sBuf.getSize();
219 for(; j < iMax && (sBuf[j] >= '0' && sBuf[j] <= '9'); j++ ) { }
220 i = 0;
221 type iPos = 1;
222 for(j--; j >= 0; j-- )
223 {
224 if( sBuf[j] == '+' )
225 continue;
226 i += (sBuf[j]-'0')*iPos;
227 iPos *= fLast.uRadix;
228 }
229
230 usedFormat();
231 }
232
233 template<typename type>
234 void fparse( type &f, const Bu::String &sBuf )
235 {
236 double fIn;
237 sscanf( sBuf.getStr(), "%lf", &fIn );
238 f = fIn;
239 usedFormat();
240 }
241
242 enum Special
243 {
244 nl,
245 flush
246 };
247
248 void doFlush();
249
250 private:
251 Stream &rStream;
252 Fmt fLast;
253 bool bTempFmt;
254 uint8_t uIndent;
255 char cIndent;
256 };
257
258 Formatter &operator<<( Formatter &f, const Fmt &fmt );
259 Formatter &operator<<( Formatter &f, Formatter::Special s );
260 Formatter &operator<<( Formatter &f, const char *sStr );
261 Formatter &operator<<( Formatter &f, char *sStr );
262 Formatter &operator<<( Formatter &f, const Bu::String &sStr );
263 Formatter &operator<<( Formatter &f, signed char c );
264 Formatter &operator<<( Formatter &f, char c );
265 Formatter &operator<<( Formatter &f, unsigned char c );
266 Formatter &operator<<( Formatter &f, signed short i );
267 Formatter &operator<<( Formatter &f, unsigned short i );
268 Formatter &operator<<( Formatter &f, signed int i );
269 Formatter &operator<<( Formatter &f, unsigned int i );
270 Formatter &operator<<( Formatter &f, signed long i );
271 Formatter &operator<<( Formatter &f, unsigned long i );
272 Formatter &operator<<( Formatter &f, signed long long i );
273 Formatter &operator<<( Formatter &f, unsigned long long i );
274 Formatter &operator<<( Formatter &f, float flt );
275 Formatter &operator<<( Formatter &f, double flt );
276 Formatter &operator<<( Formatter &f, long double flt );
277 Formatter &operator<<( Formatter &f, bool b );
278
279 Formatter &operator>>( Formatter &f, Bu::String &sStr );
280 Formatter &operator>>( Formatter &f, signed char &c );
281 Formatter &operator>>( Formatter &f, char &c );
282 Formatter &operator>>( Formatter &f, unsigned char &c );
283 Formatter &operator>>( Formatter &f, signed short &i );
284 Formatter &operator>>( Formatter &f, unsigned short &i );
285 Formatter &operator>>( Formatter &f, signed int &i );
286 Formatter &operator>>( Formatter &f, unsigned int &i );
287 Formatter &operator>>( Formatter &f, signed long &i );
288 Formatter &operator>>( Formatter &f, unsigned long &i );
289 Formatter &operator>>( Formatter &f, signed long long &i );
290 Formatter &operator>>( Formatter &f, unsigned long long &i );
291 Formatter &operator>>( Formatter &f, float &flt );
292 Formatter &operator>>( Formatter &f, double &flt );
293 Formatter &operator>>( Formatter &f, long double &flt );
294 Formatter &operator>>( Formatter &f, bool &b );
295
296 template<typename type>
297 Formatter &operator<<( Formatter &f, const type *p )
298 {
299 return f << "0x" << Fmt::hex(sizeof(ptrdiff_t)*2) << (ptrdiff_t)(p);
300 }
301};
302
303#endif
diff --git a/src/stable/formula.cpp b/src/stable/formula.cpp
new file mode 100644
index 0000000..ac435ed
--- /dev/null
+++ b/src/stable/formula.cpp
@@ -0,0 +1,14 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/formula.h"
9
10namespace Bu
11{
12 subExceptionDef( FormulaException );
13}
14
diff --git a/src/stable/formula.h b/src/stable/formula.h
new file mode 100644
index 0000000..687e6c3
--- /dev/null
+++ b/src/stable/formula.h
@@ -0,0 +1,430 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef FORMULA_H
9#define FORMULA_H
10
11#include <stdint.h>
12#include <stdlib.h>
13
14#include <math.h>
15//#include "sbuffer.h"
16
17#include "bu/stack.h"
18#include "bu/exceptionbase.h"
19#include "bu/hash.h"
20#include "bu/string.h"
21
22namespace Bu
23{
24 subExceptionDecl( FormulaException );
25 /**
26 * Implements a very simple formula parser that allows use of variables and
27 * custom functions. This is based on a simple calculator-type parser that
28 * executes as it processes, accounting for operator precedence and
29 * grouping.
30 *
31 * prec = precision, a type to use for all math (except binary ops)
32 * bin = binary type, a type to hard cast all data to for binary ops
33 */
34 template<typename prec, typename bin=uint32_t>
35 class Formula
36 {
37 public:
38 class Func
39 {
40 public:
41 virtual prec operator()( prec )=0;
42 };
43
44 typedef Hash<Bu::String, prec> varHash;
45 typedef Hash<Bu::String, Func *> funcHash;
46
47 Formula()
48 {
49 }
50
51 virtual ~Formula()
52 {
53 for( typename funcHash::iterator i = hFunc.begin();
54 i != hFunc.end(); i++ )
55 {
56 delete (*i);
57 }
58 }
59
60 prec run( const Bu::String &sFormulaSrc )
61 {
62 if( sFormulaSrc.isEmpty() )
63 throw FormulaException("Empty formula, nothing to do.");
64 try
65 {
66 const char *sFormula = sFormulaSrc.getStr();
67 for(;;)
68 {
69 uint8_t tNum = nextToken( &sFormula );
70 if( tNum == symSubtract )
71 {
72 sOper.push( symNegate );
73 continue;
74 }
75 else if( tNum == symNot )
76 {
77 sOper.push( symNot );
78 continue;
79 }
80 else if( tNum == symOpenParen )
81 {
82 sOper.push( tNum );
83 continue;
84 }
85 else if( tNum == symFunction )
86 {
87 sOper.push( symFunction );
88 continue;
89 }
90 else if( tNum == symEOS )
91 {
92 throw Bu::FormulaException(
93 "Cannot end with an operator.");
94 }
95
96 oppart: uint8_t tOpr = nextToken( &sFormula );
97 if( tOpr == symEOS )
98 {
99 reduce();
100 prec ret = sValue.top();
101 sValue.clear();
102 sFunc.clear();
103 sOper.clear();
104 return ret;
105 }
106 if( !sOper.isEmpty() && getPrec( sOper.top() ) >
107 getPrec( tOpr ) )
108 {
109 reduce();
110 }
111 if( tOpr != symCloseParen )
112 {
113 sOper.push( tOpr );
114 }
115 else
116 {
117 reduce( true );
118 goto oppart;
119 }
120 }
121 }
122 catch( ... )
123 {
124 sValue.clear();
125 sFunc.clear();
126 sOper.clear();
127 throw;
128 }
129 }
130
131 varHash hVars;
132 funcHash hFunc;
133
134 private:
135 enum
136 {
137 symEOS,
138 symAdd,
139 symSubtract,
140 symMultiply,
141 symDivide,
142 symOpenParen,
143 symCloseParen,
144 symNumber,
145 symVariable,
146 symFunction,
147 symExponent,
148 symNegate,
149 symModulus,
150
151 symAnd,
152 symOr,
153 symXor,
154 symNot
155 };
156
157 typedef uint8_t symType;
158
159 Bu::Stack<symType> sOper;
160 Bu::Stack<prec> sValue;
161 Bu::Stack<Bu::String> sFunc;
162
163 private:
164 symType getPrec( symType nOper )
165 {
166 switch( nOper )
167 {
168 case symNumber:
169 case symVariable:
170 case symOpenParen:
171 case symCloseParen:
172 return 0;
173
174 case symAdd:
175 case symSubtract:
176 return 1;
177
178 case symMultiply:
179 case symDivide:
180 case symModulus:
181 return 2;
182
183 case symAnd:
184 case symOr:
185 case symXor:
186 return 2;
187
188 case symExponent:
189 case symNot:
190 case symNegate:
191 case symFunction:
192 return 3;
193
194 default:
195 return 0;
196 }
197 }
198
199 symType nextToken( const char **sBuf )
200 {
201 for(;;)
202 {
203 char cbuf = **sBuf;
204 ++(*sBuf);
205 switch( cbuf )
206 {
207 case '+':
208 return symAdd;
209
210 case '-':
211 return symSubtract;
212
213 case '*':
214 return symMultiply;
215
216 case '/':
217 return symDivide;
218
219 case '^':
220 return symExponent;
221
222 case '%':
223 return symModulus;
224
225 case '(':
226 return symOpenParen;
227
228 case ')':
229 return symCloseParen;
230
231 case '|':
232 return symOr;
233
234 case '&':
235 return symAnd;
236
237 case '#':
238 return symXor;
239
240 case '~':
241 return symNot;
242
243 case ' ':
244 case '\t':
245 case '\n':
246 case '\r':
247 break;
248
249 case '\0':
250 return symEOS;
251
252 default:
253 if( cbuf == '.' || (cbuf >= '0' && cbuf <= '9') )
254 {
255 char num[50]={cbuf};
256 int nPos = 1;
257 bool bDot = false;
258
259 for(;;)
260 {
261 cbuf = **sBuf;
262 if( cbuf == '.' )
263 {
264 if( bDot == false )
265 bDot = true;
266 else
267 throw FormulaException(
268 "Numbers cannot have more than one "
269 ". in them."
270 );
271 }
272 if( cbuf == '.' ||
273 (cbuf >= '0' && cbuf <= '9') )
274 {
275 num[nPos++] = cbuf;
276 }
277 else
278 {
279 num[nPos] = '\0';
280 sValue.push(
281 static_cast<prec>(
282 strtod( num, NULL )
283 )
284 );
285 return symNumber;
286 }
287 ++(*sBuf);
288 }
289 }
290 else if( (cbuf >= 'a' && cbuf <= 'z') ||
291 (cbuf >= 'A' && cbuf <= 'Z') ||
292 (cbuf == '_') )
293 {
294 char tok[50]={cbuf};
295 int nPos = 1;
296
297 for(;;)
298 {
299 cbuf = **sBuf;
300 if( (cbuf >= 'a' && cbuf <= 'z') ||
301 (cbuf >= 'A' && cbuf <= 'Z') ||
302 (cbuf >= '0' && cbuf <= '9') ||
303 cbuf == '_' || cbuf == '.' || cbuf == ':' )
304 {
305 tok[nPos++] = cbuf;
306 }
307 else
308 {
309 tok[nPos] = '\0';
310 if( hVars.has( tok ) )
311 {
312 sValue.push( hVars[tok] );
313 return symNumber;
314 }
315 else if( hFunc.has( tok ) )
316 {
317 sFunc.push( tok );
318 return symFunction;
319 }
320 else
321 {
322 throw FormulaException(
323 "No variable or function named "
324 "\"%s\" exists.",
325 tok
326 );
327 }
328 }
329 ++(*sBuf);
330 }
331 }
332 break;
333 }
334 }
335 }
336
337 void reduce( bool bCloseParen = false )
338 {
339 while( !sOper.isEmpty() )
340 {
341 uint8_t nOpr = sOper.top();
342 if( nOpr == symOpenParen )
343 {
344 if( bCloseParen == true )
345 sOper.pop();
346 return;
347 }
348 sOper.pop();
349
350 prec dTop = sValue.top();
351 sValue.pop();
352
353 switch( nOpr )
354 {
355 case symAdd:
356 sValue.top() += dTop;
357 break;
358
359 case symSubtract:
360 sValue.top() -= dTop;
361 break;
362
363 case symMultiply:
364 sValue.top() *= dTop;
365 break;
366
367 case symDivide:
368 sValue.top() /= dTop;
369 break;
370
371 case symExponent:
372 sValue.top() = static_cast<prec>(
373 pow( sValue.top(), dTop )
374 );
375 break;
376
377 case symModulus:
378 sValue.top() = static_cast<prec>(
379 fmod( sValue.top(), dTop )
380 );
381 break;
382
383 case symOr:
384 sValue.top() = static_cast<prec>(
385 static_cast<bin>(sValue.top()) |
386 static_cast<bin>(dTop)
387 );
388 break;
389
390 case symAnd:
391 sValue.top() = static_cast<prec>(
392 static_cast<bin>(sValue.top()) &
393 static_cast<bin>(dTop)
394 );
395 break;
396
397 case symXor:
398 sValue.top() = static_cast<prec>(
399 static_cast<bin>(sValue.top()) ^
400 static_cast<bin>(dTop)
401 );
402 break;
403
404 case symFunction:
405 sValue.push( (*hFunc.get( sFunc.pop() ))( dTop ) );
406 break;
407
408 case symNegate:
409 sValue.push( -dTop );
410 break;
411
412 case symNot:
413 sValue.push( static_cast<prec>(
414 ~static_cast<bin>(dTop)
415 ) );
416 break;
417 }
418 }
419
420 if( bCloseParen == true )
421 {
422 throw FormulaException(
423 "Close-paren found without matching open-paren."
424 );
425 }
426 }
427 };
428}
429
430#endif
diff --git a/src/stable/hash.cpp b/src/stable/hash.cpp
new file mode 100644
index 0000000..59572ec
--- /dev/null
+++ b/src/stable/hash.cpp
@@ -0,0 +1,69 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/hash.h"
9
10namespace Bu { subExceptionDef( HashException ) }
11
12template<>
13uint32_t Bu::__calcHashCode<const char *>( const char * const &k )
14{
15 if (k == NULL)
16 {
17 return 0;
18 }
19
20 unsigned long int nPos = 0;
21 for( const char *s = k; *s; s++ )
22 {
23 nPos = *s + (nPos << 6) + (nPos << 16) - nPos;
24 }
25
26 return nPos;
27}
28
29template<> bool Bu::__cmpHashKeys<const char *>( const char * const &a, const char * const &b )
30{
31 if( a == b )
32 return true;
33
34 for(int j=0; a[j] == b[j]; j++ )
35 if( a[j] == '\0' )
36 return true;
37
38 return false;
39}
40
41template<>
42uint32_t Bu::__calcHashCode<char *>( char * const &k )
43{
44 if (k == NULL)
45 {
46 return 0;
47 }
48
49 unsigned long int nPos = 0;
50 for( const char *s = k; *s; s++ )
51 {
52 nPos = *s + (nPos << 6) + (nPos << 16) - nPos;
53 }
54
55 return nPos;
56}
57
58template<> bool Bu::__cmpHashKeys<char *>( char * const &a, char * const &b )
59{
60 if( a == b )
61 return true;
62
63 for(int j=0; a[j] == b[j]; j++ )
64 if( a[j] == '\0' )
65 return true;
66
67 return false;
68}
69
diff --git a/src/stable/hash.h b/src/stable/hash.h
new file mode 100644
index 0000000..71aec73
--- /dev/null
+++ b/src/stable/hash.h
@@ -0,0 +1,1306 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_HASH_H
9#define BU_HASH_H
10
11#include <memory>
12#include "bu/exceptionbase.h"
13#include "bu/list.h"
14#include "bu/util.h"
15#include "bu/archivebase.h"
16#include "bu/sharedcore.h"
17
18namespace Bu
19{
20 subExceptionDecl( HashException )
21
22 enum eHashException
23 {
24 excodeNotFilled
25 };
26
27 template<typename T>
28 uint32_t __calcHashCode( const T &k );
29
30 template<typename T>
31 bool __cmpHashKeys( const T &a, const T &b );
32
33 /**
34 * Default functor used to compute the size of hash tables. This version
35 * effectively doubles the size of the table when space is low, ensuring
36 * that you always wind up with an odd number for the table size. A
37 * better but slower option is to always find the next prime number that's
38 * above double your current table size, but that has the potential to be
39 * slower.
40 */
41 struct __calcNextTSize_fast
42 {
43 uint32_t operator()( uint32_t nCapacity, uint32_t nFilled,
44 uint32_t nDeleted ) const
45 {
46 // This frist case will allow hashtables that are mostly deleted
47 // items to reset to small allocations
48 if( nFilled-nDeleted <= nCapacity/4 )
49 {
50 nCapacity = 11;
51 while( nCapacity < nFilled*5/4 )
52 nCapacity = nCapacity*2+1;
53 return nCapacity;
54 }
55 // This will hopefully prevent hash tables from growing needlessly
56 if( nFilled-nDeleted <= nCapacity/2 )
57 return nCapacity;
58 // Otherwise, just increase the capacity
59 return nCapacity*2+1;
60 }
61 };
62
63 template<typename totype>
64 int bitsTo( int iCount )
65 {
66 return ( (iCount/(sizeof(totype)*8))
67 + (iCount%(sizeof(totype)*8)>0 ? 1 : 0));
68 }
69
70 template<typename key, typename value, typename sizecalc, typename keyalloc,
71 typename valuealloc, typename challoc>
72 class Hash;
73
74 /** @cond DEVEL */
75 template<typename key, typename value, typename sizecalc, typename keyalloc,
76 typename valuealloc, typename challoc >
77 class HashCore
78 {
79 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>;
80 friend class SharedCore<
81 Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>,
82 HashCore<key, value, sizecalc, keyalloc, valuealloc, challoc>
83 >;
84 private:
85 HashCore() :
86 nCapacity( 0 ),
87 nFilled( 0 ),
88 nDeleted( 0 ),
89 bFilled( NULL ),
90 bDeleted( NULL ),
91 aKeys( NULL ),
92 aValues( NULL ),
93 aHashCodes( NULL )
94 {
95 }
96
97 virtual ~HashCore()
98 {
99 clear();
100 }
101
102 void init()
103 {
104 if( nCapacity > 0 )
105 return;
106
107 nCapacity = 11;
108 nKeysSize = bitsTo<uint32_t>( nCapacity );
109 bFilled = ca.allocate( nKeysSize );
110 bDeleted = ca.allocate( nKeysSize );
111 clearBits();
112
113 aHashCodes = ca.allocate( nCapacity );
114 aKeys = ka.allocate( nCapacity );
115 aValues = va.allocate( nCapacity );
116 }
117
118 void clearBits()
119 {
120 if( nCapacity == 0 )
121 return;
122
123 for( uint32_t j = 0; j < nKeysSize; j++ )
124 {
125 bFilled[j] = bDeleted[j] = 0;
126 }
127 }
128
129 void fill( uint32_t loc, const key &k, const value &v, uint32_t hash )
130 {
131 init();
132
133 bFilled[loc/32] |= (1<<(loc%32));
134 va.construct( &aValues[loc], v );
135 ka.construct( &aKeys[loc], k );
136 aHashCodes[loc] = hash;
137 nFilled++;
138 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
139 // nFilled, nDeleted, nCapacity );
140 }
141
142 void _erase( uint32_t loc )
143 {
144 if( nCapacity == 0 )
145 return;
146
147 bDeleted[loc/32] |= (1<<(loc%32));
148 va.destroy( &aValues[loc] );
149 ka.destroy( &aKeys[loc] );
150 nDeleted++;
151 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
152 // nFilled, nDeleted, nCapacity );
153 }
154
155 key &getKeyAtPos( uint32_t nPos )
156 {
157 if( nPos >= nCapacity )
158 throw HashException("Referenced position invalid.");
159 return aKeys[nPos];
160 }
161
162 const key &getKeyAtPos( uint32_t nPos ) const
163 {
164 if( nPos >= nCapacity )
165 throw HashException("Referenced position invalid.");
166 return aKeys[nPos];
167 }
168
169 value &getValueAtPos( uint32_t nPos )
170 {
171 if( nPos >= nCapacity )
172 throw HashException("Referenced position invalid.");
173 return aValues[nPos];
174 }
175
176 const value &getValueAtPos( uint32_t nPos ) const
177 {
178 if( nPos >= nCapacity )
179 throw HashException("Referenced position invalid.");
180 return aValues[nPos];
181 }
182
183 uint32_t getFirstPos( bool &bFinished ) const
184 {
185 for( uint32_t j = 0; j < nCapacity; j++ )
186 {
187 if( isFilled( j ) )
188 if( !isDeleted( j ) )
189 return j;
190 }
191
192 bFinished = true;
193 return 0;
194 }
195
196 uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const
197 {
198 for( uint32_t j = nPos+1; j < nCapacity; j++ )
199 {
200 if( isFilled( j ) )
201 if( !isDeleted( j ) )
202 return j;
203 }
204
205 bFinished = true;
206 return 0;
207 }
208
209 uint32_t probe( uint32_t hash, const key &k, bool &bFill, bool rehash=true )
210 {
211 init();
212
213 uint32_t nCur = hash%nCapacity;
214
215 // First we scan to see if the key is already there, abort if we
216 // run out of probing room, or we find a non-filled entry
217 int8_t j;
218 for( j = 0;
219 isFilled( nCur ) && j < 32;
220 nCur = (nCur + (1<<j))%nCapacity, j++
221 )
222 {
223 // Is this the same hash code we were looking for?
224 if( hash == aHashCodes[nCur] )
225 {
226 // Skip over deleted entries. Deleted entries are also filled,
227 // so we only have to do this check here.
228 if( isDeleted( nCur ) )
229 continue;
230
231 // Is it really the same key? (for safety)
232 if( __cmpHashKeys( aKeys[nCur], k ) == true )
233 {
234 bFill = true;
235 return nCur;
236 }
237 }
238 }
239
240 // This is our insurance, if the table is full, then go ahead and
241 // rehash, then try again.
242 if( (isFilled( nCur ) || j == 32) && rehash == true )
243 {
244 reHash( szCalc( nCapacity, nFilled, nDeleted ) );
245
246 // This is potentially dangerous, and could cause an infinite loop.
247 // Be careful writing probe, eh?
248 return probe( hash, k, bFill );
249 }
250
251 bFill = false;
252 return nCur;
253 }
254
255 uint32_t probe( uint32_t hash, key k, bool &bFill ) const
256 {
257 if( nCapacity == 0 )
258 throw Bu::ExceptionBase("Probe in empty hash table.");
259
260 uint32_t nCur = hash%nCapacity;
261
262 // First we scan to see if the key is already there, abort if we
263 // run out of probing room, or we find a non-filled entry
264 for( int8_t j = 0;
265 isFilled( nCur ) && j < 32;
266 nCur = (nCur + (1<<j))%nCapacity, j++
267 )
268 {
269 // Is this the same hash code we were looking for?
270 if( hash == aHashCodes[nCur] )
271 {
272 // Skip over deleted entries. Deleted entries are also filled,
273 // so we only have to do this check here.
274 if( isDeleted( nCur ) )
275 continue;
276
277 // Is it really the same key? (for safety)
278 if( __cmpHashKeys( aKeys[nCur], k ) == true )
279 {
280 bFill = true;
281 return nCur;
282 }
283 }
284 }
285
286 bFill = false;
287 return nCur;
288 }
289
290 void insert( const key &k, const value &v )
291 {
292 uint32_t hash = __calcHashCode( k );
293 bool bFill;
294 uint32_t nPos = probe( hash, k, bFill );
295
296 if( bFill )
297 {
298 va.destroy( &aValues[nPos] );
299 va.construct( &aValues[nPos], v );
300 }
301 else
302 {
303 fill( nPos, k, v, hash );
304 }
305 }
306
307 void reHash( uint32_t nNewSize )
308 {
309 //printf("---REHASH---");
310 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
311 // nFilled, nDeleted, nCapacity );
312
313 // Save all the old data
314 uint32_t nOldCapacity = nCapacity;
315 uint32_t *bOldFilled = bFilled;
316 uint32_t *aOldHashCodes = aHashCodes;
317 uint32_t nOldKeysSize = nKeysSize;
318 uint32_t *bOldDeleted = bDeleted;
319 value *aOldValues = aValues;
320 key *aOldKeys = aKeys;
321
322 // Calculate new sizes
323 nCapacity = nNewSize;
324 nKeysSize = bitsTo<uint32_t>( nCapacity );
325
326 // Allocate new memory + prep
327 bFilled = ca.allocate( nKeysSize );
328 bDeleted = ca.allocate( nKeysSize );
329 clearBits();
330
331 aHashCodes = ca.allocate( nCapacity );
332 aKeys = ka.allocate( nCapacity );
333 aValues = va.allocate( nCapacity );
334
335 nDeleted = nFilled = 0;
336
337 // Re-insert all of the old data (except deleted items)
338 for( uint32_t j = 0; j < nOldCapacity; j++ )
339 {
340 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 &&
341 (bOldDeleted[j/32]&(1<<(j%32)))==0 )
342 {
343 insert( aOldKeys[j], aOldValues[j] );
344 }
345 }
346
347 // Delete all of the old data
348 for( uint32_t j = 0; j < nOldCapacity; j++ )
349 {
350 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 &&
351 (bOldDeleted[j/32]&(1<<(j%32)))==0 )
352 {
353 va.destroy( &aOldValues[j] );
354 ka.destroy( &aOldKeys[j] );
355 }
356 }
357 va.deallocate( aOldValues, nOldCapacity );
358 ka.deallocate( aOldKeys, nOldCapacity );
359 ca.deallocate( bOldFilled, nOldKeysSize );
360 ca.deallocate( bOldDeleted, nOldKeysSize );
361 ca.deallocate( aOldHashCodes, nOldCapacity );
362 }
363
364 bool isFilled( uint32_t loc ) const
365 {
366 if( loc >= nCapacity )
367 throw HashException("Referenced position invalid.");
368 return (bFilled[loc/32]&(1<<(loc%32)))!=0;
369 }
370
371 bool isDeleted( uint32_t loc ) const
372 {
373 if( loc >= nCapacity )
374 throw HashException("Referenced position invalid.");
375 return (bDeleted[loc/32]&(1<<(loc%32)))!=0;
376 }
377
378 void clear()
379 {
380 for( uint32_t j = 0; j < nCapacity; j++ )
381 {
382 if( isFilled( j ) )
383 if( !isDeleted( j ) )
384 {
385 va.destroy( &aValues[j] );
386 ka.destroy( &aKeys[j] );
387 }
388 }
389 va.deallocate( aValues, nCapacity );
390 ka.deallocate( aKeys, nCapacity );
391 ca.deallocate( bFilled, nKeysSize );
392 ca.deallocate( bDeleted, nKeysSize );
393 ca.deallocate( aHashCodes, nCapacity );
394
395 bFilled = NULL;
396 bDeleted = NULL;
397 aKeys = NULL;
398 aValues = NULL;
399 aHashCodes = NULL;
400
401 nCapacity = 0;
402 nFilled = 0;
403 nDeleted = 0;
404 }
405
406 uint32_t nCapacity;
407 uint32_t nFilled;
408 uint32_t nDeleted;
409 uint32_t *bFilled;
410 uint32_t *bDeleted;
411 uint32_t nKeysSize;
412 key *aKeys;
413 value *aValues;
414 uint32_t *aHashCodes;
415 valuealloc va;
416 keyalloc ka;
417 challoc ca;
418 sizecalc szCalc;
419 };
420 /** @endcond */
421
422 /**
423 * Libbu++ Template Hash Table. This is your average hash table, that uses
424 * template functions in order to do fast, efficient, generalized hashing.
425 * It's pretty easy to use, and works well with all other libbu++ types so
426 * far.
427 *
428 * In order to use it, I recommend the following for all basic usage:
429 *@code
430 // Define a Hash typedef with strings as keys and ints as values.
431 typedef Bu::Hash<Bu::String, int> StrIntHash;
432
433 // Create one
434 StrIntHash hInts;
435
436 // Insert some integers
437 hInts["one"] = 1;
438 hInts["forty-two"] = 42;
439 hInts.insert("forty two", 42 );
440
441 // Get values out of the hash, the last two options are the most explicit,
442 // and must be used if the hash's value type does not match what you're
443 // comparing to exactly.
444 if( hInts["one"] == 1 ) doSomething();
445 if( hInts["forty-two"].value() == 42 ) doSomething();
446 if( hInts.get("forty two") == 42 ) doSomething();
447
448 // Iterate through the Hash
449 for( StrIntHash::iterator i = hInts.begin(); i != hInts.end(); i++ )
450 {
451 // i.getValue() works too
452 print("'%s' = %d\n", i.getKey().getStr(), (*i) );
453 }
454
455 @endcode
456 *@param key (typename) The datatype of the hashtable keys
457 *@param value (typename) The datatype of the hashtable data
458 *@param sizecalc (typename) Functor to compute new table size on rehash
459 *@param keyalloc (typename) Memory allocator for hashtable keys
460 *@param valuealloc (typename) Memory allocator for hashtable values
461 *@param challoc (typename) Byte allocator for bitflags
462 *@ingroup Containers
463 */
464 template<typename key, typename value,
465 typename sizecalc = __calcNextTSize_fast,
466 typename keyalloc = std::allocator<key>,
467 typename valuealloc = std::allocator<value>,
468 typename challoc = std::allocator<uint32_t>
469 >
470 class Hash : public SharedCore<
471 Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>,
472 HashCore<key, value, sizecalc, keyalloc, valuealloc, challoc>
473 >
474 {
475 private:
476 typedef class HashCore<key, value, sizecalc, keyalloc, valuealloc, challoc> Core;
477 typedef class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> MyType;
478 protected:
479 using SharedCore<MyType, Core>::core;
480 using SharedCore<MyType, Core>::_hardCopy;
481 using SharedCore<MyType, Core>::_resetCore;
482 using SharedCore<MyType, Core>::_allocateCore;
483
484 public:
485 Hash()
486 {
487 }
488
489 Hash( const MyType &src ) :
490 SharedCore<MyType, Core >( src )
491 {
492 }
493
494 virtual ~Hash()
495 {
496 }
497
498 /**
499 * Get the current hash table capacity. (Changes at re-hash)
500 *@returns (uint32_t) The current capacity.
501 */
502 uint32_t getCapacity() const
503 {
504 return core->nCapacity;
505 }
506
507 /**
508 * Get the number of hash locations spoken for. (Including
509 * not-yet-cleaned-up deleted items.)
510 *@returns (uint32_t) The current fill state.
511 */
512 uint32_t getFill() const
513 {
514 return core->nFilled;
515 }
516
517 /**
518 * Get the number of items stored in the hash table.
519 *@returns (uint32_t) The number of items stored in the hash table.
520 */
521 uint32_t getSize() const
522 {
523 return core->nFilled-core->nDeleted;
524 }
525
526 bool isEmpty() const
527 {
528 return (core->nFilled-core->nDeleted) == 0;
529 }
530
531 /**
532 * Get the number of items which have been deleted, but not yet
533 * cleaned up.
534 *@returns (uint32_t) The number of deleted items.
535 */
536 uint32_t getDeleted() const
537 {
538 return core->nDeleted;
539 }
540
541 struct HashProxy
542 {
543 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>;
544 private:
545 HashProxy( MyType &h, const key *k, uint32_t nPos, uint32_t hash ) :
546 hsh( h ),
547 pKey( k ),
548 nPos( nPos ),
549 hash( hash ),
550 bFilled( false )
551 {
552 }
553
554 HashProxy( MyType &h, uint32_t nPos, value *pValue ) :
555 hsh( h ),
556 nPos( nPos ),
557 pValue( pValue ),
558 bFilled( true )
559 {
560 }
561
562 MyType &hsh;
563 const key *pKey;
564 uint32_t nPos;
565 value *pValue;
566 uint32_t hash;
567 bool bFilled;
568
569 public:
570 /**
571 * Cast operator for HashProxy.
572 *@returns (value_type &) The value the HashProxy is pointing to.
573 */
574 operator value &()
575 {
576 if( bFilled == false )
577 throw HashException(
578 excodeNotFilled,
579 "No data assosiated with that key."
580 );
581 return *pValue;
582 }
583
584 /**
585 * Direct function for retrieving a value out of the HashProxy.
586 *@returns (value_type &) The value pointed to by this HashProxy.
587 */
588 value &getValue()
589 {
590 if( bFilled == false )
591 throw HashException(
592 excodeNotFilled,
593 "No data assosiated with that key."
594 );
595 return *pValue;
596 }
597
598 /**
599 * Whether this HashProxy points to something real or not.
600 */
601 bool isFilled()
602 {
603 return bFilled;
604 }
605
606 /**
607 * Erase the data pointed to by this HashProxy.
608 */
609 void erase()
610 {
611 if( bFilled )
612 {
613 hsh.core->_erase( nPos );
614 }
615 }
616
617 /**
618 * Assign data to this point in the hash table.
619 *@param nval (value_type) the data to assign.
620 */
621 value operator=( value nval )
622 {
623 if( bFilled )
624 {
625 hsh.core->va.destroy( &hsh.core->aValues[nPos] );
626 hsh.core->va.construct( &hsh.core->aValues[nPos], nval );
627 }
628 else
629 {
630 hsh.core->fill( nPos, *pKey, nval, hash );
631 }
632
633 return nval;
634 }
635
636 /**
637 * Pointer extraction operator. Access to members of data pointed to
638 * by HashProxy.
639 *@returns (value_type *)
640 */
641 value *operator->()
642 {
643 if( bFilled == false )
644 throw HashException(
645 excodeNotFilled,
646 "No data assosiated with that key."
647 );
648 return pValue;
649 }
650 };
651
652 /**
653 * Hash table index operator
654 *@param k (key_type) Key of data to be retrieved.
655 *@returns (HashProxy) Proxy pointing to the data.
656 */
657 HashProxy operator[]( const key &k )
658 {
659 _hardCopy();
660
661 uint32_t hash = __calcHashCode( k );
662 bool bFill;
663 uint32_t nPos = core->probe( hash, k, bFill );
664
665 if( bFill )
666 {
667 return HashProxy( *this, nPos, &core->aValues[nPos] );
668 }
669 else
670 {
671 return HashProxy( *this, &k, nPos, hash );
672 }
673 }
674
675 /**
676 * Insert a value (v) under key (k) into the hash table
677 *@param k (key_type) Key to list the value under.
678 *@param v (value_type) Value to store in the hash table.
679 */
680 void insert( const key &k, const value &v )
681 {
682 _hardCopy();
683
684 core->insert( k, v );
685 }
686
687 /**
688 * Remove a value from the hash table.
689 *@param k (key_type) The data under this key will be erased.
690 */
691 void erase( const key &k )
692 {
693 _hardCopy();
694
695 uint32_t hash = __calcHashCode( k );
696 bool bFill;
697 uint32_t nPos = core->probe( hash, k, bFill );
698
699 if( bFill )
700 {
701 core->_erase( nPos );
702 }
703 }
704
705 struct iterator;
706
707 /**
708 * Remove a value from the hash pointed to from an iterator.
709 *@param i (iterator &) The data to be erased.
710 */
711 void erase( struct iterator &i )
712 {
713 if( this != i.hsh )
714 throw HashException("This iterator didn't come from this Hash.");
715
716 _hardCopy();
717
718 if( core->isFilled( i.nPos ) && !core->isDeleted( i.nPos ) )
719 {
720 core->_erase( i.nPos );
721 }
722 }
723
724 /**
725 * Remove all data from the hash table.
726 */
727 virtual void clear()
728 {
729 _resetCore();
730 }
731
732 /**
733 * Get an item of data from the hash table.
734 *@param k (key_type) Key pointing to the data to be retrieved.
735 *@returns (value_type &) The data pointed to by (k).
736 */
737 value &get( const key &k )
738 {
739 _hardCopy();
740
741 uint32_t hash = __calcHashCode( k );
742 bool bFill;
743 uint32_t nPos = core->probe( hash, k, bFill, false );
744
745 if( bFill )
746 {
747 return core->aValues[nPos];
748 }
749 else
750 {
751 throw HashException(
752 excodeNotFilled,
753 "No data assosiated with that key."
754 );
755 }
756 }
757
758 /**
759 * Get a const item of data from the hash table.
760 *@param k (key_type) Key pointing to the data to be retrieved.
761 *@returns (const value_type &) A const version of the data pointed
762 * to by (k).
763 */
764 const value &get( const key &k ) const
765 {
766 uint32_t hash = __calcHashCode( k );
767 bool bFill;
768 uint32_t nPos = core->probe( hash, k, bFill );
769
770 if( bFill )
771 {
772 return core->aValues[nPos];
773 }
774 else
775 {
776 throw HashException(
777 excodeNotFilled,
778 "No data assosiated with that key."
779 );
780 }
781 }
782
783 /**
784 * Does the hash table contain an item under key (k).
785 *@param k (key_type) The key to check.
786 *@returns (bool) Whether there was an item in the hash under key (k).
787 */
788 bool has( const key &k ) const
789 {
790 bool bFill;
791 core->probe( __calcHashCode( k ), k, bFill );
792
793 return bFill;
794 }
795
796 /**
797 * Iteration structure for iterating through the hash.
798 */
799 typedef struct iterator
800 {
801 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>;
802 private:
803 iterator( MyType *hsh ) :
804 hsh( hsh ),
805 nPos( 0 ),
806 bFinished( false )
807 {
808 nPos = hsh->core->getFirstPos( bFinished );
809 }
810
811 iterator( MyType *hsh, bool bDone ) :
812 hsh( hsh ),
813 nPos( 0 ),
814 bFinished( bDone )
815 {
816 }
817
818 MyType *hsh;
819 uint32_t nPos;
820 bool bFinished;
821
822 public:
823 iterator( const iterator &i ) :
824 hsh( i.hsh ),
825 nPos( i.nPos ),
826 bFinished( i.bFinished )
827 {
828 }
829
830 iterator() :
831 hsh( NULL ),
832 nPos( NULL ),
833 bFinished( true )
834 {
835 }
836
837 bool isValid() const
838 {
839 return !bFinished;
840 }
841
842 operator bool() const
843 {
844 return !bFinished;
845 }
846
847 /**
848 * Iterator incrementation operator. Move the iterator forward.
849 */
850 iterator operator++( int )
851 {
852 if( bFinished == false )
853 nPos = hsh->core->getNextPos( nPos, bFinished );
854
855 return *this;
856 }
857
858 /**
859 * Iterator incrementation operator. Move the iterator forward.
860 */
861 iterator operator++()
862 {
863 if( bFinished == false )
864 nPos = hsh->core->getNextPos( nPos, bFinished );
865
866 return *this;
867 }
868
869 /**
870 * Iterator equality comparison operator. Iterators the same?
871 */
872 bool operator==( const iterator &oth ) const
873 {
874 if( bFinished != oth.bFinished )
875 return false;
876 if( bFinished == true )
877 {
878 return true;
879 }
880 else
881 {
882 if( oth.nPos == nPos )
883 return true;
884 return false;
885 }
886 }
887
888 /**
889 * Iterator not equality comparison operator. Not the same?
890 */
891 bool operator!=( const iterator &oth ) const
892 {
893 return !(*this == oth );
894 }
895
896 /**
897 * Iterator assignment operator.
898 */
899 iterator operator=( const iterator &oth )
900 {
901 hsh = oth.hsh;
902 nPos = oth.nPos;
903 bFinished = oth.bFinished;
904 return *this;
905 }
906
907 /**
908 * Iterator dereference operator... err.. get the value
909 *@returns (value_type &) The value behind this iterator.
910 */
911 value &operator *()
912 {
913 hsh->_hardCopy();
914 return hsh->core->getValueAtPos( nPos );
915 }
916
917 const value &operator *() const
918 {
919 return hsh->core->getValueAtPos( nPos );
920 }
921
922 /**
923 * Get the key behind this iterator.
924 *@returns (key_type &) The key behind this iterator.
925 */
926 const key &getKey() const
927 {
928 return hsh->core->getKeyAtPos( nPos );
929 }
930
931 /**
932 * Get the value behind this iterator.
933 *@returns (value_type &) The value behind this iterator.
934 */
935 value &getValue()
936 {
937 hsh->_hardCopy();
938 return hsh->core->getValueAtPos( nPos );
939 }
940
941 /**
942 * Get the value behind this iterator.
943 *@returns (value_type &) The value behind this iterator.
944 */
945 const value &getValue() const
946 {
947 return hsh->core->getValueAtPos( nPos );
948 }
949 } iterator;
950
951 /**
952 * Iteration structure for iterating through the hash (const).
953 */
954 typedef struct const_iterator
955 {
956 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>;
957 private:
958 const_iterator( const MyType *hsh ) :
959 hsh( hsh ),
960 nPos( 0 ),
961 bFinished( false )
962 {
963 nPos = hsh->core->getFirstPos( bFinished );
964 }
965
966 const_iterator( const MyType *hsh, bool bDone ) :
967 hsh( hsh ),
968 nPos( 0 ),
969 bFinished( bDone )
970 {
971 }
972
973 const MyType *hsh;
974 uint32_t nPos;
975 bool bFinished;
976
977 public:
978 const_iterator() :
979 hsh( NULL ),
980 nPos( 0 ),
981 bFinished( true )
982 {
983 }
984
985 const_iterator( const const_iterator &src ) :
986 hsh( src.hsh ),
987 nPos( src.nPos ),
988 bFinished( src.bFinished )
989 {
990 }
991
992 const_iterator( const iterator &src ) :
993 hsh( src.hsh ),
994 nPos( src.nPos ),
995 bFinished( src.bFinished )
996 {
997 }
998
999 bool isValid() const
1000 {
1001 return !bFinished;
1002 }
1003
1004 operator bool() const
1005 {
1006 return !bFinished;
1007 }
1008
1009 /**
1010 * Iterator incrementation operator. Move the iterator forward.
1011 */
1012 const_iterator operator++( int )
1013 {
1014 if( bFinished == false )
1015 nPos = hsh->core->getNextPos( nPos, bFinished );
1016
1017 return *this;
1018 }
1019
1020 /**
1021 * Iterator incrementation operator. Move the iterator forward.
1022 */
1023 const_iterator operator++()
1024 {
1025 if( bFinished == false )
1026 nPos = hsh->core->getNextPos( nPos, bFinished );
1027
1028 return *this;
1029 }
1030
1031 /**
1032 * Iterator equality comparison operator. Iterators the same?
1033 */
1034 bool operator==( const const_iterator &oth ) const
1035 {
1036 if( bFinished != oth.bFinished )
1037 return false;
1038 if( bFinished == true )
1039 {
1040 return true;
1041 }
1042 else
1043 {
1044 if( oth.nPos == nPos )
1045 return true;
1046 return false;
1047 }
1048 }
1049
1050 /**
1051 * Iterator not equality comparison operator. Not the same?
1052 */
1053 bool operator!=( const const_iterator &oth ) const
1054 {
1055 return !(*this == oth );
1056 }
1057
1058 /**
1059 * Iterator assignment operator.
1060 */
1061 const_iterator operator=( const const_iterator &oth )
1062 {
1063 hsh = oth.hsh;
1064 nPos = oth.nPos;
1065 bFinished = oth.bFinished;
1066 return *this;
1067 }
1068
1069 /**
1070 * Iterator dereference operator... err.. get the value
1071 *@returns (value_type &) The value behind this iterator.
1072 */
1073 const value &operator *() const
1074 {
1075 return hsh->core->getValueAtPos( nPos );
1076 }
1077
1078 /**
1079 * Get the key behind this iterator.
1080 *@returns (key_type &) The key behind this iterator.
1081 */
1082 const key &getKey() const
1083 {
1084 return hsh->core->getKeyAtPos( nPos );
1085 }
1086
1087 /**
1088 * Get the value behind this iterator.
1089 *@returns (value_type &) The value behind this iterator.
1090 */
1091 const value &getValue() const
1092 {
1093 return hsh->core->getValueAtPos( nPos );
1094 }
1095 } const_iterator;
1096
1097 /**
1098 * Get an iterator pointing to the first item in the hash table.
1099 *@returns (iterator) An iterator pointing to the first item in the
1100 * hash table.
1101 */
1102 iterator begin()
1103 {
1104 return iterator( this );
1105 }
1106
1107 const_iterator begin() const
1108 {
1109 return const_iterator( this );
1110 }
1111
1112 /**
1113 * Get an iterator pointing to a point just past the last item in the
1114 * hash table.
1115 *@returns (iterator) An iterator pointing to a point just past the
1116 * last item in the hash table.
1117 */
1118 iterator end()
1119 {
1120 return iterator( this, true );
1121 }
1122
1123 const_iterator end() const
1124 {
1125 return const_iterator( this, true );
1126 }
1127
1128 /**
1129 * Get a list of all the keys in the hash table.
1130 *@returns (std::list<key_type>) The list of keys in the hash table.
1131 */
1132 Bu::List<key> getKeys() const
1133 {
1134 Bu::List<key> lKeys;
1135
1136 for( uint32_t j = 0; j < core->nCapacity; j++ )
1137 {
1138 if( core->isFilled( j ) )
1139 {
1140 if( !core->isDeleted( j ) )
1141 {
1142 lKeys.append( core->aKeys[j] );
1143 }
1144 }
1145 }
1146
1147 return lKeys;
1148 }
1149
1150 Bu::List<value> getValues() const
1151 {
1152 Bu::List<value> lValues;
1153
1154 for( uint32_t j = 0; j < core->nCapacity; j++ )
1155 {
1156 if( core->isFilled( j ) )
1157 {
1158 if( !core->isDeleted( j ) )
1159 {
1160 lValues.append( core->aValues[j] );
1161 }
1162 }
1163 }
1164
1165 return lValues;
1166 }
1167
1168 bool operator==( const MyType &rhs ) const
1169 {
1170 if( this == &rhs )
1171 return true;
1172 if( core == rhs.core )
1173 return true;
1174 if( core == NULL || rhs.core == NULL )
1175 return false;
1176 if( getSize() != rhs.getSize() )
1177 return false;
1178
1179 for( uint32_t j = 0; j < core->nCapacity; j++ )
1180 {
1181 if( core->isFilled( j ) )
1182 {
1183 if( !core->isDeleted( j ) )
1184 {
1185 // Check to see if this key is in the other hash
1186 if( rhs.has( core->aKeys[j] ) )
1187 {
1188 if( !(core->aValues[j] == rhs.get( core->aKeys[j]) ) )
1189 {
1190 return false;
1191 }
1192 }
1193 else
1194 {
1195 return false;
1196 }
1197 }
1198 }
1199 }
1200
1201 return true;
1202 }
1203
1204 bool operator!=( const MyType &rhs ) const
1205 {
1206 return !(*this == rhs);
1207 }
1208
1209 protected:
1210 virtual Core *_copyCore( Core *src )
1211 {
1212 Core *pRet = _allocateCore();
1213
1214 pRet->nFilled = 0;
1215 pRet->nDeleted = 0;
1216 pRet->nCapacity = src->nCapacity;
1217 pRet->nKeysSize = bitsTo<uint32_t>( pRet->nCapacity );
1218 pRet->bFilled = pRet->ca.allocate( pRet->nKeysSize );
1219 pRet->bDeleted = pRet->ca.allocate( pRet->nKeysSize );
1220 pRet->clearBits();
1221
1222 pRet->aHashCodes = pRet->ca.allocate( pRet->nCapacity );
1223 pRet->aKeys = pRet->ka.allocate( pRet->nCapacity );
1224 pRet->aValues = pRet->va.allocate( pRet->nCapacity );
1225
1226 for( uint32_t j = 0; j < src->nCapacity; j++ )
1227 {
1228 if( src->isFilled( j ) && !src->isDeleted( j ) )
1229 {
1230 pRet->insert( src->aKeys[j], src->aValues[j] );
1231 }
1232 }
1233
1234 return pRet;
1235 }
1236 };
1237
1238 template<typename T> uint32_t __calcHashCode( const T &k )
1239 {
1240 return static_cast<uint32_t>( k );
1241 }
1242
1243 template<typename T> bool __cmpHashKeys( const T &a, const T &b )
1244 {
1245 return (a == b);
1246 }
1247
1248 template<> uint32_t __calcHashCode<const char *>( const char * const &k );
1249 template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b );
1250
1251 template<> uint32_t __calcHashCode<char *>( char * const &k );
1252 template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b );
1253
1254 class Formatter;
1255 Formatter &operator<<( Formatter &rOut, char *sStr );
1256 Formatter &operator<<( Formatter &rOut, signed char c );
1257 template<typename key, typename value>
1258 Formatter &operator<<( Formatter &f, const Bu::Hash<key, value> &l )
1259 {
1260 f << '{';
1261 for( typename Bu::Hash<key,value>::const_iterator i = l.begin(); i; i++ )
1262 {
1263 if( i != l.begin() )
1264 f << ", ";
1265 f << i.getKey() << ": " << i.getValue();
1266 }
1267 f << '}';
1268
1269 return f;
1270 }
1271
1272 template<typename key, typename value, typename a, typename b,
1273 typename c, typename d>
1274 ArchiveBase &operator<<( ArchiveBase &ar, const Hash<key,value,a,b,c,d> &h )
1275 {
1276 long iSize = h.getSize();
1277 ar << iSize;
1278 for( typename Hash<key,value,a,b,c,d>::const_iterator i = h.begin(); i != h.end(); i++ )
1279 {
1280 ar << (i.getKey());
1281 ar << (i.getValue());
1282 }
1283
1284 return ar;
1285 }
1286
1287 template<typename key, typename value, typename a, typename b,
1288 typename c, typename d>
1289 ArchiveBase &operator>>( ArchiveBase &ar, Hash<key,value,a,b,c,d> &h )
1290 {
1291 h.clear();
1292 long nSize;
1293 ar >> nSize;
1294
1295 for( long j = 0; j < nSize; j++ )
1296 {
1297 key k; value v;
1298 ar >> k >> v;
1299 h.insert( k, v );
1300 }
1301
1302 return ar;
1303 }
1304}
1305
1306#endif
diff --git a/src/stable/heap.cpp b/src/stable/heap.cpp
new file mode 100644
index 0000000..a2ffac2
--- /dev/null
+++ b/src/stable/heap.cpp
@@ -0,0 +1,10 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/heap.h"
9
10namespace Bu { subExceptionDef( HeapException ) }
diff --git a/src/stable/heap.h b/src/stable/heap.h
new file mode 100644
index 0000000..afe8be6
--- /dev/null
+++ b/src/stable/heap.h
@@ -0,0 +1,612 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_HEAP_H
9#define BU_HEAP_H
10
11#include <stddef.h>
12#include <memory>
13#include "bu/exceptionbase.h"
14#include "bu/util.h"
15#include "bu/queue.h"
16#include "bu/sharedcore.h"
17
18namespace Bu
19{
20 subExceptionDecl( HeapException );
21
22 template<typename item, typename cmpfunc, typename itemalloc>
23 class Heap;
24
25 /** @cond DEVEL */
26 template<typename item, typename cmpfunc, typename itemalloc>
27 class HeapCore
28 {
29 friend class Heap<item, cmpfunc, itemalloc>;
30 friend class SharedCore<
31 Heap<item, cmpfunc, itemalloc>, HeapCore<item, cmpfunc, itemalloc>
32 >;
33 private:
34 HeapCore() :
35 iSize( 0 ),
36 iFill( 0 ),
37 aItem( NULL )
38 {
39 }
40
41 virtual ~HeapCore()
42 {
43 clear();
44 }
45
46 void init()
47 {
48 if( iSize > 0 )
49 return;
50
51 iSize = 7;
52 iFill = 0;
53 aItem = ia.allocate( iSize );
54 }
55
56 void init( int iCap )
57 {
58 if( iSize > 0 )
59 return;
60
61 for( iSize = 1; iSize < iCap; iSize=iSize*2+1 ) { }
62 iFill = 0;
63 aItem = ia.allocate( iSize );
64 }
65
66 void clear()
67 {
68 if( iSize == 0 )
69 return;
70
71 for( int j = 0; j < iFill; j++ )
72 ia.destroy( &aItem[j] );
73 ia.deallocate( aItem, iSize );
74 aItem = NULL;
75 iSize = 0;
76 iFill = 0;
77 }
78
79 void upSize()
80 {
81 if( iSize == 0 )
82 {
83 init();
84 return;
85 }
86
87 item *aNewItems = ia.allocate( iSize*2+1 );
88 //
89 // We cannot use a memcopy here because we don't know what kind
90 // of datastructures are being used, we have to copy them one at
91 // a time.
92 //
93 for( int j = 0; j < iFill; j++ )
94 {
95 ia.construct( &aNewItems[j], aItem[j] );
96 ia.destroy( &aItem[j] );
97 }
98 ia.deallocate( aItem, iSize );
99 aItem = aNewItems;
100 iSize = iSize*2+1;
101 }
102
103 virtual void enqueue( const item &it )
104 {
105 item i = it; // TODO: This is a silly workaround, put the i item
106 // at the end.
107 if( iFill+1 >= iSize )
108 upSize();
109
110 for( int j = 0; j < iFill; )
111 {
112 if( cmp( i, aItem[j] ) )
113 {
114 Bu::swap( i, aItem[j] );
115 }
116
117 if( j*2+1 >= iFill )
118 break;
119 if( cmp( i, aItem[j*2+1] ) )
120 {
121 j = j*2+1;
122 }
123 else
124 {
125 j = j*2+2;
126 }
127 }
128 ia.construct( &aItem[iFill], i );
129 if( iFill > 0 )
130 {
131 for( int j = iFill; j >= 0; )
132 {
133 int k = (j-1)/2;
134 if( j == k )
135 break;
136 if( cmp( aItem[k], aItem[j] ) )
137 break;
138
139 Bu::swap( aItem[k], aItem[j] );
140 j = k;
141 }
142 }
143 iFill++;
144 }
145
146 virtual item dequeue()
147 {
148 if( iFill == 0 )
149 throw HeapException("Heap empty.");
150 item iRet = aItem[0];
151 int j;
152 for( j = 0; j < iFill; )
153 {
154 int k = j*2+1;
155 if( k+1 < iFill && cmp( aItem[k+1], aItem[k] ) )
156 {
157 if( k+1 < iFill-1 && cmp( aItem[iFill-1], aItem[k+1] ) )
158 break;
159 aItem[j] = aItem[k+1];
160 j = k+1;
161 }
162 else if( k < iFill )
163 {
164 if( k < iFill-1 && cmp( aItem[iFill-1], aItem[k] ) )
165 break;
166 aItem[j] = aItem[k];
167 j = k;
168 }
169 else
170 break;
171 }
172 if( j < iFill-1 )
173 aItem[j] = aItem[iFill-1];
174 ia.destroy( &aItem[iFill-1] );
175 iFill--;
176
177 return iRet;
178 }
179
180 private:
181 int iSize;
182 int iFill;
183 item *aItem;
184 cmpfunc cmp;
185 itemalloc ia;
186 };
187 /** @endcond */
188
189 /**
190 * A priority queue that allows for an unlimited number of priorities. All
191 * objects enqueued must support less-than-comparison. Then every time an
192 * item is dequeued it is always the least item in the heap. The heap
193 * operates using a binary tree for storage, which allows most operations
194 * to be very fast. Enqueueing and dequeueing are both O(log(N)) operatoins
195 * whereas peeking is constant time.
196 *
197 * This heap implementation allows iterating, however please note that any
198 * enqueue or dequeue operation will invalidate the iterator and make it
199 * unusable (if it still works, you shouldn't trust the results). Also,
200 * the items are not stored in memory in order, they are optomized into a
201 * tree. This means that the items will be in effectively random order
202 * while iterating through them, and the order cannot be trusted. Also,
203 * modifying an item in the heap will not cause that item to be re-sorted.
204 * If you want to change the position of an item in the heap you will have
205 * to dequeue every item before it, dequeue that item, change it, and
206 * re-enqueue all of the items removed.
207 */
208 template<typename item, typename cmpfunc=__basicLTCmp<item>, typename itemalloc=std::allocator<item> >
209 class Heap : public Queue<item>, public SharedCore<
210 Heap<item, cmpfunc, itemalloc>,
211 HeapCore<item, cmpfunc, itemalloc>
212 >
213 {
214 private:
215 typedef class Heap<item,cmpfunc,itemalloc> MyType;
216 typedef class HeapCore<item,cmpfunc,itemalloc> Core;
217
218 protected:
219 using SharedCore<MyType, Core>::core;
220 using SharedCore<MyType, Core>::_hardCopy;
221 using SharedCore<MyType, Core>::_resetCore;
222 using SharedCore<MyType, Core>::_allocateCore;
223
224 public:
225 Heap()
226 {
227 }
228
229 Heap( cmpfunc cmpin )
230 {
231 core->cmp = cmpin;
232 }
233
234 Heap( int iInitialCapacity )
235 {
236 core->init( iInitialCapacity );
237 }
238
239 Heap( cmpfunc cmpin, int iInitialCapacity )
240 {
241 core->cmp = cmpin;
242 core->init( iInitialCapacity );
243 }
244
245 Heap( const MyType &rSrc ) :
246 SharedCore<MyType, Core>( rSrc )
247 {
248 }
249
250 virtual ~Heap()
251 {
252 }
253
254 virtual void enqueue( const item &it )
255 {
256 _hardCopy();
257
258 core->enqueue( it );
259 }
260
261 virtual item &peek()
262 {
263 _hardCopy();
264
265 if( core->iFill == 0 )
266 throw HeapException("Heap empty.");
267 return core->aItem[0];
268 }
269
270 virtual const item &peek() const
271 {
272 if( core->iFill == 0 )
273 throw HeapException("Heap empty.");
274 return core->aItem[0];
275 }
276
277 virtual item dequeue()
278 {
279 _hardCopy();
280
281 return core->dequeue();
282 }
283
284 virtual bool isEmpty() const
285 {
286 return (core->iFill==0);
287 }
288
289 virtual int getSize() const
290 {
291 return core->iFill;
292 }
293
294 class iterator
295 {
296 friend class const_iterator;
297 friend class Heap<item, cmpfunc, itemalloc>;
298 private:
299 Heap<item, cmpfunc, itemalloc> *pHeap;
300 int iIndex;
301
302 iterator( Heap<item, cmpfunc, itemalloc> *pHeap, int iIndex ) :
303 pHeap( pHeap ), iIndex( iIndex )
304 {
305 }
306
307 void checkValid()
308 {
309 if( pHeap == NULL )
310 throw Bu::ExceptionBase("Iterator not initialized.");
311 if( iIndex < 0 || iIndex >= pHeap->core->iFill )
312 throw Bu::ExceptionBase("Iterator out of bounds.");
313 }
314
315 public:
316 iterator() :
317 pHeap( NULL ),
318 iIndex( -1 )
319 {
320 }
321
322 iterator( const iterator &i ) :
323 pHeap( i.pHeap ),
324 iIndex( i.iIndex )
325 {
326 }
327
328 bool operator==( const iterator &oth ) const
329 {
330 return (oth.pHeap == pHeap) && (oth.iIndex == iIndex);
331 }
332
333 bool operator!=( const iterator &oth ) const
334 {
335 return (oth.pHeap != pHeap) || (oth.iIndex != iIndex);
336 }
337
338 item &operator*()
339 {
340 pHeap->_hardCopy();
341
342 return pHeap->core->aItem[iIndex];
343 }
344
345 item *operator->()
346 {
347 pHeap->_hardCopy();
348
349 return &(pHeap->core->aItem[iIndex]);
350 }
351
352 iterator &operator++()
353 {
354 checkValid();
355 iIndex++;
356 if( iIndex >= pHeap->iFill )
357 iIndex = -1;
358
359 return *this;
360 }
361
362 iterator &operator--()
363 {
364 checkValid();
365 iIndex--;
366
367 return *this;
368 }
369
370 iterator &operator++( int )
371 {
372 checkValid();
373 iIndex++;
374 if( iIndex >= pHeap->core->iFill )
375 iIndex = -1;
376
377 return *this;
378 }
379
380 iterator &operator--( int )
381 {
382 checkValid();
383 iIndex--;
384
385 return *this;
386 }
387
388 iterator operator+( int iDelta )
389 {
390 checkValid();
391 iterator ret( *this );
392 ret.iIndex += iDelta;
393 if( ret.iIndex >= pHeap->core->iFill )
394 ret.iIndex = -1;
395 return ret;
396 }
397
398 iterator operator-( int iDelta )
399 {
400 checkValid();
401 iterator ret( *this );
402 ret.iIndex -= iDelta;
403 if( ret.iIndex < 0 )
404 ret.iIndex = -1;
405 return ret;
406 }
407
408 operator bool() const
409 {
410 return iIndex != -1;
411 }
412
413 bool isValid() const
414 {
415 return iIndex != -1;
416 }
417
418 iterator &operator=( const iterator &oth )
419 {
420 pHeap = oth.pHeap;
421 iIndex = oth.iIndex;
422 }
423 };
424
425 class const_iterator
426 {
427 friend class Heap<item, cmpfunc, itemalloc>;
428 private:
429 Heap<item, cmpfunc, itemalloc> *pHeap;
430 int iIndex;
431
432 const_iterator( Heap<item, cmpfunc, itemalloc> *pHeap,
433 int iIndex ) :
434 pHeap( pHeap ), iIndex( iIndex )
435 {
436 }
437
438 void checkValid()
439 {
440 if( pHeap == NULL )
441 throw Bu::ExceptionBase("Iterator not initialized.");
442 if( iIndex < 0 || iIndex >= pHeap->core->iFill )
443 throw Bu::ExceptionBase("Iterator out of bounds.");
444 }
445
446 public:
447 const_iterator() :
448 pHeap( NULL ),
449 iIndex( -1 )
450 {
451 }
452
453 const_iterator( const const_iterator &i ) :
454 pHeap( i.pHeap ),
455 iIndex( i.iIndex )
456 {
457 }
458
459 const_iterator( const iterator &i ) :
460 pHeap( i.pHeap ),
461 iIndex( i.iIndex )
462 {
463 }
464
465 bool operator==( const const_iterator &oth ) const
466 {
467 return (oth.pHeap == pHeap) && (oth.iIndex == iIndex);
468 }
469
470 bool operator!=( const const_iterator &oth ) const
471 {
472 return (oth.pHeap != pHeap) || (oth.iIndex != iIndex);
473 }
474
475 const item &operator*()
476 {
477 pHeap->_hardCopy();
478
479 return pHeap->core->aItem[iIndex];
480 }
481
482 const item *operator->()
483 {
484 pHeap->_hardCopy();
485
486 return &(pHeap->core->aItem[iIndex]);
487 }
488
489 const_iterator &operator++()
490 {
491 checkValid();
492 iIndex++;
493 if( iIndex >= pHeap->core->iFill )
494 iIndex = -1;
495
496 return *this;
497 }
498
499 const_iterator &operator--()
500 {
501 checkValid();
502 iIndex--;
503
504 return *this;
505 }
506
507 const_iterator &operator++( int )
508 {
509 checkValid();
510 iIndex++;
511 if( iIndex >= pHeap->core->iFill )
512 iIndex = -1;
513
514 return *this;
515 }
516
517 const_iterator &operator--( int )
518 {
519 checkValid();
520 iIndex--;
521
522 return *this;
523 }
524
525 const_iterator operator+( int iDelta )
526 {
527 checkValid();
528 const_iterator ret( *this );
529 ret.iIndex += iDelta;
530 if( ret.iIndex >= pHeap->iFill )
531 ret.iIndex = -1;
532 return ret;
533 }
534
535 const_iterator operator-( int iDelta )
536 {
537 checkValid();
538 const_iterator ret( *this );
539 ret.iIndex -= iDelta;
540 if( ret.iIndex < 0 )
541 ret.iIndex = -1;
542 return ret;
543 }
544
545 operator bool() const
546 {
547 return iIndex != -1;
548 }
549
550 bool isValid() const
551 {
552 return iIndex != -1;
553 }
554
555 const_iterator &operator=( const const_iterator &oth )
556 {
557 pHeap = oth.pHeap;
558 iIndex = oth.iIndex;
559 }
560
561 const_iterator &operator=( const iterator &oth )
562 {
563 pHeap = oth.pHeap;
564 iIndex = oth.iIndex;
565 }
566 };
567
568 iterator begin()
569 {
570 if( core->iFill == 0 )
571 return end();
572 return iterator( this, 0 );
573 }
574
575 const_iterator begin() const
576 {
577 if( core->iFill == 0 )
578 return end();
579 return const_iterator( this, 0 );
580 }
581
582 iterator end()
583 {
584 return iterator( this, -1 );
585 }
586
587 const_iterator end() const
588 {
589 return const_iterator( this, -1 );
590 }
591
592
593 protected:
594 virtual Core *_copyCore( Core *src )
595 {
596 Core *pRet = _allocateCore();
597
598 pRet->iSize = src->iSize;
599 pRet->iFill = src->iFill;
600 pRet->cmp = src->cmp;
601 pRet->aItem = pRet->ia.allocate( pRet->iSize );
602 for( int j = 0; j < pRet->iFill; j++ )
603 {
604 pRet->ia.construct( &pRet->aItem[j], src->aItem[j] );
605 }
606
607 return pRet;
608 }
609 };
610};
611
612#endif
diff --git a/src/stable/hex.cpp b/src/stable/hex.cpp
new file mode 100644
index 0000000..2a04c6f
--- /dev/null
+++ b/src/stable/hex.cpp
@@ -0,0 +1,69 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/hex.h"
9
10Bu::Hex::Hex( Bu::Stream &rNext, bool bUpperCase, int iChunk ) :
11 Bu::Filter( rNext ),
12 iChunk( iChunk ),
13 iPos( 0 ),
14 iIn( 0 ),
15 sChrs(bUpperCase?"0123456789ABCDEF":"0123456789abcdef")
16{
17}
18
19Bu::Hex::~Hex()
20{
21}
22
23void Bu::Hex::start()
24{
25 iPos = iIn = 0;
26}
27
28Bu::size Bu::Hex::stop()
29{
30 return iPos;
31}
32
33Bu::size Bu::Hex::read( void *pBuf, Bu::size iBytes )
34{
35 Bu::size j;
36 uint8_t *puBuf = (uint8_t *)pBuf;
37 for( j = 0; j < iBytes; j++ )
38 {
39 for(; iIn < 2; iIn++ )
40 {
41 if( rNext.read( &cIn[iIn], 1 ) == 0 )
42 return j;
43 if( cIn[iIn] == ' ' || cIn[iIn] == '\t' ||
44 cIn[iIn] == '\n' || cIn[iIn] == '\r' )
45 iIn--;
46 }
47#define chr2nibble( c ) ((c>='0'&&c<='9')?(c-'0'):((c|0x60)-'a'+10))
48 puBuf[j] = ((chr2nibble(cIn[0])<<4)|chr2nibble(cIn[1]));
49 iIn = 0;
50 }
51 return j;
52}
53
54Bu::size Bu::Hex::write( const void *pBuf, Bu::size iBytes )
55{
56 char cOut[2];
57 uint8_t *puBuf = (uint8_t *)pBuf;
58 for( Bu::size j = 0; j < iBytes; j++ )
59 {
60 cOut[0] = sChrs[(puBuf[j]&0xf0)>>4];
61 cOut[1] = sChrs[(puBuf[j]&0x0f)];
62 if( iChunk > 0 && iPos%iChunk == 0 && iPos>0 )
63 rNext.write(" ", 1 );
64 rNext.write( cOut, 2 );
65 iPos++;
66 }
67 return iBytes;
68}
69
diff --git a/src/stable/hex.h b/src/stable/hex.h
new file mode 100644
index 0000000..3595fae
--- /dev/null
+++ b/src/stable/hex.h
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_HEX_H
9#define BU_HEX_H
10
11#include "bu/filter.h"
12
13namespace Bu
14{
15 /**
16 * This very simple filter encodes to/decodes from hex encoded string data.
17 * The primary use of this filter is in debugging, use it with
18 * Bu::encodeStr to easily create hex dumps of string data, even other raw
19 * structures.
20 *
21 *@code
22 Bu::println("Hexdump: " + Bu::encodeStr<Bu::Hex>("Test data ;)") );
23 @endcode
24 * Or...
25 *@code
26 complex_struct data;
27 ...
28 Bu::println("Hexdump: " +
29 Bu::encodeStr<Bu::Hex>(
30 Bu::String( &data, sizeof(data) )
31 )
32 );
33 @endcode
34 **/
35 class Hex : public Bu::Filter
36 {
37 public:
38 Hex( Bu::Stream &rNext, bool bUpperCase=false, int iChunk=-1 );
39 virtual ~Hex();
40
41 virtual void start();
42 virtual Bu::size stop();
43
44 virtual Bu::size read( void *pBuf, Bu::size iBytes );
45 virtual Bu::size write( const void *pBuf, Bu::size iBytes );
46 using Bu::Stream::write;
47
48 private:
49 int iChunk;
50 Bu::size iPos;
51 char cIn[2];
52 int iIn;
53 const char *sChrs;
54 };
55};
56
57#endif
diff --git a/src/stable/list.cpp b/src/stable/list.cpp
new file mode 100644
index 0000000..e05765e
--- /dev/null
+++ b/src/stable/list.cpp
@@ -0,0 +1,9 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/list.h"
9
diff --git a/src/stable/list.h b/src/stable/list.h
new file mode 100644
index 0000000..21ba0b5
--- /dev/null
+++ b/src/stable/list.h
@@ -0,0 +1,1014 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_LIST_H
9#define BU_LIST_H
10
11#include <memory>
12#include "bu/exceptionbase.h"
13#include "bu/sharedcore.h"
14#include "bu/archivebase.h"
15#include "bu/heap.h"
16
17namespace Bu
18{
19 /** @cond DEVEL */
20 template<typename value>
21 struct ListLink
22 {
23 value *pValue;
24 ListLink *pNext;
25 ListLink *pPrev;
26 };
27
28 template<typename value, typename valuealloc, typename linkalloc>
29 class List;
30
31 template<typename value, typename valuealloc, typename linkalloc>
32 struct ListCore
33 {
34 friend class List<value, valuealloc, linkalloc>;
35 friend class SharedCore<
36 List<value, valuealloc, linkalloc>,
37 ListCore<value, valuealloc, linkalloc>
38 >;
39 private:
40 typedef struct ListLink<value> Link;
41 ListCore() :
42 pFirst( NULL ),
43 pLast( NULL ),
44 nSize( 0 )
45 { }
46
47 virtual ~ListCore()
48 {
49 clear();
50 }
51
52 Link *pFirst;
53 Link *pLast;
54 long nSize;
55 linkalloc la;
56 valuealloc va;
57
58 /**
59 * Append a value to the list.
60 *@param v (const value_type &) The value to append.
61 */
62 Link *append( const value &v )
63 {
64 Link *pNew = la.allocate( 1 );
65 pNew->pValue = va.allocate( 1 );
66 va.construct( pNew->pValue, v );
67 nSize++;
68 if( pFirst == NULL )
69 {
70 // Empty list
71 pFirst = pLast = pNew;
72 pNew->pNext = pNew->pPrev = NULL;
73 }
74 else
75 {
76 pNew->pNext = NULL;
77 pNew->pPrev = pLast;
78 pLast->pNext = pNew;
79 pLast = pNew;
80 }
81 return pNew;
82 }
83
84 /**
85 * Prepend a value to the list.
86 *@param v (const value_type &) The value to prepend.
87 */
88 Link *prepend( const value &v )
89 {
90 Link *pNew = la.allocate( 1 );
91 pNew->pValue = va.allocate( 1 );
92 va.construct( pNew->pValue, v );
93 nSize++;
94 if( pFirst == NULL )
95 {
96 // Empty list
97 pFirst = pLast = pNew;
98 pNew->pNext = pNew->pPrev = NULL;
99 }
100 else
101 {
102 pNew->pNext = pFirst;
103 pNew->pPrev = NULL;
104 pFirst->pPrev = pNew;
105 pFirst = pNew;
106 }
107 return pNew;
108 }
109
110 void clear()
111 {
112 Link *pCur = pFirst;
113 for(;;)
114 {
115 if( pCur == NULL ) break;
116 va.destroy( pCur->pValue );
117 va.deallocate( pCur->pValue, 1 );
118 Link *pTmp = pCur->pNext;
119 la.destroy( pCur );
120 la.deallocate( pCur, 1 );
121 pCur = pTmp;
122 }
123 pFirst = pLast = NULL;
124 nSize = 0;
125 }
126
127 Link *insert( Link *pLink, const value &v )
128 {
129 Link *pAfter = pLink;
130 if( pAfter == NULL )
131 {
132 return append( v );
133 }
134 Link *pPrev = pAfter->pPrev;
135 if( pPrev == NULL )
136 {
137 return prepend( v );
138 }
139
140 Link *pNew = la.allocate( 1 );
141 pNew->pValue = va.allocate( 1 );
142 va.construct( pNew->pValue, v );
143 nSize++;
144
145 pNew->pNext = pAfter;
146 pNew->pPrev = pPrev;
147 pAfter->pPrev = pNew;
148 pPrev->pNext = pNew;
149
150 return pNew;
151 }
152
153 /**
154 * Erase an item from the list.
155 *@param i (iterator) The item to erase.
156 */
157 void erase( Link *pLink )
158 {
159 Link *pCur = pLink;
160 if( pCur == NULL ) return;
161 Link *pPrev = pCur->pPrev;
162 if( pPrev == NULL )
163 {
164 va.destroy( pCur->pValue );
165 va.deallocate( pCur->pValue, 1 );
166 pFirst = pCur->pNext;
167 la.destroy( pCur );
168 la.deallocate( pCur, 1 );
169 if( pFirst == NULL )
170 pLast = NULL;
171 else
172 pFirst->pPrev = NULL;
173 nSize--;
174 }
175 else
176 {
177 va.destroy( pCur->pValue );
178 va.deallocate( pCur->pValue, 1 );
179 Link *pTmp = pCur->pNext;
180 la.destroy( pCur );
181 la.deallocate( pCur, 1 );
182 pPrev->pNext = pTmp;
183 if( pTmp != NULL )
184 pTmp->pPrev = pPrev;
185 else
186 pLast = pPrev;
187 nSize--;
188 }
189 }
190 };
191 /** @endcond */
192
193 /**
194 * Linked list template container. This class is similar to the stl list
195 * class except for a few minor changes. First, when const, all
196 * members are only accessable const. Second, erasing a location does not
197 * invalidate the iterator used, it simply points to the next valid
198 * location, or end() if there are no more. Other iterators pointing to
199 * the deleted record will, of course, no longer be valid.
200 *
201 *@param value (typename) The type of data to store in your list
202 *@param valuealloc (typename) Memory Allocator for your value type
203 *@param linkalloc (typename) Memory Allocator for the list links.
204 *@extends SharedCore
205 *@ingroup Containers
206 */
207 template<typename value, typename valuealloc=std::allocator<value>,
208 typename linkalloc=std::allocator<struct ListLink<value> > >
209 class List /** @cond */ : public SharedCore<
210 List<value, valuealloc, linkalloc>,
211 ListCore<value, valuealloc, linkalloc>
212 > /** @endcond */
213 {
214 private:
215 typedef struct ListLink<value> Link;
216 typedef class List<value, valuealloc, linkalloc> MyType;
217 typedef struct ListCore<value, valuealloc, linkalloc> Core;
218
219 protected:
220 using SharedCore<MyType, Core>::core;
221 using SharedCore<MyType, Core>::_hardCopy;
222 using SharedCore<MyType, Core>::_allocateCore;
223
224 public:
225 struct const_iterator;
226 struct iterator;
227
228 List()
229 {
230 }
231
232 List( const MyType &src ) :
233 SharedCore<MyType, Core >( src )
234 {
235 }
236
237 List( const value &v )
238 {
239 append( v );
240 }
241
242 ~List()
243 {
244 }
245
246 MyType &operator+=( const value &v )
247 {
248 _hardCopy();
249 append( v );
250 return *this;
251 }
252
253 MyType &operator+=( const MyType &src )
254 {
255 _hardCopy();
256 append( src );
257 return *this;
258 }
259
260 MyType operator+( const MyType &src )
261 {
262 MyType lNew( *this );
263 lNew += src;
264 return lNew;
265 }
266
267 bool operator==( const MyType &rhs ) const
268 {
269 if( getSize() != rhs.getSize() )
270 return false;
271
272 for( typename MyType::const_iterator a = begin(), b = rhs.begin();
273 a; a++, b++ )
274 {
275 if( *a != *b )
276 return false;
277 }
278
279 return true;
280 }
281
282 bool operator!=( const MyType &rhs ) const
283 {
284 return !(*this == rhs);
285 }
286
287 /**
288 * Clear the data from the list.
289 */
290 void clear()
291 {
292 _hardCopy();
293 core->clear();
294 }
295
296 MyType &enqueue( const value &v )
297 {
298 _hardCopy();
299 append( v );
300
301 return *this;
302 }
303
304 value dequeue()
305 {
306 // _hardCopy(); erase will call this for me
307 value v = *core->pFirst->pValue;
308
309 erase( begin() );
310
311 return v;
312 }
313
314 MyType &push( const value &v )
315 {
316 _hardCopy();
317 prepend( v );
318
319 return *this;
320 }
321
322 MyType &pop()
323 {
324 _hardCopy();
325 erase( begin() );
326
327 return *this;
328 }
329
330 value peekPop()
331 {
332 value v = first();
333 pop();
334 return v;
335 }
336
337 value &peek()
338 {
339 return first();
340 }
341
342 /**
343 * Append a value to the list.
344 *@param v (const value_type &) The value to append.
345 */
346 MyType &append( const value &v )
347 {
348 _hardCopy();
349 core->append( v );
350
351 return *this;
352 }
353
354 MyType &append( const MyType &rSrc )
355 {
356 _hardCopy();
357 for( typename MyType::const_iterator i = rSrc.begin();
358 i != rSrc.end(); i++ )
359 {
360 core->append( *i );
361 }
362
363 return *this;
364 }
365
366 /**
367 * Prepend a value to the list.
368 *@param v (const value_type &) The value to prepend.
369 */
370 MyType &prepend( const value &v )
371 {
372 _hardCopy();
373 core->prepend( v );
374
375 return *this;
376 }
377
378 /**
379 * Prepend another list to the front of this one. This will prepend
380 * the rSrc list in reverse order...I may fix that later.
381 */
382 MyType &prepend( const MyType &rSrc )
383 {
384 _hardCopy();
385 for( typename MyType::const_iterator i = rSrc.begin();
386 i != rSrc.end(); i++ )
387 {
388 core->prepend( *i );
389 }
390
391 return *this;
392 }
393
394 MyType &insert( MyType::iterator &i, const value &v )
395 {
396 _hardCopy();
397
398 core->insert( i.pLink, v );
399
400 return *this;
401 }
402
403 template<typename cmptype>
404 void sort( cmptype cmp )
405 {
406 Heap<value, cmptype, valuealloc> hSort( cmp, getSize() );
407 for( typename MyType::iterator i = begin(); i; i++ )
408 {
409 hSort.enqueue( *i );
410 }
411 clear();
412 while( !hSort.isEmpty() )
413 {
414 append( hSort.dequeue() );
415 }
416 }
417
418 void sort()
419 {
420 sort<__basicLTCmp<value> >();
421 }
422
423 template<typename cmptype>
424 void sort()
425 {
426 Heap<value, cmptype, valuealloc> hSort( getSize() );
427 for( typename MyType::iterator i = begin(); i; i++ )
428 {
429 hSort.enqueue( *i );
430 }
431 clear();
432 while( !hSort.isEmpty() )
433 {
434 append( hSort.dequeue() );
435 }
436 }
437
438 /**
439 * Insert a new item in sort order by searching for the first item that
440 * is larger and inserting this before it, or at the end if none are
441 * larger. If this is the only function used to insert data in the
442 * List all items will be sorted. To use this, the value type must
443 * support the > operator.
444 */
445 template<typename cmptype>
446 iterator insertSorted( cmptype cmp, const value &v )
447 {
448 _hardCopy();
449 if( core->pFirst == NULL )
450 {
451 // Empty list
452 return iterator( core->append( v ) );
453 }
454 else
455 {
456 Link *pCur = core->pFirst;
457 for(;;)
458 {
459 if( cmp( v, *(pCur->pValue)) )
460 {
461 return iterator( core->insert( pCur, v ) );
462 }
463 pCur = pCur->pNext;
464 if( pCur == NULL )
465 {
466 return iterator( core->append( v ) );
467 }
468 }
469 }
470 }
471
472 iterator insertSorted( const value &v )
473 {
474 return insertSorted<__basicLTCmp<value> >( v );
475 }
476
477 template<typename cmptype>
478 iterator insertSorted( const value &v )
479 {
480 cmptype cmp;
481 return insertSorted( cmp, v );
482 }
483
484 /**
485 * An iterator to iterate through your list.
486 */
487 typedef struct iterator
488 {
489 friend struct const_iterator;
490 friend class List<value, valuealloc, linkalloc>;
491 private:
492 Link *pLink;
493
494 iterator( Link *pLink ) :
495 pLink( pLink )
496 {
497 }
498
499 public:
500 iterator() :
501 pLink( NULL )
502 {
503 }
504
505 iterator( const iterator &i ) :
506 pLink( i.pLink )
507 {
508 }
509
510 /**
511 * Equals comparison operator.
512 *@param oth (const iterator &) The iterator to compare to.
513 *@returns (bool) Are they equal?
514 */
515 bool operator==( const iterator &oth ) const
516 {
517 return ( pLink == oth.pLink );
518 }
519
520 /**
521 * Equals comparison operator.
522 *@param pOth (const Link *) The link to compare to.
523 *@returns (bool) Are they equal?
524 */
525 bool operator==( const Link *pOth ) const
526 {
527 return ( pLink == pOth );
528 }
529
530 /**
531 * Not equals comparison operator.
532 *@param oth (const iterator &) The iterator to compare to.
533 *@returns (bool) Are they not equal?
534 */
535 bool operator!=( const iterator &oth ) const
536 {
537 return ( pLink != oth.pLink );
538 }
539
540 /**
541 * Not equals comparison operator.
542 *@param pOth (const Link *) The link to compare to.
543 *@returns (bool) Are they not equal?
544 */
545 bool operator!=( const Link *pOth ) const
546 {
547 return ( pLink != pOth );
548 }
549
550 /**
551 * Dereference operator.
552 *@returns (value_type &) The value.
553 */
554 value &operator*()
555 {
556 return *(pLink->pValue);
557 }
558
559 /**
560 * Pointer access operator.
561 *@returns (value_type *) A pointer to the value.
562 */
563 value *operator->()
564 {
565 return pLink->pValue;
566 }
567
568 iterator &operator++()
569 {
570 if( pLink == NULL )
571 throw Bu::ExceptionBase(
572 "Attempt to iterate past end of list.");
573 pLink = pLink->pNext;
574 return *this;
575 }
576
577 iterator &operator--()
578 {
579 if( pLink == NULL )
580 throw Bu::ExceptionBase(
581 "Attempt to iterate past begining of list.");
582 pLink = pLink->pPrev;
583 return *this;
584 }
585
586 iterator &operator++( int )
587 {
588 if( pLink == NULL )
589 throw Bu::ExceptionBase(
590 "Attempt to iterate past end of list.");
591 pLink = pLink->pNext;
592 return *this;
593 }
594
595 iterator &operator--( int )
596 {
597 if( pLink == NULL )
598 throw Bu::ExceptionBase(
599 "Attempt to iterate past begining of list.");
600 pLink = pLink->pPrev;
601 return *this;
602 }
603
604 iterator operator+( int iDelta )
605 {
606 iterator ret( *this );
607 for( int j = 0; j < iDelta; j++ )
608 {
609 if( ret.pLink == NULL )
610 throw Bu::ExceptionBase(
611 "Attempt to iterate past begining of list.");
612 ret.pLink = ret.pLink->pNext;
613 }
614 return ret;
615 }
616
617 iterator operator-( int iDelta )
618 {
619 iterator ret( *this );
620 for( int j = 0; j < iDelta; j++ )
621 {
622 if( ret.pLink == NULL )
623 throw Bu::ExceptionBase(
624 "Attempt to iterate past begining of list.");
625 ret.pLink = ret.pLink->pPrev;
626 }
627 return ret;
628 }
629
630 operator bool()
631 {
632 return pLink != NULL;
633 }
634
635 bool isValid()
636 {
637 return pLink != NULL;
638 }
639
640 /**
641 * Assignment operator.
642 *@param oth (const iterator &) The other iterator to set this
643 * one to.
644 */
645 iterator &operator=( const iterator &oth )
646 {
647 pLink = oth.pLink;
648 return *this;
649 }
650 } iterator;
651
652 /**
653 *@see iterator
654 */
655 typedef struct const_iterator
656 {
657 friend class List<value, valuealloc, linkalloc>;
658 private:
659 Link *pLink;
660
661 const_iterator( Link *pLink ) :
662 pLink( pLink )
663 {
664 }
665
666 public:
667 const_iterator() :
668 pLink( NULL )
669 {
670 }
671
672 const_iterator( const iterator &i ) :
673 pLink( i.pLink )
674 {
675 }
676
677 bool operator==( const const_iterator &oth ) const
678 {
679 return ( pLink == oth.pLink );
680 }
681
682 bool operator==( const Link *pOth ) const
683 {
684 return ( pLink == pOth );
685 }
686
687 bool operator!=( const const_iterator &oth ) const
688 {
689 return ( pLink != oth.pLink );
690 }
691
692 bool operator!=( const Link *pOth ) const
693 {
694 return ( pLink != pOth );
695 }
696
697 const value &operator*()
698 {
699 return *(pLink->pValue);
700 }
701
702 const value *operator->()
703 {
704 return pLink->pValue;
705 }
706
707 const_iterator &operator++()
708 {
709 if( pLink == NULL )
710 throw Bu::ExceptionBase(
711 "Attempt to iterate past end of list.");
712 pLink = pLink->pNext;
713 return *this;
714 }
715
716 const_iterator &operator--()
717 {
718 if( pLink == NULL )
719 throw Bu::ExceptionBase(
720 "Attempt to iterate past begining of list.");
721 pLink = pLink->pPrev;
722 return *this;
723 }
724
725 const_iterator &operator++( int )
726 {
727 if( pLink == NULL )
728 throw Bu::ExceptionBase(
729 "Attempt to iterate past end of list.");
730 pLink = pLink->pNext;
731 return *this;
732 }
733
734 const_iterator &operator--( int )
735 {
736 if( pLink == NULL )
737 throw Bu::ExceptionBase(
738 "Attempt to iterate past begining of list.");
739 pLink = pLink->pPrev;
740 return *this;
741 }
742
743 const_iterator operator+( int iDelta )
744 {
745 const_iterator ret( *this );
746 for( int j = 0; j < iDelta; j++ )
747 {
748 if( ret.pLink == NULL )
749 throw Bu::ExceptionBase(
750 "Attempt to iterate past begining of list.");
751 ret.pLink = ret.pLink->pNext;
752 }
753 return ret;
754 }
755
756 const_iterator operator-( int iDelta )
757 {
758 const_iterator ret( *this );
759 for( int j = 0; j < iDelta; j++ )
760 {
761 if( ret.pLink == NULL )
762 throw Bu::ExceptionBase(
763 "Attempt to iterate past begining of list.");
764 ret.pLink = ret.pLink->pPrev;
765 }
766 return ret;
767 }
768
769 const_iterator &operator=( const iterator &oth )
770 {
771 pLink = oth.pLink;
772 return *this;
773 }
774
775 const_iterator &operator=( const const_iterator &oth )
776 {
777 pLink = oth.pLink;
778 return *this;
779 }
780
781 operator bool()
782 {
783 return pLink != NULL;
784 }
785
786 bool isValid()
787 {
788 return pLink != NULL;
789 }
790 } const_iterator;
791
792 /**
793 * Get an iterator pointing to the first item in the list.
794 *@returns (iterator)
795 */
796 iterator begin()
797 {
798 _hardCopy();
799 return iterator( core->pFirst );
800 }
801
802 /**
803 * Get a const iterator pointing to the first item in the list.
804 *@returns (const const_iterator)
805 */
806 const_iterator begin() const
807 {
808 return const_iterator( core->pFirst );
809 }
810
811 /**
812 * Get an iterator pointing to a place just past the last item in
813 * the list.
814 *@returns (const Link *)
815 */
816 const iterator end()
817 {
818 return iterator( NULL );
819 }
820
821 /**
822 * Get an iterator pointing to a place just past the last item in
823 * the list.
824 *@returns (const Link *)
825 */
826 const const_iterator end() const
827 {
828 return const_iterator( NULL );
829 }
830
831 /**
832 * Erase an item from the list.
833 *@param i (iterator) The item to erase.
834 */
835 MyType &erase( iterator i )
836 {
837 _hardCopy();
838 core->erase( i.pLink );
839
840 return *this;
841 }
842
843 /**
844 * Erase an item from the list.
845 *@param i (iterator) The item to erase.
846 */
847 MyType &erase( const_iterator i )
848 {
849 _hardCopy();
850 core->erase( i.pLink );
851
852 return *this;
853 }
854
855 /**
856 * Erase an item from the list if you already know the item.
857 *@param v The item to find and erase.
858 */
859 MyType &erase( const value &v )
860 {
861 for( const_iterator i = begin(); i != end(); i++ )
862 {
863 if( (*i) == v )
864 {
865 erase( i );
866 return *this;
867 }
868 }
869
870 return *this;
871 }
872
873 iterator find( const value &v )
874 {
875 for( iterator i = begin(); i; i++ )
876 {
877 if( (*i) == v )
878 return i;
879 }
880
881 return end();
882 }
883
884 const_iterator find( const value &v ) const
885 {
886 for( const_iterator i = begin(); i; i++ )
887 {
888 if( (*i) == v )
889 return i;
890 }
891
892 return end();
893 }
894
895 /**
896 * Get the current size of the list.
897 *@returns (int) The current size of the list.
898 */
899 long getSize() const
900 {
901 return core->nSize;
902 }
903
904 /**
905 * Get the first item in the list.
906 *@returns (value_type &) The first item in the list.
907 */
908 value &first()
909 {
910 if( core->pFirst->pValue == NULL )
911 throw Bu::ExceptionBase("Attempt to read first element from empty list.");
912 _hardCopy();
913 return *core->pFirst->pValue;
914 }
915
916 /**
917 * Get the first item in the list.
918 *@returns (const value_type &) The first item in the list.
919 */
920 const value &first() const
921 {
922 if( core->pFirst->pValue == NULL )
923 throw Bu::ExceptionBase("Attempt to read first element from empty list.");
924 return *core->pFirst->pValue;
925 }
926
927 /**
928 * Get the last item in the list.
929 *@returns (value_type &) The last item in the list.
930 */
931 value &last()
932 {
933 _hardCopy();
934 return *core->pLast->pValue;
935 }
936
937 /**
938 * Get the last item in the list.
939 *@returns (const value_type &) The last item in the list.
940 */
941 const value &last() const
942 {
943 return *core->pLast->pValue;
944 }
945
946 bool isEmpty() const
947 {
948 return (core->nSize == 0);
949 }
950
951 protected:
952 virtual Core *_copyCore( Core *src )
953 {
954 Core *pRet = _allocateCore();
955 for( Link *pCur = src->pFirst; pCur; pCur = pCur->pNext )
956 {
957 pRet->append( *pCur->pValue );
958 }
959 return pRet;
960 }
961
962 private:
963 };
964
965 class Formatter;
966 Formatter &operator<<( Formatter &rOut, char *sStr );
967 Formatter &operator<<( Formatter &rOut, signed char c );
968 template<typename a, typename b, typename c>
969 Formatter &operator<<( Formatter &f, const Bu::List<a,b,c> &l )
970 {
971 f << '[';
972 for( typename Bu::List<a,b,c>::const_iterator i = l.begin(); i; i++ )
973 {
974 if( i != l.begin() )
975 f << ", ";
976 f << *i;
977 }
978 f << ']';
979
980 return f;
981 }
982
983 template<typename value, typename a, typename b>
984 ArchiveBase &operator<<( ArchiveBase &ar, const List<value,a,b> &h )
985 {
986 ar << h.getSize();
987 for( typename List<value>::const_iterator i = h.begin(); i != h.end(); i++ )
988 {
989 ar << (*i);
990 }
991
992 return ar;
993 }
994
995 template<typename value, typename a, typename b>
996 ArchiveBase &operator>>( ArchiveBase &ar, List<value,a,b> &h )
997 {
998 h.clear();
999 long nSize;
1000 ar >> nSize;
1001
1002 for( long j = 0; j < nSize; j++ )
1003 {
1004 value v;
1005 ar >> v;
1006 h.append( v );
1007 }
1008
1009 return ar;
1010 }
1011
1012}
1013
1014#endif
diff --git a/src/stable/logger.cpp b/src/stable/logger.cpp
new file mode 100644
index 0000000..8e46390
--- /dev/null
+++ b/src/stable/logger.cpp
@@ -0,0 +1,209 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/logger.h"
9#include <stdarg.h>
10#include <time.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14
15Bu::Logger::Logger()
16{
17 setFormat("%t");
18}
19
20Bu::Logger::~Logger()
21{
22}
23
24void Bu::Logger::log( uint32_t nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...)
25{
26#ifndef WIN32
27 if( (nLevel&nLevelMask) == 0 )
28 return;
29
30 va_list ap;
31 va_start( ap, sFormat );
32 char *text;
33 if( vasprintf( &text, sFormat, ap ) < 0 )
34 {
35 printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WTF?\n");
36 return;
37 }
38 va_end(ap);
39
40 time_t t = time(NULL);
41
42 char *line = NULL;
43 struct tm *pTime;
44 pTime = localtime( &t );
45 if ( asprintf(
46 &line,
47 sLogFormat.getStr(),
48 pTime->tm_year+1900,
49 pTime->tm_mon+1,
50 pTime->tm_mday,
51 pTime->tm_hour,
52 pTime->tm_min,
53 pTime->tm_sec,
54 nLevel,
55 sFile,
56 nLine,
57 text,
58 sFunction
59 ) < 0 )
60 {
61 //printf("LOGGER: ERROR ALLOCATING STRING: %s\n", strerror( errno ) );
62 return;
63 }
64 write( fileno(stdout), line, strlen(line) );
65 free( text );
66 free( line );
67#else
68 #warning Bu::Logger::log IS A STUB for WIN32!!!!
69#endif
70}
71
72void Bu::Logger::setFormat( const Bu::String &str )
73{
74 sLogFormat = "";
75
76 static char fmts[][4]={
77 {'y', 'd', '0', '1'},
78 {'m', 'd', '0', '2'},
79 {'d', 'd', '0', '3'},
80 {'h', 'd', '0', '4'},
81 {'M', 'd', '0', '5'},
82 {'s', 'd', '0', '6'},
83 {'L', 'd', '0', '7'},
84 {'f', 's', '0', '8'},
85 {'l', 'd', '0', '9'},
86 {'t', 's', '1', '0'},
87 {'F', 's', '1', '1'},
88 {'\0', '\0', '\0', '\0'},
89 };
90
91 for( const char *s = str.getStr(); *s; s++ )
92 {
93 if( *s == '%' )
94 {
95 sLogFormat += '%';
96 Bu::String sBuf;
97 for(;;)
98 {
99 s++;
100 int l;
101 for( l = 0;; l++ )
102 {
103 if( fmts[l][0] == '\0' )
104 {
105 sBuf += *s;
106 break;
107 }
108 else if( *s == fmts[l][0] )
109 {
110 sLogFormat += fmts[l][2];
111 sLogFormat += fmts[l][3];
112 sLogFormat += '$';
113 sLogFormat += sBuf;
114 sLogFormat += fmts[l][1];
115 break;
116 }
117 }
118 if( fmts[l][0] != '\0' )
119 break;
120 }
121 }
122 else
123 {
124 sLogFormat += *s;
125 }
126 }
127 sLogFormat += '\n';
128
129 //write( fileno(stdout), sLogFormat.getStr(), sLogFormat.getSize() );
130}
131
132void Bu::Logger::setMask( uint32_t n )
133{
134 nLevelMask = n;
135}
136
137uint32_t Bu::Logger::getMask()
138{
139 return nLevelMask;
140}
141
142void Bu::Logger::setLevel( uint32_t n )
143{
144 int j;
145 for( j = 31; j > 0; j-- )
146 {
147 if( (n&(1<<j)) )
148 {
149 for(; j >= 0; j-- )
150 {
151 n |= (1<<j);
152 }
153 nLevelMask = n;
154 return;
155 }
156 }
157}
158
159void Bu::Logger::hexDump( uint32_t nLevel, const char *sFile,
160 const char *sFunction, int nLine, const void *pDataV, long nDataLen,
161 const char *lpName )
162{
163 if( (nLevel&nLevelMask) == 0 )
164 return;
165
166 log( nLevel, sFile, sFunction, nLine, "Displaying %ld bytes of %s.", nDataLen, lpName );
167 const unsigned char *pData = (const unsigned char *)pDataV;
168 int j = 0;
169 Bu::String sBorder;
170 for( int l = 0; l < 8*3+2*8+2+5; l++ ) sBorder += ((l!=11&&l!=37)?("-"):("+"));
171 log( nLevel, sFile, sFunction, nLine, sBorder.getStr() );
172 Bu::String sLine;
173 for(;;)
174 {
175 {
176 char buf[16];
177 sprintf( buf, "%010d | ", j );
178 sLine += buf;
179 }
180 int kmax = 8;
181 if( nDataLen-j < 8 ) kmax = nDataLen-j;
182 for(int k = 0; k < 8; k++ )
183 {
184 if( k < kmax )
185 {
186 char buf[4];
187 sprintf( buf, "%02X ", (int)((unsigned char)pData[j+k]) );
188 sLine += buf;
189 }
190 else
191 {
192 sLine += "-- ";
193 }
194 }
195 sLine += "| ";
196 for(int k = 0; k < kmax; k++ )
197 {
198 char buf[3];
199 sprintf( buf, "%c", (pData[j+k]>32 && pData[j+k]<=128)?(pData[j+k]):('.') );
200 sLine += buf;
201 }
202 log( nLevel, sFile, sFunction, nLine, sLine.getStr() );
203 sLine = "";
204 j += kmax;
205 if( j >= nDataLen ) break;
206 }
207 log( nLevel, sFile, sFunction, nLine, sBorder.getStr() );
208}
209
diff --git a/src/stable/logger.h b/src/stable/logger.h
new file mode 100644
index 0000000..5c1352b
--- /dev/null
+++ b/src/stable/logger.h
@@ -0,0 +1,125 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_LOGGER_H
9#define BU_LOGGER_H
10
11#include "bu/singleton.h"
12#include "bu/string.h"
13
14namespace Bu
15{
16 /**
17 * Simple logging facility. All output goes straight to stdout, unlike the
18 * old multi-log system. Generally we expect any program complex enough to
19 * want to use this will have other facilities for processing the logging
20 * output, but if we need it we can add other output methods.
21 *
22 * Currently implemented as a singleton to avoid clutter with globals, you
23 * generally never want to use the logging system directly, it's annoying.
24 * Instead use the handy macros lineLog, setLogMask, setLogFormat, and
25 * setLogLevel. They do all the real work for you.
26 *
27 * In the log format, you can specify extra information that will be written
28 * to the log with every message, and extras in printf style. Use %X flags
29 * where X is one of the following:
30 * - L - Logging level of the log message (not the current mask)
31 * - y - Full year
32 * - m - Month
33 * - d - Day of month
34 * - h - Hour (24-hour format)
35 * - M - Minutes
36 * - s - Seconds
37 * - f - Source file
38 * - l - Line number
39 * - F - function name
40 * - t - Text of message (usually important)
41 *
42 * You can include anything extra that you would like, a newline will always
43 * be added automatically, so no need to worry about that. You can also
44 * include any extra printf style formatting that you would like, for
45 * example: "%h:%02M:%02s" for the time 4:02:09 instead of 4:2:9.
46 *
47 * It's generally handy to create an enum of values you use as levels during
48 * program execution (such as error, warning, info, debug, etc). These
49 * levels should be treated as bitflags, and the most desirable messages,
50 * i.e. serious errors and the like should be low order (0x01), and the much
51 * less desirable messages, like debugging info, should be higher order
52 * (0xF0). During operation you can then set either an explicit mask,
53 * selecting just the levels that you would like to see printed, or set the
54 * mask using the setLevel helper function, which simulates verbosity
55 * levels, enabling every flag lower order than the highest order set bit
56 * passed. I.E. if you had the following enumerated levels:
57 *
58 *@code
59 enum {
60 logError = 0x01,
61 logWarning = 0x02,
62 logInfo = 0x04,
63 logDebug = 0x08
64 };
65 @endcode
66 * And you set the mask with setMask( logInfo ) the only messages you would
67 * see are the ones catagorized logInfo. However, if you used
68 * setLevel( logInfo ) then you would see logInfo, logWarning, and logError
69 * type messages, since they are lower order.
70 */
71 class Logger : public Bu::Singleton<Bu::Logger>
72 {
73 friend class Bu::Singleton<Bu::Logger>;
74 private:
75 Logger();
76 virtual ~Logger();
77
78 public:
79 void log( uint32_t nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...);
80
81 void setFormat( const Bu::String &str );
82 void setMask( uint32_t n );
83 void setLevel( uint32_t n );
84 uint32_t getMask();
85
86 void hexDump( uint32_t nLevel, const char *sFile, const char *sFunction, int nLine, const void *pData, long nDataLen, const char *lpName );
87
88 private:
89 Bu::String sLogFormat;
90 uint32_t nLevelMask;
91 };
92}
93
94/**
95 * Use Bu::Logger to log a message at the given level and with the given message
96 * using printf style formatting, and include extra data such as the current
97 * file, line number, and function.
98 */
99#define lineLog( nLevel, sFrmt, ...) \
100 Bu::Logger::getInstance().log( nLevel, __FILE__, __PRETTY_FUNCTION__, __LINE__, sFrmt, ##__VA_ARGS__ )
101
102#define logHexDump( nLevel, pData, iSize, sName ) \
103 Bu::Logger::getInstance().hexDump( nLevel, __FILE__, __PRETTY_FUNCTION__, __LINE__, pData, iSize, sName )
104
105/**
106 * Set the Bu::Logger logging mask directly. See Bu::Logger::setMask for
107 * details.
108 */
109#define setLogMask( nLevel ) \
110 Bu::Logger::getInstance().setMask( nLevel )
111
112/**
113 * Set the Bu::Logger format. See Bu::Logger::setFormat for details.
114 */
115#define setLogFormat( sFrmt ) \
116 Bu::Logger::getInstance().setFormat( sFrmt )
117
118/**
119 * Set the Bu::Logger logging mask simulating levels. See Bu::Logger::setLevel
120 * for details.
121 */
122#define setLogLevel( nLevel ) \
123 Bu::Logger::getInstance().setLevel( nLevel )
124
125#endif
diff --git a/src/stable/lzma.cpp b/src/stable/lzma.cpp
new file mode 100644
index 0000000..6ed0806
--- /dev/null
+++ b/src/stable/lzma.cpp
@@ -0,0 +1,248 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/lzma.h"
9#include "bu/trace.h"
10
11#include <lzma.h>
12
13#define pState ((lzma_stream *)prState)
14
15using namespace Bu;
16
17Bu::Lzma::Lzma( Bu::Stream &rNext, int nCompression, Format eFmt ) :
18 Bu::Filter( rNext ),
19 prState( NULL ),
20 nCompression( nCompression ),
21 sTotalOut( 0 ),
22 eFmt( eFmt ),
23 bEos( false )
24{
25 TRACE( nCompression );
26 start();
27}
28
29Bu::Lzma::~Lzma()
30{
31 TRACE();
32 stop();
33}
34
35void Bu::Lzma::start()
36{
37 TRACE();
38 nBufSize = 64*1024;
39 pBuf = new char[nBufSize];
40}
41
42Bu::size Bu::Lzma::stop()
43{
44 TRACE();
45 if( pState )
46 {
47 if( bReading )
48 {
49 lzma_end( pState );
50 delete[] pBuf;
51 pBuf = NULL;
52 delete pState;
53 prState = NULL;
54 return 0;
55 }
56 else
57 {
58 for(;;)
59 {
60 pState->next_in = NULL;
61 pState->avail_in = 0;
62 pState->avail_out = nBufSize;
63 pState->next_out = (uint8_t *)pBuf;
64 int res = lzma_code( pState, LZMA_FINISH );
65 if( pState->avail_out < nBufSize )
66 {
67 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
68 }
69 if( res == LZMA_STREAM_END )
70 break;
71 }
72 lzma_end( pState );
73 delete[] pBuf;
74 pBuf = NULL;
75 delete pState;
76 prState = NULL;
77 return sTotalOut;
78 }
79 }
80 return 0;
81}
82
83void Bu::Lzma::lzmaError( int code )
84{
85 TRACE( code );
86 switch( code )
87 {
88 case LZMA_OK:
89 case LZMA_STREAM_END:
90 case LZMA_NO_CHECK:
91 case LZMA_UNSUPPORTED_CHECK:
92 break;
93
94 case LZMA_MEM_ERROR:
95 throw ExceptionBase("Lzma: Memory allocation error.");
96
97 case LZMA_MEMLIMIT_ERROR:
98 throw ExceptionBase("Lzma: Memory usage limit was reached.");
99
100 case LZMA_FORMAT_ERROR:
101 throw ExceptionBase("Lzma: File format not recognized.");
102
103 case LZMA_OPTIONS_ERROR:
104 throw ExceptionBase("Lzma: Invalid or unsupported options.");
105
106 case LZMA_DATA_ERROR:
107 throw ExceptionBase("Lzma: Data is corrupt.");
108
109 case LZMA_BUF_ERROR:
110 throw ExceptionBase("Lzma: No progress is possible.");
111
112 case LZMA_PROG_ERROR:
113 throw ExceptionBase("Lzma: Programming error.");
114
115 default:
116 throw ExceptionBase("Lzma: Unknown error encountered." );
117 }
118}
119
120Bu::size Bu::Lzma::read( void *pData, Bu::size nBytes )
121{
122 TRACE( pData, nBytes );
123 if( !pState )
124 {
125 prState = new ::lzma_stream;
126 lzma_stream zEmpty = LZMA_STREAM_INIT;
127 Bu::memcpy( prState, &zEmpty, sizeof(lzma_stream) );
128
129 bReading = true;
130 lzmaError( lzma_auto_decoder( pState, UINT64_MAX, 0 ) );
131 pState->next_in = (uint8_t *)pBuf;
132 pState->avail_in = 0;
133 }
134 if( bReading == false )
135 throw ExceptionBase("This lzma filter is in writing mode, you can't read.");
136
137 int nRead = 0;
138 int nReadTotal = pState->total_out;
139 pState->next_out = (uint8_t *)pData;
140 pState->avail_out = nBytes;
141 for(;;)
142 {
143 int ret = lzma_code( pState, LZMA_RUN );
144 printf("inflate returned %d; avail in=%d, out=%d\n", ret,
145 pState->avail_in, pState->avail_out );
146
147 nReadTotal += nRead-pState->avail_out;
148
149 if( ret == LZMA_STREAM_END )
150 {
151 bEos = true;
152 if( pState->avail_in > 0 )
153 {
154 if( rNext.isSeekable() )
155 {
156 rNext.seek( -pState->avail_in );
157 }
158 }
159 return nBytes-pState->avail_out;
160 }
161// if( ret != LZMA_BUF_ERROR )
162 lzmaError( ret );
163
164 if( pState->avail_out )
165 {
166 if( pState->avail_in == 0 )
167 {
168 nRead = rNext.read( pBuf, nBufSize );
169 if( nRead == 0 && rNext.isEos() )
170 {
171 throw Bu::ExceptionBase("Premature end of underlying "
172 "stream found reading deflate stream.");
173 }
174 pState->next_in = (uint8_t *)pBuf;
175 pState->avail_in = nRead;
176 }
177 }
178 else
179 {
180 return nBytes-pState->avail_out;
181 }
182 }
183 return 0;
184}
185
186Bu::size Bu::Lzma::write( const void *pData, Bu::size nBytes )
187{
188 TRACE( pData, nBytes );
189 if( !pState )
190 {
191 prState = new ::lzma_stream;
192 lzma_stream zEmpty = LZMA_STREAM_INIT;
193 Bu::memcpy( prState, &zEmpty, sizeof(lzma_stream) );
194
195 bReading = false;
196 if( eFmt == Xz )
197 lzmaError(
198 lzma_easy_encoder( pState, nCompression, LZMA_CHECK_CRC64 )
199 );
200 else if( eFmt == LzmaAlone )
201 {
202 lzma_options_lzma opt;
203 lzma_lzma_preset( &opt, nCompression );
204 lzmaError( lzma_alone_encoder( pState, &opt ) );
205 }
206 else
207 throw Bu::ExceptionBase("Invalid format for lzma.");
208 }
209 if( bReading == true )
210 throw ExceptionBase("This lzma filter is in reading mode, you can't write.");
211
212 pState->next_in = (uint8_t *)pData;
213 pState->avail_in = nBytes;
214 for(;;)
215 {
216 pState->avail_out = nBufSize;
217 pState->next_out = (uint8_t *)pBuf;
218
219 lzmaError( lzma_code( pState, LZMA_RUN ) );
220
221 if( pState->avail_out < nBufSize )
222 {
223 sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out );
224 }
225 if( pState->avail_in == 0 )
226 break;
227 }
228
229 return nBytes;
230}
231
232bool Bu::Lzma::isOpen()
233{
234 TRACE();
235 return (pState != NULL);
236}
237
238bool Bu::Lzma::isEos()
239{
240 TRACE();
241 return bEos;
242}
243
244Bu::size Bu::Lzma::getCompressedSize()
245{
246 return sTotalOut;
247}
248
diff --git a/src/stable/lzma.h b/src/stable/lzma.h
new file mode 100644
index 0000000..090da8d
--- /dev/null
+++ b/src/stable/lzma.h
@@ -0,0 +1,59 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_LZMA_H
9#define BU_LZMA_H
10
11#include <stdint.h>
12
13#include "bu/filter.h"
14
15namespace Bu
16{
17 /**
18 * Provides XZ compression and decompression, both LZMA1 (LzmaAlone) as
19 * well as the newer LZMA2 (xz) format. This uses .xz by default.
20 *
21 *@ingroup Streams
22 *@ingroup Compression
23 */
24 class Lzma : public Bu::Filter
25 {
26 public:
27 enum Format
28 {
29 Xz = 0x01,
30 LzmaAlone = 0x02,
31 };
32
33 Lzma( Bu::Stream &rNext, int nCompression=6, Format eFmt=Xz );
34 virtual ~Lzma();
35
36 virtual void start();
37 virtual Bu::size stop();
38 virtual Bu::size read( void *pBuf, Bu::size nBytes );
39 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
40
41 virtual bool isOpen();
42 virtual bool isEos();
43
44 Bu::size getCompressedSize();
45
46 private:
47 void lzmaError( int code );
48 void *prState;
49 bool bReading;
50 int nCompression;
51 char *pBuf;
52 uint32_t nBufSize;
53 Bu::size sTotalOut;
54 Format eFmt;
55 bool bEos;
56 };
57}
58
59#endif
diff --git a/src/stable/md5.cpp b/src/stable/md5.cpp
new file mode 100644
index 0000000..15cba17
--- /dev/null
+++ b/src/stable/md5.cpp
@@ -0,0 +1,246 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include "bu/md5.h"
12#include "bu/stream.h"
13
14#ifdef SYSTEM_BIG_ENDIAN
15# define toLittleEndian( a, b ) _toLittleEndian( a, b )
16#else
17# define toLittleEndian( a, b ) (void)0
18#endif
19
20Bu::Md5::Md5()
21{
22 reset();
23}
24
25Bu::Md5::~Md5()
26{
27}
28
29void Bu::Md5::reset()
30{
31 // These are the magic seed numbers...
32
33 sum[0] = 0x67452301U;
34 sum[1] = 0xEFCDAB89U;
35 sum[2] = 0x98BADCFEU;
36 sum[3] = 0x10325476U;
37
38 uBits[0] = 0;
39 uBits[1] = 0;
40}
41
42void Bu::Md5::setSalt( const Bu::String & /*sSalt*/ )
43{
44}
45
46void Bu::Md5::addData( const void *sVData, int iSize )
47{
48 const char *sData = (const char *)sVData;
49 uint32_t t;
50
51 t = uBits[0];
52 if( (uBits[0] = t + ((uint32_t)iSize << 3)) < t )
53 uBits[1]++;
54 uBits[1] += iSize >> 29;
55
56 t = (t >> 3) & 0x3f; /* How many bytes we have buffered */
57
58 /* Handle any leading odd-sized chunks */
59 if( t )
60 {
61 unsigned char *p = (unsigned char *) inbuf + t;
62
63 t = 64 - t;
64 if( (uint32_t)iSize < t ) {
65 memcpy( p, sData, iSize );
66 return;
67 }
68 memcpy( p, sData, t );
69 toLittleEndian( inbuf, 16 );
70 compBlock( sum, (uint32_t *)inbuf );
71 sData += t;
72 iSize -= t;
73 }
74
75 /* Process data in 64-byte chunks */
76 while( iSize >= 64 )
77 {
78 memcpy( inbuf, sData, 64 );
79 toLittleEndian( inbuf, 16 );
80 compBlock( sum, (uint32_t *)inbuf );
81 sData += 64;
82 iSize -= 64;
83 }
84
85 /* Handle any remaining bytes of data. */
86 memcpy( inbuf, sData, iSize );
87}
88
89Bu::String Bu::Md5::getResult()
90{
91 uint32_t lsum[4];
92 compCap( lsum );
93 return Bu::String( (const char *)lsum, 4*4 );
94}
95
96void Bu::Md5::writeResult( Bu::Stream &sOut )
97{
98 uint32_t lsum[4];
99 compCap( lsum );
100 sOut.write( lsum, 4*4 );
101}
102
103void Bu::Md5::compCap( uint32_t *sumout )
104{
105 uint8_t tmpbuf[64];
106 memcpy( sumout, sum, 4*4 );
107 memcpy( tmpbuf, inbuf, 64 );
108
109 uint32_t count;
110 uint8_t *p;
111
112 /* Compute number of bytes mod 64 */
113 count = (uBits[0] >> 3) & 0x3F;
114
115 /* Set the first char of padding to 0x80. This is safe since there is
116 always at least one byte free */
117 p = tmpbuf + count;
118 *p++ = 0x80;
119
120 /* Bytes of padding needed to make 64 bytes */
121 count = 64 - 1 - count;
122
123 /* Pad out to 56 mod 64 */
124 if (count < 8) {
125 /* Two lots of padding: Pad the first block to 64 bytes */
126 memset( p, 0, count );
127 toLittleEndian( tmpbuf, 16 );
128 compBlock( sumout, (uint32_t *)tmpbuf );
129
130 /* Now fill the next block with 56 bytes */
131 memset( tmpbuf, 0, 56);
132 } else {
133 /* Pad block to 56 bytes */
134 memset( p, 0, count - 8);
135 }
136 toLittleEndian( tmpbuf, 14 );
137
138 /* Append length in bits and transform */
139 ((uint32_t *) tmpbuf)[14] = uBits[0];
140 ((uint32_t *) tmpbuf)[15] = uBits[1];
141
142 compBlock( sumout, (uint32_t *)tmpbuf );
143 toLittleEndian((unsigned char *)sumout, 4);
144}
145
146#define F1(x, y, z) (z ^ (x & (y ^ z)))
147#define F2(x, y, z) F1(z, x, y)
148#define F3(x, y, z) (x ^ y ^ z)
149#define F4(x, y, z) (y ^ (x | ~z))
150
151/* This is the central step in the MD5 algorithm. */
152#define MD5STEP(f, w, x, y, z, data, s) \
153 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
154
155void Bu::Md5::compBlock( uint32_t *lsum, uint32_t *x )
156{
157 register uint32_t a, b, c, d;
158 a = lsum[0];
159 b = lsum[1];
160 c = lsum[2];
161 d = lsum[3];
162
163 MD5STEP(F1, a, b, c, d, x[0] + 0xd76aa478, 7);
164 MD5STEP(F1, d, a, b, c, x[1] + 0xe8c7b756, 12);
165 MD5STEP(F1, c, d, a, b, x[2] + 0x242070db, 17);
166 MD5STEP(F1, b, c, d, a, x[3] + 0xc1bdceee, 22);
167 MD5STEP(F1, a, b, c, d, x[4] + 0xf57c0faf, 7);
168 MD5STEP(F1, d, a, b, c, x[5] + 0x4787c62a, 12);
169 MD5STEP(F1, c, d, a, b, x[6] + 0xa8304613, 17);
170 MD5STEP(F1, b, c, d, a, x[7] + 0xfd469501, 22);
171 MD5STEP(F1, a, b, c, d, x[8] + 0x698098d8, 7);
172 MD5STEP(F1, d, a, b, c, x[9] + 0x8b44f7af, 12);
173 MD5STEP(F1, c, d, a, b, x[10] + 0xffff5bb1, 17);
174 MD5STEP(F1, b, c, d, a, x[11] + 0x895cd7be, 22);
175 MD5STEP(F1, a, b, c, d, x[12] + 0x6b901122, 7);
176 MD5STEP(F1, d, a, b, c, x[13] + 0xfd987193, 12);
177 MD5STEP(F1, c, d, a, b, x[14] + 0xa679438e, 17);
178 MD5STEP(F1, b, c, d, a, x[15] + 0x49b40821, 22);
179
180 MD5STEP(F2, a, b, c, d, x[1] + 0xf61e2562, 5);
181 MD5STEP(F2, d, a, b, c, x[6] + 0xc040b340, 9);
182 MD5STEP(F2, c, d, a, b, x[11] + 0x265e5a51, 14);
183 MD5STEP(F2, b, c, d, a, x[0] + 0xe9b6c7aa, 20);
184 MD5STEP(F2, a, b, c, d, x[5] + 0xd62f105d, 5);
185 MD5STEP(F2, d, a, b, c, x[10] + 0x02441453, 9);
186 MD5STEP(F2, c, d, a, b, x[15] + 0xd8a1e681, 14);
187 MD5STEP(F2, b, c, d, a, x[4] + 0xe7d3fbc8, 20);
188 MD5STEP(F2, a, b, c, d, x[9] + 0x21e1cde6, 5);
189 MD5STEP(F2, d, a, b, c, x[14] + 0xc33707d6, 9);
190 MD5STEP(F2, c, d, a, b, x[3] + 0xf4d50d87, 14);
191 MD5STEP(F2, b, c, d, a, x[8] + 0x455a14ed, 20);
192 MD5STEP(F2, a, b, c, d, x[13] + 0xa9e3e905, 5);
193 MD5STEP(F2, d, a, b, c, x[2] + 0xfcefa3f8, 9);
194 MD5STEP(F2, c, d, a, b, x[7] + 0x676f02d9, 14);
195 MD5STEP(F2, b, c, d, a, x[12] + 0x8d2a4c8a, 20);
196
197 MD5STEP(F3, a, b, c, d, x[5] + 0xfffa3942, 4);
198 MD5STEP(F3, d, a, b, c, x[8] + 0x8771f681, 11);
199 MD5STEP(F3, c, d, a, b, x[11] + 0x6d9d6122, 16);
200 MD5STEP(F3, b, c, d, a, x[14] + 0xfde5380c, 23);
201 MD5STEP(F3, a, b, c, d, x[1] + 0xa4beea44, 4);
202 MD5STEP(F3, d, a, b, c, x[4] + 0x4bdecfa9, 11);
203 MD5STEP(F3, c, d, a, b, x[7] + 0xf6bb4b60, 16);
204 MD5STEP(F3, b, c, d, a, x[10] + 0xbebfbc70, 23);
205 MD5STEP(F3, a, b, c, d, x[13] + 0x289b7ec6, 4);
206 MD5STEP(F3, d, a, b, c, x[0] + 0xeaa127fa, 11);
207 MD5STEP(F3, c, d, a, b, x[3] + 0xd4ef3085, 16);
208 MD5STEP(F3, b, c, d, a, x[6] + 0x04881d05, 23);
209 MD5STEP(F3, a, b, c, d, x[9] + 0xd9d4d039, 4);
210 MD5STEP(F3, d, a, b, c, x[12] + 0xe6db99e5, 11);
211 MD5STEP(F3, c, d, a, b, x[15] + 0x1fa27cf8, 16);
212 MD5STEP(F3, b, c, d, a, x[2] + 0xc4ac5665, 23);
213
214 MD5STEP(F4, a, b, c, d, x[0] + 0xf4292244, 6);
215 MD5STEP(F4, d, a, b, c, x[7] + 0x432aff97, 10);
216 MD5STEP(F4, c, d, a, b, x[14] + 0xab9423a7, 15);
217 MD5STEP(F4, b, c, d, a, x[5] + 0xfc93a039, 21);
218 MD5STEP(F4, a, b, c, d, x[12] + 0x655b59c3, 6);
219 MD5STEP(F4, d, a, b, c, x[3] + 0x8f0ccc92, 10);
220 MD5STEP(F4, c, d, a, b, x[10] + 0xffeff47d, 15);
221 MD5STEP(F4, b, c, d, a, x[1] + 0x85845dd1, 21);
222 MD5STEP(F4, a, b, c, d, x[8] + 0x6fa87e4f, 6);
223 MD5STEP(F4, d, a, b, c, x[15] + 0xfe2ce6e0, 10);
224 MD5STEP(F4, c, d, a, b, x[6] + 0xa3014314, 15);
225 MD5STEP(F4, b, c, d, a, x[13] + 0x4e0811a1, 21);
226 MD5STEP(F4, a, b, c, d, x[4] + 0xf7537e82, 6);
227 MD5STEP(F4, d, a, b, c, x[11] + 0xbd3af235, 10);
228 MD5STEP(F4, c, d, a, b, x[2] + 0x2ad7d2bb, 15);
229 MD5STEP(F4, b, c, d, a, x[9] + 0xeb86d391, 21);
230
231 lsum[0] += a;
232 lsum[1] += b;
233 lsum[2] += c;
234 lsum[3] += d;
235}
236
237void Bu::Md5::_toLittleEndian( uint8_t *buf, uint32_t count )
238{
239 uint32_t t;
240 do {
241 t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
242 ((unsigned) buf[1] << 8 | buf[0]);
243 *(uint32_t *) buf = t;
244 buf += 4;
245 } while( --count );
246}
diff --git a/src/stable/md5.h b/src/stable/md5.h
new file mode 100644
index 0000000..b7597fd
--- /dev/null
+++ b/src/stable/md5.h
@@ -0,0 +1,54 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MD5_H
9#define BU_MD5_H
10
11#include "bu/cryptohash.h"
12
13namespace Bu
14{
15 /**
16 * Class for easily calculating MD5 sums of just about any data.
17 * This code is based on some public domain code written by Colin Plumb in
18 * 1993.
19 *@author Mike Buland
20 */
21 class Md5 : public Bu::CryptoHash
22 {
23 public:
24 /** Build an MD5 sum builder. */
25 Md5();
26
27 /** Deconstruct */
28 virtual ~Md5();
29
30 virtual void reset();
31 virtual void setSalt( const Bu::String &sSalt );
32 virtual void addData( const void *sData, int iSize );
33 using Bu::CryptoHash::addData;
34 virtual String getResult();
35 virtual void writeResult( Bu::Stream &sOut );
36
37 private:
38 /**
39 * Compute one block of input data.
40 */
41 void compBlock( uint32_t *lsum, uint32_t *x );
42 void compCap( uint32_t *sumout );
43
44 void _addData( uint8_t *target, int &iCurFill, const void *sData,
45 int iSize );
46 void _toLittleEndian( uint8_t *buf, uint32_t count );
47
48 uint8_t inbuf[64];
49 uint32_t sum[4];
50 uint32_t uBits[2];
51 };
52};
53
54#endif
diff --git a/src/stable/membuf.cpp b/src/stable/membuf.cpp
new file mode 100644
index 0000000..14d0d58
--- /dev/null
+++ b/src/stable/membuf.cpp
@@ -0,0 +1,177 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/membuf.h"
9
10using namespace Bu;
11
12Bu::MemBuf::MemBuf() :
13 nPos( 0 )
14{
15}
16
17Bu::MemBuf::MemBuf( const Bu::String &str ) :
18 sBuf( str ),
19 nPos( 0 )
20{
21}
22
23Bu::MemBuf::~MemBuf()
24{
25}
26
27void Bu::MemBuf::close()
28{
29}
30
31size Bu::MemBuf::read( void *pBuf, size nBytes )
32{
33 if( (size)sBuf.getSize()-(size)nPos < nBytes )
34 nBytes = sBuf.getSize()-nPos;
35
36 memcpy( pBuf, sBuf.getStr()+nPos, nBytes );
37 nPos += nBytes;
38
39 return nBytes;
40}
41
42size Bu::MemBuf::write( const void *pBuf, size nBytes )
43{
44 if( nPos == sBuf.getSize() )
45 {
46 // Easiest, just append the data.
47 sBuf.append( (const char *)pBuf, nBytes );
48 nPos += nBytes;
49 return nBytes;
50 }
51 else
52 {
53 // Trickier, we must do this in two parts, overwrite, then append
54 // Frist, overwrite.
55 size iOver = sBuf.getSize() - nPos;
56 if( iOver > nBytes )
57 iOver = nBytes;
58 memcpy( sBuf.getStr()+nPos, pBuf, iOver );
59 // Then append
60 if( iOver < nBytes )
61 {
62 sBuf.append( ((const char *)pBuf)+iOver, nBytes-iOver );
63 }
64 nPos += nBytes;
65 return nBytes;
66 }
67}
68
69size Bu::MemBuf::tell()
70{
71 return nPos;
72}
73
74void Bu::MemBuf::seek( size offset )
75{
76 nPos += offset;
77 if( nPos < 0 ) nPos = 0;
78 else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize();
79}
80
81void Bu::MemBuf::setPos( size pos )
82{
83 nPos = pos;
84 if( nPos < 0 ) nPos = 0;
85 else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize();
86}
87
88void Bu::MemBuf::setPosEnd( size pos )
89{
90 nPos = sBuf.getSize()-pos;
91 if( nPos < 0 ) nPos = 0;
92 else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize();
93}
94
95bool Bu::MemBuf::isEos()
96{
97 return (nPos == sBuf.getSize());
98}
99
100bool Bu::MemBuf::isOpen()
101{
102 return true;
103}
104
105void Bu::MemBuf::flush()
106{
107}
108
109bool Bu::MemBuf::canRead()
110{
111 return !isEos();
112}
113
114bool Bu::MemBuf::canWrite()
115{
116 return true;
117}
118
119bool Bu::MemBuf::isReadable()
120{
121 return true;
122}
123
124bool Bu::MemBuf::isWritable()
125{
126 return true;
127}
128
129bool Bu::MemBuf::isSeekable()
130{
131 return true;
132}
133
134bool Bu::MemBuf::isBlocking()
135{
136 return true;
137}
138
139void Bu::MemBuf::setBlocking( bool )
140{
141}
142
143void Bu::MemBuf::setSize( size iSize )
144{
145 if( iSize < 0 )
146 iSize = 0;
147 sBuf.setSize( iSize );
148 if( nPos > iSize )
149 nPos = iSize;
150}
151
152Bu::size Bu::MemBuf::getSize() const
153{
154 return sBuf.getSize();
155}
156
157Bu::size Bu::MemBuf::getBlockSize() const
158{
159 return sBuf.getSize();
160}
161
162Bu::String Bu::MemBuf::getLocation() const
163{
164 return "";
165}
166
167Bu::String &Bu::MemBuf::getString()
168{
169 return sBuf;
170}
171
172void Bu::MemBuf::setString( const Bu::String &sNewData )
173{
174 sBuf = sNewData;
175 nPos = 0;
176}
177
diff --git a/src/stable/membuf.h b/src/stable/membuf.h
new file mode 100644
index 0000000..544dc83
--- /dev/null
+++ b/src/stable/membuf.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MEM_BUF_H
9#define BU_MEM_BUF_H
10
11#include <stdint.h>
12
13#include "bu/config.h"
14#include "bu/stream.h"
15#include "bu/string.h"
16
17namespace Bu
18{
19 /**
20 * A memory buffer stream. This provides a read/write stream in memory that
21 * works exactly like a file stream...only in memory. You can seed the
22 * memory buffer with a Bu::String of your own, or start with an empty one.
23 * Due to Bu::String using Bu::SharedCore starting with a string will not
24 * necesarilly cause the MemBuf to make a copy of your memory, but if you're
25 * sure you're not going to need to change the stream then use StaticMemBuf.
26 *@ingroup Streams
27 */
28 class MemBuf : public Stream
29 {
30 public:
31 MemBuf();
32 MemBuf( const Bu::String &str );
33 virtual ~MemBuf();
34
35 virtual void close();
36 virtual size read( void *pBuf, size iBytes );
37
38 virtual size write( const void *pBuf, size iBytes );
39 using Stream::write;
40 virtual size tell();
41 virtual void seek( size offset );
42 virtual void setPos( size pos );
43 virtual void setPosEnd( size pos );
44 virtual bool isEos();
45 virtual bool isOpen();
46 virtual void flush();
47 virtual bool canRead();
48 virtual bool canWrite();
49 virtual bool isReadable();
50 virtual bool isWritable();
51 virtual bool isSeekable();
52 virtual bool isBlocking();
53 virtual void setBlocking( bool bBlocking=true );
54 virtual void setSize( size iSize );
55 virtual size getSize() const;
56 virtual size getBlockSize() const;
57 virtual Bu::String getLocation() const;
58
59 Bu::String &getString();
60 void setString( const Bu::String &sNewData );
61
62 private:
63 Bu::String sBuf;
64 size nPos;
65 };
66}
67
68#endif
diff --git a/src/stable/minicron.cpp b/src/stable/minicron.cpp
new file mode 100644
index 0000000..95cf66b
--- /dev/null
+++ b/src/stable/minicron.cpp
@@ -0,0 +1,477 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/minicron.h"
9
10#include <stdlib.h>
11#include <time.h>
12
13Bu::MiniCron::MiniCron() :
14 jidNext( 1 )
15{
16}
17
18Bu::MiniCron::~MiniCron()
19{
20 while( !hJobs.isEmpty() )
21 {
22 delete hJobs.dequeue();
23 }
24}
25
26bool Bu::MiniCron::hasJobs()
27{
28 return !hJobs.isEmpty();
29}
30
31time_t Bu::MiniCron::getNextRun()
32{
33 if( hasJobs() )
34 return hJobs.peek()->getNextRun();
35 return -1;
36}
37
38time_t Bu::MiniCron::getNextRun( Bu::MiniCron::JobId jid )
39{
40 for( JobHeap::iterator i = hJobs.begin(); i; i++ )
41 {
42 if( (*i)->getId() == jid )
43 {
44 return (*i)->getNextRunTime();
45 }
46 }
47 return -1;
48}
49
50void Bu::MiniCron::poll()
51{
52 time_t tNow = time( NULL );
53
54 while( !hJobs.isEmpty() )
55 {
56 if( hJobs.peek()->getNextRun() <= tNow )
57 {
58 Job *pJob = hJobs.dequeue();
59 pJob->run();
60 if( pJob->bContinue )
61 {
62 hJobs.enqueue( pJob );
63 }
64 else
65 {
66 delete pJob;
67 }
68 }
69 else
70 {
71 break;
72 }
73 }
74}
75
76Bu::MiniCron::JobId Bu::MiniCron::addJob( const Bu::String &sName,
77 Bu::MiniCron::CronSignal sigJob, const Bu::MiniCron::Timer &t )
78{
79 JobId jid = jidNext++;
80 Job *pJob = new Job( sName, jid );
81 pJob->sigJob = sigJob;
82 pJob->pTimer = t.clone();
83 pJob->tNextRun = pJob->pTimer->nextTime();
84 hJobs.enqueue( pJob );
85
86 return jid;
87}
88
89Bu::MiniCron::JobId Bu::MiniCron::addJobOnce( const Bu::String &sName,
90 Bu::MiniCron::CronSignal sigJob, const Bu::MiniCron::Timer &t )
91{
92 JobId jid = jidNext++;
93 Job *pJob = new Job( sName, jid, false );
94 pJob->sigJob = sigJob;
95 pJob->pTimer = t.clone();
96 pJob->tNextRun = pJob->pTimer->nextTime();
97 hJobs.enqueue( pJob );
98
99 return jid;
100}
101
102void Bu::MiniCron::removeJob( JobId jid )
103{
104 Bu::List<Job *> lJobs;
105 while( !hJobs.isEmpty() )
106 {
107 Job *pJob = hJobs.dequeue();
108 if( pJob->getId() == jid )
109 {
110 delete pJob;
111 }
112 else
113 lJobs.append( pJob );
114 }
115
116 for( Bu::List<Job *>::iterator i = lJobs.begin(); i; i++ )
117 {
118 hJobs.enqueue( *i );
119 }
120}
121
122void Bu::MiniCron::runJob( JobId jid, bool bReschedule )
123{
124 Bu::List<Job *> lJobs;
125 while( !hJobs.isEmpty() )
126 {
127 Job *pJob = hJobs.dequeue();
128 if( pJob->getId() == jid )
129 {
130 pJob->run( bReschedule );
131 if( !pJob->bContinue )
132 {
133 delete pJob;
134 break;
135 }
136 lJobs.append( pJob );
137 break;
138 }
139 lJobs.append( pJob );
140 }
141
142 for( Bu::List<Job *>::iterator i = lJobs.begin(); i; i++ )
143 {
144 hJobs.enqueue( *i );
145 }
146}
147
148void Bu::MiniCron::runJob( const Bu::String &sName, bool bReschedule )
149{
150 Bu::List<Job *> lJobs;
151 while( !hJobs.isEmpty() )
152 {
153 Job *pJob = hJobs.dequeue();
154 if( pJob->getName() == sName )
155 {
156 pJob->run( bReschedule );
157 if( !pJob->bContinue )
158 {
159 delete pJob;
160 break;
161 }
162 lJobs.append( pJob );
163 break;
164 }
165 lJobs.append( pJob );
166 }
167
168 for( Bu::List<Job *>::iterator i = lJobs.begin(); i; i++ )
169 {
170 hJobs.enqueue( *i );
171 }
172}
173
174Bu::MiniCron::JobInfoList Bu::MiniCron::getJobInfo()
175{
176 JobInfoList lRet;
177 for( JobHeap::iterator i = hJobs.begin(); i; i++ )
178 {
179 lRet.append(
180 JobInfo( (*i)->getName(), (*i)->getId(), (*i)->getNextRun() )
181 );
182 }
183 lRet.sort();
184 return lRet;
185}
186
187Bu::MiniCron::Job::Job( const Bu::String &sName, JobId jid, bool bRepeat ) :
188 sName( sName ),
189 pTimer( NULL ),
190 bContinue( bRepeat ),
191 jid( jid ),
192 tAdded( time( NULL ) ),
193 iRunCount( 0 )
194{
195}
196
197Bu::MiniCron::Job::~Job()
198{
199 delete pTimer;
200 pTimer = NULL;
201}
202
203void Bu::MiniCron::Job::run( bool bReschedule )
204{
205 iRunCount++;
206 if( bReschedule )
207 tNextRun = pTimer->nextTime();
208 sigJob( *this );
209}
210
211time_t Bu::MiniCron::Job::getNextRun() const
212{
213 return tNextRun;
214}
215
216void Bu::MiniCron::Job::calcNextRun()
217{
218 if( pTimer )
219 tNextRun = pTimer->nextTime();
220}
221
222void Bu::MiniCron::Job::setTimer( const Timer &t )
223{
224 delete pTimer;
225 pTimer = t.clone();
226}
227
228void Bu::MiniCron::Job::stop()
229{
230 bContinue = false;
231}
232
233void Bu::MiniCron::Job::resume()
234{
235 bContinue = true;
236}
237
238Bu::MiniCron::JobId Bu::MiniCron::Job::getId() const
239{
240 return jid;
241}
242
243time_t Bu::MiniCron::Job::getTimeCreated() const
244{
245 return tAdded;
246}
247
248int Bu::MiniCron::Job::getRunCount() const
249{
250 return iRunCount;
251}
252
253time_t Bu::MiniCron::Job::getNextRunTime() const
254{
255 return tNextRun;
256}
257
258Bu::String Bu::MiniCron::Job::getName() const
259{
260 return sName;
261}
262
263Bu::MiniCron::JobInfo::JobInfo( const Bu::String &sName, JobId jid,
264 time_t tNext ) :
265 sName( sName ),
266 jid( jid ),
267 tNext( tNext )
268{
269}
270
271Bu::MiniCron::JobInfo::~JobInfo()
272{
273}
274
275bool Bu::MiniCron::JobInfo::operator<( const JobInfo &rhs ) const
276{
277 return jid < rhs.jid;
278}
279
280Bu::MiniCron::Timer::Timer()
281{
282}
283
284Bu::MiniCron::Timer::~Timer()
285{
286}
287
288Bu::MiniCron::TimerInterval::TimerInterval( time_t tFirst, time_t tInterval ) :
289 tNext( tFirst ),
290 tInterval( tInterval )
291{
292}
293
294Bu::MiniCron::TimerInterval::~TimerInterval()
295{
296}
297
298time_t Bu::MiniCron::TimerInterval::nextTime()
299{
300 time_t tRet = tNext;
301 tNext += tInterval;
302 return tRet;
303}
304
305Bu::MiniCron::TimerBasic::TimerBasic( const Bu::String &s ) :
306 tLast( -1 ),
307 sSpec( s )
308{
309}
310
311Bu::MiniCron::TimerBasic::~TimerBasic()
312{
313}
314
315time_t Bu::MiniCron::TimerBasic::nextTime()
316{
317 if( tLast == -1 )
318 tLast = time( NULL );
319
320 Bu::String::const_iterator i = sSpec.begin();
321 switch( lex( i ) )
322 {
323 case tokDaily:
324 {
325 int iHour = lexInt( i );
326 int iMin = lexInt( i );
327
328 struct tm t;
329 ::memcpy( &t, localtime( &tLast ), sizeof(struct tm) );
330 if( iHour < t.tm_hour ||
331 (iHour == t.tm_hour && iMin <= t.tm_min) )
332 {
333 t.tm_mday++;
334 }
335 t.tm_hour = iHour;
336 t.tm_min = iMin;
337 t.tm_sec = 0;
338 tLast = mktime( &t );
339 }
340 break;
341
342 case tokHourly:
343 {
344 int iMin = lexInt( i );
345
346 struct tm t;
347 ::memcpy( &t, localtime( &tLast ), sizeof(struct tm) );
348 if( iMin <= t.tm_min )
349 t.tm_hour++;
350 t.tm_min = iMin;
351 t.tm_sec = 0;
352 tLast = mktime( &t );
353 }
354 break;
355
356 case tokWeekly:
357 {
358 int iDay = lexInt( i );
359 int iHour = lexInt( i );
360 int iMin = lexInt( i );
361
362 struct tm t;
363 ::memcpy( &t, localtime( &tLast ), sizeof(struct tm) );
364 if( iDay < t.tm_wday ||
365 (iDay == t.tm_wday && iHour < t.tm_hour) ||
366 (iDay == t.tm_wday && iHour == t.tm_hour
367 && iMin <= t.tm_min) )
368 {
369 if( iDay <= t.tm_wday )
370 t.tm_mday += 7 - (t.tm_wday-iDay);
371 else
372 t.tm_mday += 7 - (iDay-t.tm_wday);
373 }
374 else
375 {
376 t.tm_mday += (iDay-t.tm_wday);
377 }
378 t.tm_hour = iHour;
379 t.tm_min = iMin;
380 t.tm_sec = 0;
381 tLast = mktime( &t );
382 }
383 break;
384
385 case tokMonthly:
386 break;
387
388 case tokYearly:
389 break;
390
391 default:
392 break;
393 }
394
395 return tLast;
396}
397
398Bu::MiniCron::TimerBasic::Token Bu::MiniCron::TimerBasic::lex(
399 Bu::String::const_iterator &i )
400{
401 if( !i )
402 {
403 return tokEos;
404 }
405
406 Bu::String::const_iterator b = i;
407
408 for(; b && (*b == ' ' || *b == '\t'); b++ ) { i = b+1; }
409 for(; b && *b != ' ' && *b != '\t'; b++ ) { }
410
411 Bu::String sTok( i, b );
412 i = b;
413
414 if( sTok == "daily" )
415 return tokDaily;
416 else if( sTok == "hourly" )
417 return tokHourly;
418 else if( sTok == "weekly" )
419 return tokWeekly;
420 else if( sTok == "monthly" )
421 return tokMonthly;
422 else if( sTok == "yearly" )
423 return tokYearly;
424 else if( sTok == "sun" )
425 {
426 iVal = 0;
427 return valInt;
428 }
429 else if( sTok == "mon" )
430 {
431 iVal = 1;
432 return valInt;
433 }
434 else if( sTok == "tue" )
435 {
436 iVal = 2;
437 return valInt;
438 }
439 else if( sTok == "wed" )
440 {
441 iVal = 3;
442 return valInt;
443 }
444 else if( sTok == "thu" )
445 {
446 iVal = 4;
447 return valInt;
448 }
449 else if( sTok == "fri" )
450 {
451 iVal = 5;
452 return valInt;
453 }
454 else if( sTok == "sat" )
455 {
456 iVal = 6;
457 return valInt;
458 }
459 else if( sTok[0] >= '0' && sTok[0] <= '9' )
460 {
461 iVal = strtol( sTok.getStr(), NULL, 0 );
462 return valInt;
463 }
464
465 return tokErr;
466}
467
468int Bu::MiniCron::TimerBasic::lexInt( Bu::String::const_iterator &i )
469{
470 Token t = lex( i );
471 if( t == tokEos )
472 return 0;
473 if( t != valInt )
474 throw Bu::ExceptionBase("Expected int, got something else.");
475 return iVal;
476}
477
diff --git a/src/stable/minicron.h b/src/stable/minicron.h
new file mode 100644
index 0000000..0d1cb62
--- /dev/null
+++ b/src/stable/minicron.h
@@ -0,0 +1,336 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MINICRON_H
9#define BU_MINICRON_H
10
11#include "bu/signals.h"
12#include "bu/heap.h"
13#include "bu/string.h"
14
15#include <time.h>
16
17namespace Bu
18{
19 /**
20 * A simple cron like system designed to be embedded in any program. This
21 * class creates a simple cron system that can run any number of jobs at
22 * customizable intervals or schedules. It does not support some of the
23 * more complex scheduling that some cron systems can do such as load
24 * balancing directly, but this could be done on the job side.
25 *
26 * This system is synchronous, it does not use any threads on it's own, but
27 * it is threadsafe, so a cron thread could be created if desired.
28 *
29 * The operation is fairly simple, jobs can be added at any time, and use
30 * any timer they would like, even custom timers. When it is time for a
31 * job to be run it signals the slot provided when the job was added. Every
32 * job slot recieves a handle to the job object so that it may control it's
33 * own lifetime and get information about itself. In addition, every job
34 * is assigned a unique ID that can be used to control it's operation
35 * at any time.
36 *
37 * By default a job will continually reschedule itself after being run
38 * unless it calls stop() on it's job object, it is removed using
39 * removeJob() on the cron object, or it is added with addJobOnce.
40 *
41 *@todo A minor change to the job execution system could allow a Timer to
42 * defer or reschedule execution instead of the job executing. This would,
43 * in effect, allow us to do every type of interesting scheduling that
44 * systems like fcron offer, including time constrained load-balanced
45 * execution.
46 */
47 class MiniCron
48 {
49 public:
50 class Job;
51 class Timer;
52 typedef Bu::Signal1<void, Bu::MiniCron::Job &> CronSignal;
53 typedef int JobId;
54
55 MiniCron();
56 virtual ~MiniCron();
57
58 /**
59 * Tells you if there are jobs registered in the MiniCron.
60 *@returns true if there are jobs, false otherwise.
61 */
62 virtual bool hasJobs();
63
64 /**
65 * If there are jobs, tells you the time the next one will execute.
66 *@returns The timestamp that the next job will execute at.
67 */
68 virtual time_t getNextRun();
69
70 /**
71 * Tells you the time the job matching jid will run next.
72 *@returns The timestamp that the job jid will next run.
73 */
74 virtual time_t getNextRun( JobId jid );
75
76 /**
77 * Call this regularly to execute all jobs that should be executed.
78 * This will loop until all jobs who's run time match the current time
79 * or are below the current time (we've missed them).
80 * If there is nothing to run, the runtime of this funcion is constant,
81 * it is very fast. Otherwise it executes at log(N) per job run,
82 * O(N*log(N)).
83 */
84 virtual void poll();
85
86 /**
87 * Add a job for repeated scheduling. Pass in a slot to signal, and a
88 * Timer object to use to do the scheduling. This function returns a
89 * JobId which can be used at a later time to control the execution of
90 * the job.
91 */
92 virtual JobId addJob( const Bu::String &sName, CronSignal sigJob,
93 const Timer &t );
94
95 /**
96 * Add a job for one time scheduling. Pass in a slot to signal, and a
97 * Timer object to use to schodule the one run of this job. This
98 * function returns a JobId which can be used at a later time to control
99 * the execution of the job.
100 */
101 virtual JobId addJobOnce( const Bu::String &sName, CronSignal sigJob,
102 const Timer &t );
103
104 /**
105 * Remove a job, preventing all future runs of the job. If there is no
106 * job matching the given JobId then nothing will happen. However, this
107 * function is relatively expensive compared to the others in this class
108 * and has a worse case runtime of 2*N*log(N), still not that bad, and
109 * a O(N*log(N)).
110 */
111 virtual void removeJob( JobId jid );
112
113 /**
114 * Executes the job specified right now. If bReschedule is true then
115 * the job is then removed from the queue and rescheduled as though
116 * it's time had come naturally to be run. Otherwise, it's run without
117 * interrupting the normal schedule.
118 */
119 virtual void runJob( JobId jid, bool bReschedule=false );
120
121 /**
122 * Executes the job specified right now. If bReschedule is true then
123 * the job is then removed from the queue and rescheduled as though
124 * it's time had come naturally to be run. Otherwise, it's run without
125 * interrupting the normal schedule.
126 */
127 virtual void runJob( const Bu::String &sName, bool bReschedule=false );
128
129 class JobInfo
130 {
131 public:
132 JobInfo( const Bu::String &sName, JobId jid, time_t tNext );
133 virtual ~JobInfo();
134
135 bool operator<( const JobInfo &rhs ) const;
136
137 Bu::String sName;
138 JobId jid;
139 time_t tNext;
140 };
141 typedef Bu::List<JobInfo> JobInfoList;
142
143 JobInfoList getJobInfo();
144
145 /**
146 * The baseclass for timer/schedulers for MiniCron jobs. Classes that
147 * inherit from this are used to determine when jobs will run and at
148 * what interval.
149 */
150 class Timer
151 {
152 public:
153 Timer();
154 virtual ~Timer();
155
156 /**
157 * Called by MiniCron when each job is run to determine the next
158 * time that a job should be run. When a job is run, this function
159 * is actually called before the job is executed again so that the
160 * job can tell when the next time it will be run will be.
161 */
162 virtual time_t nextTime()=0;
163
164 /**
165 * This function should return a copy of the child class.
166 */
167 virtual Timer *clone() const = 0;
168 };
169
170 /**
171 * Execute the job every tInterval seconds, also you can delay the
172 * first run by a different amount of time from the job's creation.
173 */
174 class TimerInterval : public Timer
175 {
176 public:
177 TimerInterval( time_t tFirst, time_t tInterval );
178 virtual ~TimerInterval();
179
180 virtual time_t nextTime();
181 virtual Timer *clone() const
182 { return new TimerInterval( *this ); }
183 private:
184 time_t tNext;
185 time_t tInterval;
186 };
187
188 /**
189 * A much more general timer class that can be used for much more
190 * "cron-like" functionality. The constructor takes a string that
191 * describes the times that the job should be run. At the moment the
192 * following schemes are understood:
193 *
194 * "daily [hour] [minute]"
195 * "hourly [minute]"
196 * "weekly [day] [hour] [minute]"
197 *
198 * In these examples each word in [brackets] represents a number that
199 * matches the data type in the brackets. [day] is the number of days
200 * since sunday, 0-6. You can also use lowercase three character
201 * abbreviations for the day names.
202 *
203 * Many more forms follow.
204 */
205 class TimerBasic : public Timer
206 {
207 public:
208 TimerBasic( const Bu::String &s );
209 virtual ~TimerBasic();
210
211 virtual time_t nextTime();
212 virtual Timer *clone() const
213 { return new TimerBasic( *this ); }
214
215 private:
216 enum Token
217 {
218 tokDaily,
219 tokHourly,
220 tokWeekly,
221 tokMonthly,
222 tokYearly,
223 valInt,
224 tokErr,
225 tokEos
226 };
227 Token lex( Bu::String::const_iterator &i );
228 int lexInt( Bu::String::const_iterator &i );
229 int iVal; //< A temp variable for parsing.
230 time_t tLast;
231 Bu::String sSpec;
232 };
233
234 /**
235 * Represents a MiniCron Job. This class is used for both internal
236 * job management as well as job slot interaction and control. Objects
237 * of this class are passed into the slots that are signaled when a job
238 * is executed.
239 */
240 class Job
241 {
242 friend class Bu::MiniCron;
243 private:
244 Job( const Bu::String &sName, JobId jid, bool bRepeat=true );
245 virtual ~Job();
246
247 public:
248
249 /**
250 * Execute this job once, increment the runcount and schedule the
251 * next occurance of it.
252 */
253 void run( bool bReschedule=true );
254
255 /**
256 * Get the time this job will next run.
257 */
258 time_t getNextRun() const;
259
260 /**
261 * Compute the time this job will next run.
262 */
263 void calcNextRun();
264
265 /**
266 * Replace the current job timer with a new one, this will trigger
267 * a re-schedule.
268 */
269 void setTimer( const Timer &t );
270
271 /**
272 * Stop execution of this job, never execute this job again.
273 */
274 void stop();
275
276 /**
277 * Undo a previous stop. This will cause a job that has been
278 * stopped or even added with addJobOnce to be set for repeated
279 * scheduling.
280 */
281 void resume();
282
283 /**
284 * Get the unique ID of this job.
285 */
286 JobId getId() const;
287
288 /**
289 * Get the timestamp this job was created.
290 */
291 time_t getTimeCreated() const;
292
293 /**
294 * Get the current run count of this job, how many times it has been
295 * executed. This is incremented before the slot is signaled.
296 */
297 int getRunCount() const;
298
299 /**
300 * Get the next time that this job will be run. Certain timers may
301 * have the ability to delay job executions, so this is the earliest
302 * time that the job may run.
303 */
304 time_t getNextRunTime() const;
305
306 /**
307 * Gets the name that was set when the job was created.
308 */
309 Bu::String getName() const;
310
311 private:
312 Bu::String sName;
313 CronSignal sigJob;
314 time_t tNextRun;
315 Timer *pTimer;
316 bool bContinue;
317 JobId jid;
318 time_t tAdded;
319 int iRunCount;
320 };
321
322 private:
323 struct JobPtrCmp
324 {
325 bool operator()( const Job *pLeft, const Job *pRight )
326 {
327 return pLeft->tNextRun < pRight->tNextRun;
328 }
329 };
330 typedef Bu::Heap<Job *, JobPtrCmp> JobHeap;
331 JobHeap hJobs;
332 JobId jidNext;
333 };
334};
335
336#endif
diff --git a/src/stable/multiserver.cpp b/src/stable/multiserver.cpp
new file mode 100644
index 0000000..bd598ed
--- /dev/null
+++ b/src/stable/multiserver.cpp
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/multiserver.h"
9#include "bu/protocol.h"
10#include "bu/client.h"
11
12#include "bu/config.h"
13
14Bu::MultiServer::MultiServer()
15{
16}
17
18Bu::MultiServer::~MultiServer()
19{
20}
21
22void Bu::MultiServer::addProtocol( Bu::Protocol *(*proc)(), int iPort,
23 int nPoolSize )
24{
25 hProtos[iPort] = proc;
26 addPort( iPort, nPoolSize );
27}
28
29void Bu::MultiServer::addProtocol( Protocol *(*proc)(), const String &sAddr,
30 int iPort, int nPoolSize )
31{
32 hProtos[iPort] = proc;
33 addPort( sAddr, iPort, nPoolSize );
34}
35
36void Bu::MultiServer::onNewConnection( Bu::Client *pClient, int nPort )
37{
38 pClient->setProtocol( hProtos.get( nPort )() );
39}
40
41void Bu::MultiServer::onClosedConnection( Bu::Client *pClient )
42{
43 delete pClient->getProtocol();
44}
45
46void Bu::MultiServer::shutdown()
47{
48 Bu::Server::shutdown();
49}
50
51void Bu::MultiServer::tick()
52{
53 Bu::Server::tick();
54}
55
diff --git a/src/stable/multiserver.h b/src/stable/multiserver.h
new file mode 100644
index 0000000..e3b3ec3
--- /dev/null
+++ b/src/stable/multiserver.h
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MULTI_SERVER_H
9#define BU_MULTI_SERVER_H
10
11#include "bu/server.h"
12#include "bu/hash.h"
13
14namespace Bu
15{
16 class Protocol;
17 class Client;
18
19 template<class T>
20 Protocol *genProtocol()
21 {
22 return new T;
23 }
24
25 class MultiServer : protected Server
26 {
27 public:
28 MultiServer();
29 virtual ~MultiServer();
30
31 void addProtocol( Protocol *(*proc)(), int iPort, int nPoolSize=40 );
32 void addProtocol( Protocol *(*proc)(), const String &sAddr, int iPort,
33 int nPoolSize=40 );
34
35 void scan()
36 {
37 Server::scan();
38 }
39
40 void setTimeout( int nTimeoutSec, int nTimeoutUSec=0 )
41 {
42 Server::setTimeout( nTimeoutSec, nTimeoutUSec );
43 }
44
45 virtual void onNewConnection( Client *pClient, int nPort );
46 virtual void onClosedConnection( Client *pClient );
47
48 void shutdown();
49
50 void tick();
51
52 private:
53 Bu::Hash<int, Protocol *(*)()> hProtos;
54 };
55}
56
57#endif
diff --git a/src/stable/mutex.cpp b/src/stable/mutex.cpp
new file mode 100644
index 0000000..dbaaece
--- /dev/null
+++ b/src/stable/mutex.cpp
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/mutex.h"
9
10Bu::Mutex::Mutex()
11{
12 pthread_mutex_init( &mutex, NULL );
13}
14
15Bu::Mutex::~Mutex()
16{
17 pthread_mutex_destroy( &mutex );
18}
19
20int Bu::Mutex::lock()
21{
22 return pthread_mutex_lock( &mutex );
23}
24
25int Bu::Mutex::unlock()
26{
27 return pthread_mutex_unlock( &mutex );
28}
29
30int Bu::Mutex::trylock()
31{
32 return pthread_mutex_trylock( &mutex );
33}
34
diff --git a/src/stable/mutex.h b/src/stable/mutex.h
new file mode 100644
index 0000000..b5c8b7a
--- /dev/null
+++ b/src/stable/mutex.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MUTEX_H
9#define BU_MUTEX_H
10
11#include <pthread.h>
12
13namespace Bu
14{
15 /**
16 * Simple mutex wrapper. Currently this doesn't do anything extra for you
17 * except keep all of the functionality together in an OO sorta' way and
18 * keep you from having to worry about cleaning up your mutexes properly,
19 * or initing them.
20 *@ingroup Threading
21 */
22 class Mutex
23 {
24 public:
25 /**
26 * Create an unlocked mutex.
27 */
28 Mutex();
29
30 /**
31 * Destroy a mutex. This can only be done when a mutex is unlocked.
32 * Failure to unlock before destroying a mutex object could cause it to
33 * wait for the mutex to unlock, the odds of which are usually farily
34 * low at deconstruction time.
35 */
36 ~Mutex();
37
38 /**
39 * Lock the mutex. This causes all future calls to lock on this
40 * instance of mutex to block until the first thread that called mutex
41 * unlocks it. At that point the next thread that called lock will get
42 * a chance to go to work. Because of the nature of a mutex lock it is
43 * a very bad idea to do any kind of serious or rather time consuming
44 * computation within a locked section. This can cause thread-deadlock
45 * and your program may hang.
46 */
47 int lock();
48
49 /**
50 * Unlock the mutex. This allows the next thread that asked for a lock
51 * to lock the mutex and continue with execution.
52 */
53 int unlock();
54
55 /**
56 * Try to lock the mutex. This is the option to go with if you cannot
57 * avoid putting lengthy operations within a locked section. trylock
58 * will attempt to lock the mutex, if the mutex is already locked this
59 * function returns immediately with an error code.
60 */
61 int trylock();
62
63 protected:
64 pthread_mutex_t mutex; /**< The internal mutex reference. */
65 };
66}
67
68#endif
diff --git a/src/stable/mutexlocker.cpp b/src/stable/mutexlocker.cpp
new file mode 100644
index 0000000..90b730e
--- /dev/null
+++ b/src/stable/mutexlocker.cpp
@@ -0,0 +1,24 @@
1#include "bu/mutexlocker.h"
2#include "bu/mutex.h"
3
4Bu::MutexLocker::MutexLocker( Bu::Mutex &mu ) :
5 mu( mu )
6{
7 mu.lock();
8}
9
10Bu::MutexLocker::~MutexLocker()
11{
12 mu.unlock();
13}
14
15void Bu::MutexLocker::unlock()
16{
17 mu.unlock();
18}
19
20void Bu::MutexLocker::relock()
21{
22 mu.lock();
23}
24
diff --git a/src/stable/mutexlocker.h b/src/stable/mutexlocker.h
new file mode 100644
index 0000000..7c3c97e
--- /dev/null
+++ b/src/stable/mutexlocker.h
@@ -0,0 +1,21 @@
1#ifndef BU_MUTEX_LOCKER_H
2#define BU_MUTEX_LOCKER_H
3
4namespace Bu
5{
6 class Mutex;
7 class MutexLocker
8 {
9 public:
10 MutexLocker( Mutex &mu );
11 virtual ~MutexLocker();
12
13 void unlock();
14 void relock();
15
16 private:
17 Mutex &mu;
18 };
19};
20
21#endif
diff --git a/src/stable/nullstream.cpp b/src/stable/nullstream.cpp
new file mode 100644
index 0000000..9552cc5
--- /dev/null
+++ b/src/stable/nullstream.cpp
@@ -0,0 +1,127 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/nullstream.h"
9
10Bu::NullStream::NullStream() :
11 sRead( 0 ),
12 sWrote( 0 )
13{
14}
15
16Bu::NullStream::~NullStream()
17{
18}
19
20void Bu::NullStream::close()
21{
22 sRead = sWrote = 0;
23}
24
25Bu::size Bu::NullStream::read( void *pBuf, Bu::size nBytes )
26{
27 memset( pBuf, 0, nBytes );
28 sRead += nBytes;
29 return nBytes;
30}
31
32Bu::String Bu::NullStream::readLine()
33{
34 sRead++;
35 return Bu::String("\0", 1 );
36}
37
38Bu::size Bu::NullStream::write( const void *, Bu::size nBytes )
39{
40 sWrote += nBytes;
41 return nBytes;
42}
43
44Bu::size Bu::NullStream::tell()
45{
46 return sRead + sWrote;
47}
48
49void Bu::NullStream::seek( Bu::size )
50{
51}
52
53void Bu::NullStream::setPos( Bu::size )
54{
55}
56
57void Bu::NullStream::setPosEnd( Bu::size )
58{
59}
60
61bool Bu::NullStream::isEos()
62{
63 return false;
64}
65
66bool Bu::NullStream::isOpen()
67{
68 return true;
69}
70
71void Bu::NullStream::flush()
72{
73}
74
75bool Bu::NullStream::canRead()
76{
77 return true;
78}
79
80bool Bu::NullStream::canWrite()
81{
82 return true;
83}
84
85bool Bu::NullStream::isReadable()
86{
87 return true;
88}
89
90bool Bu::NullStream::isWritable()
91{
92 return true;
93}
94
95bool Bu::NullStream::isSeekable()
96{
97 return false;
98}
99
100bool Bu::NullStream::isBlocking()
101{
102 return true;
103}
104
105void Bu::NullStream::setBlocking( bool )
106{
107}
108
109void Bu::NullStream::setSize( Bu::size )
110{
111}
112
113Bu::size Bu::NullStream::getSize() const
114{
115 return 0;
116}
117
118Bu::size Bu::NullStream::getBlockSize() const
119{
120 return 0;
121}
122
123Bu::String Bu::NullStream::getLocation() const
124{
125 return "";
126}
127
diff --git a/src/stable/nullstream.h b/src/stable/nullstream.h
new file mode 100644
index 0000000..9b75332
--- /dev/null
+++ b/src/stable/nullstream.h
@@ -0,0 +1,67 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_NULL_STREAM_H
9#define BU_NULL_STREAM_H
10
11#include "bu/stream.h"
12
13namespace Bu
14{
15 /**
16 * Works a lot like /dev/null on *nix style systems. This class allows
17 * infinite reading and writing. All operatorns "succeed" even if they
18 * don't seem to do anything. This is great for testing writing code or
19 * doing dry runs. When reading, it will produce NULL bytes, so any
20 * application that would like the ability to produce null streams as a
21 * snap-in replacement for any other Bu::Stream, this is the right option.
22 *
23 * As an added feature, the NullStream will track how many bytes it was
24 * asked to read and write, allowing you to use it to determine how many
25 * bytes a write opretion would use without actually writing anything.
26 */
27 class NullStream : public Bu::Stream
28 {
29 public:
30 NullStream();
31 virtual ~NullStream();
32
33 virtual void close();
34 virtual Bu::size read( void *pBuf, Bu::size nBytes );
35 virtual Bu::String readLine();
36 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
37 using Bu::Stream::write;
38 virtual Bu::size tell();
39 virtual void seek( Bu::size offset );
40 virtual void setPos( Bu::size pos );
41 virtual void setPosEnd( Bu::size pos );
42 virtual bool isEos();
43 virtual bool isOpen();
44 virtual void flush();
45 virtual bool canRead();
46 virtual bool canWrite();
47 virtual bool isReadable();
48 virtual bool isWritable();
49 virtual bool isSeekable();
50 virtual bool isBlocking();
51 virtual void setBlocking( bool bBlocking=true );
52 virtual void setSize( Bu::size iSize );
53
54 virtual size getSize() const;
55 virtual size getBlockSize() const;
56 virtual Bu::String getLocation() const;
57
58 Bu::size getBytesRead() { return sRead; }
59 Bu::size getByetsWritten() { return sWrote; }
60
61 private:
62 Bu::size sRead;
63 Bu::size sWrote;
64 };
65};
66
67#endif
diff --git a/src/stable/optparser.cpp b/src/stable/optparser.cpp
new file mode 100644
index 0000000..050232c
--- /dev/null
+++ b/src/stable/optparser.cpp
@@ -0,0 +1,492 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/optparser.h"
9#include "bu/sio.h"
10using namespace Bu;
11
12#include <stdlib.h>
13
14Bu::OptParser::OptParser()
15{
16}
17
18Bu::OptParser::~OptParser()
19{
20}
21
22void Bu::OptParser::parse( int argc, char **argv )
23{
24 for( int j = 1; j < argc; j++ )
25 {
26 if( argv[j][0] == '-' )
27 {
28 // Now we're on to something, which kind is it?
29 if( argv[j][1] == '-' )
30 {
31 int iEPos;
32 for( iEPos = 2; argv[j][iEPos] != '\0' &&
33 argv[j][iEPos] != '='; iEPos++ ) { }
34
35 Bu::String sOpt;
36 int iCount = argc-j;
37 Bu::String sExtraParam;
38 if( argv[j][iEPos] == '=' )
39 {
40 sOpt.set( argv[j]+2, iEPos-2 );
41 iCount++;
42 sExtraParam.set( argv[j]+iEPos+1 );
43 }
44 else
45 {
46 sOpt.set( argv[j]+2 );
47 }
48 if( !hlOption.has( sOpt ) )
49 {
50 optionError( "--" + sOpt );
51 }
52 else
53 {
54 // Long param, cool, that's easy, first search for =
55 Option *pOpt = hlOption.get( sOpt );
56 if( pOpt->sUsed )
57 {
58 Bu::StrArray aParams( iCount );
59 aParams.append( sOpt );
60 if( sExtraParam.isSet() )
61 {
62 aParams.append( argv[j]+iEPos+1 );
63 }
64 for( int k = j+1; k < argc; k++ )
65 {
66 aParams.append( argv[k] );
67 }
68 j += pOpt->sUsed( aParams );
69 }
70 else if( pOpt->pProxy )
71 {
72 if( pOpt->sOverride.isSet() )
73 {
74 pOpt->pProxy->setValue( pOpt->sOverride );
75 }
76 else if( sExtraParam.isSet() )
77 {
78 pOpt->pProxy->setValueFromStr( sExtraParam );
79 }
80 else if( argv[j+1] != '\0' )
81 {
82 pOpt->pProxy->setValueFromStr( argv[j+1] );
83 j++;
84 }
85 }
86 }
87 }
88 else
89 {
90 int iCPos;
91 for( iCPos = 1; argv[j][iCPos] != '\0'; iCPos++ )
92 {
93 if( !hsOption.has( argv[j][iCPos] ) )
94 {
95 Bu::String sOpt("-");
96 sOpt += argv[j][iCPos];
97 optionError( sOpt );
98 }
99 else
100 {
101 Option *pOpt = hsOption.get( argv[j][iCPos] );
102 char buf[2] = {argv[j][iCPos], '\0'};
103 if( pOpt->sUsed )
104 {
105 Bu::StrArray aParams( argc-j+1 );
106 aParams.append( buf );
107 int iMod = 0;
108 if( argv[j][iCPos+1] != '\0' )
109 {
110 aParams.append( argv[j]+iCPos+1 );
111 iMod = -1;
112 }
113 for( int k = j+1; k < argc; k++ )
114 {
115 aParams.append( argv[k] );
116 }
117 int iUsed = pOpt->sUsed( aParams );
118 if( iUsed > 0 )
119 {
120 j += iUsed + iMod;
121 break;
122 }
123 }
124 else if( pOpt->pProxy )
125 {
126 if( pOpt->sOverride.isSet() )
127 {
128 pOpt->pProxy->setValue( pOpt->sOverride );
129 }
130 else if( argv[j][iCPos+1] != '\0' )
131 {
132 pOpt->pProxy->setValueFromStr(
133 argv[j]+iCPos+1
134 );
135 break;
136 }
137 else if( argv[j+1] )
138 {
139 pOpt->pProxy->setValueFromStr(
140 argv[j+1]
141 );
142 j++;
143 break;
144 }
145 }
146 }
147 }
148 }
149 }
150 else
151 {
152 if( !sNonOption )
153 {
154 optionError( argv[j] );
155 }
156 else
157 {
158 int iCount = argc-j;
159 Bu::StrArray aParams( iCount );
160 for( int k = j; k < argc; k++ )
161 {
162 aParams.append( argv[k] );
163 }
164 j += sNonOption( aParams );
165 }
166 }
167 }
168}
169
170void Bu::OptParser::parse( const Bu::String &sLine )
171{
172 Bu::String sCmd = sLine.clone();
173 int iParams = 0;
174 bool bInGap = true;
175 bool bInQuote = false;
176 for( Bu::String::iterator i = sCmd.begin(); i; i++ )
177 {
178 if( bInQuote == false && (*i == ' ' || *i == '\t') )
179 {
180 if( bInGap == false )
181 {
182 bInGap = true;
183 }
184 }
185 else if( *i == '"' )
186 {
187 bInQuote = !bInQuote;
188 }
189 else
190 {
191 if( bInGap )
192 {
193 iParams++;
194 bInGap = false;
195 }
196 }
197 }
198
199 bInQuote = false;
200 bInGap = true;
201 char **asParam = new char*[iParams];
202 iParams = 0;
203 for( char *i = sCmd.getStr(); *i; i++ )
204 {
205 if( bInQuote == false && (*i == ' ' || *i == '\t') )
206 {
207 if( bInGap == false )
208 {
209 bInGap = true;
210 *i = '\0';
211 }
212 }
213 else if( *i == '"' )
214 {
215 bInQuote = !bInQuote;
216 }
217 else
218 {
219 if( bInGap )
220 {
221 asParam[iParams++] = i;
222 bInGap = false;
223 }
224 }
225 }
226
227 parse( iParams, asParam );
228
229 delete[] asParam;
230}
231
232void Bu::OptParser::addOption( const Option &opt )
233{
234 lOption.append( opt );
235 if( opt.cOpt != '\0' )
236 hsOption.insert( opt.cOpt, &lOption.last() );
237 if( opt.sOpt.isSet() )
238 hlOption.insert( opt.sOpt, &lOption.last() );
239}
240
241void Bu::OptParser::setOverride( char cOpt, const Bu::Variant &sOverride )
242{
243 hsOption.get( cOpt )->sOverride = sOverride;
244}
245
246void Bu::OptParser::setOverride( const Bu::String &sOpt, const Bu::Variant &sOverride )
247{
248 hlOption.get( sOpt )->sOverride = sOverride;
249}
250
251void Bu::OptParser::setHelpDefault( const Bu::String &sOpt, const Bu::String &sTxt )
252{
253 hlOption.get( sOpt )->sHelpDefault = sTxt;
254}
255
256void Bu::OptParser::addHelpOption( char c, const Bu::String &s, const Bu::String &sHelp )
257{
258 Option o;
259 o.sUsed = slot( this, &OptParser::optHelp );
260 o.cOpt = c;
261 o.sOpt = s;
262 o.sHelp = sHelp;
263 addOption( o );
264}
265
266void Bu::OptParser::addHelpBanner( const Bu::String &sText, bool bFormatted )
267{
268 Banner b;
269 b.sText = sText;
270 b.bFormatted = bFormatted;
271 if( lOption.getSize() > 0 )
272 {
273 for( b.iAfter = lOption.begin(); b.iAfter+1; b.iAfter++ ) { }
274 }
275 lBanner.append( b );
276}
277
278int Bu::OptParser::optHelp( StrArray /*aParams*/ )
279{
280 bool bHasShort = false;
281 int iMaxWidth = 0;
282 int iScrWidth = 80;
283 char *env = getenv("COLUMNS");
284 if( env )
285 iScrWidth = strtol( env, NULL, 10 );
286 for( OptionList::iterator i = lOption.begin(); i; i++ )
287 {
288 if( (*i).cOpt != '\0' )
289 bHasShort = true;
290 int lOptSize = (*i).sOpt.getSize() + (*i).sHelpDefault.getSize();
291 if( (*i).sOpt.isSet() && iMaxWidth < lOptSize )
292 iMaxWidth = lOptSize;
293 }
294 int iIndent = 4;
295 if( bHasShort )
296 iIndent += 4;
297 if( iMaxWidth > 0 )
298 iIndent += 4 + iMaxWidth;
299
300 BannerList::iterator iBanner;
301 for( iBanner = lBanner.begin(); iBanner; iBanner++ )
302 {
303 if( (*iBanner).iAfter )
304 break;
305
306 if( (*iBanner).bFormatted )
307 sio << format( (*iBanner).sText, iScrWidth-1, 0 );
308 else
309 sio << (*iBanner).sText;
310 sio << sio.nl;
311 }
312 for( OptionList::iterator i = lOption.begin(); i; i++ )
313 {
314 sio << " ";
315 if( bHasShort )
316 {
317 if( (*i).cOpt == '\0' )
318 sio << " ";
319 else
320 sio << "-" << (*i).cOpt;
321 sio << " ";
322 }
323 if( iMaxWidth > 0 )
324 {
325 if( (*i).sOpt.isSet() )
326 {
327 sio << "--" << Fmt(iMaxWidth, Fmt::Left)
328 << (*i).sOpt + (*i).sHelpDefault;
329 }
330 else
331 {
332 sio << " " << Fmt(iMaxWidth) << "";
333 }
334 sio << " ";
335 }
336 sio << format( (*i).sHelp, iScrWidth-iIndent-1, iIndent );
337 sio << sio.nl;
338
339 for( ; iBanner; iBanner++ )
340 {
341 if( (*iBanner).iAfter != i )
342 break;
343
344 if( (*iBanner).bFormatted )
345 sio << format( (*iBanner).sText, iScrWidth-1, 0 );
346 else
347 sio << (*iBanner).sText;
348 sio << sio.nl;
349 }
350 }
351 exit( 0 );
352 return 0;
353}
354
355void Bu::OptParser::optionError( const Bu::String &sOption )
356{
357 sio << "Unregcognized option discovered: " << sOption << sio.nl << sio.nl;
358 exit( 1 );
359}
360
361void Bu::OptParser::setNonOption( OptionSignal sSignal )
362{
363 sNonOption = sSignal;
364}
365
366Bu::String Bu::OptParser::format( const Bu::String &sIn, int iWidth,
367 int iIndent )
368{
369 Bu::String sOut;
370 Bu::String sIndent;
371 for( int j = 0; j < iIndent; j++ )
372 sIndent.append(" ", 1);
373 bool bFirst = true;
374 int iSpaceCount = 0;
375 bool bSpace = false;
376 int iPrevLineLen;
377 int iLineLen = 0;
378 Bu::String::const_iterator iLastSpace, iStart;
379 for( Bu::String::const_iterator i = iLastSpace = iStart = sIn.begin(); i; i++ )
380 {
381 if( *i == ' ' )
382 {
383 if( bSpace == false )
384 {
385 iLastSpace = i;
386 iSpaceCount++;
387 bSpace = true;
388 iPrevLineLen = iLineLen;
389 }
390 }
391 else
392 {
393 bSpace = false;
394 }
395 iLineLen++;
396
397 if( iLineLen >= iWidth )
398 {
399 iSpaceCount--;
400 if( bFirst == true )
401 bFirst = false;
402 else
403 sOut += sIndent;
404 int iExtraSpaces = iWidth-iPrevLineLen;
405 bSpace = false;
406 float fFill = 0.0;
407 int iSubSpaceCount = 0;
408 float fAdd = ((float)iExtraSpaces/(float)iSpaceCount);
409 for( Bu::String::const_iterator k = iStart; k != iLastSpace; k++ )
410 {
411 sOut += *k;
412 if( *k == ' ' )
413 {
414 if( bSpace == false && iExtraSpaces > 0 )
415 {
416 bSpace = true;
417 fFill += fAdd;
418 iSubSpaceCount++;
419 for( int sp = 0; sp < (int)(fFill); sp++ )
420 {
421 sOut += ' ';
422 iExtraSpaces--;
423 }
424 fFill -= (int)fFill;
425 if( iSubSpaceCount == iSpaceCount && iExtraSpaces > 0 )
426 {
427 for(; iExtraSpaces > 0; iExtraSpaces-- )
428 {
429 sOut += ' ';
430 }
431 }
432 }
433 }
434 else
435 bSpace = false;
436 }
437 //sOut.append( iStart, iLastSpace );
438 sOut.append("\n");
439 for(; iLastSpace && *iLastSpace == ' '; iLastSpace++ ) { }
440 iStart = i = iLastSpace;
441 bSpace = false;
442 iLineLen = 1;
443 iSpaceCount = 0;
444 }
445 }
446 if( !bFirst )
447 sOut += sIndent;
448 sOut.append( iStart );
449 return sOut;
450}
451
452
453//
454// Code for Bu::OptParser::_ValueProxy
455//
456
457Bu::OptParser::_ValueProxy::_ValueProxy()
458{
459}
460
461Bu::OptParser::_ValueProxy::~_ValueProxy()
462{
463}
464
465//
466// Code for Bu::OptParser::Option
467//
468
469Bu::OptParser::Option::Option() :
470 cOpt( '\0' ),
471 pProxy( NULL )
472{
473}
474
475Bu::OptParser::Option::Option( const Option &rSrc ) :
476 cOpt( rSrc.cOpt ),
477 sOpt( rSrc.sOpt ),
478 sHelp( rSrc.sHelp ),
479 sUsed( rSrc.sUsed ),
480 pProxy( NULL ),
481 sOverride( rSrc.sOverride )
482{
483 if( rSrc.pProxy )
484 pProxy = rSrc.pProxy->clone();
485}
486
487Bu::OptParser::Option::~Option()
488{
489 delete pProxy;
490 pProxy = NULL;
491}
492
diff --git a/src/stable/optparser.h b/src/stable/optparser.h
new file mode 100644
index 0000000..f2fe531
--- /dev/null
+++ b/src/stable/optparser.h
@@ -0,0 +1,223 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_OPT_PARSER_H
9#define BU_OPT_PARSER_H
10
11#include "bu/string.h"
12#include "bu/list.h"
13#include "bu/hash.h"
14#include "bu/signals.h"
15#include "bu/array.h"
16#include "bu/membuf.h"
17#include "bu/formatter.h"
18#include "bu/variant.h"
19
20namespace Bu
21{
22 typedef Bu::Array<Bu::String> StrArray;
23
24 /**
25 * POSIX/Gnu style command line parser. Handles long and short options in
26 * a variety of fun and useful ways, along with singal based callbacks and
27 * automatic variable setting. It's pretty easy to use, and very flexible.
28 *
29 * OptParser supports it's own builtin help mechanism which automatically
30 * enumerates the available options and their help in a well formatted and
31 * easy to read way, automatically formatting your help text per option and
32 * allows for addition "help banners" which can be placed wherever you
33 * would like.
34 */
35 class OptParser
36 {
37 private:
38 class _ValueProxy
39 {
40 public:
41 _ValueProxy();
42 virtual ~_ValueProxy();
43
44 virtual void setValueFromStr( const Bu::String & )=0;
45 virtual void setValue( const Bu::Variant &vVar )=0;
46 virtual _ValueProxy *clone()=0;
47 };
48
49 template<typename ptype>
50 class ValueProxy : public _ValueProxy
51 {
52 public:
53 ValueProxy( ptype &v ) :
54 v( v )
55 {
56 }
57
58 virtual ~ValueProxy()
59 {
60 }
61
62 virtual void setValueFromStr( const Bu::String &sVal )
63 {
64 Bu::MemBuf mb( sVal );
65 Bu::Formatter f( mb );
66 f << Bu::Fmt().tokenize( false );
67 f >> v;
68 }
69
70 virtual void setValue( const Bu::Variant &vVar )
71 {
72 if( vVar.getType() == typeid(ptype) )
73 {
74 v = vVar.get<ptype>();
75 }
76 else if( vVar.getType() == typeid(Bu::String) )
77 {
78 setValueFromStr( vVar.get<Bu::String>() );
79 }
80 else
81 {
82 Bu::MemBuf mb;
83 Bu::Formatter f( mb );
84// f << vVar;
85 setValueFromStr( mb.getString() );
86 }
87 }
88
89 virtual _ValueProxy *clone()
90 {
91 return new ValueProxy<ptype>( v );
92 }
93
94 private:
95 ptype &v;
96 };
97
98 public:
99 typedef Signal1<int, StrArray> OptionSignal;
100 class Option
101 {
102 public:
103 Option();
104 Option( const Option &rSrc );
105 virtual ~Option();
106
107 char cOpt;
108 Bu::String sOpt;
109 Bu::String sHelp;
110 OptionSignal sUsed;
111 _ValueProxy *pProxy;
112 Bu::Variant sOverride;
113 Bu::String sHelpDefault;
114 };
115
116 private:
117 typedef Bu::List<Option> OptionList;
118 typedef Bu::Hash<char, Option *> ShortOptionHash;
119 typedef Bu::Hash<Bu::String, Option *> LongOptionHash;
120
121 class Banner
122 {
123 public:
124 Bu::String sText;
125 bool bFormatted;
126 OptionList::const_iterator iAfter;
127 };
128
129 typedef Bu::List<Banner> BannerList;
130
131 public:
132 OptParser();
133 virtual ~OptParser();
134
135 void parse( int argc, char **argv );
136 void parse( const Bu::String &sLine );
137
138 void addOption( const Option &opt );
139
140 template<typename vtype>
141 void addOption( vtype &var, char cOpt, const Bu::String &sOpt,
142 const Bu::String &sHelp )
143 {
144 Option o;
145 o.cOpt = cOpt;
146 o.sOpt = sOpt;
147 o.pProxy = new ValueProxy<vtype>( var );
148 o.sHelp = sHelp;
149 addOption( o );
150 }
151
152 template<typename vtype>
153 void addOption( vtype &var, const Bu::String &sOpt,
154 const Bu::String &sHelp )
155 {
156 addOption( var, '\0', sOpt, sHelp );
157 }
158
159 template<typename vtype>
160 void addOption( vtype &var, char cOpt, const Bu::String &sHelp )
161 {
162 addOption( var, cOpt, "", sHelp );
163 }
164
165 void addOption( OptionSignal sUsed, char cOpt, const Bu::String &sOpt,
166 const Bu::String &sHelp )
167 {
168 Option o;
169 o.cOpt = cOpt;
170 o.sOpt = sOpt;
171 o.sUsed = sUsed;
172 o.sHelp = sHelp;
173 addOption( o );
174 }
175
176 void addOption( OptionSignal sUsed, const Bu::String &sOpt,
177 const Bu::String &sHelp )
178 {
179 addOption( sUsed, '\0', sOpt, sHelp );
180 }
181
182 void addOption( OptionSignal sUsed, char cOpt,
183 const Bu::String &sHelp )
184 {
185 addOption( sUsed, cOpt, "", sHelp );
186 }
187
188 void setOverride( char cOpt, const Bu::Variant &sOverride );
189 void setOverride( const Bu::String &sOpt,
190 const Bu::Variant &sOverride );
191
192 void setHelpDefault( const Bu::String &sOpt, const Bu::String &sTxt );
193
194 void addHelpOption( char c='h', const Bu::String &s="help",
195 const Bu::String &sHelp="This help." );
196 void addHelpBanner( const Bu::String &sText, bool bFormatted=true );
197
198 int optHelp( StrArray aParams );
199
200 /**
201 * This function is called when an unrecognized option is found, the
202 * default behaviour is to print an error to stdout and exit( 1 ), if
203 * you want to do something different, just override this function.
204 * This is also called by default when something is found that hasn't
205 * been handled by an option, and isn't an option (starts with - or --).
206 * To change this behaviour call
207 */
208 virtual void optionError( const Bu::String &sOption );
209
210 void setNonOption( OptionSignal sSignal );
211
212 private:
213 Bu::String format( const Bu::String &sIn, int iWidth, int iIndent );
214
215 OptionList lOption;
216 ShortOptionHash hsOption;
217 LongOptionHash hlOption;
218 BannerList lBanner;
219 OptionSignal sNonOption;
220 };
221};
222
223#endif
diff --git a/src/stable/pearsonhash.cpp b/src/stable/pearsonhash.cpp
new file mode 100644
index 0000000..d753d20
--- /dev/null
+++ b/src/stable/pearsonhash.cpp
@@ -0,0 +1,66 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/pearsonhash.h"
9#include "bu/stream.h"
10
11uint8_t Bu::PearsonHash::aSBox[] = {
12 251, 175, 119, 215, 81, 14, 79, 191, 103, 49, 181, 143, 186, 157, 0,
13 232, 31, 32, 55, 60, 152, 58, 17, 237, 174, 70, 160, 144, 220, 90, 57,
14 223, 59, 3, 18, 140, 111, 166, 203, 196, 134, 243, 124, 95, 222, 179,
15 197, 65, 180, 48, 36, 15, 107, 46, 233, 130, 165, 30, 123, 161, 209, 23,
16 97, 16, 40, 91, 219, 61, 100, 10, 210, 109, 250, 127, 22, 138, 29, 108,
17 244, 67, 207, 9, 178, 204, 74, 98, 126, 249, 167, 116, 34, 77, 193,
18 200, 121, 5, 20, 113, 71, 35, 128, 13, 182, 94, 25, 226, 227, 199, 75,
19 27, 41, 245, 230, 224, 43, 225, 177, 26, 155, 150, 212, 142, 218, 115,
20 241, 73, 88, 105, 39, 114, 62, 255, 192, 201, 145, 214, 168, 158, 221,
21 148, 154, 122, 12, 84, 82, 163, 44, 139, 228, 236, 205, 242, 217, 11,
22 187, 146, 159, 64, 86, 239, 195, 42, 106, 198, 118, 112, 184, 172, 87,
23 2, 173, 117, 176, 229, 247, 253, 137, 185, 99, 164, 102, 147, 45, 66,
24 231, 52, 141, 211, 194, 206, 246, 238, 56, 110, 78, 248, 63, 240, 189,
25 93, 92, 51, 53, 183, 19, 171, 72, 50, 33, 104, 101, 69, 8, 252, 83, 120,
26 76, 135, 85, 54, 202, 125, 188, 213, 96, 235, 136, 208, 162, 129, 190,
27 132, 156, 38, 47, 1, 7, 254, 24, 4, 216, 131, 89, 21, 28, 133, 37, 153,
28 149, 80, 170, 68, 6, 169, 234, 151
29};
30
31Bu::PearsonHash::PearsonHash()
32{
33 reset();
34}
35
36Bu::PearsonHash::~PearsonHash()
37{
38}
39
40void Bu::PearsonHash::reset()
41{
42 iValue = 0;
43}
44
45void Bu::PearsonHash::setSalt( const Bu::String & /*sSalt*/ )
46{
47}
48
49void Bu::PearsonHash::addData( const void *sData, int iSize )
50{
51 for( int j = 0; j < iSize; j++ )
52 {
53 iValue = aSBox[ iValue^((unsigned char *)sData)[j] ];
54 }
55}
56
57Bu::String Bu::PearsonHash::getResult()
58{
59 return Bu::String((char)iValue);
60}
61
62void Bu::PearsonHash::writeResult( Stream &sOut )
63{
64 sOut.write( &iValue, 1 );
65}
66
diff --git a/src/stable/pearsonhash.h b/src/stable/pearsonhash.h
new file mode 100644
index 0000000..2a9cfa7
--- /dev/null
+++ b/src/stable/pearsonhash.h
@@ -0,0 +1,46 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_PEARSON_HASH_H
9#define BU_PEARSON_HASH_H
10
11#include "bu/cryptohash.h"
12
13namespace Bu
14{
15 /**
16 * A pearson hash is a non-cryptographically secure hashing function that
17 * is very light on resources, very fast, and produces a single byte
18 * as it's output. It is strongly dependant on every byte in the input,
19 * which means that it's a good choice for adding to short messages to
20 * ensure that the contents of the messages are unchanged.
21 *
22 * Pearson hash is named for it's inventor Peter K. Pearson who described
23 * it in his article "Fast hashing of variable-length text strings"
24 * published in 1990 by ACM. I haven't read it, because you have to pay to
25 * get a copy :-P
26 */
27 class PearsonHash : public Bu::CryptoHash
28 {
29 public:
30 PearsonHash();
31 virtual ~PearsonHash();
32
33 virtual void reset();
34 virtual void setSalt( const Bu::String &sSalt );
35 virtual void addData( const void *sData, int iSize );
36 using Bu::CryptoHash::addData;
37 virtual String getResult();
38 virtual void writeResult( Stream &sOut );
39
40 private:
41 static uint8_t aSBox[256];
42 uint8_t iValue;
43 };
44};
45
46#endif
diff --git a/src/stable/plugger.cpp b/src/stable/plugger.cpp
new file mode 100644
index 0000000..fb6850a
--- /dev/null
+++ b/src/stable/plugger.cpp
@@ -0,0 +1,11 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/plugger.h"
9
10namespace Bu { subExceptionDef( PluginException ) }
11
diff --git a/src/stable/plugger.h b/src/stable/plugger.h
new file mode 100644
index 0000000..c22f964
--- /dev/null
+++ b/src/stable/plugger.h
@@ -0,0 +1,289 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_PLUGGER_H
9#define BU_PLUGGER_H
10
11#include "bu/hash.h"
12#include "bu/list.h"
13#include "bu/exceptionbase.h"
14#include "bu/string.h"
15#include <stddef.h>
16
17#include "bu/config.h"
18
19#ifdef WIN32
20# include <windows.h>
21#else
22# include <dlfcn.h>
23#endif
24
25namespace Bu
26{
27 subExceptionDecl( PluginException );
28
29 typedef struct PluginInfo
30 {
31 const char *sID;
32 const char *sAuthor;
33 unsigned short nVersion;
34 unsigned short nRevision;
35 void *(*createPlugin)();
36 void (*destroyPlugin)( void * );
37 } PluginInfo;
38
39 typedef struct PluginReg
40 {
41 bool bBuiltin;
42#ifdef WIN32
43 HMODULE dlHandle;
44#else
45 void *dlHandle;
46#endif
47 PluginInfo *pInfo;
48 } PluginReg;
49
50#define PluginInterface( classname, baseclass, name, ver, rev ) \
51 extern "C" { \
52 baseclass *create ##classname() \
53 { \
54 return new classname(); \
55 } \
56 void destroy ##classname( baseclass *pCls ) \
57 { \
58 delete pCls; \
59 } \
60 Bu::PluginInfo classname = { \
61 #classname, name, ver, rev, \
62 create ##classname, destroy ##classname }; \
63 }
64
65#define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \
66 extern "C" { \
67 baseclass *create ##classname() \
68 { \
69 return new classname(); \
70 } \
71 void destroy ##classname( baseclass *pCls ) \
72 { \
73 delete pCls; \
74 } \
75 Bu::PluginInfo pluginname = { \
76 #pluginname, name, ver, rev, \
77 (void *(*)())(create ##classname), \
78 (void (*)( void * ))(destroy ##classname) }; \
79 }
80
81//
82// This is probably the main interface to use, I'll describe it some here...
83// structname - The name of the structure, this is what you have to pass to
84// register. Depending on how you build your dll/so files this
85// will need to be unique (generally not)
86// pluginname - This is what will be used by the plugin system to refer to
87// your plugin once it's loaded. This should be unique, but not
88// a string
89// classname - The name of the class that is the plugin
90// baseclass - The name of the base class that is the parent of the plugin
91// name - The name of the author of this class (or company)
92// ver - an integer version number for the plugin
93// rev - an integer revision number for the plugin
94//
95#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \
96 extern "C" { \
97 baseclass *create ##classname() \
98 { \
99 return new classname(); \
100 } \
101 void destroy ##classname( baseclass *pCls ) \
102 { \
103 delete pCls; \
104 } \
105 Bu::PluginInfo structname = { \
106 #pluginname, name, ver, rev, \
107 (void *(*)())(create ##classname), \
108 (void (*)( void * ))(destroy ##classname) }; \
109 }
110
111 /**
112 * A complete dynamic plugin manager system. This will allow you to design
113 * and use plugins that are compiled into your program and dynamically
114 * linked to your program interchangably. It works on windows and on *nix
115 * and bsd type systems (anything that supports dlopen). Basically you
116 * create a base class that will be the basic interface of your plugins.
117 * Then you create some classes that inherit from it, and use the
118 * PluginInterface3 macro to create the required data structures for it.
119 *
120 * Once you have plugins you can create a Plugger, by passing in the base
121 * class as it's template parameter. Once it's created, you can register
122 * plugins. To register a plugin that is builtin, you just need to pass
123 * a pointer to it's interface structure to the registerBuiltinPlugin
124 * function. To register a plugin that is in a shared object or dll file
125 * you just pass the filename (with path, probably), and the name of the
126 * structure to load and you're all set.
127 *
128 * To instantiate an object from a plugin simply call instantiate with the
129 * name of the plugin as specified in the interface macro. To destroy an
130 * object crated with the plugger do not delete it, instead pass it into
131 * Plugger's destroy function.
132 *
133 * Any objects not destroyed when the plugger is deleted will be destroyed
134 * automatically.
135 *
136 * It is important to note that some systems (linux at least) partition off
137 * the memory allocated by objects linked in at run time into a seperate
138 * segment that, while it can be accessed by the main program, cannot be
139 * safely or reliably freed by the main program. With that in mind it is
140 * a good idea to free all memory allocated by a plugin object in the plugin
141 * object and not allow the calling program to delete it.
142 */
143 template<class T>
144 class Plugger
145 {
146 public:
147 typedef Bu::Hash<Bu::String, PluginReg *> PluginHash;
148 typedef Bu::Hash<ptrdiff_t, void *> InstHash;
149
150 public:
151 Plugger()
152 {
153 }
154
155 virtual ~Plugger()
156 {
157 for( InstHash::iterator i = hObj.begin(); i != hObj.end(); i++ )
158 {
159 T *pPlug = (T *)i.getKey();
160 PluginReg *pReg = (PluginReg *)*i;
161 pReg->pInfo->destroyPlugin( pPlug );
162 }
163
164 for( PluginHash::iterator i = hPlugin.begin();
165 i != hPlugin.end(); i++ )
166 {
167 if( (*i)->bBuiltin == false )
168 {
169#ifdef WIN32
170 FreeLibrary( (*i)->dlHandle );
171#else
172 dlclose( (*i)->dlHandle );
173#endif
174 }
175 delete (*i);
176 }
177 }
178
179 void registerBuiltinPlugin( PluginInfo *pInfo )
180 {
181 PluginReg *pReg = new PluginReg;
182 pReg->bBuiltin = true;
183 pReg->pInfo = pInfo;
184 hPlugin.insert( pInfo->sID, pReg );
185 }
186
187 void registerExternalPlugin( const Bu::String &sFName,
188 const Bu::String &sPluginName )
189 {
190 PluginReg *pReg;
191 if( hPlugin.has( sPluginName ) )
192 throw Bu::ExceptionBase("A plugin with name '%s' is already "
193 "loaded.", sPluginName.getStr() );
194
195 pReg = new PluginReg;
196
197 pReg->bBuiltin = false;
198#ifdef WIN32
199 pReg->dlHandle = LoadLibrary( sFName.getStr() );
200 if( pReg->dlHandle == NULL )
201 {
202 throw PluginException( 1, "Error opening %s: %s",
203 sFName.getStr(), Bu::getLastWinError().getStr() );
204 }
205 pReg->pInfo = (PluginInfo *)GetProcAddress( pReg->dlHandle,
206 sPluginName.getStr() );
207 if( pReg->pInfo == NULL )
208 {
209 throw PluginException( 2, "Error mapping %s: %s",
210 sFName.getStr(), Bu::getLastWinError().getStr() );
211 }
212#else
213 pReg->dlHandle = dlopen( sFName.getStr(), RTLD_NOW );
214 if( pReg->dlHandle == NULL )
215 {
216 throw PluginException( 1, "Error opening %s: %s",
217 sFName.getStr(), dlerror() );
218 }
219 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle,
220 sPluginName.getStr() );
221 if( pReg->pInfo == NULL )
222 {
223 throw PluginException( 2, "Error mapping %s: %s",
224 sFName.getStr(), dlerror() );
225 }
226#endif
227 hPlugin.insert( pReg->pInfo->sID, pReg );
228 }
229
230 T *instantiate( const Bu::String &lpName )
231 {
232 PluginReg *pReg = (PluginReg *)hPlugin[lpName];
233 if( pReg == NULL )
234 return NULL;
235
236 T *p = (T *)pReg->pInfo->createPlugin();
237 hObj.insert( (ptrdiff_t)p, pReg );
238 //printf("pReg: %08X, pPlug: %08X\n", pReg, p );
239
240 return p;
241 }
242
243 bool hasPlugin( const Bu::String &lpName )
244 {
245 return hPlugin.has( lpName );
246 }
247
248 void destroy( T *pPlug )
249 {
250 PluginReg *pReg = (PluginReg *)hObj.get((ptrdiff_t)pPlug);
251 //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug );
252 if( pReg == NULL )
253 return;
254
255 pReg->pInfo->destroyPlugin( pPlug );
256
257 hObj.erase( (ptrdiff_t)pPlug );
258 }
259
260 void unloadAll()
261 {
262 for( PluginHash::iterator i = hPlugin.begin();
263 i != hPlugin.end(); i++ )
264 {
265 if( (*i)->bBuiltin == false )
266 {
267#ifdef WIN32
268 FreeLibrary( (*i)->dlHandle );
269#else
270 dlclose( (*i)->dlHandle );
271#endif
272 }
273 delete (*i);
274 }
275 hPlugin.clear();
276 }
277
278 Bu::List<Bu::String> getPluginList()
279 {
280 return hPlugin.getKeys();
281 }
282
283 private:
284 PluginHash hPlugin;
285 InstHash hObj;
286 };
287}
288
289#endif
diff --git a/src/stable/process.cpp b/src/stable/process.cpp
new file mode 100644
index 0000000..a98936e
--- /dev/null
+++ b/src/stable/process.cpp
@@ -0,0 +1,441 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/process.h"
9#include <sys/types.h>
10#include <sys/wait.h>
11#include <unistd.h>
12#include <stdarg.h>
13#include <signal.h>
14#include <fcntl.h>
15#include <errno.h>
16
17#include <sys/select.h>
18
19#include "bu/config.h"
20
21Bu::Process::Process( Flags eFlags, const char *sName, char *const argv[] ) :
22 iStdIn( -1 ),
23 iStdOut( -1 ),
24 iStdErr( -1 ),
25 iPid( 0 ),
26 iProcStatus( 0 ),
27 bBlocking( true ),
28 bStdOutEos( true ),
29 bStdErrEos( true )
30{
31 gexec( eFlags, sName, argv );
32}
33
34Bu::Process::Process( Flags eFlags, const char *sName, const char *argv, ...) :
35 iStdIn( -1 ),
36 iStdOut( -1 ),
37 iStdErr( -1 ),
38 iPid( 0 ),
39 iProcStatus( 0 ),
40 bBlocking( true ),
41 bStdOutEos( true ),
42 bStdErrEos( true )
43{
44 int iCnt = 0;
45 va_list ap;
46 va_start( ap, argv );
47 for(; va_arg( ap, const char *); iCnt++ ) { }
48 va_end( ap );
49
50 char const **list = new char const *[iCnt+2];
51 va_start( ap, argv );
52 list[0] = argv;
53 for( int j = 1; j <= iCnt; j++ )
54 {
55 list[j] = va_arg( ap, const char *);
56 }
57 list[iCnt+1] = NULL;
58 va_end( ap );
59
60 gexec( eFlags, sName, (char *const *)list );
61 delete[] list;
62}
63
64Bu::Process::Process( Flags eFlags, const Bu::Process::Options &opt, const char *sName, char *const argv[] ) :
65 iStdIn( -1 ),
66 iStdOut( -1 ),
67 iStdErr( -1 ),
68 iPid( 0 ),
69 iProcStatus( 0 ),
70 bBlocking( true ),
71 bStdOutEos( true ),
72 bStdErrEos( true ),
73 opt( opt )
74{
75 gexec( eFlags, sName, argv );
76}
77
78Bu::Process::Process( Flags eFlags, const Bu::Process::Options &opt, const char *sName, const char *argv, ...) :
79 iStdIn( -1 ),
80 iStdOut( -1 ),
81 iStdErr( -1 ),
82 iPid( 0 ),
83 iProcStatus( 0 ),
84 bBlocking( true ),
85 bStdOutEos( true ),
86 bStdErrEos( true ),
87 opt( opt )
88{
89 int iCnt = 0;
90 va_list ap;
91 va_start( ap, argv );
92 for(; va_arg( ap, const char *); iCnt++ ) { }
93 va_end( ap );
94
95 char const **list = new char const *[iCnt+2];
96 va_start( ap, argv );
97 list[0] = argv;
98 for( int j = 1; j <= iCnt; j++ )
99 {
100 list[j] = va_arg( ap, const char *);
101 }
102 list[iCnt+1] = NULL;
103 va_end( ap );
104
105 gexec( eFlags, sName, (char *const *)list );
106 delete[] list;
107}
108
109Bu::Process::~Process()
110{
111 close();
112}
113
114void Bu::Process::wait()
115{
116 close();
117}
118
119void Bu::Process::gexec( Flags eFlags, const char *sName, char *const argv[] )
120{
121 int iaStdIn[2];
122 int iaStdOut[2];
123 int iaStdErr[2];
124 pipe( iaStdIn );
125 if( eFlags & StdOut )
126 {
127 pipe( iaStdOut );
128 iStdOut = iaStdOut[0];
129 bStdOutEos = false;
130 }
131 if( eFlags & StdErr )
132 {
133 pipe( iaStdErr );
134 iStdErr = iaStdErr[0];
135 bStdErrEos = false;
136 }
137
138 iStdIn = iaStdIn[1];
139
140// fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK );
141
142 iPid = fork();
143 if( iPid == 0 )
144 {
145 ::close( iaStdIn[1] );
146 dup2( iaStdIn[0], 0 );
147 if( eFlags & StdOut )
148 {
149 ::close( iaStdOut[0] );
150 dup2( iaStdOut[1], 1 );
151 }
152 if( eFlags & StdErr )
153 {
154 ::close( iaStdErr[0] );
155 dup2( iaStdErr[1], 2 );
156 }
157 if( (opt.eFlags&Options::SetGid) )
158 {
159 setgid( opt.iGid );
160 }
161 if( (opt.eFlags&Options::SetUid) )
162 {
163 setuid( opt.iUid );
164 }
165 execvp( sName, argv );
166 throw Bu::ExceptionBase("Hey, execvp failed!");
167 }
168 ::close( iaStdIn[0] );
169 if( eFlags & StdOut )
170 ::close( iaStdOut[1] );
171 if( eFlags & StdErr )
172 ::close( iaStdErr[1] );
173}
174
175void Bu::Process::close()
176{
177 if( iPid )
178 {
179 if( iStdIn > -1 )
180 ::close( iStdIn );
181 if( iStdOut > -1 )
182 ::close( iStdOut );
183 if( iStdErr > -1 )
184 ::close( iStdErr );
185 waitpid( iPid, &iProcStatus, 0 );
186 iPid = 0;
187 }
188}
189
190void Bu::Process::closeStdIn()
191{
192 ::close( iStdIn );
193 iStdIn = -1;
194}
195
196void Bu::Process::closeStdOut()
197{
198 ::close( iStdOut );
199 iStdOut = -1;
200}
201
202Bu::size Bu::Process::read( void *pBuf, Bu::size nBytes )
203{
204 if( bStdOutEos )
205 return 0;
206 fd_set rfds;
207 FD_ZERO( &rfds );
208 FD_SET( iStdOut, &rfds );
209 struct timeval tv = {0, 0};
210 if( ::bu_select( iStdOut+1, &rfds, NULL, NULL, &tv ) < 0 )
211 throw Bu::ExceptionBase( strerror( errno ) );
212 if( FD_ISSET( iStdOut, &rfds ) || bBlocking )
213 {
214 Bu::size nRead = TEMP_FAILURE_RETRY( ::read( iStdOut, pBuf, nBytes ) );
215 if( nRead == 0 )
216 {
217 bStdOutEos = true;
218 checkClose();
219 return 0;
220 }
221 if( nRead < 0 )
222 {
223 if( errno == EAGAIN )
224 return 0;
225 throw Bu::ExceptionBase( strerror( errno ) );
226 }
227 return nRead;
228 }
229 return 0;
230}
231
232Bu::size Bu::Process::readErr( void *pBuf, Bu::size nBytes )
233{
234 if( bStdErrEos )
235 return 0;
236 fd_set rfds;
237 FD_ZERO( &rfds );
238 FD_SET( iStdErr, &rfds );
239 struct timeval tv = {0, 0};
240 if( ::bu_select( iStdErr+1, &rfds, NULL, NULL, &tv ) < 0 )
241 throw Bu::ExceptionBase( strerror( errno ) );
242 if( FD_ISSET( iStdErr, &rfds ) || bBlocking )
243 {
244 Bu::size nRead = TEMP_FAILURE_RETRY( ::read( iStdErr, pBuf, nBytes ) );
245 if( nRead == 0 )
246 {
247 bStdErrEos = true;
248 checkClose();
249 return 0;
250 }
251 if( nRead < 0 )
252 {
253 if( errno == EAGAIN )
254 return 0;
255 throw Bu::ExceptionBase( strerror( errno ) );
256 }
257 return nRead;
258 }
259 return 0;
260}
261
262Bu::size Bu::Process::write( const void *pBuf, Bu::size nBytes )
263{
264 return TEMP_FAILURE_RETRY( ::write( iStdIn, pBuf, nBytes ) );
265}
266
267Bu::size Bu::Process::tell()
268{
269 return 0;
270}
271
272void Bu::Process::seek( Bu::size )
273{
274}
275
276void Bu::Process::setPos( Bu::size )
277{
278}
279
280void Bu::Process::setPosEnd( Bu::size )
281{
282}
283
284bool Bu::Process::isEos()
285{
286 return (iPid == 0);
287}
288
289bool Bu::Process::isOpen()
290{
291 return (iPid != 0);
292}
293
294void Bu::Process::flush()
295{
296}
297
298bool Bu::Process::canRead()
299{
300 return true;
301}
302
303bool Bu::Process::canWrite()
304{
305 return true;
306}
307
308bool Bu::Process::isReadable()
309{
310 return true;
311}
312
313bool Bu::Process::isWritable()
314{
315 return true;
316}
317
318bool Bu::Process::isSeekable()
319{
320 return false;
321}
322
323bool Bu::Process::isBlocking()
324{
325 return true;
326}
327
328void Bu::Process::setBlocking( bool bBlocking )
329{
330 if( bBlocking )
331 {
332 if( !bStdOutEos )
333 fcntl( iStdOut, F_SETFL, fcntl(iStdOut,F_GETFL,0 )&(~O_NONBLOCK) );
334 if( !bStdErrEos )
335 fcntl( iStdErr, F_SETFL, fcntl(iStdErr,F_GETFL,0 )&(~O_NONBLOCK) );
336 }
337 else
338 {
339 if( !bStdOutEos )
340 fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK );
341 if( !bStdErrEos )
342 fcntl( iStdErr, F_SETFL, fcntl( iStdErr, F_GETFL, 0 )|O_NONBLOCK );
343 }
344 this->bBlocking = bBlocking;
345}
346
347void Bu::Process::setSize( Bu::size )
348{
349}
350
351Bu::size Bu::Process::getBlockSize() const
352{
353 return 0;
354}
355
356Bu::size Bu::Process::getSize() const
357{
358 return 0;
359}
360
361Bu::String Bu::Process::getLocation() const
362{
363 return "";
364}
365
366void Bu::Process::select( bool &bStdOut, bool &bStdErr )
367{
368 fd_set rfds;
369 FD_ZERO( &rfds );
370 if( !bStdOutEos )
371 FD_SET( iStdOut, &rfds );
372 if( !bStdErrEos )
373 FD_SET( iStdErr, &rfds );
374 if( ::bu_select( iStdErr+1, &rfds, NULL, NULL, NULL ) < 0 )
375 throw Bu::ExceptionBase( strerror( errno ) );
376
377 if( FD_ISSET( iStdOut, &rfds ) )
378 bStdOut = true;
379 else
380 bStdOut = false;
381
382 if( FD_ISSET( iStdErr, &rfds ) )
383 bStdErr = true;
384 else
385 bStdErr = false;
386}
387
388bool Bu::Process::isRunning()
389{
390 if( waitpid( iPid, NULL, WNOHANG ) == iPid )
391 checkClose();
392 return iPid != 0;
393}
394
395void Bu::Process::ignoreStdErr()
396{
397 if( iStdErr == -1 )
398 return;
399 ::close( iStdErr );
400 iStdErr = -1;
401 bStdErrEos = true;
402}
403
404pid_t Bu::Process::getPid()
405{
406 return iPid;
407}
408
409bool Bu::Process::childExited()
410{
411 return WIFEXITED( iProcStatus );
412}
413
414int Bu::Process::childExitStatus()
415{
416 return WEXITSTATUS( iProcStatus );
417}
418
419bool Bu::Process::childSignaled()
420{
421 return WIFSIGNALED( iProcStatus );
422}
423
424int Bu::Process::childSignal()
425{
426 return WTERMSIG( iProcStatus );
427}
428
429bool Bu::Process::childCoreDumped()
430{
431 return WCOREDUMP( iProcStatus );
432}
433
434void Bu::Process::checkClose()
435{
436 if( bStdOutEos && bStdErrEos )
437 {
438 close();
439 }
440}
441
diff --git a/src/stable/process.h b/src/stable/process.h
new file mode 100644
index 0000000..d6282e0
--- /dev/null
+++ b/src/stable/process.h
@@ -0,0 +1,153 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_PROCESS_H
9#define BU_PROCESS_H
10
11#include <stdint.h>
12#include <sys/types.h>
13
14#include "bu/stream.h"
15#include "bu/string.h"
16
17namespace Bu
18{
19 /**
20 * Runs a program and attaches streams to it's stdin, stdout, and stderr.
21 * Reading from a Bu::Process will read from the program's standard output,
22 * writing to a Bu::Process will write to the program's standard input.
23 */
24 class Process : public Bu::Stream
25 {
26 public:
27 enum Flags
28 {
29 None = 0x00,
30 StdOut = 0x01,
31 StdErr = 0x02,
32 Both = 0x03
33 };
34
35 public:
36 class Options
37 {
38 public:
39 enum OptFlags
40 {
41 None = 0x00,
42 SetUid = 0x01,
43 SetGid = 0x02,
44 };
45
46 Options() : eFlags( None ) {}
47
48 int eFlags;
49 int iUid;
50 int iGid;
51 };
52
53 Process( Flags eFlags, const char *sName, char *const argv[] );
54 Process( Flags eFlags, const char *sName, const char *argv, ...);
55 Process( Flags eFlags, const Options &opt, const char *sName, char *const argv[] );
56 Process( Flags eFlags, const Options &opt, const char *sName, const char *argv, ...);
57 virtual ~Process();
58
59 /**
60 * Waits until the process exits. This blocks the caller until the
61 * child process terminates.
62 */
63 void wait();
64
65 virtual void close();
66 virtual void closeStdIn();
67 virtual void closeStdOut();
68 virtual Bu::size read( void *pBuf, Bu::size nBytes );
69 virtual Bu::size readErr( void *pBuf, Bu::size nBytes );
70 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
71 using Stream::write;
72
73 virtual Bu::size tell();
74 virtual void seek( Bu::size offset );
75 virtual void setPos( Bu::size pos );
76 virtual void setPosEnd( Bu::size pos );
77 virtual bool isEos();
78 virtual bool isOpen();
79
80 virtual void flush();
81
82 virtual bool canRead();
83 virtual bool canWrite();
84
85 virtual bool isReadable();
86 virtual bool isWritable();
87 virtual bool isSeekable();
88
89 virtual bool isBlocking();
90 virtual void setBlocking( bool bBlocking=true );
91
92 virtual void setSize( Bu::size iSize );
93
94 virtual size getBlockSize() const;
95 virtual size getSize() const;
96 virtual Bu::String getLocation() const;
97
98 void select( bool &bStdOut, bool &bStdErr );
99
100 bool isRunning();
101 void ignoreStdErr();
102
103 /**
104 * Returns the pid of the child process, or zero if there is no
105 * currently running child. Note that a read operation must be
106 * performed in order to discover that the child has ended.
107 */
108 pid_t getPid();
109
110 /**
111 * Returns true if the child exited normally (by calling exit or
112 * returning from main).
113 */
114 bool childExited();
115
116 /**
117 * Returns the 8 bit integer value returned from the child program if
118 * childExited returned true.
119 */
120 int childExitStatus();
121
122 /**
123 * Returns true if the child exited because of a signal.
124 */
125 bool childSignaled();
126
127 /**
128 * Returns the signal ID if the childSignaled return true.
129 */
130 int childSignal();
131
132 /**
133 * Returns true if the child left a core dump behind when it exited.
134 */
135 bool childCoreDumped();
136
137 private:
138 int iStdIn;
139 int iStdOut;
140 int iStdErr;
141 pid_t iPid;
142 int iProcStatus;
143 bool bBlocking;
144 bool bStdOutEos;
145 bool bStdErrEos;
146
147 void gexec( Flags eFlags, const char *sName, char *const argv[] );
148 void checkClose();
149 Options opt;
150 };
151}
152
153#endif
diff --git a/src/stable/protocol.cpp b/src/stable/protocol.cpp
new file mode 100644
index 0000000..2489d05
--- /dev/null
+++ b/src/stable/protocol.cpp
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/protocol.h"
9
10using namespace Bu;
11
12Bu::Protocol::Protocol()
13{
14}
15
16Bu::Protocol::~Protocol()
17{
18}
19
20void Bu::Protocol::onNewConnection( Bu::Client * )
21{
22}
23
24void Bu::Protocol::onNewData( Bu::Client * )
25{
26}
27
28void Bu::Protocol::onMessage( Bu::Client *, const Bu::String & )
29{
30}
31
32void Bu::Protocol::onTick( Bu::Client * )
33{
34}
35
diff --git a/src/stable/protocol.h b/src/stable/protocol.h
new file mode 100644
index 0000000..0058723
--- /dev/null
+++ b/src/stable/protocol.h
@@ -0,0 +1,38 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_PROTOCOL_H
9#define BU_PROTOCOL_H
10
11#include <stdint.h>
12
13#include "bu/string.h"
14
15namespace Bu
16{
17 class Client;
18
19 /**
20 *@ingroup Serving
21 */
22 class Protocol
23 {
24 public:
25 Protocol();
26 virtual ~Protocol();
27
28 virtual void onNewConnection( Bu::Client *pClient );
29 virtual void onNewData( Bu::Client *pClient );
30 virtual void onMessage( Bu::Client *pClient, const Bu::String &sMsg );
31 virtual void onTick( Bu::Client *pClient );
32
33 private:
34
35 };
36}
37
38#endif
diff --git a/src/stable/protocolhttp.cpp b/src/stable/protocolhttp.cpp
new file mode 100644
index 0000000..eaee9d0
--- /dev/null
+++ b/src/stable/protocolhttp.cpp
@@ -0,0 +1,353 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include <dirent.h>
9
10#ifndef WIN32
11 #include <sys/wait.h>
12#endif
13
14#include <errno.h>
15#include <stdlib.h>
16#include "bu/protocolhttp.h"
17#include "bu/logger.h"
18
19#define CRLF "\x0D\x0A"
20#define CR '\x0D'
21#define LF '\x0A'
22
23using namespace Bu;
24
25Bu::ProtocolHttp::ProtocolHttp()
26{
27}
28
29Bu::ProtocolHttp::~ProtocolHttp()
30{
31}
32
33void Bu::ProtocolHttp::onNewConnection( Bu::Client *pClient )
34{
35 this->pClient = pClient;
36
37 iState = 0;
38}
39
40#define SDB( i ) (void)0
41//#define SDB( i ) printf("state %d: %d, \"%s\"\n", i, tt, sToken.getStr() )
42
43void Bu::ProtocolHttp::onNewData( Bu::Client *pClient )
44{
45/* logHexDump(
46 1,
47 pClient->getInput().getStr(),
48 pClient->getInput().getSize(),
49 "input"
50 );*/
51
52 for(;;)
53 {
54 Bu::String sToken;
55 TokenType tt = getToken( sToken );
56
57 if( tt == ttOutOfData )
58 return;
59
60 switch( iState )
61 {
62 case 0: // Start token, should be "method" (get, put, etc)
63 SDB( 0 );
64 sMethod = sToken;
65 iState = 1;
66 break;
67
68 case 1: // The path requested
69 SDB( 1 );
70 sPath = sToken;
71 iState = 2;
72 break;
73
74 case 2: // The protocol name and version
75 SDB( 2 );
76 if( strncmp( sToken.getStr(), "HTTP/", 5 ) )
77 {
78 pClient->disconnect();
79 return;
80 }
81 else
82 {
83 char *s, *s2;
84 s = sToken.getStr()+5;
85 iMajor = strtol( s, &s2, 10 );
86 iMinor = strtol( s2+1, NULL, 10 );
87 iState = 3;
88 }
89 break;
90
91 case 3: // End of initial header, now comes mime-style blocks.
92 SDB( 3 );
93 if( tt == ttNewline )
94 {
95 iState = 10;
96 }
97 else if( tt == ttDoubleNewline )
98 {
99 earlyResponse();
100 }
101 else
102 {
103 pClient->disconnect();
104 return;
105 }
106 break;
107
108 case 10: // HTTP-Message (skipped for now...)
109 SDB( 10 );
110 if( tt == ttString )
111 {
112 iState = 11;
113 }
114 else
115 {
116 pClient->disconnect();
117 }
118 break;
119
120 case 11: // Should be a colon...
121 SDB( 11 );
122 if( tt == ttSeperator && sToken == ":" )
123 {
124 iState = 12;
125 }
126 else
127 {
128 pClient->disconnect();
129 }
130 break;
131
132 case 12:
133 SDB( 12 );
134 if( tt == ttNewline )
135 {
136 iState = 10;
137 }
138 if( tt == ttDoubleNewline )
139 {
140 earlyResponse();
141 }
142 break;
143
144 case 20:
145 SDB( 20 );
146 break;
147 }
148 }
149}
150
151Bu::ProtocolHttp::TokenType Bu::ProtocolHttp::getToken( Bu::String &line )
152{
153 char s;
154 int jmax = pClient->getInputSize();
155 bool bNonWS = false;
156
157 for( int j = 0; j < jmax; j++ )
158 {
159 pClient->peek( &s, 1, j );
160 if( iState > 2 && isSeperator( s ) )
161 {
162 if( j == 0 )
163 {
164 line += s;
165 pClient->seek( 1 );
166 return ttSeperator;
167 }
168 else
169 {
170 pClient->seek( j );
171 return ttString;
172 }
173 }
174 else if( isWS( s ) )
175 {
176 if( bNonWS )
177 {
178 pClient->seek( j );
179 return ttString;
180 }
181 }
182 else if( s == CR )
183 {
184 if( pClient->getInputSize() < 4 )
185 return ttOutOfData;
186
187 char ss[3];
188 pClient->peek( ss, 3, j+1 );
189 if( ss[0] == LF && ss[1] != ' ' && ss[1] != '\t' )
190 {
191 if( bNonWS )
192 {
193 pClient->seek( j );
194 return ttString;
195 }
196 else if( ss[1] == CR && ss[2] == LF )
197 {
198 pClient->seek( 4 );
199 return ttDoubleNewline;
200 }
201 else
202 {
203 pClient->seek( 2 );
204 return ttNewline;
205 }
206 }
207
208 j += 2;
209 if( bNonWS )
210 {
211 pClient->seek( j );
212 return ttString;
213 }
214 }
215 else
216 {
217 line += s;
218 bNonWS = true;
219 }
220 }
221
222 return ttOutOfData;
223}
224
225bool Bu::ProtocolHttp::isWS( char buf )
226{
227 return (buf == ' ' || buf == '\t');
228}
229
230bool Bu::ProtocolHttp::isSeperator( char buf )
231{
232 return (buf == '(' || buf == ')' || buf == '<' || buf == '>' ||
233 buf == '@' || buf == ',' || buf == ';' || buf == ':' ||
234 buf == '\\' || buf == '\"' || buf == '/' || buf == '[' ||
235 buf == ']' || buf == '?' || buf == '=' || buf == '{' ||
236 buf == '}' );
237}
238
239void Bu::ProtocolHttp::earlyResponse()
240{
241 if( sMethod == "GET" )
242 {
243 onRequest( sMethod, sPath );
244 iState = 0;
245 }
246 else
247 {
248 iState = 20;
249 }
250}
251
252void Bu::ProtocolHttp::lateResponse()
253{
254 onRequest( sMethod, sPath );
255}
256
257void Bu::ProtocolHttp::sendResponse( const Response &rRes )
258{
259 char buf[1024];
260 int iSize = sprintf( buf, "HTTP/1.1 %d ", rRes.iCode );
261
262 pClient->write( buf, iSize );
263 pClient->write( rRes.sReason );
264 pClient->write( CRLF, 2 );
265
266 for( Response::StringHash::const_iterator i = rRes.hHeaders.begin();
267 i != rRes.hHeaders.end(); i++ )
268 {
269 pClient->write( i.getKey() );
270 pClient->write(": ", 2 );
271 pClient->write( i.getValue() );
272 pClient->write( CRLF, 2 );
273 }
274
275 iSize = sprintf( buf, "Content-Length: %ld" CRLF, rRes.sContent.getSize() );
276 pClient->write( buf, iSize );
277
278 pClient->write( CRLF, 2 );
279 pClient->write( rRes.sContent );
280}
281
282//
283// Bu::ProtocolHttp::Response
284//
285Bu::ProtocolHttp::Response::Response( int iCode ) :
286 iCode( iCode )
287{
288 switch( iCode )
289 {
290 case 100: sReason = "Continue"; break;
291 case 101: sReason = "Switching Protocols"; break;
292 case 200: sReason = "OK"; break;
293 case 201: sReason = "Created"; break;
294 case 202: sReason = "Accepted"; break;
295 case 203: sReason = "Non-Authoritative Information"; break;
296 case 204: sReason = "No Content"; break;
297 case 205: sReason = "Reset Content"; break;
298 case 206: sReason = "Partial Content"; break;
299 case 300: sReason = "Multiple Choices"; break;
300 case 301: sReason = "Moved Permanently"; break;
301 case 302: sReason = "Found"; break;
302 case 303: sReason = "See Other"; break;
303 case 304: sReason = "Not Modified"; break;
304 case 305: sReason = "Use Proxy"; break;
305 case 307: sReason = "Temporary Redirect"; break;
306 case 400: sReason = "Bad Request"; break;
307 case 401: sReason = "Unauthorized"; break;
308 case 402: sReason = "Payment Required"; break;
309 case 403: sReason = "Forbidden"; break;
310 case 404: sReason = "Not Found"; break;
311 case 405: sReason = "Method Not Allowed"; break;
312 case 406: sReason = "Not Acceptable"; break;
313 case 407: sReason = "Proxy Authentication Required"; break;
314 case 408: sReason = "Request Time-out"; break;
315 case 409: sReason = "Conflict"; break;
316 case 410: sReason = "Gone"; break;
317 case 411: sReason = "Length Required"; break;
318 case 412: sReason = "Precondition Failed"; break;
319 case 413: sReason = "Request Entity Too Large"; break;
320 case 414: sReason = "Request-URI Too Large"; break;
321 case 415: sReason = "Unsupported Media Type"; break;
322 case 416: sReason = "Requested range not satisfiable"; break;
323 case 417: sReason = "Expectation Failed"; break;
324 case 500: sReason = "Internal Server Error"; break;
325 case 501: sReason = "Not Implemented"; break;
326 case 502: sReason = "Bad Gateway"; break;
327 case 503: sReason = "Service Unavailable"; break;
328 case 504: sReason = "Gateway Time-out"; break;
329 case 505: sReason = "HTTP Version not supported"; break;
330 }
331}
332
333Bu::ProtocolHttp::Response::Response( int iCode, const Bu::String &sReason ) :
334 iCode( iCode ),
335 sReason( sReason )
336{
337}
338
339Bu::ProtocolHttp::Response::~Response()
340{
341}
342
343void Bu::ProtocolHttp::Response::setHeader(
344 const Bu::String &sKey, const Bu::String &sVal )
345{
346 hHeaders.insert( sKey, sVal );
347}
348
349void Bu::ProtocolHttp::Response::setContent( const Bu::String &sCont )
350{
351 sContent = sCont;
352}
353
diff --git a/src/stable/protocolhttp.h b/src/stable/protocolhttp.h
new file mode 100644
index 0000000..153a00d
--- /dev/null
+++ b/src/stable/protocolhttp.h
@@ -0,0 +1,106 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_PROTOCOL_HTTP_H
9#define BU_PROTOCOL_HTTP_H
10
11#include <stdint.h>
12#include <sys/types.h>
13
14#include "bu/protocol.h"
15#include "bu/client.h"
16#include "bu/string.h"
17#include "bu/hash.h"
18
19namespace Bu
20{
21 /**
22 * An HTTP Protocol handler. Yes, I know that HTTP stands for Hyper Text
23 * Transfer Protocol, and that the Protocol part is redundant, but in this
24 * case the word Protocol is refering to the Libbu++ construct Bu::Protocol,
25 * and not a means of encoding conversations. Anyway, this class represents
26 * a general HTTP server processor. Every time a request comes in it calls
27 * the onRequest function in a subclass with the method and URI that were
28 * requested. The sub-class can then do whatever it needs to to send back
29 * a response.
30 *@ingroup Serving
31 */
32 class ProtocolHttp : public Protocol
33 {
34 public: /* Types */
35 typedef Bu::List<Bu::String> TokenList;
36
37 public: /* Interface */
38 ProtocolHttp();
39 virtual ~ProtocolHttp();
40
41 virtual void onNewConnection( Bu::Client *pClient );
42 virtual void onNewData( Bu::Client *pClient );
43
44 virtual void onRequest(
45 const Bu::String &sMethod, const Bu::String &sPath )=0;
46
47 class Response
48 {
49 friend class Bu::ProtocolHttp;
50 public:
51 Response( int iCode );
52 Response( int iCode, const Bu::String &sReason );
53 virtual ~Response();
54
55 void setHeader( const Bu::String &sKey, const Bu::String &sVal );
56 void setContent( const Bu::String &sCont );
57
58 private:
59 int iCode;
60 Bu::String sReason;
61 typedef Bu::Hash<Bu::String,Bu::String> StringHash;
62 StringHash hHeaders;
63 Bu::String sContent;
64 };
65
66 void sendResponse( const Response &rRes );
67
68 private:
69 enum TokenType
70 {
71 ttOutOfData,
72 ttString,
73 ttNewline,
74 ttDoubleNewline,
75 ttSeperator
76 };
77 /**
78 * Read an HTTP line, this is up to the first CRLF that isn't followed
79 * by a continuation character, converting it to one line as it reads.
80 *@param line All data read will be appended to line, even if no
81 * end-of-line is read.
82 *@returns True if an end-of-line is read and the line should be
83 * processed, false if the end-of-line has not been reached, and more
84 * data needs to be read before this operation can continue.
85 */
86 TokenType getToken( Bu::String &line );
87 bool isWS( char buf );
88 bool isSeperator( char buf );
89
90 void earlyResponse();
91 void lateResponse();
92
93 private: /* state */
94 Bu::Client *pClient;
95 TokenList lTokens;
96
97 int iState;
98
99 Bu::String sMethod;
100 Bu::String sPath;
101 int iMajor;
102 int iMinor;
103 };
104}
105
106#endif
diff --git a/src/stable/protocoltelnet.cpp b/src/stable/protocoltelnet.cpp
new file mode 100644
index 0000000..7e37cca
--- /dev/null
+++ b/src/stable/protocoltelnet.cpp
@@ -0,0 +1,620 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/protocoltelnet.h"
9#include "bu/client.h"
10
11/* We apparently at least want defs for the lower 13, not sure we care about
12 * the rest of the chars, maybe escape.
13 */
14#define CH_NUL '\x00' /* NUL */
15#define CH_SOH '\x01' /* Start Of Heading */
16#define CH_STX '\x02' /* Start of Text */
17#define CH_ETX '\x03' /* End of Text */
18#define CH_EOT '\x04' /* End of transmission */
19#define CH_ENQ '\x05' /* Enquiery */
20#define CH_ACK '\x06' /* Acknowledge */
21#define CH_BEL '\x07' /* Bell */
22#define CH_BS '\x08' /* Backspace */
23#define CH_TAB '\x09' /* Horizontal Tab */
24#define CH_LF '\x0A' /* NL Line feed, new line */
25#define CH_VT '\x0B' /* Vertical Tab */
26#define CH_FF '\x0C' /* Form feed, new page */
27#define CH_CR '\x0D' /* Carriage return */
28#define CH_ESC '\x1B' /* Escape */
29#define CH_DEL '\x7F' /* Delete */
30
31#define CODE_SE '\xf0' /* End of subnegotiation params. */
32#define CODE_NOP '\xf1' /* No operation (keep-alive). */
33#define CODE_DM '\xf2' /* Datastream side of a Synch. */
34#define CODE_BRK '\xf3' /* Break character. */
35#define CODE_IP '\xf4' /* Interrupt Process character. */
36#define CODE_AO '\xf5' /* Abort Output character. */
37#define CODE_AYT '\xf6' /* Are You There? character. */
38#define CODE_EC '\xf7' /* Erase Character character. */
39#define CODE_EL '\xf8' /* Erase Line character. */
40#define CODE_GA '\xf9' /* Go Ahead signal. */
41#define CODE_SB '\xfa' /* Begin subnegotiation options. */
42#define CODE_WILL '\xfb' /* Desire to do something. */
43#define CODE_WONT '\xfc' /* Refuse to perform. */
44#define CODE_DO '\xfd' /* Request option. */
45#define CODE_DONT '\xfe' /* Demand a stop. */
46
47#define CODE_IAC '\xff' /* Interpret-As-Command. */
48
49#define OPT_BINARY '\x00' /* Binary mode (file transfers?). */
50#define OPT_ECHO '\x01' /* (local) Echo mode. */
51#define OPT_SUPGA '\x03' /* Suppress Go Ahead signals. */
52#define OPT_STATUS '\x05' /* Allow status messages. */
53#define OPT_TIMING '\x06' /* Place a timing mark in the code. */
54#define OPT_EXASCII '\x11' /* Extended ASCII. */
55#define OPT_LOGOUT '\x12' /* Logout. */
56#define OPT_TTYPE '\x18' /* Terminal Type. */
57#define OPT_NAWS '\x1f' /* Negotiate about window size. */
58#define OPT_TSPEED '\x20' /* Terminal Speed. */
59#define OPT_NEWENV '\x27' /* New Environment Option. */
60#define OPT_EXOPL '\xff' /* Can we, will we, handle extended options. */
61
62#ifndef __TELNET_DEBUG
63# define printCode( a ) (void)0
64# define printOpt( a ) (void)0
65#endif
66
67Bu::ProtocolTelnet::ProtocolTelnet() :
68 oBinary( *this, OPT_BINARY ),
69 oEcho( *this, OPT_ECHO ),
70 oNAWS( *this, OPT_NAWS ),
71 oSuppressGA(*this, OPT_SUPGA ),
72 bCanonical( true ),
73 bSubOpt( false )
74{
75}
76
77Bu::ProtocolTelnet::~ProtocolTelnet()
78{
79}
80
81void Bu::ProtocolTelnet::onNewConnection( Bu::Client *pClient )
82{
83 this->pClient = pClient;
84}
85
86void Bu::ProtocolTelnet::onNewData( Bu::Client *pClient )
87{
88 char bc;
89 int iLeft;
90 while( (iLeft = pClient->getInputSize()) )
91 {
92 if( bSubOpt )
93 {
94 pClient->peek( &bc, 1 );
95 if( bc == CODE_IAC )
96 {
97 if( iLeft <= 1 ) return;
98 char bc2;
99 printCode( CODE_IAC );
100 pClient->peek( &bc2, 1, 1 );
101 printCode( bc2 );
102 if( bc2 == CODE_SE )
103 {
104 bSubOpt = false;
105 onSubOpt();
106 }
107 else if( bc2 == CODE_IAC )
108 {
109 sSubBuf += CODE_IAC;
110 }
111 else
112 {
113 // Error of some sort.
114 }
115 pClient->seek( 1 );
116 }
117 else
118 {
119 sSubBuf += bc;
120 }
121 pClient->seek( 1 );
122 }
123 else
124 {
125 pClient->peek( &bc, 1 );
126 if( bc == CODE_IAC )
127 {
128 if( iLeft <= 1 ) return;
129 char bc2;
130 pClient->peek( &bc2, 1, 1 );
131 printCode( bc );
132 printCode( bc2 );
133
134 switch( bc2 )
135 {
136 case CODE_WILL:
137 if( iLeft <= 2 ) return;
138 {
139 char bc3;
140 pClient->peek( &bc3, 1, 2 );
141 pClient->seek( 1 );
142 printOpt( bc3 );
143 onWill( bc3 );
144 }
145 break;
146
147 case CODE_WONT:
148 if( iLeft <= 2 ) return;
149 {
150 char bc3;
151 pClient->peek( &bc3, 1, 2 );
152 pClient->seek( 1 );
153 printOpt( bc3 );
154 onWont( bc3 );
155 }
156 break;
157
158 case CODE_DO:
159 if( iLeft <= 2 ) return;
160 {
161 char bc3;
162 pClient->peek( &bc3, 1, 2 );
163 pClient->seek( 1 );
164 printOpt( bc3 );
165 onDo( bc3 );
166 }
167 break;
168
169 case CODE_DONT:
170 if( iLeft <= 2 ) return;
171 {
172 char bc3;
173 pClient->peek( &bc3, 1, 2 );
174 pClient->seek( 1 );
175 printOpt( bc3 );
176 onDont( bc3 );
177 }
178 break;
179
180 case CODE_SB:
181 if( iLeft <= 2 ) return;
182 {
183 pClient->peek( &cSubOpt, 1, 2 );
184 pClient->seek( 1 );
185 printOpt( cSubOpt );
186 bSubOpt = true;
187 }
188 break;
189
190 case CODE_IAC:
191 sDataBuf += CODE_IAC;
192 printCode( CODE_IAC );
193 break;
194 }
195 pClient->seek( 1 );
196#ifdef __TELNET_DEBUG
197 printf("\n");
198#endif
199 }
200 else if( bc == CODE_SB )
201 {
202 }
203 else
204 {
205 // This is where control code handling goes
206 // Also, possibly, character code conversion, although I'm not
207 // sure that really matters anymore, go ASCII/UTF-8
208 if( bCanonical )
209 {
210 if( bc < 0x20 || bc >= CH_DEL )
211 {
212 if( bc == CH_CR )
213 {
214 if( iLeft <= 1 ) return;
215 char bc2;
216 pClient->peek( &bc2, 1, 1 );
217 if( bc2 == CH_NUL || bc2 == CH_LF )
218 {
219 onCtlChar( bc );
220 gotLine( sDataBuf );
221 sDataBuf.clear();
222 }
223 pClient->seek( 1 );
224 }
225 else
226 {
227 onCtlChar( bc );
228 }
229 }
230 else
231 {
232 sDataBuf += bc;
233 if( oEcho.isLocalSet() )
234 {
235 pClient->write( &bc, 1 );
236#ifdef __TELNET_DEBUG
237 printf("%c", bc );
238 fflush( stdout );
239#endif
240 }
241 }
242 }
243 else
244 {
245 sDataBuf += bc;
246 if( oEcho.isLocalSet() )
247 {
248 pClient->write( &bc, 1 );
249 }
250 }
251 }
252 pClient->seek( 1 );
253 }
254 }
255
256 // It's true, this code will not be executed if we only have half of an
257 // IAC code or multibyte escape sequence or something, but then again, it
258 // shouldn't be called then, and really, shouldn't be, it'll be called soon
259 // enough, when we get the rest of that code.
260 if( !bCanonical )
261 {
262 gotData( sDataBuf );
263 }
264}
265
266void Bu::ProtocolTelnet::setCanonical( bool bCon )
267{
268 bCanonical = bCon;
269}
270
271bool Bu::ProtocolTelnet::isCanonical()
272{
273 return bCanonical;
274}
275
276void Bu::ProtocolTelnet::write( const Bu::String &sData )
277{
278 write( sData.getStr(), sData.getSize() );
279}
280
281void Bu::ProtocolTelnet::write( const char *pData, int iSize )
282{
283 int iLast = 0, j;
284 for( j = iLast; j < iSize; j++ )
285 {
286 if( pData[j] == '\n' )
287 {
288 if( j+1 >= iSize ||
289 (pData[j+1] != '\r' && pData[j+1] != '\0') )
290 {
291 pClient->write( pData+iLast, j-iLast );
292 pClient->write( "\n\r", 2 );
293 iLast = j+1;
294 }
295 else
296 {
297 j++;
298 }
299 }
300 }
301 if( j > iLast )
302 {
303 pClient->write( pData+iLast, iSize-iLast );
304 }
305 //pClient->write( pData, iSize );
306}
307
308void Bu::ProtocolTelnet::write( char cData )
309{
310 write( &cData, 1 );
311}
312
313void Bu::ProtocolTelnet::onWill( char cCode )
314{
315 try
316 {
317 Option *pOpt = hOpts[cCode];
318 if( pOpt->isRemoteEnabled() )
319 {
320 pOpt->fOpts |= Option::fRemoteIs;
321 char buf[3] = { CODE_IAC, CODE_DO, cCode };
322 pClient->write( buf, 3 );
323 }
324 else
325 {
326 char buf[3] = { CODE_IAC, CODE_DONT, cCode };
327 pClient->write( buf, 3 );
328 }
329
330 }
331 catch( Bu::HashException &e )
332 {
333 char buf[3] = { CODE_IAC, CODE_DONT, cCode };
334 pClient->write( buf, 3 );
335 }
336}
337
338void Bu::ProtocolTelnet::onWont( char cCode )
339{
340 try
341 {
342 Option *pOpt = hOpts[cCode];
343
344 pOpt->fOpts &= ~Option::fRemoteIs;
345 char buf[3] = { CODE_IAC, CODE_DONT, cCode };
346 pClient->write( buf, 3 );
347 }
348 catch( Bu::HashException &e )
349 {
350 char buf[3] = { CODE_IAC, CODE_DONT, cCode };
351 pClient->write( buf, 3 );
352 }
353}
354
355void Bu::ProtocolTelnet::onDo( char cCode )
356{
357 try
358 {
359 Option *pOpt = hOpts[cCode];
360 if( pOpt->isLocalEnabled() )
361 {
362 pOpt->fOpts |= Option::fLocalIs;
363 char buf[3] = { CODE_IAC, CODE_WILL, cCode };
364 pClient->write( buf, 3 );
365 }
366 else
367 {
368 char buf[3] = { CODE_IAC, CODE_WONT, cCode };
369 pClient->write( buf, 3 );
370 }
371
372 }
373 catch( Bu::HashException &e )
374 {
375 char buf[3] = { CODE_IAC, CODE_WONT, cCode };
376 pClient->write( buf, 3 );
377 }
378}
379
380void Bu::ProtocolTelnet::onDont( char cCode )
381{
382 try
383 {
384 Option *pOpt = hOpts[cCode];
385
386 pOpt->fOpts &= ~Option::fLocalIs;
387 char buf[3] = { CODE_IAC, CODE_DONT, cCode };
388 pClient->write( buf, 3 );
389 }
390 catch( Bu::HashException &e )
391 {
392 char buf[3] = { CODE_IAC, CODE_DONT, cCode };
393 pClient->write( buf, 3 );
394 }
395}
396
397void Bu::ProtocolTelnet::onSubOpt()
398{
399 switch( cSubOpt )
400 {
401 case OPT_NAWS:
402 {
403 uint16_t iWidth, iHeight;
404 ((char *)&iWidth)[1] = sSubBuf[0];
405 ((char *)&iWidth)[0] = sSubBuf[1];
406 ((char *)&iHeight)[1] = sSubBuf[2];
407 ((char *)&iHeight)[0] = sSubBuf[3];
408 onSubNAWS( iWidth, iHeight );
409 }
410 break;
411
412 default:
413 onSubUnknown( cSubOpt, sSubBuf );
414 break;
415 }
416
417 sSubBuf.clear();
418}
419
420void Bu::ProtocolTelnet::onCtlChar( char cChr )
421{
422#ifdef __TELNET_DEBUG
423 switch( cChr )
424 {
425 case CH_NUL: printf("NUL "); break;
426 case CH_SOH: printf("SOH "); break;
427 case CH_STX: printf("STX "); break;
428 case CH_ETX: printf("ETX "); break;
429 case CH_EOT: printf("EOT "); break;
430 case CH_ENQ: printf("ENQ "); break;
431 case CH_ACK: printf("ACK "); break;
432 case CH_BEL: printf("BEL "); break;
433 case CH_BS: printf("BS "); break;
434 case CH_TAB: printf("TAB "); break;
435 case CH_LF: printf("LF "); break;
436 case CH_VT: printf("VT "); break;
437 case CH_FF: printf("FF "); break;
438 case CH_CR: printf("CR "); break;
439 case CH_ESC: printf("ESC "); break;
440 case CH_DEL: printf("DEL "); break;
441 default: printf("!![%02x] ", cChr ); break;
442 }
443 fflush( stdout );
444#endif
445
446 switch( cChr )
447 {
448 case CH_DEL:
449 {
450 if( sDataBuf.getSize() > 0 )
451 {
452 sDataBuf.resize( sDataBuf.getSize()-1 );
453 char buf[3] = { CH_BS, ' ', CH_BS };
454 pClient->write( buf, 3 );
455 }
456 }
457 break;
458
459 }
460}
461
462#ifdef __TELNET_DEBUG
463void Bu::ProtocolTelnet::printCode( char cCode )
464{
465 switch( cCode )
466 {
467 case CODE_SE: printf("SE "); break;
468 case CODE_NOP: printf("NOP "); break;
469 case CODE_DM: printf("DM "); break;
470 case CODE_BRK: printf("BRK "); break;
471 case CODE_IP: printf("IP "); break;
472 case CODE_AO: printf("AO "); break;
473 case CODE_AYT: printf("AYT "); break;
474 case CODE_EC: printf("EC "); break;
475 case CODE_EL: printf("EL "); break;
476 case CODE_GA: printf("GA "); break;
477 case CODE_SB: printf("SB "); break;
478 case CODE_WILL: printf("WILL "); break;
479 case CODE_WONT: printf("WONT "); break;
480 case CODE_DO: printf("DO "); break;
481 case CODE_DONT: printf("DONT "); break;
482 case CODE_IAC: printf("IAC "); break;
483 default: printf("??%02x ", cCode ); break;
484 }
485 fflush( stdout );
486}
487
488void Bu::ProtocolTelnet::printOpt( char cOpt )
489{
490 switch( cOpt )
491 {
492 case OPT_BINARY: printf("BINARY "); break;
493 case OPT_ECHO: printf("ECHO "); break;
494 case OPT_SUPGA: printf("SUPGA "); break;
495 case OPT_STATUS: printf("STATUS "); break;
496 case OPT_TIMING: printf("TIMING "); break;
497 case OPT_EXASCII: printf("EXASCII "); break;
498 case OPT_LOGOUT: printf("LOGOUT "); break;
499 case OPT_TTYPE: printf("TTYPE "); break;
500 case OPT_NAWS: printf("NAWS "); break;
501 case OPT_TSPEED: printf("TSPEED "); break;
502 case OPT_NEWENV: printf("NEWENV "); break;
503 case OPT_EXOPL: printf("EXOPL "); break;
504 default: printf("??%02x ", cOpt); break;
505 }
506 fflush( stdout );
507}
508#endif
509
510Bu::ProtocolTelnet::Option::Option( Bu::ProtocolTelnet &rPT, char cCode ) :
511 rPT( rPT ),
512 fOpts( 0 ),
513 cCode( cCode )
514{
515 rPT.hOpts.insert( cCode, this );
516}
517
518Bu::ProtocolTelnet::Option::~Option()
519{
520}
521
522void Bu::ProtocolTelnet::Option::localEnable( bool bSet )
523{
524 if( bSet == (bool)(!(fOpts&fLocalCant)) ) return;
525
526 if( bSet )
527 fOpts &= ~fLocalCant;
528 else
529 fOpts |= fLocalCant;
530}
531
532void Bu::ProtocolTelnet::Option::localSet( bool bSet )
533{
534 if( bSet == (bool)(fOpts&fLocalIs) ) return;
535
536 char buf[3] = { CODE_IAC, 0, cCode };
537
538 if( bSet )
539 {
540 buf[1] = CODE_WILL;
541 rPT.pClient->write( buf, 3 );
542#ifdef __TELNET_DEBUG
543 printf("<= ");
544 rPT.printCode( buf[0] );
545 rPT.printCode( buf[1] );
546 rPT.printOpt( buf[2] );
547 printf("\n");
548#endif
549 }
550 else
551 {
552 buf[1] = CODE_WONT;
553 rPT.pClient->write( buf, 3 );
554#ifdef __TELNET_DEBUG
555 printf("<= ");
556 rPT.printCode( buf[0] );
557 rPT.printCode( buf[1] );
558 rPT.printOpt( buf[2] );
559 printf("\n");
560#endif
561 }
562}
563
564bool Bu::ProtocolTelnet::Option::isLocalEnabled()
565{
566 return (bool)(!(fOpts&fLocalCant));
567}
568
569bool Bu::ProtocolTelnet::Option::isLocalSet()
570{
571 return (bool)(fOpts&fLocalIs);
572}
573
574void Bu::ProtocolTelnet::Option::remoteEnable( bool /*bSet*/ )
575{
576 return;
577}
578
579void Bu::ProtocolTelnet::Option::remoteSet( bool bSet )
580{
581 //if( bSet == (bool)(fOpts&fRemoteIs) ) return;
582
583 char buf[3] = { CODE_IAC, 0, cCode };
584
585 if( bSet )
586 {
587 buf[1] = CODE_DO;
588 rPT.pClient->write( buf, 3 );
589#ifdef __TELNET_DEBUG
590 printf("<= ");
591 rPT.printCode( buf[0] );
592 rPT.printCode( buf[1] );
593 rPT.printOpt( buf[2] );
594 printf("\n");
595#endif
596 }
597 else
598 {
599 buf[1] = CODE_DONT;
600 rPT.pClient->write( buf, 3 );
601#ifdef __TELNET_DEBUG
602 printf("<= ");
603 rPT.printCode( buf[0] );
604 rPT.printCode( buf[1] );
605 rPT.printOpt( buf[2] );
606 printf("\n");
607#endif
608 }
609}
610
611bool Bu::ProtocolTelnet::Option::isRemoteEnabled()
612{
613 return (bool)(!(fOpts&fRemoteCant));
614}
615
616bool Bu::ProtocolTelnet::Option::isRemoteSet()
617{
618 return (bool)(fOpts&fRemoteIs);
619}
620
diff --git a/src/stable/protocoltelnet.h b/src/stable/protocoltelnet.h
new file mode 100644
index 0000000..74d6478
--- /dev/null
+++ b/src/stable/protocoltelnet.h
@@ -0,0 +1,220 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_PROTOCOL_TELNET_H
9#define BU_PROTOCOL_TELNET_H
10
11#include "bu/protocol.h"
12#include "bu/hash.h"
13#include "bu/string.h"
14
15// #define __TELNET_DEBUG
16
17namespace Bu
18{
19 /**
20 * Telnet Protocol handler. This attempts to provide useful and general
21 * support for most of the most commonly used Telnet extensions in a simple
22 * and easy to use way. The Option variables control the settings that can
23 * be used on the line, and control which virtual "callbacks" will be called
24 * when different events happen.
25 *
26 * To setup initial values and to disable any options you wish override the
27 * onNewConnection function in your own class, like this:
28 *@code
29 class MyTelnet : public Bu::ProtocolTelnet
30 {
31 public:
32 ...
33
34 virtual void onNewConnection( class Bu::Client *pClient )
35 {
36 // Call the parent class' onNewConnection to get everything all
37 // set up.
38 Bu::ProtocolTelnet::onNewConnection( pClient );
39
40 // These functions disable the option to send files via telnet,
41 // disabling the remote option means that we won't accept this
42 // option (binary data being sent to us) from the client.
43 //
44 // Disabling the local option means that the client cannot ask us
45 // to send them binary data.
46 oBinary.enableRemote( false );
47 oBinary.enableLocal( false );
48
49 // This requests that the client send us window size updates
50 // whenever the size of their window changes, and an initial set to
51 // boot.
52 //
53 // To see if this option is set later, try oNAWS.isRemoteSet(), but
54 // wait a little while, asking immediatly will always return false,
55 // since the remote side has yet to receive our request.
56 oNAWS.remoteSet();
57 }
58 }
59 @endcode
60 *
61 *@ingroup Serving
62 */
63 class ProtocolTelnet : public Protocol
64 {
65 public:
66 ProtocolTelnet();
67 virtual ~ProtocolTelnet();
68
69 /**
70 * If you override this function in a child class, make sure to call
71 * this version of it as the very first thing that you do, before you
72 * set any options. See the example in the class docs.
73 */
74 virtual void onNewConnection( class Bu::Client *pClient );
75
76 /**
77 * You should never override this function unless you really, really
78 * know what you're doing. If you want to get data after each line
79 * entered (in canonical mode) or after any data arrives (non canonical
80 * mode) then override the gotLine and gotData functions, respectively.
81 */
82 virtual void onNewData( class Bu::Client *pClient );
83
84 /**
85 * Override this function to be notified of lines being submitted by
86 * the client. This function is only called in canonical mode, after
87 * all edits are performed on the data. In this mode weather you use
88 * the line or not, the data will be cleared from the buffer when this
89 * function returns, any changes made to the buffer will be destroyed.
90 */
91 virtual void gotLine( Bu::String & /*sLine*/ ){};
92
93 /**
94 * Override this function to be notified of any new data that comes in
95 * from the client. This function is only called in non-canonical mode,
96 * and includes all raw data minus telnet control codes and ansi
97 * escape sequences. In this mode control of the buffer is up to the
98 * child class in this function, the buffer will never be cleared unless
99 * it happens in this function's override.
100 */
101 virtual void gotData( Bu::String & /*sData*/ ){};
102
103 /**
104 * Using this function to enable or disable canonical mode only affects
105 * the way the data is processed and which virtual functions are called
106 * during processing. It does not affect options set locally or
107 * remotely. Setting this to false will enable char-at-a-time mode,
108 * effectively disabling internal line-editing code. Characters
109 * such as backspace that are detected will not be handled and will be
110 * sent to the user override. The subclass will also be notified every
111 * time new data is available, not just whole lines.
112 *
113 * When set to true (the default), line editing control codes will be
114 * interpreted and used, and the subclass will only be notified when
115 * complete lines are available in the buffer.
116 */
117 void setCanonical( bool bCon=true );
118 bool isCanonical();
119
120 void write( const Bu::String &sData );
121 void write( const char *pData, int iSize );
122 void write( char cData );
123
124 const Bu::String &getBuffer() { return sDataBuf; }
125
126 public:
127 /**
128 * If you wish to know the current dimensions of the client window,
129 * override this function, it will be called whenever the size changes.
130 */
131 virtual void onSubNAWS( uint16_t /*iWidth*/, uint16_t /*iHeight*/ ){};
132
133 /**
134 * This function is called whenever an unknown sub negotiation option is
135 * sent over the line. This doesn't mean that it's malformatted, it
136 * just means that this class doesn't support that option yet, but you
137 * can handle it yourself if you'd like. Feel free to change the
138 * sSubBuf, it will be cleared as soon as this function returns anyway.
139 */
140 virtual void onSubUnknown( char /*cSubOpt*/,
141 Bu::String & /*sSubBuf*/ ){};
142
143 private:
144 /**
145 * Represents a basic telnet option, either on or off, no parameters.
146 * Each Option can negotiate effectively on it's own, and has two
147 * parameters in each of two classes. Both local and remote can be
148 * enabled/disabled and set/unset. Enabled represents the ability to
149 * set the option, disabling an option should also unset it. Set or
150 * unset represent wether the option is being used, if it is allowed.
151 */
152 class Option
153 {
154 friend class Bu::ProtocolTelnet;
155 private:
156 Option( ProtocolTelnet &rPT, char cCode );
157 virtual ~Option();
158
159 public:
160 void localEnable( bool bSet=true );
161 void localSet( bool bSet=true );
162
163 bool isLocalEnabled();
164 bool isLocalSet();
165
166 void remoteEnable( bool bSet=true );
167 void remoteSet( bool bSet=true );
168
169 bool isRemoteEnabled();
170 bool isRemoteSet();
171
172 private:
173 enum
174 {
175 fLocalCant = 0x01, /**< Local can't/won't allow option. */
176 fLocalIs = 0x02, /**< Local is using option. */
177 fRemoteCant = 0x04, /**< Remote can't/won't allow option. */
178 fRemoteIs = 0x08 /**< Remote is using option. */
179 };
180
181 ProtocolTelnet &rPT;
182 char fOpts;
183 char cCode;
184 };
185 friend class Bu::ProtocolTelnet::Option;
186
187 Hash<char, Option *> hOpts;
188
189 public:
190 Option oBinary;
191 Option oEcho;
192 Option oNAWS;
193 Option oSuppressGA;
194
195 private:
196 void onWill( char cCode );
197 void onWont( char cCode );
198 void onDo( char cCode );
199 void onDont( char cCode );
200 void onSubOpt();
201 void onCtlChar( char cChr );
202
203#ifdef __TELNET_DEBUG
204 void printCode( char cCode );
205 void printOpt( char cOpt );
206#endif
207
208 private:
209 Client *pClient;
210
211 Bu::String sDataBuf; /**< Buffer for regular line data. */
212 Bu::String sSubBuf; /**< Buffer for subnegotiation data. */
213 char cSubOpt; /**< Which suboption are we processing. */
214
215 bool bCanonical; /**< Are we canonicalizing incoming data? */
216 bool bSubOpt; /**< Are we processing a suboption right now? */
217 };
218}
219
220#endif
diff --git a/src/stable/queue.cpp b/src/stable/queue.cpp
new file mode 100644
index 0000000..9d6edac
--- /dev/null
+++ b/src/stable/queue.cpp
@@ -0,0 +1,8 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/queue.h"
diff --git a/src/stable/queue.h b/src/stable/queue.h
new file mode 100644
index 0000000..e5d9b5f
--- /dev/null
+++ b/src/stable/queue.h
@@ -0,0 +1,40 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_QUEUE_H
9#define BU_QUEUE_H
10
11namespace Bu
12{
13 /**
14 * Queue abstract baseclass
15 */
16 template<typename value>
17 class Queue
18 {
19 public:
20 Queue()
21 {
22 }
23
24 virtual ~Queue()
25 {
26 }
27
28 virtual void enqueue( const value &i )=0;
29 virtual value dequeue()=0;
30 virtual value &peek()=0;
31 virtual const value &peek() const=0;
32 virtual bool isEmpty() const=0;
33 virtual int getSize() const=0;
34
35 private:
36
37 };
38}
39
40#endif
diff --git a/src/stable/queuebuf.cpp b/src/stable/queuebuf.cpp
new file mode 100644
index 0000000..98d8ee0
--- /dev/null
+++ b/src/stable/queuebuf.cpp
@@ -0,0 +1,278 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/queuebuf.h"
9
10#include "bu/sio.h"
11using Bu::sio;
12
13Bu::QueueBuf::QueueBuf( int iBlockSize /*=256*/ ) :
14 iBlockSize( iBlockSize ),
15 iReadOffset( 0 ),
16 iWriteOffset( 0 ),
17 iTotalSize( 0 )
18{
19}
20
21Bu::QueueBuf::~QueueBuf()
22{
23 for( BlockList::iterator i = lBlocks.begin(); i; i++ )
24 delete[] *i;
25}
26
27void Bu::QueueBuf::close()
28{
29 for( BlockList::iterator i = lBlocks.begin(); i; i++ )
30 delete[] *i;
31 lBlocks.clear();
32 iReadOffset = iWriteOffset = iTotalSize = 0;
33}
34
35Bu::size Bu::QueueBuf::read( void *pRawBuf, Bu::size nBytes )
36{
37 if( nBytes <= 0 )
38 return 0;
39
40 if( lBlocks.isEmpty() )
41 return 0;
42
43 Bu::size iLeft = nBytes;
44 char *pBuf = (char *)pRawBuf;
45
46 while( iLeft > 0 && iTotalSize > 0 )
47 {
48 if( iReadOffset == iBlockSize )
49 {
50 removeBlock();
51 if( lBlocks.isEmpty() )
52 {
53 return nBytes-iLeft;
54 }
55 iReadOffset = 0;
56 }
57 char *pBlock = lBlocks.first();
58 Bu::size iCopy = iBlockSize-iReadOffset;
59 if( iLeft < iCopy )
60 iCopy = iLeft;
61 if( iTotalSize < iCopy )
62 iCopy = iTotalSize;
63 memcpy( pBuf, pBlock+iReadOffset, iCopy );
64 iReadOffset += iCopy;
65 iLeft -= iCopy;
66 pBuf += iCopy;
67 iTotalSize -= iCopy;
68// sio << "Read " << iCopy << " bytes, new size: " << iTotalSize << sio.nl;
69 }
70
71 return nBytes - iLeft;
72}
73
74Bu::size Bu::QueueBuf::peek( void *pBuf, Bu::size nBytes )
75{
76 return peek( pBuf, nBytes, 0 );
77}
78
79Bu::size Bu::QueueBuf::peek( void *pRawBuf, Bu::size nBytes, Bu::size nSkip )
80{
81 if( nBytes <= 0 )
82 return 0;
83
84 if( lBlocks.isEmpty() )
85 return 0;
86
87 Bu::size iLeft = nBytes;
88 char *pBuf = (char *)pRawBuf;
89
90 int iTmpReadOffset = iReadOffset + nSkip;
91 Bu::size iTmpRemSize = iTotalSize;
92 BlockList::iterator iBlock = lBlocks.begin();
93 while( iTmpReadOffset > iBlockSize )
94 {
95 iTmpReadOffset -= iBlockSize;
96 iBlock++;
97 }
98 while( iLeft > 0 && iTmpRemSize > 0 )
99 {
100 if( iTmpReadOffset == iBlockSize )
101 {
102 iBlock++;
103 if( iBlock == lBlocks.end() )
104 {
105 return nBytes-iLeft;
106 }
107 iTmpReadOffset = 0;
108 }
109 char *pBlock = *iBlock;
110 Bu::size iCopy = iBlockSize-iTmpReadOffset;
111 if( iLeft < iCopy )
112 iCopy = iLeft;
113 if( iTmpRemSize < iCopy )
114 iCopy = iTmpRemSize;
115 memcpy( pBuf, pBlock+iTmpReadOffset, iCopy );
116 iTmpReadOffset += iCopy;
117 iLeft -= iCopy;
118 pBuf += iCopy;
119 iTmpRemSize -= iCopy;
120// sio << "Read (peek) " << iCopy << " bytes, new temp size: "
121// << iTmpRemSize << sio.nl;
122 }
123
124 return nBytes - iLeft;
125}
126
127Bu::size Bu::QueueBuf::write( const void *pRawBuf, Bu::size nBytes )
128{
129 if( nBytes <= 0 )
130 return 0;
131
132 if( lBlocks.isEmpty() )
133 {
134 addBlock();
135 iWriteOffset = 0;
136 }
137 Bu::size iLeft = nBytes;
138 const char *pBuf = (const char *)pRawBuf;
139
140 while( iLeft > 0 )
141 {
142 if( iWriteOffset == iBlockSize )
143 {
144 addBlock();
145 iWriteOffset = 0;
146 }
147 char *pBlock = lBlocks.last();
148 Bu::size iCopy = iBlockSize-iWriteOffset;
149 if( iLeft < iCopy )
150 iCopy = iLeft;
151 memcpy( pBlock+iWriteOffset, pBuf, iCopy );
152 iWriteOffset += iCopy;
153 iLeft -= iCopy;
154 pBuf += iCopy;
155 iTotalSize += iCopy;
156// sio << "Wrote " << iCopy << " bytes, new size: " << iTotalSize
157// << sio.nl;
158 }
159
160 return nBytes;
161}
162
163Bu::size Bu::QueueBuf::tell()
164{
165 return -1;
166}
167
168void Bu::QueueBuf::seek( Bu::size iAmnt )
169{
170 if( iAmnt <= 0 )
171 return;
172
173 if( (Bu::size)iAmnt >= iTotalSize )
174 {
175// sio << "seek: clear all data (" << iAmnt << ">=" << iTotalSize
176// << ")." << sio.nl;
177 close();
178 return;
179 }
180
181 iReadOffset += iAmnt;
182 iTotalSize -= iAmnt;
183 while( iReadOffset >= iBlockSize )
184 {
185 removeBlock();
186 iReadOffset -= iBlockSize;
187// sio << "seek: removal step (" << iReadOffset << ")" << sio.nl;
188 }
189}
190
191void Bu::QueueBuf::setPos( Bu::size )
192{
193}
194
195void Bu::QueueBuf::setPosEnd( Bu::size )
196{
197}
198
199bool Bu::QueueBuf::isEos()
200{
201 return iTotalSize == 0;
202}
203
204bool Bu::QueueBuf::isOpen()
205{
206 return true;
207}
208
209void Bu::QueueBuf::flush()
210{
211}
212
213bool Bu::QueueBuf::canRead()
214{
215 return iTotalSize > 0;
216}
217
218bool Bu::QueueBuf::canWrite()
219{
220 return true;
221}
222
223bool Bu::QueueBuf::isReadable()
224{
225 return true;
226}
227
228bool Bu::QueueBuf::isWritable()
229{
230 return true;
231}
232
233bool Bu::QueueBuf::isSeekable()
234{
235 return false;
236}
237
238bool Bu::QueueBuf::isBlocking()
239{
240 return false;
241}
242
243void Bu::QueueBuf::setBlocking( bool )
244{
245}
246
247void Bu::QueueBuf::setSize( Bu::size )
248{
249}
250
251Bu::size Bu::QueueBuf::getSize() const
252{
253 return iTotalSize;
254}
255
256Bu::size Bu::QueueBuf::getBlockSize() const
257{
258 return iBlockSize;
259}
260
261Bu::String Bu::QueueBuf::getLocation() const
262{
263 return "";
264}
265
266void Bu::QueueBuf::addBlock()
267{
268 lBlocks.append( new char[iBlockSize] );
269// sio << "Added new block." << sio.nl;
270}
271
272void Bu::QueueBuf::removeBlock()
273{
274 delete[] lBlocks.first();
275 lBlocks.erase( lBlocks.begin() );
276// sio << "Removed block." << sio.nl;
277}
278
diff --git a/src/stable/queuebuf.h b/src/stable/queuebuf.h
new file mode 100644
index 0000000..929ca35
--- /dev/null
+++ b/src/stable/queuebuf.h
@@ -0,0 +1,66 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_QUEUE_BUF_H
9#define BU_QUEUE_BUF_H
10
11#include "bu/stream.h"
12
13namespace Bu
14{
15 /**
16 * A queuing buffer stream class. All data written to this class is
17 * appended to it, there is no stored position. All data read is read
18 * from the begining and then thrown away. It operates by using a linked
19 * list of small buffers, and deallocating or reusing them when it can.
20 */
21 class QueueBuf : public Bu::Stream
22 {
23 public:
24 QueueBuf( int iBlockSize=256 );
25 virtual ~QueueBuf();
26
27 virtual void close();
28 virtual Bu::size read( void *pBuf, Bu::size nBytes );
29 virtual Bu::size peek( void *pBuf, Bu::size nBytes );
30 virtual Bu::size peek( void *pBuf, Bu::size nBytes, Bu::size nSkip );
31 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
32 virtual Bu::size tell();
33 virtual void seek( Bu::size offset );
34 virtual void setPos( Bu::size pos );
35 virtual void setPosEnd( Bu::size pos );
36 virtual bool isEos();
37 virtual bool isOpen();
38 virtual void flush();
39 virtual bool canRead();
40 virtual bool canWrite();
41 virtual bool isReadable();
42 virtual bool isWritable();
43 virtual bool isSeekable();
44 virtual bool isBlocking();
45 virtual void setBlocking( bool bBlocking=true );
46 virtual void setSize( Bu::size iSize );
47
48 virtual size getSize() const;
49 virtual size getBlockSize() const;
50 virtual Bu::String getLocation() const;
51
52 private:
53 void addBlock();
54 void removeBlock();
55
56 private:
57 int iBlockSize;
58 int iReadOffset;
59 int iWriteOffset;
60 Bu::size iTotalSize;
61 typedef Bu::List<char *> BlockList;
62 BlockList lBlocks;
63 };
64};
65
66#endif
diff --git a/src/stable/ringbuffer.cpp b/src/stable/ringbuffer.cpp
new file mode 100644
index 0000000..99b1b1c
--- /dev/null
+++ b/src/stable/ringbuffer.cpp
@@ -0,0 +1,9 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/ringbuffer.h"
9
diff --git a/src/stable/ringbuffer.h b/src/stable/ringbuffer.h
new file mode 100644
index 0000000..f43773d
--- /dev/null
+++ b/src/stable/ringbuffer.h
@@ -0,0 +1,228 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_RING_BUFFER_H
9#define BU_RING_BUFFER_H
10
11#include <memory>
12#include "bu/exceptionbase.h"
13#include "bu/queue.h"
14#include "bu/sharedcore.h"
15
16namespace Bu
17{
18 template<typename value, typename valuealloc> class RingBuffer;
19
20 /** @cond DEVEL */
21 template<typename value, typename valuealloc>
22 class RingBufferCore
23 {
24 friend class RingBuffer<value, valuealloc>;
25 friend class SharedCore<RingBuffer<value, valuealloc>,
26 RingBufferCore<value, valuealloc> >;
27 private:
28 RingBufferCore() :
29 iCapacity( 0 ),
30 iStart( -1 ),
31 iEnd( -2 ),
32 aData( NULL )
33 {
34 }
35
36 virtual ~RingBufferCore()
37 {
38 clear();
39 }
40
41 void init( int iNewCapacity )
42 {
43 if( iCapacity > 0 )
44 return;
45
46 iCapacity = iNewCapacity;
47 iStart = -1;
48 iEnd = -2;
49 aData = va.allocate( iCapacity );
50 }
51
52 void clear()
53 {
54 for( int j = iStart; j < iEnd; j=(j+1%iCapacity) )
55 {
56 va.destroy( &aData[j] );
57 }
58 va.deallocate( aData, iCapacity );
59 aData = NULL;
60 iCapacity = 0;
61 }
62
63 void enqueue( const value &v )
64 {
65 if( iStart == -1 )
66 {
67 iStart = 0;
68 iEnd = 1;
69 va.construct( &aData[0], v );
70 }
71 else if( iStart == iEnd )
72 {
73 throw ExceptionBase("Hey, it's full!");
74 }
75 else
76 {
77 va.construct( &aData[iEnd], v );
78 iEnd = (iEnd+1)%iCapacity;
79 }
80 }
81
82 value dequeue()
83 {
84 if( iStart == -1 )
85 {
86 throw ExceptionBase("No data");
87 }
88 else
89 {
90 value &v = aData[iStart];
91 va.destroy( &aData[iStart] );
92 iStart = (iStart+1)%iCapacity;
93 if( iStart == iEnd )
94 {
95 iStart = -1;
96 iEnd = -2;
97 }
98 return v;
99 }
100 }
101
102 value &get( int iIndex )
103 {
104 return aData[(iIndex+iStart)%iCapacity];
105 }
106
107 int getSize()
108 {
109 if( iStart < 0 )
110 return 0;
111 if( iEnd == iStart )
112 return iCapacity;
113 if( iEnd < iStart )
114 return iEnd-iStart;
115 return iCapacity-(iEnd-iStart);
116 }
117
118 int iCapacity;
119 int iStart, iEnd;
120 value *aData;
121 valuealloc va;
122 };
123 /** @endcond */
124
125 /**
126 *@ingroup Containers
127 */
128 template<typename value, typename valuealloc=std::allocator<value> >
129 class RingBuffer : public Queue<value>, public SharedCore<
130 RingBuffer<value, valuealloc>,
131 RingBufferCore<value, valuealloc>
132 >
133 {
134 private:
135 typedef RingBuffer<value, valuealloc> MyType;
136 typedef RingBufferCore<value, valuealloc> Core;
137
138 protected:
139 using SharedCore<MyType, Core>::core;
140 using SharedCore<MyType, Core>::_hardCopy;
141 using SharedCore<MyType, Core>::_allocateCore;
142
143 public:
144 RingBuffer( int iCapacity )
145 {
146 core->init( iCapacity );
147 }
148
149 RingBuffer( const RingBuffer &rSrc ) :
150 SharedCore<MyType, Core>( rSrc )
151 {
152 }
153
154 virtual ~RingBuffer()
155 {
156 }
157
158 int getCapacity() const
159 {
160 return core->iCapacity;
161 }
162
163 bool isFilled() const
164 {
165 return (core->iStart == core->iEnd);
166 }
167
168 bool isEmpty() const
169 {
170 return (core->iStart == -1);
171 }
172
173 virtual void enqueue( const value &v )
174 {
175 _hardCopy();
176
177 core->enqueue( v );
178 }
179
180 virtual value dequeue()
181 {
182 _hardCopy();
183
184 return core->dequeue();
185 }
186
187 virtual int getSize() const
188 {
189 return core->getSize();
190 }
191
192 virtual value &peek()
193 {
194 _hardCopy();
195
196 return core->get( 0 );
197 }
198
199 virtual const value &peek() const
200 {
201 return core->get( 0 );
202 }
203
204 value &operator[]( int iIndex )
205 {
206 _hardCopy();
207
208 return core->get( iIndex );
209 }
210
211 protected:
212 virtual Core *_copyCore( Core *src )
213 {
214 Core *pRet = _allocateCore();
215
216 pRet->init( src->iCapacity );
217 int iSize = src->getSize();
218 for( int j = 0; j < iSize; j++ )
219 {
220 pRet->enqueue( src->get( j ) );
221 }
222
223 return pRet;
224 }
225 };
226}
227
228#endif
diff --git a/src/stable/server.cpp b/src/stable/server.cpp
new file mode 100644
index 0000000..1972a3f
--- /dev/null
+++ b/src/stable/server.cpp
@@ -0,0 +1,214 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/server.h"
9#include <errno.h>
10#include <unistd.h>
11#include "bu/tcpserversocket.h"
12#include "bu/client.h"
13#include "bu/tcpsocket.h"
14#include "bu/config.h"
15
16Bu::Server::Server() :
17 nTimeoutSec( 0 ),
18 nTimeoutUSec( 0 ),
19 bAutoTick( false )
20{
21 FD_ZERO( &fdActive );
22}
23
24Bu::Server::~Server()
25{
26 shutdown();
27}
28
29void Bu::Server::addPort( int nPort, int nPoolSize )
30{
31 TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize );
32 int nSocket = s->getSocket();
33 FD_SET( nSocket, &fdActive );
34 hServers.insert( nSocket, s );
35}
36
37void Bu::Server::addPort( const String &sAddr, int nPort, int nPoolSize )
38{
39 TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize );
40 int nSocket = s->getSocket();
41 FD_SET( nSocket, &fdActive );
42 hServers.insert( nSocket, s );
43}
44
45void Bu::Server::setTimeout( int nTimeoutSec, int nTimeoutUSec )
46{
47 this->nTimeoutSec = nTimeoutSec;
48 this->nTimeoutUSec = nTimeoutUSec;
49}
50
51void Bu::Server::scan()
52{
53 struct timeval xTimeout = { nTimeoutSec, nTimeoutUSec };
54
55 fd_set fdRead = fdActive;
56 fd_set fdWrite /* = fdActive*/;
57 fd_set fdException = fdActive;
58
59 FD_ZERO( &fdWrite );
60 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
61 {
62 if( (*i)->hasOutput() )
63 FD_SET( i.getKey(), &fdWrite );
64 }
65
66 if( TEMP_FAILURE_RETRY( select( FD_SETSIZE,
67 &fdRead, &fdWrite, &fdException, &xTimeout ) ) < 0 )
68 {
69 throw ExceptionBase("Error attempting to scan open connections.");
70 }
71
72 for( int j = 0; j < FD_SETSIZE; j++ )
73 {
74 if( FD_ISSET( j, &fdRead ) )
75 {
76 if( hServers.has( j ) )
77 {
78 TcpServerSocket *pSrv = hServers.get( j );
79 addClient( pSrv->accept(), pSrv->getPort() );
80 }
81 else
82 {
83 Client *pClient = hClients.get( j );
84 pClient->processInput();
85 if( !pClient->isOpen() )
86 {
87 closeClient( j );
88 }
89 }
90 }
91 if( FD_ISSET( j, &fdWrite ) )
92 {
93 try
94 {
95 Client *pClient = hClients.get( j );
96 try
97 {
98 pClient->processOutput();
99 }
100 catch( Bu::TcpSocketException &e )
101 {
102 closeClient( j );
103 }
104 }
105 catch( Bu::HashException &e )
106 {
107 // Do nothing, I guess, the client is already dead...
108 // TODO: Someday, we may want to handle this more graceully.
109 }
110 }
111 }
112
113 Bu::List<int> lDelete;
114 // Now we just try to write all the pending data on all the sockets.
115 // this could be done better eventually, if we care about the socket
116 // wanting to accept writes (using a select).
117 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
118 {
119 if( (*i)->wantsDisconnect() && !(*i)->hasOutput() )
120 {
121 lDelete.append( i.getKey() );
122 }
123 }
124
125 for( Bu::List<int>::iterator i = lDelete.begin(); i != lDelete.end(); i++ )
126 {
127 closeClient( *i );
128 }
129
130 if( bAutoTick )
131 tick();
132}
133
134void Bu::Server::addClient( int nSocket, int nPort )
135{
136 FD_SET( nSocket, &fdActive );
137
138 Client *c = new Client(
139 new Bu::TcpSocket( nSocket ),
140 new SrvClientLinkFactory()
141 );
142 hClients.insert( nSocket, c );
143
144 onNewConnection( c, nPort );
145}
146
147Bu::Server::SrvClientLink::SrvClientLink( Bu::Client *pClient ) :
148 pClient( pClient )
149{
150}
151
152Bu::Server::SrvClientLink::~SrvClientLink()
153{
154}
155
156void Bu::Server::SrvClientLink::sendMessage( const Bu::String &sMsg )
157{
158 pClient->onMessage( sMsg );
159}
160
161Bu::Server::SrvClientLinkFactory::SrvClientLinkFactory()
162{
163}
164
165Bu::Server::SrvClientLinkFactory::~SrvClientLinkFactory()
166{
167}
168
169Bu::ClientLink *Bu::Server::SrvClientLinkFactory::createLink(
170 Bu::Client *pClient )
171{
172 return new SrvClientLink( pClient );
173}
174
175void Bu::Server::setAutoTick( bool bEnable )
176{
177 bAutoTick = bEnable;
178}
179
180void Bu::Server::tick()
181{
182 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
183 {
184 (*i)->tick();
185 }
186}
187
188void Bu::Server::shutdown()
189{
190 for( SrvHash::iterator i = hServers.begin(); i != hServers.end(); i++ )
191 {
192 delete *i;
193 }
194
195 hServers.clear();
196
197 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
198 {
199 closeClient( i.getKey() );
200 }
201
202 hClients.clear();
203}
204
205void Bu::Server::closeClient( int iSocket )
206{
207 Bu::Client *pClient = hClients.get( iSocket );
208 onClosedConnection( pClient );
209 pClient->close();
210 hClients.erase( iSocket );
211 FD_CLR( iSocket, &fdActive );
212 delete pClient;
213}
214
diff --git a/src/stable/server.h b/src/stable/server.h
new file mode 100644
index 0000000..c59543a
--- /dev/null
+++ b/src/stable/server.h
@@ -0,0 +1,108 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SERVER_H
9#define BU_SERVER_H
10
11#include <stdint.h>
12
13#ifndef WIN32
14 #include <sys/select.h>
15#endif
16
17#include "bu/string.h"
18#include "bu/list.h"
19
20#include "bu/clientlink.h"
21#include "bu/clientlinkfactory.h"
22#include "bu/hash.h"
23
24#include "bu/config.h"
25
26namespace Bu
27{
28 class TcpServerSocket;
29 class TcpSocket;
30 class Client;
31
32 /**
33 * Core of a network server. This class is distinct from a ServerSocket in
34 * that a ServerSocket is one listening socket, nothing more. Socket will
35 * manage a pool of both ServerSockets and connected Sockets along with
36 * their protocols and buffers.
37 *
38 * To start serving on a new port, use the addPort functions. Each call to
39 * addPort creates a new ServerSocket, starts it listening, and adds it to
40 * the server pool.
41 *
42 * All of the real work is done by scan, which will wait for up
43 * to the timeout set by setTimeout before returning if there is no data
44 * pending. scan should probably be called in some sort of tight
45 * loop, possibly in it's own thread, or in the main control loop.
46 *
47 * In order to use a Server you must subclass it and implement the pure
48 * virtual functions. These allow you to receive notification of events
49 * happening within the server itself, and actually makes it useful.
50 *@ingroup Serving
51 */
52 class Server
53 {
54 public:
55 Server();
56 virtual ~Server();
57
58 void addPort( int nPort, int nPoolSize=40 );
59 void addPort( const String &sAddr, int nPort, int nPoolSize=40 );
60
61 virtual void scan();
62 void setTimeout( int nTimeoutSec, int nTimeoutUSec=0 );
63
64 void addClient( int nSocket, int nPort );
65
66 void setAutoTick( bool bEnable=true );
67 void tick();
68
69 virtual void onNewConnection( Client *pClient, int nPort )=0;
70 virtual void onClosedConnection( Client *pClient )=0;
71
72 void shutdown();
73
74 private:
75 void closeClient( int iSocket );
76 class SrvClientLink : public Bu::ClientLink
77 {
78 public:
79 SrvClientLink( Bu::Client *pClient );
80 virtual ~SrvClientLink();
81
82 virtual void sendMessage( const Bu::String &sMsg );
83
84 private:
85 Bu::Client *pClient;
86 };
87
88 class SrvClientLinkFactory : public Bu::ClientLinkFactory
89 {
90 public:
91 SrvClientLinkFactory();
92 virtual ~SrvClientLinkFactory();
93
94 virtual Bu::ClientLink *createLink( Bu::Client *pClient );
95 };
96
97 int nTimeoutSec;
98 int nTimeoutUSec;
99 fd_set fdActive;
100 typedef Hash<int,TcpServerSocket *> SrvHash;
101 SrvHash hServers;
102 typedef Hash<int,Client *> ClientHash;
103 ClientHash hClients;
104 bool bAutoTick;
105 };
106}
107
108#endif
diff --git a/src/stable/sha1.cpp b/src/stable/sha1.cpp
new file mode 100644
index 0000000..bfe4c5a
--- /dev/null
+++ b/src/stable/sha1.cpp
@@ -0,0 +1,194 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include <string.h>
9
10#include "bu/stream.h"
11
12#include "bu/sha1.h"
13
14Bu::Sha1::Sha1() :
15 uH0( 0x67452301 ),
16 uH1( 0xefcdab89 ),
17 uH2( 0x98badcfe ),
18 uH3( 0x10325476 ),
19 uH4( 0xc3d2e1f0 ),
20 iUnprocessedBytes( 0 ),
21 uTotalBytes( 0 )
22{
23 reset();
24}
25
26Bu::Sha1::~Sha1()
27{
28}
29
30void Bu::Sha1::reset()
31{
32 uH0 = 0x67452301;
33 uH1 = 0xefcdab89;
34 uH2 = 0x98badcfe;
35 uH3 = 0x10325476;
36 uH4 = 0xc3d2e1f0;
37 iUnprocessedBytes = 0;
38 uTotalBytes = 0;
39}
40
41void Bu::Sha1::setSalt( const Bu::String & /*sSalt*/ )
42{
43}
44
45void Bu::Sha1::addData( const void *sDataRaw, int iSize )
46{
47 const unsigned char *sData = (const unsigned char *)sDataRaw;
48 // add these bytes to the running total
49 uTotalBytes += iSize;
50
51 // repeat until all data is processed
52 while( iSize > 0 )
53 {
54 // number of bytes required to complete block
55 int iNeeded = 64 - iUnprocessedBytes;
56
57 // number of bytes to copy (use smaller of two)
58 int iToCopy = (iSize < iNeeded) ? iSize : iNeeded;
59
60 // Copy the bytes
61 memcpy( uBytes + iUnprocessedBytes, sData, iToCopy );
62
63 // Bytes have been copied
64 iSize -= iToCopy;
65 sData += iToCopy;
66 iUnprocessedBytes += iToCopy;
67
68 // there is a full block
69 if( iUnprocessedBytes == 64 )
70 {
71 process();
72 }
73 }
74}
75
76Bu::String Bu::Sha1::getResult()
77{
78 // save the message size
79 uint32_t totalBitsL = uTotalBytes << 3;
80 uint32_t totalBitsH = uTotalBytes >> 29;
81
82 // add 0x80 to the message
83 addData( "\x80", 1 );
84
85 unsigned char footer[64] = {
86 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
90
91 // block has no room for 8-byte filesize, so finish it
92 if( iUnprocessedBytes > 56 )
93 addData( (char*)footer, 64 - iUnprocessedBytes);
94
95 // how many zeros do we need
96 int iNeededZeros = 56 - iUnprocessedBytes;
97
98 // store file size (in bits) in big-endian format
99 toBigEndian( totalBitsH, footer + iNeededZeros );
100 toBigEndian( totalBitsL, footer + iNeededZeros + 4 );
101
102 // finish the final block
103 addData( (char*)footer, iNeededZeros + 8 );
104
105 Bu::String sRet( 20 );
106
107 unsigned char *digest = (unsigned char *)sRet.getStr();
108
109 // copy the digest bytes
110 toBigEndian( uH0, digest );
111 toBigEndian( uH1, digest + 4 );
112 toBigEndian( uH2, digest + 8 );
113 toBigEndian( uH3, digest + 12 );
114 toBigEndian( uH4, digest + 16 );
115
116 // return the digest
117 return sRet;
118}
119
120void Bu::Sha1::writeResult( Bu::Stream &sOut )
121{
122 sOut.write( getResult() );
123}
124
125void Bu::Sha1::process()
126{
127 int t;
128 uint32_t a, b, c, d, e, K, f, W[80];
129
130 // starting values
131 a = uH0;
132 b = uH1;
133 c = uH2;
134 d = uH3;
135 e = uH4;
136
137 // copy and expand the message block
138 for( t = 0; t < 16; t++ ) W[t] = (uBytes[t*4] << 24)
139 +(uBytes[t*4 + 1] << 16)
140 +(uBytes[t*4 + 2] << 8)
141 + uBytes[t*4 + 3];
142 for(; t< 80; t++ ) W[t] = lrot( W[t-3]^W[t-8]^W[t-14]^W[t-16], 1 );
143
144 /* main loop */
145 uint32_t temp;
146 for( t = 0; t < 80; t++ )
147 {
148 if( t < 20 ) {
149 K = 0x5a827999;
150 f = (b & c) | ((~b) & d);
151 } else if( t < 40 ) {
152 K = 0x6ed9eba1;
153 f = b ^ c ^ d;
154 } else if( t < 60 ) {
155 K = 0x8f1bbcdc;
156 f = (b & c) | (b & d) | (c & d);
157 } else {
158 K = 0xca62c1d6;
159 f = b ^ c ^ d;
160 }
161 temp = lrot(a,5) + f + e + W[t] + K;
162 e = d;
163 d = c;
164 c = lrot(b,30);
165 b = a;
166 a = temp;
167 //printf( "t=%d %08x %08x %08x %08x %08x\n",t,a,b,c,d,e );
168 }
169
170 /* add variables */
171 uH0 += a;
172 uH1 += b;
173 uH2 += c;
174 uH3 += d;
175 uH4 += e;
176
177 //printf( "Current: %08x %08x %08x %08x %08x\n",H0,H1,H2,H3,H4 );
178 /* all bytes have been processed */
179 iUnprocessedBytes = 0;
180}
181
182uint32_t Bu::Sha1::lrot( uint32_t x, int bits )
183{
184 return (x<<bits) | (x>>(32 - bits));
185}
186
187void Bu::Sha1::toBigEndian( uint32_t num, unsigned char* byte )
188{
189 byte[0] = (unsigned char)(num>>24);
190 byte[1] = (unsigned char)(num>>16);
191 byte[2] = (unsigned char)(num>>8);
192 byte[3] = (unsigned char)num;
193}
194
diff --git a/src/stable/sha1.h b/src/stable/sha1.h
new file mode 100644
index 0000000..1b7f6df
--- /dev/null
+++ b/src/stable/sha1.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef SHA1_H
9#define SHA1_H
10
11#include <stdint.h>
12#include "bu/cryptohash.h"
13
14namespace Bu
15{
16 /**
17 * Calculates SHA-1 sums. This is based strongly on code from Michael D.
18 * Leonhard who released his code under the terms of the MIT license,
19 * thank you! Check out his website http://tamale.net he has a lot of
20 * cool stuff there.
21 */
22 class Sha1 : public CryptoHash
23 {
24 public:
25 Sha1();
26 virtual ~Sha1();
27
28 virtual void reset();
29 virtual void setSalt( const Bu::String &sSalt );
30 virtual void addData( const void *sData, int iSize );
31 using CryptoHash::addData;
32 virtual String getResult();
33 virtual void writeResult( Stream &sOut );
34
35 void update( const char* data, int num );
36 unsigned char* getDigest();
37
38 // utility methods
39
40 private:
41 static uint32_t lrot( uint32_t x, int bits );
42 static void toBigEndian( uint32_t in, unsigned char* out );
43 void process();
44
45 private:
46 uint32_t uH0, uH1, uH2, uH3, uH4;
47 unsigned char uBytes[64];
48 int iUnprocessedBytes;
49 uint32_t uTotalBytes;
50 };
51};
52
53#endif
diff --git a/src/stable/sharedcore.cpp b/src/stable/sharedcore.cpp
new file mode 100644
index 0000000..75f92eb
--- /dev/null
+++ b/src/stable/sharedcore.cpp
@@ -0,0 +1,9 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/sharedcore.h"
9
diff --git a/src/stable/sharedcore.h b/src/stable/sharedcore.h
new file mode 100644
index 0000000..bf9395c
--- /dev/null
+++ b/src/stable/sharedcore.h
@@ -0,0 +1,193 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SHARED_CORE_H
9#define BU_SHARED_CORE_H
10
11#include "bu/util.h"
12
13#include <stdio.h>
14#include <stdarg.h>
15
16namespace Bu
17{
18 /**
19 * A mechanism for creating classes that perform lazy copies. The concept
20 * behind this is that instead of copying a large object when it is assigned
21 * or passed into a copy constructor we simply copy a pointer internally.
22 * The assumption is that many times when an object is passed by value we
23 * don't really want to keep the object around, we want the recipient to
24 * take ownership without allocating a new object. This allows that to
25 * happen.
26 *
27 * When used properly this makes object copying essentially free (O(1),
28 * that is) and performs the actual copy when a user tries to modify the
29 * object.
30 *
31 * For example, lets look at something like the getKeys function in
32 * Bu::Hash. When this function is called it creates a Bu::List of
33 * appropriate type, fills it with keys, and returns it. This is a good
34 * way for this function to behave, there may be additional issues if the
35 * List object were allocated with new and not on the stack. However,
36 * returning the List at the end of the function could potentially take
37 * a very long time depending on the size of the list and the type of the
38 * key. In this case the getKeys function doesn't want ownership of the
39 * List object, and when it returns it, it's local copy will be destroyed.
40 *
41 * However, List inherits from SharedCore, which means that when it is
42 * returned all we do is copy a pointer to the "core" of the list, which
43 * is a very fast operatorion. For a brief moment, before anyone can do
44 * anything else, there are two objects referencing the core of that single
45 * list. However, the getKeys() function will destroy it's local copy
46 * before the calling function can use it's new copy. That means that by
47 * the time the calling function can use it's new List of keys it is the
48 * only one with a reference to the core, and no copy will need to happen.
49 *
50 * Using SharedCore on your own classes is fairly straight forward. There
51 * are only a couple of steps. First, break the class into two classes.
52 * Move every variable from the original class (generally everything that's
53 * private) into the new class. Then make the original class inherit from
54 * SharedCore. The SharedCore template takes 2 parameters, first is the
55 * class it's inheriting from, second is the new core class. Now, in your
56 * original class you will have one class variable, a pointer named core.
57 * All of your original variables will be accessable through core. The next
58 * step is to access everything you used to through core, and to find
59 * every function that may change data in the core. At the top of every
60 * function that may change data you want to call _hardCopy().
61 *
62 * That's more or less it. A more detailed guide will be written soon.
63 * @todo Write a guide for this.
64 */
65 template<typename Shell, typename Core>
66 class SharedCore
67 {
68 typedef class SharedCore<Shell, Core> _SharedType;
69 public:
70 SharedCore() :
71 core( NULL ),
72 iRefCount( NULL )
73 {
74 core = _allocateCore();
75 iRefCount = new int(1);
76 }
77
78 SharedCore( const _SharedType &rSrc ) :
79 core( NULL ),
80 iRefCount( NULL )
81 {
82 _softCopy( rSrc );
83 }
84
85 virtual ~SharedCore()
86 {
87 _deref();
88 }
89
90 SharedCore &operator=( const SharedCore &rhs )
91 {
92 if( core == rhs.core )
93 return *this;
94
95 _softCopy( rhs );
96 return *this;
97 }
98
99 int getRefCount() const
100 {
101 return *iRefCount;
102 }
103
104 Shell clone() const
105 {
106 Shell s( dynamic_cast<const Shell &>(*this) );
107 s._hardCopy();
108 return s;
109 }
110
111 bool isCoreShared( const Shell &rOther ) const
112 {
113 return rOther.core == core;
114 }
115
116 protected:
117 Core *core;
118 void _hardCopy()
119 {
120 if( !core || !iRefCount )
121 return;
122 if( (*iRefCount) == 1 )
123 return;
124 Core *copy = _copyCore( core );
125 _deref();
126 core = copy;
127 iRefCount = new int( 1 );
128 }
129
130 /**
131 * Reset core acts like a hard copy, except instead of providing a
132 * standalone copy of the shared core, it provides a brand new core.
133 *
134 * Very useful in functions used to reset the state of an object.
135 */
136 void _resetCore()
137 {
138 if( core )
139 _deref();
140 core = _allocateCore();
141 iRefCount = new int( 1 );
142 }
143
144 virtual Core *_allocateCore()
145 {
146 return new Core();
147 }
148
149 virtual Core *_copyCore( Core *pSrc )
150 {
151 return new Core( *pSrc );
152 }
153
154 virtual void _deallocateCore( Core *pSrc )
155 {
156 delete pSrc;
157 }
158
159 private:
160 void _deref()
161 {
162 if( (--(*iRefCount)) == 0 )
163 {
164 _deallocateCore( core );
165 delete iRefCount;
166 }
167 core = NULL;
168 iRefCount = NULL;
169 }
170
171 void _incRefCount()
172 {
173 if( iRefCount && core )
174 ++(*iRefCount);
175 }
176
177 void _softCopy( const _SharedType &rSrc )
178 {
179 if( core )
180 _deref();
181 core = rSrc.core;
182 iRefCount = rSrc.iRefCount;
183 _incRefCount();
184 }
185
186 int *iRefCount;
187 };
188};
189
190#undef fin
191#undef fout
192
193#endif
diff --git a/src/stable/signals.cpp b/src/stable/signals.cpp
new file mode 100644
index 0000000..ffbc7ba
--- /dev/null
+++ b/src/stable/signals.cpp
@@ -0,0 +1,10 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/signals.h"
9
10namespace Bu { subExceptionDef( SignalException ) }
diff --git a/src/stable/singleton.h b/src/stable/singleton.h
new file mode 100644
index 0000000..13db01b
--- /dev/null
+++ b/src/stable/singleton.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SINGLETON_H
9#define BU_SINGLETON_H
10
11#include <stdio.h>
12
13namespace Bu
14{
15 /**
16 * Provides singleton functionality in a modular sort of way. Make this the
17 * base class of any other class and you immediately gain singleton
18 * functionality. Be sure to make your constructor and various functions use
19 * intellegent scoping. Cleanup and instantiation are performed automatically
20 * for you at first use and program exit. There are two things that you must
21 * do when using this template, first is to inherit from it with the name of
22 * your class filling in for T and then make this class a friend of your class.
23 *@code
24 * // Making the Single Singleton:
25 * class Single : public Singleton<Single>
26 * {
27 * friend class Singleton<Single>;
28 * protected:
29 * Single();
30 * ...
31 * };
32 @endcode
33 * You can still add public functions and variables to your new Singleton child
34 * class, but your constructor should be protected (hence the need for the
35 * friend decleration).
36 */
37 template <class T>
38 class Singleton
39 {
40 protected:
41 /**
42 * Private constructor. This constructor is empty but has a body so that
43 * you can make your own override of it. Be sure that you're override is
44 * also protected.
45 */
46 Singleton() {};
47
48 private:
49 /**
50 * Copy constructor, defined so that you could write your own as well.
51 */
52 Singleton( const Singleton& );
53
54 public:
55 /**
56 * Get a handle to the contained instance of the contained class. It is
57 * a reference.
58 *@returns A reference to the contained object.
59 */
60 static T &getInstance()
61 {
62 static T i;
63 return i;
64 }
65 };
66}
67
68#endif
diff --git a/src/stable/sio.cpp b/src/stable/sio.cpp
new file mode 100644
index 0000000..5f8e234
--- /dev/null
+++ b/src/stable/sio.cpp
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/sio.h"
9
10Bu::StdStream Bu::sioRaw;
11Bu::Formatter Bu::sio( Bu::sioRaw );
12
13Bu::size Bu::print( Bu::Stream &s, const Bu::String &str )
14{
15 return s.write( str.getStr(), str.getSize() );
16}
17
18Bu::size Bu::print( const Bu::String &str )
19{
20 return print( sioRaw, str );
21}
22
23Bu::size Bu::println( Bu::Stream &s, const Bu::String &str )
24{
25 Bu::size sRet = s.write( str.getStr(), str.getSize() );
26 sRet += s.write("\n", 1 );
27 s.flush();
28 return sRet;
29}
30
31Bu::size Bu::println( const Bu::String &str )
32{
33 return println( sioRaw, str );
34}
35
diff --git a/src/stable/sio.h b/src/stable/sio.h
new file mode 100644
index 0000000..9f2cd05
--- /dev/null
+++ b/src/stable/sio.h
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SIO_H
9#define BU_SIO_H
10
11#include "bu/stdstream.h"
12#include "bu/formatter.h"
13
14namespace Bu
15{
16 extern Bu::StdStream sioRaw;
17 extern Bu::Formatter sio;
18
19 Bu::size print( Bu::Stream &s, const Bu::String &str );
20 Bu::size print( const Bu::String &str );
21
22 Bu::size println( Bu::Stream &s, const Bu::String &str );
23 Bu::size println( const Bu::String &str );
24};
25
26#endif
diff --git a/src/stable/sptr.cpp b/src/stable/sptr.cpp
new file mode 100644
index 0000000..ea21e3b
--- /dev/null
+++ b/src/stable/sptr.cpp
@@ -0,0 +1,8 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/sptr.h"
diff --git a/src/stable/sptr.h b/src/stable/sptr.h
new file mode 100644
index 0000000..4eb5a52
--- /dev/null
+++ b/src/stable/sptr.h
@@ -0,0 +1,229 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SPTR_H
9#define BU_SPTR_H
10
11#include <stdint.h>
12#include <stdio.h>
13
14namespace Bu
15{
16 template<typename T> class SPtr;
17 template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src );
18
19 /**
20 *@ingroup Containers
21 */
22 template<typename T>
23 class SPtr
24 {
25 template<typename Tb, typename Ta>
26 friend SPtr<Tb> SPtrCast( SPtr<Ta> pt );
27 public:
28 SPtr() :
29 pRefCnt( NULL ),
30 pData( NULL )
31 {
32 }
33
34 ~SPtr()
35 {
36 decCount();
37 }
38
39 SPtr( const SPtr<T> &src ) :
40 pRefCnt( src.pRefCnt ),
41 pData( src.pData )
42 {
43 if( pRefCnt )
44 (*pRefCnt) += 1;
45 }
46
47 SPtr( T *pSrc ) :
48 pRefCnt( NULL ),
49 pData( pSrc )
50 {
51 if( pData )
52 {
53 pRefCnt = new int32_t;
54 (*pRefCnt) = 1;
55 }
56 }
57
58 /**
59 * Get the number of references to this pointer.
60 *@returns (int32_t) The number of references to this pointer.
61 */
62 int32_t getRefCount() const
63 {
64 return *pRefCnt;
65 }
66
67 void clear()
68 {
69 decCount();
70 pRefCnt = NULL;
71 pData = NULL;
72 }
73
74 /**
75 * Pointer access operator.
76 *@returns (const T *)
77 */
78 const T *operator->() const
79 {
80 return pData;
81 }
82
83 /**
84 * Dereference operator.
85 *@returns (const T &) The value at the end of the pointer.
86 */
87 const T &operator*() const
88 {
89 return *pData;
90 }
91
92 /**
93 * Pointer access operator.
94 *@returns (T *)
95 */
96 T *operator->()
97 {
98 return pData;
99 }
100
101 /**
102 * Dereference operator.
103 *@returns (T &) The value at the end of the pointer.
104 */
105 T &operator*()
106 {
107 return *pData;
108 }
109
110 /**
111 * Assignment operator.
112 *@param src (const SPtr<T> &)
113 */
114 SPtr<T> operator=( const SPtr<T> &src )
115 {
116 decCount();
117 pRefCnt = src.pRefCnt;
118 pData = src.pData;
119 if( pRefCnt )
120 (*pRefCnt) += 1;
121
122 return *this;
123 }
124
125 /**
126 * Assignment operator.
127 *@param src (const SPtr<T> &)
128 */
129 const SPtr<T> operator=( const SPtr<T> &src ) const
130 {
131 decCount();
132 pRefCnt = src.pRefCnt;
133 pData = src.pData;
134 if( pRefCnt )
135 (*pRefCnt) += 1;
136
137 return *this;
138 }
139
140 /**
141 * Equals comparison operator.
142 *@param src (const SPtr<T> &) The SPtr to compare to.
143 *@returns (bool) Are the equal?
144 */
145 bool operator==( const SPtr<T> &src ) const
146 {
147 return pData == src.pData;
148 }
149
150 /**
151 * Equals comparison operator.
152 *@param src (const T *) The pointer to compare to.
153 *@returns (bool) Are the equal?
154 */
155 bool operator==( const T *src ) const
156 {
157 return pData == src;
158 }
159
160 /**
161 * Not equals comparison operator.
162 *@param src (const SPtr<T> &) The SPtr to compare to.
163 *@returns (bool) Are the equal?
164 */
165 bool operator!=( const SPtr<T> &src ) const
166 {
167 return !(pData == src.pData);
168 }
169
170 /**
171 * Not equals comparison operator.
172 *@param src (const T *) The pointer to compare to.
173 *@returns (bool) Are the equal?
174 */
175 bool operator!=( const T *src ) const
176 {
177 return !(pData == src);
178 }
179
180 /**
181 * Boolean cast operator. Do we have a pointer?
182 */
183 operator bool() const
184 {
185 return pRefCnt != NULL;
186 }
187
188 /**
189 * Do we have a pointer?
190 *@returns (bool) Do we have a pointer?
191 */
192 bool isSet() const
193 {
194 return pRefCnt != NULL;
195 }
196
197 private:
198 void decCount() const
199 {
200 if( pRefCnt )
201 {
202 (*pRefCnt) -= 1;
203 //printf("Decrementing ref-count to %d\n", *pRefCnt );
204 if( (*pRefCnt) == 0 )
205 {
206 delete pRefCnt;
207 delete pData;
208 pRefCnt = NULL;
209 pData = NULL;
210 }
211 }
212 }
213
214 mutable int32_t *pRefCnt;
215 mutable T *pData;
216 };
217
218 template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src )
219 {
220 SPtr<Tb> ret;
221 ret.pRefCnt = src.pRefCnt;
222 ret.pData = dynamic_cast<Tb *>(src.pData);
223 if( ret.pRefCnt )
224 (*(ret.pRefCnt)) += 1;
225 return ret;
226 }
227}
228
229#endif
diff --git a/src/stable/stack.cpp b/src/stable/stack.cpp
new file mode 100644
index 0000000..73352d3
--- /dev/null
+++ b/src/stable/stack.cpp
@@ -0,0 +1,8 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/stack.h"
diff --git a/src/stable/stack.h b/src/stable/stack.h
new file mode 100644
index 0000000..0d1ed3c
--- /dev/null
+++ b/src/stable/stack.h
@@ -0,0 +1,85 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_STACK_H
9#define BU_STACK_H
10
11#include <memory>
12#include "bu/config.h"
13
14namespace Bu
15{
16 template<typename value, typename valuealloc=std::allocator<value> >
17 class Stack
18 {
19 private:
20 typedef struct Chunk
21 {
22 value *pValue;
23 Chunk *pPrev;
24 } Chunk;
25 public:
26 Stack() :
27 pTop( NULL )
28 {
29 }
30
31 virtual ~Stack()
32 {
33 }
34
35 void push( const value &v )
36 {
37 Chunk *pChnk = new Chunk;
38 pChnk->pValue = va.allocate( 1 );
39 va.construct( pChnk->pValue, v );
40 pChnk->pPrev = pTop;
41 pTop = pChnk;
42 }
43
44 value &peek()
45 {
46 return *pTop->pValue;
47 }
48
49 value &top()
50 {
51 return *pTop->pValue;
52 }
53
54 value pop()
55 {
56 value ret( *pTop->pValue );
57
58 Chunk *pChnk = pTop;
59 pTop = pTop->pPrev;
60
61 va.destroy( pChnk->pValue );
62 va.deallocate( pChnk->pValue, 1 );
63 delete pChnk;
64
65 return ret;
66 }
67
68 void clear()
69 {
70 while( !isEmpty() )
71 pop();
72 }
73
74 bool isEmpty()
75 {
76 return pTop == NULL;
77 }
78
79 private:
80 Chunk *pTop;
81 valuealloc va;
82 };
83}
84
85#endif
diff --git a/src/stable/staticmembuf.cpp b/src/stable/staticmembuf.cpp
new file mode 100644
index 0000000..74fae31
--- /dev/null
+++ b/src/stable/staticmembuf.cpp
@@ -0,0 +1,135 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/staticmembuf.h"
9
10using namespace Bu;
11
12Bu::StaticMemBuf::StaticMemBuf( const void *pData, size iSize ) :
13 pData( pData ),
14 iSize( iSize ),
15 nPos( 0 )
16{
17}
18
19Bu::StaticMemBuf::~StaticMemBuf()
20{
21}
22
23void Bu::StaticMemBuf::close()
24{
25}
26
27size Bu::StaticMemBuf::read( void *pBuf, size nBytes )
28{
29 if( iSize-nPos < nBytes )
30 nBytes = iSize-nPos;
31
32 memcpy( pBuf, ((char *)pData)+nPos, nBytes );
33 nPos += nBytes;
34
35 return nBytes;
36}
37
38size Bu::StaticMemBuf::write( const void *, size )
39{
40 return -1;
41}
42
43size Bu::StaticMemBuf::tell()
44{
45 return nPos;
46}
47
48void Bu::StaticMemBuf::seek( size offset )
49{
50 nPos += offset;
51 if( nPos < 0 ) nPos = 0;
52 else if( nPos > iSize ) nPos = iSize;
53}
54
55void Bu::StaticMemBuf::setPos( size pos )
56{
57 nPos = pos;
58 if( nPos < 0 ) nPos = 0;
59 else if( nPos > iSize ) nPos = iSize;
60}
61
62void Bu::StaticMemBuf::setPosEnd( size pos )
63{
64 nPos = iSize-pos;
65 if( nPos < 0 ) nPos = 0;
66 else if( nPos > iSize ) nPos = iSize;
67}
68
69bool Bu::StaticMemBuf::isEos()
70{
71 return (nPos == iSize);
72}
73
74bool Bu::StaticMemBuf::isOpen()
75{
76 return true;
77}
78
79void Bu::StaticMemBuf::flush()
80{
81}
82
83bool Bu::StaticMemBuf::canRead()
84{
85 return !isEos();
86}
87
88bool Bu::StaticMemBuf::canWrite()
89{
90 return false;
91}
92
93bool Bu::StaticMemBuf::isReadable()
94{
95 return true;
96}
97
98bool Bu::StaticMemBuf::isWritable()
99{
100 return false;
101}
102
103bool Bu::StaticMemBuf::isSeekable()
104{
105 return true;
106}
107
108bool Bu::StaticMemBuf::isBlocking()
109{
110 return true;
111}
112
113void Bu::StaticMemBuf::setBlocking( bool )
114{
115}
116
117void Bu::StaticMemBuf::setSize( size )
118{
119}
120
121Bu::size Bu::StaticMemBuf::getSize() const
122{
123 return iSize;
124}
125
126Bu::size Bu::StaticMemBuf::getBlockSize() const
127{
128 return iSize;
129}
130
131Bu::String Bu::StaticMemBuf::getLocation() const
132{
133 return "";
134}
135
diff --git a/src/stable/staticmembuf.h b/src/stable/staticmembuf.h
new file mode 100644
index 0000000..f168de3
--- /dev/null
+++ b/src/stable/staticmembuf.h
@@ -0,0 +1,65 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_STATIC_MEM_BUF_H
9#define BU_STATIC_MEM_BUF_H
10
11#include <stdint.h>
12
13#include "bu/config.h"
14#include "bu/stream.h"
15
16namespace Bu
17{
18 /**
19 * An immutable, read-only memory buffer. Construct this buffer around a
20 * block of raw memory, provide the length of the block, and you can read
21 * from that block via this class as though it were a normal stream.
22 *
23 * Use this class instead of MemBuf when you have a string already, and
24 * don't need to change it. MemBuf will make a copy of your string for
25 * it's own use (often) and this will not (ever).
26 *@ingroup Streams
27 */
28 class StaticMemBuf : public Stream
29 {
30 public:
31 StaticMemBuf( const void *pData, size iSize );
32 virtual ~StaticMemBuf();
33
34 virtual void close();
35 virtual size read( void *pBuf, size iBytes );
36
37 virtual size write( const void *pBuf, size iBytes );
38 using Stream::write;
39 virtual size tell();
40 virtual void seek( size offset );
41 virtual void setPos( size pos );
42 virtual void setPosEnd( size pos );
43 virtual bool isEos();
44 virtual bool isOpen();
45 virtual void flush();
46 virtual bool canRead();
47 virtual bool canWrite();
48 virtual bool isReadable();
49 virtual bool isWritable();
50 virtual bool isSeekable();
51 virtual bool isBlocking();
52 virtual void setBlocking( bool bBlocking=true );
53 virtual void setSize( size iSize );
54 virtual size getSize() const;
55 virtual size getBlockSize() const;
56 virtual Bu::String getLocation() const;
57
58 private:
59 const void *pData;
60 size iSize;
61 size nPos;
62 };
63}
64
65#endif
diff --git a/src/stable/stdstream.cpp b/src/stable/stdstream.cpp
new file mode 100644
index 0000000..b1d5d61
--- /dev/null
+++ b/src/stable/stdstream.cpp
@@ -0,0 +1,117 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include <stdio.h>
9#include "bu/stdstream.h"
10
11Bu::StdStream::StdStream()
12{
13}
14
15Bu::StdStream::~StdStream()
16{
17}
18
19void Bu::StdStream::close()
20{
21}
22
23Bu::size Bu::StdStream::read( void *pBuf, Bu::size nBytes )
24{
25 return fread( pBuf, 1, nBytes, stdin );
26}
27
28Bu::size Bu::StdStream::write( const void *pBuf, Bu::size nBytes )
29{
30 return fwrite( pBuf, 1, nBytes, stdout );
31}
32
33Bu::size Bu::StdStream::tell()
34{
35 return 0;
36}
37
38void Bu::StdStream::seek( Bu::size )
39{
40}
41
42void Bu::StdStream::setPos( Bu::size )
43{
44}
45
46void Bu::StdStream::setPosEnd( Bu::size )
47{
48}
49
50bool Bu::StdStream::isEos()
51{
52 return false;
53}
54
55bool Bu::StdStream::isOpen()
56{
57 return true;
58}
59
60void Bu::StdStream::flush()
61{
62 fflush( stdout );
63}
64
65bool Bu::StdStream::canRead()
66{
67 return true;
68}
69
70bool Bu::StdStream::canWrite()
71{
72 return true;
73}
74
75bool Bu::StdStream::isReadable()
76{
77 return true;
78}
79
80bool Bu::StdStream::isWritable()
81{
82 return true;
83}
84
85bool Bu::StdStream::isSeekable()
86{
87 return false;
88}
89
90bool Bu::StdStream::isBlocking()
91{
92 return true;
93}
94
95void Bu::StdStream::setBlocking( bool )
96{
97}
98
99void Bu::StdStream::setSize( Bu::size )
100{
101}
102
103Bu::size Bu::StdStream::getSize() const
104{
105 return 0;
106}
107
108Bu::size Bu::StdStream::getBlockSize() const
109{
110 return 0;
111}
112
113Bu::String Bu::StdStream::getLocation() const
114{
115 return "";
116}
117
diff --git a/src/stable/stdstream.h b/src/stable/stdstream.h
new file mode 100644
index 0000000..ff6c774
--- /dev/null
+++ b/src/stable/stdstream.h
@@ -0,0 +1,50 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_STD_STREAM_H
9#define BU_STD_STREAM_H
10
11#include <stdint.h>
12#include "stream.h"
13
14namespace Bu
15{
16 /**
17 *@ingroup Streams
18 */
19 class StdStream : public Stream
20 {
21 public:
22 StdStream();
23 virtual ~StdStream();
24
25 virtual void close();
26 virtual size read( void *pBuf, size nBytes );
27 virtual size write( const void *pBuf, size nBytes );
28 using Stream::write;
29 virtual size tell();
30 virtual void seek( size offset );
31 virtual void setPos( size pos );
32 virtual void setPosEnd( size pos );
33 virtual bool isEos();
34 virtual bool isOpen();
35 virtual void flush();
36 virtual bool canRead();
37 virtual bool canWrite();
38 virtual bool isReadable();
39 virtual bool isWritable();
40 virtual bool isSeekable();
41 virtual bool isBlocking();
42 virtual void setBlocking( bool bBlocking=true );
43 virtual void setSize( size iSize );
44 virtual size getSize() const;
45 virtual size getBlockSize() const;
46 virtual Bu::String getLocation() const;
47 };
48}
49
50#endif
diff --git a/src/stable/stream.cpp b/src/stable/stream.cpp
new file mode 100644
index 0000000..58641cc
--- /dev/null
+++ b/src/stable/stream.cpp
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/stream.h"
9
10Bu::Stream::Stream()
11{
12}
13
14Bu::Stream::~Stream()
15{
16}
17
18Bu::String Bu::Stream::readLine()
19{
20 Bu::String sRet;
21
22 for(;;)
23 {
24 char s;
25 if( read( &s, 1 ) == 0 )
26 return sRet;
27 if( s == '\n' || s == '\r' )
28 return sRet;
29 sRet.append( s );
30 }
31}
32
33Bu::String Bu::Stream::readAll()
34{
35 Bu::String sRet;
36 char buf[4096];
37
38 while( !isEos() )
39 {
40 int iRead = read( buf, 4096 );
41 if( iRead == 0 )
42 return sRet;
43 sRet.append( buf, iRead );
44 }
45
46 return sRet;
47}
48
49Bu::size Bu::Stream::write( const Bu::String &sBuf )
50{
51 return write( sBuf.getStr(), sBuf.getSize() );
52}
53
diff --git a/src/stable/stream.h b/src/stable/stream.h
new file mode 100644
index 0000000..b35f6ee
--- /dev/null
+++ b/src/stable/stream.h
@@ -0,0 +1,205 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_STREAM_H
9#define BU_STREAM_H
10
11#include "bu/config.h"
12
13#include <stdint.h>
14#include <stdio.h>
15
16#include "bu/string.h"
17
18namespace Bu
19{
20 /**
21 * The basis for a completely general data transport mechanism. Anything
22 * that inherits from this should provide at least the basic read and/or
23 * write functions, and very probably the close function. Any functions
24 * that aren't supported should throw an exception if called.
25 *
26 * The constructor of a child class should pretty much universally be used
27 * to open the stream. I can't think of anything that should require an
28 * exception.
29 *@ingroup Streams
30 */
31 class Stream
32 {
33 public:
34 Stream();
35 virtual ~Stream();
36
37 /**
38 * Close the stream.
39 */
40 virtual void close() = 0;
41
42 /**
43 * Read data from the stream into a buffer.
44 *@param pBuf (void *) Buffer which will be filled.
45 *@param nBytes (size_t) Max data to read.
46 *@returns (size_t) Amount of data read.
47 */
48 virtual size read( void *pBuf, size iBytes ) = 0;
49
50 /**
51 * Attempts to read a complete line from the stream. This will stop
52 * reading when it has reached the end of the stream, or runs out of
53 * data in a non-blocking stream.
54 *@returns The line read, not including newline character.
55 */
56 virtual Bu::String readLine();
57
58 /**
59 * Reads all data from the current position onward until isEos returns
60 * true and returns it as a Bu::String. This will also return if no
61 * data is available and the stream is in non-blocking mode. This
62 * function is intended for very particular circumstances and is often
63 * not the most efficient way to access the data that you would like.
64 *@returns The entire stream contents.
65 */
66 virtual Bu::String readAll();
67
68 /**
69 * Write data to the stream.
70 *@param pBuf (const void *) The data to be written.
71 *@param nBytes (size_t) Amount of data to write from pBuf.
72 *@returns (size_t) Amount of data actually written.
73 */
74 virtual size write( const void *pBuf, size iBytes ) = 0;
75
76 virtual size write( const Bu::String &sBuf );
77
78 /**
79 * Get the current position in the stream.
80 *@returns (long) The current position in the stream.
81 */
82 virtual size tell() = 0;
83
84 /**
85 * Seek to a position in the stream relative to the current position.
86 *@param offset (long) Offset from current position to seek to.
87 */
88 virtual void seek( size offset ) = 0;
89
90 /**
91 * Set position in the stream relative to the start of the stream.
92 *@param pos (long) The position.
93 */
94 virtual void setPos( size pos ) = 0;
95
96 /**
97 * Set position in the stream relative to the end of the stream.
98 *@param pos (long) The position.
99 */
100 virtual void setPosEnd( size pos ) = 0;
101
102 /**
103 * Are we at the end of the stream?
104 *@returns (bool) Are we at the end of the stream?
105 */
106 virtual bool isEos() = 0;
107
108 /**
109 * Is the stream open?
110 *@returns (bool) Is the stream open?
111 */
112 virtual bool isOpen() = 0;
113
114 /**
115 * Flush any data still held in buffers.
116 */
117 virtual void flush() = 0;
118
119 /**
120 * In non-blocking streams this indicates if a read operation will
121 * return data at the moment or not. In blocking streams this should
122 * return the same value as isEos().
123 */
124 virtual bool canRead() = 0;
125
126 /**
127 * In non-blocking streams this indicates if a write operation will
128 * actually write one or more bytes. In some cases writing is not
129 * allowed (e.g. internal buffers are full) temporarilly. In blocking
130 * streams this should return the same value as isWritable.
131 */
132 virtual bool canWrite() = 0;
133
134 /**
135 * Indicates if the stream is capable of read operations. This does not
136 * indicate if such operations will return useful data, see canRead for
137 * that.
138 */
139 virtual bool isReadable() = 0;
140
141 /**
142 * Indicates if the stream is capable of write operations. This does
143 * not indicate if such operations will succeed or fail, see canWrite
144 * for that.
145 */
146 virtual bool isWritable() = 0;
147
148 /**
149 * Indicates if the stream is capable of seek operations. This is
150 * generally false for non-blocking streams. Some buffered streams may
151 * support limited in-buffer seeking.
152 */
153 virtual bool isSeekable() = 0;
154
155 /**
156 * Are we currently set to block mode?
157 *@returns (bool)
158 */
159 virtual bool isBlocking() = 0;
160
161 /**
162 * Set stream to blocking or non-blocking mode.
163 *@param bBlocking (bool) Whether we should block or not.
164 */
165 virtual void setBlocking( bool bBlocking=true ) = 0;
166
167 /**
168 * Set the size of the stream, this does not apply to many types of
169 * streams. For those that it does apply to, data will be added or
170 * removed from the end of the stream, but the content of the added
171 * data is undefined.
172 */
173 virtual void setSize( size iSize ) = 0;
174
175 /**
176 * Returns the size of the stream if the stream can have a size. For
177 * streams that do not (sockets, pipes, etc.) this should throw an
178 * unsupported exception.
179 */
180 virtual size getSize() const = 0;
181
182 /**
183 * Returns the block-size of the stream, if it has one. This should
184 * throw an unsupported exception. In some cases the block size
185 * returned will not represent quite the same thing, for example,
186 * sockets will return their MTU, while files will return the
187 * filesystem's block size, and memory buffers will throw an exception.
188 */
189 virtual size getBlockSize() const = 0;
190
191 /**
192 * If possible, this returns a string that can be used to describe how
193 * to access the open stream. Not all streams support this, such as
194 * MemBuf, but for files it may give you a path to a file, for a socket
195 * it may give you an ip address, etc. If it isn't supported, an empty
196 * string may be returned.
197 */
198 virtual Bu::String getLocation() const = 0;
199
200 private:
201
202 };
203}
204
205#endif
diff --git a/src/stable/streamstack.cpp b/src/stable/streamstack.cpp
new file mode 100644
index 0000000..d45306d
--- /dev/null
+++ b/src/stable/streamstack.cpp
@@ -0,0 +1,234 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/streamstack.h"
9
10Bu::StreamStack::StreamStack()
11{
12}
13
14Bu::StreamStack::StreamStack( Bu::Stream *pStream )
15{
16 lFilts.prepend( pStream );
17}
18
19Bu::StreamStack::~StreamStack()
20{
21 clear();
22}
23
24bool Bu::StreamStack::isEmpty()
25{
26 return lFilts.isEmpty();
27}
28
29bool Bu::StreamStack::hasStream()
30{
31 return !lFilts.isEmpty();
32}
33
34void Bu::StreamStack::setStream( Bu::Stream *pStream )
35{
36 if( !lFilts.isEmpty() )
37 throw Bu::ExceptionBase("There is already a stream set.");
38
39 lFilts.prepend( pStream );
40}
41
42void Bu::StreamStack::clear()
43{
44 for( FilterList::iterator i = lFilts.begin(); i; i++ )
45 {
46 delete *i;
47 }
48
49 lFilts.clear();
50}
51
52void Bu::StreamStack::popFilter()
53{
54 if( lFilts.isEmpty() )
55 return;
56
57 delete lFilts.first();
58 lFilts.erase( lFilts.begin() );
59}
60
61Bu::Stream *Bu::StreamStack::getTop()
62{
63 checkStack();
64
65 return lFilts.first();
66}
67
68Bu::Stream *Bu::StreamStack::getStream()
69{
70 checkStack();
71
72 return lFilts.last();
73}
74
75void Bu::StreamStack::close()
76{
77 checkStack();
78
79 lFilts.first()->close();
80}
81
82Bu::size Bu::StreamStack::read( void *pBuf, Bu::size nBytes )
83{
84 checkStack();
85
86 return lFilts.first()->read( pBuf, nBytes );
87}
88
89Bu::size Bu::StreamStack::write( const void *pBuf, Bu::size nBytes )
90{
91 checkStack();
92
93 return lFilts.first()->write( pBuf, nBytes );
94}
95
96Bu::size Bu::StreamStack::write( const Bu::String &sBuf )
97{
98 checkStack();
99
100 return lFilts.first()->write( sBuf );
101}
102
103Bu::size Bu::StreamStack::tell()
104{
105 checkStack();
106
107 return lFilts.first()->tell();
108}
109
110void Bu::StreamStack::seek( Bu::size offset )
111{
112 checkStack();
113
114 lFilts.first()->seek( offset );
115}
116
117void Bu::StreamStack::setPos( Bu::size pos )
118{
119 checkStack();
120
121 lFilts.first()->setPos( pos );
122}
123
124void Bu::StreamStack::setPosEnd( Bu::size pos )
125{
126 checkStack();
127
128 lFilts.first()->setPosEnd( pos );
129}
130
131bool Bu::StreamStack::isEos()
132{
133 checkStack();
134
135 return lFilts.first()->isEos();
136}
137
138bool Bu::StreamStack::isOpen()
139{
140 checkStack();
141
142 return lFilts.first()->isOpen();
143}
144
145void Bu::StreamStack::flush()
146{
147 checkStack();
148
149 lFilts.first()->flush();
150}
151
152bool Bu::StreamStack::canRead()
153{
154 checkStack();
155
156 return lFilts.first()->canRead();
157}
158
159bool Bu::StreamStack::canWrite()
160{
161 checkStack();
162
163 return lFilts.first()->canWrite();
164}
165
166bool Bu::StreamStack::isReadable()
167{
168 checkStack();
169
170 return lFilts.first()->isReadable();
171}
172
173bool Bu::StreamStack::isWritable()
174{
175 checkStack();
176
177 return lFilts.first()->isWritable();
178}
179
180bool Bu::StreamStack::isSeekable()
181{
182 checkStack();
183
184 return lFilts.first()->isSeekable();
185}
186
187bool Bu::StreamStack::isBlocking()
188{
189 checkStack();
190
191 return lFilts.first()->isBlocking();
192}
193
194void Bu::StreamStack::setBlocking( bool bBlocking )
195{
196 checkStack();
197
198 lFilts.first()->setBlocking( bBlocking );
199}
200
201void Bu::StreamStack::setSize( Bu::size iSize )
202{
203 checkStack();
204
205 lFilts.first()->setSize( iSize );
206}
207
208Bu::size Bu::StreamStack::getSize() const
209{
210 checkStack();
211
212 return lFilts.first()->getSize();
213}
214
215Bu::size Bu::StreamStack::getBlockSize() const
216{
217 checkStack();
218
219 return lFilts.first()->getBlockSize();
220}
221
222Bu::String Bu::StreamStack::getLocation() const
223{
224 checkStack();
225
226 return lFilts.first()->getLocation();
227}
228
229inline void Bu::StreamStack::checkStack() const
230{
231 if( lFilts.isEmpty() )
232 throw Bu::ExceptionBase("StreamStack is empty.");
233}
234
diff --git a/src/stable/streamstack.h b/src/stable/streamstack.h
new file mode 100644
index 0000000..846935b
--- /dev/null
+++ b/src/stable/streamstack.h
@@ -0,0 +1,144 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_STREAM_STACK_H
9#define BU_STREAM_STACK_H
10
11#include "bu/stream.h"
12
13#include <typeinfo>
14
15namespace Bu
16{
17 class StreamStack : public Bu::Stream
18 {
19 private:
20 typedef Bu::List<Bu::Stream *> FilterList;
21
22 public:
23 StreamStack();
24 StreamStack( Bu::Stream *pStream );
25 virtual ~StreamStack();
26
27 bool isEmpty();
28 bool hasStream();
29 void setStream( Bu::Stream *pStream );
30
31 void clear();
32 void popFilter();
33 Bu::Stream *getTop();
34
35 Bu::Stream *getStream();
36
37 template<typename filter>
38 Bu::Stream *findFilter()
39 {
40 for( FilterList::iterator i = lFilts.begin(); i; i++ )
41 {
42 if( typeid(**i) == typeid( filter ) )
43 {
44 return *i;
45 }
46 }
47
48 throw Bu::ExceptionBase("Filter not found.");
49 }
50
51 template<typename filter>
52 void pushFilter()
53 {
54 checkStack();
55
56 filter *pFlt = new filter( *lFilts.first() );
57 lFilts.prepend( pFlt );
58 }
59
60 template<typename filter, typename p1t>
61 void pushFilter( p1t p1 )
62 {
63 checkStack();
64
65 filter *pFlt = new filter( *lFilts.first(), p1 );
66 lFilts.prepend( pFlt );
67 }
68
69 template<typename filter, typename p1t, typename p2t>
70 void pushFilter( p1t p1, p2t p2 )
71 {
72 checkStack();
73
74 filter *pFlt = new filter( *lFilts.first(), p1, p2 );
75 lFilts.prepend( pFlt );
76 }
77
78 template<typename filter, typename p1t, typename p2t, typename p3t>
79 void pushFilter( p1t p1, p2t p2, p3t p3 )
80 {
81 checkStack();
82
83 filter *pFlt = new filter( *lFilts.first(), p1, p2, p3 );
84 lFilts.prepend( pFlt );
85 }
86
87 template<typename filter, typename p1t, typename p2t, typename p3t,
88 typename p4t>
89 void pushFilter( p1t p1, p2t p2, p3t p3, p4t p4 )
90 {
91 checkStack();
92
93 filter *pFlt = new filter( *lFilts.first(), p1, p2, p3, p4 );
94 lFilts.prepend( pFlt );
95 }
96
97 template<typename filter, typename p1t, typename p2t, typename p3t,
98 typename p4t, typename p5t>
99 void pushFilter( p1t p1, p2t p2, p3t p3, p4t p4, p5t p5 )
100 {
101 checkStack();
102
103 filter *pFlt = new filter( *lFilts.first(), p1, p2, p3, p4, p5 );
104 lFilts.prepend( pFlt );
105 }
106
107 //
108 // Everything below here merely passes on the call to the top of the
109 // stream stack.
110 //
111
112 virtual void close();
113 virtual Bu::size read( void *pBuf, Bu::size nBytes );
114 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
115
116 virtual Bu::size write( const Bu::String &sBuf );
117 virtual Bu::size tell();
118 virtual void seek( Bu::size offset );
119 virtual void setPos( Bu::size pos );
120 virtual void setPosEnd( Bu::size pos );
121 virtual bool isEos();
122 virtual bool isOpen();
123 virtual void flush();
124 virtual bool canRead();
125 virtual bool canWrite();
126 virtual bool isReadable();
127 virtual bool isWritable();
128 virtual bool isSeekable();
129 virtual bool isBlocking();
130 virtual void setBlocking( bool bBlocking=true );
131 virtual void setSize( Bu::size iSize );
132 virtual size getSize() const;
133 virtual size getBlockSize() const;
134 virtual Bu::String getLocation() const;
135
136 private:
137 void checkStack() const;
138
139 private:
140 FilterList lFilts;
141 };
142};
143
144#endif
diff --git a/src/stable/strfilter.h b/src/stable/strfilter.h
new file mode 100644
index 0000000..8da0a3f
--- /dev/null
+++ b/src/stable/strfilter.h
@@ -0,0 +1,124 @@
1#ifndef STR_FILTER_H
2#define STR_FILTER_H
3
4#include "bu/string.h"
5#include "bu/membuf.h"
6
7namespace Bu
8{
9 //
10 // Encoders
11 //
12 template<typename tFilter>
13 Bu::String encodeStr( const Bu::String &sIn )
14 {
15 Bu::MemBuf mb;
16 {
17 tFilter fEnc( mb );
18 fEnc.write( sIn.getStr(), sIn.getSize() );
19 }
20 return mb.getString();
21 }
22
23 template<typename tFilter, typename p1t>
24 Bu::String encodeStr( const Bu::String &sIn, p1t p1 )
25 {
26 Bu::MemBuf mb;
27 {
28 tFilter fEnc( mb, p1 );
29 fEnc.write( sIn.getStr(), sIn.getSize() );
30 }
31 return mb.getString();
32 }
33
34 template<typename tFilter, typename p1t, typename p2t>
35 Bu::String encodeStr( const Bu::String &sIn, p1t p1, p2t p2 )
36 {
37 Bu::MemBuf mb;
38 {
39 tFilter fEnc( mb, p1, p2 );
40 fEnc.write( sIn.getStr(), sIn.getSize() );
41 }
42 return mb.getString();
43 }
44
45 template<typename tFilter, typename p1t, typename p2t, typename p3t>
46 Bu::String encodeStr( const Bu::String &sIn, p1t p1, p2t p2, p3t p3 )
47 {
48 Bu::MemBuf mb;
49 {
50 tFilter fEnc( mb, p1, p2 );
51 fEnc.write( sIn.getStr(), sIn.getSize() );
52 }
53 return mb.getString();
54 }
55
56 //
57 // Decoders
58 //
59 template<typename tFilter>
60 Bu::String decodeStr( const Bu::String &sIn )
61 {
62 Bu::MemBuf mb( sIn );
63 tFilter fDec( mb );
64 char buf[1024];
65 String sRet;
66 for(;;)
67 {
68 int iRead = fDec.read( buf, 1024 );
69 if( iRead == 0 )
70 return sRet;
71 sRet.append( buf, iRead );
72 }
73 }
74
75 template<typename tFilter, typename p1t>
76 Bu::String decodeStr( const Bu::String &sIn, p1t p1 )
77 {
78 Bu::MemBuf mb( sIn );
79 tFilter fDec( mb, p1 );
80 char buf[1024];
81 String sRet;
82 for(;;)
83 {
84 int iRead = fDec.read( buf, 1024 );
85 if( iRead == 0 )
86 return sRet;
87 sRet.append( buf, iRead );
88 }
89 }
90
91 template<typename tFilter, typename p1t, typename p2t>
92 Bu::String decodeStr( const Bu::String &sIn, p1t p1, p2t p2 )
93 {
94 Bu::MemBuf mb( sIn );
95 tFilter fDec( mb, p1, p2 );
96 char buf[1024];
97 String sRet;
98 for(;;)
99 {
100 int iRead = fDec.read( buf, 1024 );
101 if( iRead == 0 )
102 return sRet;
103 sRet.append( buf, iRead );
104 }
105 }
106
107 template<typename tFilter, typename p1t, typename p2t, typename p3t>
108 Bu::String decodeStr( const Bu::String &sIn, p1t p1, p2t p2, p3t p3 )
109 {
110 Bu::MemBuf mb( sIn );
111 tFilter fDec( mb, p1, p2, p3 );
112 char buf[1024];
113 String sRet;
114 for(;;)
115 {
116 int iRead = fDec.read( buf, 1024 );
117 if( iRead == 0 )
118 return sRet;
119 sRet.append( buf, iRead );
120 }
121 }
122};
123
124#endif
diff --git a/src/stable/string.cpp b/src/stable/string.cpp
new file mode 100644
index 0000000..1a9018b
--- /dev/null
+++ b/src/stable/string.cpp
@@ -0,0 +1,1470 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#define BU_TRACE
9#include "bu/trace.h"
10
11#include "bu/string.h"
12#include "bu/hash.h"
13#include "bu/membuf.h"
14#include "bu/formatter.h"
15#include <stdlib.h>
16
17#define nMinSize (256)
18
19Bu::StringCore::StringCore() :
20 nLength( 0 ),
21 pFirst( NULL ),
22 pLast( NULL )
23{
24}
25
26Bu::StringCore::StringCore( const StringCore &rSrc ) :
27 nLength( rSrc.nLength ),
28 pFirst( NULL ),
29 pLast( NULL )
30{
31 if( rSrc.pFirst == NULL || rSrc.nLength == 0 )
32 {
33 pFirst = pLast = NULL;
34 }
35 else
36 {
37 pFirst = pLast = newChunk( nLength );
38 Chunk *pLink = rSrc.pFirst;
39 int iPos = 0;
40 while( pLink != NULL )
41 {
42 memcpy( pFirst->pData+iPos, pLink->pData, pLink->nLength );
43 iPos += pLink->nLength;
44 pLink = pLink->pNext;
45 }
46 }
47}
48
49Bu::StringCore::~StringCore()
50{
51 clear();
52}
53
54void Bu::StringCore::clear() const
55{
56 if( pFirst == NULL )
57 return;
58
59 Chunk *i = pFirst;
60 for(;;)
61 {
62 Chunk *n = i->pNext;
63 delete[] i->pData;
64 delete i;
65 if( n == NULL )
66 break;
67 i = n;
68 }
69 pFirst = pLast = NULL;
70 nLength = 0;
71}
72
73Bu::StringCore::Chunk *Bu::StringCore::newChunk() const
74{
75 Chunk *pNew = new Chunk;
76 pNew->pNext = NULL;
77 return pNew;
78}
79
80Bu::StringCore::Chunk *Bu::StringCore::newChunk( long nLen ) const
81{
82 Chunk *pNew = new Chunk;
83 pNew->pNext = NULL;
84 pNew->nLength = nLen;
85 pNew->pData = new char[(nLen<nMinSize)?(nMinSize):(nLen)+1];
86 pNew->pData[nLen] = (char)0;
87 return pNew;
88}
89
90Bu::StringCore::Chunk *Bu::StringCore::copyChunk(
91 Bu::StringCore::Chunk *pSrc ) const
92{
93 Chunk *pNew = new Chunk;
94 pNew->pNext = pSrc->pNext;
95 pNew->nLength = pSrc->nLength;
96 pNew->pData = new char[
97 (pNew->nLength<nMinSize)?(nMinSize):(pNew->nLength)+1
98 ];
99 memcpy( pNew->pData, pSrc->pData, pSrc->nLength );
100 pNew->pData[pNew->nLength] = (char)0;
101 return pNew;
102}
103
104void Bu::StringCore::appendChunk( Bu::StringCore::Chunk *pNewChunk )
105{
106 if( pFirst == NULL )
107 pLast = pFirst = pNewChunk;
108 else
109 {
110 pLast->pNext = pNewChunk;
111 pLast = pNewChunk;
112 }
113
114 nLength += pNewChunk->nLength;
115}
116
117void Bu::StringCore::prependChunk( Bu::StringCore::Chunk *pNewChunk )
118{
119 if( pFirst == NULL )
120 pLast = pFirst = pNewChunk;
121 else
122 {
123 pNewChunk->pNext = pFirst;
124 pFirst = pNewChunk;
125 }
126
127 nLength += pNewChunk->nLength;
128}
129
130Bu::String::String()
131{
132}
133
134Bu::String::String( const char *pData )
135{
136 append( pData );
137}
138
139Bu::String::String( const char *pData, long nLength )
140{
141 append( pData, nLength );
142}
143
144Bu::String::String( const Bu::String &rSrc ) :
145 Bu::SharedCore<Bu::String, Bu::StringCore>( rSrc )
146{
147}
148
149Bu::String::String( const Bu::String &rSrc, long nLength )
150{
151 append( rSrc, nLength );
152}
153
154Bu::String::String( const Bu::String &rSrc, long nStart, long nLength )
155{
156 append( rSrc, nStart, nLength );
157}
158
159Bu::String::String( long nSize )
160{
161 core->pFirst = core->pLast = core->newChunk( nSize );
162 core->nLength = nSize;
163}
164
165Bu::String::String( const Bu::String::const_iterator &s )
166{
167 append( s );
168}
169
170Bu::String::String( const Bu::String::const_iterator &s,
171 const Bu::String::const_iterator &e )
172{
173 append( s, e );
174}
175
176Bu::String::~String()
177{
178}
179
180void Bu::String::append( const char *pData )
181{
182 if( !pData ) return;
183 long nLen;
184 for( nLen = 0; pData[nLen] != (char)0; nLen++ ) { }
185
186 append( pData, 0, nLen );
187}
188
189void Bu::String::append( const char *pData, long nLen )
190{
191 append( pData, 0, nLen );
192}
193
194void Bu::String::append( const char *pData, long nStart, long nLen )
195{
196 if( !pData ) return;
197 if( nLen <= 0 )
198 return;
199
200 pData += nStart;
201
202 _hardCopy();
203
204 if( core->pLast && core->pLast->nLength < nMinSize )
205 {
206 int nAmnt = nMinSize - core->pLast->nLength;
207 if( nAmnt > nLen )
208 nAmnt = nLen;
209 memcpy(
210 core->pLast->pData+core->pLast->nLength,
211 pData,
212 nAmnt
213 );
214 pData += nAmnt;
215 core->pLast->nLength += nAmnt;
216 nLen -= nAmnt;
217 core->nLength += nAmnt;
218 }
219
220 if( nLen > 0 )
221 {
222 Chunk *pNew = core->newChunk( nLen );
223 memcpy( pNew->pData, pData, nLen );
224 core->appendChunk( pNew );
225// core->nLength += nLen;
226 }
227}
228
229void Bu::String::append( const char &cData )
230{
231 if( core->pLast && core->pLast->nLength < nMinSize )
232 {
233 _hardCopy();
234 core->pLast->pData[core->pLast->nLength] = cData;
235 ++core->pLast->nLength; ++core->nLength;
236// pLast->pData[pLast->nLength] = (char)0;
237 }
238 else
239 {
240 append( &cData, 1 );
241 }
242}
243
244void Bu::String::append( const String & sData )
245{
246 append( sData.getStr(), 0, sData.getSize() );
247}
248
249void Bu::String::append( const String & sData, long nLen )
250{
251 append( sData.getStr(), 0, nLen );
252}
253
254void Bu::String::append( const String & sData, long nStart, long nLen )
255{
256 if( nLen < 0 )
257 nLen = sData.getSize() - nStart;
258 append( sData.getStr(), nStart, nLen );
259}
260
261void Bu::String::append( const const_iterator &s )
262{
263 if( !s.isValid() )
264 return;
265 Chunk *pSrc = s.pChunk;
266
267 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
268 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
269
270 _hardCopy();
271 core->appendChunk( pNew );
272
273 while( (pSrc = pSrc->pNext) )
274 {
275 core->appendChunk( core->copyChunk( pSrc ) );
276 }
277}
278
279void Bu::String::append( const iterator &s )
280{
281 append( const_iterator( s ) );
282}
283
284void Bu::String::append( const const_iterator &s, const const_iterator &e )
285{
286 if( !s.isValid() )
287 return;
288 if( !e.isValid() )
289 {
290 append( s );
291 return;
292 }
293 _hardCopy();
294 if( s.pChunk == e.pChunk )
295 {
296 // Simple case, they're the same chunk
297 Chunk *pNew = core->newChunk( e.iPos-s.iPos );
298 memcpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos );
299 core->appendChunk( pNew );
300 }
301 else
302 {
303 // A little trickier, scan the blocks...
304 Chunk *pSrc = s.pChunk;
305 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
306 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
307 core->appendChunk( pNew );
308
309 while( (pSrc = pSrc->pNext) != e.pChunk )
310 {
311 core->appendChunk( core->copyChunk( pSrc ) );
312 }
313
314 pNew = core->newChunk( e.iPos );
315 memcpy( pNew->pData, pSrc->pData, e.iPos );
316 core->appendChunk( pNew );
317 }
318}
319
320void Bu::String::prepend( const String & sData )
321{
322 prepend( sData.getStr(), sData.getSize() );
323}
324
325void Bu::String::prepend( const char *pData )
326{
327 if( pData == NULL )
328 return;
329
330 _hardCopy();
331 long nLen;
332 for( nLen = 0; pData[nLen] != (char)0; nLen++ ) { }
333
334 Chunk *pNew = core->newChunk( nLen );
335 memcpy( pNew->pData, pData, nLen );
336
337 core->prependChunk( pNew );
338}
339
340void Bu::String::prepend( const char *pData, long nLen )
341{
342 Chunk *pNew = core->newChunk( nLen );
343
344 memcpy( pNew->pData, pData, nLen );
345
346 _hardCopy();
347 core->prependChunk( pNew );
348}
349
350void Bu::String::prepend( const char c )
351{
352 prepend( &c, 1 );
353}
354
355void Bu::String::insert( long nPos, const char *pData, long nLen )
356{
357 if( nLen <= 0 )
358 return;
359 if( nPos <= 0 )
360 {
361 prepend( pData, nLen );
362 }
363 else if( nPos >= core->nLength )
364 {
365 append( pData, nLen );
366 }
367 else
368 {
369 // If we're going to flatten anyway, might as well for everyone
370 flatten();
371 _hardCopy();
372 Chunk *p1 = core->newChunk( nPos );
373 Chunk *p2 = core->newChunk( nLen );
374 Chunk *p3 = core->newChunk( core->nLength-nPos );
375 memcpy( p1->pData, core->pFirst->pData, nPos );
376 memcpy( p2->pData, pData, nLen );
377 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
378 core->clear();
379 core->appendChunk( p1 );
380 core->appendChunk( p2 );
381 core->appendChunk( p3 );
382 }
383}
384
385void Bu::String::insert( long nPos, const String &str )
386{
387 if( nPos <= 0 )
388 {
389 prepend( str );
390 }
391 else if( nPos >= core->nLength )
392 {
393 append( str );
394 }
395 else
396 {
397 flatten();
398 _hardCopy();
399 Chunk *p1 = core->newChunk( nPos );
400 Chunk *p3 = core->newChunk( core->nLength-nPos );
401 memcpy( p1->pData, core->pFirst->pData, nPos );
402 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
403 core->clear();
404 core->appendChunk( p1 );
405 for( Chunk *pChnk = str.core->pFirst; pChnk;
406 pChnk = pChnk->pNext )
407 {
408 core->appendChunk( core->copyChunk( pChnk ) );
409 }
410
411 core->appendChunk( p3 );
412 }
413}
414
415void Bu::String::insert( long nPos, const char *pData )
416{
417 insert( nPos, pData, strlen( pData ) );
418}
419
420void Bu::String::remove( long nPos, long nLen )
421{
422 if( nLen <= 0 || nPos < 0 || nPos >= core->nLength )
423 return;
424 if( nLen > core->nLength-nPos )
425 nLen = core->nLength-nPos;
426 flatten();
427 _hardCopy();
428 memmove( core->pFirst->pData+nPos, core->pFirst->pData+nPos+nLen, core->nLength-nPos-nLen+1 );
429 core->nLength -= nLen;
430 core->pFirst->nLength -= nLen;
431}
432
433void Bu::String::clear()
434{
435 _hardCopy();
436 core->clear();
437}
438
439Bu::String Bu::String::replace( const Bu::String &fnd,
440 const Bu::String &rep ) const
441{
442 String out;
443 const_iterator o = begin();
444 while( true )
445 {
446 const_iterator i = o.find( fnd, fnd.getSize() );
447 if( !i )
448 {
449 out.append( o );
450 return out;
451 }
452 else
453 {
454 out.append( o, i );
455 out.append( rep );
456 o = i;
457 o += fnd.getSize();
458 }
459 }
460}
461
462void Bu::String::resize( long nNewSize )
463{
464 if( core->nLength == nNewSize )
465 return;
466 if( nNewSize < 0 )
467 nNewSize = 0;
468
469 flatten();
470 _hardCopy();
471
472 // TODO: This is bad
473
474 Chunk *pNew = core->newChunk( nNewSize );
475 long nNewLen = (nNewSize<core->nLength)?(nNewSize):(core->nLength);
476 if( core->nLength > 0 )
477 {
478 memcpy( pNew->pData, core->pFirst->pData, nNewLen );
479 delete[] core->pFirst->pData;
480 delete core->pFirst;
481 }
482 pNew->pData[nNewLen] = (char)0;
483 core->pFirst = core->pLast = pNew;
484 core->nLength = nNewSize;
485}
486
487long Bu::String::getSize() const
488{
489 return core->nLength;
490}
491
492char *Bu::String::getStr()
493{
494 if( core->pFirst == NULL || core->nLength == 0 )
495 return (char *)"";
496
497 flatten();
498 _hardCopy();
499 core->pFirst->pData[core->nLength] = (char)0;
500 return core->pFirst->pData;
501}
502
503const char *Bu::String::getStr() const
504{
505 if( core->pFirst == NULL || core->nLength == 0 )
506 return (char *)"";
507
508 flatten();
509 core->pFirst->pData[core->nLength] = (char)0;
510 return core->pFirst->pData;
511}
512
513const char *Bu::String::getConstStr() const
514{
515 return getStr();
516}
517
518Bu::String Bu::String::getSubStrIdx( long iStart, long iSize ) const
519{
520 if( iStart < 0 )
521 iStart = 0;
522 if( iStart >= core->nLength )
523 return (const char[]){(char)0};
524 if( iSize < 0 )
525 iSize = core->nLength;
526 if( iStart+iSize > core->nLength )
527 iSize = core->nLength-iStart;
528 if( iSize == 0 )
529 return (const char[]){(char)0};
530
531 flatten();
532 String ret( core->pFirst->pData+iStart, iSize );
533 return ret;
534}
535
536Bu::String Bu::String::getSubStr( const_iterator iBegin,
537 const_iterator iEnd ) const
538{
539 if( !iBegin.isValid() )
540 return String();
541 if( iBegin.pChunk == iEnd.pChunk )
542 {
543 return String( iBegin.pChunk->pData+iBegin.iPos,
544 iEnd.iPos-iBegin.iPos );
545 }
546 else if( !iEnd.isValid() )
547 {
548 String ret;
549 ret.append(
550 iBegin.pChunk->pData+iBegin.iPos,
551 iBegin.pChunk->nLength-iBegin.iPos
552 );
553 for( Chunk *pCur = iBegin.pChunk->pNext;
554 pCur; pCur = pCur->pNext )
555 {
556 ret.append( pCur->pData, pCur->nLength );
557 }
558 return ret;
559 }
560 else
561 {
562 String ret;
563 ret.append(
564 iBegin.pChunk->pData+iBegin.iPos,
565 iBegin.pChunk->nLength-iBegin.iPos
566 );
567 for( Chunk *pCur = iBegin.pChunk->pNext;
568 pCur != iEnd.pChunk; pCur = pCur->pNext )
569 {
570 ret.append( pCur->pData, pCur->nLength );
571 }
572 ret.append(
573 iEnd.pChunk->pData,
574 iEnd.iPos
575 );
576 return ret;
577 }
578}
579
580Bu::StringList Bu::String::split( const char c ) const
581{
582 Bu::StringList ret;
583 const_iterator l, r;
584 l = begin();
585 for(r=l; l;)
586 {
587 for( r = l; r && r != c; r++ ) { }
588 ret.append( String( l, r ) );
589 l = r;
590 l++;
591 }
592 return ret;
593}
594
595Bu::String &Bu::String::operator+=( const char *pData )
596{
597 append( pData );
598
599 return (*this);
600}
601
602Bu::String &Bu::String::operator+=( const Bu::String &rSrc )
603{
604 append( rSrc );
605
606 return (*this);
607}
608
609Bu::String &Bu::String::operator+=( const Bu::String::const_iterator &i )
610{
611 append( i, i+1 );
612
613 return (*this);
614}
615
616Bu::String &Bu::String::operator+=( const char cData )
617{
618 if( core->pLast && core->pLast->nLength < nMinSize )
619 {
620 _hardCopy();
621 core->pLast->pData[core->pLast->nLength] = cData;
622 ++core->pLast->nLength; ++core->nLength;
623// pLast->pData[pLast->nLength] = (char)0;
624 }
625 else
626 {
627 append( &cData, 1 );
628 }
629 //append( pData );
630
631 return (*this);
632}
633
634Bu::String &Bu::String::operator=( const char *pData )
635{
636 set( pData );
637
638 return (*this);
639}
640
641Bu::String Bu::String::operator+( const Bu::String &rRight ) const
642{
643 String ret( *this );
644 ret.append( rRight );
645 return ret;
646}
647
648Bu::String Bu::String::operator+( const char *pRight ) const
649{
650 String ret( *this );
651 ret.append( pRight );
652 return ret;
653}
654
655Bu::String Bu::String::operator+( char *pRight ) const
656{
657 String ret( *this );
658 ret.append( pRight );
659 return ret;
660}
661
662void Bu::String::set( const char *pData )
663{
664 clear();
665 append( pData );
666}
667
668void Bu::String::set( const char *pData, long nSize )
669{
670 clear();
671 append( pData, nSize );
672}
673
674void Bu::String::set( const char *pData, long nStart, long nSize )
675{
676 clear();
677 append( pData, nStart, nSize );
678}
679
680void Bu::String::set( const String &rData )
681{
682 clear();
683 append( rData );
684}
685
686void Bu::String::set( const String &rData, long nSize )
687{
688 clear();
689 append( rData, nSize );
690}
691
692void Bu::String::set( const String &rData, long nStart, long nSize )
693{
694 clear();
695 append( rData, nStart, nSize );
696}
697
698void Bu::String::set( const_iterator s )
699{
700 clear();
701 append( s );
702}
703
704void Bu::String::set( const_iterator s, const_iterator e )
705{
706 clear();
707 append( s, e );
708}
709
710void Bu::String::setSize( long iSize )
711{
712 _hardCopy();
713 core->clear();
714 core->appendChunk( core->newChunk( iSize ) );
715}
716
717bool Bu::String::operator==( const char *pData ) const
718{
719 if( core->pFirst == NULL || core->nLength == 0 ) {
720 if( pData == NULL )
721 return true;
722 if( pData[0] == (char)0 )
723 return true;
724 return false;
725 }
726
727 flatten();
728 core->pFirst->pData[core->nLength] = (char)0;
729 const char *a = pData;
730 char *b = core->pFirst->pData;
731 for( long j = 0; *a!=(char)0 || *b!=(char)0; j++, a++, b++ )
732 {
733 if( *a != *b )
734 return false;
735 if( *a == (char)0 && j < core->nLength )
736 return false;
737 }
738
739 return true;
740}
741
742bool Bu::String::operator==( const String &pData ) const
743{
744 if( core == pData.core )
745 return true;
746 if( core->pFirst == pData.core->pFirst )
747 return true;
748 if( (core->nLength == 0 && pData.core->nLength == 0) )
749 return true;
750 if( core->nLength != pData.core->nLength )
751 return false;
752 if( pData.core->pFirst == NULL || core->pFirst == NULL )
753 return false;
754
755 flatten();
756 pData.flatten();
757 const char *a = pData.core->pFirst->pData;
758 char *b = core->pFirst->pData;
759 for( long j = 0; j < core->nLength; j++, a++, b++ )
760 {
761 if( *a != *b )
762 return false;
763 }
764
765 return true;
766}
767
768bool Bu::String::operator!=(const char *pData ) const
769{
770 return !(*this == pData);
771}
772
773bool Bu::String::operator!=(const String &pData ) const
774{
775 return !(*this == pData);
776}
777
778bool Bu::String::operator<(const String &pData ) const
779{
780 flatten();
781 pData.flatten();
782
783 const char *a = core->pFirst->pData;
784 char *b = pData.core->pFirst->pData;
785 for( long j = 0; j < core->nLength; j++, a++, b++ )
786 {
787 if( *a != *b )
788 return *a < *b;
789 }
790
791 return false;
792}
793
794bool Bu::String::operator<=(const String &pData ) const
795{
796 flatten();
797 pData.flatten();
798
799 const char *a = core->pFirst->pData;
800 char *b = pData.core->pFirst->pData;
801 for( long j = 0; j < core->nLength; j++, a++, b++ )
802 {
803 if( *a != *b )
804 return *a < *b;
805 }
806
807 return true;
808}
809
810bool Bu::String::operator>(const String &pData ) const
811{
812 flatten();
813 pData.flatten();
814
815 const char *a = core->pFirst->pData;
816 char *b = pData.core->pFirst->pData;
817 for( long j = 0; j < core->nLength; j++, a++, b++ )
818 {
819 if( *a != *b )
820 return *a > *b;
821 }
822
823 return false;
824}
825
826bool Bu::String::operator>=(const String &pData ) const
827{
828 flatten();
829 pData.flatten();
830
831 const char *a = core->pFirst->pData;
832 char *b = pData.core->pFirst->pData;
833 for( long j = 0; j < core->nLength; j++, a++, b++ )
834 {
835 if( *a != *b )
836 return *a > *b;
837 }
838
839 return true;
840}
841
842char &Bu::String::operator[]( long nIndex )
843{
844 if( nIndex < 0 || nIndex >= core->nLength )
845 throw Bu::ExceptionBase("Index out of range.");
846 flatten();
847 _hardCopy();
848
849 return core->pFirst->pData[nIndex];
850}
851
852const char &Bu::String::operator[]( long nIndex ) const
853{
854 if( nIndex < 0 || nIndex >= core->nLength )
855 throw Bu::ExceptionBase("Index out of range.");
856 flatten();
857
858 return core->pFirst->pData[nIndex];
859}
860
861bool Bu::String::isSet() const
862{
863 return (core->pFirst != NULL);
864}
865
866bool Bu::String::compareSub( const char *pData, long nIndex, long nLen ) const
867{
868 if( core->pFirst == NULL || core->nLength == 0 ) {
869 if( pData == NULL )
870 return true;
871 if( nLen == 0 )
872 return true;
873 if( pData[0] == (char)0 )
874 return true;
875 return false;
876 }
877 if( nIndex+nLen > core->nLength )
878 return false;
879
880 flatten();
881 core->pFirst->pData[core->nLength] = (char)0;
882 const char *a = pData;
883 char *b = core->pFirst->pData+nIndex;
884 for( long j = 0; j < nLen; j++, a++, b++ )
885 {
886 if( *a != *b )
887 return false;
888 if( *a == (char)0 && j < core->nLength )
889 return false;
890 }
891
892 return true;
893}
894
895bool Bu::String::compareSub( const String &rData, long nIndex, long nLen ) const
896{
897 if( core->pFirst == NULL || core->nLength == 0 || rData.core->pFirst == NULL || rData.core->nLength == 0 )
898 return false;
899 if( nLen < 0 )
900 nLen = rData.core->nLength;
901 if( nIndex+nLen > core->nLength )
902 return false;
903
904 flatten();
905 rData.flatten();
906 const char *a = rData.core->pFirst->pData;
907 char *b = core->pFirst->pData + nIndex;
908 for( long j = 0; j < nLen; j++, a++, b++ )
909 {
910 if( *a != *b )
911 return false;
912 }
913
914 return true;
915}
916
917bool Bu::String::isWS( long nIndex ) const
918{
919 flatten();
920
921 return core->pFirst->pData[nIndex]==' ' || core->pFirst->pData[nIndex]=='\t'
922 || core->pFirst->pData[nIndex]=='\r' || core->pFirst->pData[nIndex]=='\n';
923}
924
925bool Bu::String::isAlpha( long nIndex ) const
926{
927 flatten();
928
929 return (core->pFirst->pData[nIndex] >= 'a' && core->pFirst->pData[nIndex] <= 'z')
930 || (core->pFirst->pData[nIndex] >= 'A' && core->pFirst->pData[nIndex] <= 'Z');
931}
932
933Bu::String Bu::String::toLower() const
934{
935 Bu::String sRet = *this;
936
937 sRet.flatten();
938 sRet._hardCopy();
939
940 for( long j = 0; j < sRet.core->nLength; j++ )
941 {
942 if( sRet.core->pFirst->pData[j] >= 'A' &&
943 sRet.core->pFirst->pData[j] <= 'Z' )
944 sRet.core->pFirst->pData[j] -= 'A'-'a';
945 }
946
947 return sRet;
948}
949
950Bu::String Bu::String::toUpper() const
951{
952 Bu::String sRet = *this;
953
954 sRet.flatten();
955 sRet._hardCopy();
956
957 for( long j = 0; j < sRet.core->nLength; j++ )
958 {
959 if( sRet.core->pFirst->pData[j] >= 'a' &&
960 sRet.core->pFirst->pData[j] <= 'z' )
961 sRet.core->pFirst->pData[j] += 'A'-'a';
962 }
963
964 return sRet;
965}
966
967Bu::String::const_iterator Bu::String::find( const char cChar,
968 Bu::String::const_iterator iStart ) const
969{
970 if( !iStart ) iStart = begin();
971 for( ; iStart; iStart++ )
972 {
973 if( cChar == *iStart )
974 return iStart;
975 }
976 return end();
977}
978
979Bu::String::const_iterator Bu::String::find( const char *sText, int nLen,
980 Bu::String::const_iterator iStart ) const
981{
982 if( !iStart ) iStart = begin();
983 for( ; iStart; iStart++ )
984 {
985 if( iStart.compare( sText, nLen ) )
986 return iStart;
987 }
988 return end();
989}
990
991Bu::String::const_iterator Bu::String::find( const String &rStr,
992 Bu::String::const_iterator iStart ) const
993{
994 if( !iStart ) iStart = begin();
995 for( ; iStart; iStart++ )
996 {
997 if( iStart.compare( rStr ) )
998 return iStart;
999 }
1000 return end();
1001}
1002
1003Bu::String::const_iterator Bu::String::find( const String &rStr, int nLen,
1004 Bu::String::const_iterator iStart ) const
1005{
1006 if( !iStart ) iStart = begin();
1007 for( ; iStart; iStart++ )
1008 {
1009 if( iStart.compare( rStr, nLen ) )
1010 return iStart;
1011 }
1012 return end();
1013}
1014
1015Bu::String::iterator Bu::String::find( const char cChar,
1016 Bu::String::const_iterator iStart )
1017{
1018 if( !iStart ) iStart = begin();
1019 for( ; iStart; iStart++ )
1020 {
1021 if( cChar == *iStart )
1022 return iterator( iStart.pChunk, iStart.iPos );
1023 }
1024 return end();
1025}
1026
1027Bu::String::iterator Bu::String::find( const char *sText, int nLen,
1028 Bu::String::const_iterator iStart )
1029{
1030 if( !iStart ) iStart = begin();
1031 for( ; iStart; iStart++ )
1032 {
1033 if( iStart.compare( sText, nLen ) )
1034 return iterator( iStart.pChunk, iStart.iPos );
1035 }
1036 return end();
1037}
1038
1039Bu::String::iterator Bu::String::find( const String &rStr,
1040 Bu::String::const_iterator iStart )
1041{
1042 if( !iStart ) iStart = begin();
1043 for( ; iStart; iStart++ )
1044 {
1045 if( iStart.compare( rStr ) )
1046 return iterator( iStart.pChunk, iStart.iPos );
1047 }
1048 return end();
1049}
1050
1051Bu::String::iterator Bu::String::find( const String &rStr, int nLen,
1052 Bu::String::const_iterator iStart )
1053{
1054 if( !iStart ) iStart = begin();
1055 for( ; iStart; iStart++ )
1056 {
1057 if( iStart.compare( rStr, nLen ) )
1058 return iterator( iStart.pChunk, iStart.iPos );
1059 }
1060 return end();
1061}
1062
1063long Bu::String::findIdx( const char cChar, long iStart ) const
1064{
1065 flatten();
1066 for( long j = iStart; j < core->pFirst->nLength; j++ )
1067 {
1068 if( core->pFirst->pData[j] == cChar )
1069 return j;
1070 }
1071 return -1;
1072}
1073
1074long Bu::String::findIdx( const char *sText, long iStart ) const
1075{
1076 long nTLen = strlen( sText );
1077 flatten();
1078 for( long j = iStart; j < core->pFirst->nLength-nTLen; j++ )
1079 {
1080 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1081 return j;
1082 }
1083 return -1;
1084}
1085
1086long Bu::String::rfindIdx( const char *sText ) const
1087{
1088 long nTLen = strlen( sText );
1089 flatten();
1090 for( long j = core->pFirst->nLength-nTLen-1; j >= 0; j-- )
1091 {
1092 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1093 return j;
1094 }
1095 return -1;
1096}
1097
1098void Bu::String::trimFront( long nAmnt )
1099{
1100 long nNewLen = core->nLength - nAmnt;
1101 flatten();
1102 Chunk *pNew = core->newChunk( nNewLen );
1103 memcpy( pNew->pData, core->pFirst->pData+nAmnt, nNewLen );
1104 _hardCopy();
1105 core->clear();
1106 core->appendChunk( pNew );
1107}
1108/*
1109void Bu::String::trimBack( char c )
1110{
1111 if( core->pFirst == NULL || core->nLength == 0 )
1112 return;
1113 flatten();
1114 for( ; core->pFirst->nLength > 0 &&
1115 core->pFirst->pData[core->pFirst->nLength-1] == c;
1116 core->pFirst->nLength--, core->nLength-- ) { }
1117}
1118*/
1119void Bu::String::trimBack( long iAmnt )
1120{
1121 if( iAmnt < 0 )
1122 return;
1123 if( core->nLength - iAmnt < 0 )
1124 {
1125 clear();
1126 return;
1127 }
1128 if( core->pFirst == NULL || core->nLength == 0 )
1129 return;
1130
1131 flatten();
1132 core->pFirst->nLength -= iAmnt;
1133 core->nLength -= iAmnt;
1134}
1135
1136Bu::String Bu::String::trimWhitespace() const
1137{
1138 if( core->nLength == 0 )
1139 return "";
1140 const_iterator i = begin();
1141 for( ; i && (*i == ' ' || *i == '\t' || *i == '\n' || *i == '\r'); i++ ) { }
1142 if( !i )
1143 return "";
1144
1145 const_iterator e = i;
1146 for( ; e; e++ )
1147 {
1148 if( *e == ' ' || *e == '\t' || *e == '\n' || *e == '\r' )
1149 {
1150 const_iterator t = e;
1151 for( ; t && (*t == ' ' || *t == '\t' || *t == '\n' || *t == '\r'); t++ ) { }
1152 if( t )
1153 {
1154 e = t;
1155 }
1156 else
1157 {
1158 break;
1159 }
1160 }
1161 }
1162
1163 return Bu::String( i, e );
1164}
1165
1166Bu::String::iterator Bu::String::begin()
1167{
1168 if( core->nLength == 0 )
1169 return iterator( NULL, 0 );
1170 return iterator( core->pFirst, 0 );
1171}
1172
1173Bu::String::const_iterator Bu::String::begin() const
1174{
1175 if( core->nLength == 0 )
1176 return const_iterator( NULL, 0 );
1177 return iterator( core->pFirst, 0 );
1178}
1179
1180Bu::String::iterator Bu::String::end()
1181{
1182 return iterator( NULL, 0 );
1183}
1184
1185Bu::String::const_iterator Bu::String::end() const
1186{
1187 return const_iterator( NULL, 0 );
1188}
1189
1190bool Bu::String::isEmpty() const
1191{
1192 if( core->nLength == 0 )
1193 return true;
1194 return false;
1195}
1196
1197void Bu::String::flatten() const
1198{
1199 if( isFlat() )
1200 return;
1201
1202 if( core->pFirst == NULL || core->nLength == 0 )
1203 return;
1204
1205 Chunk *pNew = core->newChunk( core->nLength );
1206 char *pos = pNew->pData;
1207 Chunk *i = core->pFirst;
1208 for(;;)
1209 {
1210 memcpy( pos, i->pData, i->nLength );
1211 pos += i->nLength;
1212 i = i->pNext;
1213 if( i == NULL )
1214 break;
1215 }
1216 core->clear();
1217
1218 core->pLast = core->pFirst = pNew;
1219 core->nLength = pNew->nLength;
1220}
1221
1222bool Bu::String::isFlat() const
1223{
1224 return (core->pFirst == core->pLast);
1225}
1226
1227//
1228// Sub-class Bu::String::FormatProxy
1229//
1230
1231Bu::String::FormatProxy::FormatProxy( const String &rFmt ) :
1232 rFmt( rFmt )
1233{
1234}
1235
1236Bu::String::FormatProxy::~FormatProxy()
1237{
1238}
1239
1240Bu::String::FormatProxy::operator Bu::String() const
1241{
1242 int iCount = lArgs.getSize();
1243 ArgList::const_iterator *aArg =
1244 new ArgList::const_iterator[iCount];
1245 {
1246 int j = 0;
1247 for( ArgList::const_iterator i = lArgs.begin();
1248 i; i++, j++ )
1249 {
1250 aArg[j] = i;
1251 }
1252 }
1253 Bu::MemBuf mbOut;
1254 Bu::Formatter f( mbOut );
1255 for( String::const_iterator s = rFmt.begin(); s; s++ )
1256 {
1257 if( *s == '%' )
1258 {
1259 s++;
1260 if( *s == '%' )
1261 f << *s;
1262 else
1263 {
1264 String sNum;
1265 while( s && *s >= '0' && *s <= '9' )
1266 {
1267 sNum += *s;
1268 s++;
1269 }
1270 int iIndex = strtol( sNum.getStr(), 0, 10 )-1;
1271 if( iIndex < 0 || iIndex >= iCount )
1272 {
1273 delete[] aArg;
1274 throw Bu::ExceptionBase(
1275 "Argument index %d is outside of "
1276 "valid range (1-%d).", iIndex+1, iCount
1277 );
1278 }
1279
1280 f << (*aArg[iIndex]).format << (*aArg[iIndex]).value;
1281 if( s )
1282 f << *s;
1283 }
1284 }
1285 else
1286 {
1287 f << *s;
1288 }
1289 }
1290
1291 delete[] aArg;
1292 return mbOut.getString();
1293}
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341template<> uint32_t Bu::__calcHashCode<Bu::String>( const Bu::String &k )
1342{
1343 long j, sz = k.getSize();
1344 const char *s = k.getStr();
1345
1346 long nPos = 0;
1347 for( j = 0; j < sz; j++, s++ )
1348 {
1349 nPos = *s + (nPos << 6) + (nPos << 16) - nPos;
1350 }
1351
1352 return nPos;
1353}
1354
1355template<> bool Bu::__cmpHashKeys<Bu::String>(
1356 const Bu::String &a, const Bu::String &b )
1357{
1358 return a == b;
1359}
1360
1361template<> void Bu::__tracer_format<Bu::String>( const Bu::String &v )
1362{
1363 printf("(%ld)\"%s\"", v.getSize(), v.getStr() );
1364}
1365
1366bool &Bu::operator<<( bool &dst, const Bu::String &sIn )
1367{
1368 if( sIn == "true" || sIn == "yes" || sIn == "t" )
1369 dst = true;
1370 else
1371 dst = false;
1372
1373 return dst;
1374}
1375
1376uint8_t &Bu::operator<<( uint8_t &dst, const Bu::String &sIn )
1377{
1378 sscanf( sIn.getStr(), "%hhu", &dst );
1379 return dst;
1380}
1381
1382int8_t &Bu::operator<<( int8_t &dst, const Bu::String &sIn )
1383{
1384 sscanf( sIn.getStr(), "%hhd", &dst );
1385 return dst;
1386}
1387
1388char &Bu::operator<<( char &dst, const Bu::String &sIn )
1389{
1390 sscanf( sIn.getStr(), "%hhd", &dst );
1391 return dst;
1392}
1393
1394uint16_t &Bu::operator<<( uint16_t &dst, const Bu::String &sIn )
1395{
1396 sscanf( sIn.getStr(), "%hu", &dst );
1397 return dst;
1398}
1399
1400int16_t &Bu::operator<<( int16_t &dst, const Bu::String &sIn )
1401{
1402 sscanf( sIn.getStr(), "%hd", &dst );
1403 return dst;
1404}
1405
1406uint32_t &Bu::operator<<( uint32_t &dst, const Bu::String &sIn )
1407{
1408 sscanf( sIn.getStr(), "%u", &dst );
1409 return dst;
1410}
1411
1412int32_t &Bu::operator<<( int32_t &dst, const Bu::String &sIn )
1413{
1414 sscanf( sIn.getStr(), "%d", &dst );
1415 return dst;
1416}
1417
1418uint64_t &Bu::operator<<( uint64_t &dst, const Bu::String &sIn )
1419{
1420 sscanf( sIn.getStr(), "%llu", &dst );
1421 return dst;
1422}
1423
1424int64_t &Bu::operator<<( int64_t &dst, const Bu::String &sIn )
1425{
1426 sscanf( sIn.getStr(), "%lld", &dst );
1427 return dst;
1428}
1429
1430float &Bu::operator<<( float &dst, const Bu::String &sIn )
1431{
1432 sscanf( sIn.getStr(), "%f", &dst );
1433 return dst;
1434}
1435
1436double &Bu::operator<<( double &dst, const Bu::String &sIn )
1437{
1438 sscanf( sIn.getStr(), "%lf", &dst );
1439 return dst;
1440}
1441
1442long double &Bu::operator<<( long double &dst, const Bu::String &sIn )
1443{
1444 sscanf( sIn.getStr(), "%Lf", &dst );
1445 return dst;
1446}
1447
1448Bu::String &Bu::operator<<( Bu::String &dst, const Bu::String &sIn )
1449{
1450 dst = sIn;
1451 return dst;
1452}
1453
1454Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, const Bu::String &s )
1455{
1456 long n = s.getSize();
1457 ar << n;
1458 ar.write( s.getConstStr(), n );
1459 return ar;
1460}
1461
1462Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, Bu::String &s )
1463{
1464 long n;
1465 ar >> n;
1466 s.setSize( n );
1467 ar.read( s.getStr(), n );
1468 return ar;
1469}
1470
diff --git a/src/stable/string.h b/src/stable/string.h
new file mode 100644
index 0000000..a9006d1
--- /dev/null
+++ b/src/stable/string.h
@@ -0,0 +1,1053 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_STRING_H
9#define BU_STRING_H
10
11#include <stdint.h>
12#include <memory>
13
14#include "bu/util.h"
15#include "bu/sharedcore.h"
16#include "bu/exceptionbase.h"
17#include "bu/archivebase.h"
18#include "bu/list.h"
19#include "bu/fmt.h"
20#include "bu/variant.h"
21#include <string.h>
22
23namespace Bu
24{
25 class String;
26 class MemBuf;
27
28 /** @cond DEVEL */
29 class StringCore
30 {
31 friend class String;
32 friend class SharedCore<String, StringCore>;
33 private:
34 struct Chunk
35 {
36 long nLength;
37 char *pData;
38 Chunk *pNext;
39 };
40
41 StringCore();
42 StringCore( const StringCore &rSrc );
43 virtual ~StringCore();
44
45 mutable long nLength;
46 mutable Chunk *pFirst;
47 mutable Chunk *pLast;
48
49 void clear() const;
50 Chunk *newChunk() const;
51 Chunk *newChunk( long nLen ) const;
52 Chunk *copyChunk( Chunk *pSrc ) const;
53 void appendChunk( Chunk *pNewChunk );
54 void prependChunk( Chunk *pNewChunk );
55 };
56 /** @endcond */
57
58 /**
59 */
60 class String : public SharedCore<String, StringCore>
61 {
62 protected:
63 using SharedCore<String, StringCore >::core;
64 using SharedCore<String, StringCore >::_hardCopy;
65
66 private:
67 typedef StringCore::Chunk Chunk;
68
69 public: // Iterators
70 struct iterator;
71 typedef struct const_iterator
72 {
73 friend class String;
74 friend struct iterator;
75 private:
76 const_iterator( Chunk *pChunk, int iPos ) :
77 pChunk( pChunk ),
78 iPos( iPos )
79 {
80 }
81
82 Chunk *pChunk;
83 int iPos;
84
85 public:
86 const_iterator( const const_iterator &i ) :
87 pChunk( i.pChunk ),
88 iPos( i.iPos )
89 {
90 }
91
92 const_iterator( const struct iterator &i ) :
93 pChunk( i.pChunk ),
94 iPos( i.iPos )
95 {
96 }
97
98 const_iterator() :
99 pChunk( NULL ),
100 iPos( 0 )
101 {
102 }
103
104 bool operator==( const const_iterator &i ) const
105 {
106 return pChunk == i.pChunk && iPos == i.iPos;
107 }
108
109 bool operator!=( const const_iterator &i ) const
110 {
111 return !(*this == i);
112 }
113
114 const_iterator &operator=( const const_iterator &i )
115 {
116 pChunk = i.pChunk;
117 iPos = i.iPos;
118 return *this;
119 }
120
121 const_iterator &operator=( const iterator &i )
122 {
123 pChunk = i.pChunk;
124 iPos = i.iPos;
125 return *this;
126 }
127
128 const_iterator &operator++()
129 {
130 if( !pChunk ) return *this;
131 iPos++;
132 if( iPos >= pChunk->nLength )
133 {
134 iPos = 0;
135 pChunk = pChunk->pNext;
136 }
137 return *this;
138 }
139
140 const_iterator &operator++( int )
141 {
142 if( !pChunk ) return *this;
143 iPos++;
144 if( iPos >= pChunk->nLength )
145 {
146 iPos = 0;
147 pChunk = pChunk->pNext;
148 }
149 return *this;
150 }
151
152 const_iterator &operator+=( int iAmnt )
153 {
154 if( !pChunk ) return *this;
155 iPos += iAmnt;
156 while( iPos >= pChunk->nLength )
157 {
158 iPos -= pChunk->nLength;
159 pChunk = pChunk->pNext;
160 if( pChunk == NULL )
161 break;
162 }
163 return *this;
164 }
165
166 const_iterator operator+( int iAmnt ) const
167 {
168 if( !pChunk ) return *this;
169 const_iterator ret( *this );
170 ret += iAmnt;
171 return ret;
172 }
173
174 const char &operator *() const
175 {
176 if( !pChunk ) throw Bu::ExceptionBase("Not a valid const_iterator.");
177 return pChunk->pData[iPos];
178 }
179
180 bool operator==( const char &c ) const
181 {
182 if( !pChunk ) return false;
183 return pChunk->pData[iPos] == c;
184 }
185
186 bool operator!=( const char &c ) const
187 {
188 if( !pChunk ) return false;
189 return pChunk->pData[iPos] != c;
190 }
191
192 operator bool() const
193 {
194 return pChunk != NULL;
195 }
196
197 bool isValid() const
198 {
199 return pChunk != NULL;
200 }
201
202 bool compare( const const_iterator &c ) const
203 {
204 const_iterator a = *this;
205 const_iterator b = c;
206 if( a == b )
207 return true;
208 for(; a && b; a++, b++ )
209 {
210 if( *a != *b )
211 return false;
212 }
213 if( (bool)a != (bool)b )
214 return false;
215 return true;
216 }
217
218 bool compare( const const_iterator &c, int nLen ) const
219 {
220 const_iterator a = *this;
221 const_iterator b = c;
222 if( a == b )
223 return true;
224 for(int j = 0; j < nLen; a++, b++, j++ )
225 {
226 if( !a || !b || *a != *b )
227 return false;
228 }
229 return true;
230 }
231
232 bool compare( const char *c ) const
233 {
234 if( !pChunk ) return false;
235 const_iterator a = *this;
236 for(; a && *c; a++, c++ )
237 {
238 if( *a != *c )
239 return false;
240 }
241 if( a.isValid() != (*c!=(char)0) )
242 return false;
243 return true;
244 }
245
246 bool compare( const char *c, int nLen ) const
247 {
248 if( !pChunk ) return false;
249 const_iterator a = *this;
250 int j = 0;
251 for(; a && j < nLen; a++, c++, j++ )
252 {
253 if( *a != *c )
254 return false;
255 }
256 if( j < nLen )
257 return false;
258 return true;
259 }
260
261 bool compare( const String &s ) const
262 {
263 if( !pChunk ) return false;
264 return compare( s.begin() );
265 }
266
267 bool compare( const String &s, int nLen ) const
268 {
269 if( !pChunk ) return false;
270 return compare( s.begin(), nLen );
271 }
272
273 const_iterator find( const char c ) const
274 {
275 for( const_iterator i = *this; i; i++ )
276 {
277 if( *i == c )
278 return i;
279 }
280 return const_iterator( NULL, 0 );
281 }
282
283 const_iterator find( const char *pStr, int nLen ) const
284 {
285 for( const_iterator i = *this; i; i++ )
286 {
287 if( i.compare( pStr, nLen ) )
288 return i;
289 }
290 return const_iterator( NULL, 0 );
291 }
292
293 const_iterator find( const String &s ) const
294 {
295 for( const_iterator i = *this; i; i++ )
296 {
297 if( i.compare( s ) )
298 return i;
299 }
300 return const_iterator( NULL, 0 );
301 }
302
303 const_iterator find( const String &s, int nLen ) const
304 {
305 for( const_iterator i = *this; i; i++ )
306 {
307 if( i.compare( s, nLen ) )
308 return i;
309 }
310 return const_iterator( NULL, 0 );
311 }
312 } const_iterator;
313
314 typedef struct iterator
315 {
316 friend class String;
317 friend struct const_iterator;
318 private:
319 iterator( Chunk *pChunk, int iPos ) :
320 pChunk( pChunk ),
321 iPos( iPos )
322 {
323 }
324
325 Chunk *pChunk;
326 int iPos;
327
328 public:
329 iterator( const iterator &i ) :
330 pChunk( i.pChunk ),
331 iPos( i.iPos )
332 {
333 }
334
335 iterator() :
336 pChunk( NULL ),
337 iPos( 0 )
338 {
339 }
340
341 operator const_iterator() const
342 {
343 return const_iterator( pChunk, iPos );
344 }
345
346 bool operator==( const iterator &i ) const
347 {
348 return pChunk == i.pChunk && iPos == i.iPos;
349 }
350
351 bool operator!=( const iterator &i ) const
352 {
353 return !(*this == i);
354 }
355
356 iterator &operator=( const iterator &i )
357 {
358 pChunk = i.pChunk;
359 iPos = i.iPos;
360 return *this;
361 }
362
363 iterator &operator++()
364 {
365 if( !pChunk ) return *this;
366 iPos++;
367 if( iPos >= pChunk->nLength )
368 {
369 iPos = 0;
370 pChunk = pChunk->pNext;
371 }
372 return *this;
373 }
374
375 iterator &operator++( int )
376 {
377 if( !pChunk ) return *this;
378 iPos++;
379 if( iPos >= pChunk->nLength )
380 {
381 iPos = 0;
382 pChunk = pChunk->pNext;
383 }
384 return *this;
385 }
386
387 iterator &operator+=( int iAmnt )
388 {
389 if( !pChunk ) return *this;
390 iPos += iAmnt;
391 while( iPos >= pChunk->nLength )
392 {
393 iPos -= pChunk->nLength;
394 pChunk = pChunk->pNext;
395 if( pChunk == NULL )
396 break;
397 }
398 return *this;
399 }
400
401 iterator operator+( int iAmnt ) const
402 {
403 if( !pChunk ) return *this;
404 iterator ret( *this );
405 ret += iAmnt;
406 return ret;
407 }
408
409 char &operator*()
410 {
411 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
412 return pChunk->pData[iPos];
413 }
414
415 const char &operator*() const
416 {
417 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
418 return pChunk->pData[iPos];
419 }
420
421 bool operator==( const char &c ) const
422 {
423 if( !pChunk ) return false;
424 return pChunk->pData[iPos] == c;
425 }
426
427 bool operator!=( const char &c ) const
428 {
429 if( !pChunk ) return false;
430 return pChunk->pData[iPos] != c;
431 }
432
433 iterator &operator=( const char &c )
434 {
435 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
436 pChunk->pData[iPos] = c;
437 return *this;
438 }
439
440 operator bool() const
441 {
442 return pChunk != NULL;
443 }
444
445 bool isValid() const
446 {
447 return pChunk != NULL;
448 }
449
450 bool compare( const const_iterator &c ) const
451 {
452 const_iterator a( *this );
453 const_iterator b = c;
454 if( a == b )
455 return true;
456 for(; a && b; a++, b++ )
457 {
458 if( *a != *b )
459 return false;
460 }
461 if( (bool)a != (bool)b )
462 return false;
463 return true;
464 }
465
466 bool compare( const const_iterator &c, int nLen ) const
467 {
468 const_iterator a( *this );
469 const_iterator b = c;
470 if( a == b )
471 return true;
472 for(int j = 0; j < nLen; a++, b++, j++ )
473 {
474 if( !a || !b || *a != *b )
475 return false;
476 }
477 return true;
478 }
479
480 bool compare( const char *c ) const
481 {
482 if( !pChunk ) return false;
483 iterator a = *this;
484 for(; a && *c; a++, c++ )
485 {
486 if( *a != *c )
487 return false;
488 }
489 if( a.isValid() != (*c!=(char)0) )
490 return false;
491 return true;
492 }
493
494 bool compare( const char *c, int nLen ) const
495 {
496 if( !pChunk ) return false;
497 iterator a = *this;
498 int j = 0;
499 for(; a && j < nLen; a++, c++, j++ )
500 {
501 if( *a != *c )
502 return false;
503 }
504 if( j < nLen )
505 return false;
506 return true;
507 }
508
509 bool compare( const String &s ) const
510 {
511 if( !pChunk ) return false;
512 return compare( s.begin() );
513 }
514
515 bool compare( const String &s, int nLen ) const
516 {
517 if( !pChunk ) return false;
518 return compare( s.begin(), nLen );
519 }
520
521 iterator find( const char c ) const
522 {
523 for( iterator i = *this; i; i++ )
524 {
525 if( *i == c )
526 return i;
527 }
528 return iterator( NULL, 0 );
529 }
530
531 iterator find( const char *pStr, int nLen ) const
532 {
533 for( iterator i = *this; i; i++ )
534 {
535 if( i.compare( pStr, nLen ) )
536 return i;
537 }
538 return iterator( NULL, 0 );
539 }
540
541 iterator find( const String &s ) const
542 {
543 for( iterator i = *this; i; i++ )
544 {
545 if( i.compare( s ) )
546 return i;
547 }
548 return iterator( NULL, 0 );
549 }
550
551 iterator find( const String &s, int nLen ) const
552 {
553 for( iterator i = *this; i; i++ )
554 {
555 if( i.compare( s, nLen ) )
556 return i;
557 }
558 return iterator( NULL, 0 );
559 }
560 } iterator;
561
562 public:
563 String();
564 String( const char *pData );
565 String( const char *pData, long nLength );
566 String( const String &rSrc );
567 String( const String &rSrc, long nLength );
568 String( const String &rSrc, long nStart, long nLength );
569 String( long nSize );
570 String( const const_iterator &s );
571 String( const const_iterator &s, const const_iterator &e );
572 virtual ~String();
573
574 /**
575 * Append data to your string.
576 *@param pData (const char *) The data to append.
577 */
578 void append( const char *pData );
579
580 /**
581 * Append data to your string.
582 *@param pData (const char *) The data to append.
583 *@param nLen (long) The length of the data to append.
584 */
585 void append( const char *pData, long nLen );
586
587 /**
588 * Append data to your string.
589 *@param pData (const char *) The data to append.
590 *@param nStart (long) The start position to copy from.
591 *@param nLen (long) The length of the data to append.
592 */
593 void append( const char *pData, long nStart, long nLen );
594
595 /**
596 * Append a single char to your string.
597 *@param cData (const char &) The character to append.
598 */
599 void append( const char &cData );
600
601 /**
602 * Append another String to this one.
603 *@param sData (String &) The String to append.
604 *@todo This function can be made much faster by not using getStr()
605 */
606 void append( const String & sData );
607
608 /**
609 * Append another String to this one.
610 *@param sData (String &) The String to append.
611 *@param nLen How much data to append.
612 *@todo This function can be made much faster by not using getStr()
613 */
614 void append( const String & sData, long nLen );
615
616 /**
617 * Append another String to this one.
618 *@param sData (String &) The String to append.
619 *@param nStart Start position in sData to start copying from.
620 *@param nLen How much data to append.
621 *@todo This function can be made much faster by not using getStr()
622 */
623 void append( const String & sData, long nStart, long nLen );
624
625 /**
626 * Append data to this String using the passed in iterator as a base.
627 * The iterator is const, it is not changed.
628 *@param s Iterator from any compatible String to copy data from.
629 */
630 void append( const const_iterator &s );
631
632 /**
633 * Append data to this String using the passed in iterator as a base.
634 * The iterator is const, it is not changed.
635 *@param s Iterator from any compatible String to copy data from.
636 */
637 void append( const iterator &s );
638
639 /**
640 * Append data to this String using the passed in iterator as a base,
641 * and copy data until the ending iterator is reached. The character
642 * at the ending iterator is not copied.
643 * The iterators are const, they are not changed.
644 *@param s Iterator from any compatible String to copy data from.
645 *@param e Iterator to stop copying at.
646 */
647 void append( const const_iterator &s, const const_iterator &e );
648
649 /**
650 * Prepend another String to this one.
651 *@param sData (String &) The String to prepend.
652 *@todo This function can be made much faster by not using getStr()
653 */
654 void prepend( const String & sData );
655
656 /**
657 * Prepend data to your string.
658 *@param pData (const char *) The data to prepend.
659 */
660 void prepend( const char *pData );
661
662 /**
663 * Prepend data to your string.
664 *@param pData (const char *) The data to prepend.
665 *@param nLen (long) The length of the data to prepend.
666 */
667 void prepend( const char *pData, long nLen );
668
669 void prepend( const char c );
670
671 /**
672 * Insert pData before byte nPos, that is, the first byte of pData will
673 * start at nPos. This could probably be made faster by avoiding
674 * flattening.
675 */
676 void insert( long nPos, const char *pData, long nLen );
677
678 void insert( long nPos, const String &str );
679
680 /**
681 *@todo This function shouldn't use strlen, we should add our own to
682 * this class, one that can be overridden in a specific implementation.
683 */
684 void insert( long nPos, const char *pData );
685
686 void remove( long nPos, long nLen );
687
688 /**
689 * Clear all data from the string.
690 */
691 void clear();
692
693 String replace( const String &fnd, const String &rep ) const;
694
695 /**
696 * Force the string to resize
697 *@param nNewSize (long) The new size of the string.
698 */
699 void resize( long nNewSize );
700
701 /**
702 * Get the current size of the string.
703 *@returns (long) The current size of the string.
704 */
705 long getSize() const;
706
707 /**
708 * Get a pointer to the string array.
709 *@returns (char *) The string data.
710 */
711 char *getStr();
712
713 /**
714 * Get a const pointer to the string array.
715 *@returns (const char *) The string data.
716 */
717 const char *getStr() const;
718
719 /**
720 * A convinience function, this one won't cause as much work as the
721 * non-const getStr, so if you're not changing the data, consider it.
722 */
723 const char *getConstStr() const;
724
725 String getSubStrIdx( long iStart, long iSize=-1 ) const;
726
727 String getSubStr( const_iterator iBegin,
728 const_iterator iEnd=String::const_iterator() ) const;
729
730 Bu::List<String> split( const char c ) const;
731
732 /**
733 * Plus equals operator for String.
734 *@param pData (const char *) The data to append to your String.
735 */
736 String &operator+=( const char *pData );
737
738 /**
739 * Plus equals operator for String.
740 *@param rSrc (const String &) The String to append to your String.
741 */
742 String &operator+=( const String &rSrc );
743
744 String &operator+=( const String::const_iterator &i );
745
746 /**
747 * Plus equals operator for String.
748 *@param cData (const char) The character to append to your String.
749 */
750 String &operator+=( const char cData );
751
752 /**
753 * Assignment operator.
754 *@param pData (const char *) The character array to append to your
755 * String.
756 */
757 String &operator=( const char *pData );
758
759 String operator+( const String &rRight ) const;
760
761 String operator+( const char *pRight ) const;
762
763 String operator+( char *pRight ) const;
764
765 /**
766 * Reset your String to this character array.
767 *@param pData (const char *) The character array to set your String to.
768 */
769 void set( const char *pData );
770
771 /**
772 * Reset your String to this character array.
773 *@param pData (const char *) The character array to set your String to.
774 *@param nSize (long) The length of the inputted character array.
775 */
776 void set( const char *pData, long nSize );
777
778 void set( const char *pData, long nStart, long nSize );
779
780 void set( const String &rData );
781
782 void set( const String &rData, long nSize );
783
784 void set( const String &rData, long nStart, long nSize );
785
786 void set( const_iterator s );
787
788 void set( const_iterator s, const_iterator e );
789
790 /**
791 * Resize the string, possibly to make room for a copy. At the moment
792 * this operation *is* destructive. What was in the string will in no
793 * way be preserved. This is, however, very fast. If you want to
794 * keep your data check out resize.
795 *@param iSize the new size in bytes. The string is guranteed to have
796 * at least this much contiguous space available when done.
797 */
798 void setSize( long iSize );
799
800 /**
801 * Equals comparison operator.
802 *@param pData (const char *) The character array to compare your String
803 * to.
804 */
805 bool operator==( const char *pData ) const;
806
807 /**
808 * Equals comparison operator.
809 *@param pData (const String &) The String to compare your String to.
810 */
811 bool operator==( const String &pData ) const;
812
813 /**
814 * Not equals comparison operator.
815 *@param pData (const char *) The character array to compare your String
816 * to.
817 */
818 bool operator!=(const char *pData ) const;
819
820 /**
821 * Not equals comparison operator.
822 *@param pData (const String &) The String to compare your String to.
823 */
824 bool operator!=(const String &pData ) const;
825
826 bool operator<(const String &pData ) const;
827
828 bool operator<=(const String &pData ) const;
829
830 bool operator>(const String &pData ) const;
831
832 bool operator>=(const String &pData ) const;
833
834 /**
835 * Indexing operator
836 *@param nIndex (long) The index of the character you want.
837 *@returns (char &) The character at position (nIndex).
838 */
839 char &operator[]( long nIndex );
840
841 /**
842 * Const indexing operator
843 *@param nIndex (long) The index of the character you want.
844 *@returns (const char &) The character at position (nIndex).
845 */
846 const char &operator[]( long nIndex ) const;
847
848 bool isSet() const;
849
850 bool compareSub( const char *pData, long nIndex, long nLen ) const;
851
852 bool compareSub( const String &rData, long nIndex, long nLen ) const;
853
854 /**
855 * Is the character at index (nIndex) white space?
856 *@param nIndex (long) The index of the character you want to check.
857 *@returns (bool) Is it white space?
858 */
859 bool isWS( long nIndex ) const;
860
861 /**
862 * Is the character at index (nIndex) a letter?
863 *@param nIndex (long) The index of the character you want to check.
864 *@returns (bool) Is it a letter?
865 */
866 bool isAlpha( long nIndex ) const;
867
868 /**
869 * Convert your alpha characters to lower case.
870 */
871 String toLower() const;
872
873 /**
874 * Convert your alpha characters to upper case.
875 */
876 String toUpper() const;
877
878 const_iterator find( const char cChar,
879 const_iterator iStart=const_iterator() ) const;
880
881 const_iterator find( const char *sText, int nLen,
882 const_iterator iStart=const_iterator() ) const;
883
884 const_iterator find( const String &rStr,
885 const_iterator iStart=const_iterator() ) const;
886
887 const_iterator find( const String &rStr, int nLen,
888 const_iterator iStart=const_iterator() ) const;
889
890 iterator find( const char cChar,
891 const_iterator iStart=const_iterator() );
892
893 iterator find( const char *sText, int nLen,
894 const_iterator iStart=const_iterator() );
895
896 iterator find( const String &rStr,
897 const_iterator iStart=const_iterator() );
898
899 iterator find( const String &rStr, int nLen,
900 const_iterator iStart=const_iterator() );
901
902 /**
903 * Find the index of the first occurrance of cChar
904 *@param cChar The character to search for.
905 *@param iStart The position in the string to start searching from.
906 *@returns (long) The index of the first occurrance. -1 for not found.
907 */
908 long findIdx( const char cChar, long iStart=0 ) const;
909
910 /**
911 * Find the index of the first occurrance of sText
912 *@param sText The null-terminated string to search for.
913 *@param iStart The position in the string to start searching from.
914 *@returns The index of the first occurrance. -1 for not found.
915 */
916 long findIdx( const char *sText, long iStart=0 ) const;
917
918 /**
919 * Do a reverse search for (sText)
920 *@param sText (const char *) The string to search for.
921 *@returns (long) The index of the last occurrance. -1 for not found.
922 */
923 long rfindIdx( const char *sText ) const;
924
925 /**
926 * Remove nAmnt bytes from the front of the string. This function
927 * operates in O(n) time and should be used sparingly.
928 */
929 void trimFront( long nAmnt );
930
931 void trimBack( long iAmnt );
932
933 Bu::String trimWhitespace() const;
934
935 iterator begin();
936
937 const_iterator begin() const;
938
939 iterator end();
940
941 const_iterator end() const;
942
943 bool isEmpty() const;
944
945 private:
946 void flatten() const;
947 bool isFlat() const;
948
949 class FormatProxy
950 {
951 public:
952 FormatProxy( const String &rFmt );
953 virtual ~FormatProxy();
954
955 template<typename T>
956 FormatProxy &arg( const T &x )
957 {
958 lArgs.append( Arg( x ) );
959
960 return *this;
961 }
962
963 template<typename T>
964 FormatProxy &arg( const T &x, const Bu::Fmt &f )
965 {
966 lArgs.append( Arg( x, f ) );
967
968 return *this;
969 }
970
971 operator String() const;
972
973 private:
974 const String &rFmt;
975 class Arg
976 {
977 public:
978 template<typename T>
979 Arg( const T &v ) :
980 value( v )
981 {
982 }
983
984 template<typename T>
985 Arg( const T &v, const Bu::Fmt &f ) :
986 value( v ),
987 format( f )
988 {
989 }
990
991 Bu::Variant value;
992 Bu::Fmt format;
993 };
994 typedef Bu::List<Arg> ArgList;
995 ArgList lArgs;
996 };
997
998 public:
999 template<typename ArgType>
1000 FormatProxy arg( const ArgType &x )
1001 {
1002 return FormatProxy( *this ).arg( x );
1003 }
1004
1005 template<typename ArgType>
1006 FormatProxy arg( const ArgType &x, const Bu::Fmt &f )
1007 {
1008 return FormatProxy( *this ).arg( x, f );
1009 }
1010 };
1011
1012 template<class T> String operator+( const T *pLeft, const String &rRight )
1013 {
1014 Bu::String ret( pLeft );
1015 ret.append( rRight );
1016 return ret;
1017 }
1018
1019 ArchiveBase &operator<<( ArchiveBase &ar, const String &s );
1020 ArchiveBase &operator>>( ArchiveBase &ar, String &s );
1021
1022 template<typename T>
1023 uint32_t __calcHashCode( const T &k );
1024
1025 template<typename T>
1026 bool __cmpHashKeys( const T &a, const T &b );
1027
1028 template<> uint32_t __calcHashCode<String>( const String &k );
1029 template<> bool __cmpHashKeys<String>(
1030 const String &a, const String &b );
1031
1032 template<typename t> void __tracer_format( const t &v );
1033 template<> void __tracer_format<String>( const String &v );
1034
1035 bool &operator<<( bool &dst, const String &sIn );
1036 uint8_t &operator<<( uint8_t &dst, const String &sIn );
1037 int8_t &operator<<( int8_t &dst, const String &sIn );
1038 char &operator<<( char &dst, const String &sIn );
1039 uint16_t &operator<<( uint16_t &dst, const String &sIn );
1040 int16_t &operator<<( int16_t &dst, const String &sIn );
1041 uint32_t &operator<<( uint32_t &dst, const String &sIn );
1042 int32_t &operator<<( int32_t &dst, const String &sIn );
1043 uint64_t &operator<<( uint64_t &dst, const String &sIn );
1044 int64_t &operator<<( int64_t &dst, const String &sIn );
1045 float &operator<<( float &dst, const String &sIn );
1046 double &operator<<( double &dst, const String &sIn );
1047 long double &operator<<( long double &dst, const String &sIn );
1048 Bu::String &operator<<( Bu::String &dst, const String &sIn );
1049
1050 typedef Bu::List<String> StringList;
1051};
1052
1053#endif
diff --git a/src/stable/substream.cpp b/src/stable/substream.cpp
new file mode 100644
index 0000000..c201752
--- /dev/null
+++ b/src/stable/substream.cpp
@@ -0,0 +1,109 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/substream.h"
9
10Bu::SubStream::SubStream( Bu::Stream &rNext, Bu::size iSize ) :
11 Bu::Filter( rNext ),
12 iStart( 0 ),
13 iPos( 0 ),
14 iSize( iSize )
15{
16 iStart = rNext.tell();
17}
18
19Bu::SubStream::~SubStream()
20{
21}
22
23Bu::size Bu::SubStream::read( void *pBuf, Bu::size nBytes )
24{
25 if( (Bu::size)nBytes > iSize-iPos )
26 nBytes = iSize-iPos;
27 nBytes = rNext.read( pBuf, nBytes );
28 iPos += nBytes;
29 return nBytes;
30}
31
32Bu::size Bu::SubStream::write( const void *pBuf, Bu::size nBytes )
33{
34 if( (Bu::size)nBytes > iSize-iPos )
35 nBytes = iSize-iPos;
36 nBytes = rNext.write( pBuf, nBytes );
37 iPos += nBytes;
38 return nBytes;
39}
40
41void Bu::SubStream::start()
42{
43 // doesn't mean anything...
44}
45
46Bu::size Bu::SubStream::stop()
47{
48 // doesn't mean anything...
49 return 0;
50}
51
52void Bu::SubStream::close()
53{
54 // don't do anything? maybe...
55}
56
57Bu::size Bu::SubStream::tell()
58{
59 return iPos;
60}
61
62void Bu::SubStream::seek( Bu::size offset )
63{
64 if( iPos+offset < 0 )
65 offset = -iPos;
66 else if( iPos+offset > iSize )
67 offset = iSize-iPos;
68 rNext.seek( offset );
69 iPos += offset;
70}
71
72void Bu::SubStream::setPos( Bu::size pos )
73{
74 if( pos < 0 )
75 pos = 0;
76 else if( pos > iSize )
77 pos = iSize;
78 iPos = pos;
79 pos += iStart;
80 rNext.setPos( pos );
81}
82
83void Bu::SubStream::setPosEnd( Bu::size pos )
84{
85 if( iSize-pos < 0 )
86 pos = 0;
87 else if( iSize-pos > iSize )
88 pos = iSize;
89 else
90 pos = iSize-pos;
91 iPos = pos;
92 rNext.setPos( iStart+pos );
93}
94
95bool Bu::SubStream::isEos()
96{
97 return rNext.isEos() || iPos == iSize;
98}
99
100bool Bu::SubStream::canRead()
101{
102 return rNext.canRead() && (iPos < iSize);
103}
104
105bool Bu::SubStream::canWrite()
106{
107 return rNext.canWrite() && (iPos < iSize);
108}
109
diff --git a/src/stable/substream.h b/src/stable/substream.h
new file mode 100644
index 0000000..1db4d6c
--- /dev/null
+++ b/src/stable/substream.h
@@ -0,0 +1,63 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SUB_STREAM_H
9#define BU_SUB_STREAM_H
10
11#include "bu/filter.h"
12
13namespace Bu
14{
15 /**
16 * Creates a sub-stream of a given stream. This allows you to read and
17 * write safely to a section of another stream, keeping all data within
18 * the given bounds. The substream acts exactly like a top level stream
19 * when you reach the bounds of either the containing stream or the
20 * artificial bounds of the substream, except that unlike many stream types,
21 * when writing you cannot move beyond the bounds of the substream. Reads,
22 * on the other hand, work exactly the same way, returning less data than
23 * requested when the end of the stream is reached.
24 *
25 * The substream always begins at the current position in the base stream,
26 * if you would like to skip some data first, simply seek.
27 *
28 * The substream class is safe to use with all blocking and non-blocking
29 * base streams, including sockets, however it can have unpredictable
30 * results when used on a buffering stream that may read more data than
31 * requested in order to complete a request such as the buffer or bzip2
32 * filters.
33 */
34 class SubStream : public Bu::Filter
35 {
36 public:
37 SubStream( Bu::Stream &rNext, Bu::size iSize );
38 virtual ~SubStream();
39
40 virtual Bu::size read( void *pBuf, Bu::size nBytes );
41 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
42 using Bu::Stream::write;
43
44 virtual void start();
45 virtual Bu::size stop();
46 virtual void close();
47 virtual Bu::size tell();
48 virtual void seek( Bu::size offset );
49 virtual void setPos( Bu::size pos );
50 virtual void setPosEnd( Bu::size pos );
51 virtual bool isEos();
52
53 virtual bool canRead();
54 virtual bool canWrite();
55
56 protected:
57 Bu::size iStart;
58 Bu::size iPos;
59 Bu::size iSize;
60 };
61};
62
63#endif
diff --git a/src/stable/synchroatom.h b/src/stable/synchroatom.h
new file mode 100644
index 0000000..fb02054
--- /dev/null
+++ b/src/stable/synchroatom.h
@@ -0,0 +1,63 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SYNCHRO_ATOM_H
9#define BU_SYNCHRO_ATOM_H
10
11#include <pthread.h>
12
13#include "bu/mutex.h"
14
15namespace Bu
16{
17 /**
18 * A thread-safe wrapper class.
19 *@ingroup Threading
20 */
21 template <class T>
22 class SynchroAtom
23 {
24 public:
25 /**
26 * Construct an empty queue.
27 */
28 SynchroAtom()
29 {
30 }
31
32 SynchroAtom( const T &src ) :
33 data( src )
34 {
35 }
36
37 ~SynchroAtom()
38 {
39 }
40
41 T get()
42 {
43 mOperate.lock();
44 T ret = data;
45 mOperate.unlock();
46 return ret;
47 }
48
49 void set( const T &val )
50 {
51 mOperate.lock();
52 data = val;
53 mOperate.unlock();
54 }
55
56 private:
57 T data;
58
59 Mutex mOperate; /**< The master mutex, used on all operations. */
60 };
61};
62
63#endif
diff --git a/src/stable/synchrocounter.cpp b/src/stable/synchrocounter.cpp
new file mode 100644
index 0000000..48bbe21
--- /dev/null
+++ b/src/stable/synchrocounter.cpp
@@ -0,0 +1,8 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/synchrocounter.h"
diff --git a/src/stable/synchrocounter.h b/src/stable/synchrocounter.h
new file mode 100644
index 0000000..d201bee
--- /dev/null
+++ b/src/stable/synchrocounter.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SYNCHRO_COUNTER_H
9#define BU_SYNCHRO_COUNTER_H
10
11#include "bu/mutex.h"
12
13namespace Bu
14{
15 /**
16 * A simple thread-safe counter class. This is handy for assigning unique
17 * IDs to objects that are being created in different threads.
18 *@ingroup Threading Containers
19 */
20 template <class T>
21 class SynchroCounter
22 {
23 public:
24 SynchroCounter() :
25 tCounter( 0 )
26 {
27 }
28
29 virtual ~SynchroCounter()
30 {
31 }
32
33 T next()
34 {
35 mOperate.lock();
36 T tRet = tCounter;
37 tCounter++;
38 mOperate.unlock();
39
40 return tRet;
41 }
42
43 private:
44 T tCounter; /**< The counter itself. */
45 Mutex mOperate; /**< The master mutex, used on all operations. */
46 };
47}
48
49#endif
diff --git a/src/stable/synchroheap.cpp b/src/stable/synchroheap.cpp
new file mode 100644
index 0000000..5dcce33
--- /dev/null
+++ b/src/stable/synchroheap.cpp
@@ -0,0 +1,9 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/synchroheap.h"
9
diff --git a/src/stable/synchroheap.h b/src/stable/synchroheap.h
new file mode 100644
index 0000000..4dd898d
--- /dev/null
+++ b/src/stable/synchroheap.h
@@ -0,0 +1,151 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SYNCHRO_HEAP_H
9#define BU_SYNCHRO_HEAP_H
10
11#include "bu/heap.h"
12#include "bu/mutex.h"
13#include "bu/condition.h"
14
15namespace Bu
16{
17 template<typename item, typename cmpfunc=__basicLTCmp<item>,
18 typename itemalloc=std::allocator<item> >
19 class SynchroHeap
20 {
21 public:
22 SynchroHeap()
23 {
24 }
25
26 virtual ~SynchroHeap()
27 {
28 }
29
30 void enqueue( item i )
31 {
32 imData.lock();
33 hData.enqueue( i );
34 icBlock.signal();
35 imData.unlock();
36 }
37
38 item dequeue( bool bBlock=false )
39 {
40 imData.lock();
41 if( hData.isEmpty() )
42 {
43 imData.unlock();
44
45 if( bBlock )
46 {
47 icBlock.lock();
48
49 while( hData.isEmpty() )
50 icBlock.wait();
51
52 imData.lock();
53 try
54 {
55 item iRet = hData.dequeue();
56 imData.unlock();
57 icBlock.unlock();
58 return iRet;
59 }
60 catch(...)
61 {
62 imData.unlock();
63 icBlock.unlock();
64 throw;
65 }
66 }
67 throw HeapException("Heap empty.");
68 }
69 else
70 {
71 try
72 {
73 item iRet = hData.dequeue();
74 imData.unlock();
75 return iRet;
76 }
77 catch(...)
78 {
79 imData.unlock();
80 throw;
81 }
82 }
83 }
84
85 item dequeue( int iSec, int iUSec )
86 {
87 imData.lock();
88 if( hData.isEmpty() )
89 {
90 imData.unlock();
91
92 icBlock.lock();
93
94 icBlock.wait( iSec, iUSec );
95
96 imData.lock();
97 try
98 {
99 item iRet = hData.dequeue();
100 imData.unlock();
101 icBlock.unlock();
102 return iRet;
103 }
104 catch(...)
105 {
106 imData.unlock();
107 icBlock.unlock();
108 throw;
109 }
110 }
111 else
112 {
113 try
114 {
115 item iRet = hData.dequeue();
116 imData.unlock();
117 return iRet;
118 }
119 catch(...)
120 {
121 imData.unlock();
122 throw;
123 }
124 }
125 }
126
127 bool isEmpty()
128 {
129 imData.lock();
130 bool bRet = hData.isEmpty();
131 imData.unlock();
132 return bRet;
133 }
134
135 int getSize()
136 {
137 imData.lock();
138 int iRet = hData.getSize();
139 imData.unlock();
140 return iRet;
141 }
142
143 private:
144 Heap< item, cmpfunc, itemalloc > hData;
145 Mutex imData;
146 Condition icBlock;
147 };
148};
149
150#endif
151
diff --git a/src/stable/synchroqueue.h b/src/stable/synchroqueue.h
new file mode 100644
index 0000000..79d5e49
--- /dev/null
+++ b/src/stable/synchroqueue.h
@@ -0,0 +1,240 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SYNCHRO_QUEUE_H
9#define BU_SYNCHRO_QUEUE_H
10
11#include <pthread.h>
12
13#include "bu/mutex.h"
14#include "bu/condition.h"
15
16namespace Bu
17{
18 /**
19 * A thread-safe queue class. This class is a very simple queue with some
20 * cool extra functionality for use with the Synchro system. The main extra
21 * that it provides is the option to either dequeue without blocking, with
22 * infinite blocking, or with timed blocking, which will return a value if
23 * something is enqueued within the specified time limit, or NULL if the
24 * time limit is exceded.
25 *@ingroup Threading Containers
26 */
27 template <class T>
28 class SynchroQueue
29 {
30 private:
31 /**
32 * Helper struct. Keeps track of linked-list items for the queue data.
33 */
34 typedef struct Item
35 {
36 T pData;
37 Item *pNext;
38 } Item;
39
40 public:
41 /**
42 * Construct an empty queue.
43 */
44 SynchroQueue() :
45 pStart( NULL ),
46 pEnd( NULL ),
47 nSize( 0 )
48 {
49 }
50
51 /**
52 * Destroy the queue. This function will simply free all contained
53 * structures. If you stored pointers in the queue, this will lose the
54 * pointers without cleaning up the memory they pointed to. Make sure
55 * you're queue is empty before allowing it to be destroyed!
56 */
57 ~SynchroQueue()
58 {
59 Item *pCur = pStart;
60 while( pCur )
61 {
62 Item *pTmp = pCur->pNext;
63 delete pCur;
64 pCur = pTmp;
65 }
66 }
67
68 /**
69 * Enqueue a pieces of data. The new data will go at the end of the
70 * queue, and unless another piece of data is enqueued, will be the
71 * last piece of data to be dequeued.
72 *@param pData The data to enqueue. If this is not a primitive data
73 * type it's probably best to use a pointer type.
74 */
75 void enqueue( T pData )
76 {
77 mOperate.lock();
78
79 if( pStart == NULL )
80 {
81 pStart = pEnd = new Item;
82 pStart->pData = pData;
83 pStart->pNext = NULL;
84 nSize++;
85 }
86 else
87 {
88 pEnd->pNext = new Item;
89 pEnd = pEnd->pNext;
90 pEnd->pData = pData;
91 pEnd->pNext = NULL;
92 nSize++;
93 }
94
95 cBlock.signal();
96
97 mOperate.unlock();
98 }
99
100 /**
101 * Dequeue the first item from the queue. This function can operate in
102 * two different modes, blocking and non-blocking. In non-blocking
103 * mode it will return immediately weather there was data in the queue
104 * or not. If there was data it will remove it from the queue and
105 * return it to the caller.
106 *
107 * In blocking mode it will block forever wating for data to be
108 * enqueued. When data finally is enqueued this function will return
109 * immediately with the new data. The only way this function should
110 * ever return a null in blocking mode is if the calling thread was
111 * cancelled. It's probably a good idea to check for NULL return
112 * values even if you use blocking, just to be on the safe side.
113 *@param bBlock Set to true to enable blocking, leave as false to work
114 * in non-blocking mode.
115 *@returns The next piece of data in the queue, or NULL if no data was
116 * in the queue.
117 */
118 T dequeue( bool bBlock=false )
119 {
120 mOperate.lock();
121 if( pStart == NULL )
122 {
123 mOperate.unlock();
124
125 if( bBlock )
126 {
127 cBlock.lock();
128
129 while( pStart == NULL )
130 cBlock.wait();
131
132 T tmp = dequeue( false );
133
134 cBlock.unlock();
135 return tmp;
136
137 }
138
139 return NULL;
140 }
141 else
142 {
143 T pTmp = pStart->pData;
144 Item *pDel = pStart;
145 pStart = pStart->pNext;
146 delete pDel;
147 nSize--;
148
149 mOperate.unlock();
150 return pTmp;
151 }
152 }
153
154 /**
155 * Operates just like the other dequeue function in blocking mode with
156 * one twist. This function will block for at most nSec seconds and
157 * nUSec micro-seconds. If the timer is up and no data is available,
158 * this will just return NULL. If data is enqueued before the timeout
159 * expires, it will dequeue and exit immediately.
160 *@param nSec The number of seconds to wait, max.
161 *@param nUSec The number of micro-seconds to wait, max.
162 *@returns The next piece of data in the queue, or NULL if the timeout
163 * was exceeded.
164 */
165 T dequeue( int nSec, int nUSec )
166 {
167 mOperate.lock();
168 if( pStart == NULL )
169 {
170 mOperate.unlock();
171
172 cBlock.lock();
173
174 cBlock.wait( nSec, nUSec );
175
176 if( pStart == NULL )
177 {
178 cBlock.unlock();
179 return NULL;
180 }
181
182 mOperate.lock();
183 T pTmp = pStart->pData;
184 Item *pDel = pStart;
185 pStart = pStart->pNext;
186 delete pDel;
187 nSize--;
188 mOperate.unlock();
189
190 cBlock.unlock();
191 return pTmp;
192 }
193 else
194 {
195 T pTmp = pStart->pData;
196 Item *pDel = pStart;
197 pStart = pStart->pNext;
198 delete pDel;
199 nSize--;
200
201 mOperate.unlock();
202 return pTmp;
203 }
204 }
205
206 /**
207 * Checks to see if the queue has data in it or not. Note that there
208 * is no function to determine the length of the queue. This data
209 * isn't kept track of. If you really need to know, fix this.
210 *@returns True if the queue is empty, false if it has data in it.
211 */
212 bool isEmpty()
213 {
214 mOperate.lock();
215 bool bEmpty = (pStart == NULL );
216 mOperate.unlock();
217
218 return bEmpty;
219 }
220
221 long getSize()
222 {
223 mOperate.lock();
224 long nRet = nSize;
225 mOperate.unlock();
226
227 return nRet;
228 }
229
230 private:
231 Item *pStart; /**< The start of the queue, the next element to dequeue. */
232 Item *pEnd; /**< The end of the queue, the last element to dequeue. */
233 long nSize; /**< The number of items in the queue. */
234
235 Mutex mOperate; /**< The master mutex, used on all operations. */
236 Condition cBlock; /**< The condition for blocking dequeues. */
237 };
238}
239
240#endif
diff --git a/src/stable/taf.h b/src/stable/taf.h
new file mode 100644
index 0000000..951f80f
--- /dev/null
+++ b/src/stable/taf.h
@@ -0,0 +1,18 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8//
9// There's no protection on this file, it just includes other files.
10//
11
12#include "bu/tafnode.h"
13#include "bu/tafgroup.h"
14#include "bu/tafproperty.h"
15#include "bu/tafcomment.h"
16#include "bu/tafreader.h"
17#include "bu/tafwriter.h"
18
diff --git a/src/stable/tafcomment.cpp b/src/stable/tafcomment.cpp
new file mode 100644
index 0000000..c7096ca
--- /dev/null
+++ b/src/stable/tafcomment.cpp
@@ -0,0 +1,37 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/tafcomment.h"
9
10Bu::TafComment::TafComment( const Bu::TafComment &rSrc ) :
11 TafNode( typeComment ),
12 sText( rSrc.sText ),
13 bEOL( rSrc.bEOL )
14{
15}
16
17Bu::TafComment::TafComment( const Bu::String &sText, bool bEOL ) :
18 TafNode( typeComment ),
19 sText( sText ),
20 bEOL( bEOL )
21{
22}
23
24Bu::TafComment::~TafComment()
25{
26}
27
28const Bu::String &Bu::TafComment::getText() const
29{
30 return sText;
31}
32
33bool Bu::TafComment::isEOLStyle() const
34{
35 return bEOL;
36}
37
diff --git a/src/stable/tafcomment.h b/src/stable/tafcomment.h
new file mode 100644
index 0000000..4efd548
--- /dev/null
+++ b/src/stable/tafcomment.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_TAF_COMMENT_H
9#define BU_TAF_COMMENT_H
10
11#include <stdint.h>
12#include "bu/tafnode.h"
13
14namespace Bu
15{
16 /**
17 *
18 *@ingroup Taf
19 */
20 class TafComment : public TafNode
21 {
22 public:
23 TafComment( const Bu::TafComment &rSrc );
24 TafComment( const Bu::String &sText, bool bEOL=false );
25 virtual ~TafComment();
26
27 const Bu::String &getText() const;
28 bool isEOLStyle() const;
29
30 private:
31 Bu::String sText;
32 bool bEOL;
33 };
34}
35
36#endif
diff --git a/src/stable/tafgroup.cpp b/src/stable/tafgroup.cpp
new file mode 100644
index 0000000..ee180c3
--- /dev/null
+++ b/src/stable/tafgroup.cpp
@@ -0,0 +1,224 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/tafgroup.h"
9#include "bu/tafproperty.h"
10#include "bu/tafcomment.h"
11
12Bu::TafGroup::TafGroup( const TafGroup &rSrc ) :
13 TafNode( typeGroup ),
14 sName( rSrc.sName )
15{
16 for( NodeList::const_iterator i = rSrc.lChildren.begin(); i; i++ )
17 {
18 switch( (*i)->getType() )
19 {
20 case typeGroup:
21 addChild( new TafGroup( *dynamic_cast<const TafGroup *>(*i) ) );
22 break;
23
24 case typeProperty:
25 addChild( new TafProperty( *dynamic_cast<const TafProperty *>(*i) ) );
26 break;
27
28 case typeComment:
29 addChild( new TafComment( *dynamic_cast<const TafComment *>(*i) ) );
30 break;
31 }
32 }
33}
34
35Bu::TafGroup::TafGroup( const Bu::String &sName ) :
36 TafNode( typeGroup ),
37 sName( sName )
38{
39}
40
41Bu::TafGroup::~TafGroup()
42{
43 for( NodeList::iterator i = lChildren.begin(); i != lChildren.end(); i++ )
44 {
45 delete (*i);
46 }
47}
48
49const Bu::String &Bu::TafGroup::getName() const
50{
51 return sName;
52}
53
54void Bu::TafGroup::setName( const Bu::String &sName )
55{
56 this->sName = sName;
57}
58
59Bu::TafNode *Bu::TafGroup::addChild( Bu::TafNode *pNode )
60{
61 switch( pNode->getType() )
62 {
63 case typeGroup:
64 addChild( (Bu::TafGroup *)pNode );
65 break;
66
67 case typeProperty:
68 addChild( (Bu::TafProperty *)pNode );
69 break;
70
71 case typeComment:
72 addChild( (Bu::TafComment *)pNode );
73 break;
74 }
75
76 return pNode;
77}
78
79Bu::TafGroup *Bu::TafGroup::addChild( TafGroup *pNode )
80{
81 TafGroup *pGroup = (TafGroup *)pNode;
82 if( !hChildren.has( pGroup->getName() ) )
83 hChildren.insert( pGroup->getName(), GroupList() );
84 hChildren.get( pGroup->getName() ).append( pGroup );
85 lChildren.append( pNode );
86 return pNode;
87}
88
89Bu::TafProperty *Bu::TafGroup::addChild( TafProperty *pNode )
90{
91 TafProperty *pProperty = (TafProperty *)pNode;
92 if( !hProp.has( pProperty->getName() ) )
93 hProp.insert( pProperty->getName(), PropList() );
94 hProp.get( pProperty->getName() ).append( pProperty->getValue() );
95 lChildren.append( pNode );
96 return pNode;
97}
98
99Bu::TafComment *Bu::TafGroup::addChild( TafComment *pNode )
100{
101 lChildren.append( pNode );
102 return pNode;
103}
104
105Bu::TafGroup *Bu::TafGroup::addGroup( const Bu::String &sName )
106{
107 return addChild( new TafGroup( sName ) );
108}
109
110Bu::TafProperty *Bu::TafGroup::addProperty(
111 const Bu::String &sName, const Bu::String &sValue )
112{
113 return addChild( new TafProperty( sName, sValue ) );
114}
115
116bool Bu::TafGroup::hasChild( const Bu::String &sName ) const
117{
118 return hChildren.has( sName );
119}
120
121const Bu::TafGroup::GroupList &Bu::TafGroup::getChildren( const Bu::String &sName ) const
122{
123 try {
124 return hChildren.get( sName );
125 } catch( Bu::HashException &e )
126 {
127 throw Bu::TafException("No children of group \"%s\" match \"%s\".",
128 this->sName.getStr(), sName.getStr() );
129 }
130}
131
132const Bu::TafGroup::NodeList &Bu::TafGroup::getChildren() const
133{
134 return lChildren;
135}
136
137const Bu::TafGroup *Bu::TafGroup::getChild( const Bu::String &sName ) const
138{
139 try {
140 return hChildren.get( sName ).first();
141 } catch( Bu::HashException &e )
142 {
143 throw Bu::TafException("No children of group \"%s\" match \"%s\".",
144 this->sName.getStr(), sName.getStr() );
145 }
146}
147
148bool Bu::TafGroup::hasProperty( const Bu::String &sName ) const
149{
150 return hProp.has( sName );
151}
152
153const Bu::TafGroup::PropList &Bu::TafGroup::getProperties( const Bu::String &sName ) const
154{
155 try {
156 return hProp.get( sName );
157 } catch( Bu::HashException &e )
158 {
159 throw Bu::TafException("No properties of group \"%s\" match \"%s\".",
160 this->sName.getStr(), sName.getStr() );
161 }
162}
163
164const Bu::String &Bu::TafGroup::getProperty( const Bu::String &sName ) const
165{
166 try {
167 return hProp.get( sName ).first();
168 } catch( Bu::HashException &e )
169 {
170 throw Bu::TafException("No properties of group \"%s\" match \"%s\".",
171 this->sName.getStr(), sName.getStr() );
172 }
173}
174
175const Bu::String &Bu::TafGroup::getProperty( const Bu::String &sName,
176 const Bu::String &sDef ) const
177{
178 try
179 {
180 return hProp.get( sName ).first();
181 }
182 catch( Bu::HashException &e )
183 {
184 return sDef;
185 }
186}
187
188const Bu::TafGroup *Bu::TafGroup::getChildByPath(
189 const Bu::String &sPath ) const
190{
191 return getChildByPath( sPath.split('/') );
192}
193
194const Bu::TafGroup *Bu::TafGroup::getChildByPath( Bu::StrList lPath ) const
195{
196 const Bu::TafGroup *cur = this;
197
198 for( Bu::StrList::const_iterator i = lPath.begin(); i; i++ )
199 {
200 cur = cur->getChild( *i );
201 }
202
203 return cur;
204}
205
206const Bu::String &Bu::TafGroup::getByPath( const Bu::String &sPath ) const
207{
208 return getByPath( sPath.split('/') );
209}
210
211const Bu::String &Bu::TafGroup::getByPath( Bu::StrList lPath ) const
212{
213 const Bu::TafGroup *cur = this;
214
215 for( Bu::StrList::const_iterator i = lPath.begin(); i; i++ )
216 {
217 if( !(i+1) )
218 break;
219 cur = cur->getChild( *i );
220 }
221
222 return cur->getProperty( lPath.last() );
223}
224
diff --git a/src/stable/tafgroup.h b/src/stable/tafgroup.h
new file mode 100644
index 0000000..119e827
--- /dev/null
+++ b/src/stable/tafgroup.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_TAF_GROUP_H
9#define BU_TAF_GROUP_H
10
11#include <stdint.h>
12#include "bu/tafnode.h"
13#include "bu/string.h"
14#include "bu/hash.h"
15#include "bu/list.h"
16
17namespace Bu
18{
19 typedef Bu::List<Bu::String> StrList;
20 class TafProperty;
21 class TafComment;
22 /**
23 *
24 *@ingroup Taf
25 */
26 class TafGroup : public TafNode
27 {
28 public:
29 typedef Bu::List<Bu::String> PropList;
30 typedef Bu::Hash<Bu::String, PropList> PropHash;
31 typedef Bu::List<class Bu::TafGroup *> GroupList;
32 typedef Bu::Hash<Bu::String, GroupList> GroupHash;
33 typedef Bu::List<class Bu::TafNode *> NodeList;
34
35 TafGroup( const TafGroup &rSrc );
36 TafGroup( const Bu::String &sName );
37 virtual ~TafGroup();
38
39 const Bu::String &getName() const;
40 void setName( const Bu::String &sName );
41
42 bool hasProperty( const Bu::String &sName ) const;
43 const Bu::String &getProperty( const Bu::String &sName ) const;
44 const Bu::String &getProperty( const Bu::String &sName,
45 const Bu::String &sDef ) const;
46 const PropList &getProperties( const Bu::String &sName ) const;
47 bool hasChild( const Bu::String &sName ) const;
48 const TafGroup *getChild( const Bu::String &sName ) const;
49 const GroupList &getChildren( const Bu::String &sName ) const;
50 TafNode *addChild( TafNode *pNode );
51 TafGroup *addChild( TafGroup *pNode );
52 TafProperty *addChild( TafProperty *pNode );
53 TafComment *addChild( TafComment *pNode );
54 TafGroup *addGroup( const Bu::String &sName );
55 TafProperty *addProperty(
56 const Bu::String &sName, const Bu::String &sValue );
57 const NodeList &getChildren() const;
58 const TafGroup *getChildByPath( const Bu::String &sPath ) const;
59 const TafGroup *getChildByPath( StrList lPath ) const;
60 const Bu::String &getByPath( const Bu::String &sPath ) const;
61 const Bu::String &getByPath( StrList lPath ) const;
62
63 private:
64 Bu::String sName;
65 PropHash hProp;
66 GroupHash hChildren;
67 NodeList lChildren;
68 };
69}
70
71#endif
diff --git a/src/stable/tafnode.cpp b/src/stable/tafnode.cpp
new file mode 100644
index 0000000..0757a46
--- /dev/null
+++ b/src/stable/tafnode.cpp
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/tafnode.h"
9
10namespace Bu { subExceptionDef( TafException ) }
11
12Bu::TafNode::TafNode( NodeType eType ) :
13 eType( eType )
14{
15}
16
17Bu::TafNode::~TafNode()
18{
19}
20
21Bu::TafNode::NodeType Bu::TafNode::getType() const
22{
23 return eType;
24}
25
diff --git a/src/stable/tafnode.h b/src/stable/tafnode.h
new file mode 100644
index 0000000..d7a9159
--- /dev/null
+++ b/src/stable/tafnode.h
@@ -0,0 +1,44 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_TAF_NODE_H
9#define BU_TAF_NODE_H
10
11#include <stdint.h>
12#include "bu/string.h"
13#include "bu/hash.h"
14#include "bu/exceptionbase.h"
15
16namespace Bu
17{
18 subExceptionDecl( TafException );
19 /**
20 *
21 *@ingroup Taf
22 */
23 class TafNode
24 {
25 public:
26 enum NodeType
27 {
28 typeGroup,
29 typeProperty,
30 typeComment
31 };
32
33 public:
34 TafNode( NodeType eType );
35 virtual ~TafNode();
36
37 NodeType getType() const;
38
39 private:
40 NodeType eType;
41 };
42}
43
44#endif
diff --git a/src/stable/tafproperty.cpp b/src/stable/tafproperty.cpp
new file mode 100644
index 0000000..4ef5c24
--- /dev/null
+++ b/src/stable/tafproperty.cpp
@@ -0,0 +1,37 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/tafproperty.h"
9
10Bu::TafProperty::TafProperty( const Bu::TafProperty &rSrc ) :
11 TafNode( typeProperty ),
12 sName( rSrc.sName ),
13 sValue( rSrc.sValue )
14{
15}
16
17Bu::TafProperty::TafProperty( const Bu::String &sName, const Bu::String &sValue ) :
18 TafNode( typeProperty ),
19 sName( sName ),
20 sValue( sValue )
21{
22}
23
24Bu::TafProperty::~TafProperty()
25{
26}
27
28const Bu::String &Bu::TafProperty::getName() const
29{
30 return sName;
31}
32
33const Bu::String &Bu::TafProperty::getValue() const
34{
35 return sValue;
36}
37
diff --git a/src/stable/tafproperty.h b/src/stable/tafproperty.h
new file mode 100644
index 0000000..7091de5
--- /dev/null
+++ b/src/stable/tafproperty.h
@@ -0,0 +1,36 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_TAF_PROPERTY_H
9#define BU_TAF_PROPERTY_H
10
11#include <stdint.h>
12#include "bu/tafnode.h"
13
14namespace Bu
15{
16 /**
17 *
18 *@ingroup Taf
19 */
20 class TafProperty : public TafNode
21 {
22 public:
23 TafProperty( const Bu::TafProperty &rSrc );
24 TafProperty( const Bu::String &sName, const Bu::String &sValue );
25 virtual ~TafProperty();
26
27 const Bu::String &getName() const;
28 const Bu::String &getValue() const;
29
30 private:
31 Bu::String sName;
32 Bu::String sValue;
33 };
34}
35
36#endif
diff --git a/src/stable/tafreader.cpp b/src/stable/tafreader.cpp
new file mode 100644
index 0000000..6708c8c
--- /dev/null
+++ b/src/stable/tafreader.cpp
@@ -0,0 +1,252 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/taf.h"
9#include "bu/string.h"
10#include "bu/stream.h"
11
12#include <stdlib.h>
13
14using namespace Bu;
15
16Bu::TafReader::TafReader( Bu::Stream &sIn ) :
17 c( 0 ),
18 la( 0 ),
19 sIn( sIn ),
20 iLine( 1 ), iCol( -1 )
21{
22 next(); next();
23}
24
25Bu::TafReader::~TafReader()
26{
27
28}
29
30Bu::TafGroup *Bu::TafReader::readGroup()
31{
32 ws();
33 if( c != '{' )
34 throw TafException("%d:%d: Expected '{' got '%c'.", iLine, iCol, c );
35 next();
36 ws();
37 String sName = readStr();
38 TafGroup *pGroup = new TafGroup( sName );
39 try
40 {
41 ws();
42 if( c != ':' )
43 throw TafException("%d:%d: Expected ':' got '%c'.",
44 iLine, iCol, c );
45 next();
46 //printf("Node[%s]:\n", sName.getStr() );
47
48 groupContent( pGroup );
49
50 if( c != '}' )
51 throw TafException("%d:%d: Expected '}' got '%c'.",
52 iLine, iCol, c );
53
54 //next();
55
56 return pGroup;
57 }
58 catch(...)
59 {
60 delete pGroup;
61 throw;
62 }
63}
64
65void Bu::TafReader::groupContent( Bu::TafGroup *pGroup )
66{
67 for(;;)
68 {
69 ws();
70 if( c == '{' )
71 {
72 pGroup->addChild( readGroup() );
73 next();
74 }
75 else if( c == '}' )
76 return;
77 else if( c == '/' && la == '*' )
78 pGroup->addChild( readComment() );
79 else if( c == '/' && la == '/' )
80 pGroup->addChild( readComment( true ) );
81 else if( c == ':' )
82 throw TafException("%d:%d: Encountered stray ':' in taf stream.",
83 iLine, iCol );
84 else
85 pGroup->addChild( readProperty() );
86 }
87}
88
89Bu::TafProperty *Bu::TafReader::readProperty()
90{
91 String sName = readStr();
92 ws();
93 if( c != '=' )
94 {
95 //printf(" %s (true)\n", sName.getStr() );
96 return new Bu::TafProperty( "", sName );
97 }
98 next();
99 String sValue = readStr();
100 return new Bu::TafProperty( sName, sValue );
101 //printf(" %s = %s\n", sName.getStr(), sValue.getStr() );
102}
103
104Bu::TafComment *Bu::TafReader::readComment( bool bEOL )
105{
106 String sCmnt;
107 next();
108 if( bEOL )
109 {
110 for(;;)
111 {
112 next();
113 if( c == '\n' && la == '\r' )
114 {
115 next(); next();
116 break;
117 }
118 else if( c == '\n' || c == '\r' )
119 {
120 next();
121 break;
122 }
123 sCmnt += c;
124 }
125 }
126 else
127 {
128 for(;;)
129 {
130 next();
131 if( c == '*' && la == '/' )
132 {
133 next(); next();
134 break;
135 }
136 sCmnt += c;
137 }
138 }
139
140 return new TafComment( sCmnt, bEOL );
141}
142
143Bu::String Bu::TafReader::readStr()
144{
145 ws();
146 String s;
147 if( c == '"' )
148 {
149 next();
150 for(;;)
151 {
152 if( c == '\\' )
153 {
154 next();
155 if( c == 'x' )
156 {
157 char code[3]={'\0','\0','\0'};
158 next();
159 code[0] = c;
160 next();
161 code[1] = c;
162 c = (unsigned char)strtol( code, NULL, 16 );
163 }
164 else if( c == '"' )
165 c = '"';
166 else if( c == '\\' )
167 c = '\\';
168 else if( c == 'n' )
169 c = '\n';
170 else if( c == 't' )
171 c = '\t';
172 else
173 throw TafException("%d:%d: Invalid escape sequence '\\%c'.",
174 iLine, iCol, c );
175 }
176 else if( c == '"' )
177 break;
178 s += c;
179 next();
180 }
181 next();
182 }
183 else
184 {
185 for(;;)
186 {
187 if( isws() || c == '}' || c == '{' || c == ':' || c == '=' )
188 break;
189 s += c;
190 next();
191 }
192 }
193
194 return s;
195}
196
197void Bu::TafReader::ws()
198{
199 for(;;)
200 {
201 if( !isws() )
202 return;
203
204 next();
205 }
206}
207
208bool Bu::TafReader::isws()
209{
210 return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
211}
212
213void Bu::TafReader::next()
214{
215 if( c == '\n' )
216 {
217 iLine++;
218 iCol = 1;
219 }
220 else
221 iCol++;
222 if( c == '}' )
223 {
224 rawread( &c );
225 if( c != '}' )
226 rawread( &la );
227 }
228 else
229 {
230 c = la;
231 if( c != '}' )
232 rawread( &la );
233 }
234}
235
236void Bu::TafReader::rawread( char *c )
237{
238 if( sIn.read( c, 1 ) < 1 )
239 {
240 if( sIn.isEos() )
241 {
242 throw TafException("%d:%d: Premature end of stream.",
243 iLine, iCol, c );
244 }
245 else
246 {
247 throw TafException("%d:%d: No data read, but not end of stream?",
248 iLine, iCol, c );
249 }
250 }
251}
252
diff --git a/src/stable/tafreader.h b/src/stable/tafreader.h
new file mode 100644
index 0000000..10ebfc0
--- /dev/null
+++ b/src/stable/tafreader.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_TAF_READER_H
9#define BU_TAF_READER_H
10
11#include <stdint.h>
12#include "bu/string.h"
13
14namespace Bu
15{
16 class TafNode;
17 class TafGroup;
18 class TafProperty;
19 class TafComment;
20 class Stream;
21
22 /**
23 *
24 *@ingroup Taf
25 */
26 class TafReader
27 {
28 public:
29 TafReader( Bu::Stream &sIn );
30 virtual ~TafReader();
31
32 Bu::TafGroup *readGroup();
33
34 private:
35 void groupContent( Bu::TafGroup *pNode );
36 Bu::TafProperty *readProperty();
37 Bu::TafComment *readComment( bool bEOL=false );
38 void ws();
39 bool isws();
40 void next();
41 Bu::String readStr();
42 void rawread( char *c );
43 char c, la;
44 Bu::Stream &sIn;
45 int iLine, iCol;
46 };
47}
48
49#endif
diff --git a/src/stable/tafwriter.cpp b/src/stable/tafwriter.cpp
new file mode 100644
index 0000000..b24bd1e
--- /dev/null
+++ b/src/stable/tafwriter.cpp
@@ -0,0 +1,114 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/taf.h"
9#include "bu/stream.h"
10
11Bu::TafWriter::TafWriter( Bu::Stream &sOut ) :
12 sOut( sOut ),
13 iDepth( 0 )
14{
15}
16
17Bu::TafWriter::~TafWriter()
18{
19}
20
21void Bu::TafWriter::ident()
22{
23 for( int j = 0; j < iDepth; j++ )
24 sOut.write(" ", 4 );
25}
26
27void Bu::TafWriter::writeGroup( const Bu::TafGroup *pRoot )
28{
29 ident();
30 sOut.write("{", 1 );
31 if( pRoot->getName().isSet() )
32 writeString( pRoot->getName() );
33 sOut.write(":\n", 2 );
34 iDepth++;
35 const Bu::TafGroup::NodeList &nl = pRoot->getChildren();
36 for( Bu::TafGroup::NodeList::const_iterator i = nl.begin(); i != nl.end(); i++ )
37 {
38 switch( (*i)->getType() )
39 {
40 case Bu::TafNode::typeGroup:
41 writeGroup( (Bu::TafGroup *)(*i) );
42 break;
43
44 case Bu::TafNode::typeProperty:
45 writeProperty( (Bu::TafProperty *)(*i) );
46 break;
47
48 case Bu::TafNode::typeComment:
49 writeComment( (Bu::TafComment *)(*i) );
50 break;
51 }
52 }
53 iDepth--;
54 ident();
55 sOut.write("}\n", 2 );
56}
57
58void Bu::TafWriter::writeProperty( const Bu::TafProperty *pProp )
59{
60 ident();
61 if( !pProp->getName().isEmpty() )
62 {
63 writeString( pProp->getName() );
64 sOut.write("=", 1 );
65 writeString( pProp->getValue() );
66 }
67 else
68 {
69 writeString( pProp->getValue() );
70 }
71 sOut.write("\n", 1 );
72}
73
74void Bu::TafWriter::writeComment( const Bu::TafComment *pComment )
75{
76 ident();
77 if( pComment->isEOLStyle() )
78 {
79 sOut.write("//", 2 );
80 sOut.write( pComment->getText().getStr(), pComment->getText().getSize() );
81 sOut.write("\n", 1 );
82 }
83 else
84 {
85 sOut.write("/*", 2 );
86 sOut.write( pComment->getText().getStr(), pComment->getText().getSize() );
87 sOut.write("*/ ", 3 );
88 }
89}
90
91void Bu::TafWriter::writeString( const Bu::String &str )
92{
93 sOut.write("\"", 1 );
94 for( Bu::String::const_iterator s = str.begin(); s != str.end(); s++ )
95 {
96 if( *s == '\"' )
97 sOut.write("\\\"", 2 );
98 else if( *s == '\\' )
99 sOut.write("\\\\", 2 );
100 else if( *s < 32 || *s > 126 )
101 {
102 char buf[5];
103 sprintf( buf, "\\x%02X", (unsigned char)*s );
104 sOut.write(buf, 4 );
105 }
106 else
107 {
108 const char buf = *s;
109 sOut.write( &buf, 1 );
110 }
111 }
112 sOut.write("\"", 1 );
113}
114
diff --git a/src/stable/tafwriter.h b/src/stable/tafwriter.h
new file mode 100644
index 0000000..3fd71de
--- /dev/null
+++ b/src/stable/tafwriter.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_TAF_WRITER_H
9#define BU_TAF_WRITER_H
10
11#include <stdint.h>
12
13#include "bu/string.h"
14
15namespace Bu
16{
17 class Stream;
18 class TafNode;
19 class TafGroup;
20 class TafProperty;
21 class TafComment;
22
23 /**
24 *
25 *@ingroup Taf
26 */
27 class TafWriter
28 {
29 public:
30 TafWriter( Bu::Stream &sOut );
31 virtual ~TafWriter();
32
33 void writeGroup( const Bu::TafGroup *pRoot );
34
35 private:
36 void writeProperty( const Bu::TafProperty *pProp );
37 void writeComment( const Bu::TafComment *pComment );
38 void writeString( const Bu::String &str );
39 void ident();
40 Bu::Stream &sOut;
41 int iDepth;
42 };
43}
44
45#endif
diff --git a/src/stable/tcpserversocket.cpp b/src/stable/tcpserversocket.cpp
new file mode 100644
index 0000000..a2fe6b4
--- /dev/null
+++ b/src/stable/tcpserversocket.cpp
@@ -0,0 +1,249 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef WIN32
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <netdb.h>
12 #include <arpa/inet.h>
13#endif
14
15#include <time.h>
16#include <string.h>
17#include <stdio.h>
18#include <errno.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <sys/types.h>
22//#include <termios.h>
23#include <fcntl.h>
24#include "bu/tcpserversocket.h"
25
26#include "bu/config.h"
27
28namespace Bu { subExceptionDef( TcpServerSocketException ) }
29
30Bu::TcpServerSocket::TcpServerSocket( int nPort, int nPoolSize ) :
31 nPort( nPort )
32{
33#ifdef WIN32
34 Bu::Winsock2::getInstance();
35#endif
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 = bu_htons( nPort );
43
44 // I think this specifies who we will accept connections from,
45 // a good thing to make configurable later on
46 name.sin_addr.s_addr = bu_htonl( INADDR_ANY );
47
48 startServer( name, nPoolSize );
49}
50
51Bu::TcpServerSocket::TcpServerSocket(const String &sAddr,int nPort, int nPoolSize) :
52 nPort( nPort )
53{
54#ifdef WIN32
55 Bu::Winsock2::getInstance();
56#endif
57
58 /* Create the socket and set it up to accept connections. */
59 struct sockaddr_in name;
60
61 /* Give the socket a name. */
62 name.sin_family = AF_INET;
63
64 name.sin_port = bu_htons( nPort );
65
66#ifdef WIN32
67 name.sin_addr.s_addr = bu_inet_addr( sAddr.getStr() );
68#else
69 inet_aton( sAddr.getStr(), &name.sin_addr );
70#endif
71
72 startServer( name, nPoolSize );
73}
74
75Bu::TcpServerSocket::TcpServerSocket( int nServer, bool bInit, int nPoolSize ) :
76 nServer( nServer ),
77 nPort( 0 )
78{
79#ifdef WIN32
80 Bu::Winsock2::getInstance();
81#endif
82
83 if( bInit )
84 {
85 struct sockaddr name;
86 socklen_t namelen = sizeof(name);
87 getpeername( nServer, &name, &namelen );
88
89 initServer( *((sockaddr_in *)&name), nPoolSize );
90 }
91 else
92 {
93 FD_ZERO( &fdActive );
94 FD_SET( nServer, &fdActive );
95 }
96}
97
98Bu::TcpServerSocket::TcpServerSocket( const TcpServerSocket &rSrc )
99{
100#ifdef WIN32
101 Bu::Winsock2::getInstance();
102#endif
103
104 nServer = dup( rSrc.nServer );
105 nPort = rSrc.nPort;
106 FD_ZERO( &fdActive );
107 FD_SET( nServer, &fdActive );
108}
109
110Bu::TcpServerSocket::~TcpServerSocket()
111{
112 if( nServer > -1 )
113 ::close( nServer );
114}
115
116void Bu::TcpServerSocket::startServer( struct sockaddr_in &name, int nPoolSize )
117{
118 /* Create the socket. */
119 nServer = bu_socket( PF_INET, SOCK_STREAM, 0 );
120
121 if( nServer < 0 )
122 {
123 throw Bu::TcpServerSocketException("Couldn't create a listen socket.");
124 }
125
126 int opt = 1;
127 bu_setsockopt(
128 nServer,
129 SOL_SOCKET,
130 SO_REUSEADDR,
131 (char *)&opt,
132 sizeof( opt )
133 );
134
135 initServer( name, nPoolSize );
136}
137
138void Bu::TcpServerSocket::initServer( struct sockaddr_in &name, int nPoolSize )
139{
140 if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 )
141 {
142 throw Bu::TcpServerSocketException("Couldn't bind to the listen socket.");
143 }
144
145 if( bu_listen( nServer, nPoolSize ) < 0 )
146 {
147 throw Bu::TcpServerSocketException(
148 "Couldn't begin listening to the server socket."
149 );
150 }
151
152 FD_ZERO( &fdActive );
153 /* Initialize the set of active sockets. */
154 FD_SET( nServer, &fdActive );
155}
156
157int Bu::TcpServerSocket::getSocket()
158{
159 return nServer;
160}
161
162int Bu::TcpServerSocket::accept( int nTimeoutSec, int nTimeoutUSec )
163{
164 fd_set fdRead = fdActive;
165
166 struct timeval xT;
167
168 xT.tv_sec = nTimeoutSec;
169 xT.tv_usec = nTimeoutUSec;
170
171 if( TEMP_FAILURE_RETRY(
172 bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 )
173 {
174 throw Bu::TcpServerSocketException(
175 "Error scanning for new connections: %s", strerror( errno )
176 );
177 }
178
179 if( FD_ISSET( nServer, &fdRead ) )
180 {
181 struct sockaddr_in clientname;
182 socklen_t size;
183 int nClient;
184
185 size = sizeof( clientname );
186#ifdef WIN32
187 nClient = bu_accept( nServer, (struct sockaddr *)&clientname, &size);
188#else /* not-WIN32 */
189#ifdef __CYGWIN__
190 nClient = ::accept( nServer, (struct sockaddr *)&clientname,
191 (int *)&size
192 );
193#else /* not-cygwin */
194#ifdef __APPLE__
195 nClient = ::accept( nServer, (struct sockaddr *)&clientname, (socklen_t*)&size );
196#else /* linux */
197 nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size );
198#endif /* __APPLE__ */
199#endif /* __CYGWIN__ */
200#endif /* WIN32 */
201 if( nClient < 0 )
202 {
203 throw Bu::TcpServerSocketException(
204 "Error accepting a new connection: %s", strerror( errno )
205 );
206 }
207
208#ifndef WIN32
209 char tmpa[20];
210 inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 );
211 //"New connection from host %s, port %hd.",
212 // tmpa, ntohs (clientname.sin_port) );
213#endif
214
215 {
216#ifndef WIN32
217 int flags;
218 flags = fcntl( nClient, F_GETFL, 0 );
219 flags |= O_NONBLOCK;
220 if( fcntl( nClient, F_SETFL, flags ) < 0)
221 {
222 throw Bu::TcpServerSocketException(
223 "Error setting option on client socket: %s",
224 strerror( errno )
225 );
226 }
227#else
228 //-------------------------
229 // Set the socket I/O mode: In this case FIONBIO
230 // enables or disables the blocking mode for the
231 // socket based on the numerical value of iMode.
232 // If iMode = 0, blocking is enabled;
233 // If iMode != 0, non-blocking mode is enabled.
234 u_long iMode = 1;
235 bu_ioctlsocket(nClient, FIONBIO, &iMode);
236#endif
237 }
238
239 return nClient;
240 }
241
242 return -1;
243}
244
245int Bu::TcpServerSocket::getPort()
246{
247 return nPort;
248}
249
diff --git a/src/stable/tcpserversocket.h b/src/stable/tcpserversocket.h
new file mode 100644
index 0000000..efb7287
--- /dev/null
+++ b/src/stable/tcpserversocket.h
@@ -0,0 +1,64 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_TCP_SERVER_SOCKET_H
9#define BU_TCP_SERVER_SOCKET_H
10
11#include <stdint.h>
12#include "bu/string.h"
13#include "bu/exceptionbase.h"
14
15#ifdef WIN32
16 #include <Winsock2.h>
17#else
18 #include <sys/select.h>
19#endif
20
21namespace Bu
22{
23 subExceptionDecl( TcpServerSocketException );
24
25 /**
26 * A single tcp/ip server socket. When created the server socket will bind
27 * to the specified interface and port, and immediately begin listening for
28 * connections. When connections come in they are pooled by the networking
29 * drivers in the kernel until they are accepted, this means that failure
30 * to keep space in the connection pool will result in connection refusals.
31 *
32 * Although the accept function returns an integral file descriptor, it is
33 * designed to be used with the Socket class.
34 *
35 *@ingroup Serving
36 */
37 class TcpServerSocket
38 {
39 public:
40 TcpServerSocket( int nPort, int nPoolSize=40 );
41 TcpServerSocket( const String &sAddr, int nPort, int nPoolSize=40 );
42 TcpServerSocket( int nSocket, bool bInit, int nPoolSize=40 );
43 TcpServerSocket( const TcpServerSocket &rSrc );
44 virtual ~TcpServerSocket();
45
46 int accept( int nTimeoutSec=0, int nTimeoutUSec=0 );
47 int getSocket();
48 int getPort();
49
50 private:
51 void startServer( struct sockaddr_in &name, int nPoolSize );
52 void initServer( struct sockaddr_in &name, int nPoolSize );
53
54 fd_set fdActive;
55#ifdef WIN32
56 unsigned int nServer;
57#else
58 int nServer;
59#endif
60 int nPort;
61 };
62}
63
64#endif
diff --git a/src/stable/tcpsocket.cpp b/src/stable/tcpsocket.cpp
new file mode 100644
index 0000000..b9b215c
--- /dev/null
+++ b/src/stable/tcpsocket.cpp
@@ -0,0 +1,478 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include <string.h>
9#include <stdio.h>
10#include <errno.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <sys/types.h>
14#include <sys/time.h>
15#include <errno.h>
16#include <fcntl.h>
17#include "bu/tcpsocket.h"
18
19#include "bu/config.h"
20
21#ifndef WIN32
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <netdb.h>
25 #include <arpa/inet.h>
26#else
27 #include <Winsock2.h>
28#endif
29
30#define RBS (1024*2)
31
32namespace Bu { subExceptionDef( TcpSocketException ) }
33
34Bu::TcpSocket::TcpSocket( handle nTcpSocket ) :
35 nTcpSocket( nTcpSocket ),
36 bActive( true ),
37 bBlocking( true )
38{
39#ifdef WIN32
40 Bu::Winsock2::getInstance();
41#endif
42 setAddress();
43}
44
45Bu::TcpSocket::TcpSocket( const Bu::String &sAddr, int nPort, int nTimeout,
46 bool bBlocking ) :
47 nTcpSocket( 0 ),
48 bActive( false ),
49 bBlocking( true )
50{
51#ifdef WIN32
52 Bu::Winsock2::getInstance();
53#endif
54
55 /* Create the socket. */
56 nTcpSocket = bu_socket( PF_INET, SOCK_STREAM, 0 );
57
58 if( nTcpSocket < 0 )
59 {
60 throw ExceptionBase("Couldn't create socket.\n");
61 }
62
63 setBlocking( false );
64
65 /* Connect to the server. */
66 //printf("Resolving hostname (%s)...\n", sAddr );
67 {
68 struct addrinfo *pAddr = NULL;
69 struct addrinfo aiHints;
70 memset( &aiHints, 0, sizeof(addrinfo) );
71 aiHints.ai_flags = AI_CANONNAME;
72 aiHints.ai_family = AF_INET;
73 aiHints.ai_socktype = SOCK_STREAM;
74 char ibuf[10];
75 sprintf( ibuf, "%d", nPort );
76
77 int ret;
78 if( (ret = bu_getaddrinfo(
79 sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 )
80 {
81 close();
82 throw Bu::TcpSocketException("Couldn't resolve hostname %s (%s).\n",
83 sAddr.getStr(), bu_gai_strerror(ret));
84 }
85
86 bu_connect(
87 nTcpSocket,
88 pAddr->ai_addr,
89 pAddr->ai_addrlen
90 );
91
92 sAddress = pAddr->ai_canonname;
93
94 bu_freeaddrinfo( pAddr );
95 }
96
97 bActive = true;
98
99 if( nTimeout > 0 )
100 {
101 fd_set rfds, wfds, efds;
102 int retval;
103
104 FD_ZERO(&rfds);
105 FD_SET(nTcpSocket, &rfds);
106 FD_ZERO(&wfds);
107 FD_SET(nTcpSocket, &wfds);
108 FD_ZERO(&efds);
109 FD_SET(nTcpSocket, &efds);
110
111 struct timeval tv;
112 tv.tv_sec = nTimeout;
113 tv.tv_usec = 0;
114
115 retval = bu_select( nTcpSocket+1, &rfds, &wfds, &efds, &tv );
116
117 if( retval == 0 )
118 {
119 close();
120 throw ExceptionBase("Connection timeout.\n");
121 }
122 read( NULL, 0 ); // See if we can get any errors out of the way early.
123 }
124
125 if( bBlocking )
126 setBlocking( bBlocking );
127}
128
129Bu::TcpSocket::~TcpSocket()
130{
131 close();
132}
133
134void Bu::TcpSocket::close()
135{
136 if( bActive )
137 {
138#ifndef WIN32
139 fsync( nTcpSocket );
140#endif
141#ifdef WIN32
142 #ifndef SHUT_RDWR
143 #define SHUT_RDWR (SD_BOTH)
144 #endif
145#endif
146 bu_shutdown( nTcpSocket, SHUT_RDWR );
147 ::close( nTcpSocket );
148 }
149 bActive = false;
150}
151
152Bu::size Bu::TcpSocket::read( void *pBuf, Bu::size nBytes )
153{
154 fd_set rfds;
155 FD_ZERO(&rfds);
156 FD_SET(nTcpSocket, &rfds);
157 struct timeval tv = {0, 0};
158 if( bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ) < 0 )
159 {
160 int iErr = errno;
161 close();
162 throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) );
163 }
164 if( FD_ISSET( nTcpSocket, &rfds ) || bBlocking )
165 {
166 int nRead = TEMP_FAILURE_RETRY(
167 bu_recv( nTcpSocket, (char *) pBuf, nBytes, 0 ) );
168 if( nRead == 0 && nBytes > 0 )
169 {
170 close();
171 throw TcpSocketException( TcpSocketException::cClosed, "TcpSocket closed.");
172 }
173 if( nRead < 0 )
174 {
175#ifdef WIN32
176 int iWSAError = bu_WSAGetLastError();
177 if( iWSAError == WSAEWOULDBLOCK )
178 return 0;
179#else
180 if( errno == ENETRESET || errno == ECONNRESET )
181 {
182 close();
183 throw TcpSocketException( TcpSocketException::cClosed,
184 strerror(errno) );
185 }
186 if( errno == EAGAIN )
187 return 0;
188 int iErr = errno;
189 close();
190 throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) );
191#endif
192 }
193 return nRead;
194 }
195 return 0;
196}
197
198Bu::size Bu::TcpSocket::read( void *pBuf, Bu::size nBytes,
199 uint32_t nSec, uint32_t nUSec )
200{
201 struct timeval tv;
202 Bu::size nRead = 0;
203
204 fd_set rfds;
205 FD_ZERO(&rfds);
206 FD_SET(nTcpSocket, &rfds);
207
208#ifdef WIN32
209 DWORD dwStart = GetTickCount();
210 uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000));
211 DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver;
212#else
213 struct timeval nt, ct;
214 gettimeofday( &nt, NULL );
215 nt.tv_sec += nSec;
216 nt.tv_usec += nUSec;
217#endif
218
219 for(;;)
220 {
221 tv.tv_sec = nSec;
222 tv.tv_usec = nUSec;
223 bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv );
224 nRead += read( ((char *)pBuf)+nRead, nBytes-nRead );
225 if( nRead >= nBytes )
226 break;
227#ifdef WIN32
228 DWORD dwNow = GetTickCount();
229 if( dwNow > dwEnd )
230 break;
231#else
232 gettimeofday( &ct, NULL );
233 if( (ct.tv_sec > nt.tv_sec) ||
234 (ct.tv_sec == nt.tv_sec &&
235 ct.tv_usec >= nt.tv_usec) )
236 break;
237#endif
238 }
239 return nRead;
240}
241
242Bu::size Bu::TcpSocket::write( const void *pBuf, Bu::size nBytes )
243{
244//#ifdef WIN32
245 int nWrote = TEMP_FAILURE_RETRY(
246 bu_send( nTcpSocket, (const char *) pBuf, nBytes, 0 ) );
247//#else
248// int nWrote = TEMP_FAILURE_RETRY( ::write( nTcpSocket, pBuf, nBytes ) );
249//#endif
250 if( nWrote < 0 )
251 {
252#ifdef WIN32
253 int iWSAError = bu_WSAGetLastError();
254 if( iWSAError == WSAEWOULDBLOCK )
255 return 0;
256#else
257 if( errno == EAGAIN ) return 0;
258#endif
259 throw TcpSocketException( TcpSocketException::cWrite, strerror(errno) );
260 }
261 return nWrote;
262}
263
264Bu::size Bu::TcpSocket::write( const void *pBuf, Bu::size nBytes, uint32_t nSec, uint32_t nUSec )
265{
266 struct timeval tv;
267 Bu::size nWrote = 0;
268
269 fd_set wfds;
270 FD_ZERO(&wfds);
271 FD_SET(nTcpSocket, &wfds);
272
273#ifdef WIN32
274 DWORD dwStart = GetTickCount();
275 uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000));
276 DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver;
277#else
278 struct timeval nt, ct;
279 gettimeofday( &nt, NULL );
280 nt.tv_sec += nSec;
281 nt.tv_usec += nUSec;
282#endif
283
284 for(;;)
285 {
286 tv.tv_sec = nSec;
287 tv.tv_usec = nUSec;
288 bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv );
289 nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote );
290 if( nWrote >= nBytes )
291 break;
292#ifdef WIN32
293 DWORD dwNow = GetTickCount();
294 if( dwNow > dwEnd )
295 break;
296#else
297 gettimeofday( &ct, NULL );
298 if( (ct.tv_sec > nt.tv_sec) ||
299 (ct.tv_sec == nt.tv_sec &&
300 ct.tv_usec >= nt.tv_usec) )
301 break;
302#endif
303 }
304 return nWrote;
305}
306
307Bu::size Bu::TcpSocket::tell()
308{
309 throw UnsupportedException();
310}
311
312void Bu::TcpSocket::seek( Bu::size )
313{
314 throw UnsupportedException();
315}
316
317void Bu::TcpSocket::setPos( Bu::size )
318{
319 throw UnsupportedException();
320}
321
322void Bu::TcpSocket::setPosEnd( Bu::size )
323{
324 throw UnsupportedException();
325}
326
327bool Bu::TcpSocket::isEos()
328{
329 return !bActive;
330}
331
332bool Bu::TcpSocket::canRead()
333{
334 fd_set rfds;
335 FD_ZERO(&rfds);
336 FD_SET(nTcpSocket, &rfds);
337 struct timeval tv = { 0, 0 };
338 int retval = bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv );
339 if( retval == -1 )
340 throw TcpSocketException(
341 TcpSocketException::cBadRead,
342 "Bad Read error"
343 );
344
345 if( !FD_ISSET( nTcpSocket, &rfds ) )
346 return false;
347 return true;
348}
349
350bool Bu::TcpSocket::canWrite()
351{
352 fd_set wfds;
353 FD_ZERO(&wfds);
354 FD_SET(nTcpSocket, &wfds);
355 struct timeval tv = { 0, 0 };
356 int retval = bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv );
357 if( retval == -1 )
358 throw TcpSocketException(
359 TcpSocketException::cBadRead,
360 "Bad Read error"
361 );
362 if( !FD_ISSET( nTcpSocket, &wfds ) )
363 return false;
364 return true;
365}
366
367bool Bu::TcpSocket::isReadable()
368{
369 return true;
370}
371
372bool Bu::TcpSocket::isWritable()
373{
374 return true;
375}
376
377bool Bu::TcpSocket::isSeekable()
378{
379 return false;
380}
381
382bool Bu::TcpSocket::isBlocking()
383{
384#ifndef WIN32
385 return ((fcntl( nTcpSocket, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK);
386#else
387 return false;
388#endif
389}
390
391void Bu::TcpSocket::setBlocking( bool bBlocking )
392{
393 this->bBlocking = bBlocking;
394#ifndef WIN32
395 if( bBlocking )
396 {
397 fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) & (~O_NONBLOCK) );
398 }
399 else
400 {
401 fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) | O_NONBLOCK );
402 }
403#else
404 u_long iMode;
405 if( bBlocking )
406 iMode = 0;
407 else
408 iMode = 1;
409 //-------------------------
410 // Set the socket I/O mode: In this case FIONBIO
411 // enables or disables the blocking mode for the
412 // socket based on the numerical value of iMode.
413 // If iMode = 0, blocking is enabled;
414 // If iMode != 0, non-blocking mode is enabled.
415 bu_ioctlsocket(nTcpSocket, FIONBIO, &iMode);
416#endif
417}
418
419void Bu::TcpSocket::setSize( Bu::size )
420{
421}
422
423void Bu::TcpSocket::flush()
424{
425}
426
427bool Bu::TcpSocket::isOpen()
428{
429 return bActive;
430}
431
432void Bu::TcpSocket::setAddress()
433{
434 struct sockaddr_in addr;
435 socklen_t len = sizeof(addr);
436 addr.sin_family = AF_INET;
437 bu_getpeername( nTcpSocket, (sockaddr *)(&addr), &len );
438 sAddress = bu_inet_ntoa( addr.sin_addr );
439}
440
441Bu::String Bu::TcpSocket::getAddress() const
442{
443 return sAddress;
444}
445
446Bu::TcpSocket::operator Bu::TcpSocket::handle() const
447{
448 return nTcpSocket;
449}
450
451Bu::TcpSocket::handle Bu::TcpSocket::getHandle() const
452{
453 return nTcpSocket;
454}
455
456Bu::TcpSocket::handle Bu::TcpSocket::takeHandle()
457{
458 handle nRet = nTcpSocket;
459 bActive = false;
460 nTcpSocket = 0;
461 return nRet;
462}
463
464Bu::size Bu::TcpSocket::getSize() const
465{
466 throw UnsupportedException();
467}
468
469Bu::size Bu::TcpSocket::getBlockSize() const
470{
471 return 1500; //TODO: Fix this, it's stupid.
472}
473
474Bu::String Bu::TcpSocket::getLocation() const
475{
476 return getAddress();
477}
478
diff --git a/src/stable/tcpsocket.h b/src/stable/tcpsocket.h
new file mode 100644
index 0000000..52218bd
--- /dev/null
+++ b/src/stable/tcpsocket.h
@@ -0,0 +1,126 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_TCP_SOCKET_H
9#define BU_TCP_SOCKET_H
10
11#include <stdint.h>
12
13#include "bu/config.h"
14#include "bu/stream.h"
15#include "bu/string.h"
16#include "bu/exceptionbase.h"
17
18namespace Bu
19{
20 subExceptionDeclBegin( TcpSocketException );
21 enum {
22 cRead,
23 cWrite,
24 cBadRead,
25 cClosed,
26 cTimeout
27 };
28 subExceptionDeclEnd();
29
30 /**
31 * Network socket stream class. This class provides a mechanism for
32 * communicating over a network using TCP/IP. It will provide other low
33 * level protocol and addressing support later on, but for now it's just
34 * standard STREAM TCP/IP sockets.
35 *
36 * Unlike system sockets, these sockets are opened by default in
37 * non-blocking mode, you can specify your own timeout for opening a socket,
38 * and a number of non-fatal error messages have been automatically handled
39 * and treated as standard no-data-available-yet situations on read.
40 *
41 * Please note that there is a condition that will occur eventually (at
42 * least on *nix systems) that will trigger a SIGPIPE condition. This
43 * will terminate your program immediately unless handled properly. Most
44 * people doing any connections with TcpSocket will want to put this in
45 * their program somewhere before they use it:
46 *@code
47 #include <signal.h>
48 ...
49 ...
50 ...
51 sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::TcpSocket
52 @endcode
53 * When this is done, Bu::TcpSocket will simply throw a broken pipe
54 * exception just like every other error condition, allowing your program
55 * to handle it sanely.
56 *
57 *@ingroup Serving
58 *@ingroup Streams
59 */
60 class TcpSocket : public Stream
61 {
62 public:
63#ifdef WIN32
64 typedef unsigned int handle;
65#else
66 typedef int handle;
67#endif
68
69 TcpSocket( handle nTcpSocket );
70 TcpSocket( const String &sAddr, int nPort, int nTimeout=30,
71 bool bBlocking=true );
72 virtual ~TcpSocket();
73
74 virtual void close();
75 virtual size read( void *pBuf, size nBytes );
76 virtual size read( void *pBuf, size nBytes,
77 uint32_t nSec, uint32_t nUSec=0 );
78 virtual size write( const void *pBuf, size nBytes );
79 virtual size write( const void *pBuf, size nBytes,
80 uint32_t nSec, uint32_t nUSec=0 );
81 using Stream::write;
82
83 virtual size tell();
84 virtual void seek( size offset );
85 virtual void setPos( size pos );
86 virtual void setPosEnd( size pos );
87 virtual bool isEos();
88 virtual bool isOpen();
89
90 virtual void flush();
91
92 virtual bool canRead();
93 virtual bool canWrite();
94
95 virtual bool isReadable();
96 virtual bool isWritable();
97 virtual bool isSeekable();
98
99 virtual bool isBlocking();
100 virtual void setBlocking( bool bBlocking=true );
101
102 virtual void setSize( size iSize );
103
104 Bu::String getAddress() const;
105 operator handle() const;
106
107 handle getHandle() const;
108 handle takeHandle();
109
110 virtual size getSize() const;
111 virtual size getBlockSize() const;
112 virtual Bu::String getLocation() const;
113
114 private:
115 void setAddress();
116
117 handle nTcpSocket;
118
119 bool bActive;
120 bool bBlocking;
121 String sReadBuf;
122 String sAddress;
123 };
124}
125
126#endif
diff --git a/src/stable/thread.cpp b/src/stable/thread.cpp
new file mode 100644
index 0000000..e4563a2
--- /dev/null
+++ b/src/stable/thread.cpp
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/thread.h"
9
10#include "bu/config.h"
11
12Bu::Thread::Thread()
13{
14}
15
16Bu::Thread::~Thread()
17{
18}
19
20bool Bu::Thread::start()
21{
22 nHandle = pthread_create( &ptHandle, NULL, threadRunner, this );
23
24 return true;
25}
26
27bool Bu::Thread::stop()
28{
29 pthread_cancel( ptHandle );
30
31 return true;
32}
33
34void *Bu::Thread::threadRunner( void *pThread )
35{
36 ((Thread *)pThread)->run();
37 pthread_exit( NULL );
38 return NULL;
39}
40
41bool Bu::Thread::join()
42{
43 pthread_join( ptHandle, NULL );
44 return true;
45}
46
47void Bu::Thread::yield()
48{
49#ifndef WIN32
50 pthread_yield();
51#else
52 #warning Bu::Thread::yield IS A STUB for WIN32!!!!
53#endif
54}
55
diff --git a/src/stable/thread.h b/src/stable/thread.h
new file mode 100644
index 0000000..70e6f5f
--- /dev/null
+++ b/src/stable/thread.h
@@ -0,0 +1,107 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_THREAD_H
9#define BU_THREAD_H
10
11#include <pthread.h>
12
13namespace Bu
14{
15 /**
16 * Simple thread class. This wraps the basic pthread (posix threads)
17 * system in an object oriented sort of way. It allows you to create a
18 * class with standard member variables and callable functions that can be
19 * run in it's own thread, one per class instance.
20 *@ingroup Threading
21 */
22 class Thread
23 {
24 public:
25 /**
26 * Construct an Thread thread.
27 */
28 Thread();
29
30 /**
31 * Destroy an Thread thread.
32 */
33 virtual ~Thread();
34
35 /**
36 * Begin thread execution. This will call the overridden run function,
37 * which will simply execute in it's own thread until the function
38 * exits, the thread is killed, or the thread is cancelled (optionally).
39 * The thread started in this manner has access to all of it's class
40 * variables, but be sure to protect possible multiple-access with
41 * ThreadMutex objects.
42 * @returns True if starting the thread was successful. False if
43 * something went wrong and the thread has not started.
44 */
45 bool start();
46
47 /**
48 * Forcibly kill a thread. This is not generally considered a good
49 * thing to do, but in those rare cases you need it, it's invaluable.
50 * The problem with stopping (or killing) a thread is that it stops it
51 * the moment you call stop, no matter what it's doing. The object
52 * oriented approach to this will help clean up any class variables
53 * that were used, but anything not managed as a member variable will
54 * probably create a memory leak type of situation. Instead of stop,
55 * consider using cancel, which can be handled by the running thread in
56 * a graceful manner.
57 *@returns True if the thread was stopped, false otherwise. When this
58 * function returns the thread may not have stopped, to ensure that the
59 * thread has really stopped, call join.
60 */
61 bool stop();
62
63 /**
64 * Join the thread in action. This function performs what is commonly
65 * called a thread join. That is that it effectively makes the calling
66 * thread an the Thread thread contained in the called object one in the
67 * same, and pauses the calling thread until the called thread exits.
68 * That is, when called from, say, your main(), mythread.join() will
69 * not return until the thread mythread has exited. This is very handy
70 * at the end of programs to ensure all of your data was cleaned up.
71 *@returns True if the thread was joined, false if the thread couldn't
72 * be joined, usually because it isn't running to begin with.
73 */
74 bool join();
75
76 private:
77 pthread_t ptHandle; /**< Internal handle to the posix thread. */
78 int nHandle; /**< Numeric handle to the posix thread. */
79
80 protected:
81 /**
82 * The workhorse of the Thread class. This is the function that will run
83 * in the thread, when this function exits the thread dies and is
84 * cleaned up by the system. Make sure to read up on ThreadMutex,
85 * ThreadCondition, and cancel to see how to control and protect
86 * everything you do in a safe way within this function.
87 *@returns I'm not sure right now, but this is the posix standard form.
88 */
89 virtual void run()=0;
90
91 /**
92 * This is the hidden-heard of the thread system. While run is what the
93 * user gets to override, and everything said about it is true, this is
94 * the function that actually makes up the thread, it simply calls the
95 * run member function in an OO-friendly way. This is what allows us to
96 * use member variables from within the thread itself.
97 *@param pThread Should always be this.
98 *@returns This is specified by posix, I'm not sure yet.
99 */
100 static void *threadRunner( void *pThread );
101
102 void yield();
103
104 };
105}
106
107#endif
diff --git a/src/stable/trace.cpp b/src/stable/trace.cpp
new file mode 100644
index 0000000..03181e9
--- /dev/null
+++ b/src/stable/trace.cpp
@@ -0,0 +1,67 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/trace.h"
9
10void Bu::__tracer( const char *pf )
11{
12 printf("trace: %s\n", pf );
13}
14
15template<> void Bu::__tracer_format<float>( const float &v )
16{
17 printf("%f", v );
18}
19
20template<> void Bu::__tracer_format<double>( const double &v )
21{
22 printf("%f", v );
23}
24
25template<> void Bu::__tracer_format<void *>( void * const &v )
26{
27 printf("0x%08X", (ptrdiff_t)v );
28}
29
30template<> void Bu::__tracer_format<char *>( char * const &v )
31{
32 printf("\"%s\"", v );
33}
34
35template<> void Bu::__tracer_format<char **>( char ** const &v )
36{
37 printf("[");
38 for( int j = 0; v[j]; j++ )
39 {
40 if( j > 0 )
41 printf(", ");
42 printf("\"%s\"", v[j] );
43 }
44 printf("]");
45}
46
47template<> void Bu::__tracer_format<void const *>( void const * const &v )
48{
49 printf("0x%08X", (ptrdiff_t)v );
50}
51
52template<> void Bu::__tracer_format<char const *>( char const * const &v )
53{
54 printf("\"%s\"", v );
55}
56
57template<> void Bu::__tracer_format<char const **>( char const ** const &v )
58{
59 printf("[");
60 for( int j = 0; v[j]; j++ )
61 {
62 if( j > 0 )
63 printf(", ");
64 printf("\"%s\"", v[j] );
65 }
66 printf("]");
67}
diff --git a/src/stable/trace.h b/src/stable/trace.h
new file mode 100644
index 0000000..51dfb8e
--- /dev/null
+++ b/src/stable/trace.h
@@ -0,0 +1,187 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_TRACE_H
9#define BU_TRACE_H
10
11#include <stdio.h>
12#include <stdint.h>
13#include <stddef.h>
14#include <string.h>
15
16#include <bu/sio.h>
17
18namespace Bu
19{
20/* template<typename t> void __tracer_format( t &v )
21 {
22 __tracer_format( *const_cast<const t *>(&v) );
23 }
24*/
25 template<typename t> void __tracer_format( const t &v )
26 {
27 Bu::sio << v;
28 }
29
30 void __tracer( const char *pf );
31
32 #define looper( vv ) \
33 for( ; *n; n++ ) \
34 { \
35 if( bInBracket == true ) \
36 { \
37 if( *n == '>' ) \
38 bInBracket = false; \
39 } \
40 else if( *n == ',' || *n == ')' ) \
41 { \
42 fwrite( s, (ptrdiff_t)n-(ptrdiff_t)s, 1, stdout ); \
43 fwrite("=", 1, 1, stdout); \
44 __tracer_format( vv ); \
45 s = n; \
46 n++; \
47 break; \
48 } \
49 else if( *n == '<' ) \
50 { \
51 bInBracket = true; \
52 } \
53 } (void)0
54
55 template<typename t1> void __tracer( const char *pf, t1 &v1 )
56 {
57 printf("trace: ");
58 const char *s = pf;
59 const char *n = pf;
60 bool bInBracket = false;
61 looper( v1 );
62 fwrite( s, (ptrdiff_t)n-(ptrdiff_t)s, strlen(s), stdout );
63 fwrite( "\n", 1, 1, stdout );
64 fflush( stdout );
65 }
66
67 template<typename t1, typename t2> void __tracer( const char *pf,
68 t1 &v1, t2 &v2 )
69 {
70 printf("trace: ");
71 const char *s = pf;
72 const char *n = pf;
73 bool bInBracket = false;
74 looper( v1 );
75 looper( v2 );
76 fwrite( s, (ptrdiff_t)n-(ptrdiff_t)s, strlen(s), stdout );
77 fwrite( "\n", 1, 1, stdout );
78 fflush( stdout );
79 }
80
81 template<typename t1, typename t2, typename t3>
82 void __tracer( const char *pf, t1 &v1, t2 &v2, t3 &v3 )
83 {
84 printf("trace: ");
85 const char *s = pf;
86 const char *n = pf;
87 bool bInBracket = false;
88 looper( v1 );
89 looper( v2 );
90 looper( v3 );
91 fwrite( s, (ptrdiff_t)n-(ptrdiff_t)s, strlen(s), stdout );
92 fwrite( "\n", 1, 1, stdout );
93 fflush( stdout );
94 }
95
96 template<typename t1, typename t2, typename t3, typename t4>
97 void __tracer( const char *pf, t1 &v1, t2 &v2, t3 &v3, t4 &v4 )
98 {
99 printf("trace: ");
100 const char *s = pf;
101 const char *n = pf;
102 bool bInBracket = false;
103 looper( v1 );
104 looper( v2 );
105 looper( v3 );
106 looper( v4 );
107 fwrite( s, (ptrdiff_t)n-(ptrdiff_t)s, strlen(s), stdout );
108 fwrite( "\n", 1, 1, stdout );
109 fflush( stdout );
110 }
111
112 template<typename t1, typename t2, typename t3, typename t4, typename t5>
113 void __tracer( const char *pf, t1 &v1, t2 &v2, t3 &v3, t4 &v4, t5 &v5 )
114 {
115 printf("trace: ");
116 const char *s = pf;
117 const char *n = pf;
118 bool bInBracket = false;
119 looper( v1 );
120 looper( v2 );
121 looper( v3 );
122 looper( v4 );
123 looper( v5 );
124 fwrite( s, (ptrdiff_t)n-(ptrdiff_t)s, strlen(s), stdout );
125 fwrite( "\n", 1, 1, stdout );
126 fflush( stdout );
127 }
128
129 template<typename t1, typename t2, typename t3, typename t4, typename t5,
130 typename t6>
131 void __tracer( const char *pf, t1 &v1, t2 &v2, t3 &v3, t4 &v4, t5 &v5,
132 t6 &v6)
133 {
134 printf("trace: ");
135 const char *s = pf;
136 const char *n = pf;
137 bool bInBracket = false;
138 looper( v1 );
139 looper( v2 );
140 looper( v3 );
141 looper( v4 );
142 looper( v5 );
143 looper( v6 );
144 fwrite( s, (ptrdiff_t)n-(ptrdiff_t)s, strlen(s), stdout );
145 fwrite( "\n", 1, 1, stdout );
146 fflush( stdout );
147 }
148
149 template<typename t1, typename t2, typename t3, typename t4, typename t5,
150 typename t6, typename t7>
151 void __tracer( const char *pf, t1 &v1, t2 &v2, t3 &v3, t4 &v4, t5 &v5,
152 t6 &v6, t7 &v7 )
153 {
154 printf("trace: ");
155 const char *s = pf;
156 const char *n = pf;
157 bool bInBracket = false;
158 looper( v1 );
159 looper( v2 );
160 looper( v3 );
161 looper( v4 );
162 looper( v5 );
163 looper( v6 );
164 looper( v7 );
165 fwrite( s, (ptrdiff_t)n-(ptrdiff_t)s, strlen(s), stdout );
166 fwrite( "\n", 1, 1, stdout );
167 fflush( stdout );
168 }
169#undef looper
170
171 template<> void __tracer_format<float>( const float &v );
172 template<> void __tracer_format<double>( const double &v );
173 template<> void __tracer_format<void *>( void * const &v );
174 template<> void __tracer_format<char *>( char * const &v );
175 template<> void __tracer_format<char **>( char ** const &v );
176 template<> void __tracer_format<void const *>( void const * const &v );
177 template<> void __tracer_format<char const *>( char const * const &v );
178 template<> void __tracer_format<char const **>( char const ** const &v );
179}
180
181#ifdef BU_TRACE
182# define TRACE(args...) Bu::__tracer( __PRETTY_FUNCTION__, ##args )
183#else
184# define TRACE(args...) (void)0
185#endif
186
187#endif
diff --git a/src/stable/unitsuite.cpp b/src/stable/unitsuite.cpp
new file mode 100644
index 0000000..db930a4
--- /dev/null
+++ b/src/stable/unitsuite.cpp
@@ -0,0 +1,255 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/unitsuite.h"
9#include "bu/file.h"
10#include "bu/sio.h"
11#include "bu/optparser.h"
12#include <stdlib.h>
13#include <time.h>
14
15using namespace Bu;
16
17#include <unistd.h>
18
19Bu::UnitSuite::UnitSuite() :
20 iOptions( 0 ),
21 iNameWidth( 0 )
22{
23}
24
25Bu::UnitSuite::UnitSuite( int iOptions ) :
26 iOptions( iOptions ),
27 iNameWidth( 0 )
28{
29}
30
31Bu::UnitSuite::~UnitSuite()
32{
33}
34
35// Argument handling is coming soon, I promise.
36int Bu::UnitSuite::run( int argc, char *argv[] )
37{
38 bool bCleanup = true;
39 OptParser p;
40 p.addOption( Bu::slot( this, &Bu::UnitSuite::onListCases ), 'l', "list",
41 "List available test cases." );
42 p.addOption( bCleanup, "no-cleanup", "Don't erase temp files.");
43 p.setOverride( "no-cleanup", false );
44 p.addHelpOption();
45 p.parse( argc, argv );
46
47 int iEPass = 0;
48 int iEFail = 0;
49 int iUPass = 0;
50 int iUFail = 0;
51 for( TestList::iterator i = lTests.begin(); i != lTests.end(); i++ )
52 {
53 sio << Fmt( iNameWidth+3, Fmt::Left ).fill('.') << i->sName
54 << sio.flush;
55 try
56 {
57 iStepCount = -1;
58 iProgress = 0;
59 (this->*(i->fTest))();
60 switch( i->eExpect )
61 {
62 case expectPass:
63 sio << "pass." << sio.nl;
64 iEPass++;
65 break;
66
67 case expectFail:
68 sio << "unexpected pass." << sio.nl;
69 iUPass++;
70 break;
71 }
72 }
73 catch( Failed &e )
74 {
75 switch( i->eExpect )
76 {
77 case expectPass:
78 sio << "unexpected ";
79 iUFail++;
80 break;
81
82 case expectFail:
83 sio << "expected ";
84 iEFail++;
85 break;
86 }
87 if( e.bFile )
88 {
89 sio << "fail in unitTest(" << e.str << "). (" << e.sFile
90 << ":" << e.nLine << ")." << sio.nl;
91 }
92 else
93 {
94 sio << "fail in unitTest(" << e.str << ")." << sio.nl;
95 }
96
97 if( (iOptions & optStopOnError) )
98 return 0;
99 }
100 catch( std::exception &e )
101 {
102 switch( i->eExpect )
103 {
104 case expectPass:
105 sio << "unexpected ";
106 iUFail++;
107 break;
108
109 case expectFail:
110 sio << "expected ";
111 iEFail++;
112 break;
113 }
114 sio << "fail with unknown exception. what: " << e.what() << sio.nl;
115
116 if( (iOptions & optStopOnError) )
117 return 0;
118 }
119 catch( ... )
120 {
121 switch( i->eExpect )
122 {
123 case expectPass:
124 sio << "unexpected ";
125 iUFail++;
126 break;
127
128 case expectFail:
129 sio << "expected ";
130 iEFail++;
131 break;
132 }
133 sio << "fail with external exception." << sio.nl;
134
135 if( (iOptions & optStopOnError) )
136 return 0;
137 }
138 }
139
140 sio << sio.nl
141 << "Report:" << sio.nl
142 << "\tTotal tests run: " << lTests.getSize() << sio.nl
143 << "\tExpected passes: " << iEPass << sio.nl
144 << "\tExpected failures: " << iEFail << sio.nl
145 << "\tUnexpected passes: " << iUPass << sio.nl
146 << "\tUnexpected failures: " << iUFail << sio.nl << sio.nl;
147 if( iUPass == 0 && iUFail == 0 )
148 sio << "\tNothing unexpected." << sio.nl << sio.nl;
149
150 if( bCleanup )
151 {
152 for( StrList::iterator i = lFileCleanup.begin(); i; i++ )
153 {
154 unlink( (*i).getStr() );
155 }
156 }
157
158 return 0;
159}
160
161Bu::File Bu::UnitSuite::tempFile( Bu::String &sFileName )
162{
163 Bu::File f = Bu::File::tempFile( sFileName );
164 lFileCleanup.append( sFileName );
165 return f;
166}
167
168void Bu::UnitSuite::add( Test fTest, const Bu::String &sName, Expect e )
169{
170 TestInfo ti;
171 ti.sName = sName;
172 ti.eExpect = e;
173 long index = ti.sName.rfindIdx("::");
174 if( index != -1 )
175 {
176 String tmp = sSuiteName;
177 tmp += ti.sName.getStr()+index;
178 ti.sName = tmp;
179 }
180 ti.fTest = fTest;
181 lTests.append( ti );
182 if( iNameWidth < ti.sName.getSize() )
183 iNameWidth = ti.sName.getSize();
184}
185
186void Bu::UnitSuite::setName( const String &sName )
187{
188 sSuiteName = sName;
189}
190
191void Bu::UnitSuite::dispProgress()
192{
193 if( tLastUpdate == time( NULL ) )
194 return;
195 sio << Fmt(3) << (iProgress*100/iStepCount) << "%" << "\b\b\b\b"
196 << sio.flush;
197 tLastUpdate = time( NULL );
198}
199
200void Bu::UnitSuite::setStepCount( int iSteps )
201{
202 iStepCount = iSteps;
203 if( iStepCount < 0 )
204 return;
205 tLastUpdate = 0;
206 dispProgress();
207}
208
209void Bu::UnitSuite::incProgress( int iAmnt )
210{
211 iProgress += iAmnt;
212 if( iProgress < 0 )
213 iProgress = 0;
214 if( iProgress > iStepCount )
215 iProgress = iStepCount;
216 dispProgress();
217}
218
219void Bu::UnitSuite::setProgress( int iAmnt )
220{
221 iProgress = iAmnt;
222 if( iProgress < 0 )
223 iProgress = 0;
224 if( iProgress > iStepCount )
225 iProgress = iStepCount;
226 dispProgress();
227}
228
229int Bu::UnitSuite::onListCases( StrArray )
230{
231 sio << "Test cases:" << sio.nl;
232 for( TestList::iterator i = lTests.begin(); i; i++ )
233 {
234 sio << "\t- " << Fmt( iNameWidth, 10, Fmt::Left ) << (*i).sName << " "
235 << (*i).eExpect << sio.nl;
236 }
237 sio << sio.nl;
238 exit( 0 );
239 return 0;
240}
241
242Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::UnitSuite::Expect &e )
243{
244 switch( e )
245 {
246 case Bu::UnitSuite::expectPass:
247 return f << "expect pass";
248
249 case Bu::UnitSuite::expectFail:
250 return f << "expect fail";
251 }
252
253 return f << "**error**";
254}
255
diff --git a/src/stable/unitsuite.h b/src/stable/unitsuite.h
new file mode 100644
index 0000000..2250a4d
--- /dev/null
+++ b/src/stable/unitsuite.h
@@ -0,0 +1,139 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_UNIT_SUITE_H
9#define BU_UNIT_SUITE_H
10
11#include <stdint.h>
12#include "bu/list.h"
13#include "bu/string.h"
14#include "bu/file.h"
15#include "bu/array.h"
16
17namespace Bu
18{
19 /**
20 * Provides a unit testing framework. This is pretty easy to use, probably
21 * the best way to get started is to use ch to generate a template, or use
22 * the code below with appropriate tweaks:
23 *@code
24 * #include "unitsuite.h"
25 *
26 * class Unit : public Bu::UnitSuite
27 * {
28 * public:
29 * Unit()
30 * {
31 * setName("Example");
32 * addTest( Unit::test );
33 * }
34 *
35 * virtual ~Unit() { }
36 *
37 * //
38 * // Tests go here
39 * //
40 * void test()
41 * {
42 * unitTest( 1 == 1 );
43 * }
44 * };
45 *
46 * int main( int argc, char *argv[] )
47 * {
48 * return Unit().run( argc, argv );
49 * }
50 *
51 @endcode
52 * The main function can contain other things, but using this one exactly
53 * makes all of the test suites work exactly the same. Using the optional
54 * setName at the top of the constructor replaces the class name with the
55 * chosen name when printing out stats and info.
56 */
57 class UnitSuite
58 {
59 public:
60 UnitSuite();
61 UnitSuite( int iOptions );
62 virtual ~UnitSuite();
63
64 int run( int argc=0, char *argv[]=NULL );
65
66 Bu::File tempFile( Bu::String &sFileName );
67
68 typedef void (UnitSuite::*Test)();
69
70 class Failed
71 {
72 public:
73 Failed() : str(""), bFile( false ) { }
74 Failed( const String &s ) : str( s ), bFile( false ) { }
75 Failed( const String &s, const String &sFile, int nLine ) :
76 str( s ), sFile( sFile ), nLine( nLine ), bFile( true ) { }
77
78 String str;
79 String sFile;
80 int nLine;
81 bool bFile;
82 };
83
84 enum
85 {
86 optStopOnError = 0x000001
87 };
88
89 enum Expect
90 {
91 expectPass,
92 expectFail
93 };
94
95 protected:
96 void add( Test fTest, const Bu::String &sName, Expect e=expectPass );
97 void setName( const String &sName );
98
99 void dispProgress();
100 void setStepCount( int iSteps );
101 void incProgress( int iAmnt = 1 );
102 void setProgress( int iAmnt );
103
104 private:
105 int onListCases( Bu::Array<Bu::String> aParam );
106
107 private:
108 typedef struct TestInfo
109 {
110 String sName;
111 Test fTest;
112 Expect eExpect;
113 } TestInfo;
114
115 typedef Bu::List<TestInfo> TestList;
116 TestList lTests;
117 String sSuiteName;
118
119 int iOptions;
120
121 typedef Bu::List<Bu::String> StrList;
122 StrList lFileCleanup;
123 int iNameWidth;
124 int iStepCount;
125 int iProgress;
126 time_t tLastUpdate;
127 };
128
129Bu::Formatter &operator<<( Bu::Formatter &f, const Bu::UnitSuite::Expect &e );
130}
131
132#define addTest( fn ) add( static_cast<Bu::UnitSuite::Test>(&fn), #fn )
133#define unitTest( tst ) if( !(tst) ) \
134{ \
135 throw Bu::UnitSuite::Failed( #tst, __FILE__, __LINE__ ); \
136} else (void)0
137#define unitFailed( msg ) throw Bu::UnitSuite::Failed(msg, __FILE__, __LINE__)
138
139#endif
diff --git a/src/stable/util.cpp b/src/stable/util.cpp
new file mode 100644
index 0000000..6983dfd
--- /dev/null
+++ b/src/stable/util.cpp
@@ -0,0 +1,65 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/util.h"
9
10int Bu::getDaysInMonth( int iMonth, int iYear )
11{
12 if( iMonth > 11 )
13 {
14 iYear += iMonth/12;
15 iMonth = iMonth%12;
16 }
17 switch( iMonth )
18 {
19 case 0:
20 case 2:
21 case 4:
22 case 6:
23 case 7:
24 case 9:
25 case 11:
26 return 31;
27 break;
28
29 case 3:
30 case 5:
31 case 8:
32 case 10:
33 return 30;
34 break;
35
36 case 1:
37 if( iYear%400 == 0 )
38 return 29;
39 if( iYear%100 == 0 )
40 return 28;
41 if( iYear%4 == 0 )
42 return 29;
43 return 28;
44 break;
45
46 default:
47 return -1;
48 }
49}
50void Bu::memcpy( void *pDest, const void *pSrc, size_t iBytes )
51{
52#ifdef VALTEST
53 const char *src = (const char *)pSrc;
54 char *dest = (char *)pDest;
55 for( int j = 0; j < count; j++ )
56 {
57 *dest = *src;
58 dest++;
59 src++;
60 }
61#else
62 ::memcpy( pDest, pSrc, iBytes );
63#endif
64}
65
diff --git a/src/stable/util.h b/src/stable/util.h
new file mode 100644
index 0000000..691184d
--- /dev/null
+++ b/src/stable/util.h
@@ -0,0 +1,187 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_UTIL_H
9#define BU_UTIL_H
10
11#ifndef NULL
12# define NULL 0
13#endif
14
15/* I borrowed this from someone who borrowed it from glib who borrowed it
16 * from...
17 */
18#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
19# define DEPRECATED __attribute__((__deprecated__))
20#else
21# define DEPRECATED
22#endif /* __GNUC__ */
23
24#include <string.h>
25
26namespace Bu
27{
28 /**
29 * Swap the value of two variables, uses references, so it's pretty safe.
30 * Objects passed in must support a basic assignemnt operator (=);
31 *@param a Variable to recieve the value of parameter b
32 *@param b Variable to recieve the value of parameter a
33 */
34 template<typename item>
35 void swap( item &a, item &b )
36 {
37 item tmp = a;
38 a = b;
39 b = tmp;
40 }
41
42#ifdef WIN32
43 #warning: removing min and max win32 macros because of compile conflict
44 #undef min
45 #undef max
46#endif
47 /**
48 * Finds the lesser of the two objects, objects passed in must be
49 * less-than-comparable.
50 *@param a A value to test.
51 *@param b Another value to test.
52 *@returns A reference to the lesser of a or b.
53 */
54 template<typename item>
55 const item &min( const item &a, const item &b )
56 {
57 return a<b?a:b;
58 }
59
60 /**
61 * Finds the lesser of the two objects, objects passed in must be
62 * less-than-comparable.
63 *@param a A value to test.
64 *@param b Another value to test.
65 *@returns A reference to the lesser of a or b.
66 */
67 template<typename item>
68 item &min( item &a, item &b )
69 {
70 return a<b?a:b;
71 }
72
73 /**
74 * Finds the greater of the two objects, objects passed in must be
75 * less-than-comparable.
76 *@param a A value to test.
77 *@param b Another value to test.
78 *@returns A reference to the greater of a or b.
79 */
80 template<typename item>
81 const item &max( const item &a, const item &b )
82 {
83 return b<a?a:b;
84 }
85
86 /**
87 * Finds the greater of the two objects, objects passed in must be
88 * less-than-comparable.
89 *@param a A value to test.
90 *@param b Another value to test.
91 *@returns A reference to the greater of a or b.
92 */
93 template<typename item>
94 item &max( item &a, item &b )
95 {
96 return b<a?a:b;
97 }
98
99 /**
100 * Given three objects this finds the one between the other two.
101 *@param a A value to test.
102 *@param b Another value to test.
103 *@param c Yet another value to test.
104 *@returns A reference to the mid-value of a, b, and c.
105 */
106 template<typename item>
107 const item &mid( const item &a, const item &b, const item &c )
108 {
109 return min( max( a, b ), c );
110 }
111
112 /**
113 * Given three objects this finds the one between the other two.
114 *@param a A value to test.
115 *@param b Another value to test.
116 *@param c Yet another value to test.
117 *@returns A reference to the mid-value of a, b, and c.
118 */
119 template<typename item>
120 item &mid( item &a, item &b, item &c )
121 {
122 return min( max( a, b ), c );
123 }
124
125 //
126 // Basic comparison functors
127 //
128 /**
129 * Simple less-than comparison functor. Objects being used should be
130 * less-than-comparable.
131 */
132 template<typename item>
133 struct __basicLTCmp
134 {
135 bool operator()( const item &a, const item &b )
136 {
137 return a < b;
138 }
139 };
140
141 /**
142 * Simple greater-than comparison functor. Objects being used should be
143 * greater-than-comparable.
144 */
145 template<typename item>
146 struct __basicGTCmp
147 {
148 bool operator()( const item &a, const item &b )
149 {
150 return a > b;
151 }
152 };
153
154 /**
155 * As __basicLTCmp but dereferences the passed in pointers before comparing.
156 */
157 template<typename item>
158 struct __basicPtrLTCmp
159 {
160 bool operator()( const item &a, const item &b )
161 {
162 return *a < *b;
163 }
164 };
165
166 /**
167 * As __basicGTCmp but dereferences the passed in pointers before comparing.
168 */
169 template<typename item>
170 struct __basicPtrGTCmp
171 {
172 bool operator()( const item &a, const item &b )
173 {
174 return *a > *b;
175 }
176 };
177
178 /**
179 * Get the number of days in the month in the gregorian calendar, taking
180 * leap years into account.
181 */
182 int getDaysInMonth( int iMonth, int iYear );
183
184 void memcpy( void *pDest, const void *pSrc, size_t iBytes );
185};
186
187#endif
diff --git a/src/stable/variant.cpp b/src/stable/variant.cpp
new file mode 100644
index 0000000..5cdaa5b
--- /dev/null
+++ b/src/stable/variant.cpp
@@ -0,0 +1,99 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/variant.h"
9#include "bu/formatter.h"
10#include "bu/membuf.h"
11
12namespace Bu
13{
14 Formatter &operator<<( Formatter &f, const String &s );
15};
16
17Bu::VariantTypeRoot::VariantTypeRoot()
18{
19}
20
21Bu::VariantTypeRoot::~VariantTypeRoot()
22{
23}
24
25Bu::Variant::Variant() :
26 pCore( NULL )
27{
28}
29
30Bu::Variant::Variant( const Variant &v ) :
31 pCore( NULL )
32{
33 if( v.pCore )
34 {
35 pCore = v.pCore->clone();
36 }
37}
38
39Bu::Variant::Variant( const char *t ) :
40 pCore( NULL )
41{
42 set( Bu::String( t ) );
43}
44
45Bu::Variant::~Variant()
46{
47 if( pCore )
48 {
49 delete pCore;
50 pCore = NULL;
51 }
52}
53
54Bu::String Bu::Variant::toString() const
55{
56 Bu::MemBuf mb;
57 Bu::Formatter f( mb );
58 f << *this;
59 return mb.getString();
60}
61
62bool Bu::Variant::isSet() const
63{
64 return pCore != NULL;
65}
66
67const std::type_info &Bu::Variant::getType() const
68{
69 if( !pCore )
70 {
71 throw Bu::ExceptionBase("No data!");
72 }
73 return pCore->getType();
74}
75
76Bu::Variant &Bu::Variant::operator=( const Bu::Variant &rhs )
77{
78 if( pCore )
79 {
80 delete pCore;
81 pCore = NULL;
82 }
83 if( rhs.pCore )
84 {
85 pCore = rhs.pCore->clone();
86 }
87
88 return *this;
89}
90
91Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Variant &v )
92{
93 if( !v.pCore )
94 return f << "(null)";
95
96 v.pCore->format( f );
97 return f;
98}
99
diff --git a/src/stable/variant.h b/src/stable/variant.h
new file mode 100644
index 0000000..45e3339
--- /dev/null
+++ b/src/stable/variant.h
@@ -0,0 +1,236 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_VARIANT_H
9#define BU_VARIANT_H
10
11//#include <bu/string.h>
12#include <typeinfo>
13// #include <bu/formatter.h>
14
15#ifndef NULL
16#define NULL (0L)
17#endif
18
19#include "bu/exceptionbase.h"
20
21namespace Bu
22{
23 class String;
24 class Formatter;
25 class Variant;
26 /** @cond DEVEL */
27 template<class t> class VariantType;
28
29 class VariantTypeRoot
30 {
31 public:
32 VariantTypeRoot();
33 virtual ~VariantTypeRoot();
34
35 virtual const std::type_info &getType() const=0;
36 virtual VariantTypeRoot *clone() const=0;
37 virtual void format( Bu::Formatter &f ) const=0;
38 };
39
40 template<class t>
41 class VariantType : public VariantTypeRoot
42 {
43 friend class Variant;
44 private:
45 VariantType()
46 {
47 }
48
49 VariantType( const t &d ) :
50 data( d )
51 {
52 }
53
54 VariantType( const VariantType<t> &vt ) :
55 data( vt.data )
56 {
57 }
58
59 virtual ~VariantType()
60 {
61 }
62
63 public:
64 t &getData()
65 {
66 return data;
67 }
68
69 const t &getData() const
70 {
71 return data;
72 }
73
74 virtual void format( Formatter &f ) const
75 {
76 f << data;
77 }
78
79 virtual const std::type_info &getType() const
80 {
81 return typeid( data );
82 }
83
84 VariantType<t> operator=( const t &rhs )
85 {
86 data = rhs;
87
88 return *this;
89 }
90
91 virtual VariantTypeRoot *clone() const
92 {
93 return new VariantType<t>( *this );
94 }
95
96 private:
97 t data;
98 };
99 /** @endcond */
100
101 /**
102 * Store any data type and access it safely. Variant gives you a way to
103 * pass arbitrary data types around without having to worry about what
104 * type a variable is. It allows code to be easily extended and to manage
105 * data without having to know what type it is ahead of time.
106 *
107 * Because of the generic method that this class was implemented it may seem
108 * to have some drawbacks compared to other Variant classes you may have
109 * seen, however it is fairly easy to get it to do just about anything you
110 * may need. It is also very low overhead. On most compilers the class
111 * itself has only 3 words of overhead + the size of the variable you store
112 * in it. And, since many parts of it are templatized they can often be
113 * optimized quite a bit.
114 */
115 class Variant
116 {
117 friend Bu::Formatter &operator<<( Bu::Formatter &f, const Variant &v );
118 public:
119 Variant();
120 Variant( const Variant &v );
121 Variant( const char *t );
122 template<class t>
123 Variant( const t &v ) :
124 pCore( new VariantType<t>() )
125 {
126 (*dynamic_cast<VariantType<t> *>(pCore)) = v;
127 }
128 virtual ~Variant();
129
130 Bu::String toString() const;
131 bool isSet() const;
132 const std::type_info &getType() const;
133
134 Variant &operator=( const Variant &rhs );
135
136 template<class t>
137 Variant &operator=( const t &rhs )
138 {
139 if( pCore ) // && pCore->getType() != typeid(t) )
140 {
141 delete pCore;
142 pCore = NULL;
143 }
144 pCore = new VariantType<t>();
145 (*dynamic_cast<VariantType<t> *>(pCore)) = rhs;
146 return *this;
147 }
148
149 template<class t>
150 t &get()
151 {
152 if( !pCore )
153 {
154 throw Bu::ExceptionBase("No data!");
155 }
156 if( pCore->getType() != typeid(t) )
157 {
158 throw Bu::ExceptionBase("Invalid type conversion.");
159 }
160 return dynamic_cast<VariantType<t> *>(pCore)->getData();
161 }
162
163 template<class t>
164 t &get() const
165 {
166 if( !pCore )
167 {
168 throw Bu::ExceptionBase("No data!");
169 }
170 if( pCore->getType() != typeid(t) )
171 {
172 throw Bu::ExceptionBase("Invalid type conversion.");
173 }
174 return dynamic_cast<VariantType<t> *>(pCore)->getData();
175 }
176
177 template<class t>
178 void set( const t &val )
179 {
180 if( pCore && pCore->getType() != typeid(t) )
181 {
182 delete pCore;
183 pCore = NULL;
184 }
185 pCore = new VariantType<t>();
186 (*dynamic_cast<VariantType<t> *>(pCore)) = val;
187 }
188
189 template<class t>
190 bool isType() const
191 {
192 return pCore->getType() == typeid(t);
193 }
194
195 template<class t>
196 operator t()
197 {
198 if( !pCore )
199 {
200 throw Bu::ExceptionBase("No data!");
201 }
202 if( pCore->getType() != typeid(t) )
203 {
204 throw Bu::ExceptionBase("Invalid type conversion.");
205 }
206 return dynamic_cast<VariantType<t> *>(pCore)->getData();
207 }
208
209 template<class t>
210 operator t() const
211 {
212 if( !pCore )
213 {
214 throw Bu::ExceptionBase("No data!");
215 }
216 if( pCore->getType() != typeid(t) )
217 {
218 throw Bu::ExceptionBase("Invalid type conversion.");
219 }
220 return dynamic_cast<VariantType<t> *>(pCore)->getData();
221 }
222
223 private:
224 VariantTypeRoot *pCore;
225 };
226/*
227 template<class t>
228 Bu::Formatter &operator<<( Bu::Formatter &f, const VariantType<t> &vt )
229 {
230 return f << vt.getData;
231 }*/
232
233 Bu::Formatter &operator<<( Bu::Formatter &f, const Variant &v );
234};
235
236#endif