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"
29 int strcmpiW( const WCHAR
*str1
, const WCHAR
*str2
)
33 int ret
= tolowerW(*str1
) - tolowerW(*str2
);
34 if (ret
|| !*str1
) return ret
;
40 int strncmpiW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
43 for ( ; n
> 0; n
--, str1
++, str2
++)
44 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
)) || !*str1
) break;
48 int memicmpW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
51 for ( ; n
> 0; n
--, str1
++, str2
++)
52 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
))) break;
56 WCHAR
*strstrW( const WCHAR
*str
, const WCHAR
*sub
)
60 const WCHAR
*p1
= str
, *p2
= sub
;
61 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
62 if (!*p2
) return (WCHAR
*)str
;
68 /* strtolW and strtoulW implementation based on the GNU C library code */
69 /* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc. */
71 long int strtolW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
74 register unsigned long int cutoff
;
75 register unsigned int cutlim
;
76 register unsigned long int i
;
77 register const WCHAR
*s
;
79 const WCHAR
*save
, *end
;
82 if (base
< 0 || base
== 1 || base
> 36) return 0;
86 /* Skip white space. */
91 /* Check for a sign. */
101 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
104 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
115 /* Save the pointer so we can check later if anything happened. */
119 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
120 cutlim
= ULONG_MAX
% (unsigned long int) base
;
125 for (;c
!= '\0'; c
= *++s
)
129 if (c
>= '0' && c
<= '9')
131 else if (isalphaW (c
))
132 c
= toupperW (c
) - 'A' + 10;
137 /* Check for overflow. */
138 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
142 i
*= (unsigned long int) base
;
147 /* Check if anything actually happened. */
151 /* Store in ENDPTR the address of one character
152 past the last character we converted. */
154 *endptr
= (WCHAR
*)s
;
156 /* Check for a value that is within the range of
157 `unsigned LONG int', but outside the range of `LONG int'. */
160 ? -((unsigned long int) (LONG_MIN
+ 1)) + 1
161 : (unsigned long int) LONG_MAX
))
167 return negative
? LONG_MIN
: LONG_MAX
;
170 /* Return the result of the appropriate sign. */
171 return negative
? -i
: i
;
174 /* We must handle a special case here: the base is 0 or 16 and the
175 first two characters are '0' and 'x', but the rest are not
176 hexadecimal digits. This is no error case. We return 0 and
177 ENDPTR points to the `x`. */
180 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
182 *endptr
= (WCHAR
*)&save
[-1];
184 /* There was no number to convert. */
185 *endptr
= (WCHAR
*)nptr
;
192 unsigned long int strtoulW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
195 register unsigned long int cutoff
;
196 register unsigned int cutlim
;
197 register unsigned long int i
;
198 register const WCHAR
*s
;
200 const WCHAR
*save
, *end
;
203 if (base
< 0 || base
== 1 || base
> 36) return 0;
207 /* Skip white space. */
208 while (isspaceW (*s
))
210 if (!*s
) goto noconv
;
212 /* Check for a sign. */
222 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
225 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
236 /* Save the pointer so we can check later if anything happened. */
240 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
241 cutlim
= ULONG_MAX
% (unsigned long int) base
;
246 for (;c
!= '\0'; c
= *++s
)
250 if (c
>= '0' && c
<= '9')
252 else if (isalphaW (c
))
253 c
= toupperW (c
) - 'A' + 10;
258 /* Check for overflow. */
259 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
263 i
*= (unsigned long int) base
;
268 /* Check if anything actually happened. */
272 /* Store in ENDPTR the address of one character
273 past the last character we converted. */
275 *endptr
= (WCHAR
*)s
;
283 /* Return the result of the appropriate sign. */
284 return negative
? -i
: i
;
287 /* We must handle a special case here: the base is 0 or 16 and the
288 first two characters are '0' and 'x', but the rest are not
289 hexadecimal digits. This is no error case. We return 0 and
290 ENDPTR points to the `x`. */
293 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
295 *endptr
= (WCHAR
*)&save
[-1];
297 /* There was no number to convert. */
298 *endptr
= (WCHAR
*)nptr
;
305 /* format a WCHAR string according to a printf format; helper for vsnprintfW */
306 static size_t format_string( WCHAR
*buffer
, size_t len
, const char *format
, const WCHAR
*str
, int str_len
)
309 int i
, left_align
= 0, width
= 0, max
= 0;
311 assert( *format
== '%' );
312 format
++; /* skip '%' */
314 while (*format
== '0' || *format
== '+' || *format
== '-' || *format
== ' ' || *format
== '#')
316 if (*format
== '-') left_align
= 1;
320 while (isdigit(*format
)) width
= width
* 10 + *format
++ - '0';
322 if (str_len
== -1) str_len
= strlenW( str
);
326 while (isdigit(*format
)) max
= max
* 10 + *format
++ - '0';
327 if (max
> str_len
) max
= str_len
;
331 if (*format
== 'h' || *format
== 'l') format
++;
333 assert( *format
== 's' );
335 if (!left_align
&& width
> max
)
337 for (i
= 0; i
< width
- max
; i
++)
345 memcpy( buffer
, str
, min( max
, len
- count
) * sizeof(WCHAR
) );
349 if (left_align
&& width
> max
)
351 for (i
= 0; i
< width
- max
; i
++)
360 int vsnprintfW(WCHAR
*str
, size_t len
, const WCHAR
*format
, va_list valist
)
362 unsigned int written
= 0;
363 const WCHAR
*iter
= format
;
364 char bufa
[512], fmtbufa
[64], *fmta
;
368 while (*iter
&& *iter
!= '%')
379 *str
++ = '%'; /* "%%"->'%' */
386 while (*iter
== '0' ||
395 char *buffiter
= bufa
;
396 int fieldlen
= va_arg(valist
, int);
397 sprintf(buffiter
, "%d", fieldlen
);
399 *fmta
++ = *buffiter
++;
406 while (isdigit(*iter
))
414 char *buffiter
= bufa
;
415 int fieldlen
= va_arg(valist
, int);
416 sprintf(buffiter
, "%d", fieldlen
);
418 *fmta
++ = *buffiter
++;
422 while (isdigit(*iter
))
425 if (*iter
== 'h' || *iter
== 'l')
432 static const WCHAR none
[] = { '(','n','u','l','l',')',0 };
433 const WCHAR
*wstr
= va_arg(valist
, const WCHAR
*);
434 size_t remaining
= written
< len
? len
- written
: 0;
439 count
= format_string( str
, remaining
, fmtbufa
, wstr
? wstr
: none
, -1 );
440 str
+= min( count
, remaining
);
449 size_t remaining
= written
< len
? len
- written
: 0;
452 wstr
= va_arg(valist
, int);
455 count
= format_string( str
, remaining
, fmtbufa
, &wstr
, 1 );
456 str
+= min( count
, remaining
);
464 /* For non wc types, use system sprintf and append to wide char output */
465 /* FIXME: for unrecognised types, should ignore % when printing */
466 char *bufaiter
= bufa
;
468 sprintf(bufaiter
, "%0*lX", 2 * (int)sizeof(void*),
469 (unsigned long)va_arg(valist
, void *));
474 if (*iter
== 'a' || *iter
== 'A' ||
475 *iter
== 'e' || *iter
== 'E' ||
476 *iter
== 'f' || *iter
== 'F' ||
477 *iter
== 'g' || *iter
== 'G')
478 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, double));
481 /* FIXME: On 32 bit systems this doesn't handle int 64's. */
482 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, void *));
504 /* FIXME: POSIX [v]snprintf() returns the equivalent of written, not -1, on short buffer. */
505 return written
< len
? (int)written
: -1;
508 int vsprintfW( WCHAR
*str
, const WCHAR
*format
, va_list valist
)
510 return vsnprintfW( str
, INT_MAX
, format
, valist
);
513 int snprintfW( WCHAR
*str
, size_t len
, const WCHAR
*format
, ...)
517 va_start(valist
, format
);
518 retval
= vsnprintfW(str
, len
, format
, valist
);
523 int sprintfW( WCHAR
*str
, const WCHAR
*format
, ...)
527 va_start(valist
, format
);
528 retval
= vsnprintfW(str
, INT_MAX
, format
, valist
);