diff options
author | Mike Buland <eichlan@xagasoft.com> | 2020-02-04 19:27:37 -0800 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2020-02-04 19:27:37 -0800 |
commit | 9459cb32504c9d269bc467190bba41897f86a97b (patch) | |
tree | e16a916fbbd071462ca0e9ce94fae88f062f289a | |
parent | fd830279725081d95e3f08f768ed6879c92fe838 (diff) | |
parent | ed5e7684b766a3914b30c5b449608542695fd3b8 (diff) | |
download | libbu++-9459cb32504c9d269bc467190bba41897f86a97b.tar.gz libbu++-9459cb32504c9d269bc467190bba41897f86a97b.tar.bz2 libbu++-9459cb32504c9d269bc467190bba41897f86a97b.tar.xz libbu++-9459cb32504c9d269bc467190bba41897f86a97b.zip |
Merge branch 'master' into unicode
-rw-r--r-- | src/stable/exceptionparse.cpp | 14 | ||||
-rw-r--r-- | src/stable/exceptionparse.h | 17 | ||||
-rw-r--r-- | src/stable/hash.h | 40 | ||||
-rw-r--r-- | src/unstable/json.cpp | 208 | ||||
-rw-r--r-- | src/unstable/json.h | 39 | ||||
-rw-r--r-- | src/unstable/myriadfs.cpp | 30 |
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 | |||
10 | namespace 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 | |||
12 | namespace 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 | ||
11 | Bu::Json::Json() : | 12 | Bu::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 | ||
78 | Bu::Json::Json( Bu::UtfChar &c, Bu::Stream &sInput ) : | 79 | Bu::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 | ||
84 | Bu::Json::Json( const Json &rSrc ) : | 85 | Bu::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 | ||
303 | void Bu::Json::parse( const Bu::String &sInput ) | 304 | void 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 | ||
309 | void Bu::Json::parse( Bu::UtfChar &c, Bu::Stream &sInput ) | 310 | void 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 | ||
540 | void Bu::Json::parseString( Bu::UtfChar &c, Bu::Stream &sInput, | 543 | void 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 | ||
605 | void Bu::Json::parseString( Bu::UtfChar &c, Bu::Stream &sInput ) | 608 | void 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 | ||
612 | void Bu::Json::parseObject( Bu::UtfChar &c, Bu::Stream &sInput ) | 615 | void 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 | ||
656 | void Bu::Json::parseArray( Bu::UtfChar &c, Bu::Stream &sInput ) | 669 | void 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 | ||
695 | void Bu::Json::parseNumber( Bu::UtfChar &c, Bu::Stream &sInput ) | 709 | void 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 | ||
730 | void Bu::Json::parseLiteral( Bu::UtfChar &c, Bu::Stream &sInput ) | 747 | void 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 | ||
764 | bool Bu::Json::readChar( Bu::UtfChar &c, Bu::Stream &sInput ) | 784 | bool 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 | ||
771 | void Bu::Json::readChar( Bu::UtfChar &c, Bu::Stream &sInput, const char *sSection ) | 805 | void 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 | ||
784 | void Bu::Json::skipWs( Bu::UtfChar &c, Bu::Stream &sInput ) | 818 | void 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 | ||
887 | void 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 |