2 * Unicode string manipulation functions
4 * Copyright 2000 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/unicode.h"
26 extern const WCHAR wine_casemap_lower
[];
27 extern const WCHAR wine_casemap_upper
[];
28 extern const unsigned short wine_wctype_table
[];
30 int wine_is_dbcs_leadbyte( const union cptable
*table
, unsigned char ch
)
32 return (table
->info
.char_size
== 2) && (table
->dbcs
.cp2uni_leadbytes
[ch
]);
35 WCHAR
tolowerW( WCHAR ch
)
37 return ch
+ wine_casemap_lower
[wine_casemap_lower
[ch
>> 8] + (ch
& 0xff)];
40 WCHAR
toupperW( WCHAR ch
)
42 return ch
+ wine_casemap_upper
[wine_casemap_upper
[ch
>> 8] + (ch
& 0xff)];
45 /* the character type contains the C1_* flags in the low 12 bits */
46 /* and the C2_* type in the high 4 bits */
47 unsigned short get_char_typeW( WCHAR ch
)
49 return wine_wctype_table
[wine_wctype_table
[ch
>> 8] + (ch
& 0xff)];
52 int iscntrlW( WCHAR wc
)
54 return get_char_typeW(wc
) & C1_CNTRL
;
57 int ispunctW( WCHAR wc
)
59 return get_char_typeW(wc
) & C1_PUNCT
;
62 int isspaceW( WCHAR wc
)
64 return get_char_typeW(wc
) & C1_SPACE
;
67 int isdigitW( WCHAR wc
)
69 return get_char_typeW(wc
) & C1_DIGIT
;
72 int isxdigitW( WCHAR wc
)
74 return get_char_typeW(wc
) & C1_XDIGIT
;
77 int islowerW( WCHAR wc
)
79 return get_char_typeW(wc
) & C1_LOWER
;
82 int isupperW( WCHAR wc
)
84 return get_char_typeW(wc
) & C1_UPPER
;
87 int isalnumW( WCHAR wc
)
89 return get_char_typeW(wc
) & (C1_ALPHA
|C1_DIGIT
|C1_LOWER
|C1_UPPER
);
92 int isalphaW( WCHAR wc
)
94 return get_char_typeW(wc
) & (C1_ALPHA
|C1_LOWER
|C1_UPPER
);
97 int isgraphW( WCHAR wc
)
99 return get_char_typeW(wc
) & (C1_ALPHA
|C1_PUNCT
|C1_DIGIT
|C1_LOWER
|C1_UPPER
);
102 int isprintW( WCHAR wc
)
104 return get_char_typeW(wc
) & (C1_ALPHA
|C1_BLANK
|C1_PUNCT
|C1_DIGIT
|C1_LOWER
|C1_UPPER
);
107 unsigned int strlenW( const WCHAR
*str
)
109 const WCHAR
*s
= str
;
114 WCHAR
*strcpyW( WCHAR
*dst
, const WCHAR
*src
)
117 while ((*p
++ = *src
++));
121 int strcmpW( const WCHAR
*str1
, const WCHAR
*str2
)
123 while (*str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
124 return *str1
- *str2
;
127 int strncmpW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
129 if (n
<= 0) return 0;
130 while ((--n
> 0) && *str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
131 return *str1
- *str2
;
134 WCHAR
*strcatW( WCHAR
*dst
, const WCHAR
*src
)
136 strcpyW( dst
+ strlenW(dst
), src
);
140 WCHAR
*strchrW( const WCHAR
*str
, WCHAR ch
)
142 do { if (*str
== ch
) return (WCHAR
*)str
; } while (*str
++);
146 WCHAR
*strrchrW( const WCHAR
*str
, WCHAR ch
)
149 do { if (*str
== ch
) ret
= (WCHAR
*)str
; } while (*str
++);
153 WCHAR
*strpbrkW( const WCHAR
*str
, const WCHAR
*accept
)
155 for ( ; *str
; str
++) if (strchrW( accept
, *str
)) return (WCHAR
*)str
;
159 size_t strspnW( const WCHAR
*str
, const WCHAR
*accept
)
162 for (ptr
= str
; *ptr
; ptr
++) if (!strchrW( accept
, *ptr
)) break;
166 size_t strcspnW( const WCHAR
*str
, const WCHAR
*reject
)
169 for (ptr
= str
; *ptr
; ptr
++) if (strchrW( reject
, *ptr
)) break;
173 WCHAR
*strlwrW( WCHAR
*str
)
176 while ((*str
= tolowerW(*str
))) str
++;
180 WCHAR
*struprW( WCHAR
*str
)
183 while ((*str
= toupperW(*str
))) str
++;
187 WCHAR
*memchrW( const WCHAR
*ptr
, WCHAR ch
, size_t n
)
190 for (end
= ptr
+ n
; ptr
< end
; ptr
++) if (*ptr
== ch
) return (WCHAR
*)ptr
;
194 WCHAR
*memrchrW( const WCHAR
*ptr
, WCHAR ch
, size_t n
)
196 const WCHAR
*end
, *ret
= NULL
;
197 for (end
= ptr
+ n
; ptr
< end
; ptr
++) if (*ptr
== ch
) ret
= ptr
;
201 long int atolW( const WCHAR
*str
)
203 return strtolW( str
, (WCHAR
**)0, 10 );
206 int atoiW( const WCHAR
*str
)
208 return (int)atolW( str
);
211 int strcmpiW( const WCHAR
*str1
, const WCHAR
*str2
)
215 int ret
= tolowerW(*str1
) - tolowerW(*str2
);
216 if (ret
|| !*str1
) return ret
;
222 int strncmpiW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
225 for ( ; n
> 0; n
--, str1
++, str2
++)
226 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
)) || !*str1
) break;
230 int memicmpW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
233 for ( ; n
> 0; n
--, str1
++, str2
++)
234 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
))) break;
238 WCHAR
*strstrW( const WCHAR
*str
, const WCHAR
*sub
)
242 const WCHAR
*p1
= str
, *p2
= sub
;
243 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
244 if (!*p2
) return (WCHAR
*)str
;
250 /* strtolW and strtoulW implementation based on the GNU C library code */
251 /* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc. */
253 long int strtolW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
256 register unsigned long int cutoff
;
257 register unsigned int cutlim
;
258 register unsigned long int i
;
259 register const WCHAR
*s
;
261 const WCHAR
*save
, *end
;
264 if (base
< 0 || base
== 1 || base
> 36) return 0;
268 /* Skip white space. */
269 while (isspaceW (*s
))
271 if (!*s
) goto noconv
;
273 /* Check for a sign. */
283 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
286 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
297 /* Save the pointer so we can check later if anything happened. */
301 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
302 cutlim
= ULONG_MAX
% (unsigned long int) base
;
307 for (;c
!= '\0'; c
= *++s
)
311 if (c
>= '0' && c
<= '9')
313 else if (isalphaW (c
))
314 c
= toupperW (c
) - 'A' + 10;
319 /* Check for overflow. */
320 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
324 i
*= (unsigned long int) base
;
329 /* Check if anything actually happened. */
333 /* Store in ENDPTR the address of one character
334 past the last character we converted. */
336 *endptr
= (WCHAR
*)s
;
338 /* Check for a value that is within the range of
339 `unsigned LONG int', but outside the range of `LONG int'. */
342 ? -((unsigned long int) (LONG_MIN
+ 1)) + 1
343 : (unsigned long int) LONG_MAX
))
348 return negative
? LONG_MIN
: LONG_MAX
;
351 /* Return the result of the appropriate sign. */
352 return negative
? -i
: i
;
355 /* We must handle a special case here: the base is 0 or 16 and the
356 first two characters are '0' and 'x', but the rest are not
357 hexadecimal digits. This is no error case. We return 0 and
358 ENDPTR points to the `x`. */
361 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
363 *endptr
= (WCHAR
*)&save
[-1];
365 /* There was no number to convert. */
366 *endptr
= (WCHAR
*)nptr
;
373 unsigned long int strtoulW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
376 register unsigned long int cutoff
;
377 register unsigned int cutlim
;
378 register unsigned long int i
;
379 register const WCHAR
*s
;
381 const WCHAR
*save
, *end
;
384 if (base
< 0 || base
== 1 || base
> 36) return 0;
388 /* Skip white space. */
389 while (isspaceW (*s
))
391 if (!*s
) goto noconv
;
393 /* Check for a sign. */
403 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
406 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
417 /* Save the pointer so we can check later if anything happened. */
421 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
422 cutlim
= ULONG_MAX
% (unsigned long int) base
;
427 for (;c
!= '\0'; c
= *++s
)
431 if (c
>= '0' && c
<= '9')
433 else if (isalphaW (c
))
434 c
= toupperW (c
) - 'A' + 10;
439 /* Check for overflow. */
440 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
444 i
*= (unsigned long int) base
;
449 /* Check if anything actually happened. */
453 /* Store in ENDPTR the address of one character
454 past the last character we converted. */
456 *endptr
= (WCHAR
*)s
;
463 /* Return the result of the appropriate sign. */
464 return negative
? -i
: i
;
467 /* We must handle a special case here: the base is 0 or 16 and the
468 first two characters are '0' and 'x', but the rest are not
469 hexadecimal digits. This is no error case. We return 0 and
470 ENDPTR points to the `x`. */
473 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
475 *endptr
= (WCHAR
*)&save
[-1];
477 /* There was no number to convert. */
478 *endptr
= (WCHAR
*)nptr
;
485 int vsnprintfW(WCHAR
*str
, size_t len
, const WCHAR
*format
, va_list valist
)
487 unsigned int written
= 0;
488 const WCHAR
*iter
= format
;
489 char bufa
[256], fmtbufa
[64], *fmta
;
493 while (*iter
&& *iter
!= '%')
495 if (written
++ >= len
)
503 if (written
++ >= len
)
505 *str
++ = '%'; /* "%%"->'%' */
512 while (*iter
== '0' ||
521 char *buffiter
= bufa
;
522 int fieldlen
= va_arg(valist
, int);
523 sprintf(buffiter
, "%d", fieldlen
);
525 *fmta
++ = *buffiter
++;
532 while (isdigit(*iter
))
540 char *buffiter
= bufa
;
541 int fieldlen
= va_arg(valist
, int);
542 sprintf(buffiter
, "%d", fieldlen
);
544 *fmta
++ = *buffiter
++;
547 while (isdigit(*iter
))
550 if (*iter
== 'h' || *iter
== 'l')
557 static const WCHAR none
[] = { '(','n','u','l','l',')',0 };
558 const WCHAR
*wstr
= va_arg(valist
, const WCHAR
*);
559 const WCHAR
*striter
= wstr
? wstr
: none
;
562 if (written
++ >= len
)
571 if (written
++ >= len
)
573 *str
++ = (WCHAR
)va_arg(valist
, int);
579 /* For non wc types, use system sprintf and append to wide char output */
580 /* FIXME: for unrecognised types, should ignore % when printing */
581 char *bufaiter
= bufa
;
583 sprintf(bufaiter
, "%08lX", va_arg(valist
, long));
588 if (*iter
== 'a' || *iter
== 'A' ||
589 *iter
== 'e' || *iter
== 'E' ||
590 *iter
== 'f' || *iter
== 'F' ||
591 *iter
== 'g' || *iter
== 'G')
592 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, double));
595 /* FIXME: On 32 bit systems this doesn't handle int 64's.
596 * on 64 bit systems this doesn't work for 32 bit types
598 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, void *));
603 if (written
++ >= len
)
605 *str
++ = *bufaiter
++;
619 int vsprintfW( WCHAR
*str
, const WCHAR
*format
, va_list valist
)
621 return vsnprintfW( str
, INT_MAX
, format
, valist
);
624 int snprintfW( WCHAR
*str
, size_t len
, const WCHAR
*format
, ...)
628 va_start(valist
, format
);
629 retval
= vsnprintfW(str
, len
, format
, valist
);
634 int sprintfW( WCHAR
*str
, const WCHAR
*format
, ...)
638 va_start(valist
, format
);
639 retval
= vsnprintfW(str
, INT_MAX
, format
, valist
);