aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2020-02-04 19:27:37 -0800
committerMike Buland <eichlan@xagasoft.com>2020-02-04 19:27:37 -0800
commit9459cb32504c9d269bc467190bba41897f86a97b (patch)
treee16a916fbbd071462ca0e9ce94fae88f062f289a /src
parentfd830279725081d95e3f08f768ed6879c92fe838 (diff)
parented5e7684b766a3914b30c5b449608542695fd3b8 (diff)
downloadlibbu++-9459cb32504c9d269bc467190bba41897f86a97b.tar.gz
libbu++-9459cb32504c9d269bc467190bba41897f86a97b.tar.bz2
libbu++-9459cb32504c9d269bc467190bba41897f86a97b.tar.xz
libbu++-9459cb32504c9d269bc467190bba41897f86a97b.zip
Merge branch 'master' into unicode
Diffstat (limited to '')
-rw-r--r--src/stable/exceptionparse.cpp14
-rw-r--r--src/stable/exceptionparse.h17
-rw-r--r--src/stable/hash.h40
-rw-r--r--src/unstable/json.cpp208
-rw-r--r--src/unstable/json.h39
-rw-r--r--src/unstable/myriadfs.cpp30
6 files changed, 231 insertions, 117 deletions
diff --git a/src/stable/exceptionparse.cpp b/src/stable/exceptionparse.cpp
new file mode 100644
index 0000000..98440a4
--- /dev/null
+++ b/src/stable/exceptionparse.cpp
@@ -0,0 +1,14 @@
1/*
2 * Copyright (C) 2007-2019 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 "exceptionparse.h"
9
10namespace Bu
11{
12 subExceptionDef( ExceptionParse );
13}
14
diff --git a/src/stable/exceptionparse.h b/src/stable/exceptionparse.h
new file mode 100644
index 0000000..83eddb0
--- /dev/null
+++ b/src/stable/exceptionparse.h
@@ -0,0 +1,17 @@
1/*
2 * Copyright (C) 2007-2019 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#ifndef BU_EXCPTION_PARSE_H
8#define BU_EXCPTION_PARSE_H
9
10#include "bu/exceptionbase.h"
11
12namespace Bu
13{
14 subExceptionDecl( ExceptionParse );
15}
16
17#endif
diff --git a/src/stable/hash.h b/src/stable/hash.h
index 7f4066e..0c5bd9e 100644
--- a/src/stable/hash.h
+++ b/src/stable/hash.h
@@ -211,7 +211,7 @@ namespace Bu
211 return 0; 211 return 0;
212 } 212 }
213 213
214 uint32_t probe( uint32_t hash, const key &k, bool &bFill, bool rehash=true ) 214 uint32_t probe( uint32_t hash, const key &k, bool &bFill, bool bRehash=true )
215 { 215 {
216 init(); 216 init();
217 217
@@ -244,9 +244,9 @@ namespace Bu
244 244
245 // This is our insurance, if the table is full, then go ahead and 245 // This is our insurance, if the table is full, then go ahead and
246 // rehash, then try again. 246 // rehash, then try again.
247 if( (isFilled( nCur ) || j == 32) && rehash == true ) 247 if( (isFilled( nCur ) || j == 32) && bRehash == true )
248 { 248 {
249 reHash( szCalc( nCapacity, nFilled, nDeleted ) ); 249 rehash( szCalc( nCapacity, nFilled, nDeleted ) );
250 250
251 // This is potentially dangerous, and could cause an infinite loop. 251 // This is potentially dangerous, and could cause an infinite loop.
252 // Be careful writing probe, eh? 252 // Be careful writing probe, eh?
@@ -309,7 +309,7 @@ namespace Bu
309 } 309 }
310 } 310 }
311 311
312 void reHash( uint32_t nNewSize ) 312 void rehash( uint32_t nNewSize )
313 { 313 {
314 //printf("--rehash: %d --> %d (%d, %d)\n", nCapacity, nNewSize, nFilled, nDeleted ); 314 //printf("--rehash: %d --> %d (%d, %d)\n", nCapacity, nNewSize, nFilled, nDeleted );
315 //printf("---REHASH---"); 315 //printf("---REHASH---");
@@ -386,11 +386,13 @@ namespace Bu
386 for( uint32_t j = 0; j < nCapacity; j++ ) 386 for( uint32_t j = 0; j < nCapacity; j++ )
387 { 387 {
388 if( isFilled( j ) ) 388 if( isFilled( j ) )
389 {
389 if( !isDeleted( j ) ) 390 if( !isDeleted( j ) )
390 { 391 {
391 va.destroy( &aValues[j] ); 392 va.destroy( &aValues[j] );
392 ka.destroy( &aKeys[j] ); 393 ka.destroy( &aKeys[j] );
393 } 394 }
395 }
394 } 396 }
395 va.deallocate( aValues, nCapacity ); 397 va.deallocate( aValues, nCapacity );
396 ka.deallocate( aKeys, nCapacity ); 398 ka.deallocate( aKeys, nCapacity );
@@ -501,6 +503,8 @@ namespace Bu
501 { 503 {
502 } 504 }
503 505
506 typedef Bu::List<key> KeyList;
507
504 /** 508 /**
505 * Get the current hash table capacity. (Changes at re-hash) 509 * Get the current hash table capacity. (Changes at re-hash)
506 *@returns (uint32_t) The current capacity. 510 *@returns (uint32_t) The current capacity.
@@ -1135,9 +1139,9 @@ namespace Bu
1135 * Get a list of all the keys in the hash table. 1139 * Get a list of all the keys in the hash table.
1136 *@returns (std::list<key_type>) The list of keys in the hash table. 1140 *@returns (std::list<key_type>) The list of keys in the hash table.
1137 */ 1141 */
1138 Bu::List<key> getKeys() const 1142 KeyList getKeys() const
1139 { 1143 {
1140 Bu::List<key> lKeys; 1144 KeyList lKeys;
1141 1145
1142 for( uint32_t j = 0; j < core->nCapacity; j++ ) 1146 for( uint32_t j = 0; j < core->nCapacity; j++ )
1143 { 1147 {
@@ -1171,6 +1175,30 @@ namespace Bu
1171 return lValues; 1175 return lValues;
1172 } 1176 }
1173 1177
1178 /**
1179 * This can be a very expensive operation, but when there are a decent
1180 * number of deleted entries it can be good to be able to clean them
1181 * up on your own terms.
1182 *
1183 * This will always allocate a new table and move all non-deleted items
1184 * over to it. The size of the new table depends on which resizing
1185 * calculator is selected. The default resize calculator will shrink
1186 * the table if it's mostly deleted/empty space.
1187 *
1188 * This will be done by the system whenever it deems necesarry, but
1189 * only during probing operations. That means that an insert could
1190 * trigger a rehash, which could be very expensive. If you know, for
1191 * example, that you'll be deleting most of the entries once a night
1192 * during a low-usage time, that would probably be a good time to
1193 * manually trigger a rehash and save the extra time on the next insert
1194 * after the cleanup. This is partucularly true for systems like
1195 * caches that need to be periodically cleaned up.
1196 */
1197 void rehash()
1198 {
1199 core->rehash( core->szCalc( core->nCapacity, core->nFilled, core->nDeleted ) );
1200 }
1201
1174 bool operator==( const MyType &rhs ) const 1202 bool operator==( const MyType &rhs ) const
1175 { 1203 {
1176 if( this == &rhs ) 1204 if( this == &rhs )
diff --git a/src/unstable/json.cpp b/src/unstable/json.cpp
index f6a8d52..9745a7f 100644
--- a/src/unstable/json.cpp
+++ b/src/unstable/json.cpp
@@ -1,12 +1,13 @@
1#include "bu/json.h" 1#include "bu/json.h"
2#include "bu/staticmembuf.h" 2#include "bu/staticmembuf.h"
3#include "bu/membuf.h" 3#include "bu/membuf.h"
4#include "bu/exceptionparse.h"
4 5
5#include "bu/sio.h" 6#include "bu/sio.h"
6 7
7#include <stdlib.h> 8#include <stdlib.h>
8 9
9#define next( txt ) readChar( c, sInput, "Unexpected end of stream while reading " txt "." ) 10#define next( txt ) readChar( ps, "Unexpected end of stream while reading " txt "." )
10 11
11Bu::Json::Json() : 12Bu::Json::Json() :
12 eType( Null ) 13 eType( Null )
@@ -75,10 +76,10 @@ Bu::Json::Json( Bu::Stream &sInput ) :
75 parse( sInput ); 76 parse( sInput );
76} 77}
77 78
78Bu::Json::Json( Bu::UtfChar &c, Bu::Stream &sInput ) : 79Bu::Json::Json( Bu::Json::ParseState &ps ) :
79 eType( Invalid ) 80 eType( Invalid )
80{ 81{
81 parse( c, sInput ); 82 parse( ps );
82} 83}
83 84
84Bu::Json::Json( const Json &rSrc ) : 85Bu::Json::Json( const Json &rSrc ) :
@@ -294,10 +295,10 @@ void Bu::Json::parse( Bu::Stream &sInput )
294{ 295{
295 reset(); 296 reset();
296 297
297 Bu::UtfChar c; 298 ParseState ps( sInput );
298 next("json"); 299 next("json");
299 300
300 parse( c, sInput ); 301 parse( ps );
301} 302}
302 303
303void Bu::Json::parse( const Bu::String &sInput ) 304void Bu::Json::parse( const Bu::String &sInput )
@@ -306,40 +307,42 @@ void Bu::Json::parse( const Bu::String &sInput )
306 parse( mb ); 307 parse( mb );
307} 308}
308 309
309void Bu::Json::parse( Bu::UtfChar &c, Bu::Stream &sInput ) 310void Bu::Json::parse( ParseState &ps )
310{ 311{
311 while( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) 312 while( ps.c == ' ' || ps.c == '\t' || ps.c == '\r' || ps.c == '\n' )
312 { 313 {
313 next( "json" ); 314 next( "json" );
314 } 315 }
315 if( c == '"' ) 316 if( ps.c == '"' )
316 { 317 {
317 // String 318 // String
318 parseString( c, sInput ); 319 parseString( ps );
319 } 320 }
320 else if( c == '{' ) 321 else if( ps.c == '{' )
321 { 322 {
322 // Object 323 // Object
323 parseObject( c, sInput ); 324 parseObject( ps );
324 } 325 }
325 else if( c == '[' ) 326 else if( ps.c == '[' )
326 { 327 {
327 // Array 328 // Array
328 parseArray( c, sInput ); 329 parseArray( ps );
329 } 330 }
330 else if( c == '-' || (c >= '0' && c <= '9') ) 331 else if( ps.c == '-' || (ps.c >= '0' && ps.c <= '9') )
331 { 332 {
332 // Number -- apparently they can't start with a period 333 // Number -- apparently they can't start with a period
333 parseNumber( c, sInput ); 334 parseNumber( ps );
334 } 335 }
335 else if( c == 't' || c == 'f' || c == 'n' ) 336 else if( ps.c == 't' || ps.c == 'f' || ps.c == 'n' )
336 { 337 {
337 // True / false / null 338 // True / false / null
338 parseLiteral( c, sInput ); 339 parseLiteral( ps );
339 } 340 }
340 else 341 else
341 { 342 {
342 throw Bu::ExceptionBase("Invalid characters in json stream."); 343 ps.error(
344 Bu::String("Invalid json: Invalid character: '%1'.").arg( (char)ps.c )
345 );
343 } 346 }
344} 347}
345 348
@@ -382,7 +385,7 @@ void Bu::Json::write( Bu::Stream &sOutput ) const
382 switch( eType ) 385 switch( eType )
383 { 386 {
384 case Invalid: 387 case Invalid:
385 throw Bu::ExceptionBase("Invalid type in json"); 388 throw Bu::ExceptionBase("Invalid type in json.");
386 break; 389 break;
387 390
388 case Object: 391 case Object:
@@ -537,22 +540,21 @@ bool Bu::Json::operator==( const Bu::String &rRhs )
537 return (*uDat.pString) == rRhs; 540 return (*uDat.pString) == rRhs;
538} 541}
539 542
540void Bu::Json::parseString( Bu::UtfChar &c, Bu::Stream &sInput, 543void Bu::Json::parseString( Bu::Json::ParseState &ps, Bu::UtfString &sOut )
541 Bu::UtfString &sOut )
542{ 544{
543 skipWs( c, sInput ); 545 skipWs( ps );
544 bool bEscape = false; 546 bool bEscape = false;
545 for(;;) 547 for(;;)
546 { 548 {
547 next( "string" ); 549 next( "string" );
548 if( bEscape ) 550 if( bEscape )
549 { 551 {
550 switch( c ) 552 switch( ps.c )
551 { 553 {
552 case '"': 554 case '"':
553 case '\\': 555 case '\\':
554 case '/': 556 case '/':
555 sOut += c; 557 sOut += ps.c;
556 break; 558 break;
557 559
558 case 'b': 560 case 'b':
@@ -580,8 +582,9 @@ void Bu::Json::parseString( Bu::UtfChar &c, Bu::Stream &sInput,
580 break; 582 break;
581 583
582 default: 584 default:
583 throw Bu::ExceptionBase( 585 ps.error(
584 "Invalid escape sequence encountered in string." 586 Bu::String("Invalid json: Invalid escape sequence: "
587 " '\\%1'.").arg( (char)ps.c )
585 ); 588 );
586 break; 589 break;
587 } 590 }
@@ -589,37 +592,37 @@ void Bu::Json::parseString( Bu::UtfChar &c, Bu::Stream &sInput,
589 } 592 }
590 else 593 else
591 { 594 {
592 if( c == '\\' ) 595 if( ps.c == '\\' )
593 bEscape = true; 596 bEscape = true;
594 else if( c == '"' ) 597 else if( ps.c == '"' )
595 { 598 {
596 readChar( c, sInput ); 599 readChar( ps );
597 break; 600 break;
598 } 601 }
599 else 602 else
600 sOut += c; 603 sOut += ps.c;
601 } 604 }
602 } 605 }
603} 606}
604 607
605void Bu::Json::parseString( Bu::UtfChar &c, Bu::Stream &sInput ) 608void Bu::Json::parseString( Bu::Json::ParseState &ps )
606{ 609{
607 eType = String; 610 eType = String;
608 uDat.pString = new Bu::UtfString(); 611 uDat.pString = new Bu::UtfString();
609 parseString( c, sInput, *uDat.pString ); 612 parseString( ps, *uDat.pString );
610} 613}
611 614
612void Bu::Json::parseObject( Bu::UtfChar &c, Bu::Stream &sInput ) 615void Bu::Json::parseObject( Bu::Json::ParseState &ps )
613{ 616{
614 skipWs( c, sInput ); 617 skipWs( ps );
615 eType = Object; 618 eType = Object;
616 uDat.pObject = new JsonHash(); 619 uDat.pObject = new JsonHash();
617 620
618 next( "object" ); 621 next( "object" );
619 skipWs( c, sInput ); 622 skipWs( ps );
620 623
621 // Check to see if it's an empty object. 624 // Check to see if it's an empty object.
622 if( c == '}' ) 625 if( ps.c == '}' )
623 { 626 {
624 next("object"); 627 next("object");
625 return; 628 return;
@@ -627,35 +630,45 @@ void Bu::Json::parseObject( Bu::UtfChar &c, Bu::Stream &sInput )
627 630
628 for(;;) 631 for(;;)
629 { 632 {
633 skipWs( ps );
634 if( ps.c != '"' )
635 {
636 ps.error(
637 Bu::String("Invalid json: expected string as key in object, "
638 "found '%1'.").arg( (char)ps.c )
639 );
640 }
630 Bu::UtfString sKey; 641 Bu::UtfString sKey;
631 parseString( c, sInput, sKey ); 642 parseString( ps, sKey );
632 skipWs( c, sInput ); 643 skipWs( ps );
633 if( c != ':' ) 644 if( ps.c != ':' )
634 { 645 {
635 throw Bu::ExceptionBase( 646 ps.error(
636 "Invalid json, expected colon after key in object." 647 Bu::String("Invalid json: expected colon after key in object, "
648 "found '%1'.").arg( (char)ps.c )
637 ); 649 );
638 } 650 }
639 next("object"); 651 next("object");
640 uDat.pObject->insert( sKey, new Json( c, sInput ) ); 652 uDat.pObject->insert( sKey, new Json( ps ) );
641 skipWs( c, sInput ); 653 skipWs( ps );
642 if( c == '}' ) 654 if( ps.c == '}' )
643 { 655 {
644 readChar( c, sInput ); 656 readChar( ps );
645 break; 657 break;
646 } 658 }
647 else if( c == ',' ) 659 else if( ps.c == ',' )
648 next( "object" ); 660 next( "object" );
649 else 661 else
650 throw Bu::ExceptionBase( 662 ps.error(
651 "Invalid json, expected comma or } after value in object." 663 Bu::String("Invalid json: expected comma or } after value "
664 "in object, found '%1'.").arg( (char)ps.c )
652 ); 665 );
653 } 666 }
654} 667}
655 668
656void Bu::Json::parseArray( Bu::UtfChar &c, Bu::Stream &sInput ) 669void Bu::Json::parseArray( Bu::Json::ParseState &ps )
657{ 670{
658 skipWs( c, sInput ); 671 skipWs( ps );
659 672
660 eType = Array; 673 eType = Array;
661 uDat.pArray = new JsonList(); 674 uDat.pArray = new JsonList();
@@ -663,7 +676,7 @@ void Bu::Json::parseArray( Bu::UtfChar &c, Bu::Stream &sInput )
663 next("array"); 676 next("array");
664 677
665 // Check to see if it's an empty array. 678 // Check to see if it's an empty array.
666 if( c == ']' ) 679 if( ps.c == ']' )
667 { 680 {
668 next("array"); 681 next("array");
669 return; 682 return;
@@ -671,74 +684,78 @@ void Bu::Json::parseArray( Bu::UtfChar &c, Bu::Stream &sInput )
671 684
672 for(;;) 685 for(;;)
673 { 686 {
674 uDat.pArray->append( new Json( c, sInput ) ); 687 uDat.pArray->append( new Json( ps ) );
675 skipWs( c, sInput ); 688 skipWs( ps );
676 if( c == ']' ) 689 if( ps.c == ']' )
677 { 690 {
678 readChar( c, sInput ); 691 readChar( ps );
679 break; 692 break;
680 } 693 }
681 else if( c == ',' ) 694 else if( ps.c == ',' )
682 { 695 {
683 next("array"); 696 next("array");
684 continue; 697 continue;
685 } 698 }
686 else 699 else
687 { 700 {
688 throw Bu::ExceptionBase( 701 ps.error(
689 "Invalid json, expected comma or ] after value in array." 702 Bu::String("Invalid json: expected comma or ] after value "
703 "in array, found '%1'.").arg( (char)ps.c )
690 ); 704 );
691 } 705 }
692 } 706 }
693} 707}
694 708
695void Bu::Json::parseNumber( Bu::UtfChar &c, Bu::Stream &sInput ) 709void Bu::Json::parseNumber( Bu::Json::ParseState &ps )
696{ 710{
697 skipWs( c, sInput ); 711 skipWs( ps );
698 712
699 Bu::String sBuf; 713 Bu::String sBuf;
700 if( c == '-' ) 714 if( ps.c == '-' )
701 { 715 {
702 sBuf += c; 716 sBuf += ps.c;
703 next( "number" ); 717 next( "number" );
704 } 718 }
705 bool bIntPart = true; 719 bool bIntPart = true;
706 do 720 do
707 { 721 {
708 if( c >= '0' && c <= '9' ) 722 if( ps.c >= '0' && ps.c <= '9' )
709 sBuf += c; 723 sBuf += ps.c;
710 else if( c == '.' && bIntPart == true ) 724 else if( ps.c == '.' && bIntPart == true )
711 { 725 {
712 bIntPart = false; 726 bIntPart = false;
713 sBuf += c; 727 sBuf += ps.c;
714 } 728 }
715 else if( c == ' ' || c == '\t' || c == '\n' || c == '\r' || 729 else if( ps.c == ' ' || ps.c == '\t' || ps.c == '\n' || ps.c == '\r' ||
716 c == '}' || c == ']' || c == ',' ) 730 ps.c == '}' || ps.c == ']' || ps.c == ',' )
717 { 731 {
718 break; 732 break;
719 } 733 }
720 else 734 else
721 { 735 {
722 throw Bu::ExceptionBase("Invalid character in number."); 736 ps.error(
737 Bu::String("Invalid json: Invalid character in number: '%1'.").
738 arg( (char)ps.c )
739 );
723 } 740 }
724 } while( readChar( c, sInput ) ); 741 } while( readChar( ps ) );
725 742
726 eType = Number; 743 eType = Number;
727 uDat.dNumber = atof( sBuf.getStr() ); 744 uDat.dNumber = atof( sBuf.getStr() );
728} 745}
729 746
730void Bu::Json::parseLiteral( Bu::UtfChar &c, Bu::Stream &sInput ) 747void Bu::Json::parseLiteral( Bu::Json::ParseState &ps )
731{ 748{
732 skipWs( c, sInput ); 749 skipWs( ps );
733 750
734 Bu::String s; 751 Bu::String s;
735 do 752 do
736 { 753 {
737 if( isWs( c ) || c == ',' || c == '}' || c == ']' ) 754 if( isWs( ps.c ) || ps.c == ',' || ps.c == '}' || ps.c == ']' )
738 break; 755 break;
739 else 756 else
740 s += c; 757 s += ps.c;
741 } while( readChar( c, sInput ) ); 758 } while( readChar( ps ) );
742 759
743 if( s == "true" ) 760 if( s == "true" )
744 { 761 {
@@ -757,22 +774,39 @@ void Bu::Json::parseLiteral( Bu::UtfChar &c, Bu::Stream &sInput )
757 } 774 }
758 else 775 else
759 { 776 {
760 throw Bu::ExceptionBase("Invalid literal token found."); 777 ps.error(
778 Bu::String("Invalid json: Invalid literal token found, '%1'.").
779 arg( s )
780 );
761 } 781 }
762} 782}
763 783
764bool Bu::Json::readChar( Bu::UtfChar &c, Bu::Stream &sInput ) 784bool Bu::Json::readChar( Bu::Json::ParseState &ps )
765{ 785{
766 if( Bu::UtfString::readPoint( sInput, c ) == 0 && sInput.isEos() ) 786 if( Bu::UtfString::readPoint( ps.sInput, ps.c ) == 0 && ps.sInput.isEos() )
767 return false; 787 return false;
788
789 if( ps.c == '\n' )
790 {
791 // Increment the line and set iChar to zero. This makes sense only
792 // beacuse we only complain after a charecter has been read, so this
793 // will be too large by one unless we start at zero.
794 ps.iLine++;
795 ps.iChar = 0;
796 }
797 else
798 {
799 ps.iChar++;
800 }
801
768 return true; 802 return true;
769} 803}
770 804
771void Bu::Json::readChar( Bu::UtfChar &c, Bu::Stream &sInput, const char *sSection ) 805void Bu::Json::readChar( Bu::Json::ParseState &ps, const char *sSection )
772{ 806{
773 if( Bu::UtfString::readPoint( sInput, c ) == 0 && sInput.isEos() ) 807 if( !readChar( ps ) )
774 { 808 {
775 throw Bu::ExceptionBase( sSection ); 809 ps.error( sSection );
776 } 810 }
777} 811}
778 812
@@ -781,9 +815,9 @@ bool Bu::Json::isWs( Bu::UtfChar c )
781 return c == ' ' || c == '\t' || c == '\r' || c == '\n'; 815 return c == ' ' || c == '\t' || c == '\r' || c == '\n';
782} 816}
783 817
784void Bu::Json::skipWs( Bu::UtfChar &c, Bu::Stream &sInput ) 818void Bu::Json::skipWs( Bu::Json::ParseState &ps )
785{ 819{
786 while( isWs( c ) ) 820 while( isWs( ps.c ) )
787 { 821 {
788 next("whitespace"); 822 next("whitespace");
789 } 823 }
@@ -850,3 +884,11 @@ Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::Json &j )
850 return f; 884 return f;
851} 885}
852 886
887void Bu::Json::ParseState::error( const Bu::String &sTxt )
888{
889 throw Bu::ExceptionParse(
890 Bu::String("%1:%2: %3").
891 arg( iLine ).arg( iChar ).arg( sTxt ).end().getStr()
892 );
893}
894
diff --git a/src/unstable/json.h b/src/unstable/json.h
index 5373bcf..a973f74 100644
--- a/src/unstable/json.h
+++ b/src/unstable/json.h
@@ -16,7 +16,22 @@ namespace Bu
16 class Json 16 class Json
17 { 17 {
18 private: 18 private:
19 Json( Bu::UtfChar &c, Bu::Stream &sInput ); 19 class ParseState
20 {
21 public:
22 ParseState( Bu::Stream &sInput ) :
23 c( 0 ), sInput( sInput ), iLine( 1 ), iChar( 0 )
24 {
25 }
26
27 void error( const Bu::String &sTxt );
28
29 Bu::UtfChar c;
30 Bu::Stream &sInput;
31 int iLine;
32 int iChar;
33 };
34 Json( ParseState &ps );
20 typedef Bu::Hash<Bu::UtfString, Json *> JsonHash; 35 typedef Bu::Hash<Bu::UtfString, Json *> JsonHash;
21 typedef Bu::Array<Json *> JsonList; 36 typedef Bu::Array<Json *> JsonList;
22 37
@@ -90,19 +105,17 @@ namespace Bu
90 bool operator==( const Bu::String &rRhs ); 105 bool operator==( const Bu::String &rRhs );
91 106
92 private: 107 private:
93 void parse( Bu::UtfChar &c, Bu::Stream &sInput ); 108 void parse( ParseState &ps );
94 void parseString( Bu::UtfChar &c, Bu::Stream &sInput, 109 void parseString( ParseState &ps, Bu::UtfString &sOut );
95 Bu::UtfString &sOut ); 110 void parseString( ParseState &ps );
96 void parseString( Bu::UtfChar &c, Bu::Stream &sInput ); 111 void parseObject( ParseState &ps );
97 void parseObject( Bu::UtfChar &c, Bu::Stream &sInput ); 112 void parseArray( ParseState &ps );
98 void parseArray( Bu::UtfChar &c, Bu::Stream &sInput ); 113 void parseNumber( ParseState &ps );
99 void parseNumber( Bu::UtfChar &c, Bu::Stream &sInput ); 114 void parseLiteral( ParseState &ps );
100 void parseLiteral( Bu::UtfChar &c, Bu::Stream &sInput ); 115 bool readChar( ParseState &ps );
101 bool readChar( Bu::UtfChar &c, Bu::Stream &sInput ); 116 void readChar( ParseState &ps, const char *sSection );
102 void readChar( Bu::UtfChar &c, Bu::Stream &sInput,
103 const char *sSection );
104 bool isWs( Bu::UtfChar c ); 117 bool isWs( Bu::UtfChar c );
105 void skipWs( Bu::UtfChar &c, Bu::Stream &sInput ); 118 void skipWs( ParseState &ps );
106 void writeStr( const Bu::UtfString &sStr, Bu::Stream &sOutput ) const; 119 void writeStr( const Bu::UtfString &sStr, Bu::Stream &sOutput ) const;
107 120
108 private: 121 private:
diff --git a/src/unstable/myriadfs.cpp b/src/unstable/myriadfs.cpp
index 7a87662..6b51195 100644
--- a/src/unstable/myriadfs.cpp
+++ b/src/unstable/myriadfs.cpp
@@ -121,7 +121,7 @@ Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int /*iMode*/,
121 try 121 try
122 { 122 {
123 iNode = lookupInode( sPath, iParent ); 123 iNode = lookupInode( sPath, iParent );
124 sio << "File found." << sio.nl; 124// sio << "File found." << sio.nl;
125 // The file was found 125 // The file was found
126 return openByInode( iNode ); 126 return openByInode( iNode );
127 } 127 }
@@ -137,10 +137,10 @@ Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int /*iMode*/,
137 // The file wasn't found, but the path leading up to it was. 137 // The file wasn't found, but the path leading up to it was.
138 // first, figure out the final path element... 138 // first, figure out the final path element...
139 Bu::String sName = filePart( sPath ); 139 Bu::String sName = filePart( sPath );
140 sio << "End filename: " << sName << sio.nl; 140// sio << "End filename: " << sName << sio.nl;
141 sio << "Parent inode: " << iParent << sio.nl; 141// sio << "Parent inode: " << iParent << sio.nl;
142 iNode = create( iParent, sName, (uPerms&permMask)|typeRegFile, 0 ); 142 iNode = create( iParent, sName, (uPerms&permMask)|typeRegFile, 0 );
143 sio << "New iNode: " << iNode << sio.nl; 143// sio << "New iNode: " << iNode << sio.nl;
144 return openByInode( iNode ); 144 return openByInode( iNode );
145 } 145 }
146} 146}
@@ -164,7 +164,7 @@ void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
164 try 164 try
165 { 165 {
166 iNode = lookupInode( sPath, iParent ); 166 iNode = lookupInode( sPath, iParent );
167 sio << "File found." << sio.nl; 167// sio << "File found." << sio.nl;
168 } 168 }
169 catch( Bu::MyriadFsException &e ) 169 catch( Bu::MyriadFsException &e )
170 { 170 {
@@ -178,10 +178,10 @@ void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
178 // The file wasn't found, but the path leading up to it was. 178 // The file wasn't found, but the path leading up to it was.
179 // first, figure out the final path element... 179 // first, figure out the final path element...
180 Bu::String sName = filePart( sPath ); 180 Bu::String sName = filePart( sPath );
181 sio << "End filename: " << sName << sio.nl; 181// sio << "End filename: " << sName << sio.nl;
182 sio << "Parent inode: " << iParent << sio.nl; 182// sio << "Parent inode: " << iParent << sio.nl;
183 iNode = create( iParent, sName, iPerms, uSpecial ); 183 iNode = create( iParent, sName, iPerms, uSpecial );
184 sio << "New iNode: " << iNode << sio.nl; 184// sio << "New iNode: " << iNode << sio.nl;
185 } 185 }
186 // The file was found 186 // The file was found
187 //throw Bu::MyriadFsException("Path already exists."); 187 //throw Bu::MyriadFsException("Path already exists.");
@@ -213,10 +213,10 @@ void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget,
213 // The file wasn't found, but the path leading up to it was. 213 // The file wasn't found, but the path leading up to it was.
214 // first, figure out the final path element... 214 // first, figure out the final path element...
215 Bu::String sName = filePart( sPath ); 215 Bu::String sName = filePart( sPath );
216 sio << "End filename: " << sName << sio.nl; 216// sio << "End filename: " << sName << sio.nl;
217 sio << "Parent inode: " << iParent << sio.nl; 217// sio << "Parent inode: " << iParent << sio.nl;
218 iNode = create( iParent, sName, 0777|typeSymLink, 0 ); 218 iNode = create( iParent, sName, 0777|typeSymLink, 0 );
219 sio << "New iNode: " << iNode << sio.nl; 219// sio << "New iNode: " << iNode << sio.nl;
220 MyriadStream ms = openByInode( iNode ); 220 MyriadStream ms = openByInode( iNode );
221 ms.write( sTarget ); 221 ms.write( sTarget );
222 return; 222 return;
@@ -249,8 +249,8 @@ void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget,
249 // The file wasn't found, but the path leading up to it was. 249 // The file wasn't found, but the path leading up to it was.
250 // first, figure out the final path element... 250 // first, figure out the final path element...
251 Bu::String sName = filePart( sPath ); 251 Bu::String sName = filePart( sPath );
252 sio << "End filename: " << sName << sio.nl; 252// sio << "End filename: " << sName << sio.nl;
253 sio << "Parent inode: " << iParent << sio.nl; 253// sio << "Parent inode: " << iParent << sio.nl;
254 addToDir( iParent, iNode, sName ); 254 addToDir( iParent, iNode, sName );
255 MyriadStream is = mStore.openStream( 2 ); 255 MyriadStream is = mStore.openStream( 2 );
256 RawStat rs; 256 RawStat rs;
@@ -558,8 +558,8 @@ int32_t Bu::MyriadFs::allocInode( uint16_t uPerms, uint32_t uSpecial )
558 558
559 case typeDir: 559 case typeDir:
560 rs.uStreamIndex = mStore.createStream(); 560 rs.uStreamIndex = mStore.createStream();
561 sio << "Creating directory node, storage: " 561// sio << "Creating directory node, storage: "
562 << rs.uStreamIndex << sio.nl; 562// << rs.uStreamIndex << sio.nl;
563 { 563 {
564 Bu::MyriadStream msDir = mStore.openStream( 564 Bu::MyriadStream msDir = mStore.openStream(
565 rs.uStreamIndex 565 rs.uStreamIndex