EAString.cpp 143 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <EAStdC/internal/Config.h>
  5. #include <EAStdC/EAString.h>
  6. #include <EAStdC/EACType.h>
  7. #include <EAStdC/EAMathHelp.h>
  8. #include <EAStdC/EAStdC.h>
  9. #include <EAStdC/EAMemory.h>
  10. #include <EAStdC/EAAlignment.h>
  11. #include <EAStdC/EABitTricks.h>
  12. #include <EAAssert/eaassert.h>
  13. EA_DISABLE_ALL_VC_WARNINGS()
  14. #include <string.h>
  15. #include <stddef.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <errno.h>
  19. #include <limits.h>
  20. #include <math.h>
  21. EA_RESTORE_ALL_VC_WARNINGS()
  22. EA_DISABLE_VC_WARNING(4996 4127 6385 4146) // 'ecvt' was declared deprecated
  23. // conditional expression is constant.
  24. // Invalid data: accessing 'comp1', the readable size is '20' bytes, but '4194248' bytes might be read: Lines: 504, 505, 507, 508, 510, 512, 514
  25. // warning C4146: unary minus operator applied to unsigned type, result still unsigned
  26. #if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)
  27. EA_DISABLE_GCC_WARNING(-Wmaybe-uninitialized) // GCC 4.7+ mistakenly warns about this.
  28. #endif
  29. /////////////////////////////////////////////////////////////////////////////
  30. // EASTDC_MIN / EASTDC_MAX
  31. //
  32. #define EASTDC_MIN(a, b) ((a) < (b) ? (a) : (b))
  33. #define EASTDC_MAX(a, b) ((a) > (b) ? (a) : (b))
  34. namespace EA
  35. {
  36. namespace StdC
  37. {
  38. // Define word_type to match machine word type. This is not the same
  39. // thing as size_t or uintptr_t, as there are machines with 64 bit
  40. // words but 32 bit pointers (e.g. XBox 360, PS3).
  41. #if (EA_PLATFORM_WORD_SIZE == 8) // From EABase
  42. typedef uint64_t word_type;
  43. #else
  44. typedef uint32_t word_type;
  45. #endif
  46. EASTDC_API char* Strcpy(char* pDestination, const char* pSource)
  47. {
  48. const char* s = pSource;
  49. char* d = pDestination;
  50. while((*d++ = *s++) != 0)
  51. {} // Do nothing.
  52. return pDestination;
  53. }
  54. EASTDC_API char16_t* Strcpy(char16_t* pDestination, const char16_t* pSource)
  55. {
  56. const char16_t* s = pSource;
  57. char16_t* d = pDestination;
  58. while((*d++ = *s++) != 0)
  59. {} // Do nothing.
  60. return pDestination;
  61. }
  62. EASTDC_API char32_t* Strcpy(char32_t* pDestination, const char32_t* pSource)
  63. {
  64. const char32_t* s = pSource;
  65. char32_t* d = pDestination;
  66. while((*d++ = *s++) != 0)
  67. {} // Do nothing.
  68. return pDestination;
  69. }
  70. EASTDC_API char* Strncpy(char* pDestination, const char* pSource, size_t n)
  71. {
  72. const char* s = pSource;
  73. char* d = pDestination;
  74. n++;
  75. while(--n)
  76. {
  77. if((*d++ = *s++) == 0)
  78. {
  79. while(--n)
  80. *d++ = 0;
  81. break;
  82. }
  83. }
  84. return pDestination;
  85. }
  86. EASTDC_API char16_t* Strncpy(char16_t* pDestination, const char16_t* pSource, size_t n)
  87. {
  88. const char16_t* s = pSource;
  89. char16_t* d = pDestination;
  90. n++;
  91. while(--n)
  92. {
  93. if((*d++ = *s++) == 0)
  94. {
  95. while(--n)
  96. *d++ = 0;
  97. break;
  98. }
  99. }
  100. return pDestination;
  101. }
  102. EASTDC_API char32_t* Strncpy(char32_t* pDestination, const char32_t* pSource, size_t n)
  103. {
  104. const char32_t* s = pSource;
  105. char32_t* d = pDestination;
  106. n++;
  107. while(--n)
  108. {
  109. if((*d++ = *s++) == 0)
  110. {
  111. while(--n)
  112. *d++ = 0;
  113. break;
  114. }
  115. }
  116. return pDestination;
  117. }
  118. EASTDC_API char* StringnCopy(char* pDestination, const char* pSource, size_t n)
  119. {
  120. char* pOriginalDest = pDestination;
  121. if(n)
  122. {
  123. while(n-- && *pSource)
  124. *pDestination++ = *pSource++;
  125. if(n != static_cast<size_t>(-1)) // Is this portable?
  126. *pDestination = 0;
  127. }
  128. return pOriginalDest;
  129. }
  130. EASTDC_API char16_t* StringnCopy(char16_t* pDestination, const char16_t* pSource, size_t n)
  131. {
  132. char16_t* pOriginalDest = pDestination;
  133. if(n)
  134. {
  135. while(n-- && *pSource)
  136. *pDestination++ = *pSource++;
  137. if(n != static_cast<size_t>(-1))
  138. *pDestination = 0;
  139. }
  140. return pOriginalDest;
  141. }
  142. EASTDC_API char32_t* StringnCopy(char32_t* pDestination, const char32_t* pSource, size_t n)
  143. {
  144. char32_t* pOriginalDest = pDestination;
  145. if(n)
  146. {
  147. while(n-- && *pSource)
  148. *pDestination++ = *pSource++;
  149. if(n != static_cast<size_t>(-1))
  150. *pDestination = 0;
  151. }
  152. return pOriginalDest;
  153. }
  154. /* Reference implementation which ought to be a little slower than our more optimized implementation.
  155. EASTDC_API size_t Strlcpy(char* pDestination, const char* pSource, size_t nDestCapacity)
  156. {
  157. const size_t n = Strlen(pSource);
  158. if(n < nDestCapacity)
  159. memcpy(pDestination, pSource, (n + 1) * sizeof(*pSource));
  160. else if(nDestCapacity)
  161. {
  162. memcpy(pDestination, pSource, (nDestCapacity - 1) * sizeof(*pSource));
  163. pDestination[nDestCapacity - 1] = 0;
  164. }
  165. return n;
  166. }
  167. */
  168. EASTDC_API size_t Strlcpy(char* pDestination, const char* pSource, size_t nDestCapacity)
  169. {
  170. const char* s = pSource;
  171. size_t n = nDestCapacity;
  172. if(n && --n)
  173. {
  174. do{
  175. if((*pDestination++ = *s++) == 0)
  176. break;
  177. } while(--n);
  178. }
  179. if(!n)
  180. {
  181. if(nDestCapacity)
  182. *pDestination = 0;
  183. while(*s++)
  184. { }
  185. }
  186. return (size_t)(s - pSource - 1);
  187. }
  188. /* Reference implementation which ought to be a little slower than our more optimized implementation.
  189. EASTDC_API size_t Strlcpy(char16_t* pDestination, const char16_t* pSource, size_t nDestCapacity)
  190. {
  191. const size_t n = Strlen(pSource);
  192. if(n < nDestCapacity)
  193. memcpy(pDestination, pSource, (n + 1) * sizeof(*pSource));
  194. else if(nDestCapacity)
  195. {
  196. memcpy(pDestination, pSource, (nDestCapacity - 1) * sizeof(*pSource));
  197. pDestination[nDestCapacity - 1] = 0;
  198. }
  199. return n;
  200. }
  201. */
  202. EASTDC_API size_t Strlcpy(char16_t* pDestination, const char16_t* pSource, size_t nDestCapacity)
  203. {
  204. const char16_t* s = pSource;
  205. size_t n = nDestCapacity;
  206. if(n && --n)
  207. {
  208. do{
  209. if((*pDestination++ = *s++) == 0)
  210. break;
  211. } while(--n);
  212. }
  213. if(!n)
  214. {
  215. if(nDestCapacity)
  216. *pDestination = 0;
  217. while(*s++)
  218. { }
  219. }
  220. return (size_t)(s - pSource - 1);
  221. }
  222. EASTDC_API size_t Strlcpy(char32_t* pDestination, const char32_t* pSource, size_t nDestCapacity)
  223. {
  224. const char32_t* s = pSource;
  225. size_t n = nDestCapacity;
  226. if(n && --n)
  227. {
  228. do{
  229. if((*pDestination++ = *s++) == 0)
  230. break;
  231. } while(--n);
  232. }
  233. if(!n)
  234. {
  235. if(nDestCapacity)
  236. *pDestination = 0;
  237. while(*s++)
  238. { }
  239. }
  240. return (size_t)(s - pSource - 1);
  241. }
  242. /*
  243. // To consider: Enable this for completeness with the above:
  244. EASTDC_API int Strlcpy(char* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength)
  245. {
  246. if(nSourceLength == kSizeTypeUnset)
  247. nSourceLength = Strlen(pSource);
  248. if(nSourceLength < nDestCapacity)
  249. {
  250. memcpy(pDest, pSource, nSourceLength * sizeof(*pSource));
  251. pDest[nSourceLength] = 0;
  252. }
  253. else if(nDestCapacity)
  254. {
  255. memcpy(pDest, pSource, (nDestCapacity - 1) * sizeof(*pSource));
  256. pDest[nDestCapacity - 1] = 0;
  257. }
  258. return (int)(unsigned)nSourceLength;
  259. }
  260. EASTDC_API int Strlcpy(char16_t* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength)
  261. {
  262. if(nSourceLength == kSizeTypeUnset)
  263. nSourceLength = Strlen(pSource);
  264. if(nSourceLength < nDestCapacity)
  265. {
  266. memcpy(pDest, pSource, nSourceLength * sizeof(*pSource));
  267. pDest[nSourceLength] = 0;
  268. }
  269. else if(nDestCapacity)
  270. {
  271. memcpy(pDest, pSource, (nDestCapacity - 1) * sizeof(*pSource));
  272. pDest[nDestCapacity - 1] = 0;
  273. }
  274. return (int)(unsigned)nSourceLength;
  275. }
  276. EASTDC_API int Strlcpy(char32_t* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength)
  277. {
  278. if(nSourceLength == kSizeTypeUnset)
  279. nSourceLength = Strlen(pSource);
  280. if(nSourceLength < nDestCapacity)
  281. {
  282. memcpy(pDest, pSource, nSourceLength * sizeof(*pSource));
  283. pDest[nSourceLength] = 0;
  284. }
  285. else if(nDestCapacity)
  286. {
  287. memcpy(pDest, pSource, (nDestCapacity - 1) * sizeof(*pSource));
  288. pDest[nDestCapacity - 1] = 0;
  289. }
  290. return (int)(unsigned)nSourceLength;
  291. }
  292. */
  293. //static const int32_t kLeadingSurrogateStart = 0x0000d800;
  294. //static const int32_t kTrailingSurrogateStart = 0x0000dc00;
  295. //static const int32_t kLeadingSurrogateEnd = 0x0000dbff;
  296. //static const int32_t kTrailingSurrogateEnd = 0x0000dfff;
  297. //static const int32_t kSurrogateOffset = 0x00010000 - (kLeadingSurrogateStart << 10) - kTrailingSurrogateStart;
  298. // This is not static because it is used elsewhere.
  299. uint8_t utf8lengthTable[256] =
  300. {
  301. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  302. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  303. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  304. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  305. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  306. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  307. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  308. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  309. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  310. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  311. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  312. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  313. 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  314. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  315. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  316. 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // For full UTF8 support, this last row should be: 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0
  317. };
  318. // Used to subtract out the control bits in multi-byte sequence.
  319. static const uint32_t utf8DecodingOffsetTable[5] =
  320. {
  321. 0, // 0x00000000
  322. 0, // 0x00000000
  323. (0xC0 << 6) + 0x80, // 0x00003080
  324. (0xE0 << 12) + (0x80 << 6) + 0x80, // 0x000e2080
  325. (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 // 0x03c82080
  326. // to do
  327. // to do
  328. };
  329. // The minimum value that can be encoded in a particular number
  330. // of bytes. Used to disallow non-canonical encoded sequences.
  331. // It turns out that this is not a fully proper way to check for
  332. // valid sequences. See the Unicode Standard http://unicode.org/versions/corrigendum1.html
  333. static const uint32_t utf8MinimumValueTable[] =
  334. {
  335. 0x00000000, // This slot is unused
  336. 0x00000000, // 1 byte per char
  337. 0x00000080, // 2 bytes per char
  338. 0x00000800, // 3 bytes per char
  339. 0x00010000 // 4 bytes per char
  340. //0x00200000, // 5 bytes per char
  341. //0x04000000, // 6 bytes per char
  342. };
  343. // One past the maximum value that can be encoded in a particular number
  344. // of bytes. Used to disallow non-canonical encoded sequences.
  345. static const uint32_t utf8MaximumValueTable[] =
  346. {
  347. 0x00000000, // This slot is unused
  348. 0x00000080, // 1 byte per char
  349. 0x00000800, // 2 bytes per char
  350. 0x00010000, // 3 bytes per char
  351. 0x00110000 // 4 bytes per char *** Should be: 0x00200000
  352. //0x04000000
  353. //0x80000000
  354. };
  355. const uint32_t kUnicodeReplacementChar = 0x0000fffd;
  356. const uint32_t kUnicodeInvalidDecode = 0xffffffffu;
  357. EA_FORCE_INLINE uint32_t DecodeCodePoint(const char*& pSourceStart, const char* pSourceEnd)
  358. {
  359. const char* pSource = pSourceStart;
  360. uint32_t c = (uint8_t)*(pSource++);
  361. if(c < 128)
  362. {
  363. // Valid character, do nothing
  364. }
  365. else
  366. {
  367. uint32_t nLength = utf8lengthTable[c]; // nLength may be zero, in which case we'll return 'IncorrectEncoding'.
  368. // Do we have an incomplete or invalid string?
  369. if((pSourceStart + nLength > pSourceEnd) || (nLength == 0))
  370. {
  371. if(EA::StdC::GetAssertionsEnabled())
  372. {
  373. EA_FAIL_MSG("Incomplete Unicode character in buffer");
  374. }
  375. return kUnicodeInvalidDecode;
  376. }
  377. // Now decode the remaining ("following") bytes.
  378. for(uint32_t i = 0; i < nLength - 1; ++i)
  379. {
  380. uint8_t nByte = (uint8_t)*(pSource++);
  381. if((nByte < 0x80u) || (nByte > 0xbfu)) // Syntax check
  382. {
  383. if(EA::StdC::GetAssertionsEnabled())
  384. {
  385. EA_FAIL_MSG("Invalid following byte");
  386. }
  387. return kUnicodeInvalidDecode;
  388. }
  389. c = (c << 6) + nByte; // Preserve control bits (don't OR)
  390. }
  391. c -= utf8DecodingOffsetTable[nLength]; // Subtract accumulated control bits just once
  392. // Check for canonical encoding.
  393. if((c < utf8MinimumValueTable[nLength]) || (c >= utf8MaximumValueTable[nLength]))
  394. {
  395. return kUnicodeInvalidDecode;
  396. }
  397. }
  398. pSourceStart = pSource;
  399. return c;
  400. }
  401. EA_FORCE_INLINE bool EncodeCodePoint(uint32_t c, char*& pDestStart, char* pDestEnd)
  402. {
  403. // Encode as UTF-8
  404. if(c < 0x00000080u)
  405. {
  406. *(pDestStart++) = static_cast<char>(c);
  407. return true;
  408. }
  409. else if(c < 0x00000800u)
  410. {
  411. if (pDestStart + 2 <= pDestEnd)
  412. {
  413. char* pDest = pDestStart;
  414. *(pDest++) = static_cast<char>((c >> 6) | 0xc0);
  415. *(pDest++) = static_cast<char>((c | 0x80) & 0xbf);
  416. pDestStart = pDest;
  417. return true;
  418. }
  419. return false;
  420. }
  421. else if(c < 0x00010000u)
  422. {
  423. if (pDestStart + 3 <= pDestEnd)
  424. {
  425. char* pDest = pDestStart;
  426. *(pDest++) = static_cast<char>((c >> 12) | 0xe0);
  427. *(pDest++) = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
  428. *(pDest++) = static_cast<char>((c | 0x80) & 0xbf);
  429. pDestStart = pDest;
  430. return true;
  431. }
  432. return false;
  433. }
  434. else if(c < 0x00200000u)
  435. {
  436. if(pDestStart + 4 <= pDestEnd)
  437. {
  438. char* pDest = pDestStart;
  439. *(pDest++) = static_cast<char>((c >> 18) | 0xf0);
  440. *(pDest++) = static_cast<char>(((c >> 12) | 0x80) & 0xbf);
  441. *(pDest++) = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
  442. *(pDest++) = static_cast<char>((c | 0x80) & 0xbf);
  443. pDestStart = pDest;
  444. return true;
  445. }
  446. return false;
  447. }
  448. else
  449. {
  450. // We don't currently support Unicode beyond "Plane 0", as game software has never needed it.
  451. // If you have a need for this support, feel free to submit a patch or make a specific request.
  452. c = kUnicodeReplacementChar;
  453. if(pDestStart + 3 <= pDestEnd)
  454. {
  455. char* pDest = pDestStart;
  456. *(pDest++) = static_cast<char>((c >> 12) | 0xe0);
  457. *(pDest++) = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
  458. *(pDest++) = static_cast<char>(((c >> 0) | 0x80) & 0xbf);
  459. pDestStart = pDest;
  460. return true;
  461. }
  462. return false;
  463. }
  464. }
  465. EA_FORCE_INLINE uint32_t DecodeCodePoint(const char16_t*& pSourceStart, const char16_t* pSourceEnd)
  466. {
  467. EA_UNUSED(pSourceEnd);
  468. return (uint32_t)*(pSourceStart++);
  469. }
  470. EA_FORCE_INLINE bool EncodeCodePoint(uint32_t c, char16_t*& pDestStart, char16_t* pDestEnd)
  471. {
  472. EA_UNUSED(pDestEnd);
  473. *(pDestStart++) = static_cast<char16_t>(c);
  474. return true;
  475. }
  476. EA_FORCE_INLINE uint32_t DecodeCodePoint(const char32_t*& pSourceStart, const char32_t* pSourceEnd)
  477. {
  478. EA_UNUSED(pSourceEnd);
  479. return (uint32_t)*(pSourceStart++);
  480. }
  481. EA_FORCE_INLINE bool EncodeCodePoint(uint32_t c, char32_t*& pDestStart, char32_t* pDestEnd)
  482. {
  483. EA_UNUSED(pDestEnd);
  484. *(pDestStart++) = static_cast<char32_t>(c);
  485. return true;
  486. }
  487. template <typename InCharT, typename OutCharT>
  488. bool StrlcpyInternal(OutCharT* pDest, const InCharT* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
  489. {
  490. EA_ASSERT(pDest != nullptr && pSource != nullptr);
  491. // If we have no capacity, then just return nothing
  492. if(nDestCapacity == 0)
  493. {
  494. nDestUsed = 0;
  495. nSourceUsed = 0;
  496. return true;
  497. }
  498. const InCharT* pSourceStart = pSource;
  499. const InCharT* pSourceEnd = pSource + nSourceLength;
  500. if (pSourceEnd < pSourceStart)
  501. pSourceEnd = (const InCharT*)(uintptr_t)-1;
  502. OutCharT* pDestStart = pDest;
  503. OutCharT* pDestEnd = pDest + nDestCapacity - 1;
  504. bool bGood = true;
  505. while(bGood && (pSource < pSourceEnd) && (pDest < pDestEnd))
  506. {
  507. uint32_t c = DecodeCodePoint(pSource, pSourceEnd);
  508. if (c == 0)
  509. {
  510. pSource = pSourceEnd;
  511. break;
  512. }
  513. bGood = (c != kUnicodeInvalidDecode) && EncodeCodePoint(c, pDest, pDestEnd);
  514. }
  515. *pDest = 0;
  516. nDestUsed = pDest - pDestStart;
  517. nSourceUsed = pSource - pSourceStart;
  518. return bGood;
  519. }
  520. bool Strlcpy(char* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
  521. {
  522. return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
  523. }
  524. bool Strlcpy(char* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
  525. {
  526. return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
  527. }
  528. bool Strlcpy(char16_t* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
  529. {
  530. return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
  531. }
  532. bool Strlcpy(char16_t* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
  533. {
  534. return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
  535. }
  536. bool Strlcpy(char32_t* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
  537. {
  538. return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
  539. }
  540. bool Strlcpy(char32_t* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
  541. {
  542. return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
  543. }
  544. EASTDC_API int Strlcpy(char* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength)
  545. {
  546. size_t destCount = 0;
  547. while(nSourceLength-- > 0)
  548. {
  549. uint32_t c = (uint16_t)*pSource++; // Deal with surrogate characters
  550. // Encode as UTF-8
  551. if (c < 0x00000080u)
  552. {
  553. if(c == 0) // Break on NULL char, even if explicit length was set
  554. break;
  555. if(pDest && ((destCount + 1) < nDestCapacity))
  556. *pDest++ = static_cast<char>(c);
  557. destCount += 1;
  558. }
  559. else if(c < 0x00000800u)
  560. {
  561. if(pDest && ((destCount + 2) < nDestCapacity))
  562. {
  563. *pDest++ = static_cast<char>((c >> 6) | 0xc0);
  564. *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
  565. }
  566. destCount += 2;
  567. }
  568. else if(c < 0x00010000u)
  569. {
  570. if(pDest && ((destCount + 3) < nDestCapacity))
  571. {
  572. *pDest++ = static_cast<char>((c >> 12) | 0xe0);
  573. *pDest++ = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
  574. *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
  575. }
  576. destCount += 3;
  577. }
  578. else if(c < 0x00200000u)
  579. {
  580. if(pDest && ((destCount + 4) < nDestCapacity))
  581. {
  582. *pDest++ = static_cast<char>((c >> 18) | 0xf0);
  583. *pDest++ = static_cast<char>(((c >> 12) | 0x80) & 0xbf);
  584. *pDest++ = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
  585. *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
  586. }
  587. destCount += 4;
  588. }
  589. else
  590. {
  591. const uint32_t kIllegalUnicodeChar = 0x0000fffd;
  592. if(pDest && ((destCount + 3) < nDestCapacity))
  593. {
  594. *pDest++ = static_cast<char>( (kIllegalUnicodeChar >> 12) | 0xe0);
  595. *pDest++ = static_cast<char>(((kIllegalUnicodeChar >> 6) | 0x80) & 0xbf);
  596. *pDest++ = static_cast<char>(((kIllegalUnicodeChar >> 0) | 0x80) & 0xbf);
  597. }
  598. destCount += 3;
  599. }
  600. }
  601. if(pDest && nDestCapacity != 0)
  602. *pDest = 0;
  603. return (int)(unsigned)destCount;
  604. }
  605. EASTDC_API int Strlcpy(char* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength)
  606. {
  607. size_t destCount = 0;
  608. while(nSourceLength-- > 0)
  609. {
  610. uint32_t c = (uint32_t)*pSource++; // Deal with surrogate characters
  611. // Encode as UTF-8
  612. if (c < 0x00000080u)
  613. {
  614. if(c == 0) // Break on NULL char, even if explicit length was set
  615. break;
  616. if(pDest && ((destCount + 1) < nDestCapacity))
  617. *pDest++ = static_cast<char>(c);
  618. destCount += 1;
  619. }
  620. else if(c < 0x00000800u)
  621. {
  622. if(pDest && ((destCount + 2) < nDestCapacity))
  623. {
  624. *pDest++ = static_cast<char>((c >> 6) | 0xc0);
  625. *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
  626. }
  627. destCount += 2;
  628. }
  629. else if(c < 0x00010000u)
  630. {
  631. if(pDest && ((destCount + 3) < nDestCapacity))
  632. {
  633. *pDest++ = static_cast<char>((c >> 12) | 0xe0);
  634. *pDest++ = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
  635. *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
  636. }
  637. destCount += 3;
  638. }
  639. else if(c < 0x00200000u)
  640. {
  641. if(pDest && ((destCount + 4) < nDestCapacity))
  642. {
  643. *pDest++ = static_cast<char>((c >> 18) | 0xf0);
  644. *pDest++ = static_cast<char>(((c >> 12) | 0x80) & 0xbf);
  645. *pDest++ = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
  646. *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
  647. }
  648. destCount += 4;
  649. }
  650. else
  651. {
  652. // We don't currently support Unicode beyond "Plane 0", as game software has never needed it.
  653. // If you have a need for this support, feel free to submit a patch or make a specific request.
  654. const uint32_t kIllegalUnicodeChar = 0x0000fffd;
  655. if(pDest && ((destCount + 3) < nDestCapacity))
  656. {
  657. *pDest++ = static_cast<char>( (kIllegalUnicodeChar >> 12) | 0xe0);
  658. *pDest++ = static_cast<char>(((kIllegalUnicodeChar >> 6) | 0x80) & 0xbf);
  659. *pDest++ = static_cast<char>(((kIllegalUnicodeChar >> 0) | 0x80) & 0xbf);
  660. }
  661. destCount += 3;
  662. }
  663. }
  664. if(pDest && nDestCapacity != 0)
  665. *pDest = 0;
  666. return (int)(unsigned)destCount;
  667. }
  668. EASTDC_API int Strlcpy(char16_t* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength)
  669. {
  670. size_t destCount = 0;
  671. while(nSourceLength-- > 0)
  672. {
  673. uint32_t c = (uint8_t)*pSource++;
  674. if(c < 128)
  675. {
  676. if(c == 0) // Break on NULL char, even if explicit length was set
  677. break;
  678. if(pDest && ((destCount + 1) < nDestCapacity)) // +1 because we want to append c to pDest but also append '\0'.
  679. *pDest++ = static_cast<char16_t>(c);
  680. destCount++;
  681. }
  682. else
  683. {
  684. uint32_t nLength = utf8lengthTable[c]; // nLength may be zero, in which case we'll return 'IncorrectEncoding'.
  685. // Do we have an incomplete or invalid string?
  686. if((nLength > (nSourceLength + 1)) || (nLength == 0))
  687. {
  688. if(EA::StdC::GetAssertionsEnabled())
  689. { EA_FAIL_MSG("Incomplete Unicode character in buffer"); }
  690. if(pDest && (destCount < nDestCapacity))
  691. *pDest++ = 0; // Even though we are returning an error, 0-terminate anyway for safety.
  692. return -1;
  693. }
  694. // Now decode the remaining ("following") bytes.
  695. for(uint32_t i = 0; i < nLength - 1; ++i)
  696. {
  697. uint8_t nByte = (uint8_t)*pSource++;
  698. if((nByte < 0x80u) || (nByte > 0xbfu)) // Syntax check
  699. {
  700. if(EA::StdC::GetAssertionsEnabled())
  701. { EA_FAIL_MSG("Invalid following byte"); }
  702. if(pDest && (destCount < nDestCapacity))
  703. *pDest++ = 0; // Even though we are returning an error, 0-terminate anyway for safety.
  704. return -1;
  705. }
  706. c = (c << 6) + nByte; // Preserve control bits (don't OR)
  707. }
  708. nSourceLength -= (nLength - 1); // We've just processed all remaining bytes for this multi-byte character
  709. c -= utf8DecodingOffsetTable[nLength]; // Subtract accumulated control bits just once
  710. // Check for canonical encoding.
  711. if((c >= utf8MinimumValueTable[nLength]) && (c < utf8MaximumValueTable[nLength]))
  712. {
  713. if(pDest && ((destCount + 1) < nDestCapacity))
  714. *pDest++ = static_cast<char16_t>(c);
  715. destCount++;
  716. }
  717. else
  718. break;
  719. }
  720. }
  721. if(pDest && (nDestCapacity != 0))
  722. *pDest = 0;
  723. return (int)(unsigned)destCount;
  724. }
  725. EASTDC_API int Strlcpy(char32_t* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength)
  726. {
  727. size_t destCount = 0;
  728. while(nSourceLength-- > 0)
  729. {
  730. uint32_t c = (uint8_t)*pSource++;
  731. if(c < 128)
  732. {
  733. if(c == 0) // Break on NULL char, even if explicit length was set
  734. break;
  735. if(pDest && ((destCount + 1) < nDestCapacity)) // +1 because we want to append c to pDest but also append '\0'.
  736. *pDest++ = static_cast<char32_t>(c);
  737. destCount++;
  738. }
  739. else
  740. {
  741. uint32_t nLength = utf8lengthTable[c]; // nLength may be zero, in which case we'll return 'IncorrectEncoding'.
  742. // Do we have an incomplete or invalid string?
  743. if((nLength > (nSourceLength + 1)) || (nLength == 0))
  744. {
  745. if(EA::StdC::GetAssertionsEnabled())
  746. { EA_FAIL_MSG("Incomplete Unicode character in buffer"); }
  747. if(pDest && (destCount < nDestCapacity))
  748. *pDest++ = 0; // Even though we are returning an error, 0-terminate anyway for safety.
  749. return -1;
  750. }
  751. // Now decode the remaining ("following") bytes.
  752. for(uint32_t i = 0; i < nLength - 1; ++i)
  753. {
  754. uint8_t nByte = (uint8_t)*pSource++;
  755. if((nByte < 0x80u) || (nByte > 0xbfu)) // Syntax check
  756. {
  757. if(EA::StdC::GetAssertionsEnabled())
  758. { EA_FAIL_MSG("Invalid following byte"); }
  759. if(pDest && (destCount < nDestCapacity))
  760. *pDest++ = 0; // Even though we are returning an error, 0-terminate anyway for safety.
  761. return -1;
  762. }
  763. c = (c << 6) + nByte; // Preserve control bits (don't OR)
  764. }
  765. nSourceLength -= (nLength - 1); // We've just processed all remaining bytes for this multi-byte character
  766. c -= utf8DecodingOffsetTable[nLength]; // Subtract accumulated control bits just once
  767. // Check for canonical encoding.
  768. if((c >= utf8MinimumValueTable[nLength]) && (c < utf8MaximumValueTable[nLength]))
  769. {
  770. if(pDest && ((destCount + 1) < nDestCapacity))
  771. *pDest++ = static_cast<char32_t>(c);
  772. destCount++;
  773. }
  774. else
  775. break;
  776. }
  777. }
  778. if(pDest && (nDestCapacity != 0))
  779. *pDest = 0;
  780. return (int)(unsigned)destCount;
  781. }
  782. EASTDC_API int Strlcpy(char32_t* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength)
  783. {
  784. size_t destCount = 0;
  785. while(nSourceLength-- > 0)
  786. {
  787. uint32_t c = (uint32_t)*pSource++;
  788. if(c == 0) // Break on NULL char, even if explicit length was set
  789. break;
  790. if(pDest && ((destCount + 1) < nDestCapacity)) // +1 because we want to append c to pDest but also append '\0'.
  791. *pDest++ = static_cast<char32_t>(c);
  792. destCount += 1;
  793. }
  794. if(pDest && nDestCapacity != 0)
  795. *pDest = 0;
  796. return (int)(unsigned)destCount;
  797. }
  798. EASTDC_API int Strlcpy(char16_t* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength)
  799. {
  800. size_t destCount = 0;
  801. while(nSourceLength-- > 0)
  802. {
  803. uint32_t c = (uint32_t)*pSource++;
  804. if(c == 0) // Break on NULL char, even if explicit length was set
  805. break;
  806. if(pDest && ((destCount + 1) < nDestCapacity)) // +1 because we want to append c to pDest but also append '\0'.
  807. *pDest++ = static_cast<char16_t>(c);
  808. destCount += 1;
  809. }
  810. if(pDest && nDestCapacity != 0)
  811. *pDest = 0;
  812. return (int)(unsigned)destCount;
  813. }
  814. EASTDC_API char* Strcat(char* pDestination, const char* pSource)
  815. {
  816. const char* s = pSource;
  817. char* d = pDestination;
  818. while(*d++){} // Do nothing.
  819. --d;
  820. while((*d++ = *s++) != 0)
  821. {} // Do nothing.
  822. return pDestination;
  823. }
  824. EASTDC_API char16_t* Strcat(char16_t* pDestination, const char16_t* pSource)
  825. {
  826. const char16_t* s = pSource;
  827. char16_t* d = pDestination;
  828. while(*d++){} // Do nothing.
  829. --d;
  830. while((*d++ = *s++) != 0)
  831. {} // Do nothing.
  832. return pDestination;
  833. }
  834. EASTDC_API char32_t* Strcat(char32_t* pDestination, const char32_t* pSource)
  835. {
  836. const char32_t* s = pSource;
  837. char32_t* d = pDestination;
  838. while(*d++){} // Do nothing.
  839. --d;
  840. while((*d++ = *s++) != 0)
  841. {} // Do nothing.
  842. return pDestination;
  843. }
  844. EASTDC_API char* Strncat(char* pDestination, const char* pSource, size_t n)
  845. {
  846. const char* s = pSource;
  847. char* d = pDestination;
  848. while(*d++){} // Do nothing.
  849. --d;
  850. ++n;
  851. while(--n)
  852. {
  853. if((*d++ = *s++) == 0)
  854. {
  855. --d;
  856. break;
  857. }
  858. }
  859. *d = 0;
  860. return pDestination;
  861. }
  862. EASTDC_API char16_t* Strncat(char16_t* pDestination, const char16_t* pSource, size_t n)
  863. {
  864. const char16_t* s = pSource;
  865. char16_t* d = pDestination;
  866. while(*d++){} // Do nothing.
  867. --d;
  868. ++n;
  869. while(--n)
  870. {
  871. if((*d++ = *s++) == 0)
  872. {
  873. --d;
  874. break;
  875. }
  876. }
  877. *d = 0;
  878. return pDestination;
  879. }
  880. EASTDC_API char32_t* Strncat(char32_t* pDestination, const char32_t* pSource, size_t n)
  881. {
  882. const char32_t* s = pSource;
  883. char32_t* d = pDestination;
  884. while(*d++){} // Do nothing.
  885. --d;
  886. ++n;
  887. while(--n)
  888. {
  889. if((*d++ = *s++) == 0)
  890. {
  891. --d;
  892. break;
  893. }
  894. }
  895. *d = 0;
  896. return pDestination;
  897. }
  898. EASTDC_API char* StringnCat(char* pDestination, const char* pSource, size_t n)
  899. {
  900. char* const pOriginalDest = pDestination;
  901. if(n)
  902. {
  903. while(*pDestination)
  904. ++pDestination;
  905. while(n-- && *pSource)
  906. *pDestination++ = *pSource++;
  907. *pDestination = 0;
  908. }
  909. return pOriginalDest;
  910. }
  911. EASTDC_API char16_t* StringnCat(char16_t* pDestination, const char16_t* pSource, size_t n)
  912. {
  913. char16_t* const pOriginalDest = pDestination;
  914. if(n)
  915. {
  916. while(*pDestination)
  917. ++pDestination;
  918. while(n-- && *pSource)
  919. *pDestination++ = *pSource++;
  920. *pDestination = 0;
  921. }
  922. return pOriginalDest;
  923. }
  924. EASTDC_API char32_t* StringnCat(char32_t* pDestination, const char32_t* pSource, size_t n)
  925. {
  926. char32_t* const pOriginalDest = pDestination;
  927. if(n)
  928. {
  929. while(*pDestination)
  930. ++pDestination;
  931. while(n-- && *pSource)
  932. *pDestination++ = *pSource++;
  933. *pDestination = 0;
  934. }
  935. return pOriginalDest;
  936. }
  937. EASTDC_API size_t Strlcat(char* pDestination, const char* pSource, size_t nDestCapacity)
  938. {
  939. const size_t d = nDestCapacity ? Strlen(pDestination) : 0;
  940. const size_t s = Strlen(pSource);
  941. const size_t t = s + d;
  942. EA_ASSERT_MSG((nDestCapacity == 0) || (d < nDestCapacity), "Destination string is longer than the specified capacity! "
  943. "Either an out of bounds write has occurred previous to this call or the specified capacity is incorrect.");
  944. if(t < nDestCapacity)
  945. memcpy(pDestination + d, pSource, (s + 1) * sizeof(*pSource));
  946. else
  947. {
  948. if(nDestCapacity)
  949. {
  950. memcpy(pDestination + d, pSource, ((nDestCapacity - d) - 1) * sizeof(*pSource));
  951. pDestination[nDestCapacity - 1] = 0;
  952. }
  953. }
  954. return t;
  955. }
  956. EASTDC_API size_t Strlcat(char16_t* pDestination, const char16_t* pSource, size_t nDestCapacity)
  957. {
  958. const size_t d = nDestCapacity ? Strlen(pDestination) : 0;
  959. const size_t s = Strlen(pSource);
  960. const size_t t = s + d;
  961. EA_ASSERT_MSG((nDestCapacity == 0) || (d < nDestCapacity), "Destination string is longer than the specified capacity! "
  962. "Either an out of bounds write has occurred previous to this call or the specified capacity is incorrect.");
  963. if(t < nDestCapacity)
  964. memcpy(pDestination + d, pSource, (s + 1) * sizeof(*pSource));
  965. else
  966. {
  967. if(nDestCapacity)
  968. {
  969. memcpy(pDestination + d, pSource, ((nDestCapacity - d) - 1) * sizeof(*pSource));
  970. pDestination[nDestCapacity - 1] = 0;
  971. }
  972. }
  973. return t;
  974. }
  975. EASTDC_API size_t Strlcat(char32_t* pDestination, const char32_t* pSource, size_t nDestCapacity)
  976. {
  977. const size_t d = nDestCapacity ? Strlen(pDestination) : 0;
  978. const size_t s = Strlen(pSource);
  979. const size_t t = s + d;
  980. EA_ASSERT_MSG((nDestCapacity == 0) || (d < nDestCapacity), "Destination string is longer than the specified capacity! "
  981. "Either an out of bounds write has occurred previous to this call or the specified capacity is incorrect.");
  982. if(t < nDestCapacity)
  983. memcpy(pDestination + d, pSource, (s + 1) * sizeof(*pSource));
  984. else
  985. {
  986. if(nDestCapacity)
  987. {
  988. memcpy(pDestination + d, pSource, ((nDestCapacity - d) - 1) * sizeof(*pSource));
  989. pDestination[nDestCapacity - 1] = 0;
  990. }
  991. }
  992. return t;
  993. }
  994. EASTDC_API size_t Strlcat(char16_t* pDestination, const char* pSource, size_t nDestCapacity)
  995. {
  996. size_t sourceLen = StrlenUTF8Decoded(pSource);
  997. size_t destLen = Strlen(pDestination);
  998. if(nDestCapacity > destLen)
  999. Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
  1000. return sourceLen + destLen;
  1001. }
  1002. EASTDC_API size_t Strlcat(char32_t* pDestination, const char* pSource, size_t nDestCapacity)
  1003. {
  1004. size_t sourceLen = StrlenUTF8Decoded(pSource);
  1005. size_t destLen = Strlen(pDestination);
  1006. if(nDestCapacity > destLen)
  1007. Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
  1008. return sourceLen + destLen;
  1009. }
  1010. EASTDC_API size_t Strlcat(char* pDestination, const char16_t* pSource, size_t nDestCapacity)
  1011. {
  1012. size_t sourceLen = Strlen(pSource);
  1013. size_t destLen = StrlenUTF8Decoded(pDestination);
  1014. if(nDestCapacity > destLen)
  1015. Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
  1016. return sourceLen + destLen;
  1017. }
  1018. EASTDC_API size_t Strlcat(char* pDestination, const char32_t* pSource, size_t nDestCapacity)
  1019. {
  1020. size_t sourceLen = Strlen(pSource);
  1021. size_t destLen = StrlenUTF8Decoded(pDestination);
  1022. if(nDestCapacity > destLen)
  1023. Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
  1024. return sourceLen + destLen;
  1025. }
  1026. EASTDC_API size_t Strlcat(char16_t* pDestination, const char32_t* pSource, size_t nDestCapacity)
  1027. {
  1028. size_t sourceLen = Strlen(pSource);
  1029. size_t destLen = Strlen(pDestination);
  1030. if(nDestCapacity > destLen)
  1031. Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
  1032. return sourceLen + destLen;
  1033. }
  1034. EASTDC_API size_t Strlcat(char32_t* pDestination, const char16_t* pSource, size_t nDestCapacity)
  1035. {
  1036. size_t sourceLen = Strlen(pSource);
  1037. size_t destLen = Strlen(pDestination);
  1038. if(nDestCapacity > destLen)
  1039. Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
  1040. return sourceLen + destLen;
  1041. }
  1042. // Optimized Strlen
  1043. //
  1044. // This function assumes that we can read the last size_t-sized word at
  1045. // the end of the string, even if as many as three of the word bytes are
  1046. // beyond the end of the string. This is typically a valid assumption
  1047. // because valid memory is always aligned to big power-of-2 sizes.
  1048. //
  1049. // Tests of this Strlen show that it outperforms the basic strlen
  1050. // implementation by 2x-6x on lengths ranging from 128 bytes to 4096 bytes.
  1051. // At lengths under 10 bytes this strlen performs similarly to strlen.
  1052. // These observations apply to x86, x64 and PowerPC32 platforms.
  1053. //
  1054. // There could be faster strlen implementations with some additional
  1055. // tricks, asm, SSE, etc. But this version works well while being simple.
  1056. #if EASTDC_STATIC_ANALYSIS_ENABLED
  1057. #define EASTDC_ENABLE_OPTIMIZED_STRLEN 0 // Disabled because the optimized strlen reads words and the string may have some uninitialized chars at the end past the trailing 0 char. Valgrind reports this as an error, but it's not actually an error in practice.
  1058. #else
  1059. #define EASTDC_ENABLE_OPTIMIZED_STRLEN 1
  1060. #endif
  1061. #if EASTDC_ENABLE_OPTIMIZED_STRLEN
  1062. EASTDC_API size_t Strlen(const char* pString)
  1063. {
  1064. #if EA_COMPILER_HAS_BUILTIN(__builtin_strlen)
  1065. return __builtin_strlen(pString);
  1066. #else
  1067. // Instead of casting between types, we just create a union.
  1068. union PointerUnion
  1069. {
  1070. const char* mp8;
  1071. const word_type* mpW;
  1072. uintptr_t mU;
  1073. } pu;
  1074. // Leading unaligned bytes
  1075. for(pu.mp8 = pString; pu.mU & (sizeof(word_type) - 1); pu.mp8++)
  1076. {
  1077. if(*pu.mp8 == 0)
  1078. return (size_t)(pu.mp8 - pString);
  1079. }
  1080. for(; ; pu.mpW++)
  1081. {
  1082. #if defined(__GNUC__) && (__GNUC__ >= 3) && !defined(__EDG_VERSION__)
  1083. __builtin_prefetch(pu.mpW + 64, 0, 0);
  1084. #endif
  1085. // Quit if there are any zero chars.
  1086. const word_type kOneBytes = ((word_type)-1 / 0xff); // 0x01010101
  1087. const word_type kHighBytes = (kOneBytes * 0x80); // 0x80808080
  1088. const word_type u = *pu.mpW;
  1089. if((u - kOneBytes) & ~u & kHighBytes)
  1090. break;
  1091. }
  1092. // Trailing unaligned bytes
  1093. while(*pu.mp8)
  1094. ++pu.mp8;
  1095. return (size_t)(pu.mp8 - pString);
  1096. #endif
  1097. }
  1098. #else
  1099. EASTDC_API size_t Strlen(const char* pString)
  1100. {
  1101. ssize_t nLength = (size_t)-1; // EABase 1.0.14 and later recognize ssize_t for all platforms.
  1102. do
  1103. {
  1104. ++nLength;
  1105. } while (*pString++);
  1106. return (size_t)nLength;
  1107. }
  1108. #endif
  1109. #if EASTDC_ENABLE_OPTIMIZED_STRLEN
  1110. EASTDC_API size_t Strlen(const char16_t* pString)
  1111. {
  1112. // Instead of casting between types, we just create a union.
  1113. union PointerUnion
  1114. {
  1115. const char16_t* mp16;
  1116. const word_type* mpW;
  1117. uintptr_t mU;
  1118. } pu;
  1119. // Leading unaligned bytes
  1120. for(pu.mp16 = pString; pu.mU & (sizeof(word_type) - 1); pu.mp16++)
  1121. {
  1122. if(*pu.mp16 == 0)
  1123. return (size_t)(pu.mp16 - pString);
  1124. }
  1125. for(; ; pu.mpW++)
  1126. {
  1127. #if defined(__GNUC__) && (__GNUC__ >= 3) && !defined(__EDG_VERSION__)
  1128. __builtin_prefetch(pu.mpW + 64, 0, 0);
  1129. #endif
  1130. // Quit if there are any zero char16_ts.
  1131. const word_type kOneBytes = ((word_type)-1 / 0xffff); // 0x00010001
  1132. const word_type kHighBytes = (kOneBytes * 0x8000); // 0x80008000
  1133. const word_type u = *pu.mpW;
  1134. if((u - kOneBytes) & ~u & kHighBytes)
  1135. break;
  1136. }
  1137. // Trailing unaligned bytes
  1138. while(*pu.mp16)
  1139. ++pu.mp16;
  1140. return (size_t)(pu.mp16 - pString);
  1141. }
  1142. #else
  1143. EASTDC_API size_t Strlen(const char16_t* pString)
  1144. {
  1145. size_t nLength = (size_t)-1;
  1146. do
  1147. {
  1148. ++nLength;
  1149. } while (*pString++);
  1150. return nLength;
  1151. }
  1152. #endif
  1153. // To consider: This might benefit from an optimized implementation on machines withi 64 bit registers.
  1154. EASTDC_API size_t Strlen(const char32_t* pString)
  1155. {
  1156. size_t nLength = (size_t)-1;
  1157. do{
  1158. ++nLength;
  1159. }while(*pString++);
  1160. return nLength;
  1161. }
  1162. // Returns number of Unicode characters are in the UTF8-encoded string.
  1163. // Return value will be <= Strlen(pString).
  1164. EASTDC_API size_t StrlenUTF8Decoded(const char* pString)
  1165. {
  1166. size_t nLength = 0;
  1167. while(*pString)
  1168. {
  1169. if((*pString & 0xc0) != 0x80)
  1170. ++nLength;
  1171. ++pString;
  1172. }
  1173. return nLength;
  1174. }
  1175. // Returns number of characters that would be in a UTF8-encoded string.
  1176. // Return value will be >= Strlen(pString).
  1177. EASTDC_API size_t StrlenUTF8Encoded(const char16_t* pString)
  1178. {
  1179. size_t nLength = 0;
  1180. uint32_t c;
  1181. while((c = *pString++) != 0)
  1182. {
  1183. if(c < 0x00000080)
  1184. nLength += 1;
  1185. else if(c < 0x00000800)
  1186. nLength += 2;
  1187. else // if(c < 0x00010000)
  1188. nLength += 3;
  1189. // The following would be used if the input string was 32 bit instead of 16 bit.
  1190. //else if(c < 0x00200000)
  1191. // destCount += 4;
  1192. //else // Else we use the error char 0xfffd
  1193. // destCount += 3;
  1194. }
  1195. return nLength;
  1196. }
  1197. // Returns number of characters that would be in a UTF8-encoded string.
  1198. // Return value will be >= Strlen(pString).
  1199. EASTDC_API size_t StrlenUTF8Encoded(const char32_t* pString)
  1200. {
  1201. size_t nLength = 0;
  1202. uint32_t c;
  1203. while((c = *pString++) != 0)
  1204. {
  1205. if(c < 0x00000080)
  1206. nLength += 1;
  1207. else if(c < 0x00000800)
  1208. nLength += 2;
  1209. else // if(c < 0x00010000)
  1210. nLength += 3;
  1211. // The following would be used if the input string was 32 bit instead of 32 bit.
  1212. //else if(c < 0x00200000)
  1213. // destCount += 4;
  1214. //else // Else we use the error char 0xfffd
  1215. // destCount += 3;
  1216. }
  1217. return nLength;
  1218. }
  1219. EASTDC_API char* Strend(const char* pString)
  1220. {
  1221. while (*pString)
  1222. ++pString;
  1223. return (char*)pString;
  1224. }
  1225. EASTDC_API char16_t* Strend(const char16_t* pString)
  1226. {
  1227. while (*pString)
  1228. ++pString;
  1229. return (char16_t*)pString;
  1230. }
  1231. EASTDC_API char32_t* Strend(const char32_t* pString)
  1232. {
  1233. while(*pString)
  1234. ++pString;
  1235. return (char32_t*)pString;
  1236. }
  1237. EASTDC_API size_t Strxfrm(char* pDest, const char* pSource, size_t n)
  1238. {
  1239. const size_t nLength = Strlen(pSource);
  1240. if(n > 0)
  1241. {
  1242. Strncpy(pDest, pSource, n - 1);
  1243. if(n < nLength)
  1244. pDest[n - 1] = 0;
  1245. }
  1246. return nLength;
  1247. }
  1248. EASTDC_API size_t Strxfrm(char16_t* pDest, const char16_t* pSource, size_t n)
  1249. {
  1250. const size_t nLength = Strlen(pSource);
  1251. if(n > 0)
  1252. {
  1253. Strncpy(pDest, pSource, n - 1);
  1254. if(n < nLength)
  1255. pDest[n - 1] = 0;
  1256. }
  1257. return nLength;
  1258. }
  1259. EASTDC_API size_t Strxfrm(char32_t* pDest, const char32_t* pSource, size_t n)
  1260. {
  1261. const size_t nLength = Strlen(pSource);
  1262. if(n > 0)
  1263. {
  1264. Strncpy(pDest, pSource, n - 1);
  1265. if(n < nLength)
  1266. pDest[n - 1] = 0;
  1267. }
  1268. return nLength;
  1269. }
  1270. EASTDC_API char* Strdup(const char* pString)
  1271. {
  1272. if(pString)
  1273. {
  1274. const size_t nLength = Strlen(pString);
  1275. char* const p = EASTDC_NEW(EASTDC_ALLOC_PREFIX "Strdup") char[nLength + 1]; // '+ 1' to include terminating zero.
  1276. Strcpy(p, pString);
  1277. return p;
  1278. }
  1279. return NULL;
  1280. }
  1281. EASTDC_API char16_t* Strdup(const char16_t* pString)
  1282. {
  1283. if(pString)
  1284. {
  1285. const size_t nLength = Strlen(pString);
  1286. char16_t* const p = EASTDC_NEW(EASTDC_ALLOC_PREFIX "Strdup") char16_t[nLength + 1]; // '+ 1' to include terminating zero.
  1287. Strcpy(p, pString);
  1288. return p;
  1289. }
  1290. return NULL;
  1291. }
  1292. EASTDC_API char32_t* Strdup(const char32_t* pString)
  1293. {
  1294. if(pString)
  1295. {
  1296. const size_t nLength = Strlen(pString);
  1297. char32_t* const p = EASTDC_NEW(EASTDC_ALLOC_PREFIX "Strdup") char32_t[nLength + 1]; // '+ 1' to include terminating zero.
  1298. Strcpy(p, pString);
  1299. return p;
  1300. }
  1301. return NULL;
  1302. }
  1303. EASTDC_API void Strdel(char* pString)
  1304. {
  1305. EASTDC_DELETE[] pString;
  1306. }
  1307. EASTDC_API void Strdel(char16_t* pString)
  1308. {
  1309. EASTDC_DELETE[] pString;
  1310. }
  1311. EASTDC_API void Strdel(char32_t* pString)
  1312. {
  1313. EASTDC_DELETE[] pString;
  1314. }
  1315. EASTDC_API char* Strupr(char* pString)
  1316. {
  1317. // This implementation converts only 7 bit ASCII characters.
  1318. // As such it is safe to use with 7-bit-safe multibyte encodings
  1319. // such as UTF8 but may yield incorrect results with such text.
  1320. char* pStringTemp = pString;
  1321. while(*pStringTemp)
  1322. {
  1323. if((uint8_t)*pStringTemp <= 127)
  1324. *pStringTemp = (char)Toupper(*pStringTemp);
  1325. ++pStringTemp;
  1326. }
  1327. return pString;
  1328. }
  1329. EASTDC_API char16_t* Strupr(char16_t* pString)
  1330. {
  1331. char16_t* pStringTemp = pString;
  1332. while(*pStringTemp)
  1333. {
  1334. const char16_t c = *pStringTemp;
  1335. *pStringTemp++ = Toupper(c);
  1336. }
  1337. return pString;
  1338. }
  1339. EASTDC_API char32_t* Strupr(char32_t* pString)
  1340. {
  1341. char32_t* pStringTemp = pString;
  1342. while(*pStringTemp)
  1343. {
  1344. const char32_t c = *pStringTemp;
  1345. *pStringTemp++ = Toupper(c);
  1346. }
  1347. return pString;
  1348. }
  1349. EASTDC_API char* Strlwr(char* pString)
  1350. {
  1351. // This implementation converts only 7 bit ASCII characters.
  1352. // As such it is safe to use with 7-bit-safe multibyte encodings
  1353. // such as UTF8 but may yield incorrect results with such text.
  1354. char* pStringTemp = pString;
  1355. while(*pStringTemp)
  1356. {
  1357. if((uint8_t)*pStringTemp <= 127)
  1358. *pStringTemp = (char)Tolower(*pStringTemp);
  1359. ++pStringTemp;
  1360. }
  1361. return pString;
  1362. }
  1363. EASTDC_API char16_t* Strlwr(char16_t* pString)
  1364. {
  1365. char16_t* pStringTemp = pString;
  1366. while(*pStringTemp)
  1367. {
  1368. const char16_t c = *pStringTemp;
  1369. *pStringTemp++ = Tolower(c);
  1370. }
  1371. return pString;
  1372. }
  1373. EASTDC_API char32_t* Strlwr(char32_t* pString)
  1374. {
  1375. char32_t* pStringTemp = pString;
  1376. while(*pStringTemp)
  1377. {
  1378. const char32_t c = *pStringTemp;
  1379. *pStringTemp++ = Tolower(c);
  1380. }
  1381. return pString;
  1382. }
  1383. EASTDC_API char* Strmix(char* pDestination, const char* pSource, const char* pDelimiters)
  1384. {
  1385. bool bCapitalize = true;
  1386. char* const pOriginalDest = pDestination;
  1387. while(*pSource)
  1388. {
  1389. char c = *pSource++;
  1390. // This character is upper-cased if bCapitalize flag is true, else lower-cased
  1391. if(bCapitalize)
  1392. {
  1393. if(Islower(c))
  1394. {
  1395. c = Toupper(c);
  1396. bCapitalize = false;
  1397. }
  1398. else if(Isupper(c))
  1399. bCapitalize = false;
  1400. }
  1401. else
  1402. {
  1403. if(Isupper(c))
  1404. c = Tolower(c);
  1405. }
  1406. // Check whether this character is a separator character. If so, set the bCapitalize flag.
  1407. for(const char* pCheck = pDelimiters; *pCheck; ++pCheck)
  1408. {
  1409. if(c == *pCheck)
  1410. bCapitalize = true;
  1411. }
  1412. *pDestination++ = c;
  1413. }
  1414. *pDestination = 0;
  1415. return pOriginalDest;
  1416. }
  1417. EASTDC_API char16_t* Strmix(char16_t* pDestination, const char16_t* pSource, const char16_t* pDelimiters)
  1418. {
  1419. bool bCapitalize = true;
  1420. char16_t* const pOriginalDest = pDestination;
  1421. while(*pSource)
  1422. {
  1423. char16_t c = *pSource++;
  1424. // This character is upper-cased if bCapitalize flag is true, else lower-cased
  1425. if(bCapitalize)
  1426. {
  1427. if(Islower(c))
  1428. {
  1429. c = Toupper(c);
  1430. bCapitalize = false;
  1431. }
  1432. else if(Isupper(c))
  1433. bCapitalize = false;
  1434. }
  1435. else
  1436. {
  1437. if(Isupper(c))
  1438. c = Tolower(c);
  1439. }
  1440. // Check whether this character is a separator character. If so, set the bCapitalize flag.
  1441. for(const char16_t* pCheck = pDelimiters; *pCheck; ++pCheck)
  1442. {
  1443. if(c == *pCheck)
  1444. bCapitalize = true;
  1445. }
  1446. *pDestination++ = c;
  1447. }
  1448. *pDestination = 0;
  1449. return pOriginalDest;
  1450. }
  1451. EASTDC_API char32_t* Strmix(char32_t* pDestination, const char32_t* pSource, const char32_t* pDelimiters)
  1452. {
  1453. bool bCapitalize = true;
  1454. char32_t* const pOriginalDest = pDestination;
  1455. while(*pSource)
  1456. {
  1457. char32_t c = *pSource++;
  1458. // This character is upper-cased if bCapitalize flag is true, else lower-cased
  1459. if(bCapitalize)
  1460. {
  1461. if(Islower(c))
  1462. {
  1463. c = Toupper(c);
  1464. bCapitalize = false;
  1465. }
  1466. else if(Isupper(c))
  1467. bCapitalize = false;
  1468. }
  1469. else
  1470. {
  1471. if(Isupper(c))
  1472. c = Tolower(c);
  1473. }
  1474. // Check whether this character is a separator character. If so, set the bCapitalize flag.
  1475. for(const char32_t* pCheck = pDelimiters; *pCheck; ++pCheck)
  1476. {
  1477. if(c == *pCheck)
  1478. bCapitalize = true;
  1479. }
  1480. *pDestination++ = c;
  1481. }
  1482. *pDestination = 0;
  1483. return pOriginalDest;
  1484. }
  1485. EASTDC_API char* Strchr(const char* pString, int c)
  1486. {
  1487. do
  1488. {
  1489. if (*pString == c)
  1490. return (char*)pString;
  1491. } while (*pString++);
  1492. return NULL;
  1493. }
  1494. EASTDC_API char16_t* Strchr(const char16_t* pString, char16_t c)
  1495. {
  1496. do
  1497. {
  1498. if (*pString == c)
  1499. return (char16_t*)pString;
  1500. } while (*pString++);
  1501. return NULL;
  1502. }
  1503. EASTDC_API char32_t* Strchr(const char32_t* pString, char32_t c)
  1504. {
  1505. do {
  1506. if(*pString == c)
  1507. return (char32_t*)pString;
  1508. } while (*pString++);
  1509. return NULL;
  1510. }
  1511. EASTDC_API char* Strnchr(const char* pString, int c, size_t n)
  1512. {
  1513. while(n-- > 0)
  1514. {
  1515. if(*pString == c)
  1516. {
  1517. return (char*)pString;
  1518. }
  1519. if(*pString == '\0')
  1520. {
  1521. return NULL;
  1522. }
  1523. pString++;
  1524. }
  1525. return NULL;
  1526. }
  1527. EASTDC_API char16_t* Strnchr(const char16_t* pString, char16_t c, size_t n)
  1528. {
  1529. while(n-- > 0)
  1530. {
  1531. if(*pString == c)
  1532. {
  1533. return (char16_t*)pString;
  1534. }
  1535. if(*pString == '\0')
  1536. {
  1537. return NULL;
  1538. }
  1539. pString++;
  1540. }
  1541. return NULL;
  1542. }
  1543. EASTDC_API char32_t* Strnchr(const char32_t* pString, char32_t c, size_t n)
  1544. {
  1545. while(n-- > 0)
  1546. {
  1547. if(*pString == c)
  1548. {
  1549. return (char32_t*)pString;
  1550. }
  1551. if(*pString == '\0')
  1552. {
  1553. return NULL;
  1554. }
  1555. pString++;
  1556. }
  1557. return NULL;
  1558. }
  1559. EASTDC_API size_t Strcspn(const char* pString1, const char* pString2)
  1560. {
  1561. const char* pStringCurrent = pString1;
  1562. // This implementation does a double loop. As such, it can get slow for
  1563. // very long strings. An alternative implementation is to use a hash
  1564. // table or to create a bytemap of the chars in pString2.
  1565. while(*pStringCurrent)
  1566. {
  1567. for(const char* pCharSet = pString2; *pCharSet; ++pCharSet)
  1568. {
  1569. if(*pCharSet == *pStringCurrent)
  1570. return (size_t)(pStringCurrent - pString1);
  1571. }
  1572. ++pStringCurrent;
  1573. }
  1574. return (size_t)(pStringCurrent - pString1);
  1575. }
  1576. EASTDC_API size_t Strcspn(const char16_t* pString1, const char16_t* pString2)
  1577. {
  1578. const char16_t* pStringCurrent = pString1;
  1579. // This implementation does a double loop. As such, it can get slow for
  1580. // very long strings. An alternative implementation is to use a hash
  1581. // table or to create a bytemap of the chars in pString2. But char16_t
  1582. // means that the map would have to be 65536 bits (8192 bytes) in size.
  1583. while(*pStringCurrent)
  1584. {
  1585. for(const char16_t* pCharSet = pString2; *pCharSet; ++pCharSet)
  1586. {
  1587. if(*pCharSet == *pStringCurrent)
  1588. return (size_t)(pStringCurrent - pString1);
  1589. }
  1590. ++pStringCurrent;
  1591. }
  1592. return (size_t)(pStringCurrent - pString1);
  1593. }
  1594. EASTDC_API size_t Strcspn(const char32_t* pString1, const char32_t* pString2)
  1595. {
  1596. const char32_t* pStringCurrent = pString1;
  1597. // This implementation does a double loop. As such, it can get slow for
  1598. // very long strings. An alternative implementation is to use a hash
  1599. // table or to create a bytemap of the chars in pString2. But char32_t
  1600. // means that the map would have to be huge in size.
  1601. while(*pStringCurrent)
  1602. {
  1603. for(const char32_t* pCharSet = pString2; *pCharSet; ++pCharSet)
  1604. {
  1605. if(*pCharSet == *pStringCurrent)
  1606. return (size_t)(pStringCurrent - pString1);
  1607. }
  1608. ++pStringCurrent;
  1609. }
  1610. return (size_t)(pStringCurrent - pString1);
  1611. }
  1612. EASTDC_API char* Strpbrk(const char* pString1, const char* pString2)
  1613. {
  1614. // This implementation does a double loop. As such, it can get slow for
  1615. // very long strings. An alternative implementation is to use a hash
  1616. // table or to create a bytemap of the chars in pString2.
  1617. while(*pString1)
  1618. {
  1619. for(const char* pCharSet = pString2; *pCharSet; ++pCharSet)
  1620. {
  1621. if(*pCharSet == *pString1)
  1622. return (char*)pString1;
  1623. }
  1624. ++pString1;
  1625. }
  1626. return NULL;
  1627. }
  1628. EASTDC_API char16_t* Strpbrk(const char16_t* pString1, const char16_t* pString2)
  1629. {
  1630. // This implementation does a double loop. As such, it can get slow for
  1631. // very long strings. An alternative implementation is to use a hash
  1632. // table or to create a bytemap of the chars in pString2. But char16_t
  1633. // means that the map would have to be 65536 bits (8192 bytes) in size.
  1634. while(*pString1)
  1635. {
  1636. for(const char16_t* pCharSet = pString2; *pCharSet; ++pCharSet)
  1637. {
  1638. if(*pCharSet == *pString1)
  1639. return (char16_t*)pString1;
  1640. }
  1641. ++pString1;
  1642. }
  1643. return NULL;
  1644. }
  1645. EASTDC_API char32_t* Strpbrk(const char32_t* pString1, const char32_t* pString2)
  1646. {
  1647. // This implementation does a double loop. As such, it can get slow for
  1648. // very long strings. An alternative implementation is to use a hash
  1649. // table or to create a bytemap of the chars in pString2. But char32_t
  1650. // means that the map would have to be huge in size.
  1651. while(*pString1)
  1652. {
  1653. for(const char32_t* pCharSet = pString2; *pCharSet; ++pCharSet)
  1654. {
  1655. if(*pCharSet == *pString1)
  1656. return (char32_t*)pString1;
  1657. }
  1658. ++pString1;
  1659. }
  1660. return NULL;
  1661. }
  1662. EASTDC_API char* Strrchr(const char* pString, int c)
  1663. {
  1664. const char* pFound = NULL;
  1665. char cCurrent;
  1666. while ((cCurrent = *pString++) != 0)
  1667. {
  1668. if (cCurrent == c)
  1669. pFound = (pString - 1);
  1670. }
  1671. if (pFound)
  1672. return (char*)pFound;
  1673. return c ? NULL : (char*)(pString - 1);
  1674. }
  1675. EASTDC_API char16_t* Strrchr(const char16_t* pString, char16_t c)
  1676. {
  1677. const char16_t* pFound = NULL;
  1678. char16_t cCurrent;
  1679. while ((cCurrent = *pString++) != 0)
  1680. {
  1681. if (cCurrent == c)
  1682. pFound = (pString - 1);
  1683. }
  1684. if (pFound)
  1685. return (char16_t*)pFound;
  1686. return c ? NULL : (char16_t*)(pString - 1);
  1687. }
  1688. EASTDC_API char32_t* Strrchr(const char32_t* pString, char32_t c)
  1689. {
  1690. const char32_t* pFound = NULL;
  1691. char32_t cCurrent;
  1692. while ((cCurrent = *pString++) != 0)
  1693. {
  1694. if (cCurrent == c)
  1695. pFound = (pString - 1);
  1696. }
  1697. if (pFound)
  1698. return (char32_t*)pFound;
  1699. return c ? NULL : (char32_t*)(pString - 1);
  1700. }
  1701. EASTDC_API size_t Strspn(const char* pString, const char* pSubString)
  1702. {
  1703. // This implementation does a double loop. As such, it can get slow for
  1704. // very long strings. An alternative implementation is to use a hash
  1705. // table or to create a bytemap of the chars in pString2.
  1706. const char* pStringCurrent = pString;
  1707. while(*pStringCurrent)
  1708. {
  1709. for(const char* pSubStringCurrent = pSubString; *pSubStringCurrent != *pStringCurrent; ++pSubStringCurrent)
  1710. {
  1711. if(*pSubStringCurrent == 0)
  1712. return (size_t)(pStringCurrent - pString);
  1713. }
  1714. ++pStringCurrent;
  1715. }
  1716. return (size_t)(pStringCurrent - pString);
  1717. }
  1718. EASTDC_API size_t Strspn(const char16_t* pString, const char16_t* pSubString)
  1719. {
  1720. // This implementation does a double loop. As such, it can get slow for
  1721. // very long strings. An alternative implementation is to use a hash
  1722. // table or to create a bytemap of the chars in pString2. But char16_t
  1723. // means that the map would have to be 65536 bits (8192 bytes) in size.
  1724. const char16_t* pStringCurrent = pString;
  1725. while(*pStringCurrent)
  1726. {
  1727. for(const char16_t* pSubStringCurrent = pSubString; *pSubStringCurrent != *pStringCurrent; ++pSubStringCurrent)
  1728. {
  1729. if(*pSubStringCurrent == 0)
  1730. return (size_t)(pStringCurrent - pString);
  1731. }
  1732. ++pStringCurrent;
  1733. }
  1734. return (size_t)(pStringCurrent - pString);
  1735. }
  1736. EASTDC_API size_t Strspn(const char32_t* pString, const char32_t* pSubString)
  1737. {
  1738. // This implementation does a double loop. As such, it can get slow for
  1739. // very long strings. An alternative implementation is to use a hash
  1740. // table or to create a bytemap of the chars in pString2. But char32_t
  1741. // means that the map would have to be huge in size.
  1742. const char32_t* pStringCurrent = pString;
  1743. while(*pStringCurrent)
  1744. {
  1745. for(const char32_t* pSubStringCurrent = pSubString; *pSubStringCurrent != *pStringCurrent; ++pSubStringCurrent)
  1746. {
  1747. if(*pSubStringCurrent == 0)
  1748. return (size_t)(pStringCurrent - pString);
  1749. }
  1750. ++pStringCurrent;
  1751. }
  1752. return (size_t)(pStringCurrent - pString);
  1753. }
  1754. EASTDC_API char* Strstr(const char* pString, const char* pSubString)
  1755. {
  1756. char* s1 = (char*)pString - 1;
  1757. char* p1 = (char*)pSubString - 1;
  1758. char c0, c1, c2;
  1759. if((c0 = *++p1) == 0) // An empty pSubString results in success, return pString.
  1760. return (char*)pString;
  1761. while((c1 = *++s1) != 0)
  1762. {
  1763. if(c1 == c0)
  1764. {
  1765. const char* s2 = (s1 - 1);
  1766. const char* p2 = (p1 - 1);
  1767. while((c1 = *++s2) == (c2 = *++p2) && c1){} // Do nothing
  1768. if(!c2)
  1769. return (char*)s1;
  1770. }
  1771. }
  1772. return NULL;
  1773. }
  1774. EASTDC_API char16_t* Strstr(const char16_t* pString, const char16_t* pSubString)
  1775. {
  1776. char16_t* s1 = (char16_t*)pString - 1;
  1777. char16_t* p1 = (char16_t*)pSubString - 1;
  1778. char16_t c0, c1, c2;
  1779. if((c0 = *++p1) == 0) // An empty pSubString results in success, return pString.
  1780. return (char16_t*)pString;
  1781. while((c1 = *++s1) != 0)
  1782. {
  1783. if(c1 == c0)
  1784. {
  1785. const char16_t* s2 = (s1 - 1);
  1786. const char16_t* p2 = (p1 - 1);
  1787. while((c1 = *++s2) == (c2 = *++p2) && c1){} // Do nothing
  1788. if(!c2)
  1789. return (char16_t*)s1;
  1790. }
  1791. }
  1792. return NULL;
  1793. }
  1794. EASTDC_API char32_t* Strstr(const char32_t* pString, const char32_t* pSubString)
  1795. {
  1796. char32_t* s1 = (char32_t*)pString - 1;
  1797. char32_t* p1 = (char32_t*)pSubString - 1;
  1798. char32_t c0, c1, c2;
  1799. if((c0 = *++p1) == 0) // An empty pSubString results in success, return pString.
  1800. return (char32_t*)pString;
  1801. while((c1 = *++s1) != 0)
  1802. {
  1803. if(c1 == c0)
  1804. {
  1805. const char32_t* s2 = (s1 - 1);
  1806. const char32_t* p2 = (p1 - 1);
  1807. while((c1 = *++s2) == (c2 = *++p2) && c1){} // Do nothing
  1808. if(!c2)
  1809. return (char32_t*)s1;
  1810. }
  1811. }
  1812. return NULL;
  1813. }
  1814. EASTDC_API char* Stristr(const char* s1, const char* s2)
  1815. {
  1816. const char* cp = s1;
  1817. if(!*s2)
  1818. return (char*)s1;
  1819. while(*cp)
  1820. {
  1821. const char* s = cp;
  1822. const char* t = s2;
  1823. while(*s && *t && (Tolower(*s) == Tolower(*t)))
  1824. ++s, ++t;
  1825. if(*t == 0)
  1826. return (char*)cp;
  1827. ++cp;
  1828. }
  1829. return 0;
  1830. }
  1831. EASTDC_API char16_t* Stristr(const char16_t* s1, const char16_t* s2)
  1832. {
  1833. const char16_t* cp = s1;
  1834. if(!*s2)
  1835. return (char16_t*)s1;
  1836. while(*cp)
  1837. {
  1838. const char16_t* s = cp;
  1839. const char16_t* t = s2;
  1840. while(*s && *t && (Tolower(*s) == Tolower(*t)))
  1841. ++s, ++t;
  1842. if(*t == 0)
  1843. return (char16_t*)cp;
  1844. ++cp;
  1845. }
  1846. return 0;
  1847. }
  1848. EASTDC_API char32_t* Stristr(const char32_t* s1, const char32_t* s2)
  1849. {
  1850. const char32_t* cp = s1;
  1851. if(!*s2)
  1852. return (char32_t*)s1;
  1853. while(*cp)
  1854. {
  1855. const char32_t* s = cp;
  1856. const char32_t* t = s2;
  1857. while(*s && *t && (Tolower(*s) == Tolower(*t)))
  1858. ++s, ++t;
  1859. if(*t == 0)
  1860. return (char32_t*)cp;
  1861. ++cp;
  1862. }
  1863. return 0;
  1864. }
  1865. EASTDC_API char* Strrstr(const char* s1, const char* s2)
  1866. {
  1867. if(!*s2)
  1868. return (char*)s1;
  1869. const char* ps1 = s1 + Strlen(s1);
  1870. while(ps1 != s1)
  1871. {
  1872. const char* psc1 = --ps1;
  1873. const char* sc2 = s2;
  1874. for(;;)
  1875. {
  1876. if(*psc1++ != *sc2++)
  1877. break;
  1878. else if(!*sc2)
  1879. return (char*)ps1;
  1880. }
  1881. }
  1882. return 0;
  1883. }
  1884. EASTDC_API char16_t* Strrstr(const char16_t* s1, const char16_t* s2)
  1885. {
  1886. if(!*s2)
  1887. return (char16_t*)s1;
  1888. const char16_t* ps1 = s1 + Strlen(s1);
  1889. while(ps1 != s1)
  1890. {
  1891. const char16_t* psc1 = --ps1;
  1892. const char16_t* sc2 = s2;
  1893. for(;;)
  1894. {
  1895. if(*psc1++ != *sc2++)
  1896. break;
  1897. else if(!*sc2)
  1898. return (char16_t*)ps1;
  1899. }
  1900. }
  1901. return 0;
  1902. }
  1903. EASTDC_API char32_t* Strrstr(const char32_t* s1, const char32_t* s2)
  1904. {
  1905. if(!*s2)
  1906. return (char32_t*)s1;
  1907. const char32_t* ps1 = s1 + Strlen(s1);
  1908. while(ps1 != s1)
  1909. {
  1910. const char32_t* psc1 = --ps1;
  1911. const char32_t* sc2 = s2;
  1912. for(;;)
  1913. {
  1914. if(*psc1++ != *sc2++)
  1915. break;
  1916. else if(!*sc2)
  1917. return (char32_t*)ps1;
  1918. }
  1919. }
  1920. return 0;
  1921. }
  1922. EASTDC_API char* Strirstr(const char* s1, const char* s2)
  1923. {
  1924. if(!*s2)
  1925. return (char*)s1;
  1926. const char* ps1 = s1 + Strlen(s1);
  1927. while(ps1 != s1)
  1928. {
  1929. const char* psc1 = --ps1;
  1930. const char* sc2 = s2;
  1931. for(;;)
  1932. {
  1933. if(Tolower(*psc1++) != Tolower(*sc2++))
  1934. break;
  1935. else if(!*sc2)
  1936. return (char*)ps1;
  1937. }
  1938. }
  1939. return 0;
  1940. }
  1941. EASTDC_API char16_t* Strirstr(const char16_t* s1, const char16_t* s2)
  1942. {
  1943. if(!*s2)
  1944. return (char16_t*)s1;
  1945. const char16_t* ps1 = s1 + Strlen(s1);
  1946. while(ps1 != s1)
  1947. {
  1948. const char16_t* psc1 = --ps1;
  1949. const char16_t* sc2 = s2;
  1950. for(;;)
  1951. {
  1952. if(Tolower(*psc1++) != Tolower(*sc2++))
  1953. break;
  1954. else if(!*sc2)
  1955. return (char16_t*)ps1;
  1956. }
  1957. }
  1958. return 0;
  1959. }
  1960. EASTDC_API char32_t* Strirstr(const char32_t* s1, const char32_t* s2)
  1961. {
  1962. if(!*s2)
  1963. return (char32_t*)s1;
  1964. const char32_t* ps1 = s1 + Strlen(s1);
  1965. while(ps1 != s1)
  1966. {
  1967. const char32_t* psc1 = --ps1;
  1968. const char32_t* sc2 = s2;
  1969. for(;;)
  1970. {
  1971. if(Tolower(*psc1++) != Tolower(*sc2++))
  1972. break;
  1973. else if(!*sc2)
  1974. return (char32_t*)ps1;
  1975. }
  1976. }
  1977. return 0;
  1978. }
  1979. EASTDC_API bool Strstart(const char* pString, const char* pPrefix)
  1980. {
  1981. while(*pPrefix)
  1982. {
  1983. if(*pString++ != *pPrefix++)
  1984. return false;
  1985. }
  1986. return true;
  1987. }
  1988. EASTDC_API bool Strstart(const char16_t* pString, const char16_t* pPrefix)
  1989. {
  1990. while(*pPrefix)
  1991. {
  1992. if(*pString++ != *pPrefix++)
  1993. return false;
  1994. }
  1995. return true;
  1996. }
  1997. EASTDC_API bool Strstart(const char32_t* pString, const char32_t* pPrefix)
  1998. {
  1999. while(*pPrefix)
  2000. {
  2001. if(*pString++ != *pPrefix++)
  2002. return false;
  2003. }
  2004. return true;
  2005. }
  2006. EASTDC_API bool Stristart(const char* pString, const char* pPrefix)
  2007. {
  2008. while(*pPrefix)
  2009. {
  2010. if(Tolower(*pString++) != Tolower(*pPrefix++))
  2011. return false;
  2012. }
  2013. return true;
  2014. }
  2015. EASTDC_API bool Stristart(const char16_t* pString, const char16_t* pPrefix)
  2016. {
  2017. while(*pPrefix)
  2018. {
  2019. if(Tolower(*pString++) != Tolower(*pPrefix++))
  2020. return false;
  2021. }
  2022. return true;
  2023. }
  2024. EASTDC_API bool Stristart(const char32_t* pString, const char32_t* pPrefix)
  2025. {
  2026. while(*pPrefix)
  2027. {
  2028. if(Tolower(*pString++) != Tolower(*pPrefix++))
  2029. return false;
  2030. }
  2031. return true;
  2032. }
  2033. EASTDC_API bool Strend(const char* pString, const char* pSuffix, size_t stringLength, size_t suffixLength)
  2034. {
  2035. if(stringLength == kSizeTypeUnset)
  2036. stringLength = Strlen(pString);
  2037. if(suffixLength == kSizeTypeUnset)
  2038. suffixLength = Strlen(pSuffix);
  2039. if(stringLength >= suffixLength)
  2040. return Memcmp(pString + stringLength - suffixLength, pSuffix, suffixLength * sizeof(char)) == 0;
  2041. return false;
  2042. }
  2043. EASTDC_API bool Strend(const char16_t* pString, const char16_t* pSuffix, size_t stringLength, size_t suffixLength)
  2044. {
  2045. if(stringLength == kSizeTypeUnset)
  2046. stringLength = Strlen(pString);
  2047. if(suffixLength == kSizeTypeUnset)
  2048. suffixLength = Strlen(pSuffix);
  2049. if(stringLength >= suffixLength)
  2050. return Memcmp(pString + stringLength - suffixLength, pSuffix, suffixLength * sizeof(char16_t)) == 0;
  2051. return false;
  2052. }
  2053. EASTDC_API bool Strend(const char32_t* pString, const char32_t* pSuffix, size_t stringLength, size_t suffixLength)
  2054. {
  2055. if(stringLength == kSizeTypeUnset)
  2056. stringLength = Strlen(pString);
  2057. if(suffixLength == kSizeTypeUnset)
  2058. suffixLength = Strlen(pSuffix);
  2059. if(stringLength >= suffixLength)
  2060. return Memcmp(pString + stringLength - suffixLength, pSuffix, suffixLength * sizeof(char32_t)) == 0;
  2061. return false;
  2062. }
  2063. EASTDC_API bool Striend(const char* pString, const char* pSuffix, size_t stringLength, size_t suffixLength)
  2064. {
  2065. if(stringLength == kSizeTypeUnset)
  2066. stringLength = Strlen(pString);
  2067. if(suffixLength == kSizeTypeUnset)
  2068. suffixLength = Strlen(pSuffix);
  2069. if(stringLength >= suffixLength)
  2070. return Stricmp(pString + stringLength - suffixLength, pSuffix) == 0;
  2071. return false;
  2072. }
  2073. EASTDC_API bool Striend(const char16_t* pString, const char16_t* pSuffix, size_t stringLength, size_t suffixLength)
  2074. {
  2075. if(stringLength == kSizeTypeUnset)
  2076. stringLength = Strlen(pString);
  2077. if(suffixLength == kSizeTypeUnset)
  2078. suffixLength = Strlen(pSuffix);
  2079. if(stringLength >= suffixLength)
  2080. return Stricmp(pString + stringLength - suffixLength, pSuffix) == 0;
  2081. return false;
  2082. }
  2083. EASTDC_API bool Striend(const char32_t* pString, const char32_t* pSuffix, size_t stringLength, size_t suffixLength)
  2084. {
  2085. if(stringLength == kSizeTypeUnset)
  2086. stringLength = Strlen(pString);
  2087. if(suffixLength == kSizeTypeUnset)
  2088. suffixLength = Strlen(pSuffix);
  2089. if(stringLength >= suffixLength)
  2090. return Stricmp(pString + stringLength - suffixLength, pSuffix) == 0;
  2091. return false;
  2092. }
  2093. ///////////////////////////////////////////////////////////////////
  2094. // This function was implemented by Avery Lee.
  2095. //
  2096. EASTDC_API char* Strtok(char* pString, const char* pDelimiters, char** pContext)
  2097. {
  2098. // find point on string to resume
  2099. char* s = pString;
  2100. if(!s)
  2101. {
  2102. s = *pContext;
  2103. if(!s)
  2104. return NULL;
  2105. }
  2106. // Compute bit hash based on lower 5 bits of delimiter characters
  2107. const char* d = pDelimiters;
  2108. int32_t hash = 0;
  2109. uint32_t delimiterCount = 0;
  2110. while(const char c = *d++)
  2111. {
  2112. hash |= (int32_t)(0x80000000 >> (c & 31));
  2113. ++delimiterCount;
  2114. }
  2115. // Skip delimiters
  2116. for(;;)
  2117. {
  2118. const char c = *s;
  2119. // If we hit the end of the string, it ends solely with delimiters
  2120. // and there are no more tokens to get.
  2121. if(!c)
  2122. {
  2123. *pContext = NULL;
  2124. return NULL;
  2125. }
  2126. // Fast rejection against hash set
  2127. if(int32_t(uint64_t(hash) << (c & 31)) >= 0)
  2128. break;
  2129. // brute-force search against delimiter list
  2130. for(uint32_t i=0; i<delimiterCount; ++i)
  2131. {
  2132. if (pDelimiters[i] == c) // Is it a delimiter? ...
  2133. goto still_delimiters; // yes, continue the loop
  2134. }
  2135. // Not a token, so exit
  2136. break;
  2137. still_delimiters:
  2138. ++s;
  2139. }
  2140. // Mark beginning of token
  2141. char* const pToken = s;
  2142. // Search for end of token
  2143. while(const char c = *s)
  2144. {
  2145. // Fast rejection against hash set
  2146. if(int32_t(int64_t(hash) << (c & 31)) < 0)
  2147. {
  2148. // Brute-force search against delimiter list
  2149. for(uint32_t i=0; i<delimiterCount; ++i)
  2150. {
  2151. if(pDelimiters[i] == c)
  2152. {
  2153. // This token ends with a delimiter.
  2154. *s = 0; // null-term substring
  2155. *pContext = (s + 1); // restart on next byte
  2156. return pToken; // return found token
  2157. }
  2158. }
  2159. }
  2160. ++s;
  2161. }
  2162. // We found a token but it was at the end of the string,
  2163. // so we null out the context and return the last token.
  2164. *pContext = NULL; // no more tokens
  2165. return pToken; // return found token
  2166. }
  2167. EASTDC_API char16_t* Strtok(char16_t* pString, const char16_t* pDelimiters, char16_t** pContext)
  2168. {
  2169. // Find point on string to resume
  2170. char16_t* s = pString;
  2171. if(!s)
  2172. {
  2173. s = *pContext;
  2174. if(!s)
  2175. return NULL;
  2176. }
  2177. // compute bit hash based on lower 5 bits of delimiter characters
  2178. const char16_t* d = pDelimiters;
  2179. int32_t hash = 0;
  2180. uint32_t delimiterCount = 0;
  2181. while(const char16_t c = *d++)
  2182. {
  2183. hash |= (int32_t)(0x80000000 >> (c & 31));
  2184. ++delimiterCount;
  2185. }
  2186. // Skip delimiters
  2187. for(;;)
  2188. {
  2189. const char16_t c = *s;
  2190. // If we hit the end of the string, it ends solely with delimiters
  2191. // and there are no more tokens to get.
  2192. if(!c)
  2193. {
  2194. *pContext = NULL;
  2195. return NULL;
  2196. }
  2197. // Fast rejection against hash set
  2198. if(int32_t(int64_t(hash) << (c & 31)) >= 0)
  2199. break;
  2200. // Brute-force search against delimiter list
  2201. for(uint32_t i=0; i<delimiterCount; ++i)
  2202. {
  2203. if(pDelimiters[i] == (char16_t)c) // Is it a delimiter? ...
  2204. goto still_delimiters; // yes, continue the loop
  2205. }
  2206. // Not a token, so exit
  2207. break;
  2208. still_delimiters:
  2209. ++s;
  2210. }
  2211. // Mark beginning of token
  2212. char16_t* const pToken = s;
  2213. // Search for end of token
  2214. while(const char16_t c = *s)
  2215. {
  2216. // Fast rejection against hash set
  2217. if(int32_t(int64_t(hash) << (c & 31)) < 0)
  2218. {
  2219. // Brute-force search against delimiter list
  2220. for(uint32_t i=0; i<delimiterCount; ++i)
  2221. {
  2222. if(pDelimiters[i] == c)
  2223. {
  2224. // This token ends with a delimiter.
  2225. *s = 0; // null-term substring
  2226. *pContext = (s + 1); // restart on next byte
  2227. return pToken; // return found token
  2228. }
  2229. }
  2230. }
  2231. ++s;
  2232. }
  2233. // We found a token but it was at the end of the string,
  2234. // so we null out the context and return the last token.
  2235. *pContext = NULL; // no more tokens
  2236. return pToken; // return found token
  2237. }
  2238. EASTDC_API char32_t* Strtok(char32_t* pString, const char32_t* pDelimiters, char32_t** pContext)
  2239. {
  2240. // Find point on string to resume
  2241. char32_t* s = pString;
  2242. if(!s)
  2243. {
  2244. s = *pContext;
  2245. if(!s)
  2246. return NULL;
  2247. }
  2248. // compute bit hash based on lower 5 bits of delimiter characters
  2249. const char32_t* d = pDelimiters;
  2250. int32_t hash = 0;
  2251. uint32_t delimiterCount = 0;
  2252. while(const uint32_t c = (uint32_t)*d++)
  2253. {
  2254. hash |= (int32_t)(0x80000000 >> (c & 31));
  2255. ++delimiterCount;
  2256. }
  2257. // Skip delimiters
  2258. for(;;)
  2259. {
  2260. const char32_t c = *s;
  2261. // If we hit the end of the string, it ends solely with delimiters
  2262. // and there are no more tokens to get.
  2263. if(!c)
  2264. {
  2265. *pContext = NULL;
  2266. return NULL;
  2267. }
  2268. // Fast rejection against hash set
  2269. if(int32_t(int64_t(hash) << (c & 31)) >= 0)
  2270. break;
  2271. // Brute-force search against delimiter list
  2272. for(uint32_t i=0; i<delimiterCount; ++i)
  2273. {
  2274. if(pDelimiters[i] == c) // Is it a delimiter? ...
  2275. goto still_delimiters; // yes, continue the loop
  2276. }
  2277. // Not a token, so exit
  2278. break;
  2279. still_delimiters:
  2280. ++s;
  2281. }
  2282. // Mark beginning of token
  2283. char32_t* const pToken = s;
  2284. // Search for end of token
  2285. while(const uint32_t c = (uint32_t)*s)
  2286. {
  2287. // Fast rejection against hash set
  2288. if(int32_t(int64_t(hash) << (c & 31)) < 0)
  2289. {
  2290. // Brute-force search against delimiter list
  2291. for(uint32_t i=0; i<delimiterCount; ++i)
  2292. {
  2293. if(pDelimiters[i] == (char32_t)c)
  2294. {
  2295. // This token ends with a delimiter.
  2296. *s = 0; // null-term substring
  2297. *pContext = (s + 1); // restart on next byte
  2298. return pToken; // return found token
  2299. }
  2300. }
  2301. }
  2302. ++s;
  2303. }
  2304. // We found a token but it was at the end of the string,
  2305. // so we null out the context and return the last token.
  2306. *pContext = NULL; // no more tokens
  2307. return pToken; // return found token
  2308. }
  2309. EASTDC_API const char* Strtok2(const char* pString, const char* pDelimiters,
  2310. size_t* pResultLength, bool bFirst)
  2311. {
  2312. // Skip any non-delimiters
  2313. if(!bFirst)
  2314. {
  2315. while(*pString && !Strchr(pDelimiters, *pString))
  2316. ++pString;
  2317. }
  2318. // Skip any delimiters
  2319. while(*pString && Strchr(pDelimiters, *pString))
  2320. ++pString;
  2321. const char* const pBegin = pString;
  2322. // Calculate the length of the string
  2323. while(*pString && !Strchr(pDelimiters, *pString))
  2324. ++pString;
  2325. if(pBegin != pString)
  2326. {
  2327. *pResultLength = static_cast<size_t>(pString - pBegin);
  2328. return pBegin;
  2329. }
  2330. *pResultLength = 0;
  2331. return NULL;
  2332. }
  2333. EASTDC_API const char16_t* Strtok2(const char16_t* pString, const char16_t* pDelimiters, size_t* pResultLength, bool bFirst)
  2334. {
  2335. // Skip any non-delimiters
  2336. if(!bFirst)
  2337. {
  2338. while(*pString && !Strchr(pDelimiters, *pString))
  2339. ++pString;
  2340. }
  2341. // Skip any delimiters
  2342. while(*pString && Strchr(pDelimiters, *pString))
  2343. ++pString;
  2344. const char16_t* const pBegin = pString;
  2345. // Calculate the length of the string
  2346. while(*pString && !Strchr(pDelimiters, *pString))
  2347. ++pString;
  2348. if(pBegin != pString)
  2349. {
  2350. *pResultLength = static_cast<size_t>(pString - pBegin);
  2351. return pBegin;
  2352. }
  2353. *pResultLength = 0;
  2354. return NULL;
  2355. }
  2356. EASTDC_API const char32_t* Strtok2(const char32_t* pString, const char32_t* pDelimiters, size_t* pResultLength, bool bFirst)
  2357. {
  2358. // Skip any non-delimiters
  2359. if(!bFirst)
  2360. {
  2361. while(*pString && !Strchr(pDelimiters, *pString))
  2362. ++pString;
  2363. }
  2364. // Skip any delimiters
  2365. while(*pString && Strchr(pDelimiters, *pString))
  2366. ++pString;
  2367. const char32_t* const pBegin = pString;
  2368. // Calculate the length of the string
  2369. while(*pString && !Strchr(pDelimiters, *pString))
  2370. ++pString;
  2371. if(pBegin != pString)
  2372. {
  2373. *pResultLength = static_cast<size_t>(pString - pBegin);
  2374. return pBegin;
  2375. }
  2376. *pResultLength = 0;
  2377. return NULL;
  2378. }
  2379. EASTDC_API char* Strset(char* pString, int c)
  2380. {
  2381. char* pStringTemp = pString;
  2382. while(*pStringTemp)
  2383. *pStringTemp++ = (char)c;
  2384. return pString;
  2385. }
  2386. EASTDC_API char16_t* Strset(char16_t* pString, char16_t c)
  2387. {
  2388. char16_t* pStringTemp = pString;
  2389. while(*pStringTemp)
  2390. *pStringTemp++ = c;
  2391. return pString;
  2392. }
  2393. EASTDC_API char32_t* Strset(char32_t* pString, char32_t c)
  2394. {
  2395. char32_t* pStringTemp = pString;
  2396. while(*pStringTemp)
  2397. *pStringTemp++ = c;
  2398. return pString;
  2399. }
  2400. EASTDC_API char* Strnset(char* pString, int c, size_t n)
  2401. {
  2402. char* pSaved = pString;
  2403. for(size_t i = 0; *pString && (i < n); ++i)
  2404. *pString++ = (char)c;
  2405. return pSaved;
  2406. }
  2407. EASTDC_API char16_t* Strnset(char16_t* pString, char16_t c, size_t n)
  2408. {
  2409. char16_t* pSaved = pString;
  2410. for(size_t i = 0; *pString && (i < n); ++i)
  2411. *pString++ = c;
  2412. return pSaved;
  2413. }
  2414. EASTDC_API char32_t* Strnset(char32_t* pString, char32_t c, size_t n)
  2415. {
  2416. char32_t* pSaved = pString;
  2417. for(size_t i = 0; *pString && (i < n); ++i)
  2418. *pString++ = c;
  2419. return pSaved;
  2420. }
  2421. EASTDC_API char* Strrev(char* pString)
  2422. {
  2423. for(char* p1 = pString, *p2 = (pString + Strlen(pString)) - 1; p1 < p2; ++p1, --p2)
  2424. {
  2425. char c = *p2;
  2426. *p2 = *p1;
  2427. *p1 = c;
  2428. }
  2429. return pString;
  2430. }
  2431. EASTDC_API char16_t* Strrev(char16_t* pString)
  2432. {
  2433. for(char16_t* p1 = pString, *p2 = (pString + Strlen(pString)) - 1; p1 < p2; ++p1, --p2)
  2434. {
  2435. char16_t c = *p2;
  2436. *p2 = *p1;
  2437. *p1 = c;
  2438. }
  2439. return pString;
  2440. }
  2441. EASTDC_API char32_t* Strrev(char32_t* pString)
  2442. {
  2443. for(char32_t* p1 = pString, *p2 = (pString + Strlen(pString)) - 1; p1 < p2; ++p1, --p2)
  2444. {
  2445. char32_t c = *p2;
  2446. *p2 = *p1;
  2447. *p1 = c;
  2448. }
  2449. return pString;
  2450. }
  2451. EASTDC_API char* Strstrip(char* pString)
  2452. {
  2453. // Walk forward from the beginning and find the first non-whitespace.
  2454. while(EA::StdC::Isspace(*pString)) // Isspace returns false for *pString == '\0'.
  2455. ++pString;
  2456. if(*pString)
  2457. {
  2458. // Walk backward from the end and find the last whitespace.
  2459. size_t length = EA::StdC::Strlen(pString);
  2460. char* pEnd = (pString + length) - 1;
  2461. while((pEnd > pString) && EA::StdC::Isspace(*pEnd))
  2462. pEnd--;
  2463. pEnd[1] = '\0';
  2464. }
  2465. return pString;
  2466. }
  2467. EASTDC_API char16_t* Strstrip(char16_t* pString)
  2468. {
  2469. // Walk forward from the beginning and find the first non-whitespace.
  2470. while(EA::StdC::Isspace(*pString)) // Isspace returns false for *pString == '\0'.
  2471. ++pString;
  2472. if(*pString)
  2473. {
  2474. // Walk backward from the end and find the last whitespace.
  2475. size_t length = EA::StdC::Strlen(pString);
  2476. char16_t* pEnd = (pString + length) - 1;
  2477. while((pEnd > pString) && EA::StdC::Isspace(*pEnd))
  2478. pEnd--;
  2479. pEnd[1] = '\0';
  2480. }
  2481. return pString;
  2482. }
  2483. EASTDC_API char32_t* Strstrip(char32_t* pString)
  2484. {
  2485. // Walk forward from the beginning and find the first non-whitespace.
  2486. while(EA::StdC::Isspace(*pString)) // Isspace returns false for *pString == '\0'.
  2487. ++pString;
  2488. if(*pString)
  2489. {
  2490. // Walk backward from the end and find the last whitespace.
  2491. size_t length = EA::StdC::Strlen(pString);
  2492. char32_t* pEnd = (pString + length) - 1;
  2493. while((pEnd > pString) && EA::StdC::Isspace(*pEnd))
  2494. pEnd--;
  2495. pEnd[1] = '\0';
  2496. }
  2497. return pString;
  2498. }
  2499. // Optimized Strcmp
  2500. //
  2501. // This function assumes that we can read the last size_t-sized word at
  2502. // the end of the string, even if as many as three of the word bytes are
  2503. // beyond the end of the string. This is typically a valid assumption
  2504. // because valid memory is always aligned to big power-of-2 sizes.
  2505. //
  2506. // There could be faster strcmp implementations with some additional
  2507. // tricks, asm, SSE, etc. But this version works well while being simple.
  2508. // To do: Implement a vector-specific version for at least x64-based platforms.
  2509. #if EASTDC_STATIC_ANALYSIS_ENABLED
  2510. #define EASTDC_ENABLE_OPTIMIZED_STRCMP 0 // Disabled because the optimized strcmp reads words and the string may have some uninitialized chars at the
  2511. #else // end past the trailing 0 char. Valgrind reports this as an error, but it's not actually an error in practice.
  2512. #define EASTDC_ENABLE_OPTIMIZED_STRCMP 1
  2513. #endif
  2514. #if EASTDC_ENABLE_OPTIMIZED_STRCMP
  2515. #if defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_OSX)
  2516. // Some platforms have an optimized vector implementation of strcmp which is fast and which provides
  2517. // identical return value behavior to our Strcmp (which is to return the byte difference and not just
  2518. // -1, 0, +1). And so until we have our own vectored version we use the built-in version.
  2519. EASTDC_API int Strcmp(const char* pString1, const char* pString2)
  2520. {
  2521. return strcmp(pString1, pString2);
  2522. }
  2523. #else
  2524. // To do: Implement an x86/x64 vectorized version of Strcmp, which can work on 16 byte chunks and thus be faster than below.
  2525. EASTDC_API int Strcmp(const char* pString1, const char* pString2)
  2526. {
  2527. if(IsAligned<const char, sizeof(word_type)>(pString1) && // If pString1 and pString2 are word-aligned... compare in word-sized chunks.
  2528. IsAligned<const char, sizeof(word_type)>(pString2))
  2529. {
  2530. const word_type* pWord1 = (word_type*)pString1;
  2531. const word_type* pWord2 = (word_type*)pString2;
  2532. while(*pWord1 == *pWord2)
  2533. {
  2534. if(ZeroPresent8(*pWord1++))
  2535. return 0;
  2536. ++pWord2;
  2537. }
  2538. // At this point, the strings differ somewhere in the bytes pointed to by pWord1/pWord2.
  2539. pString1 = reinterpret_cast<const char*>(pWord1); // Fall through and do byte comparisons for the rest of the string.
  2540. pString2 = reinterpret_cast<const char*>(pWord2);
  2541. }
  2542. while(*pString1 && (*pString1 == *pString2))
  2543. {
  2544. ++pString1;
  2545. ++pString2;
  2546. }
  2547. return ((uint8_t)*pString1 - (uint8_t)*pString2);
  2548. }
  2549. #endif
  2550. #else
  2551. EASTDC_API int Strcmp(const char* pString1, const char* pString2)
  2552. {
  2553. char c1, c2;
  2554. while((c1 = *pString1++) == (c2 = *pString2++))
  2555. {
  2556. if(c1 == 0)
  2557. return 0;
  2558. }
  2559. return ((uint8_t)c1 - (uint8_t)c2);
  2560. }
  2561. #endif
  2562. #if EASTDC_ENABLE_OPTIMIZED_STRCMP
  2563. // To do: Implement an x86/x64 vectorized version of Strcmp, which can work on 16 byte chunks and thus be faster than below.
  2564. EASTDC_API int Strcmp(const char16_t* pString1, const char16_t* pString2)
  2565. {
  2566. if(IsAligned<const char16_t, sizeof(word_type)>(pString1) && // If pString1 and pString2 are word-aligned... compare in word-sized chunks.
  2567. IsAligned<const char16_t, sizeof(word_type)>(pString2))
  2568. {
  2569. const word_type* pWord1 = (word_type*)pString1;
  2570. const word_type* pWord2 = (word_type*)pString2;
  2571. while(*pWord1 == *pWord2)
  2572. {
  2573. if(ZeroPresent16(*pWord1++))
  2574. return 0;
  2575. ++pWord2;
  2576. }
  2577. // At this point, the strings differ somewhere in the bytes pointed to by pWord1/pWord2.
  2578. pString1 = reinterpret_cast<const char16_t*>(pWord1); // Fall through and do byte comparisons for the rest of the string.
  2579. pString2 = reinterpret_cast<const char16_t*>(pWord2);
  2580. }
  2581. while(*pString1 && (*pString1 == *pString2))
  2582. {
  2583. ++pString1;
  2584. ++pString2;
  2585. }
  2586. return ((uint16_t)*pString1 - (uint16_t)*pString2);
  2587. }
  2588. #else
  2589. EASTDC_API int Strcmp(const char16_t* pString1, const char16_t* pString2)
  2590. {
  2591. char16_t c1, c2;
  2592. while((c1 = *pString1++) == (c2 = *pString2++))
  2593. {
  2594. if(c1 == 0) // If we've reached the end of the string with no difference...
  2595. return 0;
  2596. }
  2597. EA_COMPILETIME_ASSERT(sizeof(int) > sizeof(uint16_t));
  2598. return ((uint16_t)c1 - (uint16_t)c2);
  2599. }
  2600. #endif
  2601. EASTDC_API int Strcmp(const char32_t* pString1, const char32_t* pString2)
  2602. {
  2603. char32_t c1, c2;
  2604. while((c1 = *pString1++) == (c2 = *pString2++))
  2605. {
  2606. if(c1 == 0) // If we've reached the end of the string with no difference...
  2607. return 0;
  2608. }
  2609. // We can't just return c1 - c2, because the difference might be greater than INT_MAX.
  2610. return ((uint32_t)c1 > (uint32_t)c2) ? 1 : -1;
  2611. }
  2612. #if EASTDC_ENABLE_OPTIMIZED_STRCMP
  2613. // Some platforms have an optimized vector implementation of strncmp which is fast and which provides
  2614. // identical return value behavior to our Strncmp (which is to return the byte difference and not just
  2615. // -1, 0, +1). And so until we have our own vectored version we use the built-in version.
  2616. EASTDC_API int Strncmp(const char* pString1, const char* pString2, size_t n)
  2617. {
  2618. return strncmp(pString1, pString2, n);
  2619. }
  2620. // To do: Implement a general portable version of a more optimized Strncmp.
  2621. #else
  2622. EASTDC_API int Strncmp(const char* pString1, const char* pString2, size_t n)
  2623. {
  2624. char c1, c2;
  2625. ++n;
  2626. while(--n)
  2627. {
  2628. if((c1 = *pString1++) != (c2 = *pString2++))
  2629. return ((uint8_t)c1 - (uint8_t)c2);
  2630. else if(c1 == 0)
  2631. break;
  2632. }
  2633. return 0;
  2634. }
  2635. #endif
  2636. EASTDC_API int Strncmp(const char16_t* pString1, const char16_t* pString2, size_t n)
  2637. {
  2638. char16_t c1, c2;
  2639. // Code below which uses (c1 - c2) assumes this.
  2640. EA_COMPILETIME_ASSERT(sizeof(int) > sizeof(uint16_t));
  2641. ++n;
  2642. while(--n)
  2643. {
  2644. if((c1 = *pString1++) != (c2 = *pString2++))
  2645. return ((uint16_t)c1 - (uint16_t)c2);
  2646. else if(c1 == 0)
  2647. break;
  2648. }
  2649. return 0;
  2650. }
  2651. EASTDC_API int Strncmp(const char32_t* pString1, const char32_t* pString2, size_t n)
  2652. {
  2653. char32_t c1, c2;
  2654. ++n;
  2655. while(--n)
  2656. {
  2657. if((c1 = *pString1++) != (c2 = *pString2++))
  2658. {
  2659. // We can't just return c1 - c2, because the difference might be greater than INT_MAX.
  2660. return ((uint32_t)c1 > (uint32_t)c2) ? 1 : -1;
  2661. }
  2662. else if(c1 == 0)
  2663. break;
  2664. }
  2665. return 0;
  2666. }
  2667. #if EASTDC_ENABLE_OPTIMIZED_STRCMP && (defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_OSX))
  2668. // Some platforms have an optimized vector implementation of stricmp/strcasecmp which is fast and which provides
  2669. // identical return value behavior to our Stricmp (which is to return the byte difference and not just
  2670. // -1, 0, +1). And so until we have our own vectored version we use the built-in version.
  2671. EASTDC_API int Stricmp(const char* pString1, const char* pString2)
  2672. {
  2673. return strcasecmp(pString1, pString2);
  2674. }
  2675. // To do: Implement a general portable version of a more optimized Stricmp.
  2676. #else
  2677. EASTDC_API int Stricmp(const char* pString1, const char* pString2)
  2678. {
  2679. char c1, c2;
  2680. while((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++)))
  2681. {
  2682. if(c1 == 0)
  2683. return 0;
  2684. }
  2685. return ((uint8_t)c1 - (uint8_t)c2);
  2686. }
  2687. #endif
  2688. EASTDC_API int Stricmp(const char16_t* pString1, const char16_t* pString2)
  2689. {
  2690. char16_t c1, c2;
  2691. while((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++)))
  2692. {
  2693. if(c1 == 0)
  2694. return 0;
  2695. }
  2696. // Code below which uses (c1 - c2) assumes this.
  2697. EA_COMPILETIME_ASSERT(sizeof(int) > sizeof(uint16_t));
  2698. return ((uint16_t)c1 - (uint16_t)c2);
  2699. }
  2700. EASTDC_API int Stricmp(const char32_t* pString1, const char32_t* pString2)
  2701. {
  2702. char32_t c1, c2;
  2703. while((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++)))
  2704. {
  2705. if(c1 == 0)
  2706. return 0;
  2707. }
  2708. // We can't just return c1 - c2, because the difference might be greater than INT_MAX.
  2709. return ((uint32_t)c1 > (uint32_t)c2) ? 1 : -1;
  2710. }
  2711. EASTDC_API int Strnicmp(const char* pString1, const char* pString2, size_t n)
  2712. {
  2713. char c1, c2;
  2714. ++n;
  2715. while(--n)
  2716. {
  2717. if((c1 = Tolower(*pString1++)) != (c2 = Tolower(*pString2++)))
  2718. return ((uint8_t)c1 - (uint8_t)c2);
  2719. else if(c1 == 0)
  2720. break;
  2721. }
  2722. return 0;
  2723. }
  2724. EASTDC_API int Strnicmp(const char16_t* pString1, const char16_t* pString2, size_t n)
  2725. {
  2726. char16_t c1, c2;
  2727. // Code below which uses (c1 - c2) assumes this.
  2728. EA_COMPILETIME_ASSERT(sizeof(int) > sizeof(uint16_t));
  2729. ++n;
  2730. while(--n)
  2731. {
  2732. if((c1 = Tolower(*pString1++)) != (c2 = Tolower(*pString2++)))
  2733. return ((uint16_t)c1 - (uint16_t)c2);
  2734. else if(c1 == 0)
  2735. break;
  2736. }
  2737. return 0;
  2738. }
  2739. EASTDC_API int Strnicmp(const char32_t* pString1, const char32_t* pString2, size_t n)
  2740. {
  2741. char32_t c1, c2;
  2742. ++n;
  2743. while(--n)
  2744. {
  2745. if((c1 = Tolower(*pString1++)) != (c2 = Tolower(*pString2++)))
  2746. {
  2747. // We can't just return c1 - c2, because the difference might be greater than INT_MAX.
  2748. return ((uint32_t)c1 > (uint32_t)c2) ? 1 : -1;
  2749. }
  2750. else if(c1 == 0)
  2751. break;
  2752. }
  2753. return 0;
  2754. }
  2755. // *** this function is deprecated. ***
  2756. EASTDC_API int StrcmpAlnum(const char* pString1, const char* pString2)
  2757. {
  2758. char c1, c2;
  2759. const char* pStart1 = pString1;
  2760. const char* pStart2 = pString2;
  2761. const char* pDigitStart1 = pString1;
  2762. while(((c1 = *pString1++) == (c2 = *pString2++)) && c1)
  2763. {
  2764. if(!Isdigit(c1))
  2765. pDigitStart1 = pString1;
  2766. }
  2767. const int c1d = Isdigit(c1);
  2768. const int c2d = Isdigit(c2);
  2769. if(c1d && c2d)
  2770. return (int)StrtoI32(pDigitStart1, NULL, 10) - (int)StrtoI32(pStart2 + (pDigitStart1 - pStart1), NULL, 10);
  2771. if(c1d != c2d) // If one char is decimal and the other is not..
  2772. return c1d ? 1 : -1;
  2773. return ((uint8_t)c1 - (uint8_t)c2);
  2774. }
  2775. // *** this function is deprecated. ***
  2776. EASTDC_API int StrcmpAlnum(const char16_t* pString1, const char16_t* pString2)
  2777. {
  2778. char16_t c1, c2;
  2779. const char16_t* pStart1 = pString1;
  2780. const char16_t* pStart2 = pString2;
  2781. const char16_t* pDigitStart1 = pString1;
  2782. while(((c1 = *pString1++) == (c2 = *pString2++)) && c1)
  2783. {
  2784. if(!Isdigit(c1))
  2785. pDigitStart1 = pString1;
  2786. }
  2787. const int c1d = Isdigit(c1);
  2788. const int c2d = Isdigit(c2);
  2789. if(c1d && c2d)
  2790. return (int)StrtoI32(pDigitStart1, NULL, 10) - (int)StrtoI32(pStart2 + (pDigitStart1 - pStart1), NULL, 10);
  2791. if(c1d != c2d) // If one char is decimal and the other is not..
  2792. return c1d ? 1 : -1;
  2793. return ((uint16_t)c1 - (uint16_t)c2);
  2794. }
  2795. // *** this function is deprecated. ***
  2796. EASTDC_API int StricmpAlnum(const char* pString1, const char* pString2)
  2797. {
  2798. char c1, c2;
  2799. const char* pStart1 = pString1;
  2800. const char* pStart2 = pString2;
  2801. const char* pDigitStart1 = pString1;
  2802. while(((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++))) && c1)
  2803. {
  2804. if(!Isdigit(c1))
  2805. pDigitStart1 = pString1;
  2806. }
  2807. const int c1d = Isdigit(c1);
  2808. const int c2d = Isdigit(c2);
  2809. if(c1d && c2d)
  2810. return (int)StrtoI32(pDigitStart1, NULL, 10) - (int)StrtoI32(pStart2 + (pDigitStart1 - pStart1), NULL, 10);
  2811. if(c1d != c2d) // If one char is decimal and the other is not..
  2812. return c1d ? 1 : -1;
  2813. return ((uint8_t)c1 - (uint8_t)c2);
  2814. }
  2815. // *** this function is deprecated. ***
  2816. EASTDC_API int StricmpAlnum(const char16_t* pString1, const char16_t* pString2)
  2817. {
  2818. char16_t c1, c2;
  2819. const char16_t* pStart1 = pString1;
  2820. const char16_t* pStart2 = pString2;
  2821. const char16_t* pDigitStart1 = pString1;
  2822. while(((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++))) && c1)
  2823. {
  2824. if(!Isdigit(c1))
  2825. pDigitStart1 = pString1;
  2826. }
  2827. const int c1d = Isdigit(c1);
  2828. const int c2d = Isdigit(c2);
  2829. if(c1d && c2d)
  2830. return (int)StrtoI32(pDigitStart1, NULL, 10) - (int)StrtoI32(pStart2 + (pDigitStart1 - pStart1), NULL, 10);
  2831. if(c1d != c2d) // If one char is decimal and the other is not..
  2832. return c1d ? 1 : -1;
  2833. return ((uint16_t)c1 - (uint16_t)c2);
  2834. }
  2835. EASTDC_API int StrcmpNumeric(const char* pString1, const char* pString2,
  2836. size_t length1, size_t length2,
  2837. char decimal, char thousandsSeparator)
  2838. {
  2839. // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
  2840. EA_UNUSED(pString1);
  2841. EA_UNUSED(pString2);
  2842. EA_UNUSED(length1);
  2843. EA_UNUSED(length2);
  2844. EA_UNUSED(decimal);
  2845. EA_UNUSED(thousandsSeparator);
  2846. return 0;
  2847. }
  2848. EASTDC_API int StrcmpNumeric(const char16_t* pString1, const char16_t* pString2,
  2849. size_t length1, size_t length2,
  2850. char16_t decimal, char16_t thousandsSeparator)
  2851. {
  2852. // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
  2853. EA_UNUSED(pString1);
  2854. EA_UNUSED(pString2);
  2855. EA_UNUSED(length1);
  2856. EA_UNUSED(length2);
  2857. EA_UNUSED(decimal);
  2858. EA_UNUSED(thousandsSeparator);
  2859. return 0;
  2860. }
  2861. EASTDC_API int StrcmpNumeric(const char32_t* pString1, const char32_t* pString2,
  2862. size_t length1, size_t length2,
  2863. char32_t decimal, char32_t thousandsSeparator)
  2864. {
  2865. // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
  2866. EA_UNUSED(pString1);
  2867. EA_UNUSED(pString2);
  2868. EA_UNUSED(length1);
  2869. EA_UNUSED(length2);
  2870. EA_UNUSED(decimal);
  2871. EA_UNUSED(thousandsSeparator);
  2872. return 0;
  2873. }
  2874. EASTDC_API int StricmpNumeric(const char* pString1, const char* pString2,
  2875. size_t length1, size_t length2,
  2876. char decimal, char thousandsSeparator)
  2877. {
  2878. // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
  2879. EA_UNUSED(pString1);
  2880. EA_UNUSED(pString2);
  2881. EA_UNUSED(length1);
  2882. EA_UNUSED(length2);
  2883. EA_UNUSED(decimal);
  2884. EA_UNUSED(thousandsSeparator);
  2885. return 0;
  2886. }
  2887. EASTDC_API int StricmpNumeric(const char16_t* pString1, const char16_t* pString2,
  2888. size_t length1, size_t length2,
  2889. char16_t decimal, char16_t thousandsSeparator)
  2890. {
  2891. // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
  2892. EA_UNUSED(pString1);
  2893. EA_UNUSED(pString2);
  2894. EA_UNUSED(length1);
  2895. EA_UNUSED(length2);
  2896. EA_UNUSED(decimal);
  2897. EA_UNUSED(thousandsSeparator);
  2898. return 0;
  2899. }
  2900. EASTDC_API int StricmpNumeric(const char32_t* pString1, const char32_t* pString2,
  2901. size_t length1, size_t length2,
  2902. char32_t decimal, char32_t thousandsSeparator)
  2903. {
  2904. // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
  2905. EA_UNUSED(pString1);
  2906. EA_UNUSED(pString2);
  2907. EA_UNUSED(length1);
  2908. EA_UNUSED(length2);
  2909. EA_UNUSED(decimal);
  2910. EA_UNUSED(thousandsSeparator);
  2911. return 0;
  2912. }
  2913. EASTDC_API int Strcoll(const char* pString1, const char* pString2)
  2914. {
  2915. // The user needs to use a localization package to get proper localized collation.
  2916. return Strcmp(pString1, pString2);
  2917. }
  2918. EASTDC_API int Strcoll(const char16_t* pString1, const char16_t* pString2)
  2919. {
  2920. // The user needs to use a localization package to get proper localized collation.
  2921. return Strcmp(pString1, pString2);
  2922. }
  2923. EASTDC_API int Strcoll(const char32_t* pString1, const char32_t* pString2)
  2924. {
  2925. // The user needs to use a localization package to get proper localized collation.
  2926. return Strcmp(pString1, pString2);
  2927. }
  2928. EASTDC_API int Strncoll(const char* pString1, const char* pString2, size_t n)
  2929. {
  2930. // The user needs to use a localization package to get proper localized collation.
  2931. return Strncmp(pString1, pString2, n);
  2932. }
  2933. EASTDC_API int Strncoll(const char16_t* pString1, const char16_t* pString2, size_t n)
  2934. {
  2935. // The user needs to use a localization package to get proper localized collation.
  2936. return Strncmp(pString1, pString2, n);
  2937. }
  2938. EASTDC_API int Strncoll(const char32_t* pString1, const char32_t* pString2, size_t n)
  2939. {
  2940. // The user needs to use a localization package to get proper localized collation.
  2941. return Strncmp(pString1, pString2, n);
  2942. }
  2943. EASTDC_API int Stricoll(const char* pString1, const char* pString2)
  2944. {
  2945. // The user needs to use a localization package to get proper localized collation.
  2946. return Stricmp(pString1, pString2);
  2947. }
  2948. EASTDC_API int Stricoll(const char16_t* pString1, const char16_t* pString2)
  2949. {
  2950. // The user needs to use a localization package to get proper localized collation.
  2951. return Stricmp(pString1, pString2);
  2952. }
  2953. EASTDC_API int Stricoll(const char32_t* pString1, const char32_t* pString2)
  2954. {
  2955. // The user needs to use a localization package to get proper localized collation.
  2956. return Stricmp(pString1, pString2);
  2957. }
  2958. EASTDC_API int Strnicoll(const char* pString1, const char* pString2, size_t n)
  2959. {
  2960. // The user needs to use a localization package to get proper localized collation.
  2961. return Strnicmp(pString1, pString2, n);
  2962. }
  2963. EASTDC_API int Strnicoll(const char16_t* pString1, const char16_t* pString2, size_t n)
  2964. {
  2965. // The user needs to use a localization package to get proper localized collation.
  2966. return Strnicmp(pString1, pString2, n);
  2967. }
  2968. EASTDC_API int Strnicoll(const char32_t* pString1, const char32_t* pString2, size_t n)
  2969. {
  2970. // The user needs to use a localization package to get proper localized collation.
  2971. return Strnicmp(pString1, pString2, n);
  2972. }
  2973. ///////////////////////////////////////////////////////////////////////////////
  2974. // EcvtBuf / FcvtBuf
  2975. //
  2976. #if EASTDC_NATIVE_FCVT
  2977. EASTDC_API char* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char* buffer)
  2978. {
  2979. #ifdef __GNUC__
  2980. const char* const pResult = ecvt(dValue, nDigitCount, decimalPos, sign);
  2981. #else
  2982. const char* const pResult = _ecvt(dValue, nDigitCount, decimalPos, sign);
  2983. #endif
  2984. strcpy(buffer, pResult);
  2985. #if EASTDC_NATIVE_FCVT_SHORT
  2986. // For ecvt, nDigitCount is the resulting length of the buffer of digits, regardless of the decimal point location.
  2987. if(nDigitCount > 15) // The '> 15' part is a quick check to avoid the rest of the code for most cases.
  2988. {
  2989. int len = (int)strlen(buffer);
  2990. while(len < nDigitCount)
  2991. buffer[len++] = '0';
  2992. buffer[len] = 0;
  2993. }
  2994. #endif
  2995. return buffer;
  2996. }
  2997. EASTDC_API char* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char* buffer)
  2998. {
  2999. #ifdef __GNUC__
  3000. const char* const pResult = fcvt(dValue, nDigitCountAfterDecimal, decimalPos, sign);
  3001. #else
  3002. char pResult[_CVTBUFSIZE+1];
  3003. _fcvt_s(pResult, sizeof(pResult), dValue, nDigitCountAfterDecimal, decimalPos, sign);
  3004. #endif
  3005. strcpy(buffer, pResult);
  3006. #if EASTDC_NATIVE_FCVT_SHORT
  3007. // For fcvt, nDigitCount is the resulting length of the buffer of digits after the decimal point location.
  3008. nDigitCountAfterDecimal += *decimalPos;
  3009. if(nDigitCountAfterDecimal > 15) // The '> 15' part is a quick check to avoid the rest of the code for most cases.
  3010. {
  3011. int len = (int)strlen(buffer);
  3012. while(len < nDigitCountAfterDecimal)
  3013. buffer[len++] = '0';
  3014. buffer[len] = 0;
  3015. }
  3016. #endif
  3017. return buffer;
  3018. }
  3019. #else
  3020. #if defined(EA_COMPILER_MSVC)
  3021. #include <float.h>
  3022. #define isnan(x) _isnan(x)
  3023. //#define isinf(x) !_finite(x)
  3024. #endif
  3025. #if !defined(isnan)
  3026. inline bool isnan(double fValue)
  3027. {
  3028. const union {
  3029. double f;
  3030. int64_t i;
  3031. } converter = { fValue };
  3032. // An IEEE real value is a NaN if all exponent bits are one and
  3033. // the mantissa is not zero.
  3034. return (converter.i & ~kFloat64SignMask) > kFloat64ExponentMask;
  3035. }
  3036. #endif
  3037. union DoubleShape
  3038. {
  3039. double mValue;
  3040. uint32_t mUint64;
  3041. #if defined(EA_SYSTEM_LITTLE_ENDIAN)
  3042. struct numberStruct
  3043. {
  3044. unsigned int fraction1 : 32;
  3045. unsigned int fraction0 : 20;
  3046. unsigned int exponent : 11;
  3047. unsigned int sign : 1;
  3048. } mNumber;
  3049. #else
  3050. struct numberStruct
  3051. {
  3052. unsigned int sign : 1;
  3053. unsigned int exponent : 11;
  3054. unsigned int fraction0 : 20;
  3055. unsigned int fraction1 : 32;
  3056. } mNumber;
  3057. #endif
  3058. };
  3059. union FloatShape
  3060. {
  3061. float mValue;
  3062. uint32_t mUint32;
  3063. #if defined(EA_SYSTEM_LITTLE_ENDIAN)
  3064. struct numberStruct
  3065. {
  3066. unsigned int fraction : 23;
  3067. unsigned int exponent : 8;
  3068. unsigned int sign : 1;
  3069. } mNumber;
  3070. #else
  3071. struct numberStruct
  3072. {
  3073. unsigned int sign : 1;
  3074. unsigned int exponent : 8;
  3075. unsigned int fraction : 23;
  3076. } mNumber;
  3077. #endif
  3078. };
  3079. EASTDC_API char* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char* buffer)
  3080. {
  3081. int nDigitCountAfterDecimal;
  3082. double fract;
  3083. double integer;
  3084. double tmp;
  3085. int neg = 0;
  3086. int expcnt = 0;
  3087. char* buf = buffer;
  3088. char* t = buf;
  3089. char* p = buf + kEcvtBufMaxSize - 1;
  3090. char* pbuf = p;
  3091. // We follow the same preconditions as Microsoft does with its _ecvt function.
  3092. EA_ASSERT((nDigitCount >= 0) && (decimalPos != NULL) && (sign != NULL) && (buffer != NULL));
  3093. // assume decimal to left of digits in string
  3094. *decimalPos = 0;
  3095. // To consider: Enable the following.
  3096. //if(nDigitCount > 16) // It turns out that we can't get any more precision than this.
  3097. // nDigitCount = 16; // Any digits beyond 16 would be nearly meaningless.
  3098. if(sizeof(double) == sizeof(float)) // If the user has the compiler set to use doubles that are smaller...
  3099. {
  3100. FloatShape floatShape;
  3101. floatShape.mValue = (float)dValue; // This should be a lossless conversion.
  3102. if(floatShape.mNumber.exponent == 0xff) // If not finite...
  3103. {
  3104. if(floatShape.mUint32 & 0x007fffff) // If is a NAN...
  3105. {
  3106. *t++ = 'N';
  3107. *t++ = 'A';
  3108. *t++ = 'N';
  3109. }
  3110. else
  3111. {
  3112. *t++ = 'I';
  3113. *t++ = 'N';
  3114. *t++ = 'F';
  3115. }
  3116. *t = 0;
  3117. return buffer;
  3118. }
  3119. }
  3120. else
  3121. {
  3122. DoubleShape doubleShape;
  3123. doubleShape.mValue = dValue;
  3124. if(doubleShape.mNumber.exponent == 0x7ff) // If not finite...
  3125. {
  3126. if(isnan(dValue)) // If is a NAN...
  3127. {
  3128. *t++ = 'N';
  3129. *t++ = 'A';
  3130. *t++ = 'N';
  3131. }
  3132. else
  3133. {
  3134. *t++ = 'I';
  3135. *t++ = 'N';
  3136. *t++ = 'F';
  3137. }
  3138. *t = 0;
  3139. return buffer;
  3140. }
  3141. }
  3142. if(dValue < 0)
  3143. {
  3144. neg = 1;
  3145. dValue = -dValue;
  3146. }
  3147. fract = modf(dValue, &integer);
  3148. if(dValue >= 1.0f)
  3149. {
  3150. for(; integer; ++expcnt)
  3151. {
  3152. tmp = modf(integer / 10.0f, &integer);
  3153. *p-- = (char)((int)((tmp + 0.01f) * 10.0f) + '0');
  3154. EA_ASSERT(p >= buffer);
  3155. }
  3156. }
  3157. *t++ = 0; // Extra slot for rounding
  3158. buf += 1; // Point return value to beginning of string.
  3159. int tempExp = expcnt;
  3160. nDigitCountAfterDecimal = nDigitCount - expcnt;
  3161. if(expcnt)
  3162. {
  3163. //if expcnt > nDigitCount, need to round the integer part, and reset expcnt
  3164. if(expcnt > nDigitCount)
  3165. {
  3166. pbuf = p + nDigitCount + 1;
  3167. if(*pbuf >= '5')
  3168. {
  3169. do
  3170. {
  3171. pbuf--;
  3172. if(++*pbuf <= '9')
  3173. break;
  3174. *pbuf = '0';
  3175. }
  3176. while(pbuf >= p+1);
  3177. }
  3178. expcnt = nDigitCount;
  3179. fract = 0.0;//no more rounding will be needed down below!
  3180. }
  3181. for(++p; expcnt--;)
  3182. *t++ = *p++;
  3183. }
  3184. if(nDigitCountAfterDecimal >= 0)
  3185. {
  3186. // Per spec, don't actually put decimal in string, just let caller know where it should be...
  3187. *decimalPos = (int)(ptrdiff_t)(t - buf); // Count of chars into string when to place decimal point
  3188. }
  3189. else
  3190. *decimalPos = (int)tempExp;
  3191. bool leading = dValue < 1.0f ? true : false;//for Ecvt, leading zeros need to be omitted and decimalPos needs to be readjusted
  3192. while((nDigitCountAfterDecimal > 0) && fract)
  3193. {
  3194. fract = modf(fract * 10.0f, &tmp);
  3195. if(leading && (int)tmp == 0)
  3196. {
  3197. (*decimalPos)--;
  3198. continue;
  3199. }
  3200. else
  3201. {
  3202. leading = false;
  3203. *t++ = (char)((int)tmp + '0');
  3204. nDigitCountAfterDecimal -= 1;
  3205. }
  3206. }
  3207. if(fract)
  3208. {
  3209. char* scan = (t - 1);
  3210. // round off the number
  3211. modf(fract * 10.0f, &tmp);
  3212. if(tmp > 4)
  3213. {
  3214. for(; ; --scan)
  3215. {
  3216. if(*scan == '.')
  3217. scan -= 1;
  3218. if(++*scan <= '9')
  3219. break;
  3220. *scan = '0';
  3221. if(scan == buf)
  3222. {
  3223. *--scan = '1';
  3224. buf -= 1; // Rounded into holding spot
  3225. ++*decimalPos; // This line added by Paul Pedriana, May 8 2008, in order to fix a bug where ("%.1f", 0.952) gave "0.1" instead of "1.0". I need to investigate this more to verify the fix.
  3226. break;
  3227. }
  3228. }
  3229. }
  3230. else if(neg)
  3231. {
  3232. // fix ("%.3f", -0.0004) giving -0.000
  3233. for( ; ; scan -= 1)
  3234. {
  3235. if(scan <= buf)
  3236. break;
  3237. if(*scan == '.')
  3238. scan -= 1;
  3239. if(*scan != '0')
  3240. break;
  3241. if(scan == buf)
  3242. neg = 0;
  3243. }
  3244. }
  3245. }
  3246. if(nDigitCountAfterDecimal<0)//this means the digitcount is smaller than integre part and need to round the integer part
  3247. nDigitCountAfterDecimal = 0;
  3248. while(nDigitCountAfterDecimal--)
  3249. *t++ = '0';
  3250. *t++ = 0; // Always terminate the string of digits
  3251. if(*buffer == 0) // If the above rounding place wasn't necessary...
  3252. memmove(buffer, buffer + 1, (size_t)(t - (buffer + 1)));
  3253. *sign = neg ? 1 : 0;
  3254. return buffer;
  3255. }
  3256. EASTDC_API char* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char* buffer)
  3257. {
  3258. double fract;
  3259. double integer;
  3260. double tmp;
  3261. int neg = 0;
  3262. int expcnt = 0;
  3263. char* buf = buffer;
  3264. char* t = buf;
  3265. char* p = buf + kFcvtBufMaxSize - 1;
  3266. // We follow the same preconditions as Microsoft does with its _fcvt function.
  3267. EA_ASSERT((nDigitCountAfterDecimal >= 0) && (decimalPos != NULL) && (sign != NULL) && (buffer != NULL));
  3268. // assume decimal to left of digits in string
  3269. *decimalPos = 0;
  3270. if(sizeof(double) == sizeof(float)) // If the user has the compiler set to use doubles that are smaller...
  3271. {
  3272. FloatShape floatShape;
  3273. floatShape.mValue = (float)dValue; // This should be a lossless conversion.
  3274. if(floatShape.mNumber.exponent == 0xff) // If not finite...
  3275. {
  3276. if(floatShape.mUint32 & 0x007fffff) // If is a NAN...
  3277. {
  3278. *t++ = 'N';
  3279. *t++ = 'A';
  3280. *t++ = 'N';
  3281. }
  3282. else
  3283. {
  3284. *t++ = 'I';
  3285. *t++ = 'N';
  3286. *t++ = 'F';
  3287. }
  3288. *t = 0;
  3289. return buffer;
  3290. }
  3291. }
  3292. else
  3293. {
  3294. DoubleShape doubleShape;
  3295. doubleShape.mValue = dValue;
  3296. if(doubleShape.mNumber.exponent == 0x7ff) // If not finite...
  3297. {
  3298. if(isnan(dValue)) // If is a NAN...
  3299. {
  3300. *t++ = 'N';
  3301. *t++ = 'A';
  3302. *t++ = 'N';
  3303. }
  3304. else
  3305. {
  3306. *t++ = 'I';
  3307. *t++ = 'N';
  3308. *t++ = 'F';
  3309. }
  3310. *t = 0;
  3311. return buffer;
  3312. }
  3313. }
  3314. if(dValue < 0)
  3315. {
  3316. neg = 1;
  3317. dValue = -dValue;
  3318. }
  3319. fract = modf(dValue, &integer);
  3320. if(dValue >= 1.0f)
  3321. {
  3322. for(; integer; ++expcnt)
  3323. {
  3324. tmp = modf(integer / 10.0f, &integer);
  3325. *p-- = (char)((int)((tmp + 0.01f) * 10.0f) + '0');
  3326. EA_ASSERT(p >= buffer);
  3327. }
  3328. }
  3329. *t++ = 0; // Extra slot for rounding
  3330. buf += 1; // Point return value to beginning of string.
  3331. if(expcnt)
  3332. {
  3333. for(++p; expcnt--;)
  3334. *t++ = *p++;
  3335. }
  3336. // Per spec, don't actually put decimal in string, just let caller know where it should be...
  3337. *decimalPos = (int)(ptrdiff_t)(t - buf); // Count of chars into string when to place decimal point.
  3338. // We give up trying to calculate fractions beyond 16 digits, which is the maximum possible precision with a double.
  3339. int count = (nDigitCountAfterDecimal <= 16) ? nDigitCountAfterDecimal : 16;
  3340. while(count && fract)
  3341. {
  3342. fract = modf(fract * 10.0f, &tmp);
  3343. *t++ = (char)((int)tmp + '0');
  3344. nDigitCountAfterDecimal--;
  3345. count--;
  3346. }
  3347. if(fract)
  3348. {
  3349. char* scan = (t - 1);
  3350. // round off the number
  3351. modf(fract * 10.0f, &tmp);
  3352. if(tmp > 4)
  3353. {
  3354. for(; ; --scan)
  3355. {
  3356. if(*scan == '.')
  3357. scan -= 1;
  3358. if(++*scan <= '9')
  3359. break;
  3360. *scan = '0';
  3361. if(scan == buf)
  3362. {
  3363. *--scan = '1';
  3364. buf -= 1; // Rounded into holding spot
  3365. ++*decimalPos; // This line added by Paul Pedriana, May 8 2008, in order to fix a bug where ("%.1f", 0.952) gave "0.1" instead of "1.0". I need to investigate this more to verify the fix.
  3366. break;
  3367. }
  3368. }
  3369. }
  3370. else if(neg)
  3371. {
  3372. // fix ("%.3f", -0.0004) giving -0.000
  3373. for( ; ; --scan)
  3374. {
  3375. if(scan <= buf)
  3376. break;
  3377. if(*scan == '.')
  3378. scan -= 1;
  3379. if(*scan != '0')
  3380. break;
  3381. if(scan == buf)
  3382. neg = 0;
  3383. }
  3384. }
  3385. }
  3386. while(nDigitCountAfterDecimal--)
  3387. *t++ = '0';
  3388. *t++ = 0; // Always terminate the string of digits
  3389. if(*buffer == 0) // If the above rounding place wasn't necessary...
  3390. memmove(buffer, buffer + 1, (size_t)(t - (buffer + 1)));
  3391. *sign = neg ? 1 : 0;
  3392. return buffer;
  3393. }
  3394. // Matching #undef for each #define above for unity build friendliness.
  3395. #if defined(EA_COMPILER_MSVC)
  3396. #undef isnan
  3397. //#undef isinf
  3398. #endif
  3399. #endif // Compiler support
  3400. EASTDC_API char16_t* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char16_t* buffer)
  3401. {
  3402. // We implement this by calling the 8 bit version and copying its data.
  3403. char pBufferCvt8[kEcvtBufMaxSize];
  3404. char16_t* pCurrent16 = buffer;
  3405. EcvtBuf(dValue, nDigitCount, decimalPos, sign, pBufferCvt8);
  3406. for(char* pCurrent8 = pBufferCvt8; *pCurrent8; ) // Do a 8 bit to 16 bit strcpy.
  3407. *pCurrent16++ = (char16_t)(unsigned char)*pCurrent8++;
  3408. *pCurrent16 = 0;
  3409. return buffer;
  3410. }
  3411. EASTDC_API char32_t* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char32_t* buffer)
  3412. {
  3413. // We implement this by calling the 8 bit version and copying its data.
  3414. char pBufferCvt8[kEcvtBufMaxSize];
  3415. char32_t* pCurrent32 = buffer;
  3416. EcvtBuf(dValue, nDigitCount, decimalPos, sign, pBufferCvt8);
  3417. for(char* pCurrent8 = pBufferCvt8; *pCurrent8; ) // Do a 8 bit to 32 bit strcpy.
  3418. *pCurrent32++ = (char32_t)(unsigned char)*pCurrent8++;
  3419. *pCurrent32 = 0;
  3420. return buffer;
  3421. }
  3422. EASTDC_API char16_t* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char16_t* buffer)
  3423. {
  3424. // We implement this by calling the 8 bit version and copying its data.
  3425. char pBufferCvt8[kEcvtBufMaxSize];
  3426. char16_t* pCurrent16 = buffer;
  3427. FcvtBuf(dValue, nDigitCountAfterDecimal, decimalPos, sign, pBufferCvt8);
  3428. for(char* pCurrent8 = pBufferCvt8; *pCurrent8; ) // Do a 8 bit to 16 bit strcpy.
  3429. *pCurrent16++ = (char16_t)(unsigned char)*pCurrent8++;
  3430. *pCurrent16 = 0;
  3431. return buffer;
  3432. }
  3433. EASTDC_API char32_t* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char32_t* buffer)
  3434. {
  3435. // We implement this by calling the 8 bit version and copying its data.
  3436. char pBufferCvt8[kEcvtBufMaxSize];
  3437. char32_t* pCurrent32 = buffer;
  3438. FcvtBuf(dValue, nDigitCountAfterDecimal, decimalPos, sign, pBufferCvt8);
  3439. for(char* pCurrent8 = pBufferCvt8; *pCurrent8; ) // Do a 8 bit to 32 bit strcpy.
  3440. *pCurrent32++ = (char32_t)(unsigned char)*pCurrent8++;
  3441. *pCurrent32 = 0;
  3442. return buffer;
  3443. }
  3444. // end of EcvtBuf / FcvtBuf
  3445. ////////////////////////////////////////////////////////////////////////////////////
  3446. // Optimization technique:
  3447. // https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
  3448. // This results in performance improvements of 2x to 5x depending on the input value. Our general test in
  3449. // TestString.cpp showed a 3.1x performance gain on VC++/x64.
  3450. //
  3451. static uint32_t digits10(uint64_t v)
  3452. {
  3453. if(v < 10)
  3454. return 1;
  3455. if(v < 100)
  3456. return 2;
  3457. if(v < 1000)
  3458. return 3;
  3459. if(v < UINT64_C(1000000000000))
  3460. {
  3461. if(v < UINT64_C(100000000))
  3462. {
  3463. if(v < 1000000)
  3464. {
  3465. if (v < 10000)
  3466. return 4;
  3467. return (uint32_t)(5 + (v >= 100000));
  3468. }
  3469. return (uint32_t)(7 + (v >= 10000000));
  3470. }
  3471. if(v < UINT64_C(10000000000))
  3472. return (uint32_t)(9 + (v >= UINT64_C(1000000000)));
  3473. return (uint32_t)(11 + (v >= UINT64_C(100000000000)));
  3474. }
  3475. return 12 + digits10(v / UINT64_C(1000000000000));
  3476. }
  3477. char* X64toaCommon10(uint64_t nValue, char* pBuffer)
  3478. {
  3479. static const char digits[201] =
  3480. "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849"
  3481. "5051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899";
  3482. uint32_t length = digits10(nValue);
  3483. uint32_t next = length - 1;
  3484. pBuffer[length] = '\0';
  3485. while(nValue >= 100)
  3486. {
  3487. const uint64_t i = (nValue % 100) * 2;
  3488. nValue /= 100;
  3489. pBuffer[next] = digits[i + 1];
  3490. pBuffer[next - 1] = digits[i];
  3491. next -= 2;
  3492. }
  3493. if (nValue < 10)
  3494. pBuffer[next] = (char)('0' + (uint32_t)nValue);
  3495. else
  3496. {
  3497. const uint32_t i = (uint32_t)nValue * 2;
  3498. pBuffer[next] = digits[i + 1];
  3499. pBuffer[next - 1] = digits[i];
  3500. }
  3501. return pBuffer;
  3502. }
  3503. static char* X64toaCommon(uint64_t nValue, char* pBuffer, int nBase, bool bNegative)
  3504. {
  3505. char* pCurrent = pBuffer;
  3506. if(bNegative)
  3507. *pCurrent++ = '-';
  3508. if(nBase == 10)
  3509. X64toaCommon10(nValue, pCurrent);
  3510. else
  3511. {
  3512. char* pFirstDigit = pCurrent;
  3513. do{
  3514. const unsigned nDigit = (unsigned)(nValue % nBase);
  3515. nValue /= nBase;
  3516. if(nDigit > 9)
  3517. *pCurrent++ = (char)(nDigit - 10 + 'a');
  3518. else
  3519. *pCurrent++ = (char)(nDigit + '0');
  3520. } while(nValue > 0);
  3521. // Need to reverse the string.
  3522. *pCurrent-- = 0;
  3523. do{
  3524. const char cTemp = *pCurrent;
  3525. *pCurrent-- = *pFirstDigit;
  3526. *pFirstDigit++ = cTemp;
  3527. }while(pFirstDigit < pCurrent);
  3528. }
  3529. return pBuffer;
  3530. }
  3531. static char16_t* X64toaCommon(uint64_t nValue, char16_t* pBuffer, int nBase, bool bNegative)
  3532. {
  3533. char16_t* pCurrent = pBuffer;
  3534. if(bNegative)
  3535. *pCurrent++ = '-';
  3536. char16_t* pFirstDigit = pCurrent;
  3537. do{
  3538. const unsigned nDigit = (unsigned)(nValue % nBase);
  3539. nValue /= nBase;
  3540. if(nDigit > 9)
  3541. *pCurrent++ = (char16_t)(nDigit - 10 + 'a');
  3542. else
  3543. *pCurrent++ = (char16_t)(nDigit + '0');
  3544. } while(nValue > 0);
  3545. // Need to reverse the string.
  3546. *pCurrent-- = 0;
  3547. do{
  3548. const char16_t cTemp = *pCurrent;
  3549. *pCurrent-- = *pFirstDigit;
  3550. *pFirstDigit++ = cTemp;
  3551. }while(pFirstDigit < pCurrent);
  3552. return pBuffer;
  3553. }
  3554. static char32_t* X64toaCommon(uint64_t nValue, char32_t* pBuffer, int nBase, bool bNegative)
  3555. {
  3556. char32_t* pCurrent = pBuffer;
  3557. if(bNegative)
  3558. *pCurrent++ = '-';
  3559. char32_t* pFirstDigit = pCurrent;
  3560. do{
  3561. const unsigned nDigit = (unsigned)(nValue % nBase);
  3562. nValue /= nBase;
  3563. if(nDigit > 9)
  3564. *pCurrent++ = (char32_t)(nDigit - 10 + 'a');
  3565. else
  3566. *pCurrent++ = (char32_t)(nDigit + '0');
  3567. } while(nValue > 0);
  3568. // Need to reverse the string.
  3569. *pCurrent-- = 0;
  3570. do{
  3571. const char32_t cTemp = *pCurrent;
  3572. *pCurrent-- = *pFirstDigit;
  3573. *pFirstDigit++ = cTemp;
  3574. }while(pFirstDigit < pCurrent);
  3575. return pBuffer;
  3576. }
  3577. EASTDC_API char* I32toa(int32_t nValue, char* pBuffer, int nBase)
  3578. {
  3579. const bool bNegative = (nValue < 0) && (nBase == 10);
  3580. if(bNegative)
  3581. {
  3582. #if defined(__GNUC__) // -INT32_MIN => INT32_MIN, but with GCC on Android it's acting differently.
  3583. if(nValue != INT32_MIN)
  3584. #endif
  3585. nValue = -nValue;
  3586. }
  3587. return X64toaCommon((uint64_t)(uint32_t)nValue, pBuffer, nBase, bNegative);
  3588. }
  3589. EASTDC_API char16_t* I32toa(int32_t nValue, char16_t* pBuffer, int nBase)
  3590. {
  3591. const bool bNegative = (nValue < 0) && (nBase == 10);
  3592. if(bNegative)
  3593. {
  3594. #if defined(__GNUC__) // -INT32_MIN => INT32_MIN, but with GCC on Android it's acting differently.
  3595. if(nValue != INT32_MIN)
  3596. #endif
  3597. nValue = -nValue;
  3598. }
  3599. return X64toaCommon((uint64_t)(uint32_t)nValue, pBuffer, nBase, bNegative);
  3600. }
  3601. EASTDC_API char32_t* I32toa(int32_t nValue, char32_t* pBuffer, int nBase)
  3602. {
  3603. const bool bNegative = (nValue < 0) && (nBase == 10);
  3604. if(bNegative)
  3605. {
  3606. #if defined(__GNUC__) // -INT32_MIN => INT32_MIN, but with GCC on Android it's acting differently.
  3607. if(nValue != INT32_MIN)
  3608. #endif
  3609. nValue = -nValue;
  3610. }
  3611. return X64toaCommon((uint64_t)(uint32_t)nValue, pBuffer, nBase, bNegative);
  3612. }
  3613. EASTDC_API char* U32toa(uint32_t nValue, char* pBuffer, int nBase)
  3614. {
  3615. return X64toaCommon((uint64_t)nValue, pBuffer, nBase, 0);
  3616. }
  3617. EASTDC_API char16_t* U32toa(uint32_t nValue, char16_t* pBuffer, int nBase)
  3618. {
  3619. return X64toaCommon((uint64_t)nValue, pBuffer, nBase, 0);
  3620. }
  3621. EASTDC_API char32_t* U32toa(uint32_t nValue, char32_t* pBuffer, int nBase)
  3622. {
  3623. return X64toaCommon((uint64_t)nValue, pBuffer, nBase, 0);
  3624. }
  3625. EASTDC_API char* I64toa(int64_t nValue, char* pBuffer, int nBase)
  3626. {
  3627. const bool bNegative = (nValue < 0) && (nBase == 10);
  3628. if(bNegative)
  3629. nValue = -(uint64_t)nValue;
  3630. return X64toaCommon((uint64_t)nValue, pBuffer, nBase, bNegative);
  3631. }
  3632. EASTDC_API char16_t* I64toa(int64_t nValue, char16_t* pBuffer, int nBase)
  3633. {
  3634. const bool bNegative = (nValue < 0) && (nBase == 10);
  3635. if(bNegative)
  3636. nValue = -(uint64_t)nValue;
  3637. return X64toaCommon((uint64_t)nValue, pBuffer, nBase, bNegative);
  3638. }
  3639. EASTDC_API char32_t* I64toa(int64_t nValue, char32_t* pBuffer, int nBase)
  3640. {
  3641. const bool bNegative = (nValue < 0) && (nBase == 10);
  3642. if(bNegative)
  3643. nValue = -(uint64_t)nValue;
  3644. return X64toaCommon((uint64_t)nValue, pBuffer, nBase, bNegative);
  3645. }
  3646. EASTDC_API char* U64toa(uint64_t nValue, char* pBuffer, int nBase)
  3647. {
  3648. return X64toaCommon(nValue, pBuffer, nBase, 0);
  3649. }
  3650. EASTDC_API char16_t* U64toa(uint64_t nValue, char16_t* pBuffer, int nBase)
  3651. {
  3652. return X64toaCommon(nValue, pBuffer, nBase, 0);
  3653. }
  3654. EASTDC_API char32_t* U64toa(uint64_t nValue, char32_t* pBuffer, int nBase)
  3655. {
  3656. return X64toaCommon(nValue, pBuffer, nBase, 0);
  3657. }
  3658. EASTDC_API double StrtodEnglish(const char* pValue, char** ppEnd)
  3659. {
  3660. // This implementation is an exact copy of StrtodEnglish but
  3661. // with char in place of char16_t. For the time being, if
  3662. // you do maintenance on either of these functions, you need to
  3663. // copy the result to the other version.
  3664. int c;
  3665. double dTotal(0.0);
  3666. char chSign('+');
  3667. const char* pEnd = pValue;
  3668. while(Isspace(*pValue))
  3669. ++pValue; //Remove leading spaces.
  3670. pEnd = pValue;
  3671. c = *pValue++;
  3672. if(c == '-' || c == '+'){
  3673. chSign = (char)c;
  3674. pEnd = pValue;
  3675. c = *pValue++;
  3676. }
  3677. while((c >= '0') && (c <= '9')){
  3678. dTotal = (10 * dTotal) + (c - '0');
  3679. pEnd = pValue;
  3680. c = *pValue++;
  3681. }
  3682. if(c == '.'){
  3683. double dMultiplier(1); //Possibly some BCD variable would be more accurate.
  3684. pEnd = pValue;
  3685. c = *pValue++;
  3686. while((c >= '0') && (c <= '9')){
  3687. dMultiplier *= 0.1;
  3688. dTotal += (c - '0') * dMultiplier;
  3689. pEnd = pValue;
  3690. c = *pValue++;
  3691. }
  3692. }
  3693. if(c == 'e' || c == 'E'){
  3694. int nExponentValue(0);
  3695. double dExponentTotal;
  3696. char chExponentSign('+');
  3697. pEnd = pValue;
  3698. c = *pValue++; //Move past the exponent.
  3699. if(c == '-' || c == '+'){
  3700. chExponentSign = (char)c;
  3701. pEnd = pValue;
  3702. c = *pValue++; //Move past the '+' or '-' sign.
  3703. }
  3704. while((c >= '0') && (c <= '9')){
  3705. nExponentValue = (10 * nExponentValue) + (c - '0');
  3706. pEnd = pValue;
  3707. c = *pValue++;
  3708. }
  3709. dExponentTotal = ::pow(10.0, (double)nExponentValue); // The CRT pow function is actually somewhat slow and weak.
  3710. // It would be very nice to change this to at least implement
  3711. if(chExponentSign == '-') // the low exponents with a lookup table.
  3712. dExponentTotal = 1/dExponentTotal;
  3713. dTotal *= dExponentTotal;
  3714. }
  3715. if(ppEnd)
  3716. *ppEnd = (char*)pEnd;
  3717. if(chSign == '-')
  3718. return -dTotal;
  3719. return dTotal;
  3720. }
  3721. EASTDC_API double StrtodEnglish(const char16_t* pValue, char16_t** ppEnd)
  3722. {
  3723. // This implementation is an exact copy of StrtodEnglish8 but
  3724. // with char16_t in place of char. For the time being, if you
  3725. // do maintenance on either of these functions, you need to
  3726. // copy the result to the other version.
  3727. char16_t c;
  3728. double dTotal(0.0);
  3729. char16_t chSign('+');
  3730. const char16_t* pEnd = pValue;
  3731. while(Isspace(*pValue))
  3732. ++pValue; // Remove leading spaces.
  3733. pEnd = pValue;
  3734. c = *pValue++;
  3735. if(c == '-' || c == '+'){
  3736. chSign = (char16_t)c;
  3737. pEnd = pValue;
  3738. c = *pValue++;
  3739. }
  3740. while((c >= '0') && (c <= '9')){
  3741. dTotal = (10 * dTotal) + (c - '0');
  3742. pEnd = pValue;
  3743. c = *pValue++;
  3744. }
  3745. if(c == '.'){
  3746. double dMultiplier(1); // Possibly some BCD variable would be more accurate.
  3747. pEnd = pValue;
  3748. c = *pValue++;
  3749. while((c >= '0') && (c <= '9')){
  3750. dMultiplier *= 0.1;
  3751. dTotal += (c - '0') * dMultiplier;
  3752. pEnd = pValue;
  3753. c = *pValue++;
  3754. }
  3755. }
  3756. if(c == 'e' || c == 'E'){
  3757. int nExponentValue(0);
  3758. double dExponentTotal;
  3759. char16_t chExponentSign('+');
  3760. pEnd = pValue;
  3761. c = *pValue++; //Move past the exponent.
  3762. if(c == '-' || c == '+'){
  3763. chExponentSign = (char16_t)c;
  3764. pEnd = pValue;
  3765. c = *pValue++; // Move past the '+' or '-' sign.
  3766. }
  3767. while((c >= '0') && (c <= '9')){
  3768. nExponentValue = (int)((10 * nExponentValue) + (c - '0'));
  3769. pEnd = pValue;
  3770. c = *pValue++;
  3771. }
  3772. dExponentTotal = ::pow(10.0, (double)nExponentValue); // The CRT pow function is actually somewhat slow and weak.
  3773. // It would be very nice to change this to at least implement
  3774. if(chExponentSign == '-') // the low exponents with a lookup table.
  3775. dExponentTotal = 1/dExponentTotal;
  3776. dTotal *= dExponentTotal;
  3777. }
  3778. if(ppEnd)
  3779. *ppEnd = (char16_t*)pEnd;
  3780. if(chSign == '-')
  3781. return -dTotal;
  3782. return dTotal;
  3783. }
  3784. EASTDC_API double StrtodEnglish(const char32_t* pValue, char32_t** ppEnd)
  3785. {
  3786. // This implementation is an exact copy of StrtodEnglish8 but
  3787. // with char32_t in place of char. For the time being, if you
  3788. // do maintenance on either of these functions, you need to
  3789. // copy the result to the other version.
  3790. char32_t c;
  3791. double dTotal(0.0);
  3792. char32_t chSign('+');
  3793. const char32_t* pEnd = pValue;
  3794. while(Isspace(*pValue))
  3795. ++pValue; // Remove leading spaces.
  3796. pEnd = pValue;
  3797. c = *pValue++;
  3798. if(c == '-' || c == '+'){
  3799. chSign = (char32_t)c;
  3800. pEnd = pValue;
  3801. c = *pValue++;
  3802. }
  3803. while((c >= '0') && (c <= '9')){
  3804. dTotal = (10 * dTotal) + (c - '0');
  3805. pEnd = pValue;
  3806. c = *pValue++;
  3807. }
  3808. if(c == '.'){
  3809. double dMultiplier(1); // Possibly some BCD variable would be more accurate.
  3810. pEnd = pValue;
  3811. c = *pValue++;
  3812. while((c >= '0') && (c <= '9')){
  3813. dMultiplier *= 0.1;
  3814. dTotal += (c - '0') * dMultiplier;
  3815. pEnd = pValue;
  3816. c = *pValue++;
  3817. }
  3818. }
  3819. if(c == 'e' || c == 'E'){
  3820. int nExponentValue(0);
  3821. double dExponentTotal;
  3822. char32_t chExponentSign('+');
  3823. pEnd = pValue;
  3824. c = *pValue++; //Move past the exponent.
  3825. if(c == '-' || c == '+'){
  3826. chExponentSign = (char32_t)c;
  3827. pEnd = pValue;
  3828. c = *pValue++; // Move past the '+' or '-' sign.
  3829. }
  3830. while((c >= '0') && (c <= '9')){
  3831. nExponentValue = (int)((10 * nExponentValue) + (c - '0'));
  3832. pEnd = pValue;
  3833. c = *pValue++;
  3834. }
  3835. dExponentTotal = ::pow(10.0, (double)nExponentValue); // The CRT pow function is actually somewhat slow and weak.
  3836. // It would be very nice to change this to at least implement
  3837. if(chExponentSign == '-') // the low exponents with a lookup table.
  3838. dExponentTotal = 1/dExponentTotal;
  3839. dTotal *= dExponentTotal;
  3840. }
  3841. if(ppEnd)
  3842. *ppEnd = (char32_t*)pEnd;
  3843. if(chSign == '-')
  3844. return -dTotal;
  3845. return dTotal;
  3846. }
  3847. static uint64_t StrtoU64Common(const char* pValue, char** ppEnd, int nBase, bool bUnsigned)
  3848. {
  3849. uint64_t nValue(0); // Current value
  3850. const char* p = pValue; // Current position
  3851. char c; // Temp value
  3852. char chSign('+'); // One of either '+' or '-'
  3853. bool bDigitWasRead(false); // True if any digits were read.
  3854. bool bOverflowOccurred(false); // True if integer overflow occurred.
  3855. // Skip leading whitespace
  3856. c = *p++;
  3857. while(Isspace(c))
  3858. c = *p++;
  3859. // Check for sign.
  3860. if((c == '-') || (c == '+')){
  3861. chSign = c;
  3862. c = *p++;
  3863. }
  3864. // Do checks on nBase.
  3865. if((nBase < 0) || (nBase == 1) || (nBase > 36)){
  3866. if(ppEnd)
  3867. *ppEnd = (char*)pValue;
  3868. return 0;
  3869. }
  3870. else if(nBase == 0){
  3871. // Auto detect one of base 8, 10, or 16.
  3872. if(c != '0')
  3873. nBase = 10;
  3874. else if(*p == 'x' || *p == 'X')
  3875. nBase = 16;
  3876. else
  3877. nBase = 8;
  3878. }
  3879. if(nBase == 16){
  3880. // If there is a leading '0x', then skip past it.
  3881. if((c == '0') && ((*p == 'x') || (*p == 'X'))) {
  3882. ++p;
  3883. c = *p++;
  3884. }
  3885. }
  3886. // If nValue exceeds this, an integer overflow is reported.
  3887. #if (EA_PLATFORM_WORD_SIZE >= 8)
  3888. const uint64_t nMaxValue(UINT64_MAX / nBase);
  3889. const uint64_t nModValue(UINT64_MAX % nBase);
  3890. #else
  3891. // 32 bit platforms are very slow at doing 64 bit div and mod operations.
  3892. uint64_t nMaxValue;
  3893. uint64_t nModValue;
  3894. switch(nBase)
  3895. {
  3896. case 2:
  3897. nMaxValue = UINT64_C(9223372036854775807);
  3898. nModValue = 1;
  3899. break;
  3900. case 8:
  3901. nMaxValue = UINT64_C(2305843009213693951);
  3902. nModValue = 7;
  3903. break;
  3904. case 10:
  3905. nMaxValue = UINT64_C(1844674407370955161);
  3906. nModValue = 5;
  3907. break;
  3908. case 16:
  3909. nMaxValue = UINT64_C(1152921504606846975);
  3910. nModValue = 15;
  3911. break;
  3912. default:
  3913. nMaxValue = (UINT64_MAX / nBase);
  3914. nModValue = (UINT64_MAX % nBase);
  3915. break;
  3916. }
  3917. #endif
  3918. for(unsigned nCurrentDigit; ; ){
  3919. if(Isdigit(c))
  3920. nCurrentDigit = (unsigned)(c - '0');
  3921. else if(Isalpha(c))
  3922. nCurrentDigit = (unsigned)(Toupper(c) - 'A' + 10);
  3923. else
  3924. break; // The digit is invalid.
  3925. if(nCurrentDigit >= (unsigned)nBase)
  3926. break; // The digit is invalid.
  3927. bDigitWasRead = true;
  3928. // Check for overflow.
  3929. if((nValue < nMaxValue) || ((nValue == nMaxValue) && ((uint64_t)nCurrentDigit <= nModValue)))
  3930. nValue = (nValue * nBase) + nCurrentDigit;
  3931. else
  3932. bOverflowOccurred = true; // Set the flag, but continue processing.
  3933. c = *p++;
  3934. }
  3935. --p; // Go back to the last character
  3936. if(!bDigitWasRead){
  3937. if(ppEnd)
  3938. p = pValue; // We'll assign 'ppEnd' below.
  3939. }
  3940. else if(bOverflowOccurred || (!bUnsigned && (((chSign == '-') && (nValue > ((uint64_t)INT64_MAX + 1))) || ((chSign == '+') && (nValue > (uint64_t)INT64_MAX))))){
  3941. // Integer overflow occurred.
  3942. if(bUnsigned)
  3943. nValue = UINT64_MAX;
  3944. else if(chSign == '-')
  3945. nValue = (uint64_t)INT64_MAX + 1; // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
  3946. else
  3947. nValue = INT64_MAX;
  3948. errno = ERANGE; // The standard specifies that we set this value.
  3949. }
  3950. if(ppEnd)
  3951. *ppEnd = (char*)p;
  3952. if(chSign == '-')
  3953. nValue = -nValue;
  3954. return nValue;
  3955. }
  3956. static uint64_t StrtoU64Common(const char16_t* pValue, char16_t** ppEnd, int nBase, bool bUnsigned)
  3957. {
  3958. uint64_t nValue(0); // Current value
  3959. const char16_t* p = pValue; // Current position
  3960. char16_t c; // Temp value
  3961. char16_t chSign('+'); // One of either '+' or '-'
  3962. bool bDigitWasRead(false); // True if any digits were read.
  3963. bool bOverflowOccurred(false); // True if integer overflow occurred.
  3964. // Skip leading whitespace
  3965. c = *p++;
  3966. while(Isspace(c))
  3967. c = *p++;
  3968. // Check for sign.
  3969. if((c == '-') || (c == '+')){
  3970. chSign = c;
  3971. c = *p++;
  3972. }
  3973. // Do checks on nBase.
  3974. if((nBase < 0) || (nBase == 1) || (nBase > 36)){
  3975. if(ppEnd)
  3976. *ppEnd = (char16_t*)pValue;
  3977. return 0;
  3978. }
  3979. else if(nBase == 0){
  3980. // Auto detect one of base 8, 10, or 16.
  3981. if(c != '0')
  3982. nBase = 10;
  3983. else if(*p == 'x' || *p == 'X')
  3984. nBase = 16;
  3985. else
  3986. nBase = 8;
  3987. }
  3988. if(nBase == 16){
  3989. // If there is a leading '0x', then skip past it.
  3990. if((c == '0') && ((*p == 'x') || (*p == 'X'))) {
  3991. ++p;
  3992. c = *p++;
  3993. }
  3994. }
  3995. // If nValue exceeds this, an integer overflow is reported.
  3996. #if (EA_PLATFORM_WORD_SIZE >= 8)
  3997. const uint64_t nMaxValue(UINT64_MAX / nBase);
  3998. const uint64_t nModValue(UINT64_MAX % nBase);
  3999. #else
  4000. // 32 bit platforms are very slow at doing 64 bit div and mod operations.
  4001. uint64_t nMaxValue;
  4002. uint64_t nModValue;
  4003. switch(nBase)
  4004. {
  4005. case 2:
  4006. nMaxValue = UINT64_C(9223372036854775807);
  4007. nModValue = 1;
  4008. break;
  4009. case 8:
  4010. nMaxValue = UINT64_C(2305843009213693951);
  4011. nModValue = 7;
  4012. break;
  4013. case 10:
  4014. nMaxValue = UINT64_C(1844674407370955161);
  4015. nModValue = 5;
  4016. break;
  4017. case 16:
  4018. nMaxValue = UINT64_C(1152921504606846975);
  4019. nModValue = 15;
  4020. break;
  4021. default:
  4022. nMaxValue = (UINT64_MAX / nBase);
  4023. nModValue = (UINT64_MAX % nBase);
  4024. break;
  4025. }
  4026. #endif
  4027. for(unsigned nCurrentDigit; ;){
  4028. if(Isdigit(c))
  4029. nCurrentDigit = (unsigned)(c - '0');
  4030. else if(Isalpha(c))
  4031. nCurrentDigit = (unsigned)(Toupper(c) - 'A' + 10);
  4032. else
  4033. break; // The digit is invalid.
  4034. if(nCurrentDigit >= (unsigned)nBase)
  4035. break; // The digit is invalid.
  4036. bDigitWasRead = true;
  4037. // Check for overflow.
  4038. if((nValue < nMaxValue) || ((nValue == nMaxValue) && ((uint64_t)nCurrentDigit <= nModValue)))
  4039. nValue = (nValue * nBase) + nCurrentDigit;
  4040. else
  4041. bOverflowOccurred = true; // Set the flag, but continue processing.
  4042. c = *p++;
  4043. }
  4044. --p; // Go back to the last character
  4045. if(!bDigitWasRead){
  4046. if(ppEnd)
  4047. p = pValue; // We'll assign 'ppEnd' below.
  4048. } // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
  4049. else if(bOverflowOccurred || (!bUnsigned && (((chSign == '-') && (nValue > ((uint64_t)INT64_MAX + 1))) || ((chSign == '+') && (nValue > (uint64_t)INT64_MAX))))){
  4050. // Integer overflow occurred.
  4051. if(bUnsigned)
  4052. nValue = UINT64_MAX;
  4053. else if(chSign == '-')
  4054. nValue = (uint64_t)INT64_MAX + 1; // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
  4055. else
  4056. nValue = INT64_MAX;
  4057. if(EA::StdC::GetAssertionsEnabled())
  4058. { EA_FAIL_MSG("StrtoU64Common: Range underflow or overflow.");}
  4059. errno = ERANGE; // The standard specifies that we set this value.
  4060. }
  4061. if(ppEnd)
  4062. *ppEnd = (char16_t*)p;
  4063. if(chSign == '-')
  4064. nValue = -nValue;
  4065. return nValue;
  4066. }
  4067. static uint64_t StrtoU64Common(const char32_t* pValue, char32_t** ppEnd, int nBase, bool bUnsigned)
  4068. {
  4069. uint64_t nValue(0); // Current value
  4070. const char32_t* p = pValue; // Current position
  4071. char32_t c; // Temp value
  4072. char32_t chSign('+'); // One of either '+' or '-'
  4073. bool bDigitWasRead(false); // True if any digits were read.
  4074. bool bOverflowOccurred(false); // True if integer overflow occurred.
  4075. // Skip leading whitespace
  4076. c = *p++;
  4077. while(Isspace(c))
  4078. c = *p++;
  4079. // Check for sign.
  4080. if((c == '-') || (c == '+')){
  4081. chSign = c;
  4082. c = *p++;
  4083. }
  4084. // Do checks on nBase.
  4085. if((nBase < 0) || (nBase == 1) || (nBase > 36)){
  4086. if(ppEnd)
  4087. *ppEnd = (char32_t*)pValue;
  4088. return 0;
  4089. }
  4090. else if(nBase == 0){
  4091. // Auto detect one of base 8, 10, or 32.
  4092. if(c != '0')
  4093. nBase = 10;
  4094. else if(*p == 'x' || *p == 'X')
  4095. nBase = 32;
  4096. else
  4097. nBase = 8;
  4098. }
  4099. if(nBase == 16){
  4100. // If there is a leading '0x', then skip past it.
  4101. if((c == '0') && ((*p == 'x') || (*p == 'X'))) {
  4102. ++p;
  4103. c = *p++;
  4104. }
  4105. }
  4106. // If nValue exceeds this, an integer overflow is reported.
  4107. #if (EA_PLATFORM_WORD_SIZE >= 8)
  4108. const uint64_t nMaxValue(UINT64_MAX / nBase);
  4109. const uint64_t nModValue(UINT64_MAX % nBase);
  4110. #else
  4111. // 32 bit platforms are very slow at doing 64 bit div and mod operations.
  4112. uint64_t nMaxValue;
  4113. uint64_t nModValue;
  4114. switch(nBase)
  4115. {
  4116. case 2:
  4117. nMaxValue = UINT64_C(9223372036854775807);
  4118. nModValue = 1;
  4119. break;
  4120. case 8:
  4121. nMaxValue = UINT64_C(2305843009213693951);
  4122. nModValue = 7;
  4123. break;
  4124. case 10:
  4125. nMaxValue = UINT64_C(1844674407370955161);
  4126. nModValue = 5;
  4127. break;
  4128. case 16:
  4129. nMaxValue = UINT64_C(1152921504606846975);
  4130. nModValue = 15;
  4131. break;
  4132. default:
  4133. nMaxValue = (UINT64_MAX / nBase);
  4134. nModValue = (UINT64_MAX % nBase);
  4135. break;
  4136. }
  4137. #endif
  4138. for(unsigned nCurrentDigit; ;){
  4139. if(Isdigit(c))
  4140. nCurrentDigit = (unsigned)(c - '0');
  4141. else if(Isalpha(c))
  4142. nCurrentDigit = (unsigned)(Toupper(c) - 'A' + 10);
  4143. else
  4144. break; // The digit is invalid.
  4145. if(nCurrentDigit >= (unsigned)nBase)
  4146. break; // The digit is invalid.
  4147. bDigitWasRead = true;
  4148. // Check for overflow.
  4149. if((nValue < nMaxValue) || ((nValue == nMaxValue) && ((uint64_t)nCurrentDigit <= nModValue)))
  4150. nValue = (nValue * nBase) + nCurrentDigit;
  4151. else
  4152. bOverflowOccurred = true; // Set the flag, but continue processing.
  4153. c = *p++;
  4154. }
  4155. --p; // Go back to the last character
  4156. if(!bDigitWasRead){
  4157. if(ppEnd)
  4158. p = pValue; // We'll assign 'ppEnd' below.
  4159. } // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
  4160. else if(bOverflowOccurred || (!bUnsigned && (((chSign == '-') && (nValue > ((uint64_t)INT64_MAX + 1))) || ((chSign == '+') && (nValue > (uint64_t)INT64_MAX))))){
  4161. // Integer overflow occurred.
  4162. if(bUnsigned)
  4163. nValue = UINT64_MAX;
  4164. else if(chSign == '-')
  4165. nValue = (uint64_t)INT64_MAX + 1; // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
  4166. else
  4167. nValue = INT64_MAX;
  4168. if(EA::StdC::GetAssertionsEnabled())
  4169. { EA_FAIL_MSG("StrtoU64Common: Range underflow or overflow.");}
  4170. errno = ERANGE; // The standard specifies that we set this value.
  4171. }
  4172. if(ppEnd)
  4173. *ppEnd = (char32_t*)p;
  4174. if(chSign == '-')
  4175. nValue = -nValue;
  4176. return nValue;
  4177. }
  4178. EASTDC_API int32_t StrtoI32(const char* pValue, char** ppEnd, int nBase)
  4179. {
  4180. int64_t val = (int64_t) StrtoU64Common(pValue, ppEnd, nBase, false);
  4181. if(val < INT32_MIN)
  4182. {
  4183. if(EA::StdC::GetAssertionsEnabled())
  4184. { EA_FAIL_MSG("StrtoI32: Range underflow. You may need to use StrtoI64 instead."); }
  4185. errno = ERANGE;
  4186. return (int32_t)INT32_MIN;
  4187. }
  4188. if(val > INT32_MAX)
  4189. {
  4190. if(EA::StdC::GetAssertionsEnabled())
  4191. { EA_FAIL_MSG("StrtoI32: Range overflow. You may need to use StrtoU32 or StrtoU64 instead."); }
  4192. errno = ERANGE;
  4193. return INT32_MAX;
  4194. }
  4195. return (int32_t) val;
  4196. }
  4197. EASTDC_API int32_t StrtoI32(const char16_t* pValue, char16_t** ppEnd, int nBase)
  4198. {
  4199. int64_t val = (int64_t) StrtoU64Common(pValue, ppEnd, nBase, false);
  4200. if(val < INT32_MIN)
  4201. {
  4202. if(EA::StdC::GetAssertionsEnabled())
  4203. { EA_FAIL_MSG("StrtoI32: Range underflow. You may need to use StrtoI64 instead."); }
  4204. errno = ERANGE;
  4205. return (int32_t)INT32_MIN;
  4206. }
  4207. if(val > INT32_MAX)
  4208. {
  4209. if(EA::StdC::GetAssertionsEnabled())
  4210. { EA_FAIL_MSG("StrtoI32: Range overflow. You may need to use StrtoU32 or StrtoU64 instead."); }
  4211. errno = ERANGE;
  4212. return INT32_MAX;
  4213. }
  4214. return (int32_t) val;
  4215. }
  4216. EASTDC_API int32_t StrtoI32(const char32_t* pValue, char32_t** ppEnd, int nBase)
  4217. {
  4218. int64_t val = (int64_t) StrtoU64Common(pValue, ppEnd, nBase, false);
  4219. if(val < INT32_MIN)
  4220. {
  4221. if(EA::StdC::GetAssertionsEnabled())
  4222. { EA_FAIL_MSG("StrtoI32: Range underflow. You may need to use StrtoI64 instead."); }
  4223. errno = ERANGE;
  4224. return (int32_t)INT32_MIN;
  4225. }
  4226. if(val > INT32_MAX)
  4227. {
  4228. if(EA::StdC::GetAssertionsEnabled())
  4229. { EA_FAIL_MSG("StrtoI32: Range overflow. You may need to use StrtoU32 or StrtoU64 instead."); }
  4230. errno = ERANGE;
  4231. return INT32_MAX;
  4232. }
  4233. return (int32_t) val;
  4234. }
  4235. EASTDC_API uint32_t StrtoU32(const char* pValue, char** ppEnd, int nBase)
  4236. {
  4237. uint64_t val = StrtoU64Common(pValue, ppEnd, nBase, true);
  4238. if(val > UINT32_MAX)
  4239. {
  4240. if(EA::StdC::GetAssertionsEnabled())
  4241. { EA_FAIL_MSG("StrtoU32: Range overflow. You may need to use StrtoU64 instead."); }
  4242. errno = ERANGE;
  4243. return UINT32_MAX;
  4244. }
  4245. return (uint32_t)val;
  4246. }
  4247. EASTDC_API uint32_t StrtoU32(const char16_t* pValue, char16_t** ppEnd, int nBase)
  4248. {
  4249. uint64_t val = StrtoU64Common(pValue, ppEnd, nBase, true);
  4250. if(val > UINT32_MAX)
  4251. {
  4252. if(EA::StdC::GetAssertionsEnabled())
  4253. { EA_FAIL_MSG("StrtoU32: Range overflow. You may need to use StrtoU64 instead."); }
  4254. errno = ERANGE;
  4255. return UINT32_MAX;
  4256. }
  4257. return (uint32_t)val;
  4258. }
  4259. EASTDC_API uint32_t StrtoU32(const char32_t* pValue, char32_t** ppEnd, int nBase)
  4260. {
  4261. uint64_t val = StrtoU64Common(pValue, ppEnd, nBase, true);
  4262. if(val > UINT32_MAX)
  4263. {
  4264. if(EA::StdC::GetAssertionsEnabled())
  4265. { EA_FAIL_MSG("StrtoU32: Range overflow. You may need to use StrtoU64 instead."); }
  4266. errno = ERANGE;
  4267. return UINT32_MAX;
  4268. }
  4269. return (uint32_t)val;
  4270. }
  4271. EASTDC_API int64_t StrtoI64(const char* pString, char** ppStringEnd, int nBase)
  4272. {
  4273. return (int64_t)StrtoU64Common(pString, ppStringEnd, nBase, false);
  4274. }
  4275. EASTDC_API int64_t StrtoI64(const char16_t* pString, char16_t** ppStringEnd, int nBase)
  4276. {
  4277. return (int64_t)StrtoU64Common(pString, ppStringEnd, nBase, false);
  4278. }
  4279. EASTDC_API int64_t StrtoI64(const char32_t* pString, char32_t** ppStringEnd, int nBase)
  4280. {
  4281. return (int64_t)StrtoU64Common(pString, ppStringEnd, nBase, false);
  4282. }
  4283. EASTDC_API uint64_t StrtoU64(const char* pString, char** ppStringEnd, int nBase)
  4284. {
  4285. return StrtoU64Common(pString, ppStringEnd, nBase, true);
  4286. }
  4287. EASTDC_API uint64_t StrtoU64(const char16_t* pString, char16_t** ppStringEnd, int nBase)
  4288. {
  4289. return StrtoU64Common(pString, ppStringEnd, nBase, true);
  4290. }
  4291. EASTDC_API uint64_t StrtoU64(const char32_t* pString, char32_t** ppStringEnd, int nBase)
  4292. {
  4293. return StrtoU64Common(pString, ppStringEnd, nBase, true);
  4294. }
  4295. EASTDC_API char* FtoaEnglish(double dValue, char* pResult, int nResultCapacity, int nPrecision, bool bExponentEnabled)
  4296. {
  4297. // Note that this function is a duplicate of FtoaEnglish16 but
  4298. // with char instead of char16_t. Modifications to either of
  4299. // these functions should be replicated to the other.
  4300. int nDecimalPosition, nSign;
  4301. int nPositionResult(0);
  4302. int nPositionTemp(0);
  4303. int i;
  4304. int nExponent;
  4305. if(nResultCapacity <= 0)
  4306. return NULL;
  4307. if(bExponentEnabled){
  4308. if(dValue == 0.0)
  4309. nExponent = 0;
  4310. else
  4311. {
  4312. const double dValueAbs = fabs(dValue);
  4313. const double dValueLog = ::log10(dValueAbs);
  4314. nExponent = (int)::floor(dValueLog);
  4315. }
  4316. if((nExponent >= nPrecision) || (nExponent < -4)){ // printf's %g switches to exponential whenever exp >= precision || exp < -4.
  4317. // Compute how many digits we need for the exponent.
  4318. int nDigits = 1;
  4319. int nLimit = 10;
  4320. while(nLimit <= nExponent){
  4321. nLimit *= 10;
  4322. ++nDigits;
  4323. }
  4324. const double dExpPow = ::pow(10.0, (double)-nExponent);
  4325. if(FtoaEnglish(dValue * dExpPow, pResult, nResultCapacity - nDigits - 2, nPrecision, false)){
  4326. char* p = pResult + Strlen(pResult);
  4327. *p++ = (char)'e';
  4328. *p++ = ((nExponent < 0) ? (char)'-' : (char)'+');
  4329. I32toa(abs(nExponent), p, 10);
  4330. return pResult;
  4331. }
  4332. return NULL;
  4333. }
  4334. }
  4335. // fcvt is a function that converts a floating point value to its component
  4336. // string, sign, and decimal position. It doesn't convert it to a fully
  4337. // finished string because sign and decimal usage usually varies between
  4338. // locales and this function is trying to be locale-independent. It is up
  4339. // to the user of this function to present the final data in a form that
  4340. // is locale-savvy. Actually, not all compilers implement fcvt.
  4341. #if EASTDC_NATIVE_FCVT
  4342. #ifdef __GNUC__ // nPrecision refers to the number of digits after the decimal point.
  4343. const char* const pResultTemp = fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
  4344. #else
  4345. char pResultTemp[_CVTBUFSIZE+1];
  4346. _fcvt_s(pResultTemp, sizeof(pResultTemp), dValue, nPrecision, &nDecimalPosition, &nSign);
  4347. #endif
  4348. #else
  4349. char bufferTemp[kFcvtBufMaxSize];
  4350. const char* const pResultTemp = FcvtBuf(dValue, nPrecision, &nDecimalPosition, &nSign, bufferTemp);
  4351. #endif
  4352. // If the value is negative, then add a leading '-' sign.
  4353. if(nSign){
  4354. if(nPositionResult >= nResultCapacity){
  4355. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4356. return NULL;
  4357. }
  4358. pResult[nPositionResult] = '-';
  4359. nPositionResult++;
  4360. }
  4361. // If the value is < 1, then add a leading '0' digit.
  4362. if(fabs(dValue) < 1.0){
  4363. #if EASTDC_NATIVE_FCVT && defined(__GNUC__)
  4364. // GCC's fcvt has a quirk: If the input dValue is 0 (but no other value, fractional or not),
  4365. // it yields an output string with a leading "0." So we need to make a special case to
  4366. // detect this here.
  4367. if(dValue != 0.0)
  4368. #endif
  4369. {
  4370. if(nPositionResult >= nResultCapacity){
  4371. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4372. return NULL;
  4373. }
  4374. pResult[nPositionResult++] = '0';
  4375. }
  4376. }
  4377. // Read digits up to the decimal position and write them to the output string.
  4378. if(nDecimalPosition > 0){ // If the input was something like 1000.0
  4379. for(i = 0; (i < nDecimalPosition) && pResultTemp[nPositionTemp]; i++){
  4380. if(nPositionResult >= nResultCapacity){
  4381. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4382. return NULL;
  4383. }
  4384. pResult[nPositionResult++] = pResultTemp[nPositionTemp++];
  4385. }
  4386. }
  4387. if(pResultTemp[nPositionTemp]){
  4388. // Find the last of the zeroes in the pResultTemp string. We don't want
  4389. // to add unnecessary trailing zeroes to the returned string and don't
  4390. // want to return a decimal point in the string if it isn't necessary.
  4391. int nFirstTrailingZeroPosition(nPositionTemp);
  4392. int nLastPositionTemp(nPositionTemp);
  4393. while(pResultTemp[nLastPositionTemp]){
  4394. if(pResultTemp[nLastPositionTemp] != '0')
  4395. nFirstTrailingZeroPosition = nLastPositionTemp + 1;
  4396. nLastPositionTemp++;
  4397. }
  4398. // If there is any reason to write a decimal point, then we write
  4399. // it and write the data that comes after it.
  4400. if((nFirstTrailingZeroPosition > nPositionTemp) && (nPrecision > 0)){
  4401. // Add a decimal point.
  4402. if(nPositionResult >= nResultCapacity){
  4403. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4404. return NULL;
  4405. }
  4406. pResult[nPositionResult++] = '.';
  4407. if(nDecimalPosition < 0){ // If there are zeroes after the decimal...
  4408. for(i = nDecimalPosition; i < 0; i++){
  4409. if(nPositionResult >= nResultCapacity){
  4410. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4411. return NULL;
  4412. }
  4413. pResult[nPositionResult++] = '0';
  4414. --nPrecision;
  4415. }
  4416. }
  4417. // Read digits after the decimal position and write them to the output string.
  4418. for(i = 0; (i < nPrecision) && (nPositionTemp < nFirstTrailingZeroPosition) && pResultTemp[nPositionTemp]; i++){
  4419. if(nPositionResult >= nResultCapacity){
  4420. //What we do here is possibly erase trailing zeroes that we've written after the decimal.
  4421. int nEndPosition = EASTDC_MAX(nPositionResult - 1, 0);
  4422. pResult[nEndPosition] = 0;
  4423. while((--nEndPosition > 0) && (pResult[nEndPosition] == '0'))
  4424. pResult[nEndPosition] = 0;
  4425. return NULL;
  4426. }
  4427. pResult[nPositionResult++] = pResultTemp[nPositionTemp++];
  4428. }
  4429. }
  4430. }
  4431. // Write the final terminating zero.
  4432. if(nPositionResult >= nResultCapacity){
  4433. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4434. return NULL;
  4435. }
  4436. pResult[nPositionResult] = 0;
  4437. return pResult;
  4438. }
  4439. EASTDC_API char16_t* FtoaEnglish(double dValue, char16_t* pResult, int nResultCapacity, int nPrecision, bool bExponentEnabled)
  4440. {
  4441. // Note that this function is a duplicate of FtoaEnglish8 but
  4442. // with char16_t instead of char. Modifications to either of
  4443. // these functions should be replicated to the other.
  4444. int nDecimalPosition, nSign;
  4445. int nPositionResult(0);
  4446. int nPositionTemp(0);
  4447. int i;
  4448. int nExponent;
  4449. if(nResultCapacity <= 0)
  4450. return NULL;
  4451. if(bExponentEnabled){
  4452. if(dValue == 0.0)
  4453. nExponent = 0;
  4454. else
  4455. {
  4456. const double dValueAbs = fabs(dValue);
  4457. const double dValueLog = ::log10(dValueAbs);
  4458. nExponent = (int)::floor(dValueLog);
  4459. }
  4460. if((nExponent >= nPrecision) || (nExponent < -4)){ // printf's %g switches to exponential whenever exp >= mnPrecisionUsed || exp < -4.
  4461. // Compute how many digits we need for the exponent.
  4462. int nDigits = 1;
  4463. int nLimit = 10;
  4464. while(nLimit <= nExponent){
  4465. nLimit *= 10;
  4466. ++nDigits;
  4467. }
  4468. const double dExpPow = ::pow(10.0, (double)-nExponent);
  4469. if(FtoaEnglish(dValue * dExpPow, pResult, nResultCapacity - nDigits - 2, nPrecision, false)){
  4470. char16_t* p = pResult + Strlen(pResult);
  4471. *p++ = (char16_t)'e';
  4472. *p++ = ((nExponent < 0) ? (char16_t)'-' : (char16_t)'+');
  4473. I32toa(abs(nExponent), p, 10);
  4474. return pResult;
  4475. }
  4476. return NULL;
  4477. }
  4478. }
  4479. // fcvt is a function that converts a floating point value to its component
  4480. // string, sign, and decimal position. It doesn't convert it to a fully
  4481. // finished string because sign and decimal usage usually varies between
  4482. // locales and this function is trying to be locale-independent. It is up
  4483. // to the user of this function to present the final data in a form that
  4484. // is locale-savvy. Actually, not all compilers implement fcvt.
  4485. #if EASTDC_NATIVE_FCVT
  4486. #ifdef __GNUC__
  4487. const char* const pResultTemp = fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
  4488. #else
  4489. const char* const pResultTemp = _fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
  4490. #endif
  4491. #else
  4492. char bufferTemp[kFcvtBufMaxSize];
  4493. const char* const pResultTemp = FcvtBuf(dValue, nPrecision, &nDecimalPosition, &nSign, bufferTemp);
  4494. #endif
  4495. // If the value is negative, then add a leading '-' sign.
  4496. if(nSign){
  4497. if(nPositionResult >= nResultCapacity){
  4498. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4499. return NULL;
  4500. }
  4501. pResult[nPositionResult] = '-';
  4502. nPositionResult++;
  4503. }
  4504. // If the value is < 1, then add a leading '0' digit.
  4505. if(fabs(dValue) < 1.0){
  4506. #if EASTDC_NATIVE_FCVT && defined(__GNUC__)
  4507. // GCC's fcvt has a quirk: If the input dValue is 0 (but no other value, fractional or not),
  4508. // it yields an output string with a leading "0." So we need to make a special case to
  4509. // detect this here.
  4510. if(dValue != 0.0)
  4511. #endif
  4512. {
  4513. if(nPositionResult >= nResultCapacity){
  4514. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4515. return NULL;
  4516. }
  4517. pResult[nPositionResult++] = '0';
  4518. }
  4519. }
  4520. // Read digits up to the decimal position and write them to the output string.
  4521. if(nDecimalPosition > 0){ // If the input was something like 1000.0
  4522. for(i = 0; (i < nDecimalPosition) && pResultTemp[nPositionTemp]; i++){
  4523. if(nPositionResult >= nResultCapacity){
  4524. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4525. return NULL;
  4526. }
  4527. pResult[nPositionResult++] = (char16_t)pResultTemp[nPositionTemp++];
  4528. }
  4529. }
  4530. if(pResultTemp[nPositionTemp]){
  4531. // Find the last of the zeroes in the pResultTemp string. We don't want
  4532. // to add unnecessary trailing zeroes to the returned string and don't
  4533. // want to return a decimal point in the string if it isn't necessary.
  4534. int nFirstTrailingZeroPosition(nPositionTemp);
  4535. int nLastPositionTemp(nPositionTemp);
  4536. while(pResultTemp[nLastPositionTemp]){
  4537. if(pResultTemp[nLastPositionTemp] != '0')
  4538. nFirstTrailingZeroPosition = nLastPositionTemp + 1;
  4539. nLastPositionTemp++;
  4540. }
  4541. // If there is any reason to write a decimal point, then we write
  4542. // it and write the data that comes after it.
  4543. if((nFirstTrailingZeroPosition > nPositionTemp) && (nPrecision > 0)){
  4544. // Add a decimal point.
  4545. if(nPositionResult >= nResultCapacity){
  4546. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4547. return NULL;
  4548. }
  4549. pResult[nPositionResult++] = '.';
  4550. if(nDecimalPosition < 0){ // If there are zeroes after the decimal...
  4551. for(i = nDecimalPosition; i < 0; i++){
  4552. if(nPositionResult >= nResultCapacity){
  4553. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4554. return NULL;
  4555. }
  4556. pResult[nPositionResult++] = '0';
  4557. --nPrecision;
  4558. }
  4559. }
  4560. // Read digits after the decimal position and write them to the output string.
  4561. for(i = 0; (i < nPrecision) && (nPositionTemp < nFirstTrailingZeroPosition) && pResultTemp[nPositionTemp]; i++){
  4562. if(nPositionResult >= nResultCapacity){
  4563. //What we do here is possibly erase trailing zeroes that we've written after the decimal.
  4564. int nEndPosition = EASTDC_MAX(nPositionResult - 1, 0);
  4565. pResult[nEndPosition] = 0;
  4566. while((--nEndPosition > 0) && (pResult[nEndPosition] == '0'))
  4567. pResult[nEndPosition] = 0;
  4568. return NULL;
  4569. }
  4570. pResult[nPositionResult++] = (char16_t)pResultTemp[nPositionTemp++];
  4571. }
  4572. }
  4573. }
  4574. // Write the final terminating zero.
  4575. if(nPositionResult >= nResultCapacity){
  4576. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4577. return NULL;
  4578. }
  4579. pResult[nPositionResult] = 0;
  4580. return pResult;
  4581. }
  4582. EASTDC_API char32_t* FtoaEnglish(double dValue, char32_t* pResult, int nResultCapacity, int nPrecision, bool bExponentEnabled)
  4583. {
  4584. // Note that this function is a duplicate of FtoaEnglish8 but
  4585. // with char32_t instead of char. Modifications to either of
  4586. // these functions should be replicated to the other.
  4587. int nDecimalPosition, nSign;
  4588. int nPositionResult(0);
  4589. int nPositionTemp(0);
  4590. int i;
  4591. int nExponent;
  4592. if(nResultCapacity <= 0)
  4593. return NULL;
  4594. if(bExponentEnabled){
  4595. if(dValue == 0.0)
  4596. nExponent = 0;
  4597. else
  4598. {
  4599. const double dValueAbs = fabs(dValue);
  4600. const double dValueLog = ::log10(dValueAbs);
  4601. nExponent = (int)::floor(dValueLog);
  4602. }
  4603. if((nExponent >= nPrecision) || (nExponent < -4)){ // printf's %g switches to exponential whenever exp >= mnPrecisionUsed || exp < -4.
  4604. // Compute how many digits we need for the exponent.
  4605. int nDigits = 1;
  4606. int nLimit = 10;
  4607. while(nLimit <= nExponent){
  4608. nLimit *= 10;
  4609. ++nDigits;
  4610. }
  4611. const double dExpPow = ::pow(10.0, (double)-nExponent);
  4612. if(FtoaEnglish(dValue * dExpPow, pResult, nResultCapacity - nDigits - 2, nPrecision, false)){
  4613. char32_t* p = pResult + Strlen(pResult);
  4614. *p++ = (char32_t)'e';
  4615. *p++ = ((nExponent < 0) ? (char32_t)'-' : (char32_t)'+');
  4616. I32toa(abs(nExponent), p, 10);
  4617. return pResult;
  4618. }
  4619. return NULL;
  4620. }
  4621. }
  4622. // fcvt is a function that converts a floating point value to its component
  4623. // string, sign, and decimal position. It doesn't convert it to a fully
  4624. // finished string because sign and decimal usage usually varies between
  4625. // locales and this function is trying to be locale-independent. It is up
  4626. // to the user of this function to present the final data in a form that
  4627. // is locale-savvy. Actually, not all compilers implement fcvt.
  4628. #if EASTDC_NATIVE_FCVT
  4629. #ifdef __GNUC__
  4630. const char* const pResultTemp = fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
  4631. #else
  4632. const char* const pResultTemp = _fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
  4633. #endif
  4634. #else
  4635. char bufferTemp[kFcvtBufMaxSize];
  4636. const char* const pResultTemp = FcvtBuf(dValue, nPrecision, &nDecimalPosition, &nSign, bufferTemp);
  4637. #endif
  4638. // If the value is negative, then add a leading '-' sign.
  4639. if(nSign){
  4640. if(nPositionResult >= nResultCapacity){
  4641. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4642. return NULL;
  4643. }
  4644. pResult[nPositionResult] = '-';
  4645. nPositionResult++;
  4646. }
  4647. // If the value is < 1, then add a leading '0' digit.
  4648. if(fabs(dValue) < 1.0){
  4649. #if EASTDC_NATIVE_FCVT && defined(__GNUC__)
  4650. // GCC's fcvt has a quirk: If the input dValue is 0 (but no other value, fractional or not),
  4651. // it yields an output string with a leading "0." So we need to make a special case to
  4652. // detect this here.
  4653. if(dValue != 0.0)
  4654. #endif
  4655. {
  4656. if(nPositionResult >= nResultCapacity){
  4657. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4658. return NULL;
  4659. }
  4660. pResult[nPositionResult++] = '0';
  4661. }
  4662. }
  4663. // Read digits up to the decimal position and write them to the output string.
  4664. if(nDecimalPosition > 0){ // If the input was something like 1000.0
  4665. for(i = 0; (i < nDecimalPosition) && pResultTemp[nPositionTemp]; i++){
  4666. if(nPositionResult >= nResultCapacity){
  4667. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4668. return NULL;
  4669. }
  4670. pResult[nPositionResult++] = (char32_t)pResultTemp[nPositionTemp++];
  4671. }
  4672. }
  4673. if(pResultTemp[nPositionTemp]){
  4674. // Find the last of the zeroes in the pResultTemp string. We don't want
  4675. // to add unnecessary trailing zeroes to the returned string and don't
  4676. // want to return a decimal point in the string if it isn't necessary.
  4677. int nFirstTrailingZeroPosition(nPositionTemp);
  4678. int nLastPositionTemp(nPositionTemp);
  4679. while(pResultTemp[nLastPositionTemp]){
  4680. if(pResultTemp[nLastPositionTemp] != '0')
  4681. nFirstTrailingZeroPosition = nLastPositionTemp + 1;
  4682. nLastPositionTemp++;
  4683. }
  4684. // If there is any reason to write a decimal point, then we write
  4685. // it and write the data that comes after it.
  4686. if((nFirstTrailingZeroPosition > nPositionTemp) && (nPrecision > 0)){
  4687. // Add a decimal point.
  4688. if(nPositionResult >= nResultCapacity){
  4689. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4690. return NULL;
  4691. }
  4692. pResult[nPositionResult++] = '.';
  4693. if(nDecimalPosition < 0){ // If there are zeroes after the decimal...
  4694. for(i = nDecimalPosition; i < 0; i++){
  4695. if(nPositionResult >= nResultCapacity){
  4696. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4697. return NULL;
  4698. }
  4699. pResult[nPositionResult++] = '0';
  4700. --nPrecision;
  4701. }
  4702. }
  4703. // Read digits after the decimal position and write them to the output string.
  4704. for(i = 0; (i < nPrecision) && (nPositionTemp < nFirstTrailingZeroPosition) && pResultTemp[nPositionTemp]; i++){
  4705. if(nPositionResult >= nResultCapacity){
  4706. //What we do here is possibly erase trailing zeroes that we've written after the decimal.
  4707. int nEndPosition = EASTDC_MAX(nPositionResult - 1, 0);
  4708. pResult[nEndPosition] = 0;
  4709. while((--nEndPosition > 0) && (pResult[nEndPosition] == '0'))
  4710. pResult[nEndPosition] = 0;
  4711. return NULL;
  4712. }
  4713. pResult[nPositionResult++] = (char32_t)pResultTemp[nPositionTemp++];
  4714. }
  4715. }
  4716. }
  4717. // Write the final terminating zero.
  4718. if(nPositionResult >= nResultCapacity){
  4719. pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
  4720. return NULL;
  4721. }
  4722. pResult[nPositionResult] = 0;
  4723. return pResult;
  4724. }
  4725. EASTDC_API size_t ReduceFloatString(char* pString, size_t nLength)
  4726. {
  4727. if(nLength == (size_t)-1)
  4728. nLength = strlen(pString);
  4729. size_t nNewLength(nLength);
  4730. if(nLength > 0)
  4731. {
  4732. // Get the decimal index and exponent index. We won't chop off any zeros
  4733. // unless they are after the decimal position and before an exponent position.
  4734. int nDecimalIndex = -1;
  4735. int nExponentIndex = -1;
  4736. int nCurrentIndex = 0;
  4737. while(nCurrentIndex < (int)nLength)
  4738. {
  4739. if(pString[nCurrentIndex] == '.')
  4740. nDecimalIndex = nCurrentIndex;
  4741. if((pString[nCurrentIndex] == 'e') || (pString[nCurrentIndex] == 'E'))
  4742. nExponentIndex = nCurrentIndex;
  4743. nCurrentIndex++;
  4744. }
  4745. // Now we need to go to the end of the string and walk backwards to
  4746. // find any contiguous zero digits after a decimal point.
  4747. if(nDecimalIndex >= 0) // If there is any decimal point...
  4748. {
  4749. const int nFirstDigitToCheck(nDecimalIndex + 1);
  4750. const int nLastDigitToCheck ((nExponentIndex >= 0) ? (nExponentIndex - 1) : (int)(nLength - 1));
  4751. nCurrentIndex = nLastDigitToCheck;
  4752. while(nCurrentIndex >= nFirstDigitToCheck)
  4753. {
  4754. // assert((pString[nCurrentIndex] >= '0') && (pString[nCurrentIndex] <= '9'));
  4755. if(pString[nCurrentIndex] == '0')
  4756. {
  4757. // Copy the string downward. Note that we copy the trailing
  4758. // terminator of the string as well.
  4759. for(int i = nCurrentIndex; i < (int)nNewLength; i++)
  4760. pString[i] = pString[i + 1]; // Copy the string downward.
  4761. nNewLength--;
  4762. }
  4763. else
  4764. break;
  4765. nCurrentIndex--;
  4766. }
  4767. }
  4768. else
  4769. {
  4770. // If the string is all zeroes, convert it to just one zero.
  4771. size_t i;
  4772. for(i = 0; (i < nLength) && (pString[i] == '0'); i++)
  4773. { } // Do nothing.
  4774. if(i == nLength)
  4775. nLength = 0; // And fall through to the code below.
  4776. }
  4777. // It is possible that the input string was "000", in which case the above code would
  4778. // erase the entire string. Here we simply make a string of "0" and return it.
  4779. if(nLength == 0)
  4780. {
  4781. pString[0] = '0';
  4782. pString[1] = 0;
  4783. nNewLength = 1;
  4784. }
  4785. else
  4786. {
  4787. // We may have a number such as "234.", in which case we remove the trailing decimal.
  4788. if((nDecimalIndex >= 0) && (nDecimalIndex == ((int)(unsigned)nNewLength - 1)))
  4789. {
  4790. pString[nDecimalIndex] = 0;
  4791. nNewLength--;
  4792. }
  4793. size_t i;
  4794. // It is also posible that we now have a string like "0." or "000." or just ".".
  4795. // In this case, we simply set the string to "0".
  4796. for(i = 0; i < nNewLength; i++)
  4797. {
  4798. if((pString[i] != '0') && (pString[i] != '.'))
  4799. break;
  4800. }
  4801. if(i == nNewLength) // If the string was all zeros...
  4802. {
  4803. pString[0] = '0';
  4804. pString[1] = 0;
  4805. nNewLength = 1;
  4806. }
  4807. if((nNewLength >= 3) && (pString[0] == '0') && (pString[1] == '.')) // If we have "0.x"
  4808. {
  4809. memmove(pString, pString + 1, nNewLength * sizeof(char));
  4810. nNewLength--;
  4811. }
  4812. }
  4813. }
  4814. return nNewLength;
  4815. }
  4816. EASTDC_API size_t ReduceFloatString(char16_t* pString, size_t nLength)
  4817. {
  4818. // We implement this by calling the 8 bit version and copying its data.
  4819. char pBuffer8[64];
  4820. char* pCurrent8;
  4821. char16_t* pCurrent16;
  4822. size_t n = 0;
  4823. if(nLength < 63)
  4824. nLength = 63;
  4825. for(pCurrent8 = pBuffer8, pCurrent16 = pString; *pCurrent16 && (n < nLength); ++n) // Do a 16 bit to 8 bit strcpy.
  4826. *pCurrent8++ = (char)(unsigned char)*pCurrent16++;
  4827. *pCurrent8 = 0;
  4828. n = ReduceFloatString(pBuffer8, n);
  4829. for(pCurrent8 = pBuffer8, pCurrent16 = pString; *pCurrent8; ) // Do a 8 bit to 16 bit strcpy.
  4830. *pCurrent16++ = (char16_t)(unsigned char)*pCurrent8++;
  4831. *pCurrent16 = 0;
  4832. return n;
  4833. }
  4834. EASTDC_API size_t ReduceFloatString(char32_t* pString, size_t nLength)
  4835. {
  4836. // We implement this by calling the 8 bit version and copying its data.
  4837. char pBuffer8[64];
  4838. char* pCurrent8;
  4839. char32_t* pCurrent32;
  4840. size_t n = 0;
  4841. if(nLength < 63)
  4842. nLength = 63;
  4843. for(pCurrent8 = pBuffer8, pCurrent32 = pString; *pCurrent32 && (n < nLength); ++n) // Do a 32 bit to 8 bit strcpy.
  4844. *pCurrent8++ = (char)(unsigned char)*pCurrent32++;
  4845. *pCurrent8 = 0;
  4846. n = ReduceFloatString(pBuffer8, n);
  4847. for(pCurrent8 = pBuffer8, pCurrent32 = pString; *pCurrent8; ) // Do a 8 bit to 32 bit strcpy.
  4848. *pCurrent32++ = (char32_t)(unsigned char)*pCurrent8++;
  4849. *pCurrent32 = 0;
  4850. return n;
  4851. }
  4852. } // namespace StdC
  4853. } // namespace EA
  4854. #undef EASTDC_MIN
  4855. #undef EASTDC_MAX
  4856. #if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)
  4857. EA_RESTORE_GCC_WARNING()
  4858. #endif
  4859. EA_RESTORE_VC_WARNING()