| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107 |
- ///////////////////////////////////////////////////////////////////////////////
- // Copyright (c) Electronic Arts Inc. All rights reserved.
- ///////////////////////////////////////////////////////////////////////////////
- #include <EAStdC/internal/Config.h>
- #include <EAStdC/EAString.h>
- #include <EAStdC/EACType.h>
- #include <EAStdC/EAMathHelp.h>
- #include <EAStdC/EAStdC.h>
- #include <EAStdC/EAMemory.h>
- #include <EAStdC/EAAlignment.h>
- #include <EAStdC/EABitTricks.h>
- #include <EAAssert/eaassert.h>
- EA_DISABLE_ALL_VC_WARNINGS()
- #include <string.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <limits.h>
- #include <math.h>
- EA_RESTORE_ALL_VC_WARNINGS()
- EA_DISABLE_VC_WARNING(4996 4127 6385 4146) // 'ecvt' was declared deprecated
- // conditional expression is constant.
- // Invalid data: accessing 'comp1', the readable size is '20' bytes, but '4194248' bytes might be read: Lines: 504, 505, 507, 508, 510, 512, 514
- // warning C4146: unary minus operator applied to unsigned type, result still unsigned
- #if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)
- EA_DISABLE_GCC_WARNING(-Wmaybe-uninitialized) // GCC 4.7+ mistakenly warns about this.
- #endif
- /////////////////////////////////////////////////////////////////////////////
- // EASTDC_MIN / EASTDC_MAX
- //
- #define EASTDC_MIN(a, b) ((a) < (b) ? (a) : (b))
- #define EASTDC_MAX(a, b) ((a) > (b) ? (a) : (b))
- namespace EA
- {
- namespace StdC
- {
- // Define word_type to match machine word type. This is not the same
- // thing as size_t or uintptr_t, as there are machines with 64 bit
- // words but 32 bit pointers (e.g. XBox 360, PS3).
- #if (EA_PLATFORM_WORD_SIZE == 8) // From EABase
- typedef uint64_t word_type;
- #else
- typedef uint32_t word_type;
- #endif
- EASTDC_API char* Strcpy(char* pDestination, const char* pSource)
- {
- const char* s = pSource;
- char* d = pDestination;
- while((*d++ = *s++) != 0)
- {} // Do nothing.
-
- return pDestination;
- }
- EASTDC_API char16_t* Strcpy(char16_t* pDestination, const char16_t* pSource)
- {
- const char16_t* s = pSource;
- char16_t* d = pDestination;
- while((*d++ = *s++) != 0)
- {} // Do nothing.
-
- return pDestination;
- }
- EASTDC_API char32_t* Strcpy(char32_t* pDestination, const char32_t* pSource)
- {
- const char32_t* s = pSource;
- char32_t* d = pDestination;
- while((*d++ = *s++) != 0)
- {} // Do nothing.
-
- return pDestination;
- }
- EASTDC_API char* Strncpy(char* pDestination, const char* pSource, size_t n)
- {
- const char* s = pSource;
- char* d = pDestination;
- n++;
- while(--n)
- {
- if((*d++ = *s++) == 0)
- {
- while(--n)
- *d++ = 0;
- break;
- }
- }
-
- return pDestination;
- }
- EASTDC_API char16_t* Strncpy(char16_t* pDestination, const char16_t* pSource, size_t n)
- {
- const char16_t* s = pSource;
- char16_t* d = pDestination;
- n++;
- while(--n)
- {
- if((*d++ = *s++) == 0)
- {
- while(--n)
- *d++ = 0;
- break;
- }
- }
-
- return pDestination;
- }
- EASTDC_API char32_t* Strncpy(char32_t* pDestination, const char32_t* pSource, size_t n)
- {
- const char32_t* s = pSource;
- char32_t* d = pDestination;
- n++;
- while(--n)
- {
- if((*d++ = *s++) == 0)
- {
- while(--n)
- *d++ = 0;
- break;
- }
- }
-
- return pDestination;
- }
- EASTDC_API char* StringnCopy(char* pDestination, const char* pSource, size_t n)
- {
- char* pOriginalDest = pDestination;
- if(n)
- {
- while(n-- && *pSource)
- *pDestination++ = *pSource++;
- if(n != static_cast<size_t>(-1)) // Is this portable?
- *pDestination = 0;
- }
- return pOriginalDest;
- }
- EASTDC_API char16_t* StringnCopy(char16_t* pDestination, const char16_t* pSource, size_t n)
- {
- char16_t* pOriginalDest = pDestination;
- if(n)
- {
- while(n-- && *pSource)
- *pDestination++ = *pSource++;
- if(n != static_cast<size_t>(-1))
- *pDestination = 0;
- }
- return pOriginalDest;
- }
- EASTDC_API char32_t* StringnCopy(char32_t* pDestination, const char32_t* pSource, size_t n)
- {
- char32_t* pOriginalDest = pDestination;
- if(n)
- {
- while(n-- && *pSource)
- *pDestination++ = *pSource++;
- if(n != static_cast<size_t>(-1))
- *pDestination = 0;
- }
- return pOriginalDest;
- }
- /* Reference implementation which ought to be a little slower than our more optimized implementation.
- EASTDC_API size_t Strlcpy(char* pDestination, const char* pSource, size_t nDestCapacity)
- {
- const size_t n = Strlen(pSource);
- if(n < nDestCapacity)
- memcpy(pDestination, pSource, (n + 1) * sizeof(*pSource));
- else if(nDestCapacity)
- {
- memcpy(pDestination, pSource, (nDestCapacity - 1) * sizeof(*pSource));
- pDestination[nDestCapacity - 1] = 0;
- }
- return n;
- }
- */
- EASTDC_API size_t Strlcpy(char* pDestination, const char* pSource, size_t nDestCapacity)
- {
- const char* s = pSource;
- size_t n = nDestCapacity;
- if(n && --n)
- {
- do{
- if((*pDestination++ = *s++) == 0)
- break;
- } while(--n);
- }
- if(!n)
- {
- if(nDestCapacity)
- *pDestination = 0;
- while(*s++)
- { }
- }
- return (size_t)(s - pSource - 1);
- }
- /* Reference implementation which ought to be a little slower than our more optimized implementation.
- EASTDC_API size_t Strlcpy(char16_t* pDestination, const char16_t* pSource, size_t nDestCapacity)
- {
- const size_t n = Strlen(pSource);
- if(n < nDestCapacity)
- memcpy(pDestination, pSource, (n + 1) * sizeof(*pSource));
- else if(nDestCapacity)
- {
- memcpy(pDestination, pSource, (nDestCapacity - 1) * sizeof(*pSource));
- pDestination[nDestCapacity - 1] = 0;
- }
- return n;
- }
- */
- EASTDC_API size_t Strlcpy(char16_t* pDestination, const char16_t* pSource, size_t nDestCapacity)
- {
- const char16_t* s = pSource;
- size_t n = nDestCapacity;
- if(n && --n)
- {
- do{
- if((*pDestination++ = *s++) == 0)
- break;
- } while(--n);
- }
- if(!n)
- {
- if(nDestCapacity)
- *pDestination = 0;
- while(*s++)
- { }
- }
- return (size_t)(s - pSource - 1);
- }
- EASTDC_API size_t Strlcpy(char32_t* pDestination, const char32_t* pSource, size_t nDestCapacity)
- {
- const char32_t* s = pSource;
- size_t n = nDestCapacity;
- if(n && --n)
- {
- do{
- if((*pDestination++ = *s++) == 0)
- break;
- } while(--n);
- }
- if(!n)
- {
- if(nDestCapacity)
- *pDestination = 0;
- while(*s++)
- { }
- }
- return (size_t)(s - pSource - 1);
- }
- /*
- // To consider: Enable this for completeness with the above:
- EASTDC_API int Strlcpy(char* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength)
- {
- if(nSourceLength == kSizeTypeUnset)
- nSourceLength = Strlen(pSource);
- if(nSourceLength < nDestCapacity)
- {
- memcpy(pDest, pSource, nSourceLength * sizeof(*pSource));
- pDest[nSourceLength] = 0;
- }
- else if(nDestCapacity)
- {
- memcpy(pDest, pSource, (nDestCapacity - 1) * sizeof(*pSource));
- pDest[nDestCapacity - 1] = 0;
- }
- return (int)(unsigned)nSourceLength;
- }
- EASTDC_API int Strlcpy(char16_t* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength)
- {
- if(nSourceLength == kSizeTypeUnset)
- nSourceLength = Strlen(pSource);
- if(nSourceLength < nDestCapacity)
- {
- memcpy(pDest, pSource, nSourceLength * sizeof(*pSource));
- pDest[nSourceLength] = 0;
- }
- else if(nDestCapacity)
- {
- memcpy(pDest, pSource, (nDestCapacity - 1) * sizeof(*pSource));
- pDest[nDestCapacity - 1] = 0;
- }
- return (int)(unsigned)nSourceLength;
- }
- EASTDC_API int Strlcpy(char32_t* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength)
- {
- if(nSourceLength == kSizeTypeUnset)
- nSourceLength = Strlen(pSource);
- if(nSourceLength < nDestCapacity)
- {
- memcpy(pDest, pSource, nSourceLength * sizeof(*pSource));
- pDest[nSourceLength] = 0;
- }
- else if(nDestCapacity)
- {
- memcpy(pDest, pSource, (nDestCapacity - 1) * sizeof(*pSource));
- pDest[nDestCapacity - 1] = 0;
- }
- return (int)(unsigned)nSourceLength;
- }
- */
- //static const int32_t kLeadingSurrogateStart = 0x0000d800;
- //static const int32_t kTrailingSurrogateStart = 0x0000dc00;
- //static const int32_t kLeadingSurrogateEnd = 0x0000dbff;
- //static const int32_t kTrailingSurrogateEnd = 0x0000dfff;
- //static const int32_t kSurrogateOffset = 0x00010000 - (kLeadingSurrogateStart << 10) - kTrailingSurrogateStart;
- // This is not static because it is used elsewhere.
- uint8_t utf8lengthTable[256] =
- {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 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
- };
- // Used to subtract out the control bits in multi-byte sequence.
- static const uint32_t utf8DecodingOffsetTable[5] =
- {
- 0, // 0x00000000
- 0, // 0x00000000
- (0xC0 << 6) + 0x80, // 0x00003080
- (0xE0 << 12) + (0x80 << 6) + 0x80, // 0x000e2080
- (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 // 0x03c82080
- // to do
- // to do
- };
- // The minimum value that can be encoded in a particular number
- // of bytes. Used to disallow non-canonical encoded sequences.
- // It turns out that this is not a fully proper way to check for
- // valid sequences. See the Unicode Standard http://unicode.org/versions/corrigendum1.html
- static const uint32_t utf8MinimumValueTable[] =
- {
- 0x00000000, // This slot is unused
- 0x00000000, // 1 byte per char
- 0x00000080, // 2 bytes per char
- 0x00000800, // 3 bytes per char
- 0x00010000 // 4 bytes per char
- //0x00200000, // 5 bytes per char
- //0x04000000, // 6 bytes per char
- };
- // One past the maximum value that can be encoded in a particular number
- // of bytes. Used to disallow non-canonical encoded sequences.
- static const uint32_t utf8MaximumValueTable[] =
- {
- 0x00000000, // This slot is unused
- 0x00000080, // 1 byte per char
- 0x00000800, // 2 bytes per char
- 0x00010000, // 3 bytes per char
- 0x00110000 // 4 bytes per char *** Should be: 0x00200000
- //0x04000000
- //0x80000000
- };
- const uint32_t kUnicodeReplacementChar = 0x0000fffd;
- const uint32_t kUnicodeInvalidDecode = 0xffffffffu;
- EA_FORCE_INLINE uint32_t DecodeCodePoint(const char*& pSourceStart, const char* pSourceEnd)
- {
- const char* pSource = pSourceStart;
- uint32_t c = (uint8_t)*(pSource++);
- if(c < 128)
- {
- // Valid character, do nothing
- }
- else
- {
- uint32_t nLength = utf8lengthTable[c]; // nLength may be zero, in which case we'll return 'IncorrectEncoding'.
- // Do we have an incomplete or invalid string?
- if((pSourceStart + nLength > pSourceEnd) || (nLength == 0))
- {
- if(EA::StdC::GetAssertionsEnabled())
- {
- EA_FAIL_MSG("Incomplete Unicode character in buffer");
- }
- return kUnicodeInvalidDecode;
- }
- // Now decode the remaining ("following") bytes.
- for(uint32_t i = 0; i < nLength - 1; ++i)
- {
- uint8_t nByte = (uint8_t)*(pSource++);
- if((nByte < 0x80u) || (nByte > 0xbfu)) // Syntax check
- {
- if(EA::StdC::GetAssertionsEnabled())
- {
- EA_FAIL_MSG("Invalid following byte");
- }
- return kUnicodeInvalidDecode;
- }
- c = (c << 6) + nByte; // Preserve control bits (don't OR)
- }
- c -= utf8DecodingOffsetTable[nLength]; // Subtract accumulated control bits just once
- // Check for canonical encoding.
- if((c < utf8MinimumValueTable[nLength]) || (c >= utf8MaximumValueTable[nLength]))
- {
- return kUnicodeInvalidDecode;
- }
- }
- pSourceStart = pSource;
- return c;
- }
- EA_FORCE_INLINE bool EncodeCodePoint(uint32_t c, char*& pDestStart, char* pDestEnd)
- {
- // Encode as UTF-8
- if(c < 0x00000080u)
- {
- *(pDestStart++) = static_cast<char>(c);
- return true;
- }
- else if(c < 0x00000800u)
- {
- if (pDestStart + 2 <= pDestEnd)
- {
- char* pDest = pDestStart;
- *(pDest++) = static_cast<char>((c >> 6) | 0xc0);
- *(pDest++) = static_cast<char>((c | 0x80) & 0xbf);
- pDestStart = pDest;
- return true;
- }
- return false;
- }
- else if(c < 0x00010000u)
- {
- if (pDestStart + 3 <= pDestEnd)
- {
- char* pDest = pDestStart;
- *(pDest++) = static_cast<char>((c >> 12) | 0xe0);
- *(pDest++) = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
- *(pDest++) = static_cast<char>((c | 0x80) & 0xbf);
- pDestStart = pDest;
- return true;
- }
- return false;
- }
- else if(c < 0x00200000u)
- {
- if(pDestStart + 4 <= pDestEnd)
- {
- char* pDest = pDestStart;
- *(pDest++) = static_cast<char>((c >> 18) | 0xf0);
- *(pDest++) = static_cast<char>(((c >> 12) | 0x80) & 0xbf);
- *(pDest++) = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
- *(pDest++) = static_cast<char>((c | 0x80) & 0xbf);
- pDestStart = pDest;
- return true;
- }
- return false;
- }
- else
- {
- // We don't currently support Unicode beyond "Plane 0", as game software has never needed it.
- // If you have a need for this support, feel free to submit a patch or make a specific request.
- c = kUnicodeReplacementChar;
- if(pDestStart + 3 <= pDestEnd)
- {
- char* pDest = pDestStart;
- *(pDest++) = static_cast<char>((c >> 12) | 0xe0);
- *(pDest++) = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
- *(pDest++) = static_cast<char>(((c >> 0) | 0x80) & 0xbf);
- pDestStart = pDest;
- return true;
- }
- return false;
- }
- }
- EA_FORCE_INLINE uint32_t DecodeCodePoint(const char16_t*& pSourceStart, const char16_t* pSourceEnd)
- {
- EA_UNUSED(pSourceEnd);
- return (uint32_t)*(pSourceStart++);
- }
- EA_FORCE_INLINE bool EncodeCodePoint(uint32_t c, char16_t*& pDestStart, char16_t* pDestEnd)
- {
- EA_UNUSED(pDestEnd);
- *(pDestStart++) = static_cast<char16_t>(c);
- return true;
- }
- EA_FORCE_INLINE uint32_t DecodeCodePoint(const char32_t*& pSourceStart, const char32_t* pSourceEnd)
- {
- EA_UNUSED(pSourceEnd);
- return (uint32_t)*(pSourceStart++);
- }
- EA_FORCE_INLINE bool EncodeCodePoint(uint32_t c, char32_t*& pDestStart, char32_t* pDestEnd)
- {
- EA_UNUSED(pDestEnd);
- *(pDestStart++) = static_cast<char32_t>(c);
- return true;
- }
- template <typename InCharT, typename OutCharT>
- bool StrlcpyInternal(OutCharT* pDest, const InCharT* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
- {
- EA_ASSERT(pDest != nullptr && pSource != nullptr);
- // If we have no capacity, then just return nothing
- if(nDestCapacity == 0)
- {
- nDestUsed = 0;
- nSourceUsed = 0;
- return true;
- }
- const InCharT* pSourceStart = pSource;
- const InCharT* pSourceEnd = pSource + nSourceLength;
- if (pSourceEnd < pSourceStart)
- pSourceEnd = (const InCharT*)(uintptr_t)-1;
- OutCharT* pDestStart = pDest;
- OutCharT* pDestEnd = pDest + nDestCapacity - 1;
- bool bGood = true;
- while(bGood && (pSource < pSourceEnd) && (pDest < pDestEnd))
- {
- uint32_t c = DecodeCodePoint(pSource, pSourceEnd);
- if (c == 0)
- {
- pSource = pSourceEnd;
- break;
- }
- bGood = (c != kUnicodeInvalidDecode) && EncodeCodePoint(c, pDest, pDestEnd);
- }
- *pDest = 0;
- nDestUsed = pDest - pDestStart;
- nSourceUsed = pSource - pSourceStart;
- return bGood;
- }
- bool Strlcpy(char* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
- {
- return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
- }
- bool Strlcpy(char* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
- {
- return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
- }
- bool Strlcpy(char16_t* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
- {
- return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
- }
- bool Strlcpy(char16_t* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
- {
- return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
- }
- bool Strlcpy(char32_t* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
- {
- return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
- }
- bool Strlcpy(char32_t* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength, size_t& nDestUsed, size_t& nSourceUsed)
- {
- return StrlcpyInternal(pDest, pSource, nDestCapacity, nSourceLength, nDestUsed, nSourceUsed);
- }
- EASTDC_API int Strlcpy(char* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength)
- {
- size_t destCount = 0;
- while(nSourceLength-- > 0)
- {
- uint32_t c = (uint16_t)*pSource++; // Deal with surrogate characters
- // Encode as UTF-8
- if (c < 0x00000080u)
- {
- if(c == 0) // Break on NULL char, even if explicit length was set
- break;
- if(pDest && ((destCount + 1) < nDestCapacity))
- *pDest++ = static_cast<char>(c);
- destCount += 1;
- }
- else if(c < 0x00000800u)
- {
- if(pDest && ((destCount + 2) < nDestCapacity))
- {
- *pDest++ = static_cast<char>((c >> 6) | 0xc0);
- *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
- }
- destCount += 2;
- }
- else if(c < 0x00010000u)
- {
- if(pDest && ((destCount + 3) < nDestCapacity))
- {
- *pDest++ = static_cast<char>((c >> 12) | 0xe0);
- *pDest++ = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
- *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
- }
- destCount += 3;
- }
- else if(c < 0x00200000u)
- {
- if(pDest && ((destCount + 4) < nDestCapacity))
- {
- *pDest++ = static_cast<char>((c >> 18) | 0xf0);
- *pDest++ = static_cast<char>(((c >> 12) | 0x80) & 0xbf);
- *pDest++ = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
- *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
- }
- destCount += 4;
- }
- else
- {
- const uint32_t kIllegalUnicodeChar = 0x0000fffd;
- if(pDest && ((destCount + 3) < nDestCapacity))
- {
- *pDest++ = static_cast<char>( (kIllegalUnicodeChar >> 12) | 0xe0);
- *pDest++ = static_cast<char>(((kIllegalUnicodeChar >> 6) | 0x80) & 0xbf);
- *pDest++ = static_cast<char>(((kIllegalUnicodeChar >> 0) | 0x80) & 0xbf);
- }
- destCount += 3;
- }
- }
- if(pDest && nDestCapacity != 0)
- *pDest = 0;
- return (int)(unsigned)destCount;
- }
- EASTDC_API int Strlcpy(char* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength)
- {
- size_t destCount = 0;
- while(nSourceLength-- > 0)
- {
- uint32_t c = (uint32_t)*pSource++; // Deal with surrogate characters
- // Encode as UTF-8
- if (c < 0x00000080u)
- {
- if(c == 0) // Break on NULL char, even if explicit length was set
- break;
- if(pDest && ((destCount + 1) < nDestCapacity))
- *pDest++ = static_cast<char>(c);
- destCount += 1;
- }
- else if(c < 0x00000800u)
- {
- if(pDest && ((destCount + 2) < nDestCapacity))
- {
- *pDest++ = static_cast<char>((c >> 6) | 0xc0);
- *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
- }
- destCount += 2;
- }
- else if(c < 0x00010000u)
- {
- if(pDest && ((destCount + 3) < nDestCapacity))
- {
- *pDest++ = static_cast<char>((c >> 12) | 0xe0);
- *pDest++ = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
- *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
- }
- destCount += 3;
- }
- else if(c < 0x00200000u)
- {
- if(pDest && ((destCount + 4) < nDestCapacity))
- {
- *pDest++ = static_cast<char>((c >> 18) | 0xf0);
- *pDest++ = static_cast<char>(((c >> 12) | 0x80) & 0xbf);
- *pDest++ = static_cast<char>(((c >> 6) | 0x80) & 0xbf);
- *pDest++ = static_cast<char>((c | 0x80) & 0xbf);
- }
- destCount += 4;
- }
- else
- {
- // We don't currently support Unicode beyond "Plane 0", as game software has never needed it.
- // If you have a need for this support, feel free to submit a patch or make a specific request.
- const uint32_t kIllegalUnicodeChar = 0x0000fffd;
- if(pDest && ((destCount + 3) < nDestCapacity))
- {
- *pDest++ = static_cast<char>( (kIllegalUnicodeChar >> 12) | 0xe0);
- *pDest++ = static_cast<char>(((kIllegalUnicodeChar >> 6) | 0x80) & 0xbf);
- *pDest++ = static_cast<char>(((kIllegalUnicodeChar >> 0) | 0x80) & 0xbf);
- }
- destCount += 3;
- }
- }
- if(pDest && nDestCapacity != 0)
- *pDest = 0;
- return (int)(unsigned)destCount;
- }
- EASTDC_API int Strlcpy(char16_t* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength)
- {
- size_t destCount = 0;
- while(nSourceLength-- > 0)
- {
- uint32_t c = (uint8_t)*pSource++;
- if(c < 128)
- {
- if(c == 0) // Break on NULL char, even if explicit length was set
- break;
- if(pDest && ((destCount + 1) < nDestCapacity)) // +1 because we want to append c to pDest but also append '\0'.
- *pDest++ = static_cast<char16_t>(c);
- destCount++;
- }
- else
- {
- uint32_t nLength = utf8lengthTable[c]; // nLength may be zero, in which case we'll return 'IncorrectEncoding'.
- // Do we have an incomplete or invalid string?
- if((nLength > (nSourceLength + 1)) || (nLength == 0))
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("Incomplete Unicode character in buffer"); }
- if(pDest && (destCount < nDestCapacity))
- *pDest++ = 0; // Even though we are returning an error, 0-terminate anyway for safety.
- return -1;
- }
- // Now decode the remaining ("following") bytes.
- for(uint32_t i = 0; i < nLength - 1; ++i)
- {
- uint8_t nByte = (uint8_t)*pSource++;
- if((nByte < 0x80u) || (nByte > 0xbfu)) // Syntax check
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("Invalid following byte"); }
- if(pDest && (destCount < nDestCapacity))
- *pDest++ = 0; // Even though we are returning an error, 0-terminate anyway for safety.
- return -1;
- }
- c = (c << 6) + nByte; // Preserve control bits (don't OR)
- }
- nSourceLength -= (nLength - 1); // We've just processed all remaining bytes for this multi-byte character
- c -= utf8DecodingOffsetTable[nLength]; // Subtract accumulated control bits just once
- // Check for canonical encoding.
- if((c >= utf8MinimumValueTable[nLength]) && (c < utf8MaximumValueTable[nLength]))
- {
- if(pDest && ((destCount + 1) < nDestCapacity))
- *pDest++ = static_cast<char16_t>(c);
- destCount++;
- }
- else
- break;
- }
- }
- if(pDest && (nDestCapacity != 0))
- *pDest = 0;
- return (int)(unsigned)destCount;
- }
- EASTDC_API int Strlcpy(char32_t* pDest, const char* pSource, size_t nDestCapacity, size_t nSourceLength)
- {
- size_t destCount = 0;
- while(nSourceLength-- > 0)
- {
- uint32_t c = (uint8_t)*pSource++;
- if(c < 128)
- {
- if(c == 0) // Break on NULL char, even if explicit length was set
- break;
- if(pDest && ((destCount + 1) < nDestCapacity)) // +1 because we want to append c to pDest but also append '\0'.
- *pDest++ = static_cast<char32_t>(c);
- destCount++;
- }
- else
- {
- uint32_t nLength = utf8lengthTable[c]; // nLength may be zero, in which case we'll return 'IncorrectEncoding'.
- // Do we have an incomplete or invalid string?
- if((nLength > (nSourceLength + 1)) || (nLength == 0))
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("Incomplete Unicode character in buffer"); }
- if(pDest && (destCount < nDestCapacity))
- *pDest++ = 0; // Even though we are returning an error, 0-terminate anyway for safety.
- return -1;
- }
- // Now decode the remaining ("following") bytes.
- for(uint32_t i = 0; i < nLength - 1; ++i)
- {
- uint8_t nByte = (uint8_t)*pSource++;
- if((nByte < 0x80u) || (nByte > 0xbfu)) // Syntax check
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("Invalid following byte"); }
- if(pDest && (destCount < nDestCapacity))
- *pDest++ = 0; // Even though we are returning an error, 0-terminate anyway for safety.
- return -1;
- }
- c = (c << 6) + nByte; // Preserve control bits (don't OR)
- }
- nSourceLength -= (nLength - 1); // We've just processed all remaining bytes for this multi-byte character
- c -= utf8DecodingOffsetTable[nLength]; // Subtract accumulated control bits just once
- // Check for canonical encoding.
- if((c >= utf8MinimumValueTable[nLength]) && (c < utf8MaximumValueTable[nLength]))
- {
- if(pDest && ((destCount + 1) < nDestCapacity))
- *pDest++ = static_cast<char32_t>(c);
- destCount++;
- }
- else
- break;
- }
- }
- if(pDest && (nDestCapacity != 0))
- *pDest = 0;
- return (int)(unsigned)destCount;
- }
- EASTDC_API int Strlcpy(char32_t* pDest, const char16_t* pSource, size_t nDestCapacity, size_t nSourceLength)
- {
- size_t destCount = 0;
- while(nSourceLength-- > 0)
- {
- uint32_t c = (uint32_t)*pSource++;
- if(c == 0) // Break on NULL char, even if explicit length was set
- break;
- if(pDest && ((destCount + 1) < nDestCapacity)) // +1 because we want to append c to pDest but also append '\0'.
- *pDest++ = static_cast<char32_t>(c);
- destCount += 1;
- }
- if(pDest && nDestCapacity != 0)
- *pDest = 0;
- return (int)(unsigned)destCount;
- }
- EASTDC_API int Strlcpy(char16_t* pDest, const char32_t* pSource, size_t nDestCapacity, size_t nSourceLength)
- {
- size_t destCount = 0;
- while(nSourceLength-- > 0)
- {
- uint32_t c = (uint32_t)*pSource++;
- if(c == 0) // Break on NULL char, even if explicit length was set
- break;
- if(pDest && ((destCount + 1) < nDestCapacity)) // +1 because we want to append c to pDest but also append '\0'.
- *pDest++ = static_cast<char16_t>(c);
- destCount += 1;
- }
- if(pDest && nDestCapacity != 0)
- *pDest = 0;
- return (int)(unsigned)destCount;
- }
- EASTDC_API char* Strcat(char* pDestination, const char* pSource)
- {
- const char* s = pSource;
- char* d = pDestination;
- while(*d++){} // Do nothing.
- --d;
- while((*d++ = *s++) != 0)
- {} // Do nothing.
-
- return pDestination;
- }
- EASTDC_API char16_t* Strcat(char16_t* pDestination, const char16_t* pSource)
- {
- const char16_t* s = pSource;
- char16_t* d = pDestination;
- while(*d++){} // Do nothing.
- --d;
- while((*d++ = *s++) != 0)
- {} // Do nothing.
-
- return pDestination;
- }
- EASTDC_API char32_t* Strcat(char32_t* pDestination, const char32_t* pSource)
- {
- const char32_t* s = pSource;
- char32_t* d = pDestination;
- while(*d++){} // Do nothing.
- --d;
- while((*d++ = *s++) != 0)
- {} // Do nothing.
- return pDestination;
- }
- EASTDC_API char* Strncat(char* pDestination, const char* pSource, size_t n)
- {
- const char* s = pSource;
- char* d = pDestination;
-
- while(*d++){} // Do nothing.
- --d;
- ++n;
- while(--n)
- {
- if((*d++ = *s++) == 0)
- {
- --d;
- break;
- }
- }
- *d = 0;
-
- return pDestination;
- }
- EASTDC_API char16_t* Strncat(char16_t* pDestination, const char16_t* pSource, size_t n)
- {
- const char16_t* s = pSource;
- char16_t* d = pDestination;
-
- while(*d++){} // Do nothing.
- --d;
- ++n;
- while(--n)
- {
- if((*d++ = *s++) == 0)
- {
- --d;
- break;
- }
- }
- *d = 0;
-
- return pDestination;
- }
- EASTDC_API char32_t* Strncat(char32_t* pDestination, const char32_t* pSource, size_t n)
- {
- const char32_t* s = pSource;
- char32_t* d = pDestination;
-
- while(*d++){} // Do nothing.
- --d;
- ++n;
- while(--n)
- {
- if((*d++ = *s++) == 0)
- {
- --d;
- break;
- }
- }
- *d = 0;
-
- return pDestination;
- }
- EASTDC_API char* StringnCat(char* pDestination, const char* pSource, size_t n)
- {
- char* const pOriginalDest = pDestination;
- if(n)
- {
- while(*pDestination)
- ++pDestination;
- while(n-- && *pSource)
- *pDestination++ = *pSource++;
- *pDestination = 0;
- }
- return pOriginalDest;
- }
- EASTDC_API char16_t* StringnCat(char16_t* pDestination, const char16_t* pSource, size_t n)
- {
- char16_t* const pOriginalDest = pDestination;
- if(n)
- {
- while(*pDestination)
- ++pDestination;
- while(n-- && *pSource)
- *pDestination++ = *pSource++;
- *pDestination = 0;
- }
- return pOriginalDest;
- }
- EASTDC_API char32_t* StringnCat(char32_t* pDestination, const char32_t* pSource, size_t n)
- {
- char32_t* const pOriginalDest = pDestination;
- if(n)
- {
- while(*pDestination)
- ++pDestination;
- while(n-- && *pSource)
- *pDestination++ = *pSource++;
- *pDestination = 0;
- }
- return pOriginalDest;
- }
- EASTDC_API size_t Strlcat(char* pDestination, const char* pSource, size_t nDestCapacity)
- {
- const size_t d = nDestCapacity ? Strlen(pDestination) : 0;
- const size_t s = Strlen(pSource);
- const size_t t = s + d;
- EA_ASSERT_MSG((nDestCapacity == 0) || (d < nDestCapacity), "Destination string is longer than the specified capacity! "
- "Either an out of bounds write has occurred previous to this call or the specified capacity is incorrect.");
- if(t < nDestCapacity)
- memcpy(pDestination + d, pSource, (s + 1) * sizeof(*pSource));
- else
- {
- if(nDestCapacity)
- {
- memcpy(pDestination + d, pSource, ((nDestCapacity - d) - 1) * sizeof(*pSource));
- pDestination[nDestCapacity - 1] = 0;
- }
- }
- return t;
- }
- EASTDC_API size_t Strlcat(char16_t* pDestination, const char16_t* pSource, size_t nDestCapacity)
- {
- const size_t d = nDestCapacity ? Strlen(pDestination) : 0;
- const size_t s = Strlen(pSource);
- const size_t t = s + d;
- EA_ASSERT_MSG((nDestCapacity == 0) || (d < nDestCapacity), "Destination string is longer than the specified capacity! "
- "Either an out of bounds write has occurred previous to this call or the specified capacity is incorrect.");
- if(t < nDestCapacity)
- memcpy(pDestination + d, pSource, (s + 1) * sizeof(*pSource));
- else
- {
- if(nDestCapacity)
- {
- memcpy(pDestination + d, pSource, ((nDestCapacity - d) - 1) * sizeof(*pSource));
- pDestination[nDestCapacity - 1] = 0;
- }
- }
- return t;
- }
- EASTDC_API size_t Strlcat(char32_t* pDestination, const char32_t* pSource, size_t nDestCapacity)
- {
- const size_t d = nDestCapacity ? Strlen(pDestination) : 0;
- const size_t s = Strlen(pSource);
- const size_t t = s + d;
- EA_ASSERT_MSG((nDestCapacity == 0) || (d < nDestCapacity), "Destination string is longer than the specified capacity! "
- "Either an out of bounds write has occurred previous to this call or the specified capacity is incorrect.");
- if(t < nDestCapacity)
- memcpy(pDestination + d, pSource, (s + 1) * sizeof(*pSource));
- else
- {
- if(nDestCapacity)
- {
- memcpy(pDestination + d, pSource, ((nDestCapacity - d) - 1) * sizeof(*pSource));
- pDestination[nDestCapacity - 1] = 0;
- }
- }
- return t;
- }
- EASTDC_API size_t Strlcat(char16_t* pDestination, const char* pSource, size_t nDestCapacity)
- {
- size_t sourceLen = StrlenUTF8Decoded(pSource);
- size_t destLen = Strlen(pDestination);
- if(nDestCapacity > destLen)
- Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
-
- return sourceLen + destLen;
- }
- EASTDC_API size_t Strlcat(char32_t* pDestination, const char* pSource, size_t nDestCapacity)
- {
- size_t sourceLen = StrlenUTF8Decoded(pSource);
- size_t destLen = Strlen(pDestination);
- if(nDestCapacity > destLen)
- Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
-
- return sourceLen + destLen;
- }
- EASTDC_API size_t Strlcat(char* pDestination, const char16_t* pSource, size_t nDestCapacity)
- {
- size_t sourceLen = Strlen(pSource);
- size_t destLen = StrlenUTF8Decoded(pDestination);
- if(nDestCapacity > destLen)
- Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
-
- return sourceLen + destLen;
- }
- EASTDC_API size_t Strlcat(char* pDestination, const char32_t* pSource, size_t nDestCapacity)
- {
- size_t sourceLen = Strlen(pSource);
- size_t destLen = StrlenUTF8Decoded(pDestination);
- if(nDestCapacity > destLen)
- Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
-
- return sourceLen + destLen;
- }
- EASTDC_API size_t Strlcat(char16_t* pDestination, const char32_t* pSource, size_t nDestCapacity)
- {
- size_t sourceLen = Strlen(pSource);
- size_t destLen = Strlen(pDestination);
- if(nDestCapacity > destLen)
- Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
-
- return sourceLen + destLen;
- }
- EASTDC_API size_t Strlcat(char32_t* pDestination, const char16_t* pSource, size_t nDestCapacity)
- {
- size_t sourceLen = Strlen(pSource);
- size_t destLen = Strlen(pDestination);
- if(nDestCapacity > destLen)
- Strlcpy(pDestination + destLen, pSource, nDestCapacity - destLen);
-
- return sourceLen + destLen;
- }
- // Optimized Strlen
- //
- // This function assumes that we can read the last size_t-sized word at
- // the end of the string, even if as many as three of the word bytes are
- // beyond the end of the string. This is typically a valid assumption
- // because valid memory is always aligned to big power-of-2 sizes.
- //
- // Tests of this Strlen show that it outperforms the basic strlen
- // implementation by 2x-6x on lengths ranging from 128 bytes to 4096 bytes.
- // At lengths under 10 bytes this strlen performs similarly to strlen.
- // These observations apply to x86, x64 and PowerPC32 platforms.
- //
- // There could be faster strlen implementations with some additional
- // tricks, asm, SSE, etc. But this version works well while being simple.
- #if EASTDC_STATIC_ANALYSIS_ENABLED
- #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.
- #else
- #define EASTDC_ENABLE_OPTIMIZED_STRLEN 1
- #endif
- #if EASTDC_ENABLE_OPTIMIZED_STRLEN
- EASTDC_API size_t Strlen(const char* pString)
- {
- #if EA_COMPILER_HAS_BUILTIN(__builtin_strlen)
- return __builtin_strlen(pString);
- #else
- // Instead of casting between types, we just create a union.
- union PointerUnion
- {
- const char* mp8;
- const word_type* mpW;
- uintptr_t mU;
- } pu;
- // Leading unaligned bytes
- for(pu.mp8 = pString; pu.mU & (sizeof(word_type) - 1); pu.mp8++)
- {
- if(*pu.mp8 == 0)
- return (size_t)(pu.mp8 - pString);
- }
- for(; ; pu.mpW++)
- {
- #if defined(__GNUC__) && (__GNUC__ >= 3) && !defined(__EDG_VERSION__)
- __builtin_prefetch(pu.mpW + 64, 0, 0);
- #endif
- // Quit if there are any zero chars.
- const word_type kOneBytes = ((word_type)-1 / 0xff); // 0x01010101
- const word_type kHighBytes = (kOneBytes * 0x80); // 0x80808080
- const word_type u = *pu.mpW;
- if((u - kOneBytes) & ~u & kHighBytes)
- break;
- }
- // Trailing unaligned bytes
- while(*pu.mp8)
- ++pu.mp8;
- return (size_t)(pu.mp8 - pString);
- #endif
- }
- #else
- EASTDC_API size_t Strlen(const char* pString)
- {
- ssize_t nLength = (size_t)-1; // EABase 1.0.14 and later recognize ssize_t for all platforms.
- do
- {
- ++nLength;
- } while (*pString++);
- return (size_t)nLength;
- }
- #endif
- #if EASTDC_ENABLE_OPTIMIZED_STRLEN
- EASTDC_API size_t Strlen(const char16_t* pString)
- {
- // Instead of casting between types, we just create a union.
- union PointerUnion
- {
- const char16_t* mp16;
- const word_type* mpW;
- uintptr_t mU;
- } pu;
- // Leading unaligned bytes
- for(pu.mp16 = pString; pu.mU & (sizeof(word_type) - 1); pu.mp16++)
- {
- if(*pu.mp16 == 0)
- return (size_t)(pu.mp16 - pString);
- }
- for(; ; pu.mpW++)
- {
- #if defined(__GNUC__) && (__GNUC__ >= 3) && !defined(__EDG_VERSION__)
- __builtin_prefetch(pu.mpW + 64, 0, 0);
- #endif
- // Quit if there are any zero char16_ts.
- const word_type kOneBytes = ((word_type)-1 / 0xffff); // 0x00010001
- const word_type kHighBytes = (kOneBytes * 0x8000); // 0x80008000
- const word_type u = *pu.mpW;
- if((u - kOneBytes) & ~u & kHighBytes)
- break;
- }
- // Trailing unaligned bytes
- while(*pu.mp16)
- ++pu.mp16;
- return (size_t)(pu.mp16 - pString);
- }
- #else
- EASTDC_API size_t Strlen(const char16_t* pString)
- {
- size_t nLength = (size_t)-1;
- do
- {
- ++nLength;
- } while (*pString++);
- return nLength;
- }
- #endif
- // To consider: This might benefit from an optimized implementation on machines withi 64 bit registers.
- EASTDC_API size_t Strlen(const char32_t* pString)
- {
- size_t nLength = (size_t)-1;
-
- do{
- ++nLength;
- }while(*pString++);
-
- return nLength;
- }
- // Returns number of Unicode characters are in the UTF8-encoded string.
- // Return value will be <= Strlen(pString).
- EASTDC_API size_t StrlenUTF8Decoded(const char* pString)
- {
- size_t nLength = 0;
- while(*pString)
- {
- if((*pString & 0xc0) != 0x80)
- ++nLength;
- ++pString;
- }
- return nLength;
- }
- // Returns number of characters that would be in a UTF8-encoded string.
- // Return value will be >= Strlen(pString).
- EASTDC_API size_t StrlenUTF8Encoded(const char16_t* pString)
- {
- size_t nLength = 0;
- uint32_t c;
- while((c = *pString++) != 0)
- {
- if(c < 0x00000080)
- nLength += 1;
- else if(c < 0x00000800)
- nLength += 2;
- else // if(c < 0x00010000)
- nLength += 3;
- // The following would be used if the input string was 32 bit instead of 16 bit.
- //else if(c < 0x00200000)
- // destCount += 4;
- //else // Else we use the error char 0xfffd
- // destCount += 3;
- }
- return nLength;
- }
- // Returns number of characters that would be in a UTF8-encoded string.
- // Return value will be >= Strlen(pString).
- EASTDC_API size_t StrlenUTF8Encoded(const char32_t* pString)
- {
- size_t nLength = 0;
- uint32_t c;
- while((c = *pString++) != 0)
- {
- if(c < 0x00000080)
- nLength += 1;
- else if(c < 0x00000800)
- nLength += 2;
- else // if(c < 0x00010000)
- nLength += 3;
- // The following would be used if the input string was 32 bit instead of 32 bit.
- //else if(c < 0x00200000)
- // destCount += 4;
- //else // Else we use the error char 0xfffd
- // destCount += 3;
- }
- return nLength;
- }
- EASTDC_API char* Strend(const char* pString)
- {
- while (*pString)
- ++pString;
- return (char*)pString;
- }
- EASTDC_API char16_t* Strend(const char16_t* pString)
- {
- while (*pString)
- ++pString;
- return (char16_t*)pString;
- }
- EASTDC_API char32_t* Strend(const char32_t* pString)
- {
- while(*pString)
- ++pString;
- return (char32_t*)pString;
- }
- EASTDC_API size_t Strxfrm(char* pDest, const char* pSource, size_t n)
- {
- const size_t nLength = Strlen(pSource);
- if(n > 0)
- {
- Strncpy(pDest, pSource, n - 1);
- if(n < nLength)
- pDest[n - 1] = 0;
- }
- return nLength;
- }
- EASTDC_API size_t Strxfrm(char16_t* pDest, const char16_t* pSource, size_t n)
- {
- const size_t nLength = Strlen(pSource);
- if(n > 0)
- {
- Strncpy(pDest, pSource, n - 1);
- if(n < nLength)
- pDest[n - 1] = 0;
- }
- return nLength;
- }
- EASTDC_API size_t Strxfrm(char32_t* pDest, const char32_t* pSource, size_t n)
- {
- const size_t nLength = Strlen(pSource);
- if(n > 0)
- {
- Strncpy(pDest, pSource, n - 1);
- if(n < nLength)
- pDest[n - 1] = 0;
- }
- return nLength;
- }
- EASTDC_API char* Strdup(const char* pString)
- {
- if(pString)
- {
- const size_t nLength = Strlen(pString);
- char* const p = EASTDC_NEW(EASTDC_ALLOC_PREFIX "Strdup") char[nLength + 1]; // '+ 1' to include terminating zero.
- Strcpy(p, pString);
- return p;
- }
- return NULL;
- }
- EASTDC_API char16_t* Strdup(const char16_t* pString)
- {
- if(pString)
- {
- const size_t nLength = Strlen(pString);
- char16_t* const p = EASTDC_NEW(EASTDC_ALLOC_PREFIX "Strdup") char16_t[nLength + 1]; // '+ 1' to include terminating zero.
- Strcpy(p, pString);
- return p;
- }
- return NULL;
- }
- EASTDC_API char32_t* Strdup(const char32_t* pString)
- {
- if(pString)
- {
- const size_t nLength = Strlen(pString);
- char32_t* const p = EASTDC_NEW(EASTDC_ALLOC_PREFIX "Strdup") char32_t[nLength + 1]; // '+ 1' to include terminating zero.
- Strcpy(p, pString);
- return p;
- }
- return NULL;
- }
- EASTDC_API void Strdel(char* pString)
- {
- EASTDC_DELETE[] pString;
- }
- EASTDC_API void Strdel(char16_t* pString)
- {
- EASTDC_DELETE[] pString;
- }
- EASTDC_API void Strdel(char32_t* pString)
- {
- EASTDC_DELETE[] pString;
- }
- EASTDC_API char* Strupr(char* pString)
- {
- // This implementation converts only 7 bit ASCII characters.
- // As such it is safe to use with 7-bit-safe multibyte encodings
- // such as UTF8 but may yield incorrect results with such text.
- char* pStringTemp = pString;
- while(*pStringTemp)
- {
- if((uint8_t)*pStringTemp <= 127)
- *pStringTemp = (char)Toupper(*pStringTemp);
- ++pStringTemp;
- }
- return pString;
- }
- EASTDC_API char16_t* Strupr(char16_t* pString)
- {
- char16_t* pStringTemp = pString;
- while(*pStringTemp)
- {
- const char16_t c = *pStringTemp;
- *pStringTemp++ = Toupper(c);
- }
- return pString;
- }
- EASTDC_API char32_t* Strupr(char32_t* pString)
- {
- char32_t* pStringTemp = pString;
- while(*pStringTemp)
- {
- const char32_t c = *pStringTemp;
- *pStringTemp++ = Toupper(c);
- }
- return pString;
- }
- EASTDC_API char* Strlwr(char* pString)
- {
- // This implementation converts only 7 bit ASCII characters.
- // As such it is safe to use with 7-bit-safe multibyte encodings
- // such as UTF8 but may yield incorrect results with such text.
- char* pStringTemp = pString;
- while(*pStringTemp)
- {
- if((uint8_t)*pStringTemp <= 127)
- *pStringTemp = (char)Tolower(*pStringTemp);
- ++pStringTemp;
- }
- return pString;
- }
- EASTDC_API char16_t* Strlwr(char16_t* pString)
- {
- char16_t* pStringTemp = pString;
- while(*pStringTemp)
- {
- const char16_t c = *pStringTemp;
- *pStringTemp++ = Tolower(c);
- }
- return pString;
- }
- EASTDC_API char32_t* Strlwr(char32_t* pString)
- {
- char32_t* pStringTemp = pString;
- while(*pStringTemp)
- {
- const char32_t c = *pStringTemp;
- *pStringTemp++ = Tolower(c);
- }
- return pString;
- }
- EASTDC_API char* Strmix(char* pDestination, const char* pSource, const char* pDelimiters)
- {
- bool bCapitalize = true;
- char* const pOriginalDest = pDestination;
- while(*pSource)
- {
- char c = *pSource++;
- // This character is upper-cased if bCapitalize flag is true, else lower-cased
- if(bCapitalize)
- {
- if(Islower(c))
- {
- c = Toupper(c);
- bCapitalize = false;
- }
- else if(Isupper(c))
- bCapitalize = false;
- }
- else
- {
- if(Isupper(c))
- c = Tolower(c);
- }
- // Check whether this character is a separator character. If so, set the bCapitalize flag.
- for(const char* pCheck = pDelimiters; *pCheck; ++pCheck)
- {
- if(c == *pCheck)
- bCapitalize = true;
- }
- *pDestination++ = c;
- }
- *pDestination = 0;
- return pOriginalDest;
- }
- EASTDC_API char16_t* Strmix(char16_t* pDestination, const char16_t* pSource, const char16_t* pDelimiters)
- {
- bool bCapitalize = true;
- char16_t* const pOriginalDest = pDestination;
- while(*pSource)
- {
- char16_t c = *pSource++;
- // This character is upper-cased if bCapitalize flag is true, else lower-cased
- if(bCapitalize)
- {
- if(Islower(c))
- {
- c = Toupper(c);
- bCapitalize = false;
- }
- else if(Isupper(c))
- bCapitalize = false;
- }
- else
- {
- if(Isupper(c))
- c = Tolower(c);
- }
- // Check whether this character is a separator character. If so, set the bCapitalize flag.
- for(const char16_t* pCheck = pDelimiters; *pCheck; ++pCheck)
- {
- if(c == *pCheck)
- bCapitalize = true;
- }
- *pDestination++ = c;
- }
- *pDestination = 0;
- return pOriginalDest;
- }
- EASTDC_API char32_t* Strmix(char32_t* pDestination, const char32_t* pSource, const char32_t* pDelimiters)
- {
- bool bCapitalize = true;
- char32_t* const pOriginalDest = pDestination;
- while(*pSource)
- {
- char32_t c = *pSource++;
- // This character is upper-cased if bCapitalize flag is true, else lower-cased
- if(bCapitalize)
- {
- if(Islower(c))
- {
- c = Toupper(c);
- bCapitalize = false;
- }
- else if(Isupper(c))
- bCapitalize = false;
- }
- else
- {
- if(Isupper(c))
- c = Tolower(c);
- }
- // Check whether this character is a separator character. If so, set the bCapitalize flag.
- for(const char32_t* pCheck = pDelimiters; *pCheck; ++pCheck)
- {
- if(c == *pCheck)
- bCapitalize = true;
- }
- *pDestination++ = c;
- }
- *pDestination = 0;
- return pOriginalDest;
- }
- EASTDC_API char* Strchr(const char* pString, int c)
- {
- do
- {
- if (*pString == c)
- return (char*)pString;
- } while (*pString++);
- return NULL;
- }
- EASTDC_API char16_t* Strchr(const char16_t* pString, char16_t c)
- {
- do
- {
- if (*pString == c)
- return (char16_t*)pString;
- } while (*pString++);
- return NULL;
- }
- EASTDC_API char32_t* Strchr(const char32_t* pString, char32_t c)
- {
- do {
- if(*pString == c)
- return (char32_t*)pString;
- } while (*pString++);
- return NULL;
- }
- EASTDC_API char* Strnchr(const char* pString, int c, size_t n)
- {
- while(n-- > 0)
- {
- if(*pString == c)
- {
- return (char*)pString;
- }
- if(*pString == '\0')
- {
- return NULL;
- }
- pString++;
- }
- return NULL;
- }
- EASTDC_API char16_t* Strnchr(const char16_t* pString, char16_t c, size_t n)
- {
- while(n-- > 0)
- {
- if(*pString == c)
- {
- return (char16_t*)pString;
- }
- if(*pString == '\0')
- {
- return NULL;
- }
- pString++;
- }
- return NULL;
- }
- EASTDC_API char32_t* Strnchr(const char32_t* pString, char32_t c, size_t n)
- {
- while(n-- > 0)
- {
- if(*pString == c)
- {
- return (char32_t*)pString;
- }
- if(*pString == '\0')
- {
- return NULL;
- }
- pString++;
- }
- return NULL;
- }
- EASTDC_API size_t Strcspn(const char* pString1, const char* pString2)
- {
- const char* pStringCurrent = pString1;
- // This implementation does a double loop. As such, it can get slow for
- // very long strings. An alternative implementation is to use a hash
- // table or to create a bytemap of the chars in pString2.
- while(*pStringCurrent)
- {
- for(const char* pCharSet = pString2; *pCharSet; ++pCharSet)
- {
- if(*pCharSet == *pStringCurrent)
- return (size_t)(pStringCurrent - pString1);
- }
- ++pStringCurrent;
- }
- return (size_t)(pStringCurrent - pString1);
- }
- EASTDC_API size_t Strcspn(const char16_t* pString1, const char16_t* pString2)
- {
- const char16_t* pStringCurrent = pString1;
- // This implementation does a double loop. As such, it can get slow for
- // very long strings. An alternative implementation is to use a hash
- // table or to create a bytemap of the chars in pString2. But char16_t
- // means that the map would have to be 65536 bits (8192 bytes) in size.
- while(*pStringCurrent)
- {
- for(const char16_t* pCharSet = pString2; *pCharSet; ++pCharSet)
- {
- if(*pCharSet == *pStringCurrent)
- return (size_t)(pStringCurrent - pString1);
- }
- ++pStringCurrent;
- }
- return (size_t)(pStringCurrent - pString1);
- }
- EASTDC_API size_t Strcspn(const char32_t* pString1, const char32_t* pString2)
- {
- const char32_t* pStringCurrent = pString1;
- // This implementation does a double loop. As such, it can get slow for
- // very long strings. An alternative implementation is to use a hash
- // table or to create a bytemap of the chars in pString2. But char32_t
- // means that the map would have to be huge in size.
- while(*pStringCurrent)
- {
- for(const char32_t* pCharSet = pString2; *pCharSet; ++pCharSet)
- {
- if(*pCharSet == *pStringCurrent)
- return (size_t)(pStringCurrent - pString1);
- }
- ++pStringCurrent;
- }
- return (size_t)(pStringCurrent - pString1);
- }
- EASTDC_API char* Strpbrk(const char* pString1, const char* pString2)
- {
- // This implementation does a double loop. As such, it can get slow for
- // very long strings. An alternative implementation is to use a hash
- // table or to create a bytemap of the chars in pString2.
- while(*pString1)
- {
- for(const char* pCharSet = pString2; *pCharSet; ++pCharSet)
- {
- if(*pCharSet == *pString1)
- return (char*)pString1;
- }
- ++pString1;
- }
- return NULL;
- }
- EASTDC_API char16_t* Strpbrk(const char16_t* pString1, const char16_t* pString2)
- {
- // This implementation does a double loop. As such, it can get slow for
- // very long strings. An alternative implementation is to use a hash
- // table or to create a bytemap of the chars in pString2. But char16_t
- // means that the map would have to be 65536 bits (8192 bytes) in size.
- while(*pString1)
- {
- for(const char16_t* pCharSet = pString2; *pCharSet; ++pCharSet)
- {
- if(*pCharSet == *pString1)
- return (char16_t*)pString1;
- }
- ++pString1;
- }
- return NULL;
- }
- EASTDC_API char32_t* Strpbrk(const char32_t* pString1, const char32_t* pString2)
- {
- // This implementation does a double loop. As such, it can get slow for
- // very long strings. An alternative implementation is to use a hash
- // table or to create a bytemap of the chars in pString2. But char32_t
- // means that the map would have to be huge in size.
- while(*pString1)
- {
- for(const char32_t* pCharSet = pString2; *pCharSet; ++pCharSet)
- {
- if(*pCharSet == *pString1)
- return (char32_t*)pString1;
- }
- ++pString1;
- }
- return NULL;
- }
- EASTDC_API char* Strrchr(const char* pString, int c)
- {
- const char* pFound = NULL;
- char cCurrent;
- while ((cCurrent = *pString++) != 0)
- {
- if (cCurrent == c)
- pFound = (pString - 1);
- }
- if (pFound)
- return (char*)pFound;
- return c ? NULL : (char*)(pString - 1);
- }
- EASTDC_API char16_t* Strrchr(const char16_t* pString, char16_t c)
- {
- const char16_t* pFound = NULL;
- char16_t cCurrent;
- while ((cCurrent = *pString++) != 0)
- {
- if (cCurrent == c)
- pFound = (pString - 1);
- }
- if (pFound)
- return (char16_t*)pFound;
- return c ? NULL : (char16_t*)(pString - 1);
- }
- EASTDC_API char32_t* Strrchr(const char32_t* pString, char32_t c)
- {
- const char32_t* pFound = NULL;
- char32_t cCurrent;
- while ((cCurrent = *pString++) != 0)
- {
- if (cCurrent == c)
- pFound = (pString - 1);
- }
- if (pFound)
- return (char32_t*)pFound;
- return c ? NULL : (char32_t*)(pString - 1);
- }
- EASTDC_API size_t Strspn(const char* pString, const char* pSubString)
- {
- // This implementation does a double loop. As such, it can get slow for
- // very long strings. An alternative implementation is to use a hash
- // table or to create a bytemap of the chars in pString2.
- const char* pStringCurrent = pString;
- while(*pStringCurrent)
- {
- for(const char* pSubStringCurrent = pSubString; *pSubStringCurrent != *pStringCurrent; ++pSubStringCurrent)
- {
- if(*pSubStringCurrent == 0)
- return (size_t)(pStringCurrent - pString);
- }
- ++pStringCurrent;
- }
- return (size_t)(pStringCurrent - pString);
- }
- EASTDC_API size_t Strspn(const char16_t* pString, const char16_t* pSubString)
- {
- // This implementation does a double loop. As such, it can get slow for
- // very long strings. An alternative implementation is to use a hash
- // table or to create a bytemap of the chars in pString2. But char16_t
- // means that the map would have to be 65536 bits (8192 bytes) in size.
- const char16_t* pStringCurrent = pString;
- while(*pStringCurrent)
- {
- for(const char16_t* pSubStringCurrent = pSubString; *pSubStringCurrent != *pStringCurrent; ++pSubStringCurrent)
- {
- if(*pSubStringCurrent == 0)
- return (size_t)(pStringCurrent - pString);
- }
- ++pStringCurrent;
- }
- return (size_t)(pStringCurrent - pString);
- }
- EASTDC_API size_t Strspn(const char32_t* pString, const char32_t* pSubString)
- {
- // This implementation does a double loop. As such, it can get slow for
- // very long strings. An alternative implementation is to use a hash
- // table or to create a bytemap of the chars in pString2. But char32_t
- // means that the map would have to be huge in size.
- const char32_t* pStringCurrent = pString;
- while(*pStringCurrent)
- {
- for(const char32_t* pSubStringCurrent = pSubString; *pSubStringCurrent != *pStringCurrent; ++pSubStringCurrent)
- {
- if(*pSubStringCurrent == 0)
- return (size_t)(pStringCurrent - pString);
- }
- ++pStringCurrent;
- }
- return (size_t)(pStringCurrent - pString);
- }
- EASTDC_API char* Strstr(const char* pString, const char* pSubString)
- {
- char* s1 = (char*)pString - 1;
- char* p1 = (char*)pSubString - 1;
- char c0, c1, c2;
- if((c0 = *++p1) == 0) // An empty pSubString results in success, return pString.
- return (char*)pString;
- while((c1 = *++s1) != 0)
- {
- if(c1 == c0)
- {
- const char* s2 = (s1 - 1);
- const char* p2 = (p1 - 1);
-
- while((c1 = *++s2) == (c2 = *++p2) && c1){} // Do nothing
- if(!c2)
- return (char*)s1;
- }
- }
- return NULL;
- }
- EASTDC_API char16_t* Strstr(const char16_t* pString, const char16_t* pSubString)
- {
- char16_t* s1 = (char16_t*)pString - 1;
- char16_t* p1 = (char16_t*)pSubString - 1;
- char16_t c0, c1, c2;
- if((c0 = *++p1) == 0) // An empty pSubString results in success, return pString.
- return (char16_t*)pString;
- while((c1 = *++s1) != 0)
- {
- if(c1 == c0)
- {
- const char16_t* s2 = (s1 - 1);
- const char16_t* p2 = (p1 - 1);
-
- while((c1 = *++s2) == (c2 = *++p2) && c1){} // Do nothing
- if(!c2)
- return (char16_t*)s1;
- }
- }
- return NULL;
- }
- EASTDC_API char32_t* Strstr(const char32_t* pString, const char32_t* pSubString)
- {
- char32_t* s1 = (char32_t*)pString - 1;
- char32_t* p1 = (char32_t*)pSubString - 1;
- char32_t c0, c1, c2;
- if((c0 = *++p1) == 0) // An empty pSubString results in success, return pString.
- return (char32_t*)pString;
- while((c1 = *++s1) != 0)
- {
- if(c1 == c0)
- {
- const char32_t* s2 = (s1 - 1);
- const char32_t* p2 = (p1 - 1);
-
- while((c1 = *++s2) == (c2 = *++p2) && c1){} // Do nothing
- if(!c2)
- return (char32_t*)s1;
- }
- }
- return NULL;
- }
- EASTDC_API char* Stristr(const char* s1, const char* s2)
- {
- const char* cp = s1;
- if(!*s2)
- return (char*)s1;
- while(*cp)
- {
- const char* s = cp;
- const char* t = s2;
- while(*s && *t && (Tolower(*s) == Tolower(*t)))
- ++s, ++t;
- if(*t == 0)
- return (char*)cp;
- ++cp;
- }
- return 0;
- }
- EASTDC_API char16_t* Stristr(const char16_t* s1, const char16_t* s2)
- {
- const char16_t* cp = s1;
- if(!*s2)
- return (char16_t*)s1;
- while(*cp)
- {
- const char16_t* s = cp;
- const char16_t* t = s2;
- while(*s && *t && (Tolower(*s) == Tolower(*t)))
- ++s, ++t;
- if(*t == 0)
- return (char16_t*)cp;
- ++cp;
- }
- return 0;
- }
- EASTDC_API char32_t* Stristr(const char32_t* s1, const char32_t* s2)
- {
- const char32_t* cp = s1;
- if(!*s2)
- return (char32_t*)s1;
- while(*cp)
- {
- const char32_t* s = cp;
- const char32_t* t = s2;
- while(*s && *t && (Tolower(*s) == Tolower(*t)))
- ++s, ++t;
- if(*t == 0)
- return (char32_t*)cp;
- ++cp;
- }
- return 0;
- }
- EASTDC_API char* Strrstr(const char* s1, const char* s2)
- {
- if(!*s2)
- return (char*)s1;
- const char* ps1 = s1 + Strlen(s1);
- while(ps1 != s1)
- {
- const char* psc1 = --ps1;
- const char* sc2 = s2;
- for(;;)
- {
- if(*psc1++ != *sc2++)
- break;
- else if(!*sc2)
- return (char*)ps1;
- }
- }
- return 0;
- }
- EASTDC_API char16_t* Strrstr(const char16_t* s1, const char16_t* s2)
- {
- if(!*s2)
- return (char16_t*)s1;
- const char16_t* ps1 = s1 + Strlen(s1);
- while(ps1 != s1)
- {
- const char16_t* psc1 = --ps1;
- const char16_t* sc2 = s2;
- for(;;)
- {
- if(*psc1++ != *sc2++)
- break;
- else if(!*sc2)
- return (char16_t*)ps1;
- }
- }
- return 0;
- }
- EASTDC_API char32_t* Strrstr(const char32_t* s1, const char32_t* s2)
- {
- if(!*s2)
- return (char32_t*)s1;
- const char32_t* ps1 = s1 + Strlen(s1);
- while(ps1 != s1)
- {
- const char32_t* psc1 = --ps1;
- const char32_t* sc2 = s2;
- for(;;)
- {
- if(*psc1++ != *sc2++)
- break;
- else if(!*sc2)
- return (char32_t*)ps1;
- }
- }
- return 0;
- }
- EASTDC_API char* Strirstr(const char* s1, const char* s2)
- {
- if(!*s2)
- return (char*)s1;
- const char* ps1 = s1 + Strlen(s1);
- while(ps1 != s1)
- {
- const char* psc1 = --ps1;
- const char* sc2 = s2;
- for(;;)
- {
- if(Tolower(*psc1++) != Tolower(*sc2++))
- break;
- else if(!*sc2)
- return (char*)ps1;
- }
- }
- return 0;
- }
- EASTDC_API char16_t* Strirstr(const char16_t* s1, const char16_t* s2)
- {
- if(!*s2)
- return (char16_t*)s1;
- const char16_t* ps1 = s1 + Strlen(s1);
- while(ps1 != s1)
- {
- const char16_t* psc1 = --ps1;
- const char16_t* sc2 = s2;
- for(;;)
- {
- if(Tolower(*psc1++) != Tolower(*sc2++))
- break;
- else if(!*sc2)
- return (char16_t*)ps1;
- }
- }
- return 0;
- }
- EASTDC_API char32_t* Strirstr(const char32_t* s1, const char32_t* s2)
- {
- if(!*s2)
- return (char32_t*)s1;
- const char32_t* ps1 = s1 + Strlen(s1);
- while(ps1 != s1)
- {
- const char32_t* psc1 = --ps1;
- const char32_t* sc2 = s2;
- for(;;)
- {
- if(Tolower(*psc1++) != Tolower(*sc2++))
- break;
- else if(!*sc2)
- return (char32_t*)ps1;
- }
- }
- return 0;
- }
- EASTDC_API bool Strstart(const char* pString, const char* pPrefix)
- {
- while(*pPrefix)
- {
- if(*pString++ != *pPrefix++)
- return false;
- }
- return true;
- }
- EASTDC_API bool Strstart(const char16_t* pString, const char16_t* pPrefix)
- {
- while(*pPrefix)
- {
- if(*pString++ != *pPrefix++)
- return false;
- }
- return true;
- }
- EASTDC_API bool Strstart(const char32_t* pString, const char32_t* pPrefix)
- {
- while(*pPrefix)
- {
- if(*pString++ != *pPrefix++)
- return false;
- }
- return true;
- }
- EASTDC_API bool Stristart(const char* pString, const char* pPrefix)
- {
- while(*pPrefix)
- {
- if(Tolower(*pString++) != Tolower(*pPrefix++))
- return false;
- }
- return true;
- }
- EASTDC_API bool Stristart(const char16_t* pString, const char16_t* pPrefix)
- {
- while(*pPrefix)
- {
- if(Tolower(*pString++) != Tolower(*pPrefix++))
- return false;
- }
- return true;
- }
- EASTDC_API bool Stristart(const char32_t* pString, const char32_t* pPrefix)
- {
- while(*pPrefix)
- {
- if(Tolower(*pString++) != Tolower(*pPrefix++))
- return false;
- }
- return true;
- }
- EASTDC_API bool Strend(const char* pString, const char* pSuffix, size_t stringLength, size_t suffixLength)
- {
- if(stringLength == kSizeTypeUnset)
- stringLength = Strlen(pString);
- if(suffixLength == kSizeTypeUnset)
- suffixLength = Strlen(pSuffix);
- if(stringLength >= suffixLength)
- return Memcmp(pString + stringLength - suffixLength, pSuffix, suffixLength * sizeof(char)) == 0;
- return false;
- }
- EASTDC_API bool Strend(const char16_t* pString, const char16_t* pSuffix, size_t stringLength, size_t suffixLength)
- {
- if(stringLength == kSizeTypeUnset)
- stringLength = Strlen(pString);
- if(suffixLength == kSizeTypeUnset)
- suffixLength = Strlen(pSuffix);
- if(stringLength >= suffixLength)
- return Memcmp(pString + stringLength - suffixLength, pSuffix, suffixLength * sizeof(char16_t)) == 0;
- return false;
- }
- EASTDC_API bool Strend(const char32_t* pString, const char32_t* pSuffix, size_t stringLength, size_t suffixLength)
- {
- if(stringLength == kSizeTypeUnset)
- stringLength = Strlen(pString);
- if(suffixLength == kSizeTypeUnset)
- suffixLength = Strlen(pSuffix);
- if(stringLength >= suffixLength)
- return Memcmp(pString + stringLength - suffixLength, pSuffix, suffixLength * sizeof(char32_t)) == 0;
- return false;
- }
- EASTDC_API bool Striend(const char* pString, const char* pSuffix, size_t stringLength, size_t suffixLength)
- {
- if(stringLength == kSizeTypeUnset)
- stringLength = Strlen(pString);
- if(suffixLength == kSizeTypeUnset)
- suffixLength = Strlen(pSuffix);
- if(stringLength >= suffixLength)
- return Stricmp(pString + stringLength - suffixLength, pSuffix) == 0;
- return false;
- }
- EASTDC_API bool Striend(const char16_t* pString, const char16_t* pSuffix, size_t stringLength, size_t suffixLength)
- {
- if(stringLength == kSizeTypeUnset)
- stringLength = Strlen(pString);
- if(suffixLength == kSizeTypeUnset)
- suffixLength = Strlen(pSuffix);
- if(stringLength >= suffixLength)
- return Stricmp(pString + stringLength - suffixLength, pSuffix) == 0;
- return false;
- }
- EASTDC_API bool Striend(const char32_t* pString, const char32_t* pSuffix, size_t stringLength, size_t suffixLength)
- {
- if(stringLength == kSizeTypeUnset)
- stringLength = Strlen(pString);
- if(suffixLength == kSizeTypeUnset)
- suffixLength = Strlen(pSuffix);
- if(stringLength >= suffixLength)
- return Stricmp(pString + stringLength - suffixLength, pSuffix) == 0;
- return false;
- }
- ///////////////////////////////////////////////////////////////////
- // This function was implemented by Avery Lee.
- //
- EASTDC_API char* Strtok(char* pString, const char* pDelimiters, char** pContext)
- {
- // find point on string to resume
- char* s = pString;
- if(!s)
- {
- s = *pContext;
- if(!s)
- return NULL;
- }
- // Compute bit hash based on lower 5 bits of delimiter characters
- const char* d = pDelimiters;
- int32_t hash = 0;
- uint32_t delimiterCount = 0;
- while(const char c = *d++)
- {
- hash |= (int32_t)(0x80000000 >> (c & 31));
- ++delimiterCount;
- }
- // Skip delimiters
- for(;;)
- {
- const char c = *s;
- // If we hit the end of the string, it ends solely with delimiters
- // and there are no more tokens to get.
- if(!c)
- {
- *pContext = NULL;
- return NULL;
- }
- // Fast rejection against hash set
- if(int32_t(uint64_t(hash) << (c & 31)) >= 0)
- break;
- // brute-force search against delimiter list
- for(uint32_t i=0; i<delimiterCount; ++i)
- {
- if (pDelimiters[i] == c) // Is it a delimiter? ...
- goto still_delimiters; // yes, continue the loop
- }
- // Not a token, so exit
- break;
- still_delimiters:
- ++s;
- }
- // Mark beginning of token
- char* const pToken = s;
- // Search for end of token
- while(const char c = *s)
- {
- // Fast rejection against hash set
- if(int32_t(int64_t(hash) << (c & 31)) < 0)
- {
- // Brute-force search against delimiter list
- for(uint32_t i=0; i<delimiterCount; ++i)
- {
- if(pDelimiters[i] == c)
- {
- // This token ends with a delimiter.
- *s = 0; // null-term substring
- *pContext = (s + 1); // restart on next byte
- return pToken; // return found token
- }
- }
- }
- ++s;
- }
- // We found a token but it was at the end of the string,
- // so we null out the context and return the last token.
- *pContext = NULL; // no more tokens
- return pToken; // return found token
- }
- EASTDC_API char16_t* Strtok(char16_t* pString, const char16_t* pDelimiters, char16_t** pContext)
- {
- // Find point on string to resume
- char16_t* s = pString;
- if(!s)
- {
- s = *pContext;
- if(!s)
- return NULL;
- }
- // compute bit hash based on lower 5 bits of delimiter characters
- const char16_t* d = pDelimiters;
- int32_t hash = 0;
- uint32_t delimiterCount = 0;
- while(const char16_t c = *d++)
- {
- hash |= (int32_t)(0x80000000 >> (c & 31));
- ++delimiterCount;
- }
- // Skip delimiters
- for(;;)
- {
- const char16_t c = *s;
- // If we hit the end of the string, it ends solely with delimiters
- // and there are no more tokens to get.
- if(!c)
- {
- *pContext = NULL;
- return NULL;
- }
- // Fast rejection against hash set
- if(int32_t(int64_t(hash) << (c & 31)) >= 0)
- break;
- // Brute-force search against delimiter list
- for(uint32_t i=0; i<delimiterCount; ++i)
- {
- if(pDelimiters[i] == (char16_t)c) // Is it a delimiter? ...
- goto still_delimiters; // yes, continue the loop
- }
- // Not a token, so exit
- break;
- still_delimiters:
- ++s;
- }
- // Mark beginning of token
- char16_t* const pToken = s;
- // Search for end of token
- while(const char16_t c = *s)
- {
- // Fast rejection against hash set
- if(int32_t(int64_t(hash) << (c & 31)) < 0)
- {
- // Brute-force search against delimiter list
- for(uint32_t i=0; i<delimiterCount; ++i)
- {
- if(pDelimiters[i] == c)
- {
- // This token ends with a delimiter.
- *s = 0; // null-term substring
- *pContext = (s + 1); // restart on next byte
- return pToken; // return found token
- }
- }
- }
- ++s;
- }
- // We found a token but it was at the end of the string,
- // so we null out the context and return the last token.
- *pContext = NULL; // no more tokens
- return pToken; // return found token
- }
- EASTDC_API char32_t* Strtok(char32_t* pString, const char32_t* pDelimiters, char32_t** pContext)
- {
- // Find point on string to resume
- char32_t* s = pString;
- if(!s)
- {
- s = *pContext;
- if(!s)
- return NULL;
- }
- // compute bit hash based on lower 5 bits of delimiter characters
- const char32_t* d = pDelimiters;
- int32_t hash = 0;
- uint32_t delimiterCount = 0;
- while(const uint32_t c = (uint32_t)*d++)
- {
- hash |= (int32_t)(0x80000000 >> (c & 31));
- ++delimiterCount;
- }
- // Skip delimiters
- for(;;)
- {
- const char32_t c = *s;
- // If we hit the end of the string, it ends solely with delimiters
- // and there are no more tokens to get.
- if(!c)
- {
- *pContext = NULL;
- return NULL;
- }
- // Fast rejection against hash set
- if(int32_t(int64_t(hash) << (c & 31)) >= 0)
- break;
- // Brute-force search against delimiter list
- for(uint32_t i=0; i<delimiterCount; ++i)
- {
- if(pDelimiters[i] == c) // Is it a delimiter? ...
- goto still_delimiters; // yes, continue the loop
- }
- // Not a token, so exit
- break;
- still_delimiters:
- ++s;
- }
- // Mark beginning of token
- char32_t* const pToken = s;
- // Search for end of token
- while(const uint32_t c = (uint32_t)*s)
- {
- // Fast rejection against hash set
- if(int32_t(int64_t(hash) << (c & 31)) < 0)
- {
- // Brute-force search against delimiter list
- for(uint32_t i=0; i<delimiterCount; ++i)
- {
- if(pDelimiters[i] == (char32_t)c)
- {
- // This token ends with a delimiter.
- *s = 0; // null-term substring
- *pContext = (s + 1); // restart on next byte
- return pToken; // return found token
- }
- }
- }
- ++s;
- }
- // We found a token but it was at the end of the string,
- // so we null out the context and return the last token.
- *pContext = NULL; // no more tokens
- return pToken; // return found token
- }
- EASTDC_API const char* Strtok2(const char* pString, const char* pDelimiters,
- size_t* pResultLength, bool bFirst)
- {
- // Skip any non-delimiters
- if(!bFirst)
- {
- while(*pString && !Strchr(pDelimiters, *pString))
- ++pString;
- }
- // Skip any delimiters
- while(*pString && Strchr(pDelimiters, *pString))
- ++pString;
- const char* const pBegin = pString;
- // Calculate the length of the string
- while(*pString && !Strchr(pDelimiters, *pString))
- ++pString;
- if(pBegin != pString)
- {
- *pResultLength = static_cast<size_t>(pString - pBegin);
- return pBegin;
- }
- *pResultLength = 0;
- return NULL;
- }
- EASTDC_API const char16_t* Strtok2(const char16_t* pString, const char16_t* pDelimiters, size_t* pResultLength, bool bFirst)
- {
- // Skip any non-delimiters
- if(!bFirst)
- {
- while(*pString && !Strchr(pDelimiters, *pString))
- ++pString;
- }
- // Skip any delimiters
- while(*pString && Strchr(pDelimiters, *pString))
- ++pString;
- const char16_t* const pBegin = pString;
- // Calculate the length of the string
- while(*pString && !Strchr(pDelimiters, *pString))
- ++pString;
- if(pBegin != pString)
- {
- *pResultLength = static_cast<size_t>(pString - pBegin);
- return pBegin;
- }
- *pResultLength = 0;
- return NULL;
- }
- EASTDC_API const char32_t* Strtok2(const char32_t* pString, const char32_t* pDelimiters, size_t* pResultLength, bool bFirst)
- {
- // Skip any non-delimiters
- if(!bFirst)
- {
- while(*pString && !Strchr(pDelimiters, *pString))
- ++pString;
- }
- // Skip any delimiters
- while(*pString && Strchr(pDelimiters, *pString))
- ++pString;
- const char32_t* const pBegin = pString;
- // Calculate the length of the string
- while(*pString && !Strchr(pDelimiters, *pString))
- ++pString;
- if(pBegin != pString)
- {
- *pResultLength = static_cast<size_t>(pString - pBegin);
- return pBegin;
- }
- *pResultLength = 0;
- return NULL;
- }
- EASTDC_API char* Strset(char* pString, int c)
- {
- char* pStringTemp = pString;
- while(*pStringTemp)
- *pStringTemp++ = (char)c;
- return pString;
- }
- EASTDC_API char16_t* Strset(char16_t* pString, char16_t c)
- {
- char16_t* pStringTemp = pString;
- while(*pStringTemp)
- *pStringTemp++ = c;
- return pString;
- }
- EASTDC_API char32_t* Strset(char32_t* pString, char32_t c)
- {
- char32_t* pStringTemp = pString;
- while(*pStringTemp)
- *pStringTemp++ = c;
- return pString;
- }
- EASTDC_API char* Strnset(char* pString, int c, size_t n)
- {
- char* pSaved = pString;
- for(size_t i = 0; *pString && (i < n); ++i)
- *pString++ = (char)c;
- return pSaved;
- }
- EASTDC_API char16_t* Strnset(char16_t* pString, char16_t c, size_t n)
- {
- char16_t* pSaved = pString;
- for(size_t i = 0; *pString && (i < n); ++i)
- *pString++ = c;
- return pSaved;
- }
- EASTDC_API char32_t* Strnset(char32_t* pString, char32_t c, size_t n)
- {
- char32_t* pSaved = pString;
- for(size_t i = 0; *pString && (i < n); ++i)
- *pString++ = c;
- return pSaved;
- }
- EASTDC_API char* Strrev(char* pString)
- {
- for(char* p1 = pString, *p2 = (pString + Strlen(pString)) - 1; p1 < p2; ++p1, --p2)
- {
- char c = *p2;
- *p2 = *p1;
- *p1 = c;
- }
- return pString;
- }
- EASTDC_API char16_t* Strrev(char16_t* pString)
- {
- for(char16_t* p1 = pString, *p2 = (pString + Strlen(pString)) - 1; p1 < p2; ++p1, --p2)
- {
- char16_t c = *p2;
- *p2 = *p1;
- *p1 = c;
- }
- return pString;
- }
- EASTDC_API char32_t* Strrev(char32_t* pString)
- {
- for(char32_t* p1 = pString, *p2 = (pString + Strlen(pString)) - 1; p1 < p2; ++p1, --p2)
- {
- char32_t c = *p2;
- *p2 = *p1;
- *p1 = c;
- }
- return pString;
- }
- EASTDC_API char* Strstrip(char* pString)
- {
- // Walk forward from the beginning and find the first non-whitespace.
- while(EA::StdC::Isspace(*pString)) // Isspace returns false for *pString == '\0'.
- ++pString;
- if(*pString)
- {
- // Walk backward from the end and find the last whitespace.
- size_t length = EA::StdC::Strlen(pString);
- char* pEnd = (pString + length) - 1;
- while((pEnd > pString) && EA::StdC::Isspace(*pEnd))
- pEnd--;
- pEnd[1] = '\0';
- }
- return pString;
- }
- EASTDC_API char16_t* Strstrip(char16_t* pString)
- {
- // Walk forward from the beginning and find the first non-whitespace.
- while(EA::StdC::Isspace(*pString)) // Isspace returns false for *pString == '\0'.
- ++pString;
- if(*pString)
- {
- // Walk backward from the end and find the last whitespace.
- size_t length = EA::StdC::Strlen(pString);
- char16_t* pEnd = (pString + length) - 1;
- while((pEnd > pString) && EA::StdC::Isspace(*pEnd))
- pEnd--;
- pEnd[1] = '\0';
- }
- return pString;
- }
- EASTDC_API char32_t* Strstrip(char32_t* pString)
- {
- // Walk forward from the beginning and find the first non-whitespace.
- while(EA::StdC::Isspace(*pString)) // Isspace returns false for *pString == '\0'.
- ++pString;
- if(*pString)
- {
- // Walk backward from the end and find the last whitespace.
- size_t length = EA::StdC::Strlen(pString);
- char32_t* pEnd = (pString + length) - 1;
- while((pEnd > pString) && EA::StdC::Isspace(*pEnd))
- pEnd--;
- pEnd[1] = '\0';
- }
- return pString;
- }
- // Optimized Strcmp
- //
- // This function assumes that we can read the last size_t-sized word at
- // the end of the string, even if as many as three of the word bytes are
- // beyond the end of the string. This is typically a valid assumption
- // because valid memory is always aligned to big power-of-2 sizes.
- //
- // There could be faster strcmp implementations with some additional
- // tricks, asm, SSE, etc. But this version works well while being simple.
- // To do: Implement a vector-specific version for at least x64-based platforms.
- #if EASTDC_STATIC_ANALYSIS_ENABLED
- #define EASTDC_ENABLE_OPTIMIZED_STRCMP 0 // Disabled because the optimized strcmp reads words and the string may have some uninitialized chars at the
- #else // end past the trailing 0 char. Valgrind reports this as an error, but it's not actually an error in practice.
- #define EASTDC_ENABLE_OPTIMIZED_STRCMP 1
- #endif
- #if EASTDC_ENABLE_OPTIMIZED_STRCMP
- #if defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_OSX)
- // Some platforms have an optimized vector implementation of strcmp which is fast and which provides
- // identical return value behavior to our Strcmp (which is to return the byte difference and not just
- // -1, 0, +1). And so until we have our own vectored version we use the built-in version.
- EASTDC_API int Strcmp(const char* pString1, const char* pString2)
- {
- return strcmp(pString1, pString2);
- }
- #else
- // To do: Implement an x86/x64 vectorized version of Strcmp, which can work on 16 byte chunks and thus be faster than below.
- EASTDC_API int Strcmp(const char* pString1, const char* pString2)
- {
- if(IsAligned<const char, sizeof(word_type)>(pString1) && // If pString1 and pString2 are word-aligned... compare in word-sized chunks.
- IsAligned<const char, sizeof(word_type)>(pString2))
- {
- const word_type* pWord1 = (word_type*)pString1;
- const word_type* pWord2 = (word_type*)pString2;
- while(*pWord1 == *pWord2)
- {
- if(ZeroPresent8(*pWord1++))
- return 0;
- ++pWord2;
- }
- // At this point, the strings differ somewhere in the bytes pointed to by pWord1/pWord2.
- pString1 = reinterpret_cast<const char*>(pWord1); // Fall through and do byte comparisons for the rest of the string.
- pString2 = reinterpret_cast<const char*>(pWord2);
- }
- while(*pString1 && (*pString1 == *pString2))
- {
- ++pString1;
- ++pString2;
- }
- return ((uint8_t)*pString1 - (uint8_t)*pString2);
- }
- #endif
- #else
- EASTDC_API int Strcmp(const char* pString1, const char* pString2)
- {
- char c1, c2;
- while((c1 = *pString1++) == (c2 = *pString2++))
- {
- if(c1 == 0)
- return 0;
- }
- return ((uint8_t)c1 - (uint8_t)c2);
- }
- #endif
- #if EASTDC_ENABLE_OPTIMIZED_STRCMP
- // To do: Implement an x86/x64 vectorized version of Strcmp, which can work on 16 byte chunks and thus be faster than below.
- EASTDC_API int Strcmp(const char16_t* pString1, const char16_t* pString2)
- {
- if(IsAligned<const char16_t, sizeof(word_type)>(pString1) && // If pString1 and pString2 are word-aligned... compare in word-sized chunks.
- IsAligned<const char16_t, sizeof(word_type)>(pString2))
- {
- const word_type* pWord1 = (word_type*)pString1;
- const word_type* pWord2 = (word_type*)pString2;
- while(*pWord1 == *pWord2)
- {
- if(ZeroPresent16(*pWord1++))
- return 0;
- ++pWord2;
- }
- // At this point, the strings differ somewhere in the bytes pointed to by pWord1/pWord2.
- pString1 = reinterpret_cast<const char16_t*>(pWord1); // Fall through and do byte comparisons for the rest of the string.
- pString2 = reinterpret_cast<const char16_t*>(pWord2);
- }
- while(*pString1 && (*pString1 == *pString2))
- {
- ++pString1;
- ++pString2;
- }
- return ((uint16_t)*pString1 - (uint16_t)*pString2);
- }
- #else
- EASTDC_API int Strcmp(const char16_t* pString1, const char16_t* pString2)
- {
- char16_t c1, c2;
- while((c1 = *pString1++) == (c2 = *pString2++))
- {
- if(c1 == 0) // If we've reached the end of the string with no difference...
- return 0;
- }
- EA_COMPILETIME_ASSERT(sizeof(int) > sizeof(uint16_t));
- return ((uint16_t)c1 - (uint16_t)c2);
- }
- #endif
- EASTDC_API int Strcmp(const char32_t* pString1, const char32_t* pString2)
- {
- char32_t c1, c2;
- while((c1 = *pString1++) == (c2 = *pString2++))
- {
- if(c1 == 0) // If we've reached the end of the string with no difference...
- return 0;
- }
- // We can't just return c1 - c2, because the difference might be greater than INT_MAX.
- return ((uint32_t)c1 > (uint32_t)c2) ? 1 : -1;
- }
- #if EASTDC_ENABLE_OPTIMIZED_STRCMP
- // Some platforms have an optimized vector implementation of strncmp which is fast and which provides
- // identical return value behavior to our Strncmp (which is to return the byte difference and not just
- // -1, 0, +1). And so until we have our own vectored version we use the built-in version.
- EASTDC_API int Strncmp(const char* pString1, const char* pString2, size_t n)
- {
- return strncmp(pString1, pString2, n);
- }
- // To do: Implement a general portable version of a more optimized Strncmp.
- #else
- EASTDC_API int Strncmp(const char* pString1, const char* pString2, size_t n)
- {
- char c1, c2;
- ++n;
- while(--n)
- {
- if((c1 = *pString1++) != (c2 = *pString2++))
- return ((uint8_t)c1 - (uint8_t)c2);
- else if(c1 == 0)
- break;
- }
-
- return 0;
- }
- #endif
- EASTDC_API int Strncmp(const char16_t* pString1, const char16_t* pString2, size_t n)
- {
- char16_t c1, c2;
- // Code below which uses (c1 - c2) assumes this.
- EA_COMPILETIME_ASSERT(sizeof(int) > sizeof(uint16_t));
- ++n;
- while(--n)
- {
- if((c1 = *pString1++) != (c2 = *pString2++))
- return ((uint16_t)c1 - (uint16_t)c2);
- else if(c1 == 0)
- break;
- }
-
- return 0;
- }
- EASTDC_API int Strncmp(const char32_t* pString1, const char32_t* pString2, size_t n)
- {
- char32_t c1, c2;
- ++n;
- while(--n)
- {
- if((c1 = *pString1++) != (c2 = *pString2++))
- {
- // We can't just return c1 - c2, because the difference might be greater than INT_MAX.
- return ((uint32_t)c1 > (uint32_t)c2) ? 1 : -1;
- }
- else if(c1 == 0)
- break;
- }
- return 0;
- }
- #if EASTDC_ENABLE_OPTIMIZED_STRCMP && (defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_OSX))
- // Some platforms have an optimized vector implementation of stricmp/strcasecmp which is fast and which provides
- // identical return value behavior to our Stricmp (which is to return the byte difference and not just
- // -1, 0, +1). And so until we have our own vectored version we use the built-in version.
- EASTDC_API int Stricmp(const char* pString1, const char* pString2)
- {
- return strcasecmp(pString1, pString2);
- }
- // To do: Implement a general portable version of a more optimized Stricmp.
- #else
- EASTDC_API int Stricmp(const char* pString1, const char* pString2)
- {
- char c1, c2;
- while((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++)))
- {
- if(c1 == 0)
- return 0;
- }
- return ((uint8_t)c1 - (uint8_t)c2);
- }
- #endif
- EASTDC_API int Stricmp(const char16_t* pString1, const char16_t* pString2)
- {
- char16_t c1, c2;
- while((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++)))
- {
- if(c1 == 0)
- return 0;
- }
- // Code below which uses (c1 - c2) assumes this.
- EA_COMPILETIME_ASSERT(sizeof(int) > sizeof(uint16_t));
- return ((uint16_t)c1 - (uint16_t)c2);
- }
- EASTDC_API int Stricmp(const char32_t* pString1, const char32_t* pString2)
- {
- char32_t c1, c2;
- while((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++)))
- {
- if(c1 == 0)
- return 0;
- }
- // We can't just return c1 - c2, because the difference might be greater than INT_MAX.
- return ((uint32_t)c1 > (uint32_t)c2) ? 1 : -1;
- }
- EASTDC_API int Strnicmp(const char* pString1, const char* pString2, size_t n)
- {
- char c1, c2;
- ++n;
- while(--n)
- {
- if((c1 = Tolower(*pString1++)) != (c2 = Tolower(*pString2++)))
- return ((uint8_t)c1 - (uint8_t)c2);
- else if(c1 == 0)
- break;
- }
-
- return 0;
- }
- EASTDC_API int Strnicmp(const char16_t* pString1, const char16_t* pString2, size_t n)
- {
- char16_t c1, c2;
- // Code below which uses (c1 - c2) assumes this.
- EA_COMPILETIME_ASSERT(sizeof(int) > sizeof(uint16_t));
- ++n;
- while(--n)
- {
- if((c1 = Tolower(*pString1++)) != (c2 = Tolower(*pString2++)))
- return ((uint16_t)c1 - (uint16_t)c2);
- else if(c1 == 0)
- break;
- }
-
- return 0;
- }
- EASTDC_API int Strnicmp(const char32_t* pString1, const char32_t* pString2, size_t n)
- {
- char32_t c1, c2;
- ++n;
- while(--n)
- {
- if((c1 = Tolower(*pString1++)) != (c2 = Tolower(*pString2++)))
- {
- // We can't just return c1 - c2, because the difference might be greater than INT_MAX.
- return ((uint32_t)c1 > (uint32_t)c2) ? 1 : -1;
- }
- else if(c1 == 0)
- break;
- }
-
- return 0;
- }
- // *** this function is deprecated. ***
- EASTDC_API int StrcmpAlnum(const char* pString1, const char* pString2)
- {
- char c1, c2;
- const char* pStart1 = pString1;
- const char* pStart2 = pString2;
- const char* pDigitStart1 = pString1;
- while(((c1 = *pString1++) == (c2 = *pString2++)) && c1)
- {
- if(!Isdigit(c1))
- pDigitStart1 = pString1;
- }
- const int c1d = Isdigit(c1);
- const int c2d = Isdigit(c2);
- if(c1d && c2d)
- return (int)StrtoI32(pDigitStart1, NULL, 10) - (int)StrtoI32(pStart2 + (pDigitStart1 - pStart1), NULL, 10);
- if(c1d != c2d) // If one char is decimal and the other is not..
- return c1d ? 1 : -1;
- return ((uint8_t)c1 - (uint8_t)c2);
- }
- // *** this function is deprecated. ***
- EASTDC_API int StrcmpAlnum(const char16_t* pString1, const char16_t* pString2)
- {
- char16_t c1, c2;
- const char16_t* pStart1 = pString1;
- const char16_t* pStart2 = pString2;
- const char16_t* pDigitStart1 = pString1;
- while(((c1 = *pString1++) == (c2 = *pString2++)) && c1)
- {
- if(!Isdigit(c1))
- pDigitStart1 = pString1;
- }
- const int c1d = Isdigit(c1);
- const int c2d = Isdigit(c2);
- if(c1d && c2d)
- return (int)StrtoI32(pDigitStart1, NULL, 10) - (int)StrtoI32(pStart2 + (pDigitStart1 - pStart1), NULL, 10);
- if(c1d != c2d) // If one char is decimal and the other is not..
- return c1d ? 1 : -1;
- return ((uint16_t)c1 - (uint16_t)c2);
- }
- // *** this function is deprecated. ***
- EASTDC_API int StricmpAlnum(const char* pString1, const char* pString2)
- {
- char c1, c2;
- const char* pStart1 = pString1;
- const char* pStart2 = pString2;
- const char* pDigitStart1 = pString1;
- while(((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++))) && c1)
- {
- if(!Isdigit(c1))
- pDigitStart1 = pString1;
- }
- const int c1d = Isdigit(c1);
- const int c2d = Isdigit(c2);
- if(c1d && c2d)
- return (int)StrtoI32(pDigitStart1, NULL, 10) - (int)StrtoI32(pStart2 + (pDigitStart1 - pStart1), NULL, 10);
- if(c1d != c2d) // If one char is decimal and the other is not..
- return c1d ? 1 : -1;
- return ((uint8_t)c1 - (uint8_t)c2);
- }
- // *** this function is deprecated. ***
- EASTDC_API int StricmpAlnum(const char16_t* pString1, const char16_t* pString2)
- {
- char16_t c1, c2;
- const char16_t* pStart1 = pString1;
- const char16_t* pStart2 = pString2;
- const char16_t* pDigitStart1 = pString1;
- while(((c1 = Tolower(*pString1++)) == (c2 = Tolower(*pString2++))) && c1)
- {
- if(!Isdigit(c1))
- pDigitStart1 = pString1;
- }
- const int c1d = Isdigit(c1);
- const int c2d = Isdigit(c2);
- if(c1d && c2d)
- return (int)StrtoI32(pDigitStart1, NULL, 10) - (int)StrtoI32(pStart2 + (pDigitStart1 - pStart1), NULL, 10);
- if(c1d != c2d) // If one char is decimal and the other is not..
- return c1d ? 1 : -1;
- return ((uint16_t)c1 - (uint16_t)c2);
- }
- EASTDC_API int StrcmpNumeric(const char* pString1, const char* pString2,
- size_t length1, size_t length2,
- char decimal, char thousandsSeparator)
- {
- // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
- EA_UNUSED(pString1);
- EA_UNUSED(pString2);
- EA_UNUSED(length1);
- EA_UNUSED(length2);
- EA_UNUSED(decimal);
- EA_UNUSED(thousandsSeparator);
- return 0;
- }
- EASTDC_API int StrcmpNumeric(const char16_t* pString1, const char16_t* pString2,
- size_t length1, size_t length2,
- char16_t decimal, char16_t thousandsSeparator)
- {
- // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
- EA_UNUSED(pString1);
- EA_UNUSED(pString2);
- EA_UNUSED(length1);
- EA_UNUSED(length2);
- EA_UNUSED(decimal);
- EA_UNUSED(thousandsSeparator);
- return 0;
- }
- EASTDC_API int StrcmpNumeric(const char32_t* pString1, const char32_t* pString2,
- size_t length1, size_t length2,
- char32_t decimal, char32_t thousandsSeparator)
- {
- // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
- EA_UNUSED(pString1);
- EA_UNUSED(pString2);
- EA_UNUSED(length1);
- EA_UNUSED(length2);
- EA_UNUSED(decimal);
- EA_UNUSED(thousandsSeparator);
- return 0;
- }
- EASTDC_API int StricmpNumeric(const char* pString1, const char* pString2,
- size_t length1, size_t length2,
- char decimal, char thousandsSeparator)
- {
- // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
- EA_UNUSED(pString1);
- EA_UNUSED(pString2);
- EA_UNUSED(length1);
- EA_UNUSED(length2);
- EA_UNUSED(decimal);
- EA_UNUSED(thousandsSeparator);
- return 0;
- }
- EASTDC_API int StricmpNumeric(const char16_t* pString1, const char16_t* pString2,
- size_t length1, size_t length2,
- char16_t decimal, char16_t thousandsSeparator)
- {
- // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
- EA_UNUSED(pString1);
- EA_UNUSED(pString2);
- EA_UNUSED(length1);
- EA_UNUSED(length2);
- EA_UNUSED(decimal);
- EA_UNUSED(thousandsSeparator);
- return 0;
- }
- EASTDC_API int StricmpNumeric(const char32_t* pString1, const char32_t* pString2,
- size_t length1, size_t length2,
- char32_t decimal, char32_t thousandsSeparator)
- {
- // To do: Implement this function. Ask Paul Pedriana to implement this if you need it.
- EA_UNUSED(pString1);
- EA_UNUSED(pString2);
- EA_UNUSED(length1);
- EA_UNUSED(length2);
- EA_UNUSED(decimal);
- EA_UNUSED(thousandsSeparator);
- return 0;
- }
- EASTDC_API int Strcoll(const char* pString1, const char* pString2)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Strcmp(pString1, pString2);
- }
- EASTDC_API int Strcoll(const char16_t* pString1, const char16_t* pString2)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Strcmp(pString1, pString2);
- }
- EASTDC_API int Strcoll(const char32_t* pString1, const char32_t* pString2)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Strcmp(pString1, pString2);
- }
- EASTDC_API int Strncoll(const char* pString1, const char* pString2, size_t n)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Strncmp(pString1, pString2, n);
- }
- EASTDC_API int Strncoll(const char16_t* pString1, const char16_t* pString2, size_t n)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Strncmp(pString1, pString2, n);
- }
- EASTDC_API int Strncoll(const char32_t* pString1, const char32_t* pString2, size_t n)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Strncmp(pString1, pString2, n);
- }
- EASTDC_API int Stricoll(const char* pString1, const char* pString2)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Stricmp(pString1, pString2);
- }
- EASTDC_API int Stricoll(const char16_t* pString1, const char16_t* pString2)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Stricmp(pString1, pString2);
- }
- EASTDC_API int Stricoll(const char32_t* pString1, const char32_t* pString2)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Stricmp(pString1, pString2);
- }
- EASTDC_API int Strnicoll(const char* pString1, const char* pString2, size_t n)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Strnicmp(pString1, pString2, n);
- }
- EASTDC_API int Strnicoll(const char16_t* pString1, const char16_t* pString2, size_t n)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Strnicmp(pString1, pString2, n);
- }
- EASTDC_API int Strnicoll(const char32_t* pString1, const char32_t* pString2, size_t n)
- {
- // The user needs to use a localization package to get proper localized collation.
- return Strnicmp(pString1, pString2, n);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // EcvtBuf / FcvtBuf
- //
- #if EASTDC_NATIVE_FCVT
- EASTDC_API char* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char* buffer)
- {
- #ifdef __GNUC__
- const char* const pResult = ecvt(dValue, nDigitCount, decimalPos, sign);
- #else
- const char* const pResult = _ecvt(dValue, nDigitCount, decimalPos, sign);
- #endif
- strcpy(buffer, pResult);
- #if EASTDC_NATIVE_FCVT_SHORT
- // For ecvt, nDigitCount is the resulting length of the buffer of digits, regardless of the decimal point location.
- if(nDigitCount > 15) // The '> 15' part is a quick check to avoid the rest of the code for most cases.
- {
- int len = (int)strlen(buffer);
- while(len < nDigitCount)
- buffer[len++] = '0';
- buffer[len] = 0;
- }
- #endif
- return buffer;
- }
- EASTDC_API char* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char* buffer)
- {
- #ifdef __GNUC__
- const char* const pResult = fcvt(dValue, nDigitCountAfterDecimal, decimalPos, sign);
- #else
- char pResult[_CVTBUFSIZE+1];
- _fcvt_s(pResult, sizeof(pResult), dValue, nDigitCountAfterDecimal, decimalPos, sign);
- #endif
- strcpy(buffer, pResult);
- #if EASTDC_NATIVE_FCVT_SHORT
- // For fcvt, nDigitCount is the resulting length of the buffer of digits after the decimal point location.
- nDigitCountAfterDecimal += *decimalPos;
- if(nDigitCountAfterDecimal > 15) // The '> 15' part is a quick check to avoid the rest of the code for most cases.
- {
- int len = (int)strlen(buffer);
- while(len < nDigitCountAfterDecimal)
- buffer[len++] = '0';
- buffer[len] = 0;
- }
- #endif
- return buffer;
- }
- #else
- #if defined(EA_COMPILER_MSVC)
- #include <float.h>
- #define isnan(x) _isnan(x)
- //#define isinf(x) !_finite(x)
- #endif
- #if !defined(isnan)
- inline bool isnan(double fValue)
- {
- const union {
- double f;
- int64_t i;
- } converter = { fValue };
- // An IEEE real value is a NaN if all exponent bits are one and
- // the mantissa is not zero.
- return (converter.i & ~kFloat64SignMask) > kFloat64ExponentMask;
- }
- #endif
- union DoubleShape
- {
- double mValue;
- uint32_t mUint64;
- #if defined(EA_SYSTEM_LITTLE_ENDIAN)
- struct numberStruct
- {
- unsigned int fraction1 : 32;
- unsigned int fraction0 : 20;
- unsigned int exponent : 11;
- unsigned int sign : 1;
- } mNumber;
- #else
- struct numberStruct
- {
- unsigned int sign : 1;
- unsigned int exponent : 11;
- unsigned int fraction0 : 20;
- unsigned int fraction1 : 32;
- } mNumber;
- #endif
- };
- union FloatShape
- {
- float mValue;
- uint32_t mUint32;
- #if defined(EA_SYSTEM_LITTLE_ENDIAN)
- struct numberStruct
- {
- unsigned int fraction : 23;
- unsigned int exponent : 8;
- unsigned int sign : 1;
- } mNumber;
- #else
- struct numberStruct
- {
- unsigned int sign : 1;
- unsigned int exponent : 8;
- unsigned int fraction : 23;
- } mNumber;
- #endif
- };
- EASTDC_API char* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char* buffer)
- {
- int nDigitCountAfterDecimal;
- double fract;
- double integer;
- double tmp;
- int neg = 0;
- int expcnt = 0;
- char* buf = buffer;
- char* t = buf;
- char* p = buf + kEcvtBufMaxSize - 1;
- char* pbuf = p;
- // We follow the same preconditions as Microsoft does with its _ecvt function.
- EA_ASSERT((nDigitCount >= 0) && (decimalPos != NULL) && (sign != NULL) && (buffer != NULL));
- // assume decimal to left of digits in string
- *decimalPos = 0;
- // To consider: Enable the following.
- //if(nDigitCount > 16) // It turns out that we can't get any more precision than this.
- // nDigitCount = 16; // Any digits beyond 16 would be nearly meaningless.
- if(sizeof(double) == sizeof(float)) // If the user has the compiler set to use doubles that are smaller...
- {
- FloatShape floatShape;
- floatShape.mValue = (float)dValue; // This should be a lossless conversion.
- if(floatShape.mNumber.exponent == 0xff) // If not finite...
- {
- if(floatShape.mUint32 & 0x007fffff) // If is a NAN...
- {
- *t++ = 'N';
- *t++ = 'A';
- *t++ = 'N';
- }
- else
- {
- *t++ = 'I';
- *t++ = 'N';
- *t++ = 'F';
- }
- *t = 0;
- return buffer;
- }
- }
- else
- {
- DoubleShape doubleShape;
- doubleShape.mValue = dValue;
- if(doubleShape.mNumber.exponent == 0x7ff) // If not finite...
- {
- if(isnan(dValue)) // If is a NAN...
- {
- *t++ = 'N';
- *t++ = 'A';
- *t++ = 'N';
- }
- else
- {
- *t++ = 'I';
- *t++ = 'N';
- *t++ = 'F';
- }
- *t = 0;
- return buffer;
- }
- }
- if(dValue < 0)
- {
- neg = 1;
- dValue = -dValue;
- }
- fract = modf(dValue, &integer);
- if(dValue >= 1.0f)
- {
- for(; integer; ++expcnt)
- {
- tmp = modf(integer / 10.0f, &integer);
- *p-- = (char)((int)((tmp + 0.01f) * 10.0f) + '0');
- EA_ASSERT(p >= buffer);
- }
- }
- *t++ = 0; // Extra slot for rounding
- buf += 1; // Point return value to beginning of string.
- int tempExp = expcnt;
- nDigitCountAfterDecimal = nDigitCount - expcnt;
-
- if(expcnt)
- {
- //if expcnt > nDigitCount, need to round the integer part, and reset expcnt
- if(expcnt > nDigitCount)
- {
- pbuf = p + nDigitCount + 1;
- if(*pbuf >= '5')
- {
- do
- {
- pbuf--;
- if(++*pbuf <= '9')
- break;
- *pbuf = '0';
- }
- while(pbuf >= p+1);
- }
- expcnt = nDigitCount;
- fract = 0.0;//no more rounding will be needed down below!
- }
- for(++p; expcnt--;)
- *t++ = *p++;
- }
- if(nDigitCountAfterDecimal >= 0)
- {
- // Per spec, don't actually put decimal in string, just let caller know where it should be...
- *decimalPos = (int)(ptrdiff_t)(t - buf); // Count of chars into string when to place decimal point
- }
- else
- *decimalPos = (int)tempExp;
- bool leading = dValue < 1.0f ? true : false;//for Ecvt, leading zeros need to be omitted and decimalPos needs to be readjusted
- while((nDigitCountAfterDecimal > 0) && fract)
- {
- fract = modf(fract * 10.0f, &tmp);
-
- if(leading && (int)tmp == 0)
- {
- (*decimalPos)--;
- continue;
- }
- else
- {
- leading = false;
- *t++ = (char)((int)tmp + '0');
- nDigitCountAfterDecimal -= 1;
- }
- }
-
- if(fract)
- {
- char* scan = (t - 1);
- // round off the number
- modf(fract * 10.0f, &tmp);
- if(tmp > 4)
- {
- for(; ; --scan)
- {
- if(*scan == '.')
- scan -= 1;
- if(++*scan <= '9')
- break;
- *scan = '0';
- if(scan == buf)
- {
- *--scan = '1';
- buf -= 1; // Rounded into holding spot
- ++*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.
- break;
- }
- }
- }
- else if(neg)
- {
- // fix ("%.3f", -0.0004) giving -0.000
- for( ; ; scan -= 1)
- {
- if(scan <= buf)
- break;
- if(*scan == '.')
- scan -= 1;
- if(*scan != '0')
- break;
- if(scan == buf)
- neg = 0;
- }
- }
- }
-
- if(nDigitCountAfterDecimal<0)//this means the digitcount is smaller than integre part and need to round the integer part
- nDigitCountAfterDecimal = 0;
-
- while(nDigitCountAfterDecimal--)
- *t++ = '0';
- *t++ = 0; // Always terminate the string of digits
- if(*buffer == 0) // If the above rounding place wasn't necessary...
- memmove(buffer, buffer + 1, (size_t)(t - (buffer + 1)));
- *sign = neg ? 1 : 0;
- return buffer;
- }
- EASTDC_API char* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char* buffer)
- {
- double fract;
- double integer;
- double tmp;
- int neg = 0;
- int expcnt = 0;
- char* buf = buffer;
- char* t = buf;
- char* p = buf + kFcvtBufMaxSize - 1;
- // We follow the same preconditions as Microsoft does with its _fcvt function.
- EA_ASSERT((nDigitCountAfterDecimal >= 0) && (decimalPos != NULL) && (sign != NULL) && (buffer != NULL));
- // assume decimal to left of digits in string
- *decimalPos = 0;
- if(sizeof(double) == sizeof(float)) // If the user has the compiler set to use doubles that are smaller...
- {
- FloatShape floatShape;
- floatShape.mValue = (float)dValue; // This should be a lossless conversion.
- if(floatShape.mNumber.exponent == 0xff) // If not finite...
- {
- if(floatShape.mUint32 & 0x007fffff) // If is a NAN...
- {
- *t++ = 'N';
- *t++ = 'A';
- *t++ = 'N';
- }
- else
- {
- *t++ = 'I';
- *t++ = 'N';
- *t++ = 'F';
- }
- *t = 0;
- return buffer;
- }
- }
- else
- {
- DoubleShape doubleShape;
- doubleShape.mValue = dValue;
- if(doubleShape.mNumber.exponent == 0x7ff) // If not finite...
- {
- if(isnan(dValue)) // If is a NAN...
- {
- *t++ = 'N';
- *t++ = 'A';
- *t++ = 'N';
- }
- else
- {
- *t++ = 'I';
- *t++ = 'N';
- *t++ = 'F';
- }
- *t = 0;
- return buffer;
- }
- }
- if(dValue < 0)
- {
- neg = 1;
- dValue = -dValue;
- }
- fract = modf(dValue, &integer);
- if(dValue >= 1.0f)
- {
- for(; integer; ++expcnt)
- {
- tmp = modf(integer / 10.0f, &integer);
- *p-- = (char)((int)((tmp + 0.01f) * 10.0f) + '0');
- EA_ASSERT(p >= buffer);
- }
- }
- *t++ = 0; // Extra slot for rounding
- buf += 1; // Point return value to beginning of string.
-
- if(expcnt)
- {
- for(++p; expcnt--;)
- *t++ = *p++;
- }
- // Per spec, don't actually put decimal in string, just let caller know where it should be...
- *decimalPos = (int)(ptrdiff_t)(t - buf); // Count of chars into string when to place decimal point.
- // We give up trying to calculate fractions beyond 16 digits, which is the maximum possible precision with a double.
- int count = (nDigitCountAfterDecimal <= 16) ? nDigitCountAfterDecimal : 16;
- while(count && fract)
- {
- fract = modf(fract * 10.0f, &tmp);
- *t++ = (char)((int)tmp + '0');
- nDigitCountAfterDecimal--;
- count--;
- }
- if(fract)
- {
- char* scan = (t - 1);
- // round off the number
- modf(fract * 10.0f, &tmp);
- if(tmp > 4)
- {
- for(; ; --scan)
- {
- if(*scan == '.')
- scan -= 1;
- if(++*scan <= '9')
- break;
- *scan = '0';
- if(scan == buf)
- {
- *--scan = '1';
- buf -= 1; // Rounded into holding spot
- ++*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.
- break;
- }
- }
- }
- else if(neg)
- {
- // fix ("%.3f", -0.0004) giving -0.000
- for( ; ; --scan)
- {
- if(scan <= buf)
- break;
- if(*scan == '.')
- scan -= 1;
- if(*scan != '0')
- break;
- if(scan == buf)
- neg = 0;
- }
- }
- }
- while(nDigitCountAfterDecimal--)
- *t++ = '0';
- *t++ = 0; // Always terminate the string of digits
- if(*buffer == 0) // If the above rounding place wasn't necessary...
- memmove(buffer, buffer + 1, (size_t)(t - (buffer + 1)));
- *sign = neg ? 1 : 0;
- return buffer;
- }
- // Matching #undef for each #define above for unity build friendliness.
- #if defined(EA_COMPILER_MSVC)
- #undef isnan
- //#undef isinf
- #endif
- #endif // Compiler support
- EASTDC_API char16_t* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char16_t* buffer)
- {
- // We implement this by calling the 8 bit version and copying its data.
- char pBufferCvt8[kEcvtBufMaxSize];
- char16_t* pCurrent16 = buffer;
- EcvtBuf(dValue, nDigitCount, decimalPos, sign, pBufferCvt8);
- for(char* pCurrent8 = pBufferCvt8; *pCurrent8; ) // Do a 8 bit to 16 bit strcpy.
- *pCurrent16++ = (char16_t)(unsigned char)*pCurrent8++;
- *pCurrent16 = 0;
- return buffer;
- }
- EASTDC_API char32_t* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char32_t* buffer)
- {
- // We implement this by calling the 8 bit version and copying its data.
- char pBufferCvt8[kEcvtBufMaxSize];
- char32_t* pCurrent32 = buffer;
- EcvtBuf(dValue, nDigitCount, decimalPos, sign, pBufferCvt8);
- for(char* pCurrent8 = pBufferCvt8; *pCurrent8; ) // Do a 8 bit to 32 bit strcpy.
- *pCurrent32++ = (char32_t)(unsigned char)*pCurrent8++;
- *pCurrent32 = 0;
- return buffer;
- }
- EASTDC_API char16_t* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char16_t* buffer)
- {
- // We implement this by calling the 8 bit version and copying its data.
- char pBufferCvt8[kEcvtBufMaxSize];
- char16_t* pCurrent16 = buffer;
- FcvtBuf(dValue, nDigitCountAfterDecimal, decimalPos, sign, pBufferCvt8);
- for(char* pCurrent8 = pBufferCvt8; *pCurrent8; ) // Do a 8 bit to 16 bit strcpy.
- *pCurrent16++ = (char16_t)(unsigned char)*pCurrent8++;
- *pCurrent16 = 0;
- return buffer;
- }
- EASTDC_API char32_t* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char32_t* buffer)
- {
- // We implement this by calling the 8 bit version and copying its data.
- char pBufferCvt8[kEcvtBufMaxSize];
- char32_t* pCurrent32 = buffer;
- FcvtBuf(dValue, nDigitCountAfterDecimal, decimalPos, sign, pBufferCvt8);
- for(char* pCurrent8 = pBufferCvt8; *pCurrent8; ) // Do a 8 bit to 32 bit strcpy.
- *pCurrent32++ = (char32_t)(unsigned char)*pCurrent8++;
- *pCurrent32 = 0;
- return buffer;
- }
- // end of EcvtBuf / FcvtBuf
- ////////////////////////////////////////////////////////////////////////////////////
- // Optimization technique:
- // https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
- // This results in performance improvements of 2x to 5x depending on the input value. Our general test in
- // TestString.cpp showed a 3.1x performance gain on VC++/x64.
- //
- static uint32_t digits10(uint64_t v)
- {
- if(v < 10)
- return 1;
- if(v < 100)
- return 2;
- if(v < 1000)
- return 3;
- if(v < UINT64_C(1000000000000))
- {
- if(v < UINT64_C(100000000))
- {
- if(v < 1000000)
- {
- if (v < 10000)
- return 4;
- return (uint32_t)(5 + (v >= 100000));
- }
- return (uint32_t)(7 + (v >= 10000000));
- }
- if(v < UINT64_C(10000000000))
- return (uint32_t)(9 + (v >= UINT64_C(1000000000)));
- return (uint32_t)(11 + (v >= UINT64_C(100000000000)));
- }
- return 12 + digits10(v / UINT64_C(1000000000000));
- }
- char* X64toaCommon10(uint64_t nValue, char* pBuffer)
- {
- static const char digits[201] =
- "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849"
- "5051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899";
- uint32_t length = digits10(nValue);
- uint32_t next = length - 1;
- pBuffer[length] = '\0';
- while(nValue >= 100)
- {
- const uint64_t i = (nValue % 100) * 2;
- nValue /= 100;
- pBuffer[next] = digits[i + 1];
- pBuffer[next - 1] = digits[i];
- next -= 2;
- }
- if (nValue < 10)
- pBuffer[next] = (char)('0' + (uint32_t)nValue);
- else
- {
- const uint32_t i = (uint32_t)nValue * 2;
- pBuffer[next] = digits[i + 1];
- pBuffer[next - 1] = digits[i];
- }
- return pBuffer;
- }
- static char* X64toaCommon(uint64_t nValue, char* pBuffer, int nBase, bool bNegative)
- {
- char* pCurrent = pBuffer;
- if(bNegative)
- *pCurrent++ = '-';
- if(nBase == 10)
- X64toaCommon10(nValue, pCurrent);
- else
- {
- char* pFirstDigit = pCurrent;
- do{
- const unsigned nDigit = (unsigned)(nValue % nBase);
- nValue /= nBase;
- if(nDigit > 9)
- *pCurrent++ = (char)(nDigit - 10 + 'a');
- else
- *pCurrent++ = (char)(nDigit + '0');
- } while(nValue > 0);
- // Need to reverse the string.
- *pCurrent-- = 0;
- do{
- const char cTemp = *pCurrent;
- *pCurrent-- = *pFirstDigit;
- *pFirstDigit++ = cTemp;
- }while(pFirstDigit < pCurrent);
- }
- return pBuffer;
- }
- static char16_t* X64toaCommon(uint64_t nValue, char16_t* pBuffer, int nBase, bool bNegative)
- {
- char16_t* pCurrent = pBuffer;
- if(bNegative)
- *pCurrent++ = '-';
- char16_t* pFirstDigit = pCurrent;
- do{
- const unsigned nDigit = (unsigned)(nValue % nBase);
- nValue /= nBase;
- if(nDigit > 9)
- *pCurrent++ = (char16_t)(nDigit - 10 + 'a');
- else
- *pCurrent++ = (char16_t)(nDigit + '0');
- } while(nValue > 0);
- // Need to reverse the string.
- *pCurrent-- = 0;
- do{
- const char16_t cTemp = *pCurrent;
- *pCurrent-- = *pFirstDigit;
- *pFirstDigit++ = cTemp;
- }while(pFirstDigit < pCurrent);
- return pBuffer;
- }
- static char32_t* X64toaCommon(uint64_t nValue, char32_t* pBuffer, int nBase, bool bNegative)
- {
- char32_t* pCurrent = pBuffer;
- if(bNegative)
- *pCurrent++ = '-';
- char32_t* pFirstDigit = pCurrent;
- do{
- const unsigned nDigit = (unsigned)(nValue % nBase);
- nValue /= nBase;
- if(nDigit > 9)
- *pCurrent++ = (char32_t)(nDigit - 10 + 'a');
- else
- *pCurrent++ = (char32_t)(nDigit + '0');
- } while(nValue > 0);
- // Need to reverse the string.
- *pCurrent-- = 0;
- do{
- const char32_t cTemp = *pCurrent;
- *pCurrent-- = *pFirstDigit;
- *pFirstDigit++ = cTemp;
- }while(pFirstDigit < pCurrent);
- return pBuffer;
- }
- EASTDC_API char* I32toa(int32_t nValue, char* pBuffer, int nBase)
- {
- const bool bNegative = (nValue < 0) && (nBase == 10);
- if(bNegative)
- {
- #if defined(__GNUC__) // -INT32_MIN => INT32_MIN, but with GCC on Android it's acting differently.
- if(nValue != INT32_MIN)
- #endif
- nValue = -nValue;
- }
- return X64toaCommon((uint64_t)(uint32_t)nValue, pBuffer, nBase, bNegative);
- }
- EASTDC_API char16_t* I32toa(int32_t nValue, char16_t* pBuffer, int nBase)
- {
- const bool bNegative = (nValue < 0) && (nBase == 10);
- if(bNegative)
- {
- #if defined(__GNUC__) // -INT32_MIN => INT32_MIN, but with GCC on Android it's acting differently.
- if(nValue != INT32_MIN)
- #endif
- nValue = -nValue;
- }
- return X64toaCommon((uint64_t)(uint32_t)nValue, pBuffer, nBase, bNegative);
- }
- EASTDC_API char32_t* I32toa(int32_t nValue, char32_t* pBuffer, int nBase)
- {
- const bool bNegative = (nValue < 0) && (nBase == 10);
- if(bNegative)
- {
- #if defined(__GNUC__) // -INT32_MIN => INT32_MIN, but with GCC on Android it's acting differently.
- if(nValue != INT32_MIN)
- #endif
- nValue = -nValue;
- }
- return X64toaCommon((uint64_t)(uint32_t)nValue, pBuffer, nBase, bNegative);
- }
- EASTDC_API char* U32toa(uint32_t nValue, char* pBuffer, int nBase)
- {
- return X64toaCommon((uint64_t)nValue, pBuffer, nBase, 0);
- }
- EASTDC_API char16_t* U32toa(uint32_t nValue, char16_t* pBuffer, int nBase)
- {
- return X64toaCommon((uint64_t)nValue, pBuffer, nBase, 0);
- }
- EASTDC_API char32_t* U32toa(uint32_t nValue, char32_t* pBuffer, int nBase)
- {
- return X64toaCommon((uint64_t)nValue, pBuffer, nBase, 0);
- }
- EASTDC_API char* I64toa(int64_t nValue, char* pBuffer, int nBase)
- {
- const bool bNegative = (nValue < 0) && (nBase == 10);
- if(bNegative)
- nValue = -(uint64_t)nValue;
- return X64toaCommon((uint64_t)nValue, pBuffer, nBase, bNegative);
- }
- EASTDC_API char16_t* I64toa(int64_t nValue, char16_t* pBuffer, int nBase)
- {
- const bool bNegative = (nValue < 0) && (nBase == 10);
- if(bNegative)
- nValue = -(uint64_t)nValue;
- return X64toaCommon((uint64_t)nValue, pBuffer, nBase, bNegative);
- }
- EASTDC_API char32_t* I64toa(int64_t nValue, char32_t* pBuffer, int nBase)
- {
- const bool bNegative = (nValue < 0) && (nBase == 10);
- if(bNegative)
- nValue = -(uint64_t)nValue;
- return X64toaCommon((uint64_t)nValue, pBuffer, nBase, bNegative);
- }
- EASTDC_API char* U64toa(uint64_t nValue, char* pBuffer, int nBase)
- {
- return X64toaCommon(nValue, pBuffer, nBase, 0);
- }
- EASTDC_API char16_t* U64toa(uint64_t nValue, char16_t* pBuffer, int nBase)
- {
- return X64toaCommon(nValue, pBuffer, nBase, 0);
- }
- EASTDC_API char32_t* U64toa(uint64_t nValue, char32_t* pBuffer, int nBase)
- {
- return X64toaCommon(nValue, pBuffer, nBase, 0);
- }
- EASTDC_API double StrtodEnglish(const char* pValue, char** ppEnd)
- {
- // This implementation is an exact copy of StrtodEnglish but
- // with char in place of char16_t. For the time being, if
- // you do maintenance on either of these functions, you need to
- // copy the result to the other version.
- int c;
- double dTotal(0.0);
- char chSign('+');
- const char* pEnd = pValue;
- while(Isspace(*pValue))
- ++pValue; //Remove leading spaces.
- pEnd = pValue;
- c = *pValue++;
- if(c == '-' || c == '+'){
- chSign = (char)c;
- pEnd = pValue;
- c = *pValue++;
- }
- while((c >= '0') && (c <= '9')){
- dTotal = (10 * dTotal) + (c - '0');
- pEnd = pValue;
- c = *pValue++;
- }
- if(c == '.'){
- double dMultiplier(1); //Possibly some BCD variable would be more accurate.
- pEnd = pValue;
- c = *pValue++;
- while((c >= '0') && (c <= '9')){
- dMultiplier *= 0.1;
- dTotal += (c - '0') * dMultiplier;
- pEnd = pValue;
- c = *pValue++;
- }
- }
- if(c == 'e' || c == 'E'){
- int nExponentValue(0);
- double dExponentTotal;
- char chExponentSign('+');
- pEnd = pValue;
- c = *pValue++; //Move past the exponent.
- if(c == '-' || c == '+'){
- chExponentSign = (char)c;
- pEnd = pValue;
- c = *pValue++; //Move past the '+' or '-' sign.
- }
- while((c >= '0') && (c <= '9')){
- nExponentValue = (10 * nExponentValue) + (c - '0');
- pEnd = pValue;
- c = *pValue++;
- }
- dExponentTotal = ::pow(10.0, (double)nExponentValue); // The CRT pow function is actually somewhat slow and weak.
- // It would be very nice to change this to at least implement
- if(chExponentSign == '-') // the low exponents with a lookup table.
- dExponentTotal = 1/dExponentTotal;
- dTotal *= dExponentTotal;
- }
- if(ppEnd)
- *ppEnd = (char*)pEnd;
- if(chSign == '-')
- return -dTotal;
- return dTotal;
- }
- EASTDC_API double StrtodEnglish(const char16_t* pValue, char16_t** ppEnd)
- {
- // This implementation is an exact copy of StrtodEnglish8 but
- // with char16_t in place of char. For the time being, if you
- // do maintenance on either of these functions, you need to
- // copy the result to the other version.
- char16_t c;
- double dTotal(0.0);
- char16_t chSign('+');
- const char16_t* pEnd = pValue;
- while(Isspace(*pValue))
- ++pValue; // Remove leading spaces.
- pEnd = pValue;
- c = *pValue++;
- if(c == '-' || c == '+'){
- chSign = (char16_t)c;
- pEnd = pValue;
- c = *pValue++;
- }
- while((c >= '0') && (c <= '9')){
- dTotal = (10 * dTotal) + (c - '0');
- pEnd = pValue;
- c = *pValue++;
- }
- if(c == '.'){
- double dMultiplier(1); // Possibly some BCD variable would be more accurate.
- pEnd = pValue;
- c = *pValue++;
- while((c >= '0') && (c <= '9')){
- dMultiplier *= 0.1;
- dTotal += (c - '0') * dMultiplier;
- pEnd = pValue;
- c = *pValue++;
- }
- }
- if(c == 'e' || c == 'E'){
- int nExponentValue(0);
- double dExponentTotal;
- char16_t chExponentSign('+');
- pEnd = pValue;
- c = *pValue++; //Move past the exponent.
- if(c == '-' || c == '+'){
- chExponentSign = (char16_t)c;
- pEnd = pValue;
- c = *pValue++; // Move past the '+' or '-' sign.
- }
- while((c >= '0') && (c <= '9')){
- nExponentValue = (int)((10 * nExponentValue) + (c - '0'));
- pEnd = pValue;
- c = *pValue++;
- }
- dExponentTotal = ::pow(10.0, (double)nExponentValue); // The CRT pow function is actually somewhat slow and weak.
- // It would be very nice to change this to at least implement
- if(chExponentSign == '-') // the low exponents with a lookup table.
- dExponentTotal = 1/dExponentTotal;
- dTotal *= dExponentTotal;
- }
- if(ppEnd)
- *ppEnd = (char16_t*)pEnd;
- if(chSign == '-')
- return -dTotal;
- return dTotal;
- }
- EASTDC_API double StrtodEnglish(const char32_t* pValue, char32_t** ppEnd)
- {
- // This implementation is an exact copy of StrtodEnglish8 but
- // with char32_t in place of char. For the time being, if you
- // do maintenance on either of these functions, you need to
- // copy the result to the other version.
- char32_t c;
- double dTotal(0.0);
- char32_t chSign('+');
- const char32_t* pEnd = pValue;
- while(Isspace(*pValue))
- ++pValue; // Remove leading spaces.
- pEnd = pValue;
- c = *pValue++;
- if(c == '-' || c == '+'){
- chSign = (char32_t)c;
- pEnd = pValue;
- c = *pValue++;
- }
- while((c >= '0') && (c <= '9')){
- dTotal = (10 * dTotal) + (c - '0');
- pEnd = pValue;
- c = *pValue++;
- }
- if(c == '.'){
- double dMultiplier(1); // Possibly some BCD variable would be more accurate.
- pEnd = pValue;
- c = *pValue++;
- while((c >= '0') && (c <= '9')){
- dMultiplier *= 0.1;
- dTotal += (c - '0') * dMultiplier;
- pEnd = pValue;
- c = *pValue++;
- }
- }
- if(c == 'e' || c == 'E'){
- int nExponentValue(0);
- double dExponentTotal;
- char32_t chExponentSign('+');
- pEnd = pValue;
- c = *pValue++; //Move past the exponent.
- if(c == '-' || c == '+'){
- chExponentSign = (char32_t)c;
- pEnd = pValue;
- c = *pValue++; // Move past the '+' or '-' sign.
- }
- while((c >= '0') && (c <= '9')){
- nExponentValue = (int)((10 * nExponentValue) + (c - '0'));
- pEnd = pValue;
- c = *pValue++;
- }
- dExponentTotal = ::pow(10.0, (double)nExponentValue); // The CRT pow function is actually somewhat slow and weak.
- // It would be very nice to change this to at least implement
- if(chExponentSign == '-') // the low exponents with a lookup table.
- dExponentTotal = 1/dExponentTotal;
- dTotal *= dExponentTotal;
- }
- if(ppEnd)
- *ppEnd = (char32_t*)pEnd;
- if(chSign == '-')
- return -dTotal;
- return dTotal;
- }
- static uint64_t StrtoU64Common(const char* pValue, char** ppEnd, int nBase, bool bUnsigned)
- {
- uint64_t nValue(0); // Current value
- const char* p = pValue; // Current position
- char c; // Temp value
- char chSign('+'); // One of either '+' or '-'
- bool bDigitWasRead(false); // True if any digits were read.
- bool bOverflowOccurred(false); // True if integer overflow occurred.
- // Skip leading whitespace
- c = *p++;
- while(Isspace(c))
- c = *p++;
- // Check for sign.
- if((c == '-') || (c == '+')){
- chSign = c;
- c = *p++;
- }
- // Do checks on nBase.
- if((nBase < 0) || (nBase == 1) || (nBase > 36)){
- if(ppEnd)
- *ppEnd = (char*)pValue;
- return 0;
- }
- else if(nBase == 0){
- // Auto detect one of base 8, 10, or 16.
- if(c != '0')
- nBase = 10;
- else if(*p == 'x' || *p == 'X')
- nBase = 16;
- else
- nBase = 8;
- }
- if(nBase == 16){
- // If there is a leading '0x', then skip past it.
- if((c == '0') && ((*p == 'x') || (*p == 'X'))) {
- ++p;
- c = *p++;
- }
- }
- // If nValue exceeds this, an integer overflow is reported.
- #if (EA_PLATFORM_WORD_SIZE >= 8)
- const uint64_t nMaxValue(UINT64_MAX / nBase);
- const uint64_t nModValue(UINT64_MAX % nBase);
- #else
- // 32 bit platforms are very slow at doing 64 bit div and mod operations.
- uint64_t nMaxValue;
- uint64_t nModValue;
- switch(nBase)
- {
- case 2:
- nMaxValue = UINT64_C(9223372036854775807);
- nModValue = 1;
- break;
- case 8:
- nMaxValue = UINT64_C(2305843009213693951);
- nModValue = 7;
- break;
- case 10:
- nMaxValue = UINT64_C(1844674407370955161);
- nModValue = 5;
- break;
- case 16:
- nMaxValue = UINT64_C(1152921504606846975);
- nModValue = 15;
- break;
- default:
- nMaxValue = (UINT64_MAX / nBase);
- nModValue = (UINT64_MAX % nBase);
- break;
- }
- #endif
- for(unsigned nCurrentDigit; ; ){
- if(Isdigit(c))
- nCurrentDigit = (unsigned)(c - '0');
- else if(Isalpha(c))
- nCurrentDigit = (unsigned)(Toupper(c) - 'A' + 10);
- else
- break; // The digit is invalid.
- if(nCurrentDigit >= (unsigned)nBase)
- break; // The digit is invalid.
- bDigitWasRead = true;
- // Check for overflow.
- if((nValue < nMaxValue) || ((nValue == nMaxValue) && ((uint64_t)nCurrentDigit <= nModValue)))
- nValue = (nValue * nBase) + nCurrentDigit;
- else
- bOverflowOccurred = true; // Set the flag, but continue processing.
- c = *p++;
- }
- --p; // Go back to the last character
- if(!bDigitWasRead){
- if(ppEnd)
- p = pValue; // We'll assign 'ppEnd' below.
- }
- else if(bOverflowOccurred || (!bUnsigned && (((chSign == '-') && (nValue > ((uint64_t)INT64_MAX + 1))) || ((chSign == '+') && (nValue > (uint64_t)INT64_MAX))))){
- // Integer overflow occurred.
- if(bUnsigned)
- nValue = UINT64_MAX;
- else if(chSign == '-')
- nValue = (uint64_t)INT64_MAX + 1; // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
- else
- nValue = INT64_MAX;
- errno = ERANGE; // The standard specifies that we set this value.
- }
- if(ppEnd)
- *ppEnd = (char*)p;
- if(chSign == '-')
- nValue = -nValue;
- return nValue;
- }
- static uint64_t StrtoU64Common(const char16_t* pValue, char16_t** ppEnd, int nBase, bool bUnsigned)
- {
- uint64_t nValue(0); // Current value
- const char16_t* p = pValue; // Current position
- char16_t c; // Temp value
- char16_t chSign('+'); // One of either '+' or '-'
- bool bDigitWasRead(false); // True if any digits were read.
- bool bOverflowOccurred(false); // True if integer overflow occurred.
- // Skip leading whitespace
- c = *p++;
- while(Isspace(c))
- c = *p++;
- // Check for sign.
- if((c == '-') || (c == '+')){
- chSign = c;
- c = *p++;
- }
- // Do checks on nBase.
- if((nBase < 0) || (nBase == 1) || (nBase > 36)){
- if(ppEnd)
- *ppEnd = (char16_t*)pValue;
- return 0;
- }
- else if(nBase == 0){
- // Auto detect one of base 8, 10, or 16.
- if(c != '0')
- nBase = 10;
- else if(*p == 'x' || *p == 'X')
- nBase = 16;
- else
- nBase = 8;
- }
- if(nBase == 16){
- // If there is a leading '0x', then skip past it.
- if((c == '0') && ((*p == 'x') || (*p == 'X'))) {
- ++p;
- c = *p++;
- }
- }
- // If nValue exceeds this, an integer overflow is reported.
- #if (EA_PLATFORM_WORD_SIZE >= 8)
- const uint64_t nMaxValue(UINT64_MAX / nBase);
- const uint64_t nModValue(UINT64_MAX % nBase);
- #else
- // 32 bit platforms are very slow at doing 64 bit div and mod operations.
- uint64_t nMaxValue;
- uint64_t nModValue;
- switch(nBase)
- {
- case 2:
- nMaxValue = UINT64_C(9223372036854775807);
- nModValue = 1;
- break;
- case 8:
- nMaxValue = UINT64_C(2305843009213693951);
- nModValue = 7;
- break;
- case 10:
- nMaxValue = UINT64_C(1844674407370955161);
- nModValue = 5;
- break;
- case 16:
- nMaxValue = UINT64_C(1152921504606846975);
- nModValue = 15;
- break;
- default:
- nMaxValue = (UINT64_MAX / nBase);
- nModValue = (UINT64_MAX % nBase);
- break;
- }
- #endif
- for(unsigned nCurrentDigit; ;){
- if(Isdigit(c))
- nCurrentDigit = (unsigned)(c - '0');
- else if(Isalpha(c))
- nCurrentDigit = (unsigned)(Toupper(c) - 'A' + 10);
- else
- break; // The digit is invalid.
- if(nCurrentDigit >= (unsigned)nBase)
- break; // The digit is invalid.
- bDigitWasRead = true;
- // Check for overflow.
- if((nValue < nMaxValue) || ((nValue == nMaxValue) && ((uint64_t)nCurrentDigit <= nModValue)))
- nValue = (nValue * nBase) + nCurrentDigit;
- else
- bOverflowOccurred = true; // Set the flag, but continue processing.
- c = *p++;
- }
- --p; // Go back to the last character
- if(!bDigitWasRead){
- if(ppEnd)
- p = pValue; // We'll assign 'ppEnd' below.
- } // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
- else if(bOverflowOccurred || (!bUnsigned && (((chSign == '-') && (nValue > ((uint64_t)INT64_MAX + 1))) || ((chSign == '+') && (nValue > (uint64_t)INT64_MAX))))){
- // Integer overflow occurred.
- if(bUnsigned)
- nValue = UINT64_MAX;
- else if(chSign == '-')
- nValue = (uint64_t)INT64_MAX + 1; // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
- else
- nValue = INT64_MAX;
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoU64Common: Range underflow or overflow.");}
- errno = ERANGE; // The standard specifies that we set this value.
- }
- if(ppEnd)
- *ppEnd = (char16_t*)p;
- if(chSign == '-')
- nValue = -nValue;
- return nValue;
- }
- static uint64_t StrtoU64Common(const char32_t* pValue, char32_t** ppEnd, int nBase, bool bUnsigned)
- {
- uint64_t nValue(0); // Current value
- const char32_t* p = pValue; // Current position
- char32_t c; // Temp value
- char32_t chSign('+'); // One of either '+' or '-'
- bool bDigitWasRead(false); // True if any digits were read.
- bool bOverflowOccurred(false); // True if integer overflow occurred.
- // Skip leading whitespace
- c = *p++;
- while(Isspace(c))
- c = *p++;
- // Check for sign.
- if((c == '-') || (c == '+')){
- chSign = c;
- c = *p++;
- }
- // Do checks on nBase.
- if((nBase < 0) || (nBase == 1) || (nBase > 36)){
- if(ppEnd)
- *ppEnd = (char32_t*)pValue;
- return 0;
- }
- else if(nBase == 0){
- // Auto detect one of base 8, 10, or 32.
- if(c != '0')
- nBase = 10;
- else if(*p == 'x' || *p == 'X')
- nBase = 32;
- else
- nBase = 8;
- }
- if(nBase == 16){
- // If there is a leading '0x', then skip past it.
- if((c == '0') && ((*p == 'x') || (*p == 'X'))) {
- ++p;
- c = *p++;
- }
- }
- // If nValue exceeds this, an integer overflow is reported.
- #if (EA_PLATFORM_WORD_SIZE >= 8)
- const uint64_t nMaxValue(UINT64_MAX / nBase);
- const uint64_t nModValue(UINT64_MAX % nBase);
- #else
- // 32 bit platforms are very slow at doing 64 bit div and mod operations.
- uint64_t nMaxValue;
- uint64_t nModValue;
- switch(nBase)
- {
- case 2:
- nMaxValue = UINT64_C(9223372036854775807);
- nModValue = 1;
- break;
- case 8:
- nMaxValue = UINT64_C(2305843009213693951);
- nModValue = 7;
- break;
- case 10:
- nMaxValue = UINT64_C(1844674407370955161);
- nModValue = 5;
- break;
- case 16:
- nMaxValue = UINT64_C(1152921504606846975);
- nModValue = 15;
- break;
- default:
- nMaxValue = (UINT64_MAX / nBase);
- nModValue = (UINT64_MAX % nBase);
- break;
- }
- #endif
- for(unsigned nCurrentDigit; ;){
- if(Isdigit(c))
- nCurrentDigit = (unsigned)(c - '0');
- else if(Isalpha(c))
- nCurrentDigit = (unsigned)(Toupper(c) - 'A' + 10);
- else
- break; // The digit is invalid.
- if(nCurrentDigit >= (unsigned)nBase)
- break; // The digit is invalid.
- bDigitWasRead = true;
- // Check for overflow.
- if((nValue < nMaxValue) || ((nValue == nMaxValue) && ((uint64_t)nCurrentDigit <= nModValue)))
- nValue = (nValue * nBase) + nCurrentDigit;
- else
- bOverflowOccurred = true; // Set the flag, but continue processing.
- c = *p++;
- }
- --p; // Go back to the last character
- if(!bDigitWasRead){
- if(ppEnd)
- p = pValue; // We'll assign 'ppEnd' below.
- } // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
- else if(bOverflowOccurred || (!bUnsigned && (((chSign == '-') && (nValue > ((uint64_t)INT64_MAX + 1))) || ((chSign == '+') && (nValue > (uint64_t)INT64_MAX))))){
- // Integer overflow occurred.
- if(bUnsigned)
- nValue = UINT64_MAX;
- else if(chSign == '-')
- nValue = (uint64_t)INT64_MAX + 1; // INT64_MAX + 1 is the same thing as -INT64_MIN with most compilers.
- else
- nValue = INT64_MAX;
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoU64Common: Range underflow or overflow.");}
- errno = ERANGE; // The standard specifies that we set this value.
- }
- if(ppEnd)
- *ppEnd = (char32_t*)p;
- if(chSign == '-')
- nValue = -nValue;
- return nValue;
- }
- EASTDC_API int32_t StrtoI32(const char* pValue, char** ppEnd, int nBase)
- {
- int64_t val = (int64_t) StrtoU64Common(pValue, ppEnd, nBase, false);
- if(val < INT32_MIN)
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoI32: Range underflow. You may need to use StrtoI64 instead."); }
- errno = ERANGE;
- return (int32_t)INT32_MIN;
- }
- if(val > INT32_MAX)
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoI32: Range overflow. You may need to use StrtoU32 or StrtoU64 instead."); }
- errno = ERANGE;
- return INT32_MAX;
- }
-
- return (int32_t) val;
- }
- EASTDC_API int32_t StrtoI32(const char16_t* pValue, char16_t** ppEnd, int nBase)
- {
- int64_t val = (int64_t) StrtoU64Common(pValue, ppEnd, nBase, false);
- if(val < INT32_MIN)
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoI32: Range underflow. You may need to use StrtoI64 instead."); }
- errno = ERANGE;
- return (int32_t)INT32_MIN;
- }
- if(val > INT32_MAX)
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoI32: Range overflow. You may need to use StrtoU32 or StrtoU64 instead."); }
- errno = ERANGE;
- return INT32_MAX;
- }
-
- return (int32_t) val;
- }
- EASTDC_API int32_t StrtoI32(const char32_t* pValue, char32_t** ppEnd, int nBase)
- {
- int64_t val = (int64_t) StrtoU64Common(pValue, ppEnd, nBase, false);
- if(val < INT32_MIN)
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoI32: Range underflow. You may need to use StrtoI64 instead."); }
- errno = ERANGE;
- return (int32_t)INT32_MIN;
- }
- if(val > INT32_MAX)
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoI32: Range overflow. You may need to use StrtoU32 or StrtoU64 instead."); }
- errno = ERANGE;
- return INT32_MAX;
- }
-
- return (int32_t) val;
- }
- EASTDC_API uint32_t StrtoU32(const char* pValue, char** ppEnd, int nBase)
- {
- uint64_t val = StrtoU64Common(pValue, ppEnd, nBase, true);
- if(val > UINT32_MAX)
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoU32: Range overflow. You may need to use StrtoU64 instead."); }
- errno = ERANGE;
- return UINT32_MAX;
- }
- return (uint32_t)val;
- }
- EASTDC_API uint32_t StrtoU32(const char16_t* pValue, char16_t** ppEnd, int nBase)
- {
- uint64_t val = StrtoU64Common(pValue, ppEnd, nBase, true);
- if(val > UINT32_MAX)
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoU32: Range overflow. You may need to use StrtoU64 instead."); }
- errno = ERANGE;
- return UINT32_MAX;
- }
- return (uint32_t)val;
- }
- EASTDC_API uint32_t StrtoU32(const char32_t* pValue, char32_t** ppEnd, int nBase)
- {
- uint64_t val = StrtoU64Common(pValue, ppEnd, nBase, true);
- if(val > UINT32_MAX)
- {
- if(EA::StdC::GetAssertionsEnabled())
- { EA_FAIL_MSG("StrtoU32: Range overflow. You may need to use StrtoU64 instead."); }
- errno = ERANGE;
- return UINT32_MAX;
- }
- return (uint32_t)val;
- }
- EASTDC_API int64_t StrtoI64(const char* pString, char** ppStringEnd, int nBase)
- {
- return (int64_t)StrtoU64Common(pString, ppStringEnd, nBase, false);
- }
- EASTDC_API int64_t StrtoI64(const char16_t* pString, char16_t** ppStringEnd, int nBase)
- {
- return (int64_t)StrtoU64Common(pString, ppStringEnd, nBase, false);
- }
- EASTDC_API int64_t StrtoI64(const char32_t* pString, char32_t** ppStringEnd, int nBase)
- {
- return (int64_t)StrtoU64Common(pString, ppStringEnd, nBase, false);
- }
- EASTDC_API uint64_t StrtoU64(const char* pString, char** ppStringEnd, int nBase)
- {
- return StrtoU64Common(pString, ppStringEnd, nBase, true);
- }
- EASTDC_API uint64_t StrtoU64(const char16_t* pString, char16_t** ppStringEnd, int nBase)
- {
- return StrtoU64Common(pString, ppStringEnd, nBase, true);
- }
- EASTDC_API uint64_t StrtoU64(const char32_t* pString, char32_t** ppStringEnd, int nBase)
- {
- return StrtoU64Common(pString, ppStringEnd, nBase, true);
- }
- EASTDC_API char* FtoaEnglish(double dValue, char* pResult, int nResultCapacity, int nPrecision, bool bExponentEnabled)
- {
- // Note that this function is a duplicate of FtoaEnglish16 but
- // with char instead of char16_t. Modifications to either of
- // these functions should be replicated to the other.
- int nDecimalPosition, nSign;
- int nPositionResult(0);
- int nPositionTemp(0);
- int i;
- int nExponent;
- if(nResultCapacity <= 0)
- return NULL;
- if(bExponentEnabled){
- if(dValue == 0.0)
- nExponent = 0;
- else
- {
- const double dValueAbs = fabs(dValue);
- const double dValueLog = ::log10(dValueAbs);
- nExponent = (int)::floor(dValueLog);
- }
- if((nExponent >= nPrecision) || (nExponent < -4)){ // printf's %g switches to exponential whenever exp >= precision || exp < -4.
- // Compute how many digits we need for the exponent.
- int nDigits = 1;
- int nLimit = 10;
- while(nLimit <= nExponent){
- nLimit *= 10;
- ++nDigits;
- }
- const double dExpPow = ::pow(10.0, (double)-nExponent);
- if(FtoaEnglish(dValue * dExpPow, pResult, nResultCapacity - nDigits - 2, nPrecision, false)){
- char* p = pResult + Strlen(pResult);
- *p++ = (char)'e';
- *p++ = ((nExponent < 0) ? (char)'-' : (char)'+');
- I32toa(abs(nExponent), p, 10);
- return pResult;
- }
- return NULL;
- }
- }
- // fcvt is a function that converts a floating point value to its component
- // string, sign, and decimal position. It doesn't convert it to a fully
- // finished string because sign and decimal usage usually varies between
- // locales and this function is trying to be locale-independent. It is up
- // to the user of this function to present the final data in a form that
- // is locale-savvy. Actually, not all compilers implement fcvt.
- #if EASTDC_NATIVE_FCVT
- #ifdef __GNUC__ // nPrecision refers to the number of digits after the decimal point.
- const char* const pResultTemp = fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
- #else
- char pResultTemp[_CVTBUFSIZE+1];
- _fcvt_s(pResultTemp, sizeof(pResultTemp), dValue, nPrecision, &nDecimalPosition, &nSign);
- #endif
- #else
- char bufferTemp[kFcvtBufMaxSize];
- const char* const pResultTemp = FcvtBuf(dValue, nPrecision, &nDecimalPosition, &nSign, bufferTemp);
- #endif
- // If the value is negative, then add a leading '-' sign.
- if(nSign){
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult] = '-';
- nPositionResult++;
- }
- // If the value is < 1, then add a leading '0' digit.
- if(fabs(dValue) < 1.0){
- #if EASTDC_NATIVE_FCVT && defined(__GNUC__)
- // GCC's fcvt has a quirk: If the input dValue is 0 (but no other value, fractional or not),
- // it yields an output string with a leading "0." So we need to make a special case to
- // detect this here.
- if(dValue != 0.0)
- #endif
- {
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = '0';
- }
- }
- // Read digits up to the decimal position and write them to the output string.
- if(nDecimalPosition > 0){ // If the input was something like 1000.0
- for(i = 0; (i < nDecimalPosition) && pResultTemp[nPositionTemp]; i++){
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = pResultTemp[nPositionTemp++];
- }
- }
- if(pResultTemp[nPositionTemp]){
- // Find the last of the zeroes in the pResultTemp string. We don't want
- // to add unnecessary trailing zeroes to the returned string and don't
- // want to return a decimal point in the string if it isn't necessary.
- int nFirstTrailingZeroPosition(nPositionTemp);
- int nLastPositionTemp(nPositionTemp);
- while(pResultTemp[nLastPositionTemp]){
- if(pResultTemp[nLastPositionTemp] != '0')
- nFirstTrailingZeroPosition = nLastPositionTemp + 1;
- nLastPositionTemp++;
- }
- // If there is any reason to write a decimal point, then we write
- // it and write the data that comes after it.
- if((nFirstTrailingZeroPosition > nPositionTemp) && (nPrecision > 0)){
- // Add a decimal point.
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = '.';
- if(nDecimalPosition < 0){ // If there are zeroes after the decimal...
- for(i = nDecimalPosition; i < 0; i++){
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = '0';
- --nPrecision;
- }
- }
- // Read digits after the decimal position and write them to the output string.
- for(i = 0; (i < nPrecision) && (nPositionTemp < nFirstTrailingZeroPosition) && pResultTemp[nPositionTemp]; i++){
- if(nPositionResult >= nResultCapacity){
- //What we do here is possibly erase trailing zeroes that we've written after the decimal.
- int nEndPosition = EASTDC_MAX(nPositionResult - 1, 0);
- pResult[nEndPosition] = 0;
- while((--nEndPosition > 0) && (pResult[nEndPosition] == '0'))
- pResult[nEndPosition] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = pResultTemp[nPositionTemp++];
- }
- }
- }
- // Write the final terminating zero.
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult] = 0;
- return pResult;
- }
- EASTDC_API char16_t* FtoaEnglish(double dValue, char16_t* pResult, int nResultCapacity, int nPrecision, bool bExponentEnabled)
- {
- // Note that this function is a duplicate of FtoaEnglish8 but
- // with char16_t instead of char. Modifications to either of
- // these functions should be replicated to the other.
- int nDecimalPosition, nSign;
- int nPositionResult(0);
- int nPositionTemp(0);
- int i;
- int nExponent;
- if(nResultCapacity <= 0)
- return NULL;
- if(bExponentEnabled){
- if(dValue == 0.0)
- nExponent = 0;
- else
- {
- const double dValueAbs = fabs(dValue);
- const double dValueLog = ::log10(dValueAbs);
- nExponent = (int)::floor(dValueLog);
- }
- if((nExponent >= nPrecision) || (nExponent < -4)){ // printf's %g switches to exponential whenever exp >= mnPrecisionUsed || exp < -4.
- // Compute how many digits we need for the exponent.
- int nDigits = 1;
- int nLimit = 10;
- while(nLimit <= nExponent){
- nLimit *= 10;
- ++nDigits;
- }
- const double dExpPow = ::pow(10.0, (double)-nExponent);
- if(FtoaEnglish(dValue * dExpPow, pResult, nResultCapacity - nDigits - 2, nPrecision, false)){
- char16_t* p = pResult + Strlen(pResult);
- *p++ = (char16_t)'e';
- *p++ = ((nExponent < 0) ? (char16_t)'-' : (char16_t)'+');
- I32toa(abs(nExponent), p, 10);
- return pResult;
- }
- return NULL;
- }
- }
- // fcvt is a function that converts a floating point value to its component
- // string, sign, and decimal position. It doesn't convert it to a fully
- // finished string because sign and decimal usage usually varies between
- // locales and this function is trying to be locale-independent. It is up
- // to the user of this function to present the final data in a form that
- // is locale-savvy. Actually, not all compilers implement fcvt.
- #if EASTDC_NATIVE_FCVT
- #ifdef __GNUC__
- const char* const pResultTemp = fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
- #else
- const char* const pResultTemp = _fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
- #endif
- #else
- char bufferTemp[kFcvtBufMaxSize];
- const char* const pResultTemp = FcvtBuf(dValue, nPrecision, &nDecimalPosition, &nSign, bufferTemp);
- #endif
- // If the value is negative, then add a leading '-' sign.
- if(nSign){
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult] = '-';
- nPositionResult++;
- }
- // If the value is < 1, then add a leading '0' digit.
- if(fabs(dValue) < 1.0){
- #if EASTDC_NATIVE_FCVT && defined(__GNUC__)
- // GCC's fcvt has a quirk: If the input dValue is 0 (but no other value, fractional or not),
- // it yields an output string with a leading "0." So we need to make a special case to
- // detect this here.
- if(dValue != 0.0)
- #endif
- {
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = '0';
- }
- }
- // Read digits up to the decimal position and write them to the output string.
- if(nDecimalPosition > 0){ // If the input was something like 1000.0
- for(i = 0; (i < nDecimalPosition) && pResultTemp[nPositionTemp]; i++){
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = (char16_t)pResultTemp[nPositionTemp++];
- }
- }
- if(pResultTemp[nPositionTemp]){
- // Find the last of the zeroes in the pResultTemp string. We don't want
- // to add unnecessary trailing zeroes to the returned string and don't
- // want to return a decimal point in the string if it isn't necessary.
- int nFirstTrailingZeroPosition(nPositionTemp);
- int nLastPositionTemp(nPositionTemp);
- while(pResultTemp[nLastPositionTemp]){
- if(pResultTemp[nLastPositionTemp] != '0')
- nFirstTrailingZeroPosition = nLastPositionTemp + 1;
- nLastPositionTemp++;
- }
- // If there is any reason to write a decimal point, then we write
- // it and write the data that comes after it.
- if((nFirstTrailingZeroPosition > nPositionTemp) && (nPrecision > 0)){
- // Add a decimal point.
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = '.';
- if(nDecimalPosition < 0){ // If there are zeroes after the decimal...
- for(i = nDecimalPosition; i < 0; i++){
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = '0';
- --nPrecision;
- }
- }
- // Read digits after the decimal position and write them to the output string.
- for(i = 0; (i < nPrecision) && (nPositionTemp < nFirstTrailingZeroPosition) && pResultTemp[nPositionTemp]; i++){
- if(nPositionResult >= nResultCapacity){
- //What we do here is possibly erase trailing zeroes that we've written after the decimal.
- int nEndPosition = EASTDC_MAX(nPositionResult - 1, 0);
- pResult[nEndPosition] = 0;
- while((--nEndPosition > 0) && (pResult[nEndPosition] == '0'))
- pResult[nEndPosition] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = (char16_t)pResultTemp[nPositionTemp++];
- }
- }
- }
- // Write the final terminating zero.
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult] = 0;
- return pResult;
- }
- EASTDC_API char32_t* FtoaEnglish(double dValue, char32_t* pResult, int nResultCapacity, int nPrecision, bool bExponentEnabled)
- {
- // Note that this function is a duplicate of FtoaEnglish8 but
- // with char32_t instead of char. Modifications to either of
- // these functions should be replicated to the other.
- int nDecimalPosition, nSign;
- int nPositionResult(0);
- int nPositionTemp(0);
- int i;
- int nExponent;
- if(nResultCapacity <= 0)
- return NULL;
- if(bExponentEnabled){
- if(dValue == 0.0)
- nExponent = 0;
- else
- {
- const double dValueAbs = fabs(dValue);
- const double dValueLog = ::log10(dValueAbs);
- nExponent = (int)::floor(dValueLog);
- }
- if((nExponent >= nPrecision) || (nExponent < -4)){ // printf's %g switches to exponential whenever exp >= mnPrecisionUsed || exp < -4.
- // Compute how many digits we need for the exponent.
- int nDigits = 1;
- int nLimit = 10;
- while(nLimit <= nExponent){
- nLimit *= 10;
- ++nDigits;
- }
- const double dExpPow = ::pow(10.0, (double)-nExponent);
- if(FtoaEnglish(dValue * dExpPow, pResult, nResultCapacity - nDigits - 2, nPrecision, false)){
- char32_t* p = pResult + Strlen(pResult);
- *p++ = (char32_t)'e';
- *p++ = ((nExponent < 0) ? (char32_t)'-' : (char32_t)'+');
- I32toa(abs(nExponent), p, 10);
- return pResult;
- }
- return NULL;
- }
- }
- // fcvt is a function that converts a floating point value to its component
- // string, sign, and decimal position. It doesn't convert it to a fully
- // finished string because sign and decimal usage usually varies between
- // locales and this function is trying to be locale-independent. It is up
- // to the user of this function to present the final data in a form that
- // is locale-savvy. Actually, not all compilers implement fcvt.
- #if EASTDC_NATIVE_FCVT
- #ifdef __GNUC__
- const char* const pResultTemp = fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
- #else
- const char* const pResultTemp = _fcvt(dValue, nPrecision, &nDecimalPosition, &nSign);
- #endif
- #else
- char bufferTemp[kFcvtBufMaxSize];
- const char* const pResultTemp = FcvtBuf(dValue, nPrecision, &nDecimalPosition, &nSign, bufferTemp);
- #endif
- // If the value is negative, then add a leading '-' sign.
- if(nSign){
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult] = '-';
- nPositionResult++;
- }
- // If the value is < 1, then add a leading '0' digit.
- if(fabs(dValue) < 1.0){
- #if EASTDC_NATIVE_FCVT && defined(__GNUC__)
- // GCC's fcvt has a quirk: If the input dValue is 0 (but no other value, fractional or not),
- // it yields an output string with a leading "0." So we need to make a special case to
- // detect this here.
- if(dValue != 0.0)
- #endif
- {
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = '0';
- }
- }
- // Read digits up to the decimal position and write them to the output string.
- if(nDecimalPosition > 0){ // If the input was something like 1000.0
- for(i = 0; (i < nDecimalPosition) && pResultTemp[nPositionTemp]; i++){
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = (char32_t)pResultTemp[nPositionTemp++];
- }
- }
- if(pResultTemp[nPositionTemp]){
- // Find the last of the zeroes in the pResultTemp string. We don't want
- // to add unnecessary trailing zeroes to the returned string and don't
- // want to return a decimal point in the string if it isn't necessary.
- int nFirstTrailingZeroPosition(nPositionTemp);
- int nLastPositionTemp(nPositionTemp);
- while(pResultTemp[nLastPositionTemp]){
- if(pResultTemp[nLastPositionTemp] != '0')
- nFirstTrailingZeroPosition = nLastPositionTemp + 1;
- nLastPositionTemp++;
- }
- // If there is any reason to write a decimal point, then we write
- // it and write the data that comes after it.
- if((nFirstTrailingZeroPosition > nPositionTemp) && (nPrecision > 0)){
- // Add a decimal point.
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = '.';
- if(nDecimalPosition < 0){ // If there are zeroes after the decimal...
- for(i = nDecimalPosition; i < 0; i++){
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = '0';
- --nPrecision;
- }
- }
- // Read digits after the decimal position and write them to the output string.
- for(i = 0; (i < nPrecision) && (nPositionTemp < nFirstTrailingZeroPosition) && pResultTemp[nPositionTemp]; i++){
- if(nPositionResult >= nResultCapacity){
- //What we do here is possibly erase trailing zeroes that we've written after the decimal.
- int nEndPosition = EASTDC_MAX(nPositionResult - 1, 0);
- pResult[nEndPosition] = 0;
- while((--nEndPosition > 0) && (pResult[nEndPosition] == '0'))
- pResult[nEndPosition] = 0;
- return NULL;
- }
- pResult[nPositionResult++] = (char32_t)pResultTemp[nPositionTemp++];
- }
- }
- }
- // Write the final terminating zero.
- if(nPositionResult >= nResultCapacity){
- pResult[EASTDC_MAX(nPositionResult - 1, 0)] = 0;
- return NULL;
- }
- pResult[nPositionResult] = 0;
- return pResult;
- }
- EASTDC_API size_t ReduceFloatString(char* pString, size_t nLength)
- {
- if(nLength == (size_t)-1)
- nLength = strlen(pString);
- size_t nNewLength(nLength);
- if(nLength > 0)
- {
- // Get the decimal index and exponent index. We won't chop off any zeros
- // unless they are after the decimal position and before an exponent position.
- int nDecimalIndex = -1;
- int nExponentIndex = -1;
- int nCurrentIndex = 0;
- while(nCurrentIndex < (int)nLength)
- {
- if(pString[nCurrentIndex] == '.')
- nDecimalIndex = nCurrentIndex;
- if((pString[nCurrentIndex] == 'e') || (pString[nCurrentIndex] == 'E'))
- nExponentIndex = nCurrentIndex;
- nCurrentIndex++;
- }
- // Now we need to go to the end of the string and walk backwards to
- // find any contiguous zero digits after a decimal point.
- if(nDecimalIndex >= 0) // If there is any decimal point...
- {
- const int nFirstDigitToCheck(nDecimalIndex + 1);
- const int nLastDigitToCheck ((nExponentIndex >= 0) ? (nExponentIndex - 1) : (int)(nLength - 1));
- nCurrentIndex = nLastDigitToCheck;
- while(nCurrentIndex >= nFirstDigitToCheck)
- {
- // assert((pString[nCurrentIndex] >= '0') && (pString[nCurrentIndex] <= '9'));
- if(pString[nCurrentIndex] == '0')
- {
- // Copy the string downward. Note that we copy the trailing
- // terminator of the string as well.
- for(int i = nCurrentIndex; i < (int)nNewLength; i++)
- pString[i] = pString[i + 1]; // Copy the string downward.
- nNewLength--;
- }
- else
- break;
- nCurrentIndex--;
- }
- }
- else
- {
- // If the string is all zeroes, convert it to just one zero.
- size_t i;
- for(i = 0; (i < nLength) && (pString[i] == '0'); i++)
- { } // Do nothing.
- if(i == nLength)
- nLength = 0; // And fall through to the code below.
- }
- // It is possible that the input string was "000", in which case the above code would
- // erase the entire string. Here we simply make a string of "0" and return it.
- if(nLength == 0)
- {
- pString[0] = '0';
- pString[1] = 0;
- nNewLength = 1;
- }
- else
- {
- // We may have a number such as "234.", in which case we remove the trailing decimal.
- if((nDecimalIndex >= 0) && (nDecimalIndex == ((int)(unsigned)nNewLength - 1)))
- {
- pString[nDecimalIndex] = 0;
- nNewLength--;
- }
- size_t i;
- // It is also posible that we now have a string like "0." or "000." or just ".".
- // In this case, we simply set the string to "0".
- for(i = 0; i < nNewLength; i++)
- {
- if((pString[i] != '0') && (pString[i] != '.'))
- break;
- }
- if(i == nNewLength) // If the string was all zeros...
- {
- pString[0] = '0';
- pString[1] = 0;
- nNewLength = 1;
- }
- if((nNewLength >= 3) && (pString[0] == '0') && (pString[1] == '.')) // If we have "0.x"
- {
- memmove(pString, pString + 1, nNewLength * sizeof(char));
- nNewLength--;
- }
- }
- }
- return nNewLength;
- }
- EASTDC_API size_t ReduceFloatString(char16_t* pString, size_t nLength)
- {
- // We implement this by calling the 8 bit version and copying its data.
- char pBuffer8[64];
- char* pCurrent8;
- char16_t* pCurrent16;
- size_t n = 0;
- if(nLength < 63)
- nLength = 63;
- for(pCurrent8 = pBuffer8, pCurrent16 = pString; *pCurrent16 && (n < nLength); ++n) // Do a 16 bit to 8 bit strcpy.
- *pCurrent8++ = (char)(unsigned char)*pCurrent16++;
-
- *pCurrent8 = 0;
- n = ReduceFloatString(pBuffer8, n);
- for(pCurrent8 = pBuffer8, pCurrent16 = pString; *pCurrent8; ) // Do a 8 bit to 16 bit strcpy.
- *pCurrent16++ = (char16_t)(unsigned char)*pCurrent8++;
- *pCurrent16 = 0;
- return n;
- }
- EASTDC_API size_t ReduceFloatString(char32_t* pString, size_t nLength)
- {
- // We implement this by calling the 8 bit version and copying its data.
- char pBuffer8[64];
- char* pCurrent8;
- char32_t* pCurrent32;
- size_t n = 0;
- if(nLength < 63)
- nLength = 63;
- for(pCurrent8 = pBuffer8, pCurrent32 = pString; *pCurrent32 && (n < nLength); ++n) // Do a 32 bit to 8 bit strcpy.
- *pCurrent8++ = (char)(unsigned char)*pCurrent32++;
-
- *pCurrent8 = 0;
- n = ReduceFloatString(pBuffer8, n);
- for(pCurrent8 = pBuffer8, pCurrent32 = pString; *pCurrent8; ) // Do a 8 bit to 32 bit strcpy.
- *pCurrent32++ = (char32_t)(unsigned char)*pCurrent8++;
- *pCurrent32 = 0;
- return n;
- }
- } // namespace StdC
- } // namespace EA
- #undef EASTDC_MIN
- #undef EASTDC_MAX
- #if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)
- EA_RESTORE_GCC_WARNING()
- #endif
- EA_RESTORE_VC_WARNING()
|