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
26 #define WINE_UNICODE_INLINE /* nothing */
27 #include "wine/unicode.h"
30 #define min(a,b) (((a) < (b)) ? (a) : (b))
33 int strcmpiW( const WCHAR
*str1
, const WCHAR
*str2
)
37 int ret
= tolowerW(*str1
) - tolowerW(*str2
);
38 if (ret
|| !*str1
) return ret
;
44 int strncmpiW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
47 for ( ; n
> 0; n
--, str1
++, str2
++)
48 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
)) || !*str1
) break;
52 int memicmpW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
55 for ( ; n
> 0; n
--, str1
++, str2
++)
56 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
))) break;
60 WCHAR
*strstrW( const WCHAR
*str
, const WCHAR
*sub
)
64 const WCHAR
*p1
= str
, *p2
= sub
;
65 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
66 if (!*p2
) return (WCHAR
*)str
;
72 /* strtolW and strtoulW implementation based on the GNU C library code */
73 /* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc. */
75 long int strtolW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
78 register unsigned long int cutoff
;
79 register unsigned int cutlim
;
80 register unsigned long int i
;
81 register const WCHAR
*s
;
83 const WCHAR
*save
, *end
;
86 if (base
< 0 || base
== 1 || base
> 36) return 0;
90 /* Skip white space. */
95 /* Check for a sign. */
105 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
108 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
119 /* Save the pointer so we can check later if anything happened. */
123 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
124 cutlim
= ULONG_MAX
% (unsigned long int) base
;
129 for (;c
!= '\0'; c
= *++s
)
133 if (c
>= '0' && c
<= '9')
135 else if (isalphaW (c
))
136 c
= toupperW (c
) - 'A' + 10;
141 /* Check for overflow. */
142 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
146 i
*= (unsigned long int) base
;
151 /* Check if anything actually happened. */
155 /* Store in ENDPTR the address of one character
156 past the last character we converted. */
158 *endptr
= (WCHAR
*)s
;
160 /* Check for a value that is within the range of
161 `unsigned LONG int', but outside the range of `LONG int'. */
164 ? -((unsigned long int) (LONG_MIN
+ 1)) + 1
165 : (unsigned long int) LONG_MAX
))
171 return negative
? LONG_MIN
: LONG_MAX
;
174 /* Return the result of the appropriate sign. */
175 return negative
? -i
: i
;
178 /* We must handle a special case here: the base is 0 or 16 and the
179 first two characters are '0' and 'x', but the rest are not
180 hexadecimal digits. This is no error case. We return 0 and
181 ENDPTR points to the `x`. */
184 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
186 *endptr
= (WCHAR
*)&save
[-1];
188 /* There was no number to convert. */
189 *endptr
= (WCHAR
*)nptr
;
196 unsigned long int strtoulW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
199 register unsigned long int cutoff
;
200 register unsigned int cutlim
;
201 register unsigned long int i
;
202 register const WCHAR
*s
;
204 const WCHAR
*save
, *end
;
207 if (base
< 0 || base
== 1 || base
> 36) return 0;
211 /* Skip white space. */
212 while (isspaceW (*s
))
214 if (!*s
) goto noconv
;
216 /* Check for a sign. */
226 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
229 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
240 /* Save the pointer so we can check later if anything happened. */
244 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
245 cutlim
= ULONG_MAX
% (unsigned long int) base
;
250 for (;c
!= '\0'; c
= *++s
)
254 if (c
>= '0' && c
<= '9')
256 else if (isalphaW (c
))
257 c
= toupperW (c
) - 'A' + 10;
262 /* Check for overflow. */
263 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
267 i
*= (unsigned long int) base
;
272 /* Check if anything actually happened. */
276 /* Store in ENDPTR the address of one character
277 past the last character we converted. */
279 *endptr
= (WCHAR
*)s
;
287 /* Return the result of the appropriate sign. */
288 return negative
? -i
: i
;
291 /* We must handle a special case here: the base is 0 or 16 and the
292 first two characters are '0' and 'x', but the rest are not
293 hexadecimal digits. This is no error case. We return 0 and
294 ENDPTR points to the `x`. */
297 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
299 *endptr
= (WCHAR
*)&save
[-1];
301 /* There was no number to convert. */
302 *endptr
= (WCHAR
*)nptr
;
309 /* format a WCHAR string according to a printf format; helper for vsnprintfW */
310 static size_t format_string( WCHAR
*buffer
, size_t len
, const char *format
, const WCHAR
*str
, int str_len
)
313 int i
, left_align
= 0, width
= 0, max
= 0;
315 assert( *format
== '%' );
316 format
++; /* skip '%' */
318 while (*format
== '0' || *format
== '+' || *format
== '-' || *format
== ' ' || *format
== '#')
320 if (*format
== '-') left_align
= 1;
324 while (isdigit(*format
)) width
= width
* 10 + *format
++ - '0';
326 if (str_len
== -1) str_len
= strlenW( str
);
330 while (isdigit(*format
)) max
= max
* 10 + *format
++ - '0';
331 if (max
> str_len
) max
= str_len
;
335 if (*format
== 'h' || *format
== 'l') format
++;
337 assert( *format
== 's' );
339 if (!left_align
&& width
> max
)
341 for (i
= 0; i
< width
- max
; i
++)
349 memcpy( buffer
, str
, min( max
, len
- count
) * sizeof(WCHAR
) );
353 if (left_align
&& width
> max
)
355 for (i
= 0; i
< width
- max
; i
++)
364 int vsnprintfW(WCHAR
*str
, size_t len
, const WCHAR
*format
, va_list valist
)
366 unsigned int written
= 0;
367 const WCHAR
*iter
= format
;
368 char bufa
[512], fmtbufa
[64], *fmta
;
372 while (*iter
&& *iter
!= '%')
383 *str
++ = '%'; /* "%%"->'%' */
390 while (*iter
== '0' ||
399 char *buffiter
= bufa
;
400 int fieldlen
= va_arg(valist
, int);
401 sprintf(buffiter
, "%d", fieldlen
);
403 *fmta
++ = *buffiter
++;
410 while (isdigit(*iter
))
418 char *buffiter
= bufa
;
419 int fieldlen
= va_arg(valist
, int);
420 sprintf(buffiter
, "%d", fieldlen
);
422 *fmta
++ = *buffiter
++;
426 while (isdigit(*iter
))
429 if (*iter
== 'h' || *iter
== 'l')
436 static const WCHAR none
[] = { '(','n','u','l','l',')',0 };
437 const WCHAR
*wstr
= va_arg(valist
, const WCHAR
*);
438 size_t remaining
= written
< len
? len
- written
: 0;
443 count
= format_string( str
, remaining
, fmtbufa
, wstr
? wstr
: none
, -1 );
444 str
+= min( count
, remaining
);
453 size_t remaining
= written
< len
? len
- written
: 0;
456 wstr
= va_arg(valist
, int);
459 count
= format_string( str
, remaining
, fmtbufa
, &wstr
, 1 );
460 str
+= min( count
, remaining
);
468 /* For non wc types, use system sprintf and append to wide char output */
469 /* FIXME: for unrecognised types, should ignore % when printing */
470 char *bufaiter
= bufa
;
472 sprintf(bufaiter
, "%0*lX", 2 * (int)sizeof(void*),
473 (unsigned long)va_arg(valist
, void *));
478 if (*iter
== 'a' || *iter
== 'A' ||
479 *iter
== 'e' || *iter
== 'E' ||
480 *iter
== 'f' || *iter
== 'F' ||
481 *iter
== 'g' || *iter
== 'G')
482 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, double));
485 /* FIXME: On 32 bit systems this doesn't handle int 64's. */
486 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, void *));
508 /* FIXME: POSIX [v]snprintf() returns the equivalent of written, not -1, on short buffer. */
509 return written
< len
? (int)written
: -1;
512 int vsprintfW( WCHAR
*str
, const WCHAR
*format
, va_list valist
)
514 return vsnprintfW( str
, INT_MAX
, format
, valist
);
517 int snprintfW( WCHAR
*str
, size_t len
, const WCHAR
*format
, ...)
521 va_start(valist
, format
);
522 retval
= vsnprintfW(str
, len
, format
, valist
);
527 int sprintfW( WCHAR
*str
, const WCHAR
*format
, ...)
531 va_start(valist
, format
);
532 retval
= vsnprintfW(str
, INT_MAX
, format
, valist
);