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