12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535 |
- // © 2016 and later: Unicode, Inc. and others.
- // License & terms of use: http://www.unicode.org/copyright.html
- /*
- ******************************************************************************
- *
- * Copyright (C) 1998-2016, International Business Machines
- * Corporation and others. All Rights Reserved.
- *
- ******************************************************************************
- *
- * File ustring.cpp
- *
- * Modification History:
- *
- * Date Name Description
- * 12/07/98 bertrand Creation.
- ******************************************************************************
- */
- #include "unicode/utypes.h"
- #include "unicode/putil.h"
- #include "unicode/uchar.h"
- #include "unicode/ustring.h"
- #include "unicode/utf16.h"
- #include "cstring.h"
- #include "cwchar.h"
- #include "cmemory.h"
- #include "ustr_imp.h"
- /* ANSI string.h - style functions ------------------------------------------ */
- /* U+ffff is the highest BMP code point, the highest one that fits into a 16-bit char16_t */
- #define U_BMP_MAX 0xffff
- /* Forward binary string search functions ----------------------------------- */
- /*
- * Test if a substring match inside a string is at code point boundaries.
- * All pointers refer to the same buffer.
- * The limit pointer may be nullptr, all others must be real pointers.
- */
- static inline UBool
- isMatchAtCPBoundary(const char16_t *start, const char16_t *match, const char16_t *matchLimit, const char16_t *limit) {
- if(U16_IS_TRAIL(*match) && start!=match && U16_IS_LEAD(*(match-1))) {
- /* the leading edge of the match is in the middle of a surrogate pair */
- return false;
- }
- if(U16_IS_LEAD(*(matchLimit-1)) && matchLimit!=limit && U16_IS_TRAIL(*matchLimit)) {
- /* the trailing edge of the match is in the middle of a surrogate pair */
- return false;
- }
- return true;
- }
- U_CAPI char16_t * U_EXPORT2
- u_strFindFirst(const char16_t *s, int32_t length,
- const char16_t *sub, int32_t subLength) {
- const char16_t *start, *p, *q, *subLimit;
- char16_t c, cs, cq;
- if(sub==nullptr || subLength<-1) {
- return (char16_t *)s;
- }
- if(s==nullptr || length<-1) {
- return nullptr;
- }
- start=s;
- if(length<0 && subLength<0) {
- /* both strings are NUL-terminated */
- if((cs=*sub++)==0) {
- return (char16_t *)s;
- }
- if(*sub==0 && !U16_IS_SURROGATE(cs)) {
- /* the substring consists of a single, non-surrogate BMP code point */
- return u_strchr(s, cs);
- }
- while((c=*s++)!=0) {
- if(c==cs) {
- /* found first substring char16_t, compare rest */
- p=s;
- q=sub;
- for(;;) {
- if((cq=*q)==0) {
- if(isMatchAtCPBoundary(start, s-1, p, nullptr)) {
- return (char16_t *)(s-1); /* well-formed match */
- } else {
- break; /* no match because surrogate pair is split */
- }
- }
- if((c=*p)==0) {
- return nullptr; /* no match, and none possible after s */
- }
- if(c!=cq) {
- break; /* no match */
- }
- ++p;
- ++q;
- }
- }
- }
- /* not found */
- return nullptr;
- }
- if(subLength<0) {
- subLength=u_strlen(sub);
- }
- if(subLength==0) {
- return (char16_t *)s;
- }
- /* get sub[0] to search for it fast */
- cs=*sub++;
- --subLength;
- subLimit=sub+subLength;
- if(subLength==0 && !U16_IS_SURROGATE(cs)) {
- /* the substring consists of a single, non-surrogate BMP code point */
- return length<0 ? u_strchr(s, cs) : u_memchr(s, cs, length);
- }
- if(length<0) {
- /* s is NUL-terminated */
- while((c=*s++)!=0) {
- if(c==cs) {
- /* found first substring char16_t, compare rest */
- p=s;
- q=sub;
- for(;;) {
- if(q==subLimit) {
- if(isMatchAtCPBoundary(start, s-1, p, nullptr)) {
- return (char16_t *)(s-1); /* well-formed match */
- } else {
- break; /* no match because surrogate pair is split */
- }
- }
- if((c=*p)==0) {
- return nullptr; /* no match, and none possible after s */
- }
- if(c!=*q) {
- break; /* no match */
- }
- ++p;
- ++q;
- }
- }
- }
- } else {
- const char16_t *limit, *preLimit;
- /* subLength was decremented above */
- if(length<=subLength) {
- return nullptr; /* s is shorter than sub */
- }
- limit=s+length;
- /* the substring must start before preLimit */
- preLimit=limit-subLength;
- while(s!=preLimit) {
- c=*s++;
- if(c==cs) {
- /* found first substring char16_t, compare rest */
- p=s;
- q=sub;
- for(;;) {
- if(q==subLimit) {
- if(isMatchAtCPBoundary(start, s-1, p, limit)) {
- return (char16_t *)(s-1); /* well-formed match */
- } else {
- break; /* no match because surrogate pair is split */
- }
- }
- if(*p!=*q) {
- break; /* no match */
- }
- ++p;
- ++q;
- }
- }
- }
- }
- /* not found */
- return nullptr;
- }
- U_CAPI char16_t * U_EXPORT2
- u_strstr(const char16_t *s, const char16_t *substring) {
- return u_strFindFirst(s, -1, substring, -1);
- }
- U_CAPI char16_t * U_EXPORT2
- u_strchr(const char16_t *s, char16_t c) {
- if(U16_IS_SURROGATE(c)) {
- /* make sure to not find half of a surrogate pair */
- return u_strFindFirst(s, -1, &c, 1);
- } else {
- char16_t cs;
- /* trivial search for a BMP code point */
- for(;;) {
- if((cs=*s)==c) {
- return (char16_t *)s;
- }
- if(cs==0) {
- return nullptr;
- }
- ++s;
- }
- }
- }
- U_CAPI char16_t * U_EXPORT2
- u_strchr32(const char16_t *s, UChar32 c) {
- if((uint32_t)c<=U_BMP_MAX) {
- /* find BMP code point */
- return u_strchr(s, (char16_t)c);
- } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
- /* find supplementary code point as surrogate pair */
- char16_t cs, lead=U16_LEAD(c), trail=U16_TRAIL(c);
- while((cs=*s++)!=0) {
- if(cs==lead && *s==trail) {
- return (char16_t *)(s-1);
- }
- }
- return nullptr;
- } else {
- /* not a Unicode code point, not findable */
- return nullptr;
- }
- }
- U_CAPI char16_t * U_EXPORT2
- u_memchr(const char16_t *s, char16_t c, int32_t count) {
- if(count<=0) {
- return nullptr; /* no string */
- } else if(U16_IS_SURROGATE(c)) {
- /* make sure to not find half of a surrogate pair */
- return u_strFindFirst(s, count, &c, 1);
- } else {
- /* trivial search for a BMP code point */
- const char16_t *limit=s+count;
- do {
- if(*s==c) {
- return (char16_t *)s;
- }
- } while(++s!=limit);
- return nullptr;
- }
- }
- U_CAPI char16_t * U_EXPORT2
- u_memchr32(const char16_t *s, UChar32 c, int32_t count) {
- if((uint32_t)c<=U_BMP_MAX) {
- /* find BMP code point */
- return u_memchr(s, (char16_t)c, count);
- } else if(count<2) {
- /* too short for a surrogate pair */
- return nullptr;
- } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
- /* find supplementary code point as surrogate pair */
- const char16_t *limit=s+count-1; /* -1 so that we do not need a separate check for the trail unit */
- char16_t lead=U16_LEAD(c), trail=U16_TRAIL(c);
- do {
- if(*s==lead && *(s+1)==trail) {
- return (char16_t *)s;
- }
- } while(++s!=limit);
- return nullptr;
- } else {
- /* not a Unicode code point, not findable */
- return nullptr;
- }
- }
- /* Backward binary string search functions ---------------------------------- */
- U_CAPI char16_t * U_EXPORT2
- u_strFindLast(const char16_t *s, int32_t length,
- const char16_t *sub, int32_t subLength) {
- const char16_t *start, *limit, *p, *q, *subLimit;
- char16_t c, cs;
- if(sub==nullptr || subLength<-1) {
- return (char16_t *)s;
- }
- if(s==nullptr || length<-1) {
- return nullptr;
- }
- /*
- * This implementation is more lazy than the one for u_strFindFirst():
- * There is no special search code for NUL-terminated strings.
- * It does not seem to be worth it for searching substrings to
- * search forward and find all matches like in u_strrchr() and similar.
- * Therefore, we simply get both string lengths and search backward.
- *
- * markus 2002oct23
- */
- if(subLength<0) {
- subLength=u_strlen(sub);
- }
- if(subLength==0) {
- return (char16_t *)s;
- }
- /* get sub[subLength-1] to search for it fast */
- subLimit=sub+subLength;
- cs=*(--subLimit);
- --subLength;
- if(subLength==0 && !U16_IS_SURROGATE(cs)) {
- /* the substring consists of a single, non-surrogate BMP code point */
- return length<0 ? u_strrchr(s, cs) : u_memrchr(s, cs, length);
- }
- if(length<0) {
- length=u_strlen(s);
- }
- /* subLength was decremented above */
- if(length<=subLength) {
- return nullptr; /* s is shorter than sub */
- }
- start=s;
- limit=s+length;
- /* the substring must start no later than s+subLength */
- s+=subLength;
- while(s!=limit) {
- c=*(--limit);
- if(c==cs) {
- /* found last substring char16_t, compare rest */
- p=limit;
- q=subLimit;
- for(;;) {
- if(q==sub) {
- if(isMatchAtCPBoundary(start, p, limit+1, start+length)) {
- return (char16_t *)p; /* well-formed match */
- } else {
- break; /* no match because surrogate pair is split */
- }
- }
- if(*(--p)!=*(--q)) {
- break; /* no match */
- }
- }
- }
- }
- /* not found */
- return nullptr;
- }
- U_CAPI char16_t * U_EXPORT2
- u_strrstr(const char16_t *s, const char16_t *substring) {
- return u_strFindLast(s, -1, substring, -1);
- }
- U_CAPI char16_t * U_EXPORT2
- u_strrchr(const char16_t *s, char16_t c) {
- if(U16_IS_SURROGATE(c)) {
- /* make sure to not find half of a surrogate pair */
- return u_strFindLast(s, -1, &c, 1);
- } else {
- const char16_t *result=nullptr;
- char16_t cs;
- /* trivial search for a BMP code point */
- for(;;) {
- if((cs=*s)==c) {
- result=s;
- }
- if(cs==0) {
- return (char16_t *)result;
- }
- ++s;
- }
- }
- }
- U_CAPI char16_t * U_EXPORT2
- u_strrchr32(const char16_t *s, UChar32 c) {
- if((uint32_t)c<=U_BMP_MAX) {
- /* find BMP code point */
- return u_strrchr(s, (char16_t)c);
- } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
- /* find supplementary code point as surrogate pair */
- const char16_t *result=nullptr;
- char16_t cs, lead=U16_LEAD(c), trail=U16_TRAIL(c);
- while((cs=*s++)!=0) {
- if(cs==lead && *s==trail) {
- result=s-1;
- }
- }
- return (char16_t *)result;
- } else {
- /* not a Unicode code point, not findable */
- return nullptr;
- }
- }
- U_CAPI char16_t * U_EXPORT2
- u_memrchr(const char16_t *s, char16_t c, int32_t count) {
- if(count<=0) {
- return nullptr; /* no string */
- } else if(U16_IS_SURROGATE(c)) {
- /* make sure to not find half of a surrogate pair */
- return u_strFindLast(s, count, &c, 1);
- } else {
- /* trivial search for a BMP code point */
- const char16_t *limit=s+count;
- do {
- if(*(--limit)==c) {
- return (char16_t *)limit;
- }
- } while(s!=limit);
- return nullptr;
- }
- }
- U_CAPI char16_t * U_EXPORT2
- u_memrchr32(const char16_t *s, UChar32 c, int32_t count) {
- if((uint32_t)c<=U_BMP_MAX) {
- /* find BMP code point */
- return u_memrchr(s, (char16_t)c, count);
- } else if(count<2) {
- /* too short for a surrogate pair */
- return nullptr;
- } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
- /* find supplementary code point as surrogate pair */
- const char16_t *limit=s+count-1;
- char16_t lead=U16_LEAD(c), trail=U16_TRAIL(c);
- do {
- if(*limit==trail && *(limit-1)==lead) {
- return (char16_t *)(limit-1);
- }
- } while(s!=--limit);
- return nullptr;
- } else {
- /* not a Unicode code point, not findable */
- return nullptr;
- }
- }
- /* Tokenization functions --------------------------------------------------- */
- /*
- * Match each code point in a string against each code point in the matchSet.
- * Return the index of the first string code point that
- * is (polarity==true) or is not (false) contained in the matchSet.
- * Return -(string length)-1 if there is no such code point.
- */
- static int32_t
- _matchFromSet(const char16_t *string, const char16_t *matchSet, UBool polarity) {
- int32_t matchLen, matchBMPLen, strItr, matchItr;
- UChar32 stringCh, matchCh;
- char16_t c, c2;
- /* first part of matchSet contains only BMP code points */
- matchBMPLen = 0;
- while((c = matchSet[matchBMPLen]) != 0 && U16_IS_SINGLE(c)) {
- ++matchBMPLen;
- }
- /* second part of matchSet contains BMP and supplementary code points */
- matchLen = matchBMPLen;
- while(matchSet[matchLen] != 0) {
- ++matchLen;
- }
- for(strItr = 0; (c = string[strItr]) != 0;) {
- ++strItr;
- if(U16_IS_SINGLE(c)) {
- if(polarity) {
- for(matchItr = 0; matchItr < matchLen; ++matchItr) {
- if(c == matchSet[matchItr]) {
- return strItr - 1; /* one matches */
- }
- }
- } else {
- for(matchItr = 0; matchItr < matchLen; ++matchItr) {
- if(c == matchSet[matchItr]) {
- goto endloop;
- }
- }
- return strItr - 1; /* none matches */
- }
- } else {
- /*
- * No need to check for string length before U16_IS_TRAIL
- * because c2 could at worst be the terminating NUL.
- */
- if(U16_IS_SURROGATE_LEAD(c) && U16_IS_TRAIL(c2 = string[strItr])) {
- ++strItr;
- stringCh = U16_GET_SUPPLEMENTARY(c, c2);
- } else {
- stringCh = c; /* unpaired trail surrogate */
- }
- if(polarity) {
- for(matchItr = matchBMPLen; matchItr < matchLen;) {
- U16_NEXT(matchSet, matchItr, matchLen, matchCh);
- if(stringCh == matchCh) {
- return strItr - U16_LENGTH(stringCh); /* one matches */
- }
- }
- } else {
- for(matchItr = matchBMPLen; matchItr < matchLen;) {
- U16_NEXT(matchSet, matchItr, matchLen, matchCh);
- if(stringCh == matchCh) {
- goto endloop;
- }
- }
- return strItr - U16_LENGTH(stringCh); /* none matches */
- }
- }
- endloop:
- /* wish C had continue with labels like Java... */;
- }
- /* Didn't find it. */
- return -strItr-1;
- }
- /* Search for a codepoint in a string that matches one of the matchSet codepoints. */
- U_CAPI char16_t * U_EXPORT2
- u_strpbrk(const char16_t *string, const char16_t *matchSet)
- {
- int32_t idx = _matchFromSet(string, matchSet, true);
- if(idx >= 0) {
- return (char16_t *)string + idx;
- } else {
- return nullptr;
- }
- }
- /* Search for a codepoint in a string that matches one of the matchSet codepoints. */
- U_CAPI int32_t U_EXPORT2
- u_strcspn(const char16_t *string, const char16_t *matchSet)
- {
- int32_t idx = _matchFromSet(string, matchSet, true);
- if(idx >= 0) {
- return idx;
- } else {
- return -idx - 1; /* == u_strlen(string) */
- }
- }
- /* Search for a codepoint in a string that does not match one of the matchSet codepoints. */
- U_CAPI int32_t U_EXPORT2
- u_strspn(const char16_t *string, const char16_t *matchSet)
- {
- int32_t idx = _matchFromSet(string, matchSet, false);
- if(idx >= 0) {
- return idx;
- } else {
- return -idx - 1; /* == u_strlen(string) */
- }
- }
- /* ----- Text manipulation functions --- */
- U_CAPI char16_t* U_EXPORT2
- u_strtok_r(char16_t *src,
- const char16_t *delim,
- char16_t **saveState)
- {
- char16_t *tokSource;
- char16_t *nextToken;
- uint32_t nonDelimIdx;
- /* If saveState is nullptr, the user messed up. */
- if (src != nullptr) {
- tokSource = src;
- *saveState = src; /* Set to "src" in case there are no delimiters */
- }
- else if (*saveState) {
- tokSource = *saveState;
- }
- else {
- /* src == nullptr && *saveState == nullptr */
- /* This shouldn't happen. We already finished tokenizing. */
- return nullptr;
- }
- /* Skip initial delimiters */
- nonDelimIdx = u_strspn(tokSource, delim);
- tokSource = &tokSource[nonDelimIdx];
- if (*tokSource) {
- nextToken = u_strpbrk(tokSource, delim);
- if (nextToken != nullptr) {
- /* Create a token */
- *(nextToken++) = 0;
- *saveState = nextToken;
- return tokSource;
- }
- else if (*saveState) {
- /* Return the last token */
- *saveState = nullptr;
- return tokSource;
- }
- }
- else {
- /* No tokens were found. Only delimiters were left. */
- *saveState = nullptr;
- }
- return nullptr;
- }
- /* Miscellaneous functions -------------------------------------------------- */
- U_CAPI char16_t* U_EXPORT2
- u_strcat(char16_t *dst,
- const char16_t *src)
- {
- char16_t *anchor = dst; /* save a pointer to start of dst */
- while(*dst != 0) { /* To end of first string */
- ++dst;
- }
- while((*(dst++) = *(src++)) != 0) { /* copy string 2 over */
- }
- return anchor;
- }
- U_CAPI char16_t* U_EXPORT2
- u_strncat(char16_t *dst,
- const char16_t *src,
- int32_t n )
- {
- if(n > 0) {
- char16_t *anchor = dst; /* save a pointer to start of dst */
- while(*dst != 0) { /* To end of first string */
- ++dst;
- }
- while((*dst = *src) != 0) { /* copy string 2 over */
- ++dst;
- if(--n == 0) {
- *dst = 0;
- break;
- }
- ++src;
- }
- return anchor;
- } else {
- return dst;
- }
- }
- /* ----- Text property functions --- */
- U_CAPI int32_t U_EXPORT2
- u_strcmp(const char16_t *s1,
- const char16_t *s2)
- {
- char16_t c1, c2;
- for(;;) {
- c1=*s1++;
- c2=*s2++;
- if (c1 != c2 || c1 == 0) {
- break;
- }
- }
- return (int32_t)c1 - (int32_t)c2;
- }
- U_CFUNC int32_t U_EXPORT2
- uprv_strCompare(const char16_t *s1, int32_t length1,
- const char16_t *s2, int32_t length2,
- UBool strncmpStyle, UBool codePointOrder) {
- const char16_t *start1, *start2, *limit1, *limit2;
- char16_t c1, c2;
- /* setup for fix-up */
- start1=s1;
- start2=s2;
- /* compare identical prefixes - they do not need to be fixed up */
- if(length1<0 && length2<0) {
- /* strcmp style, both NUL-terminated */
- if(s1==s2) {
- return 0;
- }
- for(;;) {
- c1=*s1;
- c2=*s2;
- if(c1!=c2) {
- break;
- }
- if(c1==0) {
- return 0;
- }
- ++s1;
- ++s2;
- }
- /* setup for fix-up */
- limit1=limit2=nullptr;
- } else if(strncmpStyle) {
- /* special handling for strncmp, assume length1==length2>=0 but also check for NUL */
- if(s1==s2) {
- return 0;
- }
- limit1=start1+length1;
- for(;;) {
- /* both lengths are same, check only one limit */
- if(s1==limit1) {
- return 0;
- }
- c1=*s1;
- c2=*s2;
- if(c1!=c2) {
- break;
- }
- if(c1==0) {
- return 0;
- }
- ++s1;
- ++s2;
- }
- /* setup for fix-up */
- limit2=start2+length1; /* use length1 here, too, to enforce assumption */
- } else {
- /* memcmp/UnicodeString style, both length-specified */
- int32_t lengthResult;
- if(length1<0) {
- length1=u_strlen(s1);
- }
- if(length2<0) {
- length2=u_strlen(s2);
- }
- /* limit1=start1+min(length1, length2) */
- if(length1<length2) {
- lengthResult=-1;
- limit1=start1+length1;
- } else if(length1==length2) {
- lengthResult=0;
- limit1=start1+length1;
- } else /* length1>length2 */ {
- lengthResult=1;
- limit1=start1+length2;
- }
- if(s1==s2) {
- return lengthResult;
- }
- for(;;) {
- /* check pseudo-limit */
- if(s1==limit1) {
- return lengthResult;
- }
- c1=*s1;
- c2=*s2;
- if(c1!=c2) {
- break;
- }
- ++s1;
- ++s2;
- }
- /* setup for fix-up */
- limit1=start1+length1;
- limit2=start2+length2;
- }
- /* if both values are in or above the surrogate range, fix them up */
- if(c1>=0xd800 && c2>=0xd800 && codePointOrder) {
- /* subtract 0x2800 from BMP code points to make them smaller than supplementary ones */
- if(
- (c1<=0xdbff && (s1+1)!=limit1 && U16_IS_TRAIL(*(s1+1))) ||
- (U16_IS_TRAIL(c1) && start1!=s1 && U16_IS_LEAD(*(s1-1)))
- ) {
- /* part of a surrogate pair, leave >=d800 */
- } else {
- /* BMP code point - may be surrogate code point - make <d800 */
- c1-=0x2800;
- }
- if(
- (c2<=0xdbff && (s2+1)!=limit2 && U16_IS_TRAIL(*(s2+1))) ||
- (U16_IS_TRAIL(c2) && start2!=s2 && U16_IS_LEAD(*(s2-1)))
- ) {
- /* part of a surrogate pair, leave >=d800 */
- } else {
- /* BMP code point - may be surrogate code point - make <d800 */
- c2-=0x2800;
- }
- }
- /* now c1 and c2 are in the requested (code unit or code point) order */
- return (int32_t)c1-(int32_t)c2;
- }
- /*
- * Compare two strings as presented by UCharIterators.
- * Use code unit or code point order.
- * When the function returns, it is undefined where the iterators
- * have stopped.
- */
- U_CAPI int32_t U_EXPORT2
- u_strCompareIter(UCharIterator *iter1, UCharIterator *iter2, UBool codePointOrder) {
- UChar32 c1, c2;
- /* argument checking */
- if(iter1==nullptr || iter2==nullptr) {
- return 0; /* bad arguments */
- }
- if(iter1==iter2) {
- return 0; /* identical iterators */
- }
- /* reset iterators to start? */
- iter1->move(iter1, 0, UITER_START);
- iter2->move(iter2, 0, UITER_START);
- /* compare identical prefixes - they do not need to be fixed up */
- for(;;) {
- c1=iter1->next(iter1);
- c2=iter2->next(iter2);
- if(c1!=c2) {
- break;
- }
- if(c1==-1) {
- return 0;
- }
- }
- /* if both values are in or above the surrogate range, fix them up */
- if(c1>=0xd800 && c2>=0xd800 && codePointOrder) {
- /* subtract 0x2800 from BMP code points to make them smaller than supplementary ones */
- if(
- (c1<=0xdbff && U16_IS_TRAIL(iter1->current(iter1))) ||
- (U16_IS_TRAIL(c1) && (iter1->previous(iter1), U16_IS_LEAD(iter1->previous(iter1))))
- ) {
- /* part of a surrogate pair, leave >=d800 */
- } else {
- /* BMP code point - may be surrogate code point - make <d800 */
- c1-=0x2800;
- }
- if(
- (c2<=0xdbff && U16_IS_TRAIL(iter2->current(iter2))) ||
- (U16_IS_TRAIL(c2) && (iter2->previous(iter2), U16_IS_LEAD(iter2->previous(iter2))))
- ) {
- /* part of a surrogate pair, leave >=d800 */
- } else {
- /* BMP code point - may be surrogate code point - make <d800 */
- c2-=0x2800;
- }
- }
- /* now c1 and c2 are in the requested (code unit or code point) order */
- return (int32_t)c1-(int32_t)c2;
- }
- #if 0
- /*
- * u_strCompareIter() does not leave the iterators _on_ the different units.
- * This is possible but would cost a few extra indirect function calls to back
- * up if the last unit (c1 or c2 respectively) was >=0.
- *
- * Consistently leaving them _behind_ the different units is not an option
- * because the current "unit" is the end of the string if that is reached,
- * and in such a case the iterator does not move.
- * For example, when comparing "ab" with "abc", both iterators rest _on_ the end
- * of their strings. Calling previous() on each does not move them to where
- * the comparison fails.
- *
- * So the simplest semantics is to not define where the iterators end up.
- *
- * The following fragment is part of what would need to be done for backing up.
- */
- void fragment {
- /* iff a surrogate is part of a surrogate pair, leave >=d800 */
- if(c1<=0xdbff) {
- if(!U16_IS_TRAIL(iter1->current(iter1))) {
- /* lead surrogate code point - make <d800 */
- c1-=0x2800;
- }
- } else if(c1<=0xdfff) {
- int32_t idx=iter1->getIndex(iter1, UITER_CURRENT);
- iter1->previous(iter1); /* ==c1 */
- if(!U16_IS_LEAD(iter1->previous(iter1))) {
- /* trail surrogate code point - make <d800 */
- c1-=0x2800;
- }
- /* go back to behind where the difference is */
- iter1->move(iter1, idx, UITER_ZERO);
- } else /* 0xe000<=c1<=0xffff */ {
- /* BMP code point - make <d800 */
- c1-=0x2800;
- }
- }
- #endif
- U_CAPI int32_t U_EXPORT2
- u_strCompare(const char16_t *s1, int32_t length1,
- const char16_t *s2, int32_t length2,
- UBool codePointOrder) {
- /* argument checking */
- if(s1==nullptr || length1<-1 || s2==nullptr || length2<-1) {
- return 0;
- }
- return uprv_strCompare(s1, length1, s2, length2, false, codePointOrder);
- }
- /* String compare in code point order - u_strcmp() compares in code unit order. */
- U_CAPI int32_t U_EXPORT2
- u_strcmpCodePointOrder(const char16_t *s1, const char16_t *s2) {
- return uprv_strCompare(s1, -1, s2, -1, false, true);
- }
- U_CAPI int32_t U_EXPORT2
- u_strncmp(const char16_t *s1,
- const char16_t *s2,
- int32_t n)
- {
- if(n > 0) {
- int32_t rc;
- for(;;) {
- rc = (int32_t)*s1 - (int32_t)*s2;
- if(rc != 0 || *s1 == 0 || --n == 0) {
- return rc;
- }
- ++s1;
- ++s2;
- }
- } else {
- return 0;
- }
- }
- U_CAPI int32_t U_EXPORT2
- u_strncmpCodePointOrder(const char16_t *s1, const char16_t *s2, int32_t n) {
- return uprv_strCompare(s1, n, s2, n, true, true);
- }
- U_CAPI char16_t* U_EXPORT2
- u_strcpy(char16_t *dst,
- const char16_t *src)
- {
- char16_t *anchor = dst; /* save a pointer to start of dst */
- while((*(dst++) = *(src++)) != 0) { /* copy string 2 over */
- }
- return anchor;
- }
- U_CAPI char16_t* U_EXPORT2
- u_strncpy(char16_t *dst,
- const char16_t *src,
- int32_t n)
- {
- char16_t *anchor = dst; /* save a pointer to start of dst */
- /* copy string 2 over */
- while(n > 0 && (*(dst++) = *(src++)) != 0) {
- --n;
- }
- return anchor;
- }
- U_CAPI int32_t U_EXPORT2
- u_strlen(const char16_t *s)
- {
- #if U_SIZEOF_WCHAR_T == U_SIZEOF_UCHAR
- return (int32_t)uprv_wcslen((const wchar_t *)s);
- #else
- const char16_t *t = s;
- while(*t != 0) {
- ++t;
- }
- return t - s;
- #endif
- }
- U_CAPI int32_t U_EXPORT2
- u_countChar32(const char16_t *s, int32_t length) {
- int32_t count;
- if(s==nullptr || length<-1) {
- return 0;
- }
- count=0;
- if(length>=0) {
- while(length>0) {
- ++count;
- if(U16_IS_LEAD(*s) && length>=2 && U16_IS_TRAIL(*(s+1))) {
- s+=2;
- length-=2;
- } else {
- ++s;
- --length;
- }
- }
- } else /* length==-1 */ {
- char16_t c;
- for(;;) {
- if((c=*s++)==0) {
- break;
- }
- ++count;
- /*
- * sufficient to look ahead one because of UTF-16;
- * safe to look ahead one because at worst that would be the terminating NUL
- */
- if(U16_IS_LEAD(c) && U16_IS_TRAIL(*s)) {
- ++s;
- }
- }
- }
- return count;
- }
- U_CAPI UBool U_EXPORT2
- u_strHasMoreChar32Than(const char16_t *s, int32_t length, int32_t number) {
- if(number<0) {
- return true;
- }
- if(s==nullptr || length<-1) {
- return false;
- }
- if(length==-1) {
- /* s is NUL-terminated */
- char16_t c;
- /* count code points until they exceed */
- for(;;) {
- if((c=*s++)==0) {
- return false;
- }
- if(number==0) {
- return true;
- }
- if(U16_IS_LEAD(c) && U16_IS_TRAIL(*s)) {
- ++s;
- }
- --number;
- }
- } else {
- /* length>=0 known */
- const char16_t *limit;
- int32_t maxSupplementary;
- /* s contains at least (length+1)/2 code points: <=2 UChars per cp */
- if(((length+1)/2)>number) {
- return true;
- }
- /* check if s does not even contain enough UChars */
- maxSupplementary=length-number;
- if(maxSupplementary<=0) {
- return false;
- }
- /* there are maxSupplementary=length-number more UChars than asked-for code points */
- /*
- * count code points until they exceed and also check that there are
- * no more than maxSupplementary supplementary code points (char16_t pairs)
- */
- limit=s+length;
- for(;;) {
- if(s==limit) {
- return false;
- }
- if(number==0) {
- return true;
- }
- if(U16_IS_LEAD(*s++) && s!=limit && U16_IS_TRAIL(*s)) {
- ++s;
- if(--maxSupplementary<=0) {
- /* too many pairs - too few code points */
- return false;
- }
- }
- --number;
- }
- }
- }
- U_CAPI char16_t * U_EXPORT2
- u_memcpy(char16_t *dest, const char16_t *src, int32_t count) {
- if(count > 0) {
- uprv_memcpy(dest, src, (size_t)count*U_SIZEOF_UCHAR);
- }
- return dest;
- }
- U_CAPI char16_t * U_EXPORT2
- u_memmove(char16_t *dest, const char16_t *src, int32_t count) {
- if(count > 0) {
- uprv_memmove(dest, src, (size_t)count*U_SIZEOF_UCHAR);
- }
- return dest;
- }
- U_CAPI char16_t * U_EXPORT2
- u_memset(char16_t *dest, char16_t c, int32_t count) {
- if(count > 0) {
- char16_t *ptr = dest;
- char16_t *limit = dest + count;
- while (ptr < limit) {
- *(ptr++) = c;
- }
- }
- return dest;
- }
- U_CAPI int32_t U_EXPORT2
- u_memcmp(const char16_t *buf1, const char16_t *buf2, int32_t count) {
- if(count > 0) {
- const char16_t *limit = buf1 + count;
- int32_t result;
- while (buf1 < limit) {
- result = (int32_t)(uint16_t)*buf1 - (int32_t)(uint16_t)*buf2;
- if (result != 0) {
- return result;
- }
- buf1++;
- buf2++;
- }
- }
- return 0;
- }
- U_CAPI int32_t U_EXPORT2
- u_memcmpCodePointOrder(const char16_t *s1, const char16_t *s2, int32_t count) {
- return uprv_strCompare(s1, count, s2, count, false, true);
- }
- /* u_unescape & support fns ------------------------------------------------- */
- /* This map must be in ASCENDING ORDER OF THE ESCAPE CODE */
- static const char16_t UNESCAPE_MAP[] = {
- /*" 0x22, 0x22 */
- /*' 0x27, 0x27 */
- /*? 0x3F, 0x3F */
- /*\ 0x5C, 0x5C */
- /*a*/ 0x61, 0x07,
- /*b*/ 0x62, 0x08,
- /*e*/ 0x65, 0x1b,
- /*f*/ 0x66, 0x0c,
- /*n*/ 0x6E, 0x0a,
- /*r*/ 0x72, 0x0d,
- /*t*/ 0x74, 0x09,
- /*v*/ 0x76, 0x0b
- };
- enum { UNESCAPE_MAP_LENGTH = UPRV_LENGTHOF(UNESCAPE_MAP) };
- /* Convert one octal digit to a numeric value 0..7, or -1 on failure */
- static int32_t _digit8(char16_t c) {
- if (c >= u'0' && c <= u'7') {
- return c - u'0';
- }
- return -1;
- }
- /* Convert one hex digit to a numeric value 0..F, or -1 on failure */
- static int32_t _digit16(char16_t c) {
- if (c >= u'0' && c <= u'9') {
- return c - u'0';
- }
- if (c >= u'A' && c <= u'F') {
- return c - (u'A' - 10);
- }
- if (c >= u'a' && c <= u'f') {
- return c - (u'a' - 10);
- }
- return -1;
- }
- /* Parse a single escape sequence. Although this method deals in
- * UChars, it does not use C++ or UnicodeString. This allows it to
- * be used from C contexts. */
- U_CAPI UChar32 U_EXPORT2
- u_unescapeAt(UNESCAPE_CHAR_AT charAt,
- int32_t *offset,
- int32_t length,
- void *context) {
- int32_t start = *offset;
- UChar32 c;
- UChar32 result = 0;
- int8_t n = 0;
- int8_t minDig = 0;
- int8_t maxDig = 0;
- int8_t bitsPerDigit = 4;
- int32_t dig;
- UBool braces = false;
- /* Check that offset is in range */
- if (*offset < 0 || *offset >= length) {
- goto err;
- }
- /* Fetch first char16_t after '\\' */
- c = charAt((*offset)++, context);
- /* Convert hexadecimal and octal escapes */
- switch (c) {
- case u'u':
- minDig = maxDig = 4;
- break;
- case u'U':
- minDig = maxDig = 8;
- break;
- case u'x':
- minDig = 1;
- if (*offset < length && charAt(*offset, context) == u'{') {
- ++(*offset);
- braces = true;
- maxDig = 8;
- } else {
- maxDig = 2;
- }
- break;
- default:
- dig = _digit8(c);
- if (dig >= 0) {
- minDig = 1;
- maxDig = 3;
- n = 1; /* Already have first octal digit */
- bitsPerDigit = 3;
- result = dig;
- }
- break;
- }
- if (minDig != 0) {
- while (*offset < length && n < maxDig) {
- c = charAt(*offset, context);
- dig = (bitsPerDigit == 3) ? _digit8(c) : _digit16(c);
- if (dig < 0) {
- break;
- }
- result = (result << bitsPerDigit) | dig;
- ++(*offset);
- ++n;
- }
- if (n < minDig) {
- goto err;
- }
- if (braces) {
- if (c != u'}') {
- goto err;
- }
- ++(*offset);
- }
- if (result < 0 || result >= 0x110000) {
- goto err;
- }
- /* If an escape sequence specifies a lead surrogate, see if
- * there is a trail surrogate after it, either as an escape or
- * as a literal. If so, join them up into a supplementary.
- */
- if (*offset < length && U16_IS_LEAD(result)) {
- int32_t ahead = *offset + 1;
- c = charAt(*offset, context);
- if (c == u'\\' && ahead < length) {
- // Calling ourselves recursively may cause a stack overflow if
- // we have repeated escaped lead surrogates.
- // Limit the length to 11 ("x{0000DFFF}") after ahead.
- int32_t tailLimit = ahead + 11;
- if (tailLimit > length) {
- tailLimit = length;
- }
- c = u_unescapeAt(charAt, &ahead, tailLimit, context);
- }
- if (U16_IS_TRAIL(c)) {
- *offset = ahead;
- result = U16_GET_SUPPLEMENTARY(result, c);
- }
- }
- return result;
- }
- /* Convert C-style escapes in table */
- for (int32_t i=0; i<UNESCAPE_MAP_LENGTH; i+=2) {
- if (c == UNESCAPE_MAP[i]) {
- return UNESCAPE_MAP[i+1];
- } else if (c < UNESCAPE_MAP[i]) {
- break;
- }
- }
- /* Map \cX to control-X: X & 0x1F */
- if (c == u'c' && *offset < length) {
- c = charAt((*offset)++, context);
- if (U16_IS_LEAD(c) && *offset < length) {
- char16_t c2 = charAt(*offset, context);
- if (U16_IS_TRAIL(c2)) {
- ++(*offset);
- c = U16_GET_SUPPLEMENTARY(c, c2);
- }
- }
- return 0x1F & c;
- }
- /* If no special forms are recognized, then consider
- * the backslash to generically escape the next character.
- * Deal with surrogate pairs. */
- if (U16_IS_LEAD(c) && *offset < length) {
- char16_t c2 = charAt(*offset, context);
- if (U16_IS_TRAIL(c2)) {
- ++(*offset);
- return U16_GET_SUPPLEMENTARY(c, c2);
- }
- }
- return c;
- err:
- /* Invalid escape sequence */
- *offset = start; /* Reset to initial value */
- return (UChar32)0xFFFFFFFF;
- }
- /* u_unescapeAt() callback to return a char16_t from a char* */
- static char16_t U_CALLCONV
- _charPtr_charAt(int32_t offset, void *context) {
- char16_t c16;
- /* It would be more efficient to access the invariant tables
- * directly but there is no API for that. */
- u_charsToUChars(static_cast<char*>(context) + offset, &c16, 1);
- return c16;
- }
- /* Append an escape-free segment of the text; used by u_unescape() */
- static void _appendUChars(char16_t *dest, int32_t destCapacity,
- const char *src, int32_t srcLen) {
- if (destCapacity < 0) {
- destCapacity = 0;
- }
- if (srcLen > destCapacity) {
- srcLen = destCapacity;
- }
- u_charsToUChars(src, dest, srcLen);
- }
- /* Do an invariant conversion of char* -> char16_t*, with escape parsing */
- U_CAPI int32_t U_EXPORT2
- u_unescape(const char *src, char16_t *dest, int32_t destCapacity) {
- const char *segment = src;
- int32_t i = 0;
- char c;
- while ((c=*src) != 0) {
- /* '\\' intentionally written as compiler-specific
- * character constant to correspond to compiler-specific
- * char* constants. */
- if (c == '\\') {
- int32_t lenParsed = 0;
- UChar32 c32;
- if (src != segment) {
- if (dest != nullptr) {
- _appendUChars(dest + i, destCapacity - i,
- segment, (int32_t)(src - segment));
- }
- i += (int32_t)(src - segment);
- }
- ++src; /* advance past '\\' */
- c32 = u_unescapeAt(_charPtr_charAt, &lenParsed, (int32_t)uprv_strlen(src), const_cast<char*>(src));
- if (lenParsed == 0) {
- goto err;
- }
- src += lenParsed; /* advance past escape seq. */
- if (dest != nullptr && U16_LENGTH(c32) <= (destCapacity - i)) {
- U16_APPEND_UNSAFE(dest, i, c32);
- } else {
- i += U16_LENGTH(c32);
- }
- segment = src;
- } else {
- ++src;
- }
- }
- if (src != segment) {
- if (dest != nullptr) {
- _appendUChars(dest + i, destCapacity - i,
- segment, (int32_t)(src - segment));
- }
- i += (int32_t)(src - segment);
- }
- if (dest != nullptr && i < destCapacity) {
- dest[i] = 0;
- }
- return i;
- err:
- if (dest != nullptr && destCapacity > 0) {
- *dest = 0;
- }
- return 0;
- }
- /* NUL-termination of strings ----------------------------------------------- */
- /**
- * NUL-terminate a string no matter what its type.
- * Set warning and error codes accordingly.
- */
- #define __TERMINATE_STRING(dest, destCapacity, length, pErrorCode) UPRV_BLOCK_MACRO_BEGIN { \
- if(pErrorCode!=nullptr && U_SUCCESS(*pErrorCode)) { \
- /* not a public function, so no complete argument checking */ \
- \
- if(length<0) { \
- /* assume that the caller handles this */ \
- } else if(length<destCapacity) { \
- /* NUL-terminate the string, the NUL fits */ \
- dest[length]=0; \
- /* unset the not-terminated warning but leave all others */ \
- if(*pErrorCode==U_STRING_NOT_TERMINATED_WARNING) { \
- *pErrorCode=U_ZERO_ERROR; \
- } \
- } else if(length==destCapacity) { \
- /* unable to NUL-terminate, but the string itself fit - set a warning code */ \
- *pErrorCode=U_STRING_NOT_TERMINATED_WARNING; \
- } else /* length>destCapacity */ { \
- /* even the string itself did not fit - set an error code */ \
- *pErrorCode=U_BUFFER_OVERFLOW_ERROR; \
- } \
- } \
- } UPRV_BLOCK_MACRO_END
- U_CAPI char16_t U_EXPORT2
- u_asciiToUpper(char16_t c) {
- if (u'a' <= c && c <= u'z') {
- c = c + u'A' - u'a';
- }
- return c;
- }
- U_CAPI int32_t U_EXPORT2
- u_terminateUChars(char16_t *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
- __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
- return length;
- }
- U_CAPI int32_t U_EXPORT2
- u_terminateChars(char *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
- __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
- return length;
- }
- U_CAPI int32_t U_EXPORT2
- u_terminateUChar32s(UChar32 *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
- __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
- return length;
- }
- U_CAPI int32_t U_EXPORT2
- u_terminateWChars(wchar_t *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
- __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
- return length;
- }
- // Compute the hash code for a string -------------------------------------- ***
- // Moved here from uhash.c so that UnicodeString::hashCode() does not depend
- // on UHashtable code.
- /*
- Compute the hash by iterating sparsely over about 32 (up to 63)
- characters spaced evenly through the string. For each character,
- multiply the previous hash value by a prime number and add the new
- character in, like a linear congruential random number generator,
- producing a pseudorandom deterministic value well distributed over
- the output range. [LIU]
- */
- #define STRING_HASH(TYPE, STR, STRLEN, DEREF) UPRV_BLOCK_MACRO_BEGIN { \
- uint32_t hash = 0; \
- const TYPE *p = (const TYPE*) STR; \
- if (p != nullptr) { \
- int32_t len = (int32_t)(STRLEN); \
- int32_t inc = ((len - 32) / 32) + 1; \
- const TYPE *limit = p + len; \
- while (p<limit) { \
- hash = (hash * 37) + DEREF; \
- p += inc; \
- } \
- } \
- return static_cast<int32_t>(hash); \
- } UPRV_BLOCK_MACRO_END
- /* Used by UnicodeString to compute its hashcode - Not public API. */
- U_CAPI int32_t U_EXPORT2
- ustr_hashUCharsN(const char16_t *str, int32_t length) {
- STRING_HASH(char16_t, str, length, *p);
- }
- U_CAPI int32_t U_EXPORT2
- ustr_hashCharsN(const char *str, int32_t length) {
- STRING_HASH(uint8_t, str, length, *p);
- }
- U_CAPI int32_t U_EXPORT2
- ustr_hashICharsN(const char *str, int32_t length) {
- STRING_HASH(char, str, length, (uint8_t)uprv_tolower(*p));
- }
|