EAString.cpp 144 KB

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