00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "CeylanStringUtils.h"
00028
00029
00030 #include "CeylanUtils.h"
00031
00032 #include "CeylanSystem.h"
00033 #include "CeylanOperators.h"
00034 #include "CeylanLogPlug.h"
00035
00036
00037 #ifdef CEYLAN_USES_CONFIG_H
00038 #include "CeylanConfig.h"
00039 #endif // CEYLAN_USES_CONFIG_H
00040
00041
00042 #if CEYLAN_ARCH_NINTENDO_DS
00043 #include "CeylanConfigForNintendoDS.h"
00044 #endif // CEYLAN_ARCH_NINTENDO_DS
00045
00046
00047 #include "CeylanLogLight.h"
00048
00049
00050 #if CEYLAN_ARCH_WINDOWS
00051
00052 extern "C"
00053 {
00054
00055 #include "string.h"
00056
00057 }
00058
00059 #endif // CEYLAN_ARCH_WINDOWS
00060
00061
00062 #include <cctype>
00063 #include <iostream>
00064 #include <cstring>
00065
00066
00067 using std::string ;
00068 using std::list ;
00069 using std::map ;
00070
00071 using namespace Ceylan ;
00072 using namespace Ceylan::Log ;
00073
00074
00075 #if CEYLAN_DEBUG_DEMANGLE
00076
00077 #define DISPLAY_DEBUG_DEMANGLE(message) LogPlug::debug( string( "[Demangle] " ) + message ) ;
00078
00079 #else // CEYLAN_DEBUG_DEMANGLE
00080
00081 #define DISPLAY_DEBUG_DEMANGLE(message)
00082
00083 #endif // CEYLAN_DEBUG_DEMANGLE
00084
00085
00086 const std::string Ceylan::BatchTestOption = "--batch" ;
00087
00088
00089
00090 StringSize Ceylan::countChars( const string & aString, char targetChar )
00091 {
00092
00093 StringSize charCount = 0 ;
00094
00095 StringSize size = aString.size() ;
00096
00097 for ( StringSize i = 0; i < size; i++ )
00098 if ( aString[i] == targetChar )
00099 charCount++ ;
00100
00101 return charCount ;
00102
00103 }
00104
00105
00106
00107 std::string Ceylan::reverse( const std::string & source )
00108 {
00109
00110 StringSize count = source.size() ;
00111
00112 if ( count == 0 )
00113 return "" ;
00114
00115 string result ;
00116
00117 do
00118 {
00119 count-- ;
00120 result += source[count] ;
00121
00122 }
00123 while ( count > 0 ) ;
00124
00125 return result ;
00126
00127 }
00128
00129
00130
00131 char * Ceylan::getNonConstCharFrom( const std::string & source )
00132 {
00133
00134
00135 char * res = new char[ source.size() + 1 ] ;
00136
00137 if ( res == 0 )
00138 Ceylan::emergencyShutdown(
00139 "Ceylan::getNonConstCharFrom: not enough memory." ) ;
00140
00141 #if CEYLAN_ARCH_WINDOWS
00142
00143 strcpy_s( res, source.size() + 1, source.c_str() ) ;
00144
00145 #else // CEYLAN_ARCH_WINDOWS
00146
00147 ::strcpy( res, source.c_str() ) ;
00148
00149 #endif // CEYLAN_ARCH_WINDOWS
00150
00151 return res ;
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 }
00176
00177
00178
00179 StringSize Ceylan::substituteInString( string & targetString,
00180 const string & toBeReplaced, const string & replacement )
00181 {
00182
00183 StringSize substitutionCount = 0 ;
00184
00185 StringSize charCount ;
00186
00187 Ceylan::Sint32 lenDiff = static_cast<Ceylan::Sint32>(
00188 toBeReplaced.size() - replacement.size() ) ;
00189
00190 do
00191 {
00192
00193 charCount = targetString.find( toBeReplaced ) ;
00194
00195 if ( charCount == string::npos )
00196 break ;
00197 substitutionCount++ ;
00198
00199
00200
00201
00202
00203
00204
00205 if ( lenDiff < 0 )
00206 targetString.insert( charCount + toBeReplaced.size(),
00207 - lenDiff, 'x' ) ;
00208
00209 targetString.replace( charCount, replacement.size(), replacement ) ;
00210
00211
00212
00213
00214
00215
00216
00217 if ( lenDiff > 0 )
00218 targetString.erase( charCount + replacement.size(), lenDiff ) ;
00219
00220 }
00221 while ( true ) ;
00222
00223 return substitutionCount ;
00224
00225 }
00226
00227
00228
00229 string Ceylan::substituteIn( const string & sourceString,
00230 const string & toBeReplaced, const string & replacement )
00231 {
00232
00233 string res = sourceString ;
00234
00235 substituteInString( res, toBeReplaced, replacement ) ;
00236
00237 return res ;
00238
00239 }
00240
00241
00242
00243 bool Ceylan::isLetter( char targetChar )
00244 {
00245
00246 if ( ::isalpha( targetChar ) )
00247 return true ;
00248
00249 return false ;
00250
00251 }
00252
00253
00254
00255 bool Ceylan::isFigure( char targetChar )
00256 {
00257
00258 if ( ::isalpha( targetChar ) )
00259 return true ;
00260
00261 return false ;
00262
00263 }
00264
00265
00266
00267 bool Ceylan::isAlphanumeric( char targetChar )
00268 {
00269
00270 if ( ::isalnum( targetChar ) )
00271 return true ;
00272
00273 return false ;
00274
00275 }
00276
00277
00278
00279 bool Ceylan::isPunctuation( char targetChar )
00280 {
00281
00282 if ( ::ispunct( targetChar ) )
00283 return true ;
00284
00285 return false ;
00286
00287 }
00288
00289
00290
00291 bool Ceylan::isWhitespace( char targetChar )
00292 {
00293
00294 if ( ::iswspace( targetChar ) )
00295 return true ;
00296
00297 return false ;
00298
00299 }
00300
00301
00302
00303 string Ceylan::toUppercase( const std::string & text )
00304 {
00305
00306 string result ;
00307
00308 for ( string::const_iterator it = text.begin();
00309 it != text.end(); it++ )
00310 if ( ::islower( *it ) )
00311 result += static_cast<char>( ::toupper( *it ) ) ;
00312 else
00313 result += *it ;
00314
00315 return result ;
00316
00317 }
00318
00319
00320
00321 string Ceylan::encodeToHTML( const std::string & message )
00322 {
00323
00324 string result ;
00325
00326 for ( string::const_iterator it = message.begin();
00327 it != message.end(); it++ )
00328 {
00329
00330 switch( (*it) )
00331 {
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 case '&':
00342 result += "&" ;
00343 break ;
00344
00345 case '<':
00346 result += "<" ;
00347 break ;
00348
00349 case '>':
00350 result += ">" ;
00351 break ;
00352
00353 default:
00354 result += (*it) ;
00355 break ;
00356
00357 }
00358 }
00359
00360 return result ;
00361
00362 }
00363
00364
00365
00366 string Ceylan::encodeToPhonetic( const std::string & message )
00367 {
00368
00369 const std::string phonetics[26] = {
00370
00371 "alpha",
00372 "bravo",
00373 "charlie",
00374 "delta",
00375 "echo",
00376 "fox-trot",
00377 "golf",
00378 "hotel",
00379 "india",
00380 "juliet",
00381 "kilo",
00382 "lima",
00383 "mike",
00384 "november",
00385 "oscar",
00386 "papa",
00387 "quebec",
00388 "romeo",
00389 "sierra",
00390 "tango",
00391 "uniform",
00392 "victor",
00393 "whisky",
00394 "x-ray",
00395 "yankee",
00396 "zulu"
00397
00398 } ;
00399
00400 bool firstLetter = true ;
00401 string result ;
00402
00403 for ( string::const_iterator it = message.begin();
00404 it != message.end(); it++ )
00405 {
00406
00407
00408 if ( firstLetter )
00409 firstLetter = false ;
00410 else
00411 result += " " ;
00412
00413 if ( ::isupper( *it ) )
00414 result += toUppercase( phonetics[ (*it) - 'A' ] ) ;
00415 else
00416 if ( ::islower( *it ) )
00417 result += phonetics[ (*it) - 'a' ] ;
00418 else
00419 result += *it ;
00420
00421 }
00422
00423 return result ;
00424
00425 }
00426
00427
00428
00429 string Ceylan::encodeToROT13( const std::string & message )
00430 {
00431
00432 string result ;
00433
00434 for ( string::const_iterator it = message.begin();
00435 it != message.end(); it++ )
00436 {
00437
00438 if ( ( (*it) >= 'A' ) && ( (*it) <= 'Z' ) )
00439 {
00440
00441 result += ( (*it) - 'A' + 13) % 26 + 'A' ;
00442
00443 }
00444 else if ( (*it) >= 'a' && (*it) <= 'z' )
00445 {
00446
00447 result += ( (*it) - 'a' + 13) % 26 + 'a' ;
00448
00449 }
00450 else
00451 {
00452
00453 result += (*it) ;
00454
00455 }
00456
00457 }
00458
00459 return result ;
00460
00461 }
00462
00463
00464
00465 string Ceylan::demangleSymbol( const std::string & symbol )
00466 {
00467
00468
00469
00470
00471
00472
00473
00474 DISPLAY_DEBUG_DEMANGLE( "Initial symbol is " + symbol ) ;
00475
00476
00477
00478
00479
00480
00481
00482 if ( symbol[0] != 'N' || symbol[symbol.size()-1] != 'E' )
00483 return symbol ;
00484
00485
00486 const string shorten = symbol.substr( 1, symbol.size() - 2 ) ;
00487 StringSize shortenSize = shorten.size() ;
00488
00489 DISPLAY_DEBUG_DEMANGLE( "Shorten symbol is " + shorten ) ;
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504 StringSize count = 0 ;
00505 StringSize num ;
00506 string numString, extracted ;
00507
00508 while ( count < shortenSize )
00509 {
00510
00511 DISPLAY_DEBUG_DEMANGLE( "Count is "
00512 + Ceylan::toString(
00513 static_cast<Ceylan::Uint32>( count ) )
00514 + ", extracted is "
00515 + extracted
00516 + ", shorten is "
00517 + shorten ) ;
00518
00519 while ( ::isdigit( shorten[count] ) )
00520 {
00521 numString += shorten[count] ;
00522 count++ ;
00523 }
00524
00525 if ( numString.empty() )
00526 {
00527
00528 return symbol ;
00529 }
00530
00531
00532 num = Ceylan::stringToUnsignedLong( numString ) ;
00533
00534 if ( num + count > shortenSize )
00535 {
00536
00537 return symbol ;
00538 }
00539
00540 DISPLAY_DEBUG_DEMANGLE( "Count is "
00541 + Ceylan::toString(
00542 static_cast<Ceylan::Uint32>( count ) )
00543 + ", extracted is " + extracted
00544 + ", shorten is " + shorten ) ;
00545
00546 DISPLAY_DEBUG_DEMANGLE( "Jumping " + numString + " ("
00547 + Ceylan::toString( static_cast<long>( num ) )
00548 + ") characters, taking word ["
00549 + shorten.substr( count, num ) + "]" ) ;
00550
00551 extracted += shorten.substr( count, num ) + "::" ;
00552
00553 DISPLAY_DEBUG_DEMANGLE( "Count is "
00554 + Ceylan::toString( static_cast<Ceylan::Uint32>( count ) )
00555 + ", extracted is " + extracted
00556 + ", shorten is " + shorten ) ;
00557
00558 count += num ;
00559
00560 DISPLAY_DEBUG_DEMANGLE( "Remaining string is "
00561 + shorten.substr( count, shortenSize - count ) ) ;
00562
00563 numString = "" ;
00564
00565 }
00566
00567
00568 extracted.erase( extracted.size()-2, 2 ) ;
00569
00570 DISPLAY_DEBUG_DEMANGLE( "Ceylan::demangleSymbol returning "
00571 + extracted ) ;
00572
00573 return extracted ;
00574
00575 }
00576
00577
00578
00579 list<string> Ceylan::split( const string & stringToSplit, char splittingChar )
00580 {
00581
00582 list<string> result ;
00583
00584 #define CEYLAN_TRUSTS_STL_WITH_TEMPLATES 0
00585
00586 #if CEYLAN_TRUSTS_STL_WITH_TEMPLATES
00587
00588 split<string, char>( stringToSplit, splittingChar, result ) ;
00589
00590 #else // CEYLAN_TRUSTS_STL_WITH_TEMPLATES
00591
00592 string splitWord ;
00593
00594
00595 for ( std::string::const_iterator it = stringToSplit.begin() ;
00596 it != stringToSplit.end(); it++ )
00597 {
00598
00599
00600 if ( *it == splittingChar )
00601 {
00602 result.push_back( splitWord ) ;
00603 splitWord.clear() ;
00604 }
00605 else
00606 {
00607 splitWord += *it ;
00608 }
00609
00610 }
00611
00612 if ( ! splitWord.empty() )
00613 result.push_back( splitWord ) ;
00614
00615 #endif // CEYLAN_TRUSTS_STL_WITH_TEMPLATES
00616
00617 return result ;
00618
00619 }
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 string Ceylan::join( const list<string> & toJoin, const string & joiningString )
00639 {
00640
00641
00642
00643 if ( toJoin.empty() )
00644 return "" ;
00645
00646 string res ;
00647
00648 list<string>::const_iterator it = toJoin.begin() ;
00649
00650 res = (*it) ;
00651
00652 it++ ;
00653
00654 while ( it != toJoin.end() )
00655 {
00656 res += joiningString + (*it) ;
00657 it++ ;
00658 }
00659
00660 return res ;
00661
00662 }
00663
00664
00665
00666 std::list<string> Ceylan::splitIntoWords( const string & sentenceToSplit )
00667 {
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680 string copiedSendtence = sentenceToSplit ;
00681
00682 substituteInString( copiedSendtence, "\t", " " ) ;
00683
00684 list<string> splitted = Ceylan::split( copiedSendtence, ' ' ) ;
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708 list<string> corrected ;
00709
00710 StringSize voidItemCount = 0 ;
00711
00712 for ( list<string>::const_iterator it = splitted.begin();
00713 it != splitted.end(); it++ )
00714 {
00715
00716
00717 if ( (*it).empty() )
00718 {
00719 voidItemCount++ ;
00720 }
00721 else
00722 {
00723
00724
00725
00726 if ( voidItemCount > 0 )
00727 {
00728
00729 string spaces ;
00730
00731
00732 for ( Ceylan::Uint32 i = 1; i < voidItemCount; i++ )
00733 spaces += " " ;
00734
00735 corrected.push_back( spaces ) ;
00736 voidItemCount = 0 ;
00737
00738 }
00739
00740
00741 corrected.push_back( *it ) ;
00742
00743 }
00744
00745 }
00746
00747 return corrected ;
00748
00749 }
00750
00751
00752
00753 std::list<string> Ceylan::splitIntoParagraphs( const string & textToSplit )
00754 {
00755
00756 return Ceylan::split( textToSplit, '\n' ) ;
00757
00758 }
00759
00760
00761
00762 std::string Ceylan::formatStringList( const list<string> & stringList,
00763 bool surroundByTicks )
00764 {
00765
00766 if ( stringList.empty() )
00767 return "(empty list)" ;
00768
00769 string res ;
00770
00771 if ( TextDisplayable::GetOutputFormat() == TextDisplayable::html )
00772 {
00773
00774 res = "<ul>" ;
00775
00776 for ( list<string>::const_iterator it = stringList.begin();
00777 it != stringList.end(); it++ )
00778 if ( surroundByTicks )
00779 res += "<li>'" + ( *it ) + "'</li>" ;
00780 else
00781 res += "<li>" + ( *it ) + "</li>" ;
00782
00783 res += "</ul>" ;
00784
00785 }
00786 else
00787 {
00788
00789
00790
00791 res = '\n' ;
00792 for ( list<string>::const_iterator it = stringList.begin();
00793 it != stringList.end(); it++ )
00794 if ( surroundByTicks )
00795 res += "\t+ '" + ( *it ) + "'\n" ;
00796 else
00797 res += "\t+ " + ( *it ) + '\n' ;
00798
00799 }
00800
00801 return res ;
00802
00803 }
00804
00805
00806
00807 std::string Ceylan::formatStringMap(
00808 const std::map<std::string, std::string> & stringMap,
00809 bool surroundByTicks )
00810 {
00811
00812 if ( stringMap.empty() )
00813 return "(empty map)" ;
00814
00815 string res ;
00816
00817 if ( TextDisplayable::GetOutputFormat() == TextDisplayable::html )
00818 {
00819
00820 res = "<ul>" ;
00821
00822 for ( map<string,string>::const_iterator it = stringMap.begin();
00823 it != stringMap.end(); it++ )
00824 if ( surroundByTicks )
00825 res += "<li>'" + (*it).first + "' = '"
00826 + (*it).second + "'</li>" ;
00827 else
00828 res += "<li>" + (*it).first + " = "
00829 + (*it).second + "</li>" ;
00830
00831 res += "</ul>" ;
00832
00833 }
00834 else
00835 {
00836
00837
00838
00839 res = '\n' ;
00840 for ( map<string,string>::const_iterator it = stringMap.begin();
00841 it != stringMap.end(); it++ )
00842 if ( surroundByTicks )
00843 res += "\t+ '" + (*it).first + "' = '"
00844 + (*it).second + "'\n" ;
00845 else
00846 res += "\t+ " + (*it).first + " = "
00847 + (*it).second + '\n' ;
00848
00849 }
00850
00851 return res ;
00852
00853 }
00854
00855
00856
00857 void Ceylan::display( const string & message )
00858 {
00859
00860 #if CEYLAN_ARCH_NINTENDO_DS
00861
00862
00863 #ifdef CEYLAN_RUNS_ON_ARM7
00864
00865 throw StringUtilsException( "Ceylan::display: not available for ARM7." ) ;
00866
00867 #elif defined(CEYLAN_RUNS_ON_ARM9)
00868
00869 ::iprintf( ( message + '\n' ).c_str() ) ;
00870
00871 #endif // CEYLAN_RUNS_ON_ARM7
00872
00873
00874 #else // CEYLAN_ARCH_NINTENDO_DS
00875
00876 std::cout << message << std::endl << std::flush ;
00877
00878 #endif // CEYLAN_ARCH_NINTENDO_DS
00879
00880 }
00881
00882
00883
00884 void Ceylan::displayError( const string & errorMessage )
00885 {
00886
00887 #if CEYLAN_ARCH_NINTENDO_DS
00888
00889
00890 #ifdef CEYLAN_RUNS_ON_ARM7
00891
00892 throw StringUtilsException(
00893 "Ceylan::displayError: not available for ARM7." ) ;
00894
00895 #elif defined(CEYLAN_RUNS_ON_ARM9)
00896
00897 BG_PALETTE_SUB[255] = RGB15(31,0,0) ;
00898 display( errorMessage ) ;
00899
00900
00901 BG_PALETTE_SUB[255] = RGB15(31,31,31) ;
00902
00903 #endif // CEYLAN_RUNS_ON_ARM7
00904
00905
00906 #else // CEYLAN_ARCH_NINTENDO_DS
00907
00908 std::cerr << errorMessage << std::endl << std::flush ;
00909
00910 #endif // CEYLAN_ARCH_NINTENDO_DS
00911
00912 }
00913