aboutsummaryrefslogtreecommitdiff
path: root/src/experimental
diff options
context:
space:
mode:
Diffstat (limited to 'src/experimental')
-rw-r--r--src/experimental/cache.cpp8
-rw-r--r--src/experimental/cache.h437
-rw-r--r--src/experimental/cachecalc.cpp8
-rw-r--r--src/experimental/cachecalc.h63
-rw-r--r--src/experimental/cachestore.cpp9
-rw-r--r--src/experimental/cachestore.h46
-rw-r--r--src/experimental/cachestorefiles.cpp9
-rw-r--r--src/experimental/cachestorefiles.h207
-rw-r--r--src/experimental/cachestoremyriad.cpp9
-rw-r--r--src/experimental/cachestoremyriad.h158
-rw-r--r--src/experimental/fastcgi.cpp372
-rw-r--r--src/experimental/fastcgi.h133
-rw-r--r--src/experimental/httpget.cpp126
-rw-r--r--src/experimental/httpget.h66
-rw-r--r--src/experimental/lexer.cpp40
-rw-r--r--src/experimental/lexer.h58
-rw-r--r--src/experimental/parser.cpp311
-rw-r--r--src/experimental/parser.h135
-rw-r--r--src/experimental/random.cpp0
-rw-r--r--src/experimental/random.h0
-rw-r--r--src/experimental/randombase.cpp0
-rw-r--r--src/experimental/randombase.h0
-rw-r--r--src/experimental/randombasic.cpp0
-rw-r--r--src/experimental/randombasic.h0
-rw-r--r--src/experimental/regex.cpp95
-rw-r--r--src/experimental/regex.h44
-rw-r--r--src/experimental/regexengine.cpp5
-rw-r--r--src/experimental/regexengine.h142
-rw-r--r--src/experimental/xmlreader.cpp173
-rw-r--r--src/experimental/xmlreader.h64
30 files changed, 2718 insertions, 0 deletions
diff --git a/src/experimental/cache.cpp b/src/experimental/cache.cpp
new file mode 100644
index 0000000..52bd9fc
--- /dev/null
+++ b/src/experimental/cache.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/cache.h"
diff --git a/src/experimental/cache.h b/src/experimental/cache.h
new file mode 100644
index 0000000..455cf1b
--- /dev/null
+++ b/src/experimental/cache.h
@@ -0,0 +1,437 @@
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_CACHE_H
9#define BU_CACHE_H
10
11// #include "bu/cptr.h"
12#include "bu/hash.h"
13#include "bu/list.h"
14#include "bu/cachestore.h"
15#include "bu/cachecalc.h"
16
17#include "bu/trace.h"
18
19namespace Bu
20{
21// template<class keytype, class obtype>
22// keytype __cacheGetKey( obtype *&pObj );
23 template<class keytype, class obtype>
24 keytype __cacheGetKey( const obtype *pObj )
25 {
26 return pObj->getKey();
27 }
28
29 template<class keytype, class obtype>
30 class Cache
31 {
32 public:
33 /**
34 * Cache Pointer - Provides access to data that is held within the
35 * cache. This provides safe, refcounting access to data stored in
36 * the cache, with support for lazy loading.
37 */
38 class Ptr
39 {
40 friend class Bu::Cache<keytype, obtype>;
41 private:
42 Ptr( Cache<keytype, obtype> *pCache, obtype *pData,
43 const keytype &kId ) :
44 pCache( pCache ),
45 pData( pData ),
46 kId( kId )
47 {
48 if( pCache )
49 pCache->incRef( kId );
50 }
51
52 Ptr( Cache<keytype, obtype> *pCache, const keytype &kId ) :
53 pCache( pCache ),
54 pData( NULL ),
55 kId( kId )
56 {
57 }
58
59 public:
60 Ptr( const Ptr &rSrc ) :
61 pCache( rSrc.pCache ),
62 pData( rSrc.pData ),
63 kId( rSrc.kId )
64 {
65 if( pCache && pData )
66 pCache->incRef( kId );
67 }
68
69 Ptr() :
70 pCache( 0 ),
71 pData( 0 )
72 {
73 }
74
75 virtual ~Ptr()
76 {
77 if( pCache && pData )
78 pCache->decRef( kId );
79 }
80
81 obtype &operator*()
82 {
83 checkPtr();
84 return *pData;
85 }
86
87 const obtype &operator*() const
88 {
89 checkPtr();
90 return *pData;
91 }
92
93 obtype *operator->()
94 {
95 checkPtr();
96 return pData;
97 }
98
99 const obtype *operator->() const
100 {
101 checkPtr();
102 return pData;
103 }
104
105 bool isValid() const
106 {
107 return pCache != NULL;
108 }
109
110 bool isBound() const
111 {
112 return pData != NULL;
113 }
114
115 bool isSet() const
116 {
117 return pCache != NULL;
118 }
119
120 const keytype &getKey() const
121 {
122 return kId;
123 }
124
125 void unbind()
126 {
127 if( pCache && pData )
128 pCache->decRef( kId );
129 pData = NULL;
130 }
131
132 void clear()
133 {
134 unbind();
135 pCache = NULL;
136 }
137
138 void unset()
139 {
140 clear();
141 }
142
143 Ptr &operator=( const Ptr &rRhs )
144 {
145 if( pCache && pData )
146 pCache->decRef( kId );
147 pCache = rRhs.pCache;
148 pData = rRhs.pData;
149 kId = rRhs.kId;
150 if( pCache && pData )
151 pCache->incRef( kId );
152 return *this;
153 }
154
155 bool operator==( const Ptr &rRhs ) const
156 {
157 return pCache == rRhs.pCache && kId == rRhs.kId;
158 }
159
160 bool operator!=( const Ptr &rRhs ) const
161 {
162 return pCache != rRhs.pCache || kId != rRhs.kId;
163 }
164
165 private:
166 void checkPtr() const
167 {
168 if( pCache && !pData )
169 {
170 pData = pCache->getRaw( kId );
171 pCache->incRef( kId );
172 }
173 }
174
175 private:
176 Bu::Cache<keytype, obtype> *pCache;
177 mutable obtype *pData;
178 mutable keytype kId;
179 };
180
181 private:
182 typedef Bu::CacheStore<keytype, obtype> Store;
183 typedef Bu::List<Store *> StoreList;
184 typedef Bu::CacheCalc<keytype, obtype> Calc;
185
186 typedef struct CacheEntry
187 {
188 obtype *pData;
189 int iRefs;
190 time_t tLastSync;
191 } CacheEntry;
192
193 typedef Bu::Hash<keytype, CacheEntry> CidHash;
194
195 public:
196 typedef keytype Key;
197 Cache( Calc *pCalc, Store *pStore ) :
198 pCalc( pCalc ),
199 pStore( pStore )
200 {
201 TRACE();
202 pCalc->setCache( this );
203 }
204
205 virtual ~Cache()
206 {
207 TRACE();
208
209 // Better safe than sorry, better try a sync before anything
210 // else happens.
211 sync();
212
213 // Cycle through and unload all objects from the system.
214 for( typename CidHash::iterator i = hEnt.begin();
215 i != hEnt.end(); i++ )
216 {
217 if( i.getValue().iRefs > 0 )
218 {
219 // TODO: Throw an error in this case? iRefs != 0 for an
220 // object when the Cache is destroyed.
221 throw Bu::ExceptionBase("iRefs not zero.");
222 }
223 pStore->unload(
224 i.getValue().pData,
225 i.getKey()
226 );
227 }
228 delete pCalc;
229 delete pStore;
230 }
231
232 Ptr insert( obtype *pData )
233 {
234 TRACE( pData );
235 if( pStore->has( __cacheGetKey<keytype, obtype>( pData ) ) )
236 throw Bu::ExceptionBase("Key already exists in cache.");
237 CacheEntry e = {pData, 0, 0};
238 keytype k = pStore->create( pData );
239 hEnt.insert( k, e );
240
241 pCalc->onLoad( pData, k );
242
243 pStore->sync();
244
245 return Ptr( this, pData, k );
246 }
247
248 bool has( const keytype &cId )
249 {
250 return hEnt.has( cId ) || pStore->has( cId );
251 }
252
253 /**
254 * Retrieve an object from the cache and return a pointer to it.
255 * The object returned may be loaded from backend storage if needed,
256 * or the currently live object will be returned.
257 *@param cId The id of the object to load.
258 *@returns A pointer to the object.
259 */
260 Ptr get( const keytype &cId )
261 {
262 TRACE( cId );
263 try {
264 return Ptr( this, hEnt.get( cId ).pData, cId );
265 }
266 catch( Bu::HashException &e ) {
267 CacheEntry e = {pStore->load( cId ), 0, time( NULL )};
268 pCalc->onLoad( e.pData, cId );
269 hEnt.insert( cId, e );
270 return Ptr( this, e.pData, cId );
271 }
272 }
273
274 /**
275 * Retrieve a handle to an object without loading it now. This function
276 * will return a pointer that has not yet been "realized" but can be
277 * used normally. Upon initial use in any way the object will be
278 * loaded from the cache, either linking against the already loaded
279 * object or loading it fresh from the backend storage. The advantage
280 * of this is that you recieve a usable handle to the data, but it
281 * does not count as a reference yet, meaning that the data is loaded
282 * when you need it, not before.
283 */
284 Ptr getLazy( const keytype &cId )
285 {
286 TRACE( cId );
287 return Ptr( this, cId );
288 }
289
290 int getRefCount( const keytype &cId )
291 {
292 TRACE( cId );
293 return hEnt.get( cId ).iRefs;
294 }
295
296 void unload( const keytype &cId )
297 {
298 TRACE( cId );
299 try {
300 if( hEnt.get( cId ).iRefs > 0 )
301 {
302 printf("Shouldn't unload, references still exist!\n");
303 return;
304 }
305 }
306 catch( Bu::HashException &e ) {
307 // It's not here? Eh, return.
308 return;
309 }
310 obtype *pObj = hEnt.get( cId ).pData;
311 pCalc->onUnload( pObj, cId );
312 hEnt.erase( cId );
313
314 // The unload has to happen last just in case cId is a reference
315 // to data that is about to be deleted from memory by the unload.
316 pStore->unload( pObj, cId );
317 }
318
319 void erase( const keytype &cId )
320 {
321 TRACE( cId );
322 try {
323 if( hEnt.get( cId ).iRefs > 0 )
324 {
325 printf("Shouldn't erase, references still exist!\n");
326 return;
327 }
328
329 obtype *pObj = hEnt.get( cId ).pData;
330 pCalc->onDestroy( pObj, cId );
331 hEnt.erase( cId );
332
333 pStore->destroy( pObj, cId );
334 pStore->sync();
335 }
336 catch( Bu::HashException &e ) {
337 pCalc->onDestroy( cId );
338
339 if( hEnt.has( cId ) )
340 {
341 // The object was loaded by onDestroy
342 erase( cId );
343 }
344 else
345 {
346 pStore->destroy( cId );
347 pStore->sync();
348 }
349 }
350 }
351
352 typedef Bu::List<keytype> KeyList;
353 KeyList getKeys()
354 {
355 return pStore->getKeys();
356 }
357
358 KeyList getActiveKeys()
359 {
360 return hEnt.getKeys();
361 }
362
363 int getSize()
364 {
365 return pStore->getSize();
366 }
367
368 /**
369 * Make sure all currently loaded but not-in-use objects are synced to
370 * the store.
371 */
372 void sync()
373 {
374 TRACE();
375 int iSynced = 0;
376 for( typename CidHash::iterator i = hEnt.begin();
377 i != hEnt.end(); i++ )
378 {
379 if( i.getValue().iRefs == 0 )
380 {
381 if( pCalc->shouldSync(
382 i.getValue().pData,
383 i.getKey(),
384 i.getValue().tLastSync
385 ) )
386 {
387 pStore->sync(
388 i.getValue().pData,
389 i.getKey()
390 );
391 iSynced++;
392 i.getValue().tLastSync = time( NULL );
393 }
394 }
395 }
396 if( iSynced > 0 )
397 {
398 pStore->sync();
399 }
400 }
401
402 private:
403 void incRef( const keytype &cId )
404 {
405 TRACE( cId );
406 hEnt.get( cId ).iRefs++;
407 }
408
409 void decRef( const keytype &cId )
410 {
411 TRACE( cId );
412 CacheEntry &e = hEnt.get( cId );
413 e.iRefs--;
414 }
415
416 obtype *getRaw( const keytype &cId )
417 {
418 TRACE( cId );
419 try {
420 return hEnt.get( cId ).pData;
421 }
422 catch( Bu::HashException &e ) {
423 CacheEntry e = {pStore->load( cId ), 0, time( NULL )};
424 pCalc->onLoad( e.pData, cId );
425 hEnt.insert( cId, e );
426 return e.pData;
427 }
428 }
429
430 private:
431 CidHash hEnt;
432 Calc *pCalc;
433 Store *pStore;
434 };
435};
436
437#endif
diff --git a/src/experimental/cachecalc.cpp b/src/experimental/cachecalc.cpp
new file mode 100644
index 0000000..7b8a10a
--- /dev/null
+++ b/src/experimental/cachecalc.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/cachecalc.h"
diff --git a/src/experimental/cachecalc.h b/src/experimental/cachecalc.h
new file mode 100644
index 0000000..89cfadc
--- /dev/null
+++ b/src/experimental/cachecalc.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_CACHE_CALC_H
9#define BU_CACHE_CALC_H
10
11#include "bu/trace.h"
12
13#include <time.h>
14
15namespace Bu
16{
17 template<class keytype, class obtype> class Cache;
18
19 template<class keytype, class obtype>
20 class CacheCalc
21 {
22 friend class Cache<keytype, obtype>;
23 private:
24 typedef Cache<keytype, obtype> MyCache;
25 public:
26 CacheCalc() :
27 pCache( (MyCache *)0 )
28 {
29 TRACE();
30 }
31
32 virtual ~CacheCalc()
33 {
34 TRACE();
35 }
36
37 virtual void onLoad( obtype *pSrc, const keytype &key )=0;
38 virtual void onUnload( obtype *pSrc, const keytype &key )=0;
39 virtual void onDestroy( obtype *pSrc, const keytype &key )=0;
40 virtual void onDestroy( const keytype &key )=0;
41 virtual bool shouldSync( obtype *pSrc, const keytype &key,
42 time_t tLastSync )=0;
43 virtual void onTick() { };
44
45 protected:
46 MyCache *getCache()
47 {
48 TRACE();
49 return pCache;
50 }
51
52 private:
53 void setCache( MyCache *pCache )
54 {
55 TRACE();
56 this->pCache = pCache;
57 }
58
59 MyCache *pCache;
60 };
61};
62
63#endif
diff --git a/src/experimental/cachestore.cpp b/src/experimental/cachestore.cpp
new file mode 100644
index 0000000..af49548
--- /dev/null
+++ b/src/experimental/cachestore.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/cachestore.h"
9
diff --git a/src/experimental/cachestore.h b/src/experimental/cachestore.h
new file mode 100644
index 0000000..d0d91a2
--- /dev/null
+++ b/src/experimental/cachestore.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_CACHE_STORE_H
9#define BU_CACHE_STORE_H
10
11#include "bu/list.h"
12
13namespace Bu
14{
15 /**
16 * Handles I/O for data in the cache. This also assigns ID's to the newly
17 * created objects that are requested through this system.
18 */
19 template<class keytype, class obtype>
20 class CacheStore
21 {
22 public:
23 CacheStore()
24 {
25 }
26
27 virtual ~CacheStore()
28 {
29 }
30
31 virtual obtype *load( const keytype &key )=0;
32 virtual void unload( obtype *pObj, const keytype &key )=0;
33 virtual keytype create( obtype *pSrc )=0;
34 virtual void sync()=0;
35 virtual void sync( obtype *pObj, const keytype &key )=0;
36 virtual void destroy( obtype *pObj, const keytype &key )=0;
37 virtual void destroy( const keytype &key )=0;
38 virtual bool has( const keytype &key )=0;
39 virtual Bu::List<keytype> getKeys() { return Bu::List<keytype>(); }
40 virtual int getSize() { return -1; }
41
42 private:
43 };
44};
45
46#endif
diff --git a/src/experimental/cachestorefiles.cpp b/src/experimental/cachestorefiles.cpp
new file mode 100644
index 0000000..66ce672
--- /dev/null
+++ b/src/experimental/cachestorefiles.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/cachestorefiles.h"
9
diff --git a/src/experimental/cachestorefiles.h b/src/experimental/cachestorefiles.h
new file mode 100644
index 0000000..10b2c1b
--- /dev/null
+++ b/src/experimental/cachestorefiles.h
@@ -0,0 +1,207 @@
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_CACHE_STORE_FILES_H
9#define BU_CACHE_STORE_FILES_H
10
11#include "bu/string.h"
12#include "bu/file.h"
13#include "bu/cachestore.h"
14#include "bu/archive.h"
15#include "bu/membuf.h"
16#include "bu/formatter.h"
17#include "bu/sio.h"
18
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <dirent.h>
22#include <unistd.h>
23
24namespace Bu
25{
26 template<class keytype, class obtype>
27 keytype __cacheGetKey( const obtype *pObj );
28
29 template<class keytype, class obtype>
30 obtype *__cacheStoreFilesAlloc( const keytype &key )
31 {
32 return new obtype();
33 }
34
35 template<class keytype, class obtype>
36 void __cacheStoreFilesStore( Bu::Stream &s, obtype &rObj,
37 const keytype & )
38 {
39 Bu::Archive ar( s, Bu::Archive::save );
40 ar << rObj;
41 }
42
43 template<class keytype, class obtype>
44 obtype *__cacheStoreFilesLoad( Bu::Stream &s, const keytype &key )
45 {
46 obtype *pObj = __cacheStoreFilesAlloc<keytype, obtype>( key );
47 Bu::Archive ar( s, Bu::Archive::load );
48 ar >> (*pObj);
49 return pObj;
50 }
51
52 template<class keytype, class obtype>
53 class CacheStoreFiles : public CacheStore<keytype, obtype>
54 {
55 public:
56 CacheStoreFiles( const Bu::String &sPrefix ) :
57 sPrefix( sPrefix )
58 {
59 if( access( sPrefix.getStr(), W_OK|R_OK|X_OK ) )
60 {
61 mkdir( sPrefix.getStr(), 0755 );
62 }
63 }
64
65 virtual ~CacheStoreFiles()
66 {
67 }
68
69 virtual obtype *load( const keytype &key )
70 {
71// try
72// {
73 Bu::MemBuf mb;
74 Bu::Formatter f( mb );
75 f << sPrefix << "/" << key;
76 Bu::File fIn( mb.getString(), Bu::File::Read );
77 obtype *pOb = __cacheStoreFilesLoad<keytype, obtype>( fIn, key );
78 return pOb;
79// }
80// catch( std::exception &e )
81// {
82// throw Bu::HashException( e.what() );
83// }
84 }
85
86 virtual void unload( obtype *pObj, const keytype & )
87 {
88 delete pObj;
89 }
90
91 virtual keytype create( obtype *pSrc )
92 {
93 keytype key = __cacheGetKey<keytype, obtype>( pSrc );
94 Bu::MemBuf mb;
95 Bu::Formatter f( mb );
96 f << sPrefix << "/" << key;
97
98 Bu::File fTouch( mb.getString(), Bu::File::WriteNew );
99
100 return key;
101 }
102
103 virtual void sync()
104 {
105 }
106
107 virtual void sync( obtype *pSrc, const keytype &key )
108 {
109 Bu::MemBuf mb;
110 Bu::Formatter f( mb );
111 f << sPrefix << "/" << key;
112
113 Bu::File fOut( mb.getString(), Bu::File::WriteNew );
114 __cacheStoreFilesStore<keytype, obtype>( fOut, *pSrc, key );
115 }
116
117 virtual void destroy( obtype *pObj, const keytype &key )
118 {
119 Bu::MemBuf mb;
120 Bu::Formatter f( mb );
121 f << sPrefix << "/" << key;
122
123 unlink( mb.getString().getStr() );
124 delete pObj;
125 }
126
127 virtual void destroy( const keytype &key )
128 {
129 Bu::MemBuf mb;
130 Bu::Formatter f( mb );
131 f << sPrefix << "/" << key;
132
133 unlink( mb.getString().getStr() );
134 }
135
136 virtual bool has( const keytype &key )
137 {
138 Bu::MemBuf mb;
139 Bu::Formatter f( mb );
140 f << sPrefix << "/";
141 Bu::String sBase = mb.getString();
142 f << key;
143
144 if( sBase == mb.getString() )
145 return false;
146
147 return access( mb.getString().getStr(), F_OK ) == 0;
148 }
149
150 virtual Bu::List<keytype> getKeys()
151 {
152 DIR *dir = opendir( sPrefix.getStr() );
153 struct dirent *de;
154 Bu::List<keytype> lKeys;
155
156 while( (de = readdir( dir ) ) )
157 {
158 if( de->d_type != DT_REG )
159 continue;
160
161 keytype tmp;
162 Bu::MemBuf mb( de->d_name );
163 Bu::Formatter f( mb );
164 try
165 {
166 Fmt fm;
167 fm.tokenize( false );
168 f << fm;
169 f >> tmp;
170 }
171 catch( Bu::ExceptionBase &e )
172 {
173 Bu::sio << "Parse error in dir-scan: " << e.what()
174 << Bu::sio.nl;
175 }
176 lKeys.append( tmp );
177 }
178 closedir( dir );
179
180 return lKeys;
181 }
182
183 virtual int getSize()
184 {
185 DIR *dir = opendir( sPrefix.getStr() );
186 struct dirent *de;
187 int iCount = 0;
188
189 while( (de = readdir( dir ) ) )
190 {
191 if( de->d_type != DT_REG )
192 continue;
193
194 iCount++;
195 }
196 closedir( dir );
197
198 return iCount;
199 }
200
201 private:
202 Bu::String sPrefix;
203 };
204
205};
206
207#endif
diff --git a/src/experimental/cachestoremyriad.cpp b/src/experimental/cachestoremyriad.cpp
new file mode 100644
index 0000000..9d00dce
--- /dev/null
+++ b/src/experimental/cachestoremyriad.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/cachestoremyriad.h"
9
diff --git a/src/experimental/cachestoremyriad.h b/src/experimental/cachestoremyriad.h
new file mode 100644
index 0000000..e632a82
--- /dev/null
+++ b/src/experimental/cachestoremyriad.h
@@ -0,0 +1,158 @@
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_CACHE_STORE_MYRIAD_H
9#define BU_CACHE_STORE_MYRIAD_H
10
11#include "bu/string.h"
12#include "bu/stream.h"
13#include "bu/myriad.h"
14#include "bu/cachestore.h"
15#include "bu/myriadstream.h"
16
17#include "bu/archive.h"
18
19namespace Bu
20{
21 template<class keytype, class obtype>
22 keytype __cacheGetKey( const obtype *pObj );
23
24 template<class keytype, class obtype>
25 obtype *__cacheStoreMyriadAlloc( const keytype &key )
26 {
27 return new obtype();
28 }
29
30 template<class keytype, class obtype>
31 void __cacheStoreMyriadStore( Bu::Stream &s, obtype &rObj,
32 const keytype & )
33 {
34 Bu::Archive ar( s, Bu::Archive::save );
35 ar << rObj;
36 }
37
38 template<class keytype, class obtype>
39 obtype *__cacheStoreMyriadLoad( Bu::Stream &s, const keytype &key )
40 {
41 obtype *pObj = __cacheStoreMyriadAlloc<keytype, obtype>( key );
42 Bu::Archive ar( s, Bu::Archive::load );
43 ar >> (*pObj);
44 return pObj;
45 }
46
47 template<class keytype, class obtype>
48 class CacheStoreMyriad : public CacheStore<keytype, obtype>
49 {
50 public:
51 CacheStoreMyriad( Bu::Stream &sArch,
52 int iBlockSize=512, int iPreAllocate=8 ) :
53 mStore( sArch, iBlockSize, iPreAllocate )
54 {
55 try
56 {
57 MyriadStream ns = mStore.openStream( 1 );
58 Bu::Archive ar( ns, Bu::Archive::load );
59 ar >> hId;
60 }
61 catch( Bu::MyriadException &e )
62 {
63 int iStream = mStore.createStream();
64 if( iStream != 1 )
65 throw Bu::ExceptionBase("That's...horrible...id = %d.\n\n",
66 iStream );
67 MyriadStream ns = mStore.openStream( 1 );
68 Bu::Archive ar( ns, Bu::Archive::save );
69 ar << hId;
70 }
71 }
72
73 virtual ~CacheStoreMyriad()
74 {
75 MyriadStream ns = mStore.openStream( 1 );
76 Bu::Archive ar( ns, Bu::Archive::save );
77 ar << hId;
78 }
79
80 virtual obtype *load( const keytype &key )
81 {
82 int iStream = hId.get( key );
83 MyriadStream ns = mStore.openStream( iStream );
84 obtype *pOb = __cacheStoreMyriadLoad<keytype, obtype>( ns, key );
85 return pOb;
86 }
87
88 virtual void unload( obtype *pObj, const keytype & )
89 {
90 delete pObj;
91 }
92
93 virtual keytype create( obtype *pSrc )
94 {
95 keytype key = __cacheGetKey<keytype, obtype>( pSrc );
96 int iStream = mStore.createStream();
97 hId.insert( key, iStream );
98 MyriadStream ns = mStore.openStream( iStream );
99 __cacheStoreMyriadStore<keytype, obtype>( ns, *pSrc, key );
100 ns.setSize( ns.tell() );
101 return key;
102 }
103
104 virtual void sync()
105 {
106 MyriadStream ns = mStore.openStream( 1 );
107 Bu::Archive ar( ns, Bu::Archive::save );
108 ar << hId;
109 ns.setSize( ns.tell() );
110 mStore.sync();
111 }
112
113 virtual void sync( obtype *pSrc, const keytype &key )
114 {
115 int iStream = hId.get( key );
116 MyriadStream ns = mStore.openStream( iStream );
117 __cacheStoreMyriadStore<keytype, obtype>( ns, *pSrc, key );
118 ns.setSize( ns.tell() );
119 }
120
121 virtual void destroy( obtype *pObj, const keytype &key )
122 {
123 int iStream = hId.get( key );
124 mStore.deleteStream( iStream );
125 hId.erase( key );
126 delete pObj;
127 }
128
129 virtual void destroy( const keytype &key )
130 {
131 int iStream = hId.get( key );
132 mStore.deleteStream( iStream );
133 hId.erase( key );
134 }
135
136 virtual bool has( const keytype &key )
137 {
138 return hId.has( key );
139 }
140
141 virtual Bu::List<keytype> getKeys()
142 {
143 return hId.getKeys();
144 }
145
146 virtual int getSize()
147 {
148 return hId.getSize();
149 }
150
151 private:
152 Myriad mStore;
153 typedef Bu::Hash<keytype, long> StreamHash;
154 StreamHash hId;
155 };
156};
157
158#endif
diff --git a/src/experimental/fastcgi.cpp b/src/experimental/fastcgi.cpp
new file mode 100644
index 0000000..2f9161e
--- /dev/null
+++ b/src/experimental/fastcgi.cpp
@@ -0,0 +1,372 @@
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/fastcgi.h"
9
10#ifndef WIN32
11 #include <arpa/inet.h>
12#endif
13
14#include <errno.h>
15#include <unistd.h>
16
17#include "bu/membuf.h"
18
19#include "bu/sio.h"
20using Bu::sio;
21using Bu::Fmt;
22
23Bu::FastCgi::FastCgi() :
24 pSrv( NULL ),
25 bRunning( true )
26{
27 pSrv = new Bu::TcpServerSocket( STDIN_FILENO, false );
28}
29
30Bu::FastCgi::FastCgi( int iPort ) :
31 pSrv( NULL ),
32 bRunning( true )
33{
34 pSrv = new Bu::TcpServerSocket( iPort );
35}
36
37Bu::FastCgi::~FastCgi()
38{
39}
40
41bool Bu::FastCgi::isEmbedded()
42{
43#ifndef WIN32
44 struct sockaddr name;
45 socklen_t namelen = sizeof(name);
46 if( getpeername( STDIN_FILENO, &name, &namelen ) != 0 &&
47 errno == ENOTCONN )
48 {
49 sio << "errno = " << errno << " (" << strerror( errno ) << ")" <<
50 sio.nl;
51 sio << "Socket found" << sio.nl;
52 return true;
53 }
54 else
55 {
56 sio << "errno = " << errno << " (" << strerror( errno ) << ")" <<
57 sio.nl;
58 sio << "No socket detected, running in standalone mode" << sio.nl;
59 return false;
60 }
61#else
62 #warning Bu::FastCgi::isEmbedded IS A STUB for WIN32!!!!
63 return false;
64#endif
65}
66
67void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::Record &r )
68{
69 int iRead = s.read( &r, sizeof(Record) );
70 if( iRead != sizeof(Record) )
71 throw Bu::TcpSocketException("Hey, the size %d is wrong for Record. (%s)",
72 iRead, strerror( errno ) );
73 r.uRequestId = ntohs( r.uRequestId );
74 r.uContentLength = ntohs( r.uContentLength );
75}
76
77void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::Record r )
78{
79// sio << "Out -> " << r << sio.nl;
80 r.uRequestId = htons( r.uRequestId );
81 r.uContentLength = htons( r.uContentLength );
82 s.write( &r, sizeof(Record) );
83}
84
85void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::BeginRequestBody &b )
86{
87 s.read( &b, sizeof(BeginRequestBody) );
88 b.uRole = ntohs( b.uRole );
89}
90
91void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::EndRequestBody b )
92{
93 b.uStatus = htonl( b.uStatus );
94 s.write( &b, sizeof(b) );
95}
96
97uint32_t Bu::FastCgi::readLen( Bu::TcpSocket &s, uint16_t &uRead )
98{
99 uint8_t uByte[4];
100 s.read( uByte, 1 );
101 uRead++;
102 if( uByte[0] >> 7 == 0 )
103 return uByte[0];
104
105 s.read( uByte+1, 3 );
106 uRead += 3;
107 return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]);
108}
109
110void Bu::FastCgi::readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uRead )
111{
112 uint32_t uName = readLen( s, uRead );
113 uint32_t uValue = readLen( s, uRead );
114 uRead += uName + uValue;
115 unsigned char *sName = new unsigned char[uName];
116 s.read( sName, uName );
117 Bu::String fsName( (char *)sName, uName );
118 delete[] sName;
119
120 if( uValue > 0 )
121 {
122 unsigned char *sValue = new unsigned char[uValue];
123 s.read( sValue, uValue );
124 Bu::String fsValue( (char *)sValue, uValue );
125 hParams.insert( fsName, fsValue );
126 delete[] sValue;
127 }
128 else
129 {
130 hParams.insert( fsName, "" );
131 }
132}
133
134bool Bu::FastCgi::hasChannel( int iChan )
135{
136 if( aChannel.getSize() < iChan )
137 return false;
138 if( aChannel[iChan-1] == NULL )
139 return false;
140 return true;
141}
142
143Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::FastCgi::Record &r )
144{
145 f << "[Ver=" << (uint32_t)r.uVersion <<
146 ", Type=" << (uint32_t)r.uType <<
147 ", Req=" << (uint32_t)r.uRequestId <<
148 ", clen=" << (uint32_t)r.uContentLength <<
149 ", plen=" << (uint32_t)r.uPaddingLength <<
150 ", resv=" << (uint32_t)r.uReserved <<
151 "]";
152 return f;
153}
154
155void Bu::FastCgi::run()
156{
157// sio << "sizeof(Bu::FastCgi::Record) = " << sizeof(Record) << sio.nl;
158 bRunning = true;
159 while( bRunning )
160 {
161 int iSock = pSrv->accept( 5 );
162 if( iSock < 0 )
163 continue;
164
165 Bu::TcpSocket s( iSock );
166 s.setBlocking( true );
167// sio << "Got connection, blocking? " << s.isBlocking() << sio.nl;
168 try
169 {
170 for(;;)
171 {
172 Record r;
173 memset( &r, 0, sizeof(r) );
174// try
175// {
176 read( s, r );
177// }
178// catch( Bu::ExceptionBase &e )
179// {
180// sio << "Error: " << e.what() << ", " << s.isOpen() <<
181// sio.nl;
182// continue;
183// }
184 Channel *pChan = NULL;
185 if( r.uRequestId > 0 )
186 {
187 if( !hasChannel( r.uRequestId ) &&
188 r.uType != typeBeginRequest )
189 {
190 sio << "Error, stream data without stream." << sio.nl;
191 sio << r << sio.nl;
192 if( r.uContentLength > 0 )
193 {
194 char *buf = new char[r.uContentLength];
195 sio << " (read " << s.read( buf, r.uContentLength )
196 << "/" << r.uContentLength << "):" << sio.nl;
197 sio.write( buf, r.uContentLength );
198 sio << sio.nl << sio.nl;
199 }
200 }
201 while( aChannel.getSize() < r.uRequestId )
202 aChannel.append( NULL );
203 if( r.uRequestId > 0 )
204 pChan = aChannel[r.uRequestId-1];
205 }
206
207// sio << "Record (id=" << r.uRequestId << ", len=" <<
208// r.uContentLength << ", pad=" <<
209// (unsigned int)r.uPaddingLength << "): ";
210// fflush( stdout );
211
212 switch( (RequestType)r.uType )
213 {
214 case typeBeginRequest:
215// sio << "Begin Request.";
216 {
217 BeginRequestBody b;
218 read( s, b );
219 if( pChan != NULL )
220 {
221 sio << "Error!!!" << sio.nl;
222 return;
223 }
224 pChan = aChannel[r.uRequestId-1] = new Channel();
225 }
226 break;
227
228 case typeParams:
229// sio << "Params.";
230 if( r.uContentLength == 0 )
231 {
232 pChan->uFlags |= chflgParamsDone;
233 }
234 else
235 {
236 uint16_t uUsed = 0;
237 while( uUsed < r.uContentLength )
238 {
239 readPair( s, pChan->hParams, uUsed );
240 }
241 }
242 break;
243
244 case typeStdIn:
245// sio << "StdIn.";
246 if( r.uContentLength == 0 )
247 {
248 pChan->uFlags |= chflgStdInDone;
249 }
250 else
251 {
252 char *buf = new char[r.uContentLength];
253 int iTotal = 0;
254 do
255 {
256 size_t iRead = s.read(
257 buf, r.uContentLength-iTotal );
258 iTotal += iRead;
259// sio << " (read " << iRead << " " << iTotal
260// << "/" << r.uContentLength << ")";
261 pChan->sStdIn.append( buf, iRead );
262 } while( iTotal < r.uContentLength );
263 delete[] buf;
264 }
265 break;
266
267 case typeData:
268// sio << "Data.";
269 if( r.uContentLength == 0 )
270 {
271 pChan->uFlags |= chflgDataDone;
272 }
273 else
274 {
275 char *buf = new char[r.uContentLength];
276 s.read( buf, r.uContentLength );
277 pChan->sData.append( buf, r.uContentLength );
278 delete[] buf;
279 }
280 break;
281
282 case typeStdOut:
283 case typeStdErr:
284 case typeEndRequest:
285 case typeAbortRequest:
286 case typeGetValuesResult:
287// sio << "Scary.";
288 // ??? we shouldn't get these.
289 break;
290
291 case typeGetValues:
292 break;
293 }
294
295// sio << sio.nl;
296
297 if( pChan )
298 {
299 if( pChan->uFlags == chflgAllDone )
300 {
301// sio << "All done, generating output." << sio.nl;
302 Bu::MemBuf mStdOut, mStdErr;
303 int iRet = onRequest(
304 pChan->hParams, pChan->sStdIn,
305 mStdOut, mStdErr
306 );
307
308 Bu::String &sStdOut = mStdOut.getString();
309 Bu::String &sStdErr = mStdErr.getString();
310
311 Record rOut;
312 memset( &rOut, 0, sizeof(rOut) );
313 rOut.uVersion = 1;
314 rOut.uRequestId = r.uRequestId;
315 rOut.uPaddingLength = 0;
316 rOut.uType = typeStdOut;
317 if( sStdOut.getSize() > 0 )
318 {
319 for( int iPos = 0; iPos < sStdOut.getSize();
320 iPos += 65528 )
321 {
322 int iSize = sStdOut.getSize()-iPos;
323 if( iSize > 65528 )
324 iSize = 65528;
325 rOut.uContentLength = iSize;
326 write( s, rOut );
327 s.write( sStdOut.getStr()+iPos, iSize );
328 }
329 }
330 rOut.uContentLength = 0;
331 write( s, rOut );
332
333 rOut.uType = typeStdErr;
334 if( sStdErr.getSize() > 0 )
335 {
336 for( int iPos = 0; iPos < sStdErr.getSize();
337 iPos += 65528 )
338 {
339 int iSize = sStdErr.getSize()-iPos;
340 if( iSize > 65528 )
341 iSize = 65528;
342 rOut.uContentLength = iSize;
343 write( s, rOut );
344 s.write( sStdErr.getStr()+iPos, iSize );
345 }
346 }
347 rOut.uContentLength = 0;
348 write( s, rOut );
349
350 rOut.uType = typeEndRequest;
351 rOut.uContentLength = 8;
352 write( s, rOut );
353
354 EndRequestBody b;
355 memset( &b, 0, sizeof(b) );
356 b.uStatus = iRet;
357 write( s, b );
358
359 delete pChan;
360 aChannel[r.uRequestId-1] = NULL;
361 }
362 }
363 }
364 }
365 catch( Bu::TcpSocketException &e )
366 {
367// sio << "Bu::SocketException: " << e.what() << sio.nl <<
368// "\tSocket open: " << s.isOpen() << sio.nl;
369 }
370 }
371}
372
diff --git a/src/experimental/fastcgi.h b/src/experimental/fastcgi.h
new file mode 100644
index 0000000..d290c40
--- /dev/null
+++ b/src/experimental/fastcgi.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_FAST_CGI_H
9#define BU_FAST_CGI_H
10
11#include "bu/string.h"
12#include "bu/hash.h"
13#include "bu/array.h"
14#include "bu/tcpsocket.h"
15#include "bu/tcpserversocket.h"
16
17namespace Bu
18{
19 class Stream;
20
21 class FastCgi
22 {
23 public:
24 FastCgi( int iPort );
25 FastCgi();
26 virtual ~FastCgi();
27
28 static bool isEmbedded();
29
30 typedef Bu::Hash<Bu::String, Bu::String> StrHash;
31 enum RequestType
32 {
33 typeBeginRequest = 1,
34 typeAbortRequest = 2,
35 typeEndRequest = 3,
36 typeParams = 4,
37 typeStdIn = 5,
38 typeStdOut = 6,
39 typeStdErr = 7,
40 typeData = 8,
41 typeGetValues = 9,
42 typeGetValuesResult = 10
43 };
44
45 enum Role
46 {
47 roleResponder = 1,
48 roleAuthorizer = 2,
49 roleFilter = 3
50 };
51
52 enum Flags
53 {
54 flagsKeepConn = 1
55 };
56
57 enum Status
58 {
59 statusRequestComplete = 0,
60 statusCantMpxConn = 1,
61 statusOverloaded = 2,
62 statusUnknownRole = 3
63 };
64
65 typedef struct {
66 uint8_t uVersion;
67 uint8_t uType;
68 uint16_t uRequestId;
69 uint16_t uContentLength;
70 uint8_t uPaddingLength;
71 uint8_t uReserved;
72 } Record;
73
74 typedef struct {
75 uint16_t uRole;
76 uint8_t uFlags;
77 uint8_t reserved[5];
78 } BeginRequestBody;
79
80 typedef struct {
81 uint32_t uStatus;
82 uint8_t uProtocolStatus;
83 uint8_t reserved[3];
84 } EndRequestBody;
85
86 typedef struct Channel {
87 Channel() : uFlags( 0 ) { }
88 StrHash hParams;
89 Bu::String sStdIn;
90 Bu::String sData;
91 uint8_t uFlags;
92 } Channel;
93
94 enum ChannelFlags
95 {
96 chflgParamsDone = 0x01,
97 chflgStdInDone = 0x02,
98 chflgDataDone = 0x04,
99
100 chflgAllDone = 0x03
101 };
102
103 virtual void run();
104
105 void stopRunning() { bRunning = false; }
106
107 virtual void onInit() { };
108 virtual int onRequest( const StrHash &hParams,
109 const Bu::String &sStdIn, Bu::Stream &sStdOut,
110 Bu::Stream &sStdErr )=0;
111 virtual void onUninit() { };
112
113 private:
114 void read( Bu::TcpSocket &s, Record &r );
115 void read( Bu::TcpSocket &s, BeginRequestBody &b );
116 uint32_t readLen( Bu::TcpSocket &s, uint16_t &uUsed );
117 void readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uUsed );
118
119 void write( Bu::TcpSocket &s, Record r );
120 void write( Bu::TcpSocket &s, EndRequestBody b );
121
122 bool hasChannel( int iChan );
123
124 private:
125 Bu::TcpServerSocket *pSrv;
126 bool bRunning;
127 Bu::Array<Channel *> aChannel;
128 };
129
130 Bu::Formatter &operator<<( Bu::Formatter &f, const Bu::FastCgi::Record &r );
131};
132
133#endif
diff --git a/src/experimental/httpget.cpp b/src/experimental/httpget.cpp
new file mode 100644
index 0000000..99492a2
--- /dev/null
+++ b/src/experimental/httpget.cpp
@@ -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#include "bu/httpget.h"
9
10Bu::HttpGet::HttpGet( const Bu::Url &uSrc, const Bu::String &sMethod ) :
11 uSrc( uSrc ),
12 sMethod( sMethod ),
13 sSrv( uSrc.getHost(), uSrc.getPort() )
14{
15 sSrv.write( sMethod + " " + uSrc.getFullPath() + " HTTP/1.1\r\n" );
16}
17
18Bu::HttpGet::~HttpGet()
19{
20}
21
22void Bu::HttpGet::close()
23{
24}
25
26void Bu::HttpGet::get()
27{
28 for( MimeHash::iterator i = hMimeOut.begin(); i; i++ )
29 {
30 sSrv.write( i.getKey() + ": " + i.getValue() + "\r\n" );
31 }
32 sSrv.write("\r\n", 2 );
33
34// sSrv.read(
35}
36
37Bu::size Bu::HttpGet::read( void * /*pBuf*/, Bu::size /*nBytes*/ )
38{
39 return 0;
40}
41
42Bu::size Bu::HttpGet::write( const void * /*pBuf*/, Bu::size /*nBytes*/ )
43{
44 return 0;
45}
46
47Bu::size Bu::HttpGet::tell()
48{
49 return 0;
50}
51
52void Bu::HttpGet::seek( Bu::size )
53{
54}
55
56void Bu::HttpGet::setPos( Bu::size )
57{
58}
59
60void Bu::HttpGet::setPosEnd( Bu::size )
61{
62}
63
64bool Bu::HttpGet::isEos()
65{
66 return false;
67}
68
69bool Bu::HttpGet::isOpen()
70{
71 return true;
72}
73
74void Bu::HttpGet::flush()
75{
76}
77
78bool Bu::HttpGet::canRead()
79{
80 return true;
81}
82
83bool Bu::HttpGet::canWrite()
84{
85 return false;
86}
87
88bool Bu::HttpGet::isReadable()
89{
90 return true;
91}
92
93bool Bu::HttpGet::isWritable()
94{
95 return false;
96}
97
98bool Bu::HttpGet::isSeekable()
99{
100 return false;
101}
102
103bool Bu::HttpGet::isBlocking()
104{
105 return true;
106}
107
108void Bu::HttpGet::setBlocking( bool /*bBlocking*/ )
109{
110}
111
112Bu::size Bu::HttpGet::getSize() const
113{
114 return 0;
115}
116
117Bu::size Bu::HttpGet::getBlockSize() const
118{
119 return 0;
120}
121
122Bu::String Bu::HttpGet::getLocation() const
123{
124 return uSrc.getUrl();
125}
126
diff --git a/src/experimental/httpget.h b/src/experimental/httpget.h
new file mode 100644
index 0000000..a58e8ac
--- /dev/null
+++ b/src/experimental/httpget.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_HTTP_GET_H
9#define BU_HTTP_GET_H
10
11#include "bu/stream.h"
12#include "bu/string.h"
13#include "bu/url.h"
14#include "bu/tcpsocket.h"
15#include "bu/hash.h"
16
17namespace Bu
18{
19 class HttpGet : public Bu::Stream
20 {
21 public:
22 HttpGet( const Bu::Url &uSrc, const Bu::String &sMethod="GET" );
23 virtual ~HttpGet();
24
25 void get();
26
27 // From Bu::Stream
28 virtual void close();
29 virtual Bu::size read( void *pBuf, Bu::size nBytes );
30 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
31 using Stream::write;
32
33 virtual Bu::size tell();
34 virtual void seek( Bu::size offset );
35 virtual void setPos( Bu::size pos );
36 virtual void setPosEnd( Bu::size pos );
37 virtual bool isEos();
38 virtual bool isOpen();
39
40 virtual void flush();
41
42 virtual bool canRead();
43 virtual bool canWrite();
44
45 virtual bool isReadable();
46 virtual bool isWritable();
47 virtual bool isSeekable();
48
49 virtual bool isBlocking();
50 virtual void setBlocking( bool bBlocking=true );
51
52 virtual size getSize() const;
53 virtual size getBlockSize() const;
54 virtual Bu::String getLocation() const;
55
56 private:
57 Bu::Url uSrc;
58 Bu::String sMethod;
59 Bu::TcpSocket sSrv;
60 typedef Bu::Hash<Bu::String,Bu::String> MimeHash;
61 MimeHash hMimeIn;
62 MimeHash hMimeOut;
63 };
64};
65
66#endif
diff --git a/src/experimental/lexer.cpp b/src/experimental/lexer.cpp
new file mode 100644
index 0000000..185456a
--- /dev/null
+++ b/src/experimental/lexer.cpp
@@ -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#include "bu/lexer.h"
9#include "bu/membuf.h"
10#include "bu/formatter.h"
11
12Bu::Lexer::Lexer()
13{
14}
15
16Bu::Lexer::~Lexer()
17{
18}
19
20Bu::Lexer::Token::Token() :
21 iToken( -1 )
22{
23}
24
25Bu::Lexer::Token::Token( Bu::Lexer::TokenType iToken ) :
26 iToken( iToken )
27{
28}
29
30Bu::String Bu::Lexer::tokenToString( const Bu::Lexer::Token &t )
31{
32 Bu::MemBuf mb;
33 Bu::Formatter f( mb );
34 f << "<" << t.iToken << ">";
35 if( t.vExtra.isSet() )
36 f << " (" << t.vExtra << ")";
37
38 return mb.getString();
39}
40
diff --git a/src/experimental/lexer.h b/src/experimental/lexer.h
new file mode 100644
index 0000000..b057692
--- /dev/null
+++ b/src/experimental/lexer.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_LEXER_H
9#define BU_LEXER_H
10
11#include "bu/variant.h"
12
13namespace Bu
14{
15 class Stream;
16
17 /**
18 * The base class for creating a lexical analyzer. This is designed to work
19 * in tandem with the Bu::Parser class, which uses this to tokenize textual
20 * input. It can be used by just about anything that cares about tokens
21 * more than raw input, though.
22 */
23 class Lexer
24 {
25 public:
26 Lexer();
27 virtual ~Lexer();
28
29 typedef int TokenType;
30
31 class Token
32 {
33 public:
34 Token();
35 Token( TokenType iToken );
36
37 template<class t>
38 Token( TokenType iToken, const t &v ) :
39 iToken( iToken )//,
40// vExtra( v )
41 {
42 vExtra = v;
43 }
44 TokenType iToken;
45 Bu::Variant vExtra;
46 int iStartCol;
47 int iStartRow;
48 int iEndCol;
49 int iEndRow;
50 };
51
52 virtual Token *nextToken()=0;
53
54 virtual Bu::String tokenToString( const Token &t );
55 };
56};
57
58#endif
diff --git a/src/experimental/parser.cpp b/src/experimental/parser.cpp
new file mode 100644
index 0000000..4d9f793
--- /dev/null
+++ b/src/experimental/parser.cpp
@@ -0,0 +1,311 @@
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/parser.h"
9#include "bu/lexer.h"
10
11#include "bu/sio.h"
12using namespace Bu;
13
14Bu::Parser::Parser()
15{
16}
17
18Bu::Parser::~Parser()
19{
20}
21
22void Bu::Parser::pushLexer( Lexer *pLex )
23{
24 sLexer.push( pLex );
25}
26
27void Bu::Parser::popLexer()
28{
29 delete sLexer.peekPop();
30}
31
32Lexer::Token *Bu::Parser::popToken()
33{
34 return sToken.peekPop();
35}
36
37void Bu::Parser::pushToken( Lexer::Token *pTok )
38{
39 sToken.push( pTok );
40}
41
42void Bu::Parser::parse()
43{
44 int iCurNt = iRootNonTerminal;
45 Lexer::Token *ptCur = sLexer.peek()->nextToken();
46 sio << "Token(a): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl;
47 selectProduction( iCurNt, ptCur );
48
49 while( !sState.isEmpty() )
50 {
51 switch( (*sState.peek()).eType )
52 {
53 case State::typeTerminal:
54 sio << "terminal: " << ptCur->iToken << " == "
55 << (*sState.peek()).iIndex << sio.nl;
56 if( ptCur->iToken == (*sState.peek()).iIndex )
57 {
58 advanceState();
59 delete ptCur;
60 ptCur = sLexer.peek()->nextToken();
61 sio << "Token(b): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl;
62 }
63 else
64 {
65 throw Bu::ExceptionBase("Error parsing code.");
66 }
67 break;
68
69 case State::typeTerminalPush:
70 sio << "terminalpush: " << ptCur->iToken << " == "
71 << (*sState.peek()).iIndex << sio.nl;
72 if( ptCur->iToken == (*sState.peek()).iIndex )
73 {
74 advanceState();
75 sToken.push( ptCur );
76
77 ptCur = sLexer.peek()->nextToken();
78 sio << "Token(c): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl;
79 }
80 else
81 {
82 throw Bu::ExceptionBase("Error parsing code.");
83 }
84 break;
85
86 case State::typeNonTerminal:
87 sio << "nonterminal: " << ptCur->iToken << " --> "
88 << (*sState.peek()).iIndex << sio.nl;
89 {
90 int iNt = (*sState.peek()).iIndex;
91 sio << "Current state: " << *sState.peek() << sio.nl;
92 if( !selectProduction( iNt, ptCur ) )
93 {
94 throw Bu::ExceptionBase("Error parsing code.");
95 }
96 }
97 break;
98
99 case State::typeReduction:
100 sio << "reduction" << sio.nl;
101 aReduction[(*sState.peek()).iIndex]( *this );
102 advanceState();
103 break;
104 }
105 }
106}
107
108bool Bu::Parser::selectProduction( int iNt, Lexer::Token *ptCur )
109{
110 NonTerminal &nt = aNonTerminal[iNt];
111 int j = 0;
112 for( NonTerminal::ProductionList::iterator i = nt.lProduction.begin();
113 i; i++,j++ )
114 {
115 if( (*i).isEmpty() )
116 continue;
117 sio << "-->(Attempting production " << iNt << ":" << j << ": "
118 << (*i).first() << ")" << sio.nl;
119 if( (*i).first().eType == State::typeTerminal ||
120 (*i).first().eType == State::typeTerminalPush )
121 {
122 if( (*i).first().iIndex == ptCur->iToken )
123 {
124 sState.push( (*i).begin() );
125 sio.incIndent();
126 sio << "Pushing production " << j << " from nt " << iNt
127 << sio.nl;
128 return true;
129 }
130 }
131 else if( (*i).first().eType == State::typeNonTerminal )
132 {
133 sState.push( (*i).begin() );
134 sio.incIndent();
135 sio << "Pushing production " << j << " from nt " << iNt
136 << " as test." << sio.nl;
137 if( !selectProduction( (*i).first().iIndex, ptCur ) )
138 {
139 sio.decIndent();
140 sState.pop();
141 sio << "Production " << j << " from nt " << iNt
142 << " didn't work out." << sio.nl;
143 }
144 else
145 {
146 return true;
147 }
148 }
149 }
150 if( nt.bCanSkip )
151 {
152 sio << "Nothing matches, skipping non-terminal." << sio.nl;
153 advanceState();
154 return true;
155 }
156 sio << "-->(Found nothing)" << sio.nl;
157 return false;
158}
159
160void Bu::Parser::advanceState()
161{
162 if( sState.isEmpty() )
163 return;
164
165 sState.peek()++;
166 if( !sState.peek() )
167 {
168 sio.decIndent();
169 sState.pop();
170 sio << "State advanced, End of production." << sio.nl;
171 advanceState();
172 return;
173 }
174 sio << "State advanced, now: " << *(sState.peek()) << sio.nl;
175}
176
177void Bu::Parser::setRootNonTerminal( int iRoot )
178{
179 iRootNonTerminal = iRoot;
180}
181
182void Bu::Parser::setRootNonTerminal( const Bu::String &sRoot )
183{
184 setRootNonTerminal( hNonTerminalName.get( sRoot ) );
185}
186
187int Bu::Parser::addNonTerminal( const Bu::String &sName, NonTerminal &nt )
188{
189 int iId = aNonTerminal.getSize();
190 aNonTerminal.append( nt );
191 hNonTerminalName.insert( sName, iId );
192 sio << "nt '" << sName << "' = " << iId << sio.nl;
193 return iId;
194}
195
196int Bu::Parser::addNonTerminal( const Bu::String &sName )
197{
198 int iId = aNonTerminal.getSize();
199 aNonTerminal.append( NonTerminal() );
200 hNonTerminalName.insert( sName, iId );
201 sio << "nt '" << sName << "' = " << iId << sio.nl;
202 return iId;
203}
204
205void Bu::Parser::setNonTerminal( const Bu::String &sName, NonTerminal &nt )
206{
207 aNonTerminal[hNonTerminalName.get(sName)] = nt;
208}
209
210int Bu::Parser::getNonTerminalId( const Bu::String &sName )
211{
212 return hNonTerminalName.get( sName );
213}
214
215bool Bu::Parser::hasNonTerminal( const Bu::String &sName )
216{
217 return hNonTerminalName.has( sName );
218}
219
220int Bu::Parser::addReduction( const Bu::String &sName, const Reduction &r )
221{
222 int iId = aReduction.getSize();
223 aReduction.append( r );
224 hReductionName.insert( sName, iId );
225 return iId;
226}
227
228int Bu::Parser::addReduction( const Bu::String &sName )
229{
230 int iId = aReduction.getSize();
231 aReduction.append( Reduction() );
232 hReductionName.insert( sName, iId );
233 return iId;
234}
235
236void Bu::Parser::setReduction( const Bu::String &sName, const Reduction &r )
237{
238 aReduction[hReductionName.get(sName)] = r;
239}
240
241int Bu::Parser::getReductionId( const Bu::String &sName )
242{
243 return hReductionName.get( sName );
244}
245
246bool Bu::Parser::hasReduction( const Bu::String &sName )
247{
248 return hReductionName.has( sName );
249}
250
251//
252// Bu::Parser::State
253//
254
255Bu::Parser::State::State( Bu::Parser::State::Type eType, int iIndex ) :
256 eType( eType ),
257 iIndex( iIndex )
258{
259}
260
261Bu::Parser::State::~State()
262{
263}
264
265//
266// Bu::Parser::NonTerminal
267//
268
269Bu::Parser::NonTerminal::NonTerminal() :
270 bCanSkip( false )
271{
272}
273
274Bu::Parser::NonTerminal::~NonTerminal()
275{
276}
277
278void Bu::Parser::NonTerminal::addProduction( Production p )
279{
280 lProduction.append( p );
281}
282
283void Bu::Parser::NonTerminal::setCanSkip()
284{
285 bCanSkip = true;
286}
287
288Bu::Formatter &Bu::operator<<( Bu::Formatter &f, Bu::Parser::State::Type t )
289{
290 switch( t )
291 {
292 case Bu::Parser::State::typeTerminal:
293 return f << "typeTerminal";
294
295 case Bu::Parser::State::typeTerminalPush:
296 return f << "typeTerminalPush";
297
298 case Bu::Parser::State::typeNonTerminal:
299 return f << "typeNonTerminal";
300
301 case Bu::Parser::State::typeReduction:
302 return f << "typeReduction";
303 }
304 return f << "***error***";
305}
306
307Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Parser::State &s )
308{
309 return f << "{" << s.eType << ": " << s.iIndex << "}";
310}
311
diff --git a/src/experimental/parser.h b/src/experimental/parser.h
new file mode 100644
index 0000000..a168c7b
--- /dev/null
+++ b/src/experimental/parser.h
@@ -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#ifndef BU_PARSER_H
9#define BU_PARSER_H
10
11#include "bu/string.h"
12#include "bu/list.h"
13#include "bu/array.h"
14#include "bu/hash.h"
15#include "bu/signals.h"
16
17#include "bu/lexer.h"
18
19namespace Bu
20{
21 /**
22 * The base framework for a LR(1) grammar parser. Provided a proper set of
23 * ParserStates this will prase any input the lexer can provide.
24 */
25 class Parser
26 {
27 public:
28 Parser();
29 virtual ~Parser();
30
31 /**
32 * When a Lexer is pushed onto the stack it becomes the source for
33 * future tokens read by the parser until it is popped off the stack.
34 * The Parser takes ownership of every Lexer pushed onto the stack,
35 * and will delete it when it is popped off the stack.
36 */
37 void pushLexer( Lexer *pLex );
38
39 /**
40 * Pop a lexer off the stack, and delete it.
41 */
42 void popLexer();
43
44 Lexer::Token *popToken();
45 void pushToken( Lexer::Token *pTok );
46
47 /**
48 * Execute a parse.
49 */
50 void parse();
51
52 void setRootNonTerminal( int iRoot );
53 void setRootNonTerminal( const Bu::String &sRoot );
54
55 typedef Bu::Signal1<void, Parser &> Reduction;
56
57 /**
58 * Represents a possible state, either a terminal or non-terminal symbol
59 * in a Production.
60 */
61 class State
62 {
63 public:
64 enum Type
65 {
66 typeTerminal,
67 typeTerminalPush,
68 typeNonTerminal,
69 typeReduction
70 };
71
72 State( Type eType, int iIndex );
73 virtual ~State();
74
75 //private:
76 Type eType;
77 int iIndex;
78 };
79
80 typedef Bu::List<State> Production;
81
82 class NonTerminal
83 {
84 public:
85 NonTerminal();
86 virtual ~NonTerminal();
87
88 void addProduction( Production p );
89 void setCanSkip();
90
91// private:
92 typedef Bu::List<Production> ProductionList;
93 ProductionList lProduction;
94 bool bCanSkip;
95 };
96
97 int addNonTerminal( const Bu::String &sName, NonTerminal &nt );
98 int addNonTerminal( const Bu::String &sName );
99 void setNonTerminal( const Bu::String &sName, NonTerminal &nt );
100 int getNonTerminalId( const Bu::String &sName );
101 bool hasNonTerminal( const Bu::String &sName );
102
103 int addReduction( const Bu::String &sName, const Reduction &r );
104 int addReduction( const Bu::String &sName );
105 void setReduction( const Bu::String &sName, const Reduction &r );
106 int getReductionId( const Bu::String &sName );
107 bool hasReduction( const Bu::String &sName );
108
109 private:
110 bool selectProduction( int iNt, Lexer::Token *ptCur );
111 void advanceState();
112
113 private:
114 typedef Bu::List<Lexer *> LexerStack;
115 typedef Bu::List<Lexer::Token *> TokenStack;
116 typedef Bu::List<Production::const_iterator> StateStack;
117 typedef Bu::Array<Reduction> ReductionArray;
118 typedef Bu::Hash<Bu::String,int> NameIndexHash;
119 typedef Bu::Array<NonTerminal> NonTerminalArray;
120
121 LexerStack sLexer;
122 TokenStack sToken;
123 StateStack sState;
124 ReductionArray aReduction;
125 NameIndexHash hReductionName;
126 NonTerminalArray aNonTerminal;
127 NameIndexHash hNonTerminalName;
128 int iRootNonTerminal;
129 };
130Bu::Formatter &operator<<( Bu::Formatter &f, Bu::Parser::State::Type t );
131Bu::Formatter &operator<<( Bu::Formatter &f, const Bu::Parser::State &s );
132};
133
134
135#endif
diff --git a/src/experimental/random.cpp b/src/experimental/random.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/experimental/random.cpp
diff --git a/src/experimental/random.h b/src/experimental/random.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/experimental/random.h
diff --git a/src/experimental/randombase.cpp b/src/experimental/randombase.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/experimental/randombase.cpp
diff --git a/src/experimental/randombase.h b/src/experimental/randombase.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/experimental/randombase.h
diff --git a/src/experimental/randombasic.cpp b/src/experimental/randombasic.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/experimental/randombasic.cpp
diff --git a/src/experimental/randombasic.h b/src/experimental/randombasic.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/experimental/randombasic.h
diff --git a/src/experimental/regex.cpp b/src/experimental/regex.cpp
new file mode 100644
index 0000000..af0d364
--- /dev/null
+++ b/src/experimental/regex.cpp
@@ -0,0 +1,95 @@
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/regex.h"
9
10#include <regex.h> // Please, please include the system regex.h file
11
12#define re ((regex_t *)pRegEx)
13#define aSubStr ((regmatch_t *)paSubStr)
14
15Bu::RegEx::RegEx() :
16 pRegEx( NULL ),
17 bCompiled( false ),
18 paSubStr( NULL )
19{
20}
21
22Bu::RegEx::RegEx( const Bu::String &sSrc ) :
23 pRegEx( NULL ),
24 bCompiled( false ),
25 paSubStr( NULL )
26{
27 compile( sSrc );
28}
29
30Bu::RegEx::~RegEx()
31{
32 if( bCompiled )
33 {
34 regfree( re );
35 delete re;
36 delete[] aSubStr;
37 }
38}
39
40void Bu::RegEx::compile( const Bu::String &sSrc )
41{
42 if( bCompiled )
43 {
44 regfree( re );
45 delete re;
46 delete[] aSubStr;
47 bCompiled = false;
48 }
49 pRegEx = (void *)(new regex_t);
50
51 int nErr = regcomp( re, sSrc.getStr(), REG_EXTENDED|REG_NEWLINE );
52 if( nErr )
53 {
54 size_t length = regerror( nErr, re, NULL, 0 );
55 char *buffer = new char[length];
56 (void) regerror( nErr, re, buffer, length );
57 Bu::String s( buffer );
58 delete[] buffer;
59 throw "???"; // BuildException( s.getStr() );
60 }
61 bCompiled = true;
62 this->sSrc = sSrc;
63
64 nSubStr = re->re_nsub+1;
65 paSubStr = (void *)(new regmatch_t[nSubStr]);
66}
67
68int Bu::RegEx::getNumSubStrings()
69{
70 return nSubStr;
71}
72
73bool Bu::RegEx::execute( const Bu::String &sSrc )
74{
75 sTest = sSrc;
76 if( regexec( re, sSrc.getStr(), nSubStr, aSubStr, 0 ) )
77 return false;
78 return true;
79}
80
81void Bu::RegEx::getSubStringRange( int nIndex, int &iStart, int &iEnd )
82{
83 iStart = aSubStr[nIndex].rm_so;
84 iEnd = aSubStr[nIndex].rm_eo;
85}
86
87Bu::String Bu::RegEx::getSubString( int nIndex )
88{
89// regmatch_t *Subs = aSubStr;
90 return Bu::String(
91 sTest.getStr()+aSubStr[nIndex].rm_so,
92 aSubStr[nIndex].rm_eo - aSubStr[nIndex].rm_so
93 );
94}
95
diff --git a/src/experimental/regex.h b/src/experimental/regex.h
new file mode 100644
index 0000000..f0aa5d5
--- /dev/null
+++ b/src/experimental/regex.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_REG_EX_H
9#define BU_REG_EX_H
10
11#include "bu/string.h"
12
13#include <stdint.h>
14
15namespace Bu
16{
17 class RegEx
18 {
19 public:
20 RegEx();
21 RegEx( const Bu::String &sSrc );
22 virtual ~RegEx();
23
24 void compile( const Bu::String &sSrc );
25 int getNumSubStrings();
26 bool execute( const Bu::String &sSrc );
27 void getSubStringRange( int nIndex, int &iStart, int &iEnd );
28 Bu::String getSubString( int nIndex );
29 const Bu::String &getSource()
30 {
31 return sSrc;
32 }
33
34 private:
35 Bu::String sSrc;
36 Bu::String sTest;
37 void *pRegEx;
38 bool bCompiled;
39 int nSubStr;
40 void *paSubStr;
41 };
42};
43
44#endif
diff --git a/src/experimental/regexengine.cpp b/src/experimental/regexengine.cpp
new file mode 100644
index 0000000..72bc381
--- /dev/null
+++ b/src/experimental/regexengine.cpp
@@ -0,0 +1,5 @@
1#include "bu/regexengine.h"
2#include "bu/utfstring.h"
3
4template class Bu::RegExEngine<char>;
5template class Bu::RegExEngine<Bu::UtfChar>;
diff --git a/src/experimental/regexengine.h b/src/experimental/regexengine.h
new file mode 100644
index 0000000..ec181c1
--- /dev/null
+++ b/src/experimental/regexengine.h
@@ -0,0 +1,142 @@
1#ifndef BU_REG_EX_ENGINE_H
2#define BU_REG_EX_ENGINE_H
3
4#include "bu/sharedcore.h"
5#include "bu/array.h"
6#include "bu/sio.h"
7
8namespace Bu
9{
10 template<typename chr> class RegExEngine;
11
12 template<typename chr>
13 class RegExEngineCore
14 {
15 friend class RegExEngine<chr>;
16 friend class SharedCore<RegExEngine<chr>, RegExEngineCore<chr> >;
17 private:
18 RegExEngineCore()
19 {
20 }
21
22 virtual ~RegExEngineCore()
23 {
24 }
25
26 class Range
27 {
28 public:
29 Range( chr cLower, chr cUpper, int iTrgState ) :
30 cLower( cLower ), cUpper( cUpper ), iTrgState( iTrgState )
31 {
32 }
33
34 chr cLower;
35 chr cUpper;
36 int iTrgState;
37 };
38
39 class State
40 {
41 public:
42 Bu::Array<Range> aRange;
43 };
44
45 int addState()
46 {
47 aState.append( State() );
48 return aState.getSize()-1;
49 }
50
51 void addCompletion( int iState, chr cLower, chr cUpper, int iTrgState )
52 {
53 aState[iState].aRange.append( Range( cLower, cUpper, iTrgState ) );
54 }
55
56 template<typename str>
57 bool match( const str &sIn, int &iSize, int &iCompletion )
58 {
59 bool bMatch;
60 int iState = 0;
61 iSize = 0;
62 for( typename str::const_iterator i = sIn.begin(); i; i++ )
63 {
64 Bu::sio << "Finding char " << *i << " in state " << iState
65 << ":" << Bu::sio.nl;
66 bMatch = false;
67 for( typename Bu::Array<Range>::iterator j =
68 aState[iState].aRange.begin(); j; j++ )
69 {
70 Bu::sio << " Testing range " << (*j).cLower << " - " << (*j).cUpper << Bu::sio.nl;
71 if( *i >= (*j).cLower && *i <= (*j).cUpper )
72 {
73 iState = (*j).iTrgState;
74 bMatch = true;
75 iSize++;
76 if( iState < 0 )
77 {
78 iCompletion = iState;
79 return true;
80 }
81 }
82 }
83 if( bMatch == false )
84 {
85 return false;
86 }
87 }
88
89 iCompletion = 0;
90 return true;
91 }
92
93 typedef Bu::Array<State> StateArray;
94 StateArray aState;
95 };
96
97 template<typename chr>
98 class RegExEngine : public SharedCore<RegExEngine<chr>,
99 RegExEngineCore<chr> >
100 {
101 private:
102 typedef class RegExEngine<chr> MyType;
103 typedef class RegExEngineCore<chr> Core;
104 typedef class Core::Range Range;
105 typedef class Core::State State;
106
107 protected:
108 using SharedCore<MyType, Core>::core;
109 using SharedCore<MyType, Core>::_hardCopy;
110 using SharedCore<MyType, Core>::_resetCore;
111 using SharedCore<MyType, Core>::_allocateCore;
112
113 public:
114 RegExEngine()
115 {
116 }
117
118 virtual ~RegExEngine()
119 {
120 }
121
122 int addState()
123 {
124 return core->addState();
125 }
126
127 void addCompletion( int iState, chr cLower, chr cUpper, int iTrgState )
128 {
129 core->addCompletion( iState, cLower, cUpper, iTrgState );
130 }
131
132 template<typename str>
133 bool match( const str &sIn, int &iSize, int &iCompletion )
134 {
135 return core->match( sIn, iSize, iCompletion );
136 }
137
138 private:
139 };
140};
141
142#endif
diff --git a/src/experimental/xmlreader.cpp b/src/experimental/xmlreader.cpp
new file mode 100644
index 0000000..ba7fb3d
--- /dev/null
+++ b/src/experimental/xmlreader.cpp
@@ -0,0 +1,173 @@
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/xmlreader.h"
9#include "bu/stream.h"
10
11namespace Bu { subExceptionDef( XmlException ) }
12
13Bu::XmlReader::XmlReader( Stream &rInput ) :
14 rInput( rInput ),
15 iCurToken( 0 ),
16 iNextToken( 0 ),
17 bIgnoreWS( true )
18{
19 nextToken();
20 stDocument();
21}
22
23Bu::XmlReader::~XmlReader()
24{
25}
26
27void Bu::XmlReader::fillBuffer()
28{
29 if( rInput.isEos() )
30 return;
31 char buf[1024];
32 int iSize = rInput.read( buf, 1024 );
33 sBuf.append( buf, iSize );
34}
35
36void Bu::XmlReader::cleanupBuffer( int iUsed )
37{
38 for( int j = 0; j < iUsed; j++ )
39 {
40 if( sBuf[j] == '\n' )
41 {
42 spNextToken.iLine++;
43 spNextToken.iChar = 1;
44 }
45 else
46 {
47 spNextToken.iChar++;
48 }
49 }
50
51 printf("--Deleting %d bytes from front of buffer.\n", iUsed );
52 sBuf.trimFront( iUsed );
53}
54
55int Bu::XmlReader::nextToken()
56{
57 fillBuffer();
58
59 int iUsed = 1;
60
61 iCurToken = iNextToken;
62 spCurToken = spNextToken;
63
64 switch( sBuf[0] )
65 {
66 case '<':
67 if( !strncmp( sBuf.getStr(), "<?xml", 5 ) )
68 {
69 iNextToken = tokXmlDeclHead;
70 iUsed = 5;
71 }
72 else
73 {
74 iNextToken = '<';
75 }
76 break;
77
78 case '?':
79 if( sBuf[1] == '>' )
80 {
81 iNextToken = tokXmlDeclEnd;
82 iUsed = 2;
83 }
84 else
85 {
86 iNextToken = '?';
87 }
88 break;
89
90 case ' ':
91 case '\t':
92 case '\n':
93 case '\r':
94 for( int j = 1;; j++ )
95 {
96 if( j == sBuf.getSize() )
97 {
98 if( rInput.isEos() )
99 error("Reached end of input while waiting for whitespace to end.");
100
101 fillBuffer();
102 }
103 if( sBuf[j] == ' ' || sBuf[j] == '\t' ||
104 sBuf[j] == '\n' || sBuf[j] == '\r' )
105 iUsed++;
106 else
107 break;
108 }
109 sStr.clear();
110 sStr.append( sBuf, iUsed );
111 iNextToken = tokWS;
112 break;
113
114 case '=':
115 iNextToken = sBuf[0];
116 break;
117
118 default:
119 if( (sBuf[0] >= 'a' && sBuf[0] <= 'z') ||
120 (sBuf[0] >= 'A' && sBuf[0] <= 'Z') )
121 {
122 for( int j = 1;; j++ )
123 {
124 if( j == sBuf.getSize() )
125 {
126 if( rInput.isEos() )
127 error("Reached end of input while waiting for a string to end.");
128
129 fillBuffer();
130 }
131 if( (sBuf[j] >= 'a' && sBuf[j] <= 'z') ||
132 (sBuf[j] >= 'A' && sBuf[j] <= 'Z') )
133 iUsed++;
134 else
135 break;
136 }
137 sStr.clear();
138 sStr.append( sBuf, iUsed );
139 iNextToken = tokIdent;
140 }
141 }
142
143 cleanupBuffer( iUsed );
144
145 return iCurToken;
146}
147
148void Bu::XmlReader::error( const char *sMessage )
149{
150 throw Bu::XmlException("%d:%d: %s",
151 spCurToken.iLine, spCurToken.iChar, sMessage );
152}
153
154void Bu::XmlReader::stDocument()
155{
156 stProlog();
157}
158
159void Bu::XmlReader::stProlog()
160{
161 stXmlDecl();
162}
163
164void Bu::XmlReader::stXmlDecl()
165{
166 if( nextToken() != tokXmlDeclHead )
167 error("You must begin your xml file with a declaration: <?xml ... ?>");
168 if( nextToken() != tokIdent )
169 error("A version comes first!");
170 if( sStr != "version" )
171 error("No, a version!");
172}
173
diff --git a/src/experimental/xmlreader.h b/src/experimental/xmlreader.h
new file mode 100644
index 0000000..7cb44c9
--- /dev/null
+++ b/src/experimental/xmlreader.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_XML_READER_H
9#define BU_XML_READER_H
10
11#include "bu/string.h"
12#include "bu/exceptionbase.h"
13
14namespace Bu
15{
16 class Stream;
17
18 subExceptionDecl( XmlException );
19
20 class XmlReader
21 {
22 public:
23 XmlReader( Stream &rInput );
24 virtual ~XmlReader();
25
26 private:
27 Stream &rInput;
28 int iCurToken;
29 int iNextToken;
30 Bu::String sBuf;
31 Bu::String sStr;
32 bool bIgnoreWS;
33 typedef struct StreamPos
34 {
35 StreamPos() : iLine( 1 ), iChar( 1 ) { }
36 int iLine;
37 int iChar;
38 } StreamPos;
39 StreamPos spCurToken;
40 StreamPos spNextToken;
41
42
43 enum
44 {
45 tokXmlDeclHead = 0x100,
46 tokXmlDeclEnd,
47 tokWS,
48 tokIdent,
49 tokString
50 };
51
52 void fillBuffer();
53 void cleanupBuffer( int iUsed );
54 int nextToken();
55
56 void stDocument();
57 void stProlog();
58 void stXmlDecl();
59
60 void error( const char *sMessage );
61 };
62};
63
64#endif