aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.conf10
-rwxr-xr-xmkunit.sh34
-rw-r--r--src/fbasicstring.cpp9
-rw-r--r--src/fbasicstring.h1132
-rw-r--r--src/fstring.cpp8
-rw-r--r--src/fstring.h1111
-rw-r--r--src/unit/archive.cpp145
-rw-r--r--src/unit/archive.unit130
-rw-r--r--src/unit/array.cpp101
-rw-r--r--src/unit/array.unit80
-rw-r--r--src/unit/file.cpp117
-rw-r--r--src/unit/file.unit95
-rw-r--r--src/unit/fstring.cpp170
-rw-r--r--src/unit/fstring.unit140
-rw-r--r--src/unit/hash.cpp109
-rw-r--r--src/unit/hash.unit86
-rw-r--r--src/unit/membuf.cpp60
-rw-r--r--src/unit/membuf.unit45
-rw-r--r--src/unit/taf.cpp133
-rw-r--r--src/unit/taf.unit112
-rw-r--r--src/unit/xml.cpp39
-rw-r--r--src/unit/xml.unit20
-rw-r--r--src/unitsuite.cpp2
-rw-r--r--src/unitsuite.h8
24 files changed, 1911 insertions, 1985 deletions
diff --git a/build.conf b/build.conf
index 898d6d4..769fa31 100644
--- a/build.conf
+++ b/build.conf
@@ -49,7 +49,7 @@ filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"):
49 "tests/itoheap"]: 49 "tests/itoheap"]:
50 set "LDFLAGS" += "-lpthread" 50 set "LDFLAGS" += "-lpthread"
51 51
52filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"): 52filesIn("src/unit") filter regexp("^src/unit/(.*)\\.unit$", "unit/{re:1}"):
53 rule "exe", 53 rule "exe",
54 target file, 54 target file,
55 group "tests", 55 group "tests",
@@ -57,7 +57,7 @@ filesIn("src/unit") filter regexp("^src/unit/(.*)\\.cpp$", "unit/{re:1}"):
57 requires "libbu++.a", 57 requires "libbu++.a",
58 set "CXXFLAGS" += "-I.", 58 set "CXXFLAGS" += "-I.",
59 set "LDFLAGS" += "-L. -lbu++", 59 set "LDFLAGS" += "-L. -lbu++",
60 input "src/{target}.cpp" 60 input "src/{target}.unit"
61 61
62"tests/plugin": set "LDFLAGS" += "-ldl" 62"tests/plugin": set "LDFLAGS" += "-ldl"
63 63
@@ -79,6 +79,12 @@ rule "cpp":
79 requires commandToList("g++ -M {CXXFLAGS} {match}", "make"), 79 requires commandToList("g++ -M {CXXFLAGS} {match}", "make"),
80 perform command("g++ {CXXFLAGS} -c -o {target} {match}") 80 perform command("g++ {CXXFLAGS} -c -o {target} {match}")
81 81
82rule "unit":
83 matches regexp("(.*)\\.unit$"),
84 produces "{re:1}.cpp",
85 requires "mkunit.sh",
86 perform command("./mkunit.sh \"{match}\" \"{target}\"")
87
82rule "hln": 88rule "hln":
83 matches regexp("src/(.*)\\.h"), 89 matches regexp("src/(.*)\\.h"),
84 produces "bu/{re:1}.h", 90 produces "bu/{re:1}.h",
diff --git a/mkunit.sh b/mkunit.sh
new file mode 100755
index 0000000..867d6df
--- /dev/null
+++ b/mkunit.sh
@@ -0,0 +1,34 @@
1#!/bin/bash
2
3function mkfunc()
4{
5 echo "void $1() /**< expect ${2:-pass} */"
6}
7
8function mkadd()
9{
10 ex="expectPass"
11 if [ "$2" == "fail" ]; then
12 ex="expectFail"
13 fi
14 echo "\\\\tadd( static_cast<Bu::UnitSuite::Test>(\\&Unit::$1), \"$1\", Bu::UnitSuite::${ex} );\\\\n"
15}
16
17sedbits=""
18init="#include \"bu/unitsuite.h\"\\\\n\\\\nclass Unit : public Bu::UnitSuite\\\\n{\\\\npublic:\\\\n\\\\nUnit()\\\\n{\\\\n\\\\tsetName(\"${1%.*}\");\\\\n"
19for i in $(grep {% "$1"); do
20 sedbits="${sedbits}s@${i}@$(mkfunc $(echo $i | sed -e 's/.*{%\(.*\)}/\1/' -e 's/:/ /g'))@\n"
21 init="${init}$(mkadd $(echo $i | sed -e 's/.*{%\(.*\)}/\1/' -e 's/:/ /g'))"
22done
23
24init="${init}\\\\n}\\\\n\\\\nvirtual ~Unit() { }\\\\n\\\\n"
25
26sedbits="${sedbits}s@.*{=Init}@${init}@\n"
27
28temp=$(mktemp)
29echo -e "$sedbits" > $temp
30sed -f $temp $1 > $2
31echo -e "\n};\n\nint main( int argc, char *argv[] )\n{\n\treturn Unit().run( argc, argv );\n}\n" >> $2
32
33rm $temp
34
diff --git a/src/fbasicstring.cpp b/src/fbasicstring.cpp
new file mode 100644
index 0000000..6ef4893
--- /dev/null
+++ b/src/fbasicstring.cpp
@@ -0,0 +1,9 @@
1/*
2 * Copyright (C) 2007-2008 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 "fbasicstring.h"
9
diff --git a/src/fbasicstring.h b/src/fbasicstring.h
new file mode 100644
index 0000000..669784b
--- /dev/null
+++ b/src/fbasicstring.h
@@ -0,0 +1,1132 @@
1/*
2 * Copyright (C) 2007-2008 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_F_BASIC_STRING_H
9#define BU_F_BASIC_STRING_H
10
11#include <stdint.h>
12#include <memory>
13
14#ifndef WIN32
15#include <wordexp.h>
16#endif
17
18#include "bu/archival.h"
19#include "bu/archive.h"
20#include "bu/util.h"
21
22namespace Bu
23{
24 template< typename chr >
25 struct FStringChunk
26 {
27 long nLength;
28 chr *pData;
29 FStringChunk *pNext;
30 };
31 /**
32 * Flexible String class. This class was designed with string passing and
33 * generation in mind. Like the standard string class you can specify what
34 * datatype to use for each character. Unlike the standard string class,
35 * collection of appended and prepended terms is done lazily, making long
36 * operations that involve many appends very inexpensive. In addition
37 * internal ref-counting means that if you pass strings around between
38 * functions there's almost no overhead in time or memory since a reference
39 * is created and no data is actually copied. This also means that you
40 * never need to put any FBasicString into a ref-counting container class.
41 *
42 *@param chr (typename) Type of character (i.e. char)
43 *@param nMinSize (int) Chunk size (default: 256)
44 *@param chralloc (typename) Memory Allocator for chr
45 *@param chunkalloc (typename) Memory Allocator for chr chunks
46 */
47 template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
48 class FBasicString : public Archival
49 {
50#ifndef VALTEST
51#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) )
52#endif
53 private:
54 //template< typename chr >
55 /* struct Chunk
56 {
57 long nLength;
58 chr *pData;
59 FChunk *pNext;
60 }; */
61
62 typedef struct FStringChunk<chr> Chunk;
63 typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType;
64
65 public:
66 FBasicString() :
67 nLength( 0 ),
68 pFirst( NULL ),
69 pLast( NULL )
70 {
71 }
72
73 FBasicString( const chr *pData ) :
74 nLength( 0 ),
75 pFirst( NULL ),
76 pLast( NULL )
77 {
78 append( pData );
79 }
80
81 FBasicString( const chr *pData, long nLength ) :
82 nLength( 0 ),
83 pFirst( NULL ),
84 pLast( NULL )
85 {
86 append( pData, nLength );
87 }
88
89 FBasicString( const MyType &rSrc ) :
90 Archival(),
91 nLength( 0 ),
92 pFirst( NULL ),
93 pLast( NULL )
94 {
95 if( rSrc.nLength > 0 )
96 {
97 rSrc.flatten();
98 append( rSrc.pFirst->pData, rSrc.nLength );
99 }
100 }
101
102 FBasicString( const MyType &rSrc, long nLength ) :
103 nLength( 0 ),
104 pFirst( NULL ),
105 pLast( NULL )
106 {
107 append( rSrc.pFirst->pData, nLength );
108 }
109
110 FBasicString( const MyType &rSrc, long nStart, long nLength ) :
111 nLength( 0 ),
112 pFirst( NULL ),
113 pLast( NULL )
114 {
115 append( rSrc.pFirst->pData+nStart, nLength );
116 }
117
118 FBasicString( long nSize ) :
119 nLength( nSize ),
120 pFirst( NULL ),
121 pLast( NULL )
122 {
123 pFirst = pLast = newChunk( nSize );
124 }
125
126 virtual ~FBasicString()
127 {
128 clear();
129 }
130
131 /**
132 *@todo void append( const MyType & sData )
133 */
134
135 /**
136 * Append data to your string.
137 *@param pData (const chr *) The data to append.
138 */
139 void append( const chr *pData )
140 {
141 if( !pData ) return;
142 long nLen;
143 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
144 if( nLen == 0 )
145 return;
146
147 Chunk *pNew = newChunk( nLen );
148 cpy( pNew->pData, pData, nLen );
149
150 appendChunk( pNew );
151 }
152
153 /**
154 * Append data to your string.
155 *@param pData (const chr *) The data to append.
156 *@param nLen (long) The length of the data to append.
157 */
158 void append( const chr *pData, long nLen )
159 {
160 if( nLen == 0 )
161 return;
162
163 Chunk *pNew = newChunk( nLen );
164
165 cpy( pNew->pData, pData, nLen );
166
167 appendChunk( pNew );
168 }
169
170 /**
171 * Append a single chr to your string.
172 *@param cData (const chr &) The character to append.
173 */
174 void append( const chr &cData )
175 {
176 if( pLast && pLast->nLength < nMinSize )
177 {
178 pLast->pData[pLast->nLength] = cData;
179 ++pLast->nLength; ++nLength;
180 // pLast->pData[pLast->nLength] = (chr)0;
181 }
182 else
183 {
184 append( &cData, 1 );
185 }
186 }
187
188 /**
189 * Append another FString to this one.
190 *@param sData (MyType &) The FString to append.
191 */
192 void append( const MyType & sData )
193 {
194 append( sData.getStr(), sData.getSize() );
195 }
196
197 /**
198 * Append another FString to this one.
199 *@param sData (MyType &) The FString to append.
200 *@param nLen How much data to append.
201 */
202 void append( const MyType & sData, long nLen )
203 {
204 append( sData.getStr(), nLen );
205 }
206
207 /**
208 * Prepend another FString to this one.
209 *@param sData (MyType &) The FString to prepend.
210 */
211 void prepend( const MyType & sData )
212 {
213 prepend( sData.getStr(), sData.getSize() );
214 }
215
216 /**
217 * Prepend data to your string.
218 *@param pData (const chr *) The data to prepend.
219 */
220 void prepend( const chr *pData )
221 {
222 if( pData == NULL )
223 return;
224 long nLen;
225 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
226
227 Chunk *pNew = newChunk( nLen );
228 cpy( pNew->pData, pData, nLen );
229
230 prependChunk( pNew );
231 }
232
233 /**
234 * Prepend data to your string.
235 *@param pData (const chr *) The data to prepend.
236 *@param nLen (long) The length of the data to prepend.
237 */
238 void prepend( const chr *pData, long nLen )
239 {
240 Chunk *pNew = newChunk( nLen );
241
242 cpy( pNew->pData, pData, nLen );
243
244 prependChunk( pNew );
245 }
246
247 void insert( long nPos, const chr *pData, long nLen )
248 {
249 if( nLen <= 0 )
250 return;
251 if( nPos <= 0 )
252 {
253 prepend( pData, nLen );
254 }
255 else if( nPos >= nLength )
256 {
257 append( pData, nLen );
258 }
259 else
260 {
261 flatten();
262 Chunk *p1 = newChunk( nPos );
263 Chunk *p2 = newChunk( nLen );
264 Chunk *p3 = newChunk( nLength-nPos );
265 cpy( p1->pData, pFirst->pData, nPos );
266 cpy( p2->pData, pData, nLen );
267 cpy( p3->pData, pFirst->pData+nPos, nLength-nPos );
268 clear();
269 appendChunk( p1 );
270 appendChunk( p2 );
271 appendChunk( p3 );
272 }
273 }
274
275 void insert( long nPos, const MyType &str )
276 {
277 if( nPos <= 0 )
278 {
279 prepend( str );
280 }
281 else if( nPos >= nLength )
282 {
283 append( str );
284 }
285 else
286 {
287 flatten();
288 Chunk *p1 = newChunk( nPos );
289 Chunk *p3 = newChunk( nLength-nPos );
290 cpy( p1->pData, pFirst->pData, nPos );
291 cpy( p3->pData, pFirst->pData+nPos, nLength-nPos );
292 clear();
293 appendChunk( p1 );
294 for( Chunk *pChnk = str.pFirst; pChnk; pChnk = pChnk->pNext )
295 {
296 appendChunk( copyChunk( pChnk ) );
297 }
298
299 appendChunk( p3 );
300 }
301 }
302
303 void insert( long nPos, const chr *pData )
304 {
305 insert( nPos, pData, strlen( pData ) );
306 }
307
308 void remove( long nPos, long nLen )
309 {
310 if( nLen <= 0 || nPos < 0 || nPos >= nLength )
311 return;
312 if( nLen > nLength-nPos )
313 nLen = nLength-nPos;
314 flatten();
315 cpy( pFirst->pData+nPos, pFirst->pData+nPos+nLen, nLength-nPos-nLen+1 );
316 nLength -= nLen;
317 pFirst->nLength -= nLen;
318 }
319
320 /**
321 *@todo void prepend( const chr &cData )
322 */
323
324 /**
325 * Clear all data from the string.
326 */
327 void clear()
328 {
329 realClear();
330 }
331
332 /**
333 * Force the string to resize
334 *@param nNewSize (long) The new size of the string.
335 */
336 void resize( long nNewSize )
337 {
338 if( nLength == nNewSize )
339 return;
340 if( nNewSize < 0 )
341 nNewSize = 0;
342
343 flatten();
344
345 Chunk *pNew = newChunk( nNewSize );
346 long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength);
347 if( nLength > 0 )
348 {
349 cpy( pNew->pData, pFirst->pData, nNewLen );
350 aChr.deallocate( pFirst->pData, pFirst->nLength+1 );
351 aChunk.deallocate( pFirst, 1 );
352 }
353 pNew->pData[nNewLen] = (chr)0;
354 pFirst = pLast = pNew;
355 nLength = nNewSize;
356 }
357
358 /**
359 * Get the current size of the string.
360 *@returns (long) The current size of the string.
361 */
362 long getSize() const
363 {
364 return nLength;
365 }
366
367 /**
368 * Get a pointer to the string array.
369 *@returns (chr *) The string data.
370 */
371 chr *getStr()
372 {
373 if( pFirst == NULL )
374 return (chr *)"";
375
376 flatten();
377 pFirst->pData[nLength] = (chr)0;
378 return pFirst->pData;
379 }
380
381 /**
382 * Get a const pointer to the string array.
383 *@returns (const chr *) The string data.
384 */
385 const chr *getStr() const
386 {
387 if( pFirst == NULL )
388 return (chr *)"";
389
390 flatten();
391 pFirst->pData[nLength] = (chr)0;
392 return pFirst->pData;
393 }
394
395 MyType getSubStr( long iStart, long iSize=-1 ) const
396 {
397 if( iStart < 0 )
398 iStart = 0;
399 if( iStart >= nLength )
400 return "";
401 if( iSize < 0 )
402 iSize = nLength;
403 if( iStart+iSize > nLength )
404 iSize = nLength-iStart;
405 if( iSize == 0 )
406 return "";
407
408 flatten();
409 MyType ret( pFirst->pData+iStart, iSize );
410 return ret;
411 }
412
413 /**
414 * (std::string compatability) Get a pointer to the string array.
415 *@returns (chr *) The string data.
416 */
417 DEPRECATED
418 chr *c_str()
419 {
420 if( pFirst == NULL )
421 return NULL;
422
423 flatten();
424 pFirst->pData[nLength] = (chr)0;
425 return pFirst->pData;
426 }
427
428 /**
429 * (std::string compatability) Get a const pointer to the string array.
430 *@returns (const chr *) The string data.
431 */
432 DEPRECATED
433 const chr *c_str() const
434 {
435 if( pFirst == NULL )
436 return NULL;
437
438 flatten();
439 pFirst->pData[nLength] = (chr)0;
440 return pFirst->pData;
441 }
442
443 /**
444 * Plus equals operator for FString.
445 *@param pData (const chr *) The data to append to your FString.
446 */
447 MyType &operator +=( const chr *pData )
448 {
449 append( pData );
450
451 return (*this);
452 }
453
454 /**
455 * Plus equals operator for FString.
456 *@param pData (const MyType &) The FString to append to your FString.
457 */
458 MyType &operator +=( const MyType &rSrc )
459 {
460 if( rSrc.nLength == 0 )
461 return (*this);
462 rSrc.flatten();
463 append( rSrc.pFirst->pData, rSrc.nLength );
464
465 return (*this);
466 }
467
468 /**
469 * Plus equals operator for FString.
470 *@param pData (const chr) The character to append to your FString.
471 */
472 MyType &operator +=( const chr cData )
473 {
474 if( pLast && pLast->nLength < nMinSize )
475 {
476 pLast->pData[pLast->nLength] = cData;
477 ++pLast->nLength; ++nLength;
478 // pLast->pData[pLast->nLength] = (chr)0;
479 }
480 else
481 {
482 append( &cData, 1 );
483 }
484 //append( pData );
485
486 return (*this);
487 }
488
489 /**
490 * Assignment operator.
491 *@param pData (const chr *) The character array to append to your
492 * FString.
493 */
494 MyType &operator =( const chr *pData )
495 {
496 clear();
497 append( pData );
498
499 return (*this);
500 }
501
502 MyType &operator =( const std::basic_string<chr> &rData )
503 {
504 clear();
505 append( rData.c_str(), rData.size() );
506
507 return (*this);
508 }
509
510 MyType operator +( const MyType &rRight )
511 {
512 MyType ret( *this );
513 ret.append( rRight );
514 return ret;
515 }
516
517 MyType operator +( const chr *pRight )
518 {
519 MyType ret( *this );
520 ret.append( pRight );
521 return ret;
522 }
523
524 MyType operator +( chr *pRight )
525 {
526 MyType ret( *this );
527 ret.append( pRight );
528 return ret;
529 }
530
531 /**
532 * Reset your FString to this character array.
533 *@param pData (const chr *) The character array to set your FString to.
534 */
535 void set( const chr *pData )
536 {
537 clear();
538 append( pData );
539 }
540
541 /**
542 * Reset your FString to this character array.
543 *@param pData (const chr *) The character array to set your FString to.
544 *@param nSize (long) The length of the inputted character array.
545 */
546 void set( const chr *pData, long nSize )
547 {
548 clear();
549 append( pData, nSize );
550 }
551
552 void expand()
553 {
554 flatten();
555
556#ifndef WIN32
557 wordexp_t result;
558
559 /* Expand the string for the program to run. */
560 switch (wordexp (pFirst->pData, &result, 0))
561 {
562 case 0: /* Successful. */
563 {
564 set( result.we_wordv[0] );
565 wordfree( &result );
566 return;
567 }
568 break;
569 case WRDE_NOSPACE:
570 /* If the error was `WRDE_NOSPACE',
571 then perhaps part of the result was allocated. */
572 wordfree (&result);
573 default: /* Some other error. */
574 return;
575 }
576#endif
577 }
578
579 /**
580 * Assignment operator.
581 *@param rSrc (const MyType &) The FString to set your FString to.
582 */
583 MyType &operator =( const MyType &rSrc )
584 {
585 copyFrom( rSrc );
586
587 return (*this);
588 }
589
590 /**
591 * Equals comparison operator.
592 *@param pData (const chr *) The character array to compare your FString
593 * to.
594 */
595 bool operator ==( const chr *pData ) const
596 {
597 if( pFirst == NULL ) {
598 if( pData == NULL )
599 return true;
600 if( pData[0] == (chr)0 )
601 return true;
602 return false;
603 }
604
605 flatten();
606 pFirst->pData[nLength] = (chr)0;
607 const chr *a = pData;
608 chr *b = pFirst->pData;
609 for( long j = 0; *a!=(chr)0 || *b!=(chr)0; j++, a++, b++ )
610 {
611 if( *a != *b )
612 return false;
613 if( *a == (chr)0 && j < nLength )
614 return false;
615 }
616
617 return true;
618 }
619
620 /**
621 * Equals comparison operator.
622 *@param pData (const MyType &) The FString to compare your FString to.
623 */
624 bool operator ==( const MyType &pData ) const
625 {
626 if( pFirst == pData.pFirst )
627 return true;
628 if( pFirst == NULL )
629 return false;
630 if( nLength != pData.nLength )
631 return false;
632
633 flatten();
634 pData.flatten();
635 const chr *a = pData.pFirst->pData;
636 chr *b = pFirst->pData;
637 for( long j = 0; j < nLength; j++, a++, b++ )
638 {
639 if( *a != *b )
640 return false;
641 }
642
643 return true;
644 }
645
646 /**
647 * Not equals comparison operator.
648 *@param pData (const chr *) The character array to compare your FString
649 * to.
650 */
651 bool operator !=(const chr *pData ) const
652 {
653 return !(*this == pData);
654 }
655
656 /**
657 * Not equals comparison operator.
658 *@param pData (const MyType &) The FString to compare your FString to.
659 */
660 bool operator !=(const MyType &pData ) const
661 {
662 return !(*this == pData);
663 }
664
665 /**
666 * Indexing operator
667 *@param nIndex (long) The index of the character you want.
668 *@returns (chr &) The character at position (nIndex).
669 */
670 chr &operator[]( long nIndex )
671 {
672 flatten();
673
674 return pFirst->pData[nIndex];
675 }
676
677 /**
678 * Const indexing operator
679 *@param nIndex (long) The index of the character you want.
680 *@returns (const chr &) The character at position (nIndex).
681 */
682 const chr &operator[]( long nIndex ) const
683 {
684 flatten();
685
686 return pFirst->pData[nIndex];
687 }
688/*
689 operator const chr *() const
690 {
691 if( !pFirst ) return NULL;
692 flatten();
693 return pFirst->pData;
694 }
695 */
696
697 operator bool() const
698 {
699 return (pFirst != NULL);
700 }
701
702 bool isSet() const
703 {
704 return (pFirst != NULL);
705 }
706
707 /**
708 * Is the character at index (nIndex) white space?
709 *@param nIndex (long) The index of the character you want to check.
710 *@returns (bool) Is it white space?
711 */
712 bool isWS( long nIndex ) const
713 {
714 flatten();
715
716 return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t'
717 || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n';
718 }
719
720 /**
721 * Is the character at index (nIndex) a letter?
722 *@param nIndex (long) The index of the character you want to check.
723 *@returns (bool) Is it a letter?
724 */
725 bool isAlpha( long nIndex ) const
726 {
727 flatten();
728
729 return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z')
730 || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z');
731 }
732
733 /**
734 * Convert your alpha characters to lower case.
735 */
736 void toLower()
737 {
738 flatten();
739
740 for( long j = 0; j < nLength; j++ )
741 {
742 if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' )
743 pFirst->pData[j] -= 'A'-'a';
744 }
745 }
746
747 /**
748 * Convert your alpha characters to upper case.
749 */
750 void toUpper()
751 {
752 flatten();
753
754 for( long j = 0; j < nLength; j++ )
755 {
756 if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' )
757 pFirst->pData[j] += 'A'-'a';
758 }
759 }
760
761 /**
762 * Find the index of the first occurrance of (sText)
763 *@param sText (const chr *) The string to search for.
764 *@returns (long) The index of the first occurrance. -1 for not found.
765 */
766 long find( const chr cChar ) const
767 {
768 flatten();
769 for( long j = 0; j < pFirst->nLength; j++ )
770 {
771 if( pFirst->pData[j] == cChar )
772 return j;
773 }
774 return -1;
775 }
776
777 /**
778 * Find the index of the first occurrance of cChar
779 *@param cChar (const chr) The character to search for.
780 *@returns (long) The index of the first occurrance. -1 for not found.
781 */
782 long find( const chr *sText ) const
783 {
784 long nTLen = strlen( sText );
785 flatten();
786 for( long j = 0; j < pFirst->nLength-nTLen; j++ )
787 {
788 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
789 return j;
790 }
791 return -1;
792 }
793
794 /**
795 * Find the index of the first occurrance of cChar
796 *@param sText (const chr *) The string to search for.
797 *@returns (long) The index of the first occurrance. -1 for not found.
798 */
799 long find( long iStart, const chr cChar ) const
800 {
801 flatten();
802 for( long j = iStart; j < pFirst->nLength; j++ )
803 {
804 if( pFirst->pData[j] == cChar )
805 return j;
806 }
807 return -1;
808 }
809
810 /**
811 * Find the index of the first occurrance of sText
812 *@param cChar (const chr) The character to search for.
813 *@returns (long) The index of the first occurrance. -1 for not found.
814 */
815 long find( long iStart, const chr *sText ) const
816 {
817 long nTLen = strlen( sText );
818 flatten();
819 for( long j = iStart; j < pFirst->nLength-nTLen; j++ )
820 {
821 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
822 return j;
823 }
824 return -1;
825 }
826
827 /**
828 * Do a reverse search for (sText)
829 *@param sText (const chr *) The string to search for.
830 *@returns (long) The index of the last occurrance. -1 for not found.
831 */
832 long rfind( const chr *sText ) const
833 {
834 long nTLen = strlen( sText );
835 flatten();
836 for( long j = pFirst->nLength-nTLen-1; j >= 0; j-- )
837 {
838 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
839 return j;
840 }
841 return -1;
842 }
843
844 /**
845 * Remove nAmnt bytes from the front of the string. This function
846 * operates in O(n) time and should be used sparingly.
847 */
848 void trimFront( long nAmnt )
849 {
850 long nNewLen = nLength - nAmnt;
851 flatten();
852 Chunk *pNew = newChunk( nNewLen );
853 cpy( pNew->pData, pFirst->pData+nAmnt, nNewLen );
854 clear();
855 appendChunk( pNew );
856 }
857
858 void format( const char *sFrmt, ...)
859 {
860 clear();
861
862 va_list ap;
863 va_start( ap, sFrmt );
864
865 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
866
867 Chunk *pNew = newChunk( iLen );
868 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
869 appendChunk( pNew );
870
871 va_end( ap );
872 }
873
874 void formatAppend( const char *sFrmt, ...)
875 {
876 va_list ap;
877 va_start( ap, sFrmt );
878
879 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
880
881 Chunk *pNew = newChunk( iLen );
882 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
883 appendChunk( pNew );
884
885 va_end( ap );
886 }
887
888 void formatPrepend( const char *sFrmt, ...)
889 {
890 va_list ap;
891 va_start( ap, sFrmt );
892
893 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
894
895 Chunk *pNew = newChunk( iLen );
896 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
897 prependChunk( pNew );
898
899 va_end( ap );
900 }
901
902 /**
903 * Function the archiver calls to archive your FString.
904 *@param ar (Archive) The archive which is archiving your FString.
905 */
906 void archive( class Archive &ar )
907 {
908 if( ar.isLoading() )
909 {
910 clear();
911 long nLen;
912 ar >> nLen;
913
914 if( nLen > 0 )
915 {
916 Chunk *pNew = newChunk( nLen );
917 ar.read( pNew->pData, nLen*sizeof(chr) );
918 appendChunk( pNew );
919 }
920 }
921 else
922 {
923 flatten();
924
925 ar << nLength;
926 if( nLength )
927 ar.write( pFirst->pData, nLength*sizeof(chr) );
928 }
929 }
930
931 typedef chr *iterator;
932 typedef const chr *const_iterator;
933
934 iterator begin()
935 {
936 if( nLength == 0 )
937 return NULL;
938 flatten();
939 return pFirst->pData;
940 }
941
942 const_iterator begin() const
943 {
944 if( nLength == 0 )
945 return NULL;
946 flatten();
947 return pFirst->pData;
948 }
949
950 iterator end()
951 {
952 if( nLength == 0 )
953 return NULL;
954 return pFirst->pData+pFirst->nLength;
955 }
956
957 const_iterator end() const
958 {
959 if( nLength == 0 )
960 return NULL;
961 return pFirst->pData+pFirst->nLength;
962 }
963
964 bool isEmpty() const
965 {
966 if( nLength == 0 )
967 return true;
968 return false;
969 }
970
971 private:
972 void flatten() const
973 {
974 if( isFlat() )
975 return;
976
977 if( pFirst == NULL )
978 return;
979
980 Chunk *pNew = newChunk( nLength );
981 chr *pos = pNew->pData;
982 Chunk *i = pFirst;
983 for(;;)
984 {
985 cpy( pos, i->pData, i->nLength );
986 pos += i->nLength;
987 i = i->pNext;
988 if( i == NULL )
989 break;
990 }
991 realClear();
992
993 pLast = pFirst = pNew;
994 nLength = pNew->nLength;
995 }
996
997 void realClear() const
998 {
999 if( pFirst == NULL )
1000 return;
1001
1002 Chunk *i = pFirst;
1003 for(;;)
1004 {
1005 Chunk *n = i->pNext;
1006 aChr.deallocate( i->pData, i->nLength+1 );
1007 aChunk.deallocate( i, 1 );
1008 if( n == NULL )
1009 break;
1010 i = n;
1011 }
1012 pFirst = pLast = NULL;
1013 nLength = 0;
1014 }
1015
1016 void copyFrom( const FBasicString<chr, nMinSize, chralloc, chunkalloc> &rSrc )
1017 {
1018 if( rSrc.pFirst == NULL )
1019 {
1020 clear();
1021 return;
1022 }
1023
1024 Chunk *pNew = newChunk( rSrc.nLength );
1025 chr *pos = pNew->pData;
1026 Chunk *i = rSrc.pFirst;
1027 for(;;)
1028 {
1029 cpy( pos, i->pData, i->nLength );
1030 pos += i->nLength;
1031 i = i->pNext;
1032 if( i == NULL )
1033 break;
1034 }
1035 clear();
1036
1037 appendChunk( pNew );
1038 }
1039
1040 bool isFlat() const
1041 {
1042 return (pFirst == pLast);
1043 }
1044
1045 Chunk *newChunk() const
1046 {
1047 Chunk *pNew = aChunk.allocate( 1 );
1048 pNew->pNext = NULL;
1049 return pNew;
1050 }
1051
1052 Chunk *newChunk( long nLen ) const
1053 {
1054 Chunk *pNew = aChunk.allocate( 1 );
1055 pNew->pNext = NULL;
1056 pNew->nLength = nLen;
1057 pNew->pData = aChr.allocate( (nLen<nMinSize)?(nMinSize):(nLen)+1 );
1058 pNew->pData[nLen] = (chr)0;
1059 return pNew;
1060 }
1061
1062 Chunk *copyChunk( Chunk *pSrc ) const
1063 {
1064 Chunk *pNew = aChunk.allocate( 1 );
1065 pNew->pNext = pSrc->pNext;
1066 pNew->nLength = pSrc->nLength;
1067 pNew->pData = aChr.allocate( pSrc->nLength+1 );
1068 cpy( pNew->pData, pSrc->pData, pSrc->nLength );
1069 pNew->pData[pNew->nLength] = (chr)0;
1070 return pNew;
1071 }
1072
1073 void appendChunk( Chunk *pNewChunk )
1074 {
1075 if( pFirst == NULL )
1076 pLast = pFirst = pNewChunk;
1077 else
1078 {
1079 pLast->pNext = pNewChunk;
1080 pLast = pNewChunk;
1081 }
1082
1083 nLength += pNewChunk->nLength;
1084 }
1085
1086 void prependChunk( Chunk *pNewChunk )
1087 {
1088 if( pFirst == NULL )
1089 pLast = pFirst = pNewChunk;
1090 else
1091 {
1092 pNewChunk->pNext = pFirst;
1093 pFirst = pNewChunk;
1094 }
1095
1096 nLength += pNewChunk->nLength;
1097 }
1098
1099#ifdef VALTEST
1100 void cpy( chr *dest, const chr *src, long count ) const
1101 {
1102 for( int j = 0; j < count; j++ )
1103 {
1104 *dest = *src;
1105 dest++;
1106 src++;
1107 }
1108 }
1109#endif
1110
1111 private:
1112 mutable long nLength;
1113 mutable Chunk *pFirst;
1114 mutable Chunk *pLast;
1115
1116 mutable chralloc aChr;
1117 mutable chunkalloc aChunk;
1118 };
1119
1120 template<class T> FBasicString<T> operator +( const T *pLeft, const FBasicString<T> &rRight )
1121 {
1122 Bu::FBasicString<T> ret( pLeft );
1123 ret.append( rRight );
1124 return ret;
1125 }
1126}
1127
1128#ifndef VALTEST
1129#undef cpy
1130#endif
1131
1132#endif
diff --git a/src/fstring.cpp b/src/fstring.cpp
index 3ed4f2b..e4dc716 100644
--- a/src/fstring.cpp
+++ b/src/fstring.cpp
@@ -8,8 +8,10 @@
8#define BU_TRACE 8#define BU_TRACE
9#include "bu/trace.h" 9#include "bu/trace.h"
10 10
11#include "fstring.h" 11#include "bu/fstring.h"
12#include "hash.h" 12#include "bu/hash.h"
13
14template class Bu::FBasicString<char>;
13 15
14template<> uint32_t Bu::__calcHashCode<Bu::FString>( const Bu::FString &k ) 16template<> uint32_t Bu::__calcHashCode<Bu::FString>( const Bu::FString &k )
15{ 17{
@@ -37,8 +39,8 @@ std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FS
37 return os; 39 return os;
38} 40}
39 41
40
41template<> void Bu::__tracer_format<Bu::FString>( const Bu::FString &v ) 42template<> void Bu::__tracer_format<Bu::FString>( const Bu::FString &v )
42{ 43{
43 printf("(%ld)\"%s\"", v.getSize(), v.getStr() ); 44 printf("(%ld)\"%s\"", v.getSize(), v.getStr() );
44} 45}
46
diff --git a/src/fstring.h b/src/fstring.h
index e1660f9..0793154 100644
--- a/src/fstring.h
+++ b/src/fstring.h
@@ -8,1121 +8,24 @@
8#ifndef BU_F_STRING_H 8#ifndef BU_F_STRING_H
9#define BU_F_STRING_H 9#define BU_F_STRING_H
10 10
11#include <stdint.h> 11#include "bu/fbasicstring.h"
12#include <string>
13#include <memory>
14
15#ifndef WIN32
16#include <wordexp.h>
17#endif
18
19#include "bu/archival.h"
20#include "bu/archive.h"
21#include "bu/hash.h"
22#include "bu/util.h"
23 12
24namespace Bu 13namespace Bu
25{ 14{
26 template< typename chr >
27 struct FStringChunk
28 {
29 long nLength;
30 chr *pData;
31 FStringChunk *pNext;
32 };
33
34 /**
35 * Flexible String class. This class was designed with string passing and
36 * generation in mind. Like the standard string class you can specify what
37 * datatype to use for each character. Unlike the standard string class,
38 * collection of appended and prepended terms is done lazily, making long
39 * operations that involve many appends very inexpensive. In addition
40 * internal ref-counting means that if you pass strings around between
41 * functions there's almost no overhead in time or memory since a reference
42 * is created and no data is actually copied. This also means that you
43 * never need to put any FBasicString into a ref-counting container class.
44 *
45 *@param chr (typename) Type of character (i.e. char)
46 *@param nMinSize (int) Chunk size (default: 256)
47 *@param chralloc (typename) Memory Allocator for chr
48 *@param chunkalloc (typename) Memory Allocator for chr chunks
49 */
50 template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
51 class FBasicString : public Archival
52 {
53#ifndef VALTEST
54#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) )
55#endif
56 private:
57 typedef struct FStringChunk<chr> Chunk;
58 typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType;
59
60 public:
61 FBasicString() :
62 nLength( 0 ),
63 pFirst( NULL ),
64 pLast( NULL )
65 {
66 }
67
68 FBasicString( const chr *pData ) :
69 nLength( 0 ),
70 pFirst( NULL ),
71 pLast( NULL )
72 {
73 append( pData );
74 }
75
76 FBasicString( const chr *pData, long nLength ) :
77 nLength( 0 ),
78 pFirst( NULL ),
79 pLast( NULL )
80 {
81 append( pData, nLength );
82 }
83
84 FBasicString( const MyType &rSrc ) :
85 Archival(),
86 nLength( 0 ),
87 pFirst( NULL ),
88 pLast( NULL )
89 {
90 if( rSrc.nLength > 0 )
91 {
92 rSrc.flatten();
93 append( rSrc.pFirst->pData, rSrc.nLength );
94 }
95 }
96
97 FBasicString( const MyType &rSrc, long nLength ) :
98 nLength( 0 ),
99 pFirst( NULL ),
100 pLast( NULL )
101 {
102 append( rSrc.pFirst->pData, nLength );
103 }
104
105 FBasicString( const MyType &rSrc, long nStart, long nLength ) :
106 nLength( 0 ),
107 pFirst( NULL ),
108 pLast( NULL )
109 {
110 append( rSrc.pFirst->pData+nStart, nLength );
111 }
112
113 FBasicString( long nSize ) :
114 nLength( nSize ),
115 pFirst( NULL ),
116 pLast( NULL )
117 {
118 pFirst = pLast = newChunk( nSize );
119 }
120
121 virtual ~FBasicString()
122 {
123 clear();
124 }
125
126 /**
127 *@todo void append( const MyType & sData )
128 */
129
130 /**
131 * Append data to your string.
132 *@param pData (const chr *) The data to append.
133 */
134 void append( const chr *pData )
135 {
136 if( !pData ) return;
137 long nLen;
138 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
139 if( nLen == 0 )
140 return;
141
142 Chunk *pNew = newChunk( nLen );
143 cpy( pNew->pData, pData, nLen );
144
145 appendChunk( pNew );
146 }
147
148 /**
149 * Append data to your string.
150 *@param pData (const chr *) The data to append.
151 *@param nLen (long) The length of the data to append.
152 */
153 void append( const chr *pData, long nLen )
154 {
155 if( nLen == 0 )
156 return;
157
158 Chunk *pNew = newChunk( nLen );
159
160 cpy( pNew->pData, pData, nLen );
161
162 appendChunk( pNew );
163 }
164
165 /**
166 * Append a single chr to your string.
167 *@param cData (const chr &) The character to append.
168 */
169 void append( const chr &cData )
170 {
171 if( pLast && pLast->nLength < nMinSize )
172 {
173 pLast->pData[pLast->nLength] = cData;
174 ++pLast->nLength; ++nLength;
175 // pLast->pData[pLast->nLength] = (chr)0;
176 }
177 else
178 {
179 append( &cData, 1 );
180 }
181 }
182
183 /**
184 * Append another FString to this one.
185 *@param sData (MyType &) The FString to append.
186 */
187 void append( const MyType & sData )
188 {
189 append( sData.getStr(), sData.getSize() );
190 }
191
192 /**
193 * Append another FString to this one.
194 *@param sData (MyType &) The FString to append.
195 *@param nLen How much data to append.
196 */
197 void append( const MyType & sData, long nLen )
198 {
199 append( sData.getStr(), nLen );
200 }
201
202 /**
203 * Prepend another FString to this one.
204 *@param sData (MyType &) The FString to prepend.
205 */
206 void prepend( const MyType & sData )
207 {
208 prepend( sData.getStr(), sData.getSize() );
209 }
210
211 /**
212 * Prepend data to your string.
213 *@param pData (const chr *) The data to prepend.
214 */
215 void prepend( const chr *pData )
216 {
217 if( pData == NULL )
218 return;
219 long nLen;
220 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
221
222 Chunk *pNew = newChunk( nLen );
223 cpy( pNew->pData, pData, nLen );
224
225 prependChunk( pNew );
226 }
227
228 /**
229 * Prepend data to your string.
230 *@param pData (const chr *) The data to prepend.
231 *@param nLen (long) The length of the data to prepend.
232 */
233 void prepend( const chr *pData, long nLen )
234 {
235 Chunk *pNew = newChunk( nLen );
236
237 cpy( pNew->pData, pData, nLen );
238
239 prependChunk( pNew );
240 }
241
242 void insert( long nPos, const chr *pData, long nLen )
243 {
244 if( nLen <= 0 )
245 return;
246 if( nPos <= 0 )
247 {
248 prepend( pData, nLen );
249 }
250 else if( nPos >= nLength )
251 {
252 append( pData, nLen );
253 }
254 else
255 {
256 flatten();
257 Chunk *p1 = newChunk( nPos );
258 Chunk *p2 = newChunk( nLen );
259 Chunk *p3 = newChunk( nLength-nPos );
260 cpy( p1->pData, pFirst->pData, nPos );
261 cpy( p2->pData, pData, nLen );
262 cpy( p3->pData, pFirst->pData+nPos, nLength-nPos );
263 clear();
264 appendChunk( p1 );
265 appendChunk( p2 );
266 appendChunk( p3 );
267 }
268 }
269
270 void insert( long nPos, const MyType &str )
271 {
272 if( nPos <= 0 )
273 {
274 prepend( str );
275 }
276 else if( nPos >= nLength )
277 {
278 append( str );
279 }
280 else
281 {
282 flatten();
283 Chunk *p1 = newChunk( nPos );
284 Chunk *p3 = newChunk( nLength-nPos );
285 cpy( p1->pData, pFirst->pData, nPos );
286 cpy( p3->pData, pFirst->pData+nPos, nLength-nPos );
287 clear();
288 appendChunk( p1 );
289 for( Chunk *pChnk = str->pFirst; pChnk; pChnk = pChnk->next )
290 {
291 appendChunk( copyChunk( pChnk ) );
292 }
293
294 appendChunk( p3 );
295 }
296 }
297
298 void insert( long nPos, const chr *pData )
299 {
300 insert( nPos, pData, strlen( pData ) );
301 }
302
303 void remove( long nPos, long nLen )
304 {
305 if( nLen <= 0 || nPos < 0 || nPos >= nLength )
306 return;
307 if( nLen > nLength-nPos )
308 nLen = nLength-nPos;
309 flatten();
310 cpy( pFirst->pData+nPos, pFirst->pData+nPos+nLen, nLength-nPos-nLen+1 );
311 nLength -= nLen;
312 pFirst->nLength -= nLen;
313 }
314
315 /**
316 *@todo void prepend( const chr &cData )
317 */
318
319 /**
320 * Clear all data from the string.
321 */
322 void clear()
323 {
324 realClear();
325 }
326
327 /**
328 * Force the string to resize
329 *@param nNewSize (long) The new size of the string.
330 */
331 void resize( long nNewSize )
332 {
333 if( nLength == nNewSize )
334 return;
335 if( nNewSize < 0 )
336 nNewSize = 0;
337
338 flatten();
339
340 Chunk *pNew = newChunk( nNewSize );
341 long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength);
342 if( nLength > 0 )
343 {
344 cpy( pNew->pData, pFirst->pData, nNewLen );
345 aChr.deallocate( pFirst->pData, pFirst->nLength+1 );
346 aChunk.deallocate( pFirst, 1 );
347 }
348 pNew->pData[nNewLen] = (chr)0;
349 pFirst = pLast = pNew;
350 nLength = nNewSize;
351 }
352
353 /**
354 * Get the current size of the string.
355 *@returns (long) The current size of the string.
356 */
357 long getSize() const
358 {
359 return nLength;
360 }
361
362 /**
363 * Get a pointer to the string array.
364 *@returns (chr *) The string data.
365 */
366 chr *getStr()
367 {
368 if( pFirst == NULL )
369 return (chr *)"";
370
371 flatten();
372 pFirst->pData[nLength] = (chr)0;
373 return pFirst->pData;
374 }
375
376 /**
377 * Get a const pointer to the string array.
378 *@returns (const chr *) The string data.
379 */
380 const chr *getStr() const
381 {
382 if( pFirst == NULL )
383 return (chr *)"";
384
385 flatten();
386 pFirst->pData[nLength] = (chr)0;
387 return pFirst->pData;
388 }
389
390 MyType getSubStr( long iStart, long iSize=-1 ) const
391 {
392 if( iStart < 0 )
393 iStart = 0;
394 if( iStart >= nLength )
395 return "";
396 if( iSize < 0 )
397 iSize = nLength;
398 if( iStart+iSize > nLength )
399 iSize = nLength-iStart;
400 if( iSize == 0 )
401 return "";
402
403 flatten();
404 MyType ret( pFirst->pData+iStart, iSize );
405 return ret;
406 }
407
408 /**
409 * (std::string compatability) Get a pointer to the string array.
410 *@returns (chr *) The string data.
411 */
412 DEPRECATED
413 chr *c_str()
414 {
415 if( pFirst == NULL )
416 return NULL;
417
418 flatten();
419 pFirst->pData[nLength] = (chr)0;
420 return pFirst->pData;
421 }
422
423 /**
424 * (std::string compatability) Get a const pointer to the string array.
425 *@returns (const chr *) The string data.
426 */
427 DEPRECATED
428 const chr *c_str() const
429 {
430 if( pFirst == NULL )
431 return NULL;
432
433 flatten();
434 pFirst->pData[nLength] = (chr)0;
435 return pFirst->pData;
436 }
437
438 /**
439 * Plus equals operator for FString.
440 *@param pData (const chr *) The data to append to your FString.
441 */
442 MyType &operator +=( const chr *pData )
443 {
444 append( pData );
445
446 return (*this);
447 }
448
449 /**
450 * Plus equals operator for FString.
451 *@param pData (const MyType &) The FString to append to your FString.
452 */
453 MyType &operator +=( const MyType &rSrc )
454 {
455 if( rSrc.nLength == 0 )
456 return (*this);
457 rSrc.flatten();
458 append( rSrc.pFirst->pData, rSrc.nLength );
459
460 return (*this);
461 }
462
463 /**
464 * Plus equals operator for FString.
465 *@param pData (const chr) The character to append to your FString.
466 */
467 MyType &operator +=( const chr cData )
468 {
469 if( pLast && pLast->nLength < nMinSize )
470 {
471 pLast->pData[pLast->nLength] = cData;
472 ++pLast->nLength; ++nLength;
473 // pLast->pData[pLast->nLength] = (chr)0;
474 }
475 else
476 {
477 append( &cData, 1 );
478 }
479 //append( pData );
480
481 return (*this);
482 }
483
484 /**
485 * Assignment operator.
486 *@param pData (const chr *) The character array to append to your
487 * FString.
488 */
489 MyType &operator =( const chr *pData )
490 {
491 clear();
492 append( pData );
493
494 return (*this);
495 }
496
497 MyType &operator =( const std::basic_string<chr> &rData )
498 {
499 clear();
500 append( rData.c_str(), rData.size() );
501
502 return (*this);
503 }
504
505 MyType operator +( const MyType &rRight )
506 {
507 MyType ret( *this );
508 ret.append( rRight );
509 return ret;
510 }
511
512 MyType operator +( const chr *pRight )
513 {
514 MyType ret( *this );
515 ret.append( pRight );
516 return ret;
517 }
518
519 MyType operator +( chr *pRight )
520 {
521 MyType ret( *this );
522 ret.append( pRight );
523 return ret;
524 }
525
526 /**
527 * Reset your FString to this character array.
528 *@param pData (const chr *) The character array to set your FString to.
529 */
530 void set( const chr *pData )
531 {
532 clear();
533 append( pData );
534 }
535
536 /**
537 * Reset your FString to this character array.
538 *@param pData (const chr *) The character array to set your FString to.
539 *@param nSize (long) The length of the inputted character array.
540 */
541 void set( const chr *pData, long nSize )
542 {
543 clear();
544 append( pData, nSize );
545 }
546
547 void expand()
548 {
549 flatten();
550
551#ifndef WIN32
552 wordexp_t result;
553
554 /* Expand the string for the program to run. */
555 switch (wordexp (pFirst->pData, &result, 0))
556 {
557 case 0: /* Successful. */
558 {
559 set( result.we_wordv[0] );
560 wordfree( &result );
561 return;
562 }
563 break;
564 case WRDE_NOSPACE:
565 /* If the error was `WRDE_NOSPACE',
566 then perhaps part of the result was allocated. */
567 wordfree (&result);
568 default: /* Some other error. */
569 return;
570 }
571#endif
572 }
573
574 /**
575 * Assignment operator.
576 *@param rSrc (const MyType &) The FString to set your FString to.
577 */
578 MyType &operator =( const MyType &rSrc )
579 {
580 copyFrom( rSrc );
581
582 return (*this);
583 }
584
585 /**
586 * Equals comparison operator.
587 *@param pData (const chr *) The character array to compare your FString
588 * to.
589 */
590 bool operator ==( const chr *pData ) const
591 {
592 if( pFirst == NULL ) {
593 if( pData == NULL )
594 return true;
595 if( pData[0] == (chr)0 )
596 return true;
597 return false;
598 }
599
600 flatten();
601 pFirst->pData[nLength] = (chr)0;
602 const chr *a = pData;
603 chr *b = pFirst->pData;
604 for( long j = 0; *a!=(chr)0 || *b!=(chr)0; j++, a++, b++ )
605 {
606 if( *a != *b )
607 return false;
608 if( *a == (chr)0 && j < nLength )
609 return false;
610 }
611
612 return true;
613 }
614
615 /**
616 * Equals comparison operator.
617 *@param pData (const MyType &) The FString to compare your FString to.
618 */
619 bool operator ==( const MyType &pData ) const
620 {
621 if( pFirst == pData.pFirst )
622 return true;
623 if( pFirst == NULL )
624 return false;
625 if( nLength != pData.nLength )
626 return false;
627
628 flatten();
629 pData.flatten();
630 const chr *a = pData.pFirst->pData;
631 chr *b = pFirst->pData;
632 for( long j = 0; j < nLength; j++, a++, b++ )
633 {
634 if( *a != *b )
635 return false;
636 }
637
638 return true;
639 }
640
641 /**
642 * Not equals comparison operator.
643 *@param pData (const chr *) The character array to compare your FString
644 * to.
645 */
646 bool operator !=(const chr *pData ) const
647 {
648 return !(*this == pData);
649 }
650
651 /**
652 * Not equals comparison operator.
653 *@param pData (const MyType &) The FString to compare your FString to.
654 */
655 bool operator !=(const MyType &pData ) const
656 {
657 return !(*this == pData);
658 }
659
660 /**
661 * Indexing operator
662 *@param nIndex (long) The index of the character you want.
663 *@returns (chr &) The character at position (nIndex).
664 */
665 chr &operator[]( long nIndex )
666 {
667 flatten();
668
669 return pFirst->pData[nIndex];
670 }
671
672 /**
673 * Const indexing operator
674 *@param nIndex (long) The index of the character you want.
675 *@returns (const chr &) The character at position (nIndex).
676 */
677 const chr &operator[]( long nIndex ) const
678 {
679 flatten();
680
681 return pFirst->pData[nIndex];
682 }
683/*
684 operator const chr *() const
685 {
686 if( !pFirst ) return NULL;
687 flatten();
688 return pFirst->pData;
689 }
690 */
691
692 operator bool() const
693 {
694 return (pFirst != NULL);
695 }
696
697 bool isSet() const
698 {
699 return (pFirst != NULL);
700 }
701
702 /**
703 * Is the character at index (nIndex) white space?
704 *@param nIndex (long) The index of the character you want to check.
705 *@returns (bool) Is it white space?
706 */
707 bool isWS( long nIndex ) const
708 {
709 flatten();
710
711 return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t'
712 || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n';
713 }
714
715 /**
716 * Is the character at index (nIndex) a letter?
717 *@param nIndex (long) The index of the character you want to check.
718 *@returns (bool) Is it a letter?
719 */
720 bool isAlpha( long nIndex ) const
721 {
722 flatten();
723
724 return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z')
725 || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z');
726 }
727
728 /**
729 * Convert your alpha characters to lower case.
730 */
731 void toLower()
732 {
733 flatten();
734
735 for( long j = 0; j < nLength; j++ )
736 {
737 if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' )
738 pFirst->pData[j] -= 'A'-'a';
739 }
740 }
741
742 /**
743 * Convert your alpha characters to upper case.
744 */
745 void toUpper()
746 {
747 flatten();
748
749 for( long j = 0; j < nLength; j++ )
750 {
751 if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' )
752 pFirst->pData[j] += 'A'-'a';
753 }
754 }
755
756 /**
757 * Find the index of the first occurrance of (sText)
758 *@param sText (const chr *) The string to search for.
759 *@returns (long) The index of the first occurrance. -1 for not found.
760 */
761 long find( const chr cChar ) const
762 {
763 flatten();
764 for( long j = 0; j < pFirst->nLength; j++ )
765 {
766 if( pFirst->pData[j] == cChar )
767 return j;
768 }
769 return -1;
770 }
771
772 /**
773 * Find the index of the first occurrance of cChar
774 *@param cChar (const chr) The character to search for.
775 *@returns (long) The index of the first occurrance. -1 for not found.
776 */
777 long find( const chr *sText ) const
778 {
779 long nTLen = strlen( sText );
780 flatten();
781 for( long j = 0; j < pFirst->nLength-nTLen; j++ )
782 {
783 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
784 return j;
785 }
786 return -1;
787 }
788
789 /**
790 * Find the index of the first occurrance of cChar
791 *@param sText (const chr *) The string to search for.
792 *@returns (long) The index of the first occurrance. -1 for not found.
793 */
794 long find( long iStart, const chr cChar ) const
795 {
796 flatten();
797 for( long j = iStart; j < pFirst->nLength; j++ )
798 {
799 if( pFirst->pData[j] == cChar )
800 return j;
801 }
802 return -1;
803 }
804
805 /**
806 * Find the index of the first occurrance of sText
807 *@param cChar (const chr) The character to search for.
808 *@returns (long) The index of the first occurrance. -1 for not found.
809 */
810 long find( long iStart, const chr *sText ) const
811 {
812 long nTLen = strlen( sText );
813 flatten();
814 for( long j = iStart; j < pFirst->nLength-nTLen; j++ )
815 {
816 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
817 return j;
818 }
819 return -1;
820 }
821
822 /**
823 * Do a reverse search for (sText)
824 *@param sText (const chr *) The string to search for.
825 *@returns (long) The index of the last occurrance. -1 for not found.
826 */
827 long rfind( const chr *sText ) const
828 {
829 long nTLen = strlen( sText );
830 flatten();
831 for( long j = pFirst->nLength-nTLen-1; j >= 0; j-- )
832 {
833 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
834 return j;
835 }
836 return -1;
837 }
838
839 /**
840 * Remove nAmnt bytes from the front of the string. This function
841 * operates in O(n) time and should be used sparingly.
842 */
843 void trimFront( long nAmnt )
844 {
845 long nNewLen = nLength - nAmnt;
846 flatten();
847 Chunk *pNew = newChunk( nNewLen );
848 cpy( pNew->pData, pFirst->pData+nAmnt, nNewLen );
849 clear();
850 appendChunk( pNew );
851 }
852
853 void format( const char *sFrmt, ...)
854 {
855 clear();
856
857 va_list ap;
858 va_start( ap, sFrmt );
859
860 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
861
862 Chunk *pNew = newChunk( iLen );
863 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
864 appendChunk( pNew );
865
866 va_end( ap );
867 }
868
869 void formatAppend( const char *sFrmt, ...)
870 {
871 va_list ap;
872 va_start( ap, sFrmt );
873
874 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
875
876 Chunk *pNew = newChunk( iLen );
877 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
878 appendChunk( pNew );
879
880 va_end( ap );
881 }
882
883 void formatPrepend( const char *sFrmt, ...)
884 {
885 va_list ap;
886 va_start( ap, sFrmt );
887
888 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
889
890 Chunk *pNew = newChunk( iLen );
891 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
892 prependChunk( pNew );
893
894 va_end( ap );
895 }
896
897 /**
898 * Function the archiver calls to archive your FString.
899 *@param ar (Archive) The archive which is archiving your FString.
900 */
901 void archive( class Archive &ar )
902 {
903 if( ar.isLoading() )
904 {
905 clear();
906 long nLen;
907 ar >> nLen;
908
909 if( nLen > 0 )
910 {
911 Chunk *pNew = newChunk( nLen );
912 ar.read( pNew->pData, nLen*sizeof(chr) );
913 appendChunk( pNew );
914 }
915 }
916 else
917 {
918 flatten();
919
920 ar << nLength;
921 if( nLength )
922 ar.write( pFirst->pData, nLength*sizeof(chr) );
923 }
924 }
925
926 typedef chr *iterator;
927 typedef const chr *const_iterator;
928
929 iterator begin()
930 {
931 if( nLength == 0 )
932 return NULL;
933 flatten();
934 return pFirst->pData;
935 }
936
937 const_iterator begin() const
938 {
939 if( nLength == 0 )
940 return NULL;
941 flatten();
942 return pFirst->pData;
943 }
944
945 iterator end()
946 {
947 if( nLength == 0 )
948 return NULL;
949 return pFirst->pData+pFirst->nLength;
950 }
951
952 const_iterator end() const
953 {
954 if( nLength == 0 )
955 return NULL;
956 return pFirst->pData+pFirst->nLength;
957 }
958
959 bool isEmpty() const
960 {
961 if( nLength == 0 )
962 return true;
963 return false;
964 }
965
966 private:
967 void flatten() const
968 {
969 if( isFlat() )
970 return;
971
972 if( pFirst == NULL )
973 return;
974
975 Chunk *pNew = newChunk( nLength );
976 chr *pos = pNew->pData;
977 Chunk *i = pFirst;
978 for(;;)
979 {
980 cpy( pos, i->pData, i->nLength );
981 pos += i->nLength;
982 i = i->pNext;
983 if( i == NULL )
984 break;
985 }
986 realClear();
987
988 pLast = pFirst = pNew;
989 nLength = pNew->nLength;
990 }
991
992 void realClear() const
993 {
994 if( pFirst == NULL )
995 return;
996
997 Chunk *i = pFirst;
998 for(;;)
999 {
1000 Chunk *n = i->pNext;
1001 aChr.deallocate( i->pData, i->nLength+1 );
1002 aChunk.deallocate( i, 1 );
1003 if( n == NULL )
1004 break;
1005 i = n;
1006 }
1007 pFirst = pLast = NULL;
1008 nLength = 0;
1009 }
1010
1011 void copyFrom( const FBasicString<chr, nMinSize, chralloc, chunkalloc> &rSrc )
1012 {
1013 if( rSrc.pFirst == NULL )
1014 {
1015 clear();
1016 return;
1017 }
1018
1019 Chunk *pNew = newChunk( rSrc.nLength );
1020 chr *pos = pNew->pData;
1021 Chunk *i = rSrc.pFirst;
1022 for(;;)
1023 {
1024 cpy( pos, i->pData, i->nLength );
1025 pos += i->nLength;
1026 i = i->pNext;
1027 if( i == NULL )
1028 break;
1029 }
1030 clear();
1031
1032 appendChunk( pNew );
1033 }
1034
1035 bool isFlat() const
1036 {
1037 return (pFirst == pLast);
1038 }
1039
1040 Chunk *newChunk() const
1041 {
1042 Chunk *pNew = aChunk.allocate( 1 );
1043 pNew->pNext = NULL;
1044 return pNew;
1045 }
1046
1047 Chunk *newChunk( long nLen ) const
1048 {
1049 Chunk *pNew = aChunk.allocate( 1 );
1050 pNew->pNext = NULL;
1051 pNew->nLength = nLen;
1052 pNew->pData = aChr.allocate( (nLen<nMinSize)?(nMinSize):(nLen)+1 );
1053 pNew->pData[nLen] = (chr)0;
1054 return pNew;
1055 }
1056
1057 void appendChunk( Chunk *pNewChunk )
1058 {
1059 if( pFirst == NULL )
1060 pLast = pFirst = pNewChunk;
1061 else
1062 {
1063 pLast->pNext = pNewChunk;
1064 pLast = pNewChunk;
1065 }
1066
1067 nLength += pNewChunk->nLength;
1068 }
1069
1070 void prependChunk( Chunk *pNewChunk )
1071 {
1072 if( pFirst == NULL )
1073 pLast = pFirst = pNewChunk;
1074 else
1075 {
1076 pNewChunk->pNext = pFirst;
1077 pFirst = pNewChunk;
1078 }
1079
1080 nLength += pNewChunk->nLength;
1081 }
1082
1083#ifdef VALTEST
1084 void cpy( chr *dest, const chr *src, long count ) const
1085 {
1086 for( int j = 0; j < count; j++ )
1087 {
1088 *dest = *src;
1089 dest++;
1090 src++;
1091 }
1092 }
1093#endif
1094
1095 private:
1096 mutable long nLength;
1097 mutable Chunk *pFirst;
1098 mutable Chunk *pLast;
1099
1100 mutable chralloc aChr;
1101 mutable chunkalloc aChunk;
1102 };
1103
1104 typedef FBasicString<char> FString; 15 typedef FBasicString<char> FString;
1105 16
1106 template<> uint32_t __calcHashCode<FString>( const FString &k ); 17 template<> uint32_t __calcHashCode<FString>( const FString &k );
1107 template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ); 18 template<> bool __cmpHashKeys<FString>(
1108 template<class T> FBasicString<T> operator +( const T *pLeft, const FBasicString<T> &rRight ) 19 const FString &a, const FString &b );
1109 {
1110 Bu::FBasicString<T> ret( pLeft );
1111 ret.append( rRight );
1112 return ret;
1113 }
1114 20
1115#ifdef BU_TRACE
1116 template<typename t> void __tracer_format( const t &v ); 21 template<typename t> void __tracer_format( const t &v );
1117 template<> void __tracer_format<FString>( const FString &v ); 22 template<> void __tracer_format<FString>( const FString &v );
1118#endif
1119} 23}
1120 24
25/***** I dunno about this block, I don't really want to have it... *****
1121#include <ostream> 26#include <ostream>
1122std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FString &val ); 27std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os,
1123 28 const Bu::FString &val );
1124#ifndef VALTEST 29*/
1125#undef cpy
1126#endif
1127 30
1128#endif 31#endif
diff --git a/src/unit/archive.cpp b/src/unit/archive.cpp
deleted file mode 100644
index 8e71f4b..0000000
--- a/src/unit/archive.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
1/*
2 * Copyright (C) 2007-2008 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/membuf.h"
10
11class Unit : public Bu::UnitSuite
12{
13public:
14 Unit()
15 {
16 setName("Archive");
17 addTest( Unit::testPrimitives );
18 addTest( Unit::testContainers );
19 }
20
21 virtual ~Unit()
22 {
23 }
24
25 void testPrimitives()
26 {
27 Bu::MemBuf mb;
28 {
29 Bu::Archive ar( mb, Bu::Archive::save );
30 ar << (int8_t)1;
31 ar << (uint8_t)2;
32 ar << (int16_t)3;
33 ar << (uint16_t)4;
34 ar << (int32_t)5;
35 ar << (uint32_t)6;
36 ar << (int64_t)7;
37 ar << (uint64_t)8;
38 ar << (char)9;
39 ar << (unsigned char)10;
40 ar << (short)11;
41 ar << (unsigned short)12;
42 ar << (int)13;
43 ar << (unsigned int)14;
44 ar << (long)15;
45 ar << (unsigned long)16;
46 ar << (long long)17;
47 ar << (unsigned long long)18;
48 ar.close();
49 }
50 mb.setPos( 0 );
51 {
52 Bu::Archive ar( mb, Bu::Archive::load );
53 int8_t p1;
54 uint8_t p2;
55 int16_t p3;
56 uint16_t p4;
57 int32_t p5;
58 uint32_t p6;
59 int64_t p7;
60 uint64_t p8;
61 char p9;
62 unsigned char p10;
63 short p11;
64 unsigned short p12;
65 int p13;
66 unsigned int p14;
67 long p15;
68 unsigned long p16;
69 long long p17;
70 unsigned long long p18;
71 ar >> p1;
72 ar >> p2;
73 ar >> p3;
74 ar >> p4;
75 ar >> p5;
76 ar >> p6;
77 ar >> p7;
78 ar >> p8;
79 ar >> p9;
80 ar >> p10;
81 ar >> p11;
82 ar >> p12;
83 ar >> p13;
84 ar >> p14;
85 ar >> p15;
86 ar >> p16;
87 ar >> p17;
88 ar >> p18;
89 unitTest( p1 == 1 );
90 unitTest( p2 == 2 );
91 unitTest( p3 == 3 );
92 unitTest( p4 == 4 );
93 unitTest( p5 == 5 );
94 unitTest( p6 == 6 );
95 unitTest( p7 == 7 );
96 unitTest( p8 == 8 );
97 unitTest( p9 == 9 );
98 unitTest( p10 == 10 );
99 unitTest( p11 == 11 );
100 unitTest( p12 == 12 );
101 unitTest( p13 == 13 );
102 unitTest( p14 == 14 );
103 unitTest( p15 == 15 );
104 unitTest( p16 == 16 );
105 unitTest( p17 == 17 );
106 unitTest( p18 == 18 );
107 ar.close();
108 }
109 }
110
111 void testContainers()
112 {
113 Bu::MemBuf mb;
114 {
115 Bu::Archive ar( mb, Bu::Archive::save );
116 Bu::FString sStr("This is a test string.");
117 Bu::List<int> lList;
118 lList.append( 10 );
119 lList.append( 20 );
120 lList.append( 30 );
121 lList.append( 40 );
122 ar << sStr;
123 ar << lList;
124 ar.close();
125 }
126 mb.setPos( 0 );
127 {
128 Bu::Archive ar( mb, Bu::Archive::load );
129 Bu::FString sStr;
130 Bu::List<int> lList;
131 ar >> sStr;
132 ar >> lList;
133 unitTest( sStr == "This is a test string." );
134 unitTest( lList.getSize() == 4 );
135 Bu::List<int>::iterator i = lList.begin();
136 unitTest( *i == 10 ); i++;
137 unitTest( *i == 20 ); i++;
138 unitTest( *i == 30 ); i++;
139 unitTest( *i == 40 );
140 ar.close();
141 }
142 }
143};
144
145int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); }
diff --git a/src/unit/archive.unit b/src/unit/archive.unit
new file mode 100644
index 0000000..ecc589b
--- /dev/null
+++ b/src/unit/archive.unit
@@ -0,0 +1,130 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/membuf.h"
10
11{=Init}
12
13{%testPrimitives}
14{
15 Bu::MemBuf mb;
16 {
17 Bu::Archive ar( mb, Bu::Archive::save );
18 ar << (int8_t)1;
19 ar << (uint8_t)2;
20 ar << (int16_t)3;
21 ar << (uint16_t)4;
22 ar << (int32_t)5;
23 ar << (uint32_t)6;
24 ar << (int64_t)7;
25 ar << (uint64_t)8;
26 ar << (char)9;
27 ar << (unsigned char)10;
28 ar << (short)11;
29 ar << (unsigned short)12;
30 ar << (int)13;
31 ar << (unsigned int)14;
32 ar << (long)15;
33 ar << (unsigned long)16;
34 ar << (long long)17;
35 ar << (unsigned long long)18;
36 ar.close();
37 }
38 mb.setPos( 0 );
39 {
40 Bu::Archive ar( mb, Bu::Archive::load );
41 int8_t p1;
42 uint8_t p2;
43 int16_t p3;
44 uint16_t p4;
45 int32_t p5;
46 uint32_t p6;
47 int64_t p7;
48 uint64_t p8;
49 char p9;
50 unsigned char p10;
51 short p11;
52 unsigned short p12;
53 int p13;
54 unsigned int p14;
55 long p15;
56 unsigned long p16;
57 long long p17;
58 unsigned long long p18;
59 ar >> p1;
60 ar >> p2;
61 ar >> p3;
62 ar >> p4;
63 ar >> p5;
64 ar >> p6;
65 ar >> p7;
66 ar >> p8;
67 ar >> p9;
68 ar >> p10;
69 ar >> p11;
70 ar >> p12;
71 ar >> p13;
72 ar >> p14;
73 ar >> p15;
74 ar >> p16;
75 ar >> p17;
76 ar >> p18;
77 unitTest( p1 == 1 );
78 unitTest( p2 == 2 );
79 unitTest( p3 == 3 );
80 unitTest( p4 == 4 );
81 unitTest( p5 == 5 );
82 unitTest( p6 == 6 );
83 unitTest( p7 == 7 );
84 unitTest( p8 == 8 );
85 unitTest( p9 == 9 );
86 unitTest( p10 == 10 );
87 unitTest( p11 == 11 );
88 unitTest( p12 == 12 );
89 unitTest( p13 == 13 );
90 unitTest( p14 == 14 );
91 unitTest( p15 == 15 );
92 unitTest( p16 == 16 );
93 unitTest( p17 == 17 );
94 unitTest( p18 == 18 );
95 ar.close();
96 }
97}
98
99{%testContainers}
100{
101 Bu::MemBuf mb;
102 {
103 Bu::Archive ar( mb, Bu::Archive::save );
104 Bu::FString sStr("This is a test string.");
105 Bu::List<int> lList;
106 lList.append( 10 );
107 lList.append( 20 );
108 lList.append( 30 );
109 lList.append( 40 );
110 ar << sStr;
111 ar << lList;
112 ar.close();
113 }
114 mb.setPos( 0 );
115 {
116 Bu::Archive ar( mb, Bu::Archive::load );
117 Bu::FString sStr;
118 Bu::List<int> lList;
119 ar >> sStr;
120 ar >> lList;
121 unitTest( sStr == "This is a test string." );
122 unitTest( lList.getSize() == 4 );
123 Bu::List<int>::iterator i = lList.begin();
124 unitTest( *i == 10 ); i++;
125 unitTest( *i == 20 ); i++;
126 unitTest( *i == 30 ); i++;
127 unitTest( *i == 40 );
128 ar.close();
129 }
130}
diff --git a/src/unit/array.cpp b/src/unit/array.cpp
deleted file mode 100644
index f7dc0ae..0000000
--- a/src/unit/array.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
1/*
2 * Copyright (C) 2007-2008 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/hash.h"
10#include "bu/array.h"
11
12class Unit : public Bu::UnitSuite
13{
14public:
15 Unit()
16 {
17 setName("Array");
18 addTest( Unit::general );
19 addTest( Unit::iterate1 );
20 addTest( Unit::iterate2 );
21 addTest( Unit::copy );
22 }
23
24 virtual ~Unit()
25 {
26 }
27
28 void general()
29 {
30 Bu::Array<int> ai;
31
32 ai.append( 5 );
33 ai.append( 10 );
34 unitTest( ai.getSize() == 2 );
35 unitTest( ai.getCapacity() == 10 );
36 unitTest( ai[0] == 5 );
37 unitTest( ai[1] == 10 );
38 }
39
40 void iterate1()
41 {
42 Bu::Array<int> ai;
43 for( int j = 0; j < 10; j++ )
44 ai.append( j );
45
46 int j = 0;
47 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ )
48 unitTest( (*i) == j++ );
49
50 const Bu::Array<int> &ci = ai;
51 j = 0;
52 for( Bu::Array<int>::const_iterator i = ci.begin(); i != ci.end(); i++ )
53 unitTest( (*i) == j++ );
54 }
55
56 void iterate2()
57 {
58 Bu::Array<int> ai;
59 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ )
60 unitFailed("Empty lists shouldn't be iterated through.");
61 }
62
63 void copy()
64 {
65 typedef Bu::Hash<Bu::FString, Bu::FString> StrHash;
66 typedef Bu::Array<StrHash> StrHashArray;
67
68 StrHash h1;
69 h1["Hi"] = "Yo";
70 h1["Bye"] = "Later";
71
72 StrHash h2;
73 h2["Test"] = "Bloop";
74 h2["Foo"] = "ooF";
75
76 StrHashArray a1;
77 a1.append( h1 );
78 a1.append( h2 );
79
80 StrHashArray a2(a1);
81
82 unitTest( a2[0].get("Hi") == "Yo" );
83 unitTest( a2[0].get("Bye") == "Later" );
84 unitTest( a2[1].get("Test") == "Bloop" );
85 unitTest( a2[1].get("Foo") == "ooF" );
86
87 StrHashArray a3;
88 a3 = a1;
89
90 unitTest( a3[0].get("Hi") == "Yo" );
91 unitTest( a3[0].get("Bye") == "Later" );
92 unitTest( a3[1].get("Test") == "Bloop" );
93 unitTest( a3[1].get("Foo") == "ooF" );
94 }
95};
96
97int main( int argc, char *argv[] )
98{
99 return Unit().run( argc, argv );
100}
101
diff --git a/src/unit/array.unit b/src/unit/array.unit
new file mode 100644
index 0000000..d5fc573
--- /dev/null
+++ b/src/unit/array.unit
@@ -0,0 +1,80 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/hash.h"
10#include "bu/array.h"
11
12{=Init}
13
14{%general}
15{
16 Bu::Array<int> ai;
17
18 ai.append( 5 );
19 ai.append( 10 );
20 unitTest( ai.getSize() == 2 );
21 unitTest( ai.getCapacity() == 10 );
22 unitTest( ai[0] == 5 );
23 unitTest( ai[1] == 10 );
24}
25
26{%iterate1}
27{
28 Bu::Array<int> ai;
29 for( int j = 0; j < 10; j++ )
30 ai.append( j );
31
32 int j = 0;
33 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ )
34 unitTest( (*i) == j++ );
35
36 const Bu::Array<int> &ci = ai;
37 j = 0;
38 for( Bu::Array<int>::const_iterator i = ci.begin(); i != ci.end(); i++ )
39 unitTest( (*i) == j++ );
40}
41
42{%iterate2}
43{
44 Bu::Array<int> ai;
45 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ )
46 unitFailed("Empty lists shouldn't be iterated through.");
47}
48
49{%copy}
50{
51 typedef Bu::Hash<Bu::FString, Bu::FString> StrHash;
52 typedef Bu::Array<StrHash> StrHashArray;
53
54 StrHash h1;
55 h1["Hi"] = "Yo";
56 h1["Bye"] = "Later";
57
58 StrHash h2;
59 h2["Test"] = "Bloop";
60 h2["Foo"] = "ooF";
61
62 StrHashArray a1;
63 a1.append( h1 );
64 a1.append( h2 );
65
66 StrHashArray a2(a1);
67
68 unitTest( a2[0].get("Hi") == "Yo" );
69 unitTest( a2[0].get("Bye") == "Later" );
70 unitTest( a2[1].get("Test") == "Bloop" );
71 unitTest( a2[1].get("Foo") == "ooF" );
72
73 StrHashArray a3;
74 a3 = a1;
75
76 unitTest( a3[0].get("Hi") == "Yo" );
77 unitTest( a3[0].get("Bye") == "Later" );
78 unitTest( a3[1].get("Test") == "Bloop" );
79 unitTest( a3[1].get("Foo") == "ooF" );
80}
diff --git a/src/unit/file.cpp b/src/unit/file.cpp
deleted file mode 100644
index cc19fac..0000000
--- a/src/unit/file.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
1/*
2 * Copyright (C) 2007-2008 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
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <unistd.h>
14
15class Unit : public Bu::UnitSuite
16{
17public:
18 Unit()
19 {
20 setName("File");
21 addTest( Unit::writeFull );
22 addTest( Unit::readBlocks );
23 addTest( Unit::readError1 );
24 addTest( Unit::readError2 );
25 }
26
27 virtual ~Unit() { }
28
29 //
30 // Tests go here
31 //
32 void writeFull()
33 {
34 Bu::File sf("testfile1", Bu::File::Write );
35 for( int c = 0; c < 256; c++ )
36 {
37 unsigned char ch = (unsigned char)c;
38 sf.write( &ch, 1 );
39 unitTest( sf.tell() == c+1 );
40 }
41 //unitTest( sf.canRead() == false );
42 //unitTest( sf.canWrite() == true );
43 //unitTest( sf.canSeek() == true );
44 sf.close();
45 struct stat sdat;
46 stat("testfile1", &sdat );
47 unitTest( sdat.st_size == 256 );
48 }
49
50 void readBlocks()
51 {
52 Bu::File sf("testfile1", Bu::File::Read );
53 unsigned char buf[50];
54 size_t total = 0;
55 for(;;)
56 {
57 size_t s = sf.read( buf, 50 );
58 for( size_t c = 0; c < s; c++ )
59 {
60 unitTest( buf[c] == (unsigned char)(c+total) );
61 }
62 total += s;
63 if( s < 50 )
64 {
65 unitTest( total == 256 );
66 unitTest( sf.isEOS() == true );
67 break;
68 }
69 }
70 sf.close();
71 }
72
73 void readError1()
74 {
75 try
76 {
77 Bu::File sf("doesn'texist", Bu::File::Read );
78 unitFailed("No exception thrown");
79 }
80 catch( Bu::FileException &e )
81 {
82 return;
83 }
84 }
85
86 void readError2()
87 {
88 Bu::File sf("testfile1", Bu::File::Read );
89 char buf[256];
90 int r = sf.read( buf, 256 );
91 unitTest( r == 256 );
92 // You have to read past the end to set the EOS flag.
93 unitTest( sf.isEOS() == false );
94 try
95 {
96 if( sf.read( buf, 5 ) > 0 )
97 {
98 unitFailed("Non-zero read result");
99 }
100 else
101 {
102 sf.close();
103 }
104 }
105 catch( Bu::FileException &e )
106 {
107 sf.close();
108 return;
109 }
110 }
111};
112
113int main( int argc, char *argv[] )
114{
115 return Unit().run( argc, argv );
116}
117
diff --git a/src/unit/file.unit b/src/unit/file.unit
new file mode 100644
index 0000000..e6320ad
--- /dev/null
+++ b/src/unit/file.unit
@@ -0,0 +1,95 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/file.h"
10
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <unistd.h>
14
15{=Init}
16
17{%writeFull}
18{
19 Bu::File sf("testfile1", Bu::File::Write );
20 for( int c = 0; c < 256; c++ )
21 {
22 unsigned char ch = (unsigned char)c;
23 sf.write( &ch, 1 );
24 unitTest( sf.tell() == c+1 );
25 }
26 //unitTest( sf.canRead() == false );
27 //unitTest( sf.canWrite() == true );
28 //unitTest( sf.canSeek() == true );
29 sf.close();
30 struct stat sdat;
31 stat("testfile1", &sdat );
32 unitTest( sdat.st_size == 256 );
33}
34
35{%readBlocks}
36{
37 Bu::File sf("testfile1", Bu::File::Read );
38 unsigned char buf[50];
39 size_t total = 0;
40 for(;;)
41 {
42 size_t s = sf.read( buf, 50 );
43 for( size_t c = 0; c < s; c++ )
44 {
45 unitTest( buf[c] == (unsigned char)(c+total) );
46 }
47 total += s;
48 if( s < 50 )
49 {
50 unitTest( total == 256 );
51 unitTest( sf.isEOS() == true );
52 break;
53 }
54 }
55 sf.close();
56}
57
58{%readError1}
59{
60 try
61 {
62 Bu::File sf("doesn'texist", Bu::File::Read );
63 unitFailed("No exception thrown");
64 }
65 catch( Bu::FileException &e )
66 {
67 return;
68 }
69}
70
71{%readError2}
72{
73 Bu::File sf("testfile1", Bu::File::Read );
74 char buf[256];
75 int r = sf.read( buf, 256 );
76 unitTest( r == 256 );
77 // You have to read past the end to set the EOS flag.
78 unitTest( sf.isEOS() == false );
79 try
80 {
81 if( sf.read( buf, 5 ) > 0 )
82 {
83 unitFailed("Non-zero read result");
84 }
85 else
86 {
87 sf.close();
88 }
89 }
90 catch( Bu::FileException &e )
91 {
92 sf.close();
93 return;
94 }
95}
diff --git a/src/unit/fstring.cpp b/src/unit/fstring.cpp
deleted file mode 100644
index 9430a83..0000000
--- a/src/unit/fstring.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
1/*
2 * Copyright (C) 2007-2008 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/fstring.h"
9#include "bu/unitsuite.h"
10
11#include <dirent.h>
12
13class Unit : public Bu::UnitSuite
14{
15public:
16 Unit()
17 {
18 setName("FString");
19 addTest( Unit::compare1 );
20 addTest( Unit::compare2 );
21 addTest( Unit::appendSingle );
22 addTest( Unit::shared1 );
23 addTest( Unit::insert );
24 addTest( Unit::remove );
25 addTest( Unit::add1 );
26 addTest( Unit::add2 );
27 addTest( Unit::add3 );
28 addTest( Unit::add4 );
29 addTest( Unit::add5 );
30 addTest( Unit::add6 );
31 addTest( Unit::subStr1 );
32 }
33
34 virtual ~Unit()
35 {
36 }
37
38 void compare1()
39 {
40 Bu::FString b("Bob");
41 unitTest( !(b == "Bobo") );
42 unitTest( b == "Bob" );
43 }
44
45 void compare2()
46 {
47 Bu::FString b("Bobo");
48 unitTest( !(b == "Bob") );
49 unitTest( b == "Bobo" );
50 }
51
52 void appendSingle()
53 {
54 Bu::FString b;
55 for( char l = 'a'; l < 'g'; l++ )
56 b += l;
57 unitTest( b == "abcdef" );
58 unitTest( strcmp( b.getStr(), "abcdef" ) == 0 );
59 }
60
61 void shared1()
62 {
63 Bu::FString a("Hey there");
64 Bu::FString b( a );
65 unitTest( a.getStr() == b.getStr() );
66 b += " guy";
67 unitTest( a.getStr() != b.getStr() );
68 a = b;
69 unitTest( a.getStr() == b.getStr() );
70 }
71
72 void insert()
73 {
74 Bu::FString a("abcd");
75 a.insert( 2, "-!-", 3 );
76 unitTest( a == "ab-!-cd" );
77
78 a.insert( 0, "!!", 2 );
79 unitTest( a == "!!ab-!-cd" );
80
81 a.insert( -10, "789", 3 );
82 unitTest( a == "789!!ab-!-cd" );
83
84 a.insert( 12, "89", 2 );
85 unitTest( a == "789!!ab-!-cd89" );
86
87 a.insert( 1203, "12", 2 );
88 unitTest( a == "789!!ab-!-cd8912" );
89 }
90
91 void remove()
92 {
93 Bu::FString a("abHEYcd");
94 a.remove( 2, 3 );
95 unitTest( a == "abcd" );
96 a.remove( 2, 5 );
97 unitTest( a == "ab" );
98 a += "cdefghijklmnop";
99 a.remove( 5, 1 );
100 unitTest( a = "abcdeghijklmnop" );
101 }
102
103 void add1()
104 {
105 Bu::FString a("hi there");
106 Bu::FString b(", yeah!");
107 Bu::FString c = a + b;
108
109 unitTest( c == "hi there, yeah!" );
110 }
111
112 void add2()
113 {
114 Bu::FString a("hi there");
115 Bu::FString c = a + ", yeah!";
116
117 unitTest( c == "hi there, yeah!" );
118 }
119
120 void add3()
121 {
122 Bu::FString a("hi there");
123 Bu::FString b(", yeah!");
124 Bu::FString c = a + ", Mr. Man" + b;
125
126 unitTest( c == "hi there, Mr. Man, yeah!" );
127 }
128
129 void add4()
130 {
131 Bu::FString b(", yeah!");
132 Bu::FString c = "hi there" + b;
133
134 unitTest( c == "hi there, yeah!" );
135 }
136
137 void add5()
138 {
139 Bu::FString b;
140 Bu::FString c = "sup?";
141 b += "hey, " + c;
142
143 unitTest( b == "hey, sup?" );
144 }
145
146 void add6()
147 {
148 Bu::FString a("Hello");
149 char b[256] = {"Dude"};
150 Bu::FString c = a + "/" + b;
151
152 unitTest( c == "Hello/Dude" );
153 }
154
155 void subStr1()
156 {
157 Bu::FString a("abcdefghijklmnop");
158 unitTest( a.getSubStr( 5, 3 ) == "fgh" );
159 unitTest( a.getSubStr( 10 ) == "klmnop" );
160 unitTest( a.getSubStr( 40 ) == "" );
161 unitTest( a.getSubStr( -10 ) == "abcdefghijklmnop" );
162 unitTest( a.getSubStr( -15, 4 ) == "abcd" );
163 }
164};
165
166int main( int argc, char *argv[] )
167{
168 return Unit().run( argc, argv );
169}
170
diff --git a/src/unit/fstring.unit b/src/unit/fstring.unit
new file mode 100644
index 0000000..93065fe
--- /dev/null
+++ b/src/unit/fstring.unit
@@ -0,0 +1,140 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/fstring.h"
10
11#include <dirent.h>
12
13{=Init}
14
15{%compare1}
16{
17 Bu::FString b("Bob");
18 unitTest( !(b == "Bobo") );
19 unitTest( b == "Bob" );
20}
21
22{%compare2}
23{
24 Bu::FString b("Bobo");
25 unitTest( !(b == "Bob") );
26 unitTest( b == "Bobo" );
27}
28
29{%appendSingle}
30{
31 Bu::FString b;
32 for( char l = 'a'; l < 'g'; l++ )
33 b += l;
34 unitTest( b == "abcdef" );
35 unitTest( strcmp( b.getStr(), "abcdef" ) == 0 );
36}
37
38{%shared1}
39{
40 Bu::FString a("Hey there");
41 Bu::FString b( a );
42 unitTest( a.getStr() == b.getStr() );
43 b += " guy";
44 unitTest( a.getStr() != b.getStr() );
45 a = b;
46 unitTest( a.getStr() == b.getStr() );
47}
48
49{%insert}
50{
51 Bu::FString a("abcd");
52 a.insert( 2, "-!-", 3 );
53 unitTest( a == "ab-!-cd" );
54
55 a.insert( 0, "!!", 2 );
56 unitTest( a == "!!ab-!-cd" );
57
58 a.insert( -10, "789", 3 );
59 unitTest( a == "789!!ab-!-cd" );
60
61 a.insert( 12, "89", 2 );
62 unitTest( a == "789!!ab-!-cd89" );
63
64 a.insert( 1203, "12", 2 );
65 unitTest( a == "789!!ab-!-cd8912" );
66}
67
68{%remove}
69{
70 Bu::FString a("abHEYcd");
71 a.remove( 2, 3 );
72 unitTest( a == "abcd" );
73 a.remove( 2, 5 );
74 unitTest( a == "ab" );
75 a += "cdefghijklmnop";
76 a.remove( 5, 1 );
77 unitTest( a = "abcdeghijklmnop" );
78}
79
80{%add1}
81{
82 Bu::FString a("hi there");
83 Bu::FString b(", yeah!");
84 Bu::FString c = a + b;
85
86 unitTest( c == "hi there, yeah!" );
87}
88
89{%add2}
90{
91 Bu::FString a("hi there");
92 Bu::FString c = a + ", yeah!";
93
94 unitTest( c == "hi there, yeah!" );
95}
96
97{%add3}
98{
99 Bu::FString a("hi there");
100 Bu::FString b(", yeah!");
101 Bu::FString c = a + ", Mr. Man" + b;
102
103 unitTest( c == "hi there, Mr. Man, yeah!" );
104}
105
106{%add4}
107{
108 Bu::FString b(", yeah!");
109 Bu::FString c = "hi there" + b;
110
111 unitTest( c == "hi there, yeah!" );
112}
113
114{%add5}
115{
116 Bu::FString b;
117 Bu::FString c = "sup?";
118 b += "hey, " + c;
119
120 unitTest( b == "hey, sup?" );
121}
122
123{%add6}
124{
125 Bu::FString a("Hello");
126 char b[256] = {"Dude"};
127 Bu::FString c = a + "/" + b;
128
129 unitTest( c == "Hello/Dude" );
130}
131
132{%subStr1}
133{
134 Bu::FString a("abcdefghijklmnop");
135 unitTest( a.getSubStr( 5, 3 ) == "fgh" );
136 unitTest( a.getSubStr( 10 ) == "klmnop" );
137 unitTest( a.getSubStr( 40 ) == "" );
138 unitTest( a.getSubStr( -10 ) == "abcdefghijklmnop" );
139 unitTest( a.getSubStr( -15, 4 ) == "abcd" );
140}
diff --git a/src/unit/hash.cpp b/src/unit/hash.cpp
deleted file mode 100644
index e04a656..0000000
--- a/src/unit/hash.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
1/*
2 * Copyright (C) 2007-2008 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/fstring.h"
9#include "bu/hash.h"
10#include "bu/unitsuite.h"
11
12#include <stdio.h>
13
14class Unit : public Bu::UnitSuite
15{
16private:
17 typedef Bu::Hash<Bu::FString, int> StrIntHash;
18 typedef Bu::Hash<Bu::FString, Bu::FString> StrStrHash;
19 typedef Bu::Hash<int, Bu::FString> IntStrHash;
20
21public:
22 Unit()
23 {
24 setName("Hash");
25 addTest( Unit::insert1 );
26 addTest( Unit::insert2 );
27 addTest( Unit::insert3 );
28 addTest( Unit::probe1 );
29 addTest( Unit::erase1 );
30 }
31
32 virtual ~Unit()
33 {
34 }
35
36 void probe1()
37 {
38 StrIntHash h;
39 char buf[20];
40 for(int i=1;i<10000;i++)
41 {
42 sprintf(buf,"%d",i);
43 Bu::FString sTmp(buf);
44 h[sTmp] = i;
45 unitTest( h.has(sTmp) );
46 }
47 }
48
49 void insert1()
50 {
51 StrIntHash h;
52 h["Hi"] = 42;
53 unitTest( h["Hi"] == 42 );
54 }
55
56 void insert2()
57 {
58 StrStrHash h;
59 h["Hi"] = "Yo";
60 h["Bye"] = "Later";
61 unitTest( h["Hi"].getValue() == "Yo" );
62
63 StrStrHash h2(h);
64 unitTest( h2["Hi"].getValue() = "Yo" );
65 unitTest( h2["Bye"].getValue() = "Later" );
66
67 StrStrHash h3;
68 h3 = h;
69 unitTest( h3["Hi"].getValue() = "Yo" );
70 unitTest( h3["Bye"].getValue() = "Later" );
71 }
72
73 void insert3()
74 {
75 IntStrHash h;
76
77 for( unsigned int i=1; i<50; i++ )
78 {
79 h[i] = "testing";
80 unitTest( h.getSize() == i );
81 }
82 }
83
84 void erase1()
85 {
86 StrIntHash h;
87 h.insert("Number 1", 1 );
88 h.insert("Number 2", 2 );
89 h.insert("Number 3", 3 );
90 h.erase("Number 2");
91 h.get("Number 3");
92 try {
93 h.get("Number 2");
94 unitFailed("h.get(\"Number 2\") should have thrown an exception.");
95 } catch( Bu::HashException &e ) { }
96
97 /* printf("\n");
98 for( StrIntHash::iterator i = h.begin(); i != h.end(); i++ )
99 {
100 printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() );
101 } */
102 }
103};
104
105int main( int argc, char *argv[] )
106{
107 return Unit().run( argc, argv );
108}
109
diff --git a/src/unit/hash.unit b/src/unit/hash.unit
new file mode 100644
index 0000000..bd7da61
--- /dev/null
+++ b/src/unit/hash.unit
@@ -0,0 +1,86 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/fstring.h"
10#include "bu/hash.h"
11
12#include <stdio.h>
13
14typedef Bu::Hash<Bu::FString, int> StrIntHash;
15typedef Bu::Hash<Bu::FString, Bu::FString> StrStrHash;
16typedef Bu::Hash<int, Bu::FString> IntStrHash;
17
18{=Init}
19
20{%probe1}
21{
22 StrIntHash h;
23 char buf[20];
24 for(int i=1;i<10000;i++)
25 {
26 sprintf(buf,"%d",i);
27 Bu::FString sTmp(buf);
28 h[sTmp] = i;
29 unitTest( h.has(sTmp) );
30 }
31}
32
33{%insert1}
34{
35 StrIntHash h;
36 h["Hi"] = 42;
37 unitTest( h["Hi"] == 42 );
38}
39
40{%insert2}
41{
42 StrStrHash h;
43 h["Hi"] = "Yo";
44 h["Bye"] = "Later";
45 unitTest( h["Hi"].getValue() == "Yo" );
46
47 StrStrHash h2(h);
48 unitTest( h2["Hi"].getValue() = "Yo" );
49 unitTest( h2["Bye"].getValue() = "Later" );
50
51 StrStrHash h3;
52 h3 = h;
53 unitTest( h3["Hi"].getValue() = "Yo" );
54 unitTest( h3["Bye"].getValue() = "Later" );
55}
56
57{%insert3}
58{
59 IntStrHash h;
60
61 for( unsigned int i=1; i<50; i++ )
62 {
63 h[i] = "testing";
64 unitTest( h.getSize() == i );
65 }
66}
67
68{%erase1}
69{
70 StrIntHash h;
71 h.insert("Number 1", 1 );
72 h.insert("Number 2", 2 );
73 h.insert("Number 3", 3 );
74 h.erase("Number 2");
75 h.get("Number 3");
76 try {
77 h.get("Number 2");
78 unitFailed("h.get(\"Number 2\") should have thrown an exception.");
79 } catch( Bu::HashException &e ) { }
80
81/* printf("\n");
82 for( StrIntHash::iterator i = h.begin(); i != h.end(); i++ )
83 {
84 printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() );
85 } */
86}
diff --git a/src/unit/membuf.cpp b/src/unit/membuf.cpp
deleted file mode 100644
index dc02aa3..0000000
--- a/src/unit/membuf.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
1/*
2 * Copyright (C) 2007-2008 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/membuf.h"
10
11class Unit : public Bu::UnitSuite
12{
13public:
14 Unit()
15 {
16 setName("MemBuf");
17 addTest( Unit::testWriteRead01 );
18 addTest( Unit::testOverwrite1 );
19 }
20
21 virtual ~Unit()
22 {
23 }
24
25 void testWriteRead01()
26 {
27 Bu::MemBuf mb;
28 unitTest( mb.write("ab", 2 ) == 2 );
29 unitTest( mb.write("cde", 3 ) == 3 );
30 unitTest( mb.write("FG", 2 ) == 2 );
31
32 mb.setPos( 0 );
33
34 char buf[8];
35 buf[7] = '\0';
36 unitTest( mb.read( buf, 7 ) == 7 );
37 unitTest( !strncmp( buf, "abcdeFG", 7 ) );
38 unitTest( mb.read( buf, 7 ) == 0 );
39 mb.seek( -3 );
40 unitTest( mb.read( buf, 7 ) == 3 );
41 unitTest( !strncmp( buf, "eFG", 3 ) );
42 }
43
44 void testOverwrite1()
45 {
46 Bu::MemBuf mb;
47 unitTest( mb.write("0123456789") == 10 );
48 mb.setPos( 4 );
49 unitTest( mb.write("-5-") == 3 );
50 mb.setPos( 9 );
51 mb.write("Hey!!!");
52 unitTest( mb.tell() == 15 );
53 char buf[50];
54 mb.setPos( 0 );
55 buf[mb.read( buf, 50 )] = '\0';
56 unitTest( !strcmp( buf, "0123-5-78Hey!!!" ) );
57 }
58};
59
60int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); }
diff --git a/src/unit/membuf.unit b/src/unit/membuf.unit
new file mode 100644
index 0000000..aebf36c
--- /dev/null
+++ b/src/unit/membuf.unit
@@ -0,0 +1,45 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/membuf.h"
10
11{=Init}
12
13{%testWriteRead01}
14{
15 Bu::MemBuf mb;
16 unitTest( mb.write("ab", 2 ) == 2 );
17 unitTest( mb.write("cde", 3 ) == 3 );
18 unitTest( mb.write("FG", 2 ) == 2 );
19
20 mb.setPos( 0 );
21
22 char buf[8];
23 buf[7] = '\0';
24 unitTest( mb.read( buf, 7 ) == 7 );
25 unitTest( !strncmp( buf, "abcdeFG", 7 ) );
26 unitTest( mb.read( buf, 7 ) == 0 );
27 mb.seek( -3 );
28 unitTest( mb.read( buf, 7 ) == 3 );
29 unitTest( !strncmp( buf, "eFG", 3 ) );
30}
31
32{%testOverwrite1}
33{
34 Bu::MemBuf mb;
35 unitTest( mb.write("0123456789") == 10 );
36 mb.setPos( 4 );
37 unitTest( mb.write("-5-") == 3 );
38 mb.setPos( 9 );
39 mb.write("Hey!!!");
40 unitTest( mb.tell() == 15 );
41 char buf[50];
42 mb.setPos( 0 );
43 buf[mb.read( buf, 50 )] = '\0';
44 unitTest( !strcmp( buf, "0123-5-78Hey!!!" ) );
45}
diff --git a/src/unit/taf.cpp b/src/unit/taf.cpp
deleted file mode 100644
index e4b3ccc..0000000
--- a/src/unit/taf.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
1/*
2 * Copyright (C) 2007-2008 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/tafreader.h"
11#include "bu/tafwriter.h"
12#include "bu/membuf.h"
13
14#include <string.h>
15#include <unistd.h>
16
17class Unit : public Bu::UnitSuite
18{
19public:
20 Unit()
21 {
22 setName("taf");
23 addTest( Unit::read1 );
24 addTest( Unit::encode1 );
25 addTest( Unit::emptyStr1 );
26 addTest( Unit::incomplete1 );
27 }
28
29 virtual ~Unit()
30 {
31 }
32
33 void read1()
34 {
35#define FN_TMP ("/tmp/tmpXXXXXXXX")
36 Bu::FString sFnTmp(FN_TMP);
37 Bu::File fOut = Bu::File::tempFile( sFnTmp );
38 const char *data =
39"{test: name=\"Bob\"}"
40;
41 fOut.write(data,strlen(data));
42 fOut.close();
43
44 Bu::File fIn(sFnTmp.getStr(), Bu::File::Read );
45 Bu::TafReader tr(fIn);
46
47 Bu::TafGroup *tn = tr.readGroup();
48 unitTest( !strcmp("Bob", tn->getProperty("name").getStr()) );
49 delete tn;
50
51 unlink(sFnTmp.getStr());
52#undef FN_TMP
53 }
54
55 void encode1()
56 {
57 Bu::MemBuf mb;
58 Bu::TafWriter tw( mb );
59
60 Bu::TafGroup g("Test data");
61 Bu::FString sData( 256 );
62 for( int j = 0; j < 256; j++ )
63 sData[j] = (unsigned char)j;
64 g.addChild( new Bu::TafProperty("Encoded", sData) );
65 tw.writeGroup( &g );
66
67 static const char *cmpdata = "{\"Test data\":\n \"Encoded\"=\""
68 "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07"
69 "\\x08\\x09\\x0A\\x0B\\x0C\\x0D\\x0E\\x0F"
70 "\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17"
71 "\\x18\\x19\\x1A\\x1B\\x1C\\x1D\\x1E\\x1F"
72 " !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCD"
73 "EFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghi"
74 "jklmnopqrstuvwxyz{|}~\\x7F"
75 "\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87"
76 "\\x88\\x89\\x8A\\x8B\\x8C\\x8D\\x8E\\x8F"
77 "\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97"
78 "\\x98\\x99\\x9A\\x9B\\x9C\\x9D\\x9E\\x9F"
79 "\\xA0\\xA1\\xA2\\xA3\\xA4\\xA5\\xA6\\xA7"
80 "\\xA8\\xA9\\xAA\\xAB\\xAC\\xAD\\xAE\\xAF"
81 "\\xB0\\xB1\\xB2\\xB3\\xB4\\xB5\\xB6\\xB7"
82 "\\xB8\\xB9\\xBA\\xBB\\xBC\\xBD\\xBE\\xBF"
83 "\\xC0\\xC1\\xC2\\xC3\\xC4\\xC5\\xC6\\xC7"
84 "\\xC8\\xC9\\xCA\\xCB\\xCC\\xCD\\xCE\\xCF"
85 "\\xD0\\xD1\\xD2\\xD3\\xD4\\xD5\\xD6\\xD7"
86 "\\xD8\\xD9\\xDA\\xDB\\xDC\\xDD\\xDE\\xDF"
87 "\\xE0\\xE1\\xE2\\xE3\\xE4\\xE5\\xE6\\xE7"
88 "\\xE8\\xE9\\xEA\\xEB\\xEC\\xED\\xEE\\xEF"
89 "\\xF0\\xF1\\xF2\\xF3\\xF4\\xF5\\xF6\\xF7"
90 "\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\"\n}\n";
91 unitTest( mb.getString() == cmpdata );
92 mb.setPos( 0 );
93 Bu::TafReader tr( mb );
94 Bu::TafGroup *rg = tr.readGroup();
95 unitTest( rg->getProperty("Encoded") == sData );
96 delete rg;
97 }
98
99 void emptyStr1()
100 {
101 Bu::MemBuf mb;
102 Bu::TafWriter tw( mb );
103
104 Bu::TafGroup g("Test Group");
105 Bu::FString sVal;
106 g.addChild( new Bu::TafProperty("Lame", sVal) );
107 tw.writeGroup( &g );
108
109 unitTest(
110 mb.getString() == "{\"Test Group\":\n \"Lame\"=\"\"\n}\n" );
111 }
112
113 void incomplete1()
114 {
115 try
116 {
117 Bu::MemBuf mb("{Lame: \"Hello=\"");
118 Bu::TafReader tr( mb );
119 delete tr.readGroup();
120 unitFailed("Should have thrown an exception, didn't.");
121 }
122 catch( Bu::TafException &e )
123 {
124 // Woot
125 }
126 }
127};
128
129int main( int argc, char *argv[] )
130{
131 return Unit().run( argc, argv );
132}
133
diff --git a/src/unit/taf.unit b/src/unit/taf.unit
new file mode 100644
index 0000000..5588c85
--- /dev/null
+++ b/src/unit/taf.unit
@@ -0,0 +1,112 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/file.h"
10#include "bu/tafreader.h"
11#include "bu/tafwriter.h"
12#include "bu/membuf.h"
13
14#include <string.h>
15#include <unistd.h>
16
17{=Init}
18
19{%read1}
20{
21#define FN_TMP ("/tmp/tmpXXXXXXXX")
22 Bu::FString sFnTmp(FN_TMP);
23 Bu::File fOut = Bu::File::tempFile( sFnTmp );
24 const char *data =
25"{test: name=\"Bob\"}"
26;
27 fOut.write(data,strlen(data));
28 fOut.close();
29
30 Bu::File fIn(sFnTmp.getStr(), Bu::File::Read );
31 Bu::TafReader tr(fIn);
32
33 Bu::TafGroup *tn = tr.readGroup();
34 unitTest( !strcmp("Bob", tn->getProperty("name").getStr()) );
35 delete tn;
36
37 unlink(sFnTmp.getStr());
38#undef FN_TMP
39}
40
41{%encode1}
42{
43 Bu::MemBuf mb;
44 Bu::TafWriter tw( mb );
45
46 Bu::TafGroup g("Test data");
47 Bu::FString sData( 256 );
48 for( int j = 0; j < 256; j++ )
49 sData[j] = (unsigned char)j;
50 g.addChild( new Bu::TafProperty("Encoded", sData) );
51 tw.writeGroup( &g );
52
53 static const char *cmpdata = "{\"Test data\":\n \"Encoded\"=\""
54 "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07"
55 "\\x08\\x09\\x0A\\x0B\\x0C\\x0D\\x0E\\x0F"
56 "\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17"
57 "\\x18\\x19\\x1A\\x1B\\x1C\\x1D\\x1E\\x1F"
58 " !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCD"
59 "EFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghi"
60 "jklmnopqrstuvwxyz{|}~\\x7F"
61 "\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87"
62 "\\x88\\x89\\x8A\\x8B\\x8C\\x8D\\x8E\\x8F"
63 "\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97"
64 "\\x98\\x99\\x9A\\x9B\\x9C\\x9D\\x9E\\x9F"
65 "\\xA0\\xA1\\xA2\\xA3\\xA4\\xA5\\xA6\\xA7"
66 "\\xA8\\xA9\\xAA\\xAB\\xAC\\xAD\\xAE\\xAF"
67 "\\xB0\\xB1\\xB2\\xB3\\xB4\\xB5\\xB6\\xB7"
68 "\\xB8\\xB9\\xBA\\xBB\\xBC\\xBD\\xBE\\xBF"
69 "\\xC0\\xC1\\xC2\\xC3\\xC4\\xC5\\xC6\\xC7"
70 "\\xC8\\xC9\\xCA\\xCB\\xCC\\xCD\\xCE\\xCF"
71 "\\xD0\\xD1\\xD2\\xD3\\xD4\\xD5\\xD6\\xD7"
72 "\\xD8\\xD9\\xDA\\xDB\\xDC\\xDD\\xDE\\xDF"
73 "\\xE0\\xE1\\xE2\\xE3\\xE4\\xE5\\xE6\\xE7"
74 "\\xE8\\xE9\\xEA\\xEB\\xEC\\xED\\xEE\\xEF"
75 "\\xF0\\xF1\\xF2\\xF3\\xF4\\xF5\\xF6\\xF7"
76 "\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\"\n}\n";
77 unitTest( mb.getString() == cmpdata );
78 mb.setPos( 0 );
79 Bu::TafReader tr( mb );
80 Bu::TafGroup *rg = tr.readGroup();
81 unitTest( rg->getProperty("Encoded") == sData );
82 delete rg;
83}
84
85{%emptyStr1}
86{
87 Bu::MemBuf mb;
88 Bu::TafWriter tw( mb );
89
90 Bu::TafGroup g("Test Group");
91 Bu::FString sVal;
92 g.addChild( new Bu::TafProperty("Lame", sVal) );
93 tw.writeGroup( &g );
94
95 unitTest(
96 mb.getString() == "{\"Test Group\":\n \"Lame\"=\"\"\n}\n" );
97}
98
99{%incomplete1}
100{
101 try
102 {
103 Bu::MemBuf mb("{Lame: \"Hello=\"");
104 Bu::TafReader tr( mb );
105 delete tr.readGroup();
106 unitFailed("Should have thrown an exception, didn't.");
107 }
108 catch( Bu::TafException &e )
109 {
110 // Woot
111 }
112}
diff --git a/src/unit/xml.cpp b/src/unit/xml.cpp
deleted file mode 100644
index e845cc1..0000000
--- a/src/unit/xml.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
1/*
2 * Copyright (C) 2007-2008 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/fstring.h"
9#include "bu/unitsuite.h"
10#include "bu/xmlreader.h"
11#include "bu/membuf.h"
12
13class Unit : public Bu::UnitSuite
14{
15public:
16 Unit()
17 {
18 setName("Xml");
19 addTest( Unit::declaration );
20 }
21
22 virtual ~Unit()
23 {
24 }
25
26 void declaration()
27 {
28 Bu::FString sXml("<?xml ?> <hi />");
29 Bu::MemBuf buf( sXml );
30 Bu::XmlReader xr( buf );
31 }
32
33};
34
35int main( int argc, char *argv[] )
36{
37 return Unit().run( argc, argv );
38}
39
diff --git a/src/unit/xml.unit b/src/unit/xml.unit
new file mode 100644
index 0000000..738ad66
--- /dev/null
+++ b/src/unit/xml.unit
@@ -0,0 +1,20 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/fstring.h"
10#include "bu/xmlreader.h"
11#include "bu/membuf.h"
12
13{=Init}
14
15{%declaration}
16{
17 Bu::FString sXml("<?xml ?> <hi />");
18 Bu::MemBuf buf( sXml );
19 Bu::XmlReader xr( buf );
20}
diff --git a/src/unitsuite.cpp b/src/unitsuite.cpp
index 0008721..b61baa5 100644
--- a/src/unitsuite.cpp
+++ b/src/unitsuite.cpp
@@ -72,7 +72,7 @@ int Bu::UnitSuite::run( int /*argc*/, char * /*argv */ [] )
72 return 0; 72 return 0;
73} 73}
74 74
75void Bu::UnitSuite::add( Test fTest, Bu::FString sName ) 75void Bu::UnitSuite::add( Test fTest, const Bu::FString &sName, Expect e )
76{ 76{
77 TestInfo ti; 77 TestInfo ti;
78 ti.sName = sName; 78 ti.sName = sName;
diff --git a/src/unitsuite.h b/src/unitsuite.h
index d27e322..d75211a 100644
--- a/src/unitsuite.h
+++ b/src/unitsuite.h
@@ -81,9 +81,15 @@ namespace Bu
81 { 81 {
82 optStopOnError = 0x000001 82 optStopOnError = 0x000001
83 }; 83 };
84
85 enum Expect
86 {
87 expectPass,
88 expectFail
89 };
84 90
85 protected: 91 protected:
86 void add( Test fTest, Bu::FString sName ); 92 void add( Test fTest, const Bu::FString &sName, Expect e=expectPass );
87 void setName( const FString &sName ); 93 void setName( const FString &sName );
88 94
89 private: 95 private: