intl/icu/source/common/ustring.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 ******************************************************************************
michael@0 3 *
michael@0 4 * Copyright (C) 1998-2012, International Business Machines
michael@0 5 * Corporation and others. All Rights Reserved.
michael@0 6 *
michael@0 7 ******************************************************************************
michael@0 8 *
michael@0 9 * File ustring.cpp
michael@0 10 *
michael@0 11 * Modification History:
michael@0 12 *
michael@0 13 * Date Name Description
michael@0 14 * 12/07/98 bertrand Creation.
michael@0 15 ******************************************************************************
michael@0 16 */
michael@0 17
michael@0 18 #include "unicode/utypes.h"
michael@0 19 #include "unicode/putil.h"
michael@0 20 #include "unicode/ustring.h"
michael@0 21 #include "unicode/utf16.h"
michael@0 22 #include "cstring.h"
michael@0 23 #include "cwchar.h"
michael@0 24 #include "cmemory.h"
michael@0 25 #include "ustr_imp.h"
michael@0 26
michael@0 27 /* ANSI string.h - style functions ------------------------------------------ */
michael@0 28
michael@0 29 /* U+ffff is the highest BMP code point, the highest one that fits into a 16-bit UChar */
michael@0 30 #define U_BMP_MAX 0xffff
michael@0 31
michael@0 32 /* Forward binary string search functions ----------------------------------- */
michael@0 33
michael@0 34 /*
michael@0 35 * Test if a substring match inside a string is at code point boundaries.
michael@0 36 * All pointers refer to the same buffer.
michael@0 37 * The limit pointer may be NULL, all others must be real pointers.
michael@0 38 */
michael@0 39 static inline UBool
michael@0 40 isMatchAtCPBoundary(const UChar *start, const UChar *match, const UChar *matchLimit, const UChar *limit) {
michael@0 41 if(U16_IS_TRAIL(*match) && start!=match && U16_IS_LEAD(*(match-1))) {
michael@0 42 /* the leading edge of the match is in the middle of a surrogate pair */
michael@0 43 return FALSE;
michael@0 44 }
michael@0 45 if(U16_IS_LEAD(*(matchLimit-1)) && match!=limit && U16_IS_TRAIL(*matchLimit)) {
michael@0 46 /* the trailing edge of the match is in the middle of a surrogate pair */
michael@0 47 return FALSE;
michael@0 48 }
michael@0 49 return TRUE;
michael@0 50 }
michael@0 51
michael@0 52 U_CAPI UChar * U_EXPORT2
michael@0 53 u_strFindFirst(const UChar *s, int32_t length,
michael@0 54 const UChar *sub, int32_t subLength) {
michael@0 55 const UChar *start, *p, *q, *subLimit;
michael@0 56 UChar c, cs, cq;
michael@0 57
michael@0 58 if(sub==NULL || subLength<-1) {
michael@0 59 return (UChar *)s;
michael@0 60 }
michael@0 61 if(s==NULL || length<-1) {
michael@0 62 return NULL;
michael@0 63 }
michael@0 64
michael@0 65 start=s;
michael@0 66
michael@0 67 if(length<0 && subLength<0) {
michael@0 68 /* both strings are NUL-terminated */
michael@0 69 if((cs=*sub++)==0) {
michael@0 70 return (UChar *)s;
michael@0 71 }
michael@0 72 if(*sub==0 && !U16_IS_SURROGATE(cs)) {
michael@0 73 /* the substring consists of a single, non-surrogate BMP code point */
michael@0 74 return u_strchr(s, cs);
michael@0 75 }
michael@0 76
michael@0 77 while((c=*s++)!=0) {
michael@0 78 if(c==cs) {
michael@0 79 /* found first substring UChar, compare rest */
michael@0 80 p=s;
michael@0 81 q=sub;
michael@0 82 for(;;) {
michael@0 83 if((cq=*q)==0) {
michael@0 84 if(isMatchAtCPBoundary(start, s-1, p, NULL)) {
michael@0 85 return (UChar *)(s-1); /* well-formed match */
michael@0 86 } else {
michael@0 87 break; /* no match because surrogate pair is split */
michael@0 88 }
michael@0 89 }
michael@0 90 if((c=*p)==0) {
michael@0 91 return NULL; /* no match, and none possible after s */
michael@0 92 }
michael@0 93 if(c!=cq) {
michael@0 94 break; /* no match */
michael@0 95 }
michael@0 96 ++p;
michael@0 97 ++q;
michael@0 98 }
michael@0 99 }
michael@0 100 }
michael@0 101
michael@0 102 /* not found */
michael@0 103 return NULL;
michael@0 104 }
michael@0 105
michael@0 106 if(subLength<0) {
michael@0 107 subLength=u_strlen(sub);
michael@0 108 }
michael@0 109 if(subLength==0) {
michael@0 110 return (UChar *)s;
michael@0 111 }
michael@0 112
michael@0 113 /* get sub[0] to search for it fast */
michael@0 114 cs=*sub++;
michael@0 115 --subLength;
michael@0 116 subLimit=sub+subLength;
michael@0 117
michael@0 118 if(subLength==0 && !U16_IS_SURROGATE(cs)) {
michael@0 119 /* the substring consists of a single, non-surrogate BMP code point */
michael@0 120 return length<0 ? u_strchr(s, cs) : u_memchr(s, cs, length);
michael@0 121 }
michael@0 122
michael@0 123 if(length<0) {
michael@0 124 /* s is NUL-terminated */
michael@0 125 while((c=*s++)!=0) {
michael@0 126 if(c==cs) {
michael@0 127 /* found first substring UChar, compare rest */
michael@0 128 p=s;
michael@0 129 q=sub;
michael@0 130 for(;;) {
michael@0 131 if(q==subLimit) {
michael@0 132 if(isMatchAtCPBoundary(start, s-1, p, NULL)) {
michael@0 133 return (UChar *)(s-1); /* well-formed match */
michael@0 134 } else {
michael@0 135 break; /* no match because surrogate pair is split */
michael@0 136 }
michael@0 137 }
michael@0 138 if((c=*p)==0) {
michael@0 139 return NULL; /* no match, and none possible after s */
michael@0 140 }
michael@0 141 if(c!=*q) {
michael@0 142 break; /* no match */
michael@0 143 }
michael@0 144 ++p;
michael@0 145 ++q;
michael@0 146 }
michael@0 147 }
michael@0 148 }
michael@0 149 } else {
michael@0 150 const UChar *limit, *preLimit;
michael@0 151
michael@0 152 /* subLength was decremented above */
michael@0 153 if(length<=subLength) {
michael@0 154 return NULL; /* s is shorter than sub */
michael@0 155 }
michael@0 156
michael@0 157 limit=s+length;
michael@0 158
michael@0 159 /* the substring must start before preLimit */
michael@0 160 preLimit=limit-subLength;
michael@0 161
michael@0 162 while(s!=preLimit) {
michael@0 163 c=*s++;
michael@0 164 if(c==cs) {
michael@0 165 /* found first substring UChar, compare rest */
michael@0 166 p=s;
michael@0 167 q=sub;
michael@0 168 for(;;) {
michael@0 169 if(q==subLimit) {
michael@0 170 if(isMatchAtCPBoundary(start, s-1, p, limit)) {
michael@0 171 return (UChar *)(s-1); /* well-formed match */
michael@0 172 } else {
michael@0 173 break; /* no match because surrogate pair is split */
michael@0 174 }
michael@0 175 }
michael@0 176 if(*p!=*q) {
michael@0 177 break; /* no match */
michael@0 178 }
michael@0 179 ++p;
michael@0 180 ++q;
michael@0 181 }
michael@0 182 }
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 /* not found */
michael@0 187 return NULL;
michael@0 188 }
michael@0 189
michael@0 190 U_CAPI UChar * U_EXPORT2
michael@0 191 u_strstr(const UChar *s, const UChar *substring) {
michael@0 192 return u_strFindFirst(s, -1, substring, -1);
michael@0 193 }
michael@0 194
michael@0 195 U_CAPI UChar * U_EXPORT2
michael@0 196 u_strchr(const UChar *s, UChar c) {
michael@0 197 if(U16_IS_SURROGATE(c)) {
michael@0 198 /* make sure to not find half of a surrogate pair */
michael@0 199 return u_strFindFirst(s, -1, &c, 1);
michael@0 200 } else {
michael@0 201 UChar cs;
michael@0 202
michael@0 203 /* trivial search for a BMP code point */
michael@0 204 for(;;) {
michael@0 205 if((cs=*s)==c) {
michael@0 206 return (UChar *)s;
michael@0 207 }
michael@0 208 if(cs==0) {
michael@0 209 return NULL;
michael@0 210 }
michael@0 211 ++s;
michael@0 212 }
michael@0 213 }
michael@0 214 }
michael@0 215
michael@0 216 U_CAPI UChar * U_EXPORT2
michael@0 217 u_strchr32(const UChar *s, UChar32 c) {
michael@0 218 if((uint32_t)c<=U_BMP_MAX) {
michael@0 219 /* find BMP code point */
michael@0 220 return u_strchr(s, (UChar)c);
michael@0 221 } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
michael@0 222 /* find supplementary code point as surrogate pair */
michael@0 223 UChar cs, lead=U16_LEAD(c), trail=U16_TRAIL(c);
michael@0 224
michael@0 225 while((cs=*s++)!=0) {
michael@0 226 if(cs==lead && *s==trail) {
michael@0 227 return (UChar *)(s-1);
michael@0 228 }
michael@0 229 }
michael@0 230 return NULL;
michael@0 231 } else {
michael@0 232 /* not a Unicode code point, not findable */
michael@0 233 return NULL;
michael@0 234 }
michael@0 235 }
michael@0 236
michael@0 237 U_CAPI UChar * U_EXPORT2
michael@0 238 u_memchr(const UChar *s, UChar c, int32_t count) {
michael@0 239 if(count<=0) {
michael@0 240 return NULL; /* no string */
michael@0 241 } else if(U16_IS_SURROGATE(c)) {
michael@0 242 /* make sure to not find half of a surrogate pair */
michael@0 243 return u_strFindFirst(s, count, &c, 1);
michael@0 244 } else {
michael@0 245 /* trivial search for a BMP code point */
michael@0 246 const UChar *limit=s+count;
michael@0 247 do {
michael@0 248 if(*s==c) {
michael@0 249 return (UChar *)s;
michael@0 250 }
michael@0 251 } while(++s!=limit);
michael@0 252 return NULL;
michael@0 253 }
michael@0 254 }
michael@0 255
michael@0 256 U_CAPI UChar * U_EXPORT2
michael@0 257 u_memchr32(const UChar *s, UChar32 c, int32_t count) {
michael@0 258 if((uint32_t)c<=U_BMP_MAX) {
michael@0 259 /* find BMP code point */
michael@0 260 return u_memchr(s, (UChar)c, count);
michael@0 261 } else if(count<2) {
michael@0 262 /* too short for a surrogate pair */
michael@0 263 return NULL;
michael@0 264 } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
michael@0 265 /* find supplementary code point as surrogate pair */
michael@0 266 const UChar *limit=s+count-1; /* -1 so that we do not need a separate check for the trail unit */
michael@0 267 UChar lead=U16_LEAD(c), trail=U16_TRAIL(c);
michael@0 268
michael@0 269 do {
michael@0 270 if(*s==lead && *(s+1)==trail) {
michael@0 271 return (UChar *)s;
michael@0 272 }
michael@0 273 } while(++s!=limit);
michael@0 274 return NULL;
michael@0 275 } else {
michael@0 276 /* not a Unicode code point, not findable */
michael@0 277 return NULL;
michael@0 278 }
michael@0 279 }
michael@0 280
michael@0 281 /* Backward binary string search functions ---------------------------------- */
michael@0 282
michael@0 283 U_CAPI UChar * U_EXPORT2
michael@0 284 u_strFindLast(const UChar *s, int32_t length,
michael@0 285 const UChar *sub, int32_t subLength) {
michael@0 286 const UChar *start, *limit, *p, *q, *subLimit;
michael@0 287 UChar c, cs;
michael@0 288
michael@0 289 if(sub==NULL || subLength<-1) {
michael@0 290 return (UChar *)s;
michael@0 291 }
michael@0 292 if(s==NULL || length<-1) {
michael@0 293 return NULL;
michael@0 294 }
michael@0 295
michael@0 296 /*
michael@0 297 * This implementation is more lazy than the one for u_strFindFirst():
michael@0 298 * There is no special search code for NUL-terminated strings.
michael@0 299 * It does not seem to be worth it for searching substrings to
michael@0 300 * search forward and find all matches like in u_strrchr() and similar.
michael@0 301 * Therefore, we simply get both string lengths and search backward.
michael@0 302 *
michael@0 303 * markus 2002oct23
michael@0 304 */
michael@0 305
michael@0 306 if(subLength<0) {
michael@0 307 subLength=u_strlen(sub);
michael@0 308 }
michael@0 309 if(subLength==0) {
michael@0 310 return (UChar *)s;
michael@0 311 }
michael@0 312
michael@0 313 /* get sub[subLength-1] to search for it fast */
michael@0 314 subLimit=sub+subLength;
michael@0 315 cs=*(--subLimit);
michael@0 316 --subLength;
michael@0 317
michael@0 318 if(subLength==0 && !U16_IS_SURROGATE(cs)) {
michael@0 319 /* the substring consists of a single, non-surrogate BMP code point */
michael@0 320 return length<0 ? u_strrchr(s, cs) : u_memrchr(s, cs, length);
michael@0 321 }
michael@0 322
michael@0 323 if(length<0) {
michael@0 324 length=u_strlen(s);
michael@0 325 }
michael@0 326
michael@0 327 /* subLength was decremented above */
michael@0 328 if(length<=subLength) {
michael@0 329 return NULL; /* s is shorter than sub */
michael@0 330 }
michael@0 331
michael@0 332 start=s;
michael@0 333 limit=s+length;
michael@0 334
michael@0 335 /* the substring must start no later than s+subLength */
michael@0 336 s+=subLength;
michael@0 337
michael@0 338 while(s!=limit) {
michael@0 339 c=*(--limit);
michael@0 340 if(c==cs) {
michael@0 341 /* found last substring UChar, compare rest */
michael@0 342 p=limit;
michael@0 343 q=subLimit;
michael@0 344 for(;;) {
michael@0 345 if(q==sub) {
michael@0 346 if(isMatchAtCPBoundary(start, p, limit+1, start+length)) {
michael@0 347 return (UChar *)p; /* well-formed match */
michael@0 348 } else {
michael@0 349 break; /* no match because surrogate pair is split */
michael@0 350 }
michael@0 351 }
michael@0 352 if(*(--p)!=*(--q)) {
michael@0 353 break; /* no match */
michael@0 354 }
michael@0 355 }
michael@0 356 }
michael@0 357 }
michael@0 358
michael@0 359 /* not found */
michael@0 360 return NULL;
michael@0 361 }
michael@0 362
michael@0 363 U_CAPI UChar * U_EXPORT2
michael@0 364 u_strrstr(const UChar *s, const UChar *substring) {
michael@0 365 return u_strFindLast(s, -1, substring, -1);
michael@0 366 }
michael@0 367
michael@0 368 U_CAPI UChar * U_EXPORT2
michael@0 369 u_strrchr(const UChar *s, UChar c) {
michael@0 370 if(U16_IS_SURROGATE(c)) {
michael@0 371 /* make sure to not find half of a surrogate pair */
michael@0 372 return u_strFindLast(s, -1, &c, 1);
michael@0 373 } else {
michael@0 374 const UChar *result=NULL;
michael@0 375 UChar cs;
michael@0 376
michael@0 377 /* trivial search for a BMP code point */
michael@0 378 for(;;) {
michael@0 379 if((cs=*s)==c) {
michael@0 380 result=s;
michael@0 381 }
michael@0 382 if(cs==0) {
michael@0 383 return (UChar *)result;
michael@0 384 }
michael@0 385 ++s;
michael@0 386 }
michael@0 387 }
michael@0 388 }
michael@0 389
michael@0 390 U_CAPI UChar * U_EXPORT2
michael@0 391 u_strrchr32(const UChar *s, UChar32 c) {
michael@0 392 if((uint32_t)c<=U_BMP_MAX) {
michael@0 393 /* find BMP code point */
michael@0 394 return u_strrchr(s, (UChar)c);
michael@0 395 } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
michael@0 396 /* find supplementary code point as surrogate pair */
michael@0 397 const UChar *result=NULL;
michael@0 398 UChar cs, lead=U16_LEAD(c), trail=U16_TRAIL(c);
michael@0 399
michael@0 400 while((cs=*s++)!=0) {
michael@0 401 if(cs==lead && *s==trail) {
michael@0 402 result=s-1;
michael@0 403 }
michael@0 404 }
michael@0 405 return (UChar *)result;
michael@0 406 } else {
michael@0 407 /* not a Unicode code point, not findable */
michael@0 408 return NULL;
michael@0 409 }
michael@0 410 }
michael@0 411
michael@0 412 U_CAPI UChar * U_EXPORT2
michael@0 413 u_memrchr(const UChar *s, UChar c, int32_t count) {
michael@0 414 if(count<=0) {
michael@0 415 return NULL; /* no string */
michael@0 416 } else if(U16_IS_SURROGATE(c)) {
michael@0 417 /* make sure to not find half of a surrogate pair */
michael@0 418 return u_strFindLast(s, count, &c, 1);
michael@0 419 } else {
michael@0 420 /* trivial search for a BMP code point */
michael@0 421 const UChar *limit=s+count;
michael@0 422 do {
michael@0 423 if(*(--limit)==c) {
michael@0 424 return (UChar *)limit;
michael@0 425 }
michael@0 426 } while(s!=limit);
michael@0 427 return NULL;
michael@0 428 }
michael@0 429 }
michael@0 430
michael@0 431 U_CAPI UChar * U_EXPORT2
michael@0 432 u_memrchr32(const UChar *s, UChar32 c, int32_t count) {
michael@0 433 if((uint32_t)c<=U_BMP_MAX) {
michael@0 434 /* find BMP code point */
michael@0 435 return u_memrchr(s, (UChar)c, count);
michael@0 436 } else if(count<2) {
michael@0 437 /* too short for a surrogate pair */
michael@0 438 return NULL;
michael@0 439 } else if((uint32_t)c<=UCHAR_MAX_VALUE) {
michael@0 440 /* find supplementary code point as surrogate pair */
michael@0 441 const UChar *limit=s+count-1;
michael@0 442 UChar lead=U16_LEAD(c), trail=U16_TRAIL(c);
michael@0 443
michael@0 444 do {
michael@0 445 if(*limit==trail && *(limit-1)==lead) {
michael@0 446 return (UChar *)(limit-1);
michael@0 447 }
michael@0 448 } while(s!=--limit);
michael@0 449 return NULL;
michael@0 450 } else {
michael@0 451 /* not a Unicode code point, not findable */
michael@0 452 return NULL;
michael@0 453 }
michael@0 454 }
michael@0 455
michael@0 456 /* Tokenization functions --------------------------------------------------- */
michael@0 457
michael@0 458 /*
michael@0 459 * Match each code point in a string against each code point in the matchSet.
michael@0 460 * Return the index of the first string code point that
michael@0 461 * is (polarity==TRUE) or is not (FALSE) contained in the matchSet.
michael@0 462 * Return -(string length)-1 if there is no such code point.
michael@0 463 */
michael@0 464 static int32_t
michael@0 465 _matchFromSet(const UChar *string, const UChar *matchSet, UBool polarity) {
michael@0 466 int32_t matchLen, matchBMPLen, strItr, matchItr;
michael@0 467 UChar32 stringCh, matchCh;
michael@0 468 UChar c, c2;
michael@0 469
michael@0 470 /* first part of matchSet contains only BMP code points */
michael@0 471 matchBMPLen = 0;
michael@0 472 while((c = matchSet[matchBMPLen]) != 0 && U16_IS_SINGLE(c)) {
michael@0 473 ++matchBMPLen;
michael@0 474 }
michael@0 475
michael@0 476 /* second part of matchSet contains BMP and supplementary code points */
michael@0 477 matchLen = matchBMPLen;
michael@0 478 while(matchSet[matchLen] != 0) {
michael@0 479 ++matchLen;
michael@0 480 }
michael@0 481
michael@0 482 for(strItr = 0; (c = string[strItr]) != 0;) {
michael@0 483 ++strItr;
michael@0 484 if(U16_IS_SINGLE(c)) {
michael@0 485 if(polarity) {
michael@0 486 for(matchItr = 0; matchItr < matchLen; ++matchItr) {
michael@0 487 if(c == matchSet[matchItr]) {
michael@0 488 return strItr - 1; /* one matches */
michael@0 489 }
michael@0 490 }
michael@0 491 } else {
michael@0 492 for(matchItr = 0; matchItr < matchLen; ++matchItr) {
michael@0 493 if(c == matchSet[matchItr]) {
michael@0 494 goto endloop;
michael@0 495 }
michael@0 496 }
michael@0 497 return strItr - 1; /* none matches */
michael@0 498 }
michael@0 499 } else {
michael@0 500 /*
michael@0 501 * No need to check for string length before U16_IS_TRAIL
michael@0 502 * because c2 could at worst be the terminating NUL.
michael@0 503 */
michael@0 504 if(U16_IS_SURROGATE_LEAD(c) && U16_IS_TRAIL(c2 = string[strItr])) {
michael@0 505 ++strItr;
michael@0 506 stringCh = U16_GET_SUPPLEMENTARY(c, c2);
michael@0 507 } else {
michael@0 508 stringCh = c; /* unpaired trail surrogate */
michael@0 509 }
michael@0 510
michael@0 511 if(polarity) {
michael@0 512 for(matchItr = matchBMPLen; matchItr < matchLen;) {
michael@0 513 U16_NEXT(matchSet, matchItr, matchLen, matchCh);
michael@0 514 if(stringCh == matchCh) {
michael@0 515 return strItr - U16_LENGTH(stringCh); /* one matches */
michael@0 516 }
michael@0 517 }
michael@0 518 } else {
michael@0 519 for(matchItr = matchBMPLen; matchItr < matchLen;) {
michael@0 520 U16_NEXT(matchSet, matchItr, matchLen, matchCh);
michael@0 521 if(stringCh == matchCh) {
michael@0 522 goto endloop;
michael@0 523 }
michael@0 524 }
michael@0 525 return strItr - U16_LENGTH(stringCh); /* none matches */
michael@0 526 }
michael@0 527 }
michael@0 528 endloop:
michael@0 529 /* wish C had continue with labels like Java... */;
michael@0 530 }
michael@0 531
michael@0 532 /* Didn't find it. */
michael@0 533 return -strItr-1;
michael@0 534 }
michael@0 535
michael@0 536 /* Search for a codepoint in a string that matches one of the matchSet codepoints. */
michael@0 537 U_CAPI UChar * U_EXPORT2
michael@0 538 u_strpbrk(const UChar *string, const UChar *matchSet)
michael@0 539 {
michael@0 540 int32_t idx = _matchFromSet(string, matchSet, TRUE);
michael@0 541 if(idx >= 0) {
michael@0 542 return (UChar *)string + idx;
michael@0 543 } else {
michael@0 544 return NULL;
michael@0 545 }
michael@0 546 }
michael@0 547
michael@0 548 /* Search for a codepoint in a string that matches one of the matchSet codepoints. */
michael@0 549 U_CAPI int32_t U_EXPORT2
michael@0 550 u_strcspn(const UChar *string, const UChar *matchSet)
michael@0 551 {
michael@0 552 int32_t idx = _matchFromSet(string, matchSet, TRUE);
michael@0 553 if(idx >= 0) {
michael@0 554 return idx;
michael@0 555 } else {
michael@0 556 return -idx - 1; /* == u_strlen(string) */
michael@0 557 }
michael@0 558 }
michael@0 559
michael@0 560 /* Search for a codepoint in a string that does not match one of the matchSet codepoints. */
michael@0 561 U_CAPI int32_t U_EXPORT2
michael@0 562 u_strspn(const UChar *string, const UChar *matchSet)
michael@0 563 {
michael@0 564 int32_t idx = _matchFromSet(string, matchSet, FALSE);
michael@0 565 if(idx >= 0) {
michael@0 566 return idx;
michael@0 567 } else {
michael@0 568 return -idx - 1; /* == u_strlen(string) */
michael@0 569 }
michael@0 570 }
michael@0 571
michael@0 572 /* ----- Text manipulation functions --- */
michael@0 573
michael@0 574 U_CAPI UChar* U_EXPORT2
michael@0 575 u_strtok_r(UChar *src,
michael@0 576 const UChar *delim,
michael@0 577 UChar **saveState)
michael@0 578 {
michael@0 579 UChar *tokSource;
michael@0 580 UChar *nextToken;
michael@0 581 uint32_t nonDelimIdx;
michael@0 582
michael@0 583 /* If saveState is NULL, the user messed up. */
michael@0 584 if (src != NULL) {
michael@0 585 tokSource = src;
michael@0 586 *saveState = src; /* Set to "src" in case there are no delimiters */
michael@0 587 }
michael@0 588 else if (*saveState) {
michael@0 589 tokSource = *saveState;
michael@0 590 }
michael@0 591 else {
michael@0 592 /* src == NULL && *saveState == NULL */
michael@0 593 /* This shouldn't happen. We already finished tokenizing. */
michael@0 594 return NULL;
michael@0 595 }
michael@0 596
michael@0 597 /* Skip initial delimiters */
michael@0 598 nonDelimIdx = u_strspn(tokSource, delim);
michael@0 599 tokSource = &tokSource[nonDelimIdx];
michael@0 600
michael@0 601 if (*tokSource) {
michael@0 602 nextToken = u_strpbrk(tokSource, delim);
michael@0 603 if (nextToken != NULL) {
michael@0 604 /* Create a token */
michael@0 605 *(nextToken++) = 0;
michael@0 606 *saveState = nextToken;
michael@0 607 return tokSource;
michael@0 608 }
michael@0 609 else if (*saveState) {
michael@0 610 /* Return the last token */
michael@0 611 *saveState = NULL;
michael@0 612 return tokSource;
michael@0 613 }
michael@0 614 }
michael@0 615 else {
michael@0 616 /* No tokens were found. Only delimiters were left. */
michael@0 617 *saveState = NULL;
michael@0 618 }
michael@0 619 return NULL;
michael@0 620 }
michael@0 621
michael@0 622 /* Miscellaneous functions -------------------------------------------------- */
michael@0 623
michael@0 624 U_CAPI UChar* U_EXPORT2
michael@0 625 u_strcat(UChar *dst,
michael@0 626 const UChar *src)
michael@0 627 {
michael@0 628 UChar *anchor = dst; /* save a pointer to start of dst */
michael@0 629
michael@0 630 while(*dst != 0) { /* To end of first string */
michael@0 631 ++dst;
michael@0 632 }
michael@0 633 while((*(dst++) = *(src++)) != 0) { /* copy string 2 over */
michael@0 634 }
michael@0 635
michael@0 636 return anchor;
michael@0 637 }
michael@0 638
michael@0 639 U_CAPI UChar* U_EXPORT2
michael@0 640 u_strncat(UChar *dst,
michael@0 641 const UChar *src,
michael@0 642 int32_t n )
michael@0 643 {
michael@0 644 if(n > 0) {
michael@0 645 UChar *anchor = dst; /* save a pointer to start of dst */
michael@0 646
michael@0 647 while(*dst != 0) { /* To end of first string */
michael@0 648 ++dst;
michael@0 649 }
michael@0 650 while((*dst = *src) != 0) { /* copy string 2 over */
michael@0 651 ++dst;
michael@0 652 if(--n == 0) {
michael@0 653 *dst = 0;
michael@0 654 break;
michael@0 655 }
michael@0 656 ++src;
michael@0 657 }
michael@0 658
michael@0 659 return anchor;
michael@0 660 } else {
michael@0 661 return dst;
michael@0 662 }
michael@0 663 }
michael@0 664
michael@0 665 /* ----- Text property functions --- */
michael@0 666
michael@0 667 U_CAPI int32_t U_EXPORT2
michael@0 668 u_strcmp(const UChar *s1,
michael@0 669 const UChar *s2)
michael@0 670 {
michael@0 671 UChar c1, c2;
michael@0 672
michael@0 673 for(;;) {
michael@0 674 c1=*s1++;
michael@0 675 c2=*s2++;
michael@0 676 if (c1 != c2 || c1 == 0) {
michael@0 677 break;
michael@0 678 }
michael@0 679 }
michael@0 680 return (int32_t)c1 - (int32_t)c2;
michael@0 681 }
michael@0 682
michael@0 683 U_CFUNC int32_t U_EXPORT2
michael@0 684 uprv_strCompare(const UChar *s1, int32_t length1,
michael@0 685 const UChar *s2, int32_t length2,
michael@0 686 UBool strncmpStyle, UBool codePointOrder) {
michael@0 687 const UChar *start1, *start2, *limit1, *limit2;
michael@0 688 UChar c1, c2;
michael@0 689
michael@0 690 /* setup for fix-up */
michael@0 691 start1=s1;
michael@0 692 start2=s2;
michael@0 693
michael@0 694 /* compare identical prefixes - they do not need to be fixed up */
michael@0 695 if(length1<0 && length2<0) {
michael@0 696 /* strcmp style, both NUL-terminated */
michael@0 697 if(s1==s2) {
michael@0 698 return 0;
michael@0 699 }
michael@0 700
michael@0 701 for(;;) {
michael@0 702 c1=*s1;
michael@0 703 c2=*s2;
michael@0 704 if(c1!=c2) {
michael@0 705 break;
michael@0 706 }
michael@0 707 if(c1==0) {
michael@0 708 return 0;
michael@0 709 }
michael@0 710 ++s1;
michael@0 711 ++s2;
michael@0 712 }
michael@0 713
michael@0 714 /* setup for fix-up */
michael@0 715 limit1=limit2=NULL;
michael@0 716 } else if(strncmpStyle) {
michael@0 717 /* special handling for strncmp, assume length1==length2>=0 but also check for NUL */
michael@0 718 if(s1==s2) {
michael@0 719 return 0;
michael@0 720 }
michael@0 721
michael@0 722 limit1=start1+length1;
michael@0 723
michael@0 724 for(;;) {
michael@0 725 /* both lengths are same, check only one limit */
michael@0 726 if(s1==limit1) {
michael@0 727 return 0;
michael@0 728 }
michael@0 729
michael@0 730 c1=*s1;
michael@0 731 c2=*s2;
michael@0 732 if(c1!=c2) {
michael@0 733 break;
michael@0 734 }
michael@0 735 if(c1==0) {
michael@0 736 return 0;
michael@0 737 }
michael@0 738 ++s1;
michael@0 739 ++s2;
michael@0 740 }
michael@0 741
michael@0 742 /* setup for fix-up */
michael@0 743 limit2=start2+length1; /* use length1 here, too, to enforce assumption */
michael@0 744 } else {
michael@0 745 /* memcmp/UnicodeString style, both length-specified */
michael@0 746 int32_t lengthResult;
michael@0 747
michael@0 748 if(length1<0) {
michael@0 749 length1=u_strlen(s1);
michael@0 750 }
michael@0 751 if(length2<0) {
michael@0 752 length2=u_strlen(s2);
michael@0 753 }
michael@0 754
michael@0 755 /* limit1=start1+min(lenght1, length2) */
michael@0 756 if(length1<length2) {
michael@0 757 lengthResult=-1;
michael@0 758 limit1=start1+length1;
michael@0 759 } else if(length1==length2) {
michael@0 760 lengthResult=0;
michael@0 761 limit1=start1+length1;
michael@0 762 } else /* length1>length2 */ {
michael@0 763 lengthResult=1;
michael@0 764 limit1=start1+length2;
michael@0 765 }
michael@0 766
michael@0 767 if(s1==s2) {
michael@0 768 return lengthResult;
michael@0 769 }
michael@0 770
michael@0 771 for(;;) {
michael@0 772 /* check pseudo-limit */
michael@0 773 if(s1==limit1) {
michael@0 774 return lengthResult;
michael@0 775 }
michael@0 776
michael@0 777 c1=*s1;
michael@0 778 c2=*s2;
michael@0 779 if(c1!=c2) {
michael@0 780 break;
michael@0 781 }
michael@0 782 ++s1;
michael@0 783 ++s2;
michael@0 784 }
michael@0 785
michael@0 786 /* setup for fix-up */
michael@0 787 limit1=start1+length1;
michael@0 788 limit2=start2+length2;
michael@0 789 }
michael@0 790
michael@0 791 /* if both values are in or above the surrogate range, fix them up */
michael@0 792 if(c1>=0xd800 && c2>=0xd800 && codePointOrder) {
michael@0 793 /* subtract 0x2800 from BMP code points to make them smaller than supplementary ones */
michael@0 794 if(
michael@0 795 (c1<=0xdbff && (s1+1)!=limit1 && U16_IS_TRAIL(*(s1+1))) ||
michael@0 796 (U16_IS_TRAIL(c1) && start1!=s1 && U16_IS_LEAD(*(s1-1)))
michael@0 797 ) {
michael@0 798 /* part of a surrogate pair, leave >=d800 */
michael@0 799 } else {
michael@0 800 /* BMP code point - may be surrogate code point - make <d800 */
michael@0 801 c1-=0x2800;
michael@0 802 }
michael@0 803
michael@0 804 if(
michael@0 805 (c2<=0xdbff && (s2+1)!=limit2 && U16_IS_TRAIL(*(s2+1))) ||
michael@0 806 (U16_IS_TRAIL(c2) && start2!=s2 && U16_IS_LEAD(*(s2-1)))
michael@0 807 ) {
michael@0 808 /* part of a surrogate pair, leave >=d800 */
michael@0 809 } else {
michael@0 810 /* BMP code point - may be surrogate code point - make <d800 */
michael@0 811 c2-=0x2800;
michael@0 812 }
michael@0 813 }
michael@0 814
michael@0 815 /* now c1 and c2 are in the requested (code unit or code point) order */
michael@0 816 return (int32_t)c1-(int32_t)c2;
michael@0 817 }
michael@0 818
michael@0 819 /*
michael@0 820 * Compare two strings as presented by UCharIterators.
michael@0 821 * Use code unit or code point order.
michael@0 822 * When the function returns, it is undefined where the iterators
michael@0 823 * have stopped.
michael@0 824 */
michael@0 825 U_CAPI int32_t U_EXPORT2
michael@0 826 u_strCompareIter(UCharIterator *iter1, UCharIterator *iter2, UBool codePointOrder) {
michael@0 827 UChar32 c1, c2;
michael@0 828
michael@0 829 /* argument checking */
michael@0 830 if(iter1==NULL || iter2==NULL) {
michael@0 831 return 0; /* bad arguments */
michael@0 832 }
michael@0 833 if(iter1==iter2) {
michael@0 834 return 0; /* identical iterators */
michael@0 835 }
michael@0 836
michael@0 837 /* reset iterators to start? */
michael@0 838 iter1->move(iter1, 0, UITER_START);
michael@0 839 iter2->move(iter2, 0, UITER_START);
michael@0 840
michael@0 841 /* compare identical prefixes - they do not need to be fixed up */
michael@0 842 for(;;) {
michael@0 843 c1=iter1->next(iter1);
michael@0 844 c2=iter2->next(iter2);
michael@0 845 if(c1!=c2) {
michael@0 846 break;
michael@0 847 }
michael@0 848 if(c1==-1) {
michael@0 849 return 0;
michael@0 850 }
michael@0 851 }
michael@0 852
michael@0 853 /* if both values are in or above the surrogate range, fix them up */
michael@0 854 if(c1>=0xd800 && c2>=0xd800 && codePointOrder) {
michael@0 855 /* subtract 0x2800 from BMP code points to make them smaller than supplementary ones */
michael@0 856 if(
michael@0 857 (c1<=0xdbff && U16_IS_TRAIL(iter1->current(iter1))) ||
michael@0 858 (U16_IS_TRAIL(c1) && (iter1->previous(iter1), U16_IS_LEAD(iter1->previous(iter1))))
michael@0 859 ) {
michael@0 860 /* part of a surrogate pair, leave >=d800 */
michael@0 861 } else {
michael@0 862 /* BMP code point - may be surrogate code point - make <d800 */
michael@0 863 c1-=0x2800;
michael@0 864 }
michael@0 865
michael@0 866 if(
michael@0 867 (c2<=0xdbff && U16_IS_TRAIL(iter2->current(iter2))) ||
michael@0 868 (U16_IS_TRAIL(c2) && (iter2->previous(iter2), U16_IS_LEAD(iter2->previous(iter2))))
michael@0 869 ) {
michael@0 870 /* part of a surrogate pair, leave >=d800 */
michael@0 871 } else {
michael@0 872 /* BMP code point - may be surrogate code point - make <d800 */
michael@0 873 c2-=0x2800;
michael@0 874 }
michael@0 875 }
michael@0 876
michael@0 877 /* now c1 and c2 are in the requested (code unit or code point) order */
michael@0 878 return (int32_t)c1-(int32_t)c2;
michael@0 879 }
michael@0 880
michael@0 881 #if 0
michael@0 882 /*
michael@0 883 * u_strCompareIter() does not leave the iterators _on_ the different units.
michael@0 884 * This is possible but would cost a few extra indirect function calls to back
michael@0 885 * up if the last unit (c1 or c2 respectively) was >=0.
michael@0 886 *
michael@0 887 * Consistently leaving them _behind_ the different units is not an option
michael@0 888 * because the current "unit" is the end of the string if that is reached,
michael@0 889 * and in such a case the iterator does not move.
michael@0 890 * For example, when comparing "ab" with "abc", both iterators rest _on_ the end
michael@0 891 * of their strings. Calling previous() on each does not move them to where
michael@0 892 * the comparison fails.
michael@0 893 *
michael@0 894 * So the simplest semantics is to not define where the iterators end up.
michael@0 895 *
michael@0 896 * The following fragment is part of what would need to be done for backing up.
michael@0 897 */
michael@0 898 void fragment {
michael@0 899 /* iff a surrogate is part of a surrogate pair, leave >=d800 */
michael@0 900 if(c1<=0xdbff) {
michael@0 901 if(!U16_IS_TRAIL(iter1->current(iter1))) {
michael@0 902 /* lead surrogate code point - make <d800 */
michael@0 903 c1-=0x2800;
michael@0 904 }
michael@0 905 } else if(c1<=0xdfff) {
michael@0 906 int32_t idx=iter1->getIndex(iter1, UITER_CURRENT);
michael@0 907 iter1->previous(iter1); /* ==c1 */
michael@0 908 if(!U16_IS_LEAD(iter1->previous(iter1))) {
michael@0 909 /* trail surrogate code point - make <d800 */
michael@0 910 c1-=0x2800;
michael@0 911 }
michael@0 912 /* go back to behind where the difference is */
michael@0 913 iter1->move(iter1, idx, UITER_ZERO);
michael@0 914 } else /* 0xe000<=c1<=0xffff */ {
michael@0 915 /* BMP code point - make <d800 */
michael@0 916 c1-=0x2800;
michael@0 917 }
michael@0 918 }
michael@0 919 #endif
michael@0 920
michael@0 921 U_CAPI int32_t U_EXPORT2
michael@0 922 u_strCompare(const UChar *s1, int32_t length1,
michael@0 923 const UChar *s2, int32_t length2,
michael@0 924 UBool codePointOrder) {
michael@0 925 /* argument checking */
michael@0 926 if(s1==NULL || length1<-1 || s2==NULL || length2<-1) {
michael@0 927 return 0;
michael@0 928 }
michael@0 929 return uprv_strCompare(s1, length1, s2, length2, FALSE, codePointOrder);
michael@0 930 }
michael@0 931
michael@0 932 /* String compare in code point order - u_strcmp() compares in code unit order. */
michael@0 933 U_CAPI int32_t U_EXPORT2
michael@0 934 u_strcmpCodePointOrder(const UChar *s1, const UChar *s2) {
michael@0 935 return uprv_strCompare(s1, -1, s2, -1, FALSE, TRUE);
michael@0 936 }
michael@0 937
michael@0 938 U_CAPI int32_t U_EXPORT2
michael@0 939 u_strncmp(const UChar *s1,
michael@0 940 const UChar *s2,
michael@0 941 int32_t n)
michael@0 942 {
michael@0 943 if(n > 0) {
michael@0 944 int32_t rc;
michael@0 945 for(;;) {
michael@0 946 rc = (int32_t)*s1 - (int32_t)*s2;
michael@0 947 if(rc != 0 || *s1 == 0 || --n == 0) {
michael@0 948 return rc;
michael@0 949 }
michael@0 950 ++s1;
michael@0 951 ++s2;
michael@0 952 }
michael@0 953 } else {
michael@0 954 return 0;
michael@0 955 }
michael@0 956 }
michael@0 957
michael@0 958 U_CAPI int32_t U_EXPORT2
michael@0 959 u_strncmpCodePointOrder(const UChar *s1, const UChar *s2, int32_t n) {
michael@0 960 return uprv_strCompare(s1, n, s2, n, TRUE, TRUE);
michael@0 961 }
michael@0 962
michael@0 963 U_CAPI UChar* U_EXPORT2
michael@0 964 u_strcpy(UChar *dst,
michael@0 965 const UChar *src)
michael@0 966 {
michael@0 967 UChar *anchor = dst; /* save a pointer to start of dst */
michael@0 968
michael@0 969 while((*(dst++) = *(src++)) != 0) { /* copy string 2 over */
michael@0 970 }
michael@0 971
michael@0 972 return anchor;
michael@0 973 }
michael@0 974
michael@0 975 U_CAPI UChar* U_EXPORT2
michael@0 976 u_strncpy(UChar *dst,
michael@0 977 const UChar *src,
michael@0 978 int32_t n)
michael@0 979 {
michael@0 980 UChar *anchor = dst; /* save a pointer to start of dst */
michael@0 981
michael@0 982 /* copy string 2 over */
michael@0 983 while(n > 0 && (*(dst++) = *(src++)) != 0) {
michael@0 984 --n;
michael@0 985 }
michael@0 986
michael@0 987 return anchor;
michael@0 988 }
michael@0 989
michael@0 990 U_CAPI int32_t U_EXPORT2
michael@0 991 u_strlen(const UChar *s)
michael@0 992 {
michael@0 993 #if U_SIZEOF_WCHAR_T == U_SIZEOF_UCHAR
michael@0 994 return (int32_t)uprv_wcslen(s);
michael@0 995 #else
michael@0 996 const UChar *t = s;
michael@0 997 while(*t != 0) {
michael@0 998 ++t;
michael@0 999 }
michael@0 1000 return t - s;
michael@0 1001 #endif
michael@0 1002 }
michael@0 1003
michael@0 1004 U_CAPI int32_t U_EXPORT2
michael@0 1005 u_countChar32(const UChar *s, int32_t length) {
michael@0 1006 int32_t count;
michael@0 1007
michael@0 1008 if(s==NULL || length<-1) {
michael@0 1009 return 0;
michael@0 1010 }
michael@0 1011
michael@0 1012 count=0;
michael@0 1013 if(length>=0) {
michael@0 1014 while(length>0) {
michael@0 1015 ++count;
michael@0 1016 if(U16_IS_LEAD(*s) && length>=2 && U16_IS_TRAIL(*(s+1))) {
michael@0 1017 s+=2;
michael@0 1018 length-=2;
michael@0 1019 } else {
michael@0 1020 ++s;
michael@0 1021 --length;
michael@0 1022 }
michael@0 1023 }
michael@0 1024 } else /* length==-1 */ {
michael@0 1025 UChar c;
michael@0 1026
michael@0 1027 for(;;) {
michael@0 1028 if((c=*s++)==0) {
michael@0 1029 break;
michael@0 1030 }
michael@0 1031 ++count;
michael@0 1032
michael@0 1033 /*
michael@0 1034 * sufficient to look ahead one because of UTF-16;
michael@0 1035 * safe to look ahead one because at worst that would be the terminating NUL
michael@0 1036 */
michael@0 1037 if(U16_IS_LEAD(c) && U16_IS_TRAIL(*s)) {
michael@0 1038 ++s;
michael@0 1039 }
michael@0 1040 }
michael@0 1041 }
michael@0 1042 return count;
michael@0 1043 }
michael@0 1044
michael@0 1045 U_CAPI UBool U_EXPORT2
michael@0 1046 u_strHasMoreChar32Than(const UChar *s, int32_t length, int32_t number) {
michael@0 1047
michael@0 1048 if(number<0) {
michael@0 1049 return TRUE;
michael@0 1050 }
michael@0 1051 if(s==NULL || length<-1) {
michael@0 1052 return FALSE;
michael@0 1053 }
michael@0 1054
michael@0 1055 if(length==-1) {
michael@0 1056 /* s is NUL-terminated */
michael@0 1057 UChar c;
michael@0 1058
michael@0 1059 /* count code points until they exceed */
michael@0 1060 for(;;) {
michael@0 1061 if((c=*s++)==0) {
michael@0 1062 return FALSE;
michael@0 1063 }
michael@0 1064 if(number==0) {
michael@0 1065 return TRUE;
michael@0 1066 }
michael@0 1067 if(U16_IS_LEAD(c) && U16_IS_TRAIL(*s)) {
michael@0 1068 ++s;
michael@0 1069 }
michael@0 1070 --number;
michael@0 1071 }
michael@0 1072 } else {
michael@0 1073 /* length>=0 known */
michael@0 1074 const UChar *limit;
michael@0 1075 int32_t maxSupplementary;
michael@0 1076
michael@0 1077 /* s contains at least (length+1)/2 code points: <=2 UChars per cp */
michael@0 1078 if(((length+1)/2)>number) {
michael@0 1079 return TRUE;
michael@0 1080 }
michael@0 1081
michael@0 1082 /* check if s does not even contain enough UChars */
michael@0 1083 maxSupplementary=length-number;
michael@0 1084 if(maxSupplementary<=0) {
michael@0 1085 return FALSE;
michael@0 1086 }
michael@0 1087 /* there are maxSupplementary=length-number more UChars than asked-for code points */
michael@0 1088
michael@0 1089 /*
michael@0 1090 * count code points until they exceed and also check that there are
michael@0 1091 * no more than maxSupplementary supplementary code points (UChar pairs)
michael@0 1092 */
michael@0 1093 limit=s+length;
michael@0 1094 for(;;) {
michael@0 1095 if(s==limit) {
michael@0 1096 return FALSE;
michael@0 1097 }
michael@0 1098 if(number==0) {
michael@0 1099 return TRUE;
michael@0 1100 }
michael@0 1101 if(U16_IS_LEAD(*s++) && s!=limit && U16_IS_TRAIL(*s)) {
michael@0 1102 ++s;
michael@0 1103 if(--maxSupplementary<=0) {
michael@0 1104 /* too many pairs - too few code points */
michael@0 1105 return FALSE;
michael@0 1106 }
michael@0 1107 }
michael@0 1108 --number;
michael@0 1109 }
michael@0 1110 }
michael@0 1111 }
michael@0 1112
michael@0 1113 U_CAPI UChar * U_EXPORT2
michael@0 1114 u_memcpy(UChar *dest, const UChar *src, int32_t count) {
michael@0 1115 if(count > 0) {
michael@0 1116 uprv_memcpy(dest, src, count*U_SIZEOF_UCHAR);
michael@0 1117 }
michael@0 1118 return dest;
michael@0 1119 }
michael@0 1120
michael@0 1121 U_CAPI UChar * U_EXPORT2
michael@0 1122 u_memmove(UChar *dest, const UChar *src, int32_t count) {
michael@0 1123 if(count > 0) {
michael@0 1124 uprv_memmove(dest, src, count*U_SIZEOF_UCHAR);
michael@0 1125 }
michael@0 1126 return dest;
michael@0 1127 }
michael@0 1128
michael@0 1129 U_CAPI UChar * U_EXPORT2
michael@0 1130 u_memset(UChar *dest, UChar c, int32_t count) {
michael@0 1131 if(count > 0) {
michael@0 1132 UChar *ptr = dest;
michael@0 1133 UChar *limit = dest + count;
michael@0 1134
michael@0 1135 while (ptr < limit) {
michael@0 1136 *(ptr++) = c;
michael@0 1137 }
michael@0 1138 }
michael@0 1139 return dest;
michael@0 1140 }
michael@0 1141
michael@0 1142 U_CAPI int32_t U_EXPORT2
michael@0 1143 u_memcmp(const UChar *buf1, const UChar *buf2, int32_t count) {
michael@0 1144 if(count > 0) {
michael@0 1145 const UChar *limit = buf1 + count;
michael@0 1146 int32_t result;
michael@0 1147
michael@0 1148 while (buf1 < limit) {
michael@0 1149 result = (int32_t)(uint16_t)*buf1 - (int32_t)(uint16_t)*buf2;
michael@0 1150 if (result != 0) {
michael@0 1151 return result;
michael@0 1152 }
michael@0 1153 buf1++;
michael@0 1154 buf2++;
michael@0 1155 }
michael@0 1156 }
michael@0 1157 return 0;
michael@0 1158 }
michael@0 1159
michael@0 1160 U_CAPI int32_t U_EXPORT2
michael@0 1161 u_memcmpCodePointOrder(const UChar *s1, const UChar *s2, int32_t count) {
michael@0 1162 return uprv_strCompare(s1, count, s2, count, FALSE, TRUE);
michael@0 1163 }
michael@0 1164
michael@0 1165 /* u_unescape & support fns ------------------------------------------------- */
michael@0 1166
michael@0 1167 /* This map must be in ASCENDING ORDER OF THE ESCAPE CODE */
michael@0 1168 static const UChar UNESCAPE_MAP[] = {
michael@0 1169 /*" 0x22, 0x22 */
michael@0 1170 /*' 0x27, 0x27 */
michael@0 1171 /*? 0x3F, 0x3F */
michael@0 1172 /*\ 0x5C, 0x5C */
michael@0 1173 /*a*/ 0x61, 0x07,
michael@0 1174 /*b*/ 0x62, 0x08,
michael@0 1175 /*e*/ 0x65, 0x1b,
michael@0 1176 /*f*/ 0x66, 0x0c,
michael@0 1177 /*n*/ 0x6E, 0x0a,
michael@0 1178 /*r*/ 0x72, 0x0d,
michael@0 1179 /*t*/ 0x74, 0x09,
michael@0 1180 /*v*/ 0x76, 0x0b
michael@0 1181 };
michael@0 1182 enum { UNESCAPE_MAP_LENGTH = sizeof(UNESCAPE_MAP) / sizeof(UNESCAPE_MAP[0]) };
michael@0 1183
michael@0 1184 /* Convert one octal digit to a numeric value 0..7, or -1 on failure */
michael@0 1185 static int8_t _digit8(UChar c) {
michael@0 1186 if (c >= 0x0030 && c <= 0x0037) {
michael@0 1187 return (int8_t)(c - 0x0030);
michael@0 1188 }
michael@0 1189 return -1;
michael@0 1190 }
michael@0 1191
michael@0 1192 /* Convert one hex digit to a numeric value 0..F, or -1 on failure */
michael@0 1193 static int8_t _digit16(UChar c) {
michael@0 1194 if (c >= 0x0030 && c <= 0x0039) {
michael@0 1195 return (int8_t)(c - 0x0030);
michael@0 1196 }
michael@0 1197 if (c >= 0x0041 && c <= 0x0046) {
michael@0 1198 return (int8_t)(c - (0x0041 - 10));
michael@0 1199 }
michael@0 1200 if (c >= 0x0061 && c <= 0x0066) {
michael@0 1201 return (int8_t)(c - (0x0061 - 10));
michael@0 1202 }
michael@0 1203 return -1;
michael@0 1204 }
michael@0 1205
michael@0 1206 /* Parse a single escape sequence. Although this method deals in
michael@0 1207 * UChars, it does not use C++ or UnicodeString. This allows it to
michael@0 1208 * be used from C contexts. */
michael@0 1209 U_CAPI UChar32 U_EXPORT2
michael@0 1210 u_unescapeAt(UNESCAPE_CHAR_AT charAt,
michael@0 1211 int32_t *offset,
michael@0 1212 int32_t length,
michael@0 1213 void *context) {
michael@0 1214
michael@0 1215 int32_t start = *offset;
michael@0 1216 UChar c;
michael@0 1217 UChar32 result = 0;
michael@0 1218 int8_t n = 0;
michael@0 1219 int8_t minDig = 0;
michael@0 1220 int8_t maxDig = 0;
michael@0 1221 int8_t bitsPerDigit = 4;
michael@0 1222 int8_t dig;
michael@0 1223 int32_t i;
michael@0 1224 UBool braces = FALSE;
michael@0 1225
michael@0 1226 /* Check that offset is in range */
michael@0 1227 if (*offset < 0 || *offset >= length) {
michael@0 1228 goto err;
michael@0 1229 }
michael@0 1230
michael@0 1231 /* Fetch first UChar after '\\' */
michael@0 1232 c = charAt((*offset)++, context);
michael@0 1233
michael@0 1234 /* Convert hexadecimal and octal escapes */
michael@0 1235 switch (c) {
michael@0 1236 case 0x0075 /*'u'*/:
michael@0 1237 minDig = maxDig = 4;
michael@0 1238 break;
michael@0 1239 case 0x0055 /*'U'*/:
michael@0 1240 minDig = maxDig = 8;
michael@0 1241 break;
michael@0 1242 case 0x0078 /*'x'*/:
michael@0 1243 minDig = 1;
michael@0 1244 if (*offset < length && charAt(*offset, context) == 0x7B /*{*/) {
michael@0 1245 ++(*offset);
michael@0 1246 braces = TRUE;
michael@0 1247 maxDig = 8;
michael@0 1248 } else {
michael@0 1249 maxDig = 2;
michael@0 1250 }
michael@0 1251 break;
michael@0 1252 default:
michael@0 1253 dig = _digit8(c);
michael@0 1254 if (dig >= 0) {
michael@0 1255 minDig = 1;
michael@0 1256 maxDig = 3;
michael@0 1257 n = 1; /* Already have first octal digit */
michael@0 1258 bitsPerDigit = 3;
michael@0 1259 result = dig;
michael@0 1260 }
michael@0 1261 break;
michael@0 1262 }
michael@0 1263 if (minDig != 0) {
michael@0 1264 while (*offset < length && n < maxDig) {
michael@0 1265 c = charAt(*offset, context);
michael@0 1266 dig = (int8_t)((bitsPerDigit == 3) ? _digit8(c) : _digit16(c));
michael@0 1267 if (dig < 0) {
michael@0 1268 break;
michael@0 1269 }
michael@0 1270 result = (result << bitsPerDigit) | dig;
michael@0 1271 ++(*offset);
michael@0 1272 ++n;
michael@0 1273 }
michael@0 1274 if (n < minDig) {
michael@0 1275 goto err;
michael@0 1276 }
michael@0 1277 if (braces) {
michael@0 1278 if (c != 0x7D /*}*/) {
michael@0 1279 goto err;
michael@0 1280 }
michael@0 1281 ++(*offset);
michael@0 1282 }
michael@0 1283 if (result < 0 || result >= 0x110000) {
michael@0 1284 goto err;
michael@0 1285 }
michael@0 1286 /* If an escape sequence specifies a lead surrogate, see if
michael@0 1287 * there is a trail surrogate after it, either as an escape or
michael@0 1288 * as a literal. If so, join them up into a supplementary.
michael@0 1289 */
michael@0 1290 if (*offset < length && U16_IS_LEAD(result)) {
michael@0 1291 int32_t ahead = *offset + 1;
michael@0 1292 c = charAt(*offset, context);
michael@0 1293 if (c == 0x5C /*'\\'*/ && ahead < length) {
michael@0 1294 c = (UChar) u_unescapeAt(charAt, &ahead, length, context);
michael@0 1295 }
michael@0 1296 if (U16_IS_TRAIL(c)) {
michael@0 1297 *offset = ahead;
michael@0 1298 result = U16_GET_SUPPLEMENTARY(result, c);
michael@0 1299 }
michael@0 1300 }
michael@0 1301 return result;
michael@0 1302 }
michael@0 1303
michael@0 1304 /* Convert C-style escapes in table */
michael@0 1305 for (i=0; i<UNESCAPE_MAP_LENGTH; i+=2) {
michael@0 1306 if (c == UNESCAPE_MAP[i]) {
michael@0 1307 return UNESCAPE_MAP[i+1];
michael@0 1308 } else if (c < UNESCAPE_MAP[i]) {
michael@0 1309 break;
michael@0 1310 }
michael@0 1311 }
michael@0 1312
michael@0 1313 /* Map \cX to control-X: X & 0x1F */
michael@0 1314 if (c == 0x0063 /*'c'*/ && *offset < length) {
michael@0 1315 c = charAt((*offset)++, context);
michael@0 1316 if (U16_IS_LEAD(c) && *offset < length) {
michael@0 1317 UChar c2 = charAt(*offset, context);
michael@0 1318 if (U16_IS_TRAIL(c2)) {
michael@0 1319 ++(*offset);
michael@0 1320 c = (UChar) U16_GET_SUPPLEMENTARY(c, c2); /* [sic] */
michael@0 1321 }
michael@0 1322 }
michael@0 1323 return 0x1F & c;
michael@0 1324 }
michael@0 1325
michael@0 1326 /* If no special forms are recognized, then consider
michael@0 1327 * the backslash to generically escape the next character.
michael@0 1328 * Deal with surrogate pairs. */
michael@0 1329 if (U16_IS_LEAD(c) && *offset < length) {
michael@0 1330 UChar c2 = charAt(*offset, context);
michael@0 1331 if (U16_IS_TRAIL(c2)) {
michael@0 1332 ++(*offset);
michael@0 1333 return U16_GET_SUPPLEMENTARY(c, c2);
michael@0 1334 }
michael@0 1335 }
michael@0 1336 return c;
michael@0 1337
michael@0 1338 err:
michael@0 1339 /* Invalid escape sequence */
michael@0 1340 *offset = start; /* Reset to initial value */
michael@0 1341 return (UChar32)0xFFFFFFFF;
michael@0 1342 }
michael@0 1343
michael@0 1344 /* u_unescapeAt() callback to return a UChar from a char* */
michael@0 1345 static UChar U_CALLCONV
michael@0 1346 _charPtr_charAt(int32_t offset, void *context) {
michael@0 1347 UChar c16;
michael@0 1348 /* It would be more efficient to access the invariant tables
michael@0 1349 * directly but there is no API for that. */
michael@0 1350 u_charsToUChars(((char*) context) + offset, &c16, 1);
michael@0 1351 return c16;
michael@0 1352 }
michael@0 1353
michael@0 1354 /* Append an escape-free segment of the text; used by u_unescape() */
michael@0 1355 static void _appendUChars(UChar *dest, int32_t destCapacity,
michael@0 1356 const char *src, int32_t srcLen) {
michael@0 1357 if (destCapacity < 0) {
michael@0 1358 destCapacity = 0;
michael@0 1359 }
michael@0 1360 if (srcLen > destCapacity) {
michael@0 1361 srcLen = destCapacity;
michael@0 1362 }
michael@0 1363 u_charsToUChars(src, dest, srcLen);
michael@0 1364 }
michael@0 1365
michael@0 1366 /* Do an invariant conversion of char* -> UChar*, with escape parsing */
michael@0 1367 U_CAPI int32_t U_EXPORT2
michael@0 1368 u_unescape(const char *src, UChar *dest, int32_t destCapacity) {
michael@0 1369 const char *segment = src;
michael@0 1370 int32_t i = 0;
michael@0 1371 char c;
michael@0 1372
michael@0 1373 while ((c=*src) != 0) {
michael@0 1374 /* '\\' intentionally written as compiler-specific
michael@0 1375 * character constant to correspond to compiler-specific
michael@0 1376 * char* constants. */
michael@0 1377 if (c == '\\') {
michael@0 1378 int32_t lenParsed = 0;
michael@0 1379 UChar32 c32;
michael@0 1380 if (src != segment) {
michael@0 1381 if (dest != NULL) {
michael@0 1382 _appendUChars(dest + i, destCapacity - i,
michael@0 1383 segment, (int32_t)(src - segment));
michael@0 1384 }
michael@0 1385 i += (int32_t)(src - segment);
michael@0 1386 }
michael@0 1387 ++src; /* advance past '\\' */
michael@0 1388 c32 = (UChar32)u_unescapeAt(_charPtr_charAt, &lenParsed, (int32_t)uprv_strlen(src), (void*)src);
michael@0 1389 if (lenParsed == 0) {
michael@0 1390 goto err;
michael@0 1391 }
michael@0 1392 src += lenParsed; /* advance past escape seq. */
michael@0 1393 if (dest != NULL && U16_LENGTH(c32) <= (destCapacity - i)) {
michael@0 1394 U16_APPEND_UNSAFE(dest, i, c32);
michael@0 1395 } else {
michael@0 1396 i += U16_LENGTH(c32);
michael@0 1397 }
michael@0 1398 segment = src;
michael@0 1399 } else {
michael@0 1400 ++src;
michael@0 1401 }
michael@0 1402 }
michael@0 1403 if (src != segment) {
michael@0 1404 if (dest != NULL) {
michael@0 1405 _appendUChars(dest + i, destCapacity - i,
michael@0 1406 segment, (int32_t)(src - segment));
michael@0 1407 }
michael@0 1408 i += (int32_t)(src - segment);
michael@0 1409 }
michael@0 1410 if (dest != NULL && i < destCapacity) {
michael@0 1411 dest[i] = 0;
michael@0 1412 }
michael@0 1413 return i;
michael@0 1414
michael@0 1415 err:
michael@0 1416 if (dest != NULL && destCapacity > 0) {
michael@0 1417 *dest = 0;
michael@0 1418 }
michael@0 1419 return 0;
michael@0 1420 }
michael@0 1421
michael@0 1422 /* NUL-termination of strings ----------------------------------------------- */
michael@0 1423
michael@0 1424 /**
michael@0 1425 * NUL-terminate a string no matter what its type.
michael@0 1426 * Set warning and error codes accordingly.
michael@0 1427 */
michael@0 1428 #define __TERMINATE_STRING(dest, destCapacity, length, pErrorCode) \
michael@0 1429 if(pErrorCode!=NULL && U_SUCCESS(*pErrorCode)) { \
michael@0 1430 /* not a public function, so no complete argument checking */ \
michael@0 1431 \
michael@0 1432 if(length<0) { \
michael@0 1433 /* assume that the caller handles this */ \
michael@0 1434 } else if(length<destCapacity) { \
michael@0 1435 /* NUL-terminate the string, the NUL fits */ \
michael@0 1436 dest[length]=0; \
michael@0 1437 /* unset the not-terminated warning but leave all others */ \
michael@0 1438 if(*pErrorCode==U_STRING_NOT_TERMINATED_WARNING) { \
michael@0 1439 *pErrorCode=U_ZERO_ERROR; \
michael@0 1440 } \
michael@0 1441 } else if(length==destCapacity) { \
michael@0 1442 /* unable to NUL-terminate, but the string itself fit - set a warning code */ \
michael@0 1443 *pErrorCode=U_STRING_NOT_TERMINATED_WARNING; \
michael@0 1444 } else /* length>destCapacity */ { \
michael@0 1445 /* even the string itself did not fit - set an error code */ \
michael@0 1446 *pErrorCode=U_BUFFER_OVERFLOW_ERROR; \
michael@0 1447 } \
michael@0 1448 }
michael@0 1449
michael@0 1450 U_CAPI int32_t U_EXPORT2
michael@0 1451 u_terminateUChars(UChar *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
michael@0 1452 __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
michael@0 1453 return length;
michael@0 1454 }
michael@0 1455
michael@0 1456 U_CAPI int32_t U_EXPORT2
michael@0 1457 u_terminateChars(char *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
michael@0 1458 __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
michael@0 1459 return length;
michael@0 1460 }
michael@0 1461
michael@0 1462 U_CAPI int32_t U_EXPORT2
michael@0 1463 u_terminateUChar32s(UChar32 *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
michael@0 1464 __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
michael@0 1465 return length;
michael@0 1466 }
michael@0 1467
michael@0 1468 U_CAPI int32_t U_EXPORT2
michael@0 1469 u_terminateWChars(wchar_t *dest, int32_t destCapacity, int32_t length, UErrorCode *pErrorCode) {
michael@0 1470 __TERMINATE_STRING(dest, destCapacity, length, pErrorCode);
michael@0 1471 return length;
michael@0 1472 }
michael@0 1473
michael@0 1474 // Compute the hash code for a string -------------------------------------- ***
michael@0 1475
michael@0 1476 // Moved here from uhash.c so that UnicodeString::hashCode() does not depend
michael@0 1477 // on UHashtable code.
michael@0 1478
michael@0 1479 /*
michael@0 1480 Compute the hash by iterating sparsely over about 32 (up to 63)
michael@0 1481 characters spaced evenly through the string. For each character,
michael@0 1482 multiply the previous hash value by a prime number and add the new
michael@0 1483 character in, like a linear congruential random number generator,
michael@0 1484 producing a pseudorandom deterministic value well distributed over
michael@0 1485 the output range. [LIU]
michael@0 1486 */
michael@0 1487
michael@0 1488 #define STRING_HASH(TYPE, STR, STRLEN, DEREF) \
michael@0 1489 int32_t hash = 0; \
michael@0 1490 const TYPE *p = (const TYPE*) STR; \
michael@0 1491 if (p != NULL) { \
michael@0 1492 int32_t len = (int32_t)(STRLEN); \
michael@0 1493 int32_t inc = ((len - 32) / 32) + 1; \
michael@0 1494 const TYPE *limit = p + len; \
michael@0 1495 while (p<limit) { \
michael@0 1496 hash = (hash * 37) + DEREF; \
michael@0 1497 p += inc; \
michael@0 1498 } \
michael@0 1499 } \
michael@0 1500 return hash
michael@0 1501
michael@0 1502 /* Used by UnicodeString to compute its hashcode - Not public API. */
michael@0 1503 U_CAPI int32_t U_EXPORT2
michael@0 1504 ustr_hashUCharsN(const UChar *str, int32_t length) {
michael@0 1505 STRING_HASH(UChar, str, length, *p);
michael@0 1506 }
michael@0 1507
michael@0 1508 U_CAPI int32_t U_EXPORT2
michael@0 1509 ustr_hashCharsN(const char *str, int32_t length) {
michael@0 1510 STRING_HASH(uint8_t, str, length, *p);
michael@0 1511 }
michael@0 1512
michael@0 1513 U_CAPI int32_t U_EXPORT2
michael@0 1514 ustr_hashICharsN(const char *str, int32_t length) {
michael@0 1515 STRING_HASH(char, str, length, (uint8_t)uprv_tolower(*p));
michael@0 1516 }

mercurial