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