1 /* Copyright (C) 2000-2012 by George Williams */
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 long uc_strcmp(const unichar_t
*str1
,const char *str2
) {
34 ch1
= *str1
++; ch2
= *(unsigned char *) str2
++ ;
35 if ( ch1
!=ch2
|| ch1
=='\0' )
40 long uc_strncmp(const unichar_t
*str1
,const char *str2
,int n
) {
43 ch1
= *str1
++; ch2
= *(unsigned char *) str2
++ ;
44 if ( ch1
!=ch2
|| ch1
=='\0' )
50 long uc_strmatch(const unichar_t
*str1
, const char *str2
) {
53 ch1
= *str1
++; ch2
= *(unsigned char *) str2
++ ;
56 if ( ch1
!=ch2
|| ch1
=='\0' )
61 long uc_strnmatch(const unichar_t
*str1
, const char *str2
, int len
) {
64 ch1
= *str1
++; ch2
= *(unsigned char *) str2
++ ;
67 if ( ch1
!=ch2
|| ch1
=='\0' || len
<=0 )
73 long u_strnmatch(const unichar_t
*str1
, const unichar_t
*str2
, int len
) {
76 ch1
= *str1
++; ch2
= *str2
++ ;
79 if ( ch1
!=ch2
|| ch1
=='\0' || len
<=0 )
85 long u_strcmp(const unichar_t
*str1
,const unichar_t
*str2
) {
88 ch1
= *str1
++; ch2
= *str2
++ ;
89 if ( ch1
!=ch2
|| ch1
=='\0' )
94 long u_strncmp(const unichar_t
*str1
,const unichar_t
*str2
,int n
) {
97 ch1
= *str1
++; ch2
= *str2
++ ;
98 if ( ch1
!=ch2
|| ch1
=='\0' )
104 long u_strmatch(const unichar_t
*str1
, const unichar_t
*str2
) {
107 ch1
= *str1
++; ch2
= *str2
++ ;
110 if ( ch1
!=ch2
|| ch1
=='\0' )
115 void cu_strcpy(char *to
, const unichar_t
*from
) {
116 register unichar_t ch
;
117 while ( (ch
= *from
++) != '\0' )
122 void uc_strcpy(unichar_t
*to
, const char *from
) {
123 register unichar_t ch
;
124 while ( (ch
= *(unsigned char *) from
++) != '\0' )
129 void u_strcpy(unichar_t
*to
, const unichar_t
*from
) {
130 register unichar_t ch
;
131 while ( (ch
= *from
++) != '\0' )
136 void u_strncpy(register unichar_t
*to
, const unichar_t
*from
, int len
) {
137 register unichar_t ch
;
138 while ( (ch
= *from
++) != '\0' && --len
>=0 )
143 void cu_strncpy(register char *to
, const unichar_t
*from
, int len
) {
144 register unichar_t ch
;
145 while ( (ch
= *from
++) != '\0' && --len
>=0 )
150 void uc_strncpy(register unichar_t
*to
, const char *from
, int len
) {
151 register unichar_t ch
;
152 while ( (ch
= *(unsigned char *) from
++) != '\0' && --len
>=0 )
157 void uc_strcat(unichar_t
*to
, const char *from
) {
158 uc_strcpy(to
+u_strlen(to
),from
);
161 void uc_strncat(unichar_t
*to
, const char *from
,int len
) {
162 uc_strncpy(to
+u_strlen(to
),from
,len
);
165 void cu_strcat(char *to
, const unichar_t
*from
) {
166 cu_strcpy(to
+strlen(to
),from
);
169 void cu_strncat(char *to
, const unichar_t
*from
, int len
) {
170 cu_strncpy(to
+strlen(to
),from
,len
);
173 void u_strcat(unichar_t
*to
, const unichar_t
*from
) {
174 u_strcpy(to
+u_strlen(to
),from
);
177 void u_strncat(unichar_t
*to
, const unichar_t
*from
, int len
) {
178 u_strncpy(to
+u_strlen(to
),from
,len
);
181 int u_strlen(register const unichar_t
*str
) {
182 register int len
= 0;
184 while ( *str
++!='\0' )
189 unichar_t
*u_strchr(const unichar_t
*str
,unichar_t ch
) {
190 register unichar_t test
;
192 while ( (test
=*(str
++))!='\0' )
194 return( (unichar_t
*) str
-1 );
199 unichar_t
*u_strrchr(const unichar_t
*str
,unichar_t ch
) {
200 register unichar_t test
, *last
= NULL
;
202 while ( (test
=*(str
++))!='\0' )
204 last
= (unichar_t
*) str
-1;
209 unichar_t
*uc_strstr(const unichar_t
*longer
, const char *substr
) {
211 const unichar_t
*lpt
, *str1
; const char *str2
;
213 for ( lpt
=longer
; *lpt
!='\0'; ++lpt
) {
214 str1
= lpt
; str2
= substr
;
216 ch1
= *str1
++; ch2
= *(unsigned char *) str2
++ ;
218 return((unichar_t
*) lpt
);
226 unichar_t
*u_strstr(const unichar_t
*longer
, const unichar_t
*substr
) {
228 const unichar_t
*lpt
, *str1
, *str2
;
230 for ( lpt
=longer
; *lpt
!='\0'; ++lpt
) {
231 str1
= lpt
; str2
= substr
;
233 ch1
= *str1
++; ch2
= *str2
++ ;
235 return((unichar_t
*) lpt
);
243 unichar_t
*uc_strstrmatch(const unichar_t
*longer
, const char *substr
) {
245 const unichar_t
*lpt
, *str1
; const unsigned char *str2
;
247 for ( lpt
=longer
; *lpt
!='\0'; ++lpt
) {
248 str1
= lpt
; str2
= (unsigned char *) substr
;
250 ch1
= *str1
++; ch2
= *str2
++ ;
254 return((unichar_t
*) lpt
);
262 unichar_t
*u_strstrmatch(const unichar_t
*longer
, const unichar_t
*substr
) {
264 const unichar_t
*lpt
, *str1
, *str2
;
266 for ( lpt
=longer
; *lpt
!='\0'; ++lpt
) {
267 str1
= lpt
; str2
= substr
;
269 ch1
= *str1
++; ch2
= *str2
++ ;
273 return((unichar_t
*) lpt
);
281 unichar_t
*u_copyn(const unichar_t
*pt
, long n
) {
284 if ( n
*sizeof(unichar_t
)>=MEMORY_MASK
)
285 n
= MEMORY_MASK
/sizeof(unichar_t
)-1;
287 res
= (unichar_t
*) xmalloc((n
+1)*sizeof(unichar_t
));
288 memcpy(res
,pt
,n
*sizeof(unichar_t
));
293 unichar_t
*u_copynallocm(const unichar_t
*pt
, long n
, long m
) {
296 if ( n
*sizeof(unichar_t
)>=MEMORY_MASK
)
297 n
= MEMORY_MASK
/sizeof(unichar_t
)-1;
299 res
= xmalloc((m
+1)*sizeof(unichar_t
));
300 memcpy(res
,pt
,n
*sizeof(unichar_t
));
305 unichar_t
*u_copy(const unichar_t
*pt
) {
307 return u_copyn(pt
,u_strlen(pt
));
309 return((unichar_t
*)0);
312 unichar_t
*u_concat(const unichar_t
*s1
, const unichar_t
*s2
) {
317 return( u_copy( s2
));
319 return( u_copy( s1
));
320 len1
= u_strlen(s1
); len2
= u_strlen(s2
);
321 pt
= (unichar_t
*) xmalloc((len1
+len2
+1)*sizeof(unichar_t
));
323 u_strcpy(pt
+len1
,s2
);
327 unichar_t
*uc_copyn(const char *pt
,int len
) {
328 unichar_t
*res
, *rpt
;
331 return((unichar_t
*)0);
334 if ( (len
+1)*sizeof(unichar_t
)>=MEMORY_MASK
)
335 len
= MEMORY_MASK
/sizeof(unichar_t
)-1;
337 res
= (unichar_t
*) xmalloc((len
+1)*sizeof(unichar_t
));
338 for ( rpt
=res
; --len
>=0 ; *rpt
++ = *(unsigned char *) pt
++ );
343 unichar_t
*uc_copy(const char *pt
) {
344 unichar_t
*res
, *rpt
;
348 return((unichar_t
*)0);
352 if ( (n
+1)*sizeof(unichar_t
)>=MEMORY_MASK
)
353 n
= MEMORY_MASK
/sizeof(unichar_t
)-1;
355 res
= (unichar_t
*) xmalloc((n
+1)*sizeof(unichar_t
));
356 for ( rpt
=res
; --n
>=0 ; *rpt
++ = *(unsigned char *) pt
++ );
361 char *cu_copyn(const unichar_t
*pt
,int len
) {
368 if ( (len
+1)>=MEMORY_MASK
)
371 res
= (char *) xmalloc(len
+1);
372 for ( rpt
=res
; --len
>=0 ; *rpt
++ = *pt
++ );
377 char *cu_copy(const unichar_t
*pt
) {
386 if ( (n
+1)>=MEMORY_MASK
)
387 n
= MEMORY_MASK
/sizeof(unichar_t
)-1;
389 res
= (char *) xmalloc(n
+1);
390 for ( rpt
=res
; --n
>=0 ; *rpt
++ = *pt
++ );
395 double u_strtod(const unichar_t
*str
, unichar_t
**ptr
) {
396 char buf
[60], *pt
, *ret
;
397 const unichar_t
*upt
;
399 extern double strtod(); /* Please don't delete this, not all of us have good ansi headers */
401 for ( upt
=str
, pt
=buf
; *upt
<128 && *upt
!='\0' && pt
-buf
<sizeof(buf
)-1; )
404 val
= strtod(buf
,&ret
);
407 *ptr
= (unichar_t
*) upt
;
409 *ptr
= (unichar_t
*) (str
+ (ret
-buf
));
414 long u_strtol(const unichar_t
*str
, unichar_t
**ptr
, int base
) {
415 char buf
[60], *pt
, *ret
;
416 const unichar_t
*upt
;
418 extern long strtol(); /* Please don't delete this, not all of us have good ansi headers */
420 for ( upt
=str
, pt
=buf
; *upt
<128 && *upt
!='\0' && pt
<buf
+sizeof(buf
)-1; )
423 val
= strtol(buf
,&ret
,base
);
426 *ptr
= (unichar_t
*) upt
;
428 *ptr
= (unichar_t
*) (str
+ (ret
-buf
));
433 unsigned long u_strtoul(const unichar_t
*str
, unichar_t
**ptr
, int base
) {
434 char buf
[60], *pt
, *ret
;
435 const unichar_t
*upt
;
438 for ( upt
=str
, pt
=buf
; *upt
<128 && *upt
!='\0' && pt
<buf
+sizeof(buf
)-1; )
441 val
= strtoul(buf
,&ret
,base
);
444 *ptr
= (unichar_t
*) upt
;
446 *ptr
= (unichar_t
*) (str
+ (ret
-buf
));
451 unichar_t
*cu_strstartmatch(const char *key
,const unichar_t
*str
) {
454 if(tolower(*key
) != tolower(*str
))
460 return (unichar_t
*)str
;
463 unichar_t
*u_strstartmatch(const unichar_t
*initial
, const unichar_t
*full
) {
466 ch1
= *initial
++; ch2
= *full
++ ;
468 return( (unichar_t
*) full
);
471 if ( ch1
!=ch2
|| ch1
=='\0' )
476 char *u_to_c(const unichar_t
*ubuf
) {
477 static char buf
[400];
478 cu_strncpy(buf
,ubuf
,sizeof(buf
));
482 unichar_t
*c_to_u(const char *buf
) {
483 static unichar_t ubuf
[400];
484 uc_strncpy(ubuf
,buf
,sizeof(ubuf
));
488 unichar_t
*utf82u_strncpy(unichar_t
*ubuf
,const char *utf8buf
,int len
) {
489 unichar_t
*upt
=ubuf
, *uend
=ubuf
+len
-1;
490 const uint8
*pt
= (const uint8
*) utf8buf
, *end
= pt
+strlen(utf8buf
);
493 while ( pt
<end
&& *pt
!='\0' && upt
<uend
) {
496 else if ( *pt
<=0xdf ) {
497 *upt
= ((*pt
&0x1f)<<6) | (pt
[1]&0x3f);
499 } else if ( *pt
<=0xef ) {
500 *upt
= ((*pt
&0xf)<<12) | ((pt
[1]&0x3f)<<6) | (pt
[2]&0x3f);
503 w
= ( ((*pt
&0x7)<<2) | ((pt
[1]&0x30)>>4) )-1;
504 w
= (w
<<6) | ((pt
[1]&0xf)<<2) | ((pt
[2]&0x30)>>4);
505 w2
= ((pt
[2]&0xf)<<6) | (pt
[3]&0x3f);
506 *upt
= w
*0x400 + w2
+ 0x10000;
515 unichar_t
*utf82u_strcpy(unichar_t
*ubuf
,const char *utf8buf
) {
516 return( utf82u_strncpy(ubuf
,utf8buf
,strlen(utf8buf
)+1));
519 unichar_t
*utf82u_copyn(const char *utf8buf
,int len
) {
520 unichar_t
*ubuf
= (unichar_t
*) xmalloc((len
+1)*sizeof(unichar_t
));
521 return( utf82u_strncpy(ubuf
,utf8buf
,len
+1));
524 unichar_t
*utf82u_copy(const char *utf8buf
) {
531 len
= strlen(utf8buf
);
532 ubuf
= (unichar_t
*) xmalloc((len
+1)*sizeof(unichar_t
));
533 return( utf82u_strncpy(ubuf
,utf8buf
,len
+1));
536 void utf82u_strcat(unichar_t
*to
,const char *from
) {
537 utf82u_strcpy(to
+u_strlen(to
),from
);
540 char *u2utf8_strcpy(char *utf8buf
,const unichar_t
*ubuf
) {
546 else if ( *ubuf
<0x800 ) {
547 *pt
++ = 0xc0 | (*ubuf
>>6);
548 *pt
++ = 0x80 | (*ubuf
&0x3f);
549 } else if ( *ubuf
< 0x10000 ) {
550 *pt
++ = 0xe0 | (*ubuf
>>12);
551 *pt
++ = 0x80 | ((*ubuf
>>6)&0x3f);
552 *pt
++ = 0x80 | (*ubuf
&0x3f);
554 uint32 val
= *ubuf
-0x10000;
555 int u
= ((val
&0xf0000)>>16)+1, z
=(val
&0x0f000)>>12, y
=(val
&0x00fc0)>>6, x
=val
&0x0003f;
556 *pt
++ = 0xf0 | (u
>>2);
557 *pt
++ = 0x80 | ((u
&3)<<4) | z
;
567 char *utf8_strchr(const char *str
, int search
) {
569 const char *old
= str
;
571 while ( (ch
= utf8_ildb(&str
))!=0 ) {
573 return( (char *) old
);
579 char *latin1_2_utf8_strcpy(char *utf8buf
,const char *lbuf
) {
581 const unsigned char *lpt
= (const unsigned char *) lbuf
;
587 *pt
++ = 0xc0 | (*lpt
>>6);
588 *pt
++ = 0x80 | (*lpt
&0x3f);
596 char *latin1_2_utf8_copy(const char *lbuf
) {
604 utf8buf
= (char *) xmalloc(2*len
+1);
605 return( latin1_2_utf8_strcpy(utf8buf
,lbuf
));
608 char *utf8_2_latin1_copy(const char *utf8buf
) {
611 char *lbuf
, *pt
; const char *upt
;
616 len
= strlen(utf8buf
);
617 pt
= lbuf
= (char *) xmalloc(len
+1);
618 for ( upt
=utf8buf
; (ch
=utf8_ildb(&upt
))!='\0'; )
627 char *u2utf8_copy(const unichar_t
*ubuf
) {
634 len
= u_strlen(ubuf
);
635 utf8buf
= (char *) xmalloc((len
+1)*4);
636 return( u2utf8_strcpy(utf8buf
,ubuf
));
639 char *u2utf8_copyn(const unichar_t
*ubuf
,int len
) {
646 utf8buf
= pt
= (char *) xmalloc((len
+1)*4);
647 for ( i
=0; i
<len
&& *ubuf
!='\0'; ++i
)
648 pt
= utf8_idpb(pt
, *ubuf
++);
653 int32
utf8_ildb(const char **_text
) {
656 const uint8
*text
= (const uint8
*) *_text
;
657 /* Increment and load character */
659 if ( (ch
= *text
++)<0x80 ) {
661 } else if ( ch
<=0xbf ) {
663 } else if ( ch
<=0xdf ) {
664 if ( *text
>=0x80 && *text
<0xc0 )
665 val
= ((ch
&0x1f)<<6) | (*text
++&0x3f);
666 } else if ( ch
<=0xef ) {
667 if ( *text
>=0x80 && *text
<0xc0 && text
[1]>=0x80 && text
[1]<0xc0 ) {
668 val
= ((ch
&0xf)<<12) | ((text
[0]&0x3f)<<6) | (text
[1]&0x3f);
672 int w
= ( ((ch
&0x7)<<2) | ((text
[0]&0x30)>>4) )-1, w2
;
673 w
= (w
<<6) | ((text
[0]&0xf)<<2) | ((text
[1]&0x30)>>4);
674 w2
= ((text
[1]&0xf)<<6) | (text
[2]&0x3f);
675 val
= w
*0x400 + w2
+ 0x10000;
676 if ( *text
<0x80 || text
[1]<0x80 || text
[2]<0x80 ||
677 *text
>=0xc0 || text
[1]>=0xc0 || text
[2]>=0xc0 )
682 *_text
= (const char *) text
;
686 char *utf8_idpb(char *utf8_text
,uint32 ch
) {
687 /* Increment and deposit character */
693 else if ( ch
<=0x7ff ) {
694 *utf8_text
++ = 0xc0 | (ch
>>6);
695 *utf8_text
++ = 0x80 | (ch
&0x3f);
696 } else if ( ch
<=0xffff ) {
697 *utf8_text
++ = 0xe0 | (ch
>>12);
698 *utf8_text
++ = 0x80 | ((ch
>>6)&0x3f);
699 *utf8_text
++ = 0x80 | (ch
&0x3f);
701 uint32 val
= ch
-0x10000;
702 int u
= ((val
&0xf0000)>>16)+1, z
=(val
&0x0f000)>>12, y
=(val
&0x00fc0)>>6, x
=val
&0x0003f;
703 *utf8_text
++ = 0xf0 | (u
>>2);
704 *utf8_text
++ = 0x80 | ((u
&3)<<4) | z
;
705 *utf8_text
++ = 0x80 | y
;
706 *utf8_text
++ = 0x80 | x
;
712 char *utf8_ib(char *utf8_text
) {
715 /* Increment character */
716 if ( (ch
= *utf8_text
)=='\0' )
719 return( utf8_text
+1 );
721 return( utf8_text
+2 );
723 return( utf8_text
+3 );
725 return( utf8_text
+4 );
728 int utf8_valid(const char *str
) {
729 /* Is this a valid utf8 string? */
732 while ( (ch
=utf8_ildb(&str
))!='\0' )
739 void utf8_truncatevalid(char *str
) {
740 /* There are certain cases where we have a fixed amount of space to display */
741 /* something, and if it doesn't fit in that, then we truncate it. But... */
742 /* that can leave us with a half completed utf8 byte sequence. So truncate*/
743 /* again, right before the start of the bad sequence */
748 while ( (ch
=utf8_ildb((const char **) &str
))!='\0' ) {
757 char *utf8_db(char *utf8_text
) {
758 /* Decrement utf8 pointer */
759 unsigned char *pt
= (unsigned char *) utf8_text
;
763 /* This should never happen. The pointer was looking at an intermediate */
764 /* character. However, if it does happen then we are now properly */
765 /* positioned at the start of a new char */;
766 else if ( *pt
>=0x80 ) {
770 else if ( *pt
>=0x80 ) {
774 else if ( *pt
>=0x80 )
778 return( (char *) pt
);
781 int utf8_strlen(const char *utf8_str
) {
782 /* how many characters in the string NOT bytes */
785 while ( utf8_ildb(&utf8_str
)>0 )
790 int utf82u_strlen(const char *utf8_str
) {
791 /* how many shorts needed to represent it in UCS2 */
795 while ( (ch
= utf8_ildb(&utf8_str
))>0 )
803 void utf8_strncpy(register char *to
, const char *from
, int len
) {
804 /* copy n characters NOT bytes */
805 const char *old
= from
;
806 while ( len
&& *old
) {
810 strncpy(to
, from
, old
-from
);
814 #include <chardata.h>
815 char *StripToASCII(const char *utf8_str
) {
816 /* Remove any non-ascii characters: Special case, convert the copyright symbol to (c) */
817 char *newcr
, *pt
, *end
;
819 const unichar_t
*alt
;
821 len
= strlen(utf8_str
);
822 pt
= newcr
= (char *) xmalloc(len
+1);
824 while ( (ch
= utf8_ildb(&utf8_str
))!='\0' ) {
827 newcr
= (char *) xrealloc(newcr
,(off
+10)+1);
831 if ( (ch
>=' ' && ch
<'\177' ) || ch
=='\n' || ch
=='\t' )
833 else if ( ch
=='\r' && *utf8_str
!='\n' )
835 else if ( ch
==0xa9 /* Copyright sign */ ) {
837 if ( pt
+strlen(str
)>=end
) {
839 newcr
= (char *) xrealloc(newcr
,(off
+10+strlen(str
))+1);
845 } else if ( unicode_alternates
[ch
>>8]!=NULL
&&
846 (alt
= unicode_alternates
[ch
>>8][ch
&0xff])!=NULL
) {
847 while ( *alt
!='\0' ) {
850 newcr
= (char *) xrealloc(newcr
,(off
+10)+1);
854 if ( *alt
>=' ' && *alt
<'\177' )
856 else if ( *alt
==0x300 )
858 else if ( *alt
==0x301 )
860 else if ( *alt
==0x302 )
862 else if ( *alt
==0x303 )
864 else if ( *alt
==0x308 )
874 int AllAscii(const char *txt
) {
875 for ( ; *txt
!='\0'; ++txt
) {
876 if ( *txt
=='\t' || *txt
=='\n' || *txt
=='\r' )
878 else if ( *txt
<' ' || *txt
>='\177' )
884 int uAllAscii(const unichar_t
*txt
) {
885 for ( ; *txt
!='\0'; ++txt
) {
886 if ( *txt
=='\t' || *txt
=='\n' || *txt
=='\r' )
888 else if ( *txt
<' ' || *txt
>='\177' )
894 char* chomp( char* line
) {
897 if ( line
[strlen(line
)-1]=='\n' )
898 line
[strlen(line
)-1] = '\0';
899 if ( line
[strlen(line
)-1]=='\r' )
900 line
[strlen(line
)-1] = '\0';
904 char *copytolower(const char *input
)
906 char* ret
= xstrdup(input
);
915 int endswith(const char *haystack
,const char *needle
) {
916 int haylen
= strlen( haystack
);
917 int nedlen
= strlen( needle
);
919 if( haylen
< nedlen
)
921 p
= strstr( haystack
+ haylen
- nedlen
, needle
);
922 return p
== ( haystack
+ haylen
- nedlen
);
925 int endswithi(const char *haystackZ
,const char *needleZ
) {
926 char* haystack
= copytolower(haystackZ
);
927 char* needle
= copytolower(needleZ
);
928 int ret
= endswith( haystack
, needle
);
934 int endswithi_partialExtension( const char *haystackZ
,const char *needleZ
) {
935 int nedlen
= strlen(needleZ
);
943 haystack
= copytolower(haystackZ
);
944 needle
= copytolower(needleZ
);
947 ret
|= endswith( haystack
, needle
);
948 for( ; i
>=0 && !ret
; --i
) {
950 ret
|= endswith( haystack
, needle
);
957 int u_endswith(const unichar_t
*haystack
,const unichar_t
*needle
) {
958 int haylen
= u_strlen( haystack
);
959 int nedlen
= u_strlen( needle
);
961 if( haylen
< nedlen
)
963 p
= u_strstr( haystack
+ haylen
- nedlen
, needle
);
964 return p
== ( haystack
+ haylen
- nedlen
);