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 /src | |
| 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
Diffstat (limited to 'src')
| -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 |
