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
25 #define WINE_UNICODE_INLINE /* nothing */
26 #include "wine/unicode.h"
28 int strcmpiW( const WCHAR
*str1
, const WCHAR
*str2
)
32 int ret
= tolowerW(*str1
) - tolowerW(*str2
);
33 if (ret
|| !*str1
) return ret
;
39 int strncmpiW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
42 for ( ; n
> 0; n
--, str1
++, str2
++)
43 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
)) || !*str1
) break;
47 int memicmpW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
50 for ( ; n
> 0; n
--, str1
++, str2
++)
51 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
))) break;
55 WCHAR
*strstrW( const WCHAR
*str
, const WCHAR
*sub
)
59 const WCHAR
*p1
= str
, *p2
= sub
;
60 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
61 if (!*p2
) return (WCHAR
*)str
;
67 /* strtolW and strtoulW implementation based on the GNU C library code */
68 /* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc. */
70 long int strtolW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
73 register unsigned long int cutoff
;
74 register unsigned int cutlim
;
75 register unsigned long int i
;
76 register const WCHAR
*s
;
78 const WCHAR
*save
, *end
;
81 if (base
< 0 || base
== 1 || base
> 36) return 0;
85 /* Skip white space. */
90 /* Check for a sign. */
100 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
103 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
114 /* Save the pointer so we can check later if anything happened. */
118 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
119 cutlim
= ULONG_MAX
% (unsigned long int) base
;
124 for (;c
!= '\0'; c
= *++s
)
128 if (c
>= '0' && c
<= '9')
130 else if (isalphaW (c
))
131 c
= toupperW (c
) - 'A' + 10;
136 /* Check for overflow. */
137 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
141 i
*= (unsigned long int) base
;
146 /* Check if anything actually happened. */
150 /* Store in ENDPTR the address of one character
151 past the last character we converted. */
153 *endptr
= (WCHAR
*)s
;
155 /* Check for a value that is within the range of
156 `unsigned LONG int', but outside the range of `LONG int'. */
159 ? -((unsigned long int) (LONG_MIN
+ 1)) + 1
160 : (unsigned long int) LONG_MAX
))
165 return negative
? LONG_MIN
: LONG_MAX
;
168 /* Return the result of the appropriate sign. */
169 return negative
? -i
: i
;
172 /* We must handle a special case here: the base is 0 or 16 and the
173 first two characters are '0' and 'x', but the rest are not
174 hexadecimal digits. This is no error case. We return 0 and
175 ENDPTR points to the `x`. */
178 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
180 *endptr
= (WCHAR
*)&save
[-1];
182 /* There was no number to convert. */
183 *endptr
= (WCHAR
*)nptr
;
190 unsigned long int strtoulW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
193 register unsigned long int cutoff
;
194 register unsigned int cutlim
;
195 register unsigned long int i
;
196 register const WCHAR
*s
;
198 const WCHAR
*save
, *end
;
201 if (base
< 0 || base
== 1 || base
> 36) return 0;
205 /* Skip white space. */
206 while (isspaceW (*s
))
208 if (!*s
) goto noconv
;
210 /* Check for a sign. */
220 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
223 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
234 /* Save the pointer so we can check later if anything happened. */
238 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
239 cutlim
= ULONG_MAX
% (unsigned long int) base
;
244 for (;c
!= '\0'; c
= *++s
)
248 if (c
>= '0' && c
<= '9')
250 else if (isalphaW (c
))
251 c
= toupperW (c
) - 'A' + 10;
256 /* Check for overflow. */
257 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
261 i
*= (unsigned long int) base
;
266 /* Check if anything actually happened. */
270 /* Store in ENDPTR the address of one character
271 past the last character we converted. */
273 *endptr
= (WCHAR
*)s
;
280 /* Return the result of the appropriate sign. */
281 return negative
? -i
: i
;
284 /* We must handle a special case here: the base is 0 or 16 and the
285 first two characters are '0' and 'x', but the rest are not
286 hexadecimal digits. This is no error case. We return 0 and
287 ENDPTR points to the `x`. */
290 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
292 *endptr
= (WCHAR
*)&save
[-1];
294 /* There was no number to convert. */
295 *endptr
= (WCHAR
*)nptr
;
302 /* format a WCHAR string according to a printf format; helper for vsnprintfW */
303 static int format_string( WCHAR
*buffer
, size_t len
, const char *format
, const WCHAR
*str
, int str_len
)
306 int i
, left_align
= 0, width
= 0, max
= 0;
308 assert( *format
== '%' );
309 format
++; /* skip '%' */
311 while (*format
== '0' || *format
== '+' || *format
== '-' || *format
== ' ' || *format
== '#')
313 if (*format
== '-') left_align
= 1;
317 while (isdigit(*format
)) width
= width
* 10 + *format
++ - '0';
319 if (str_len
== -1) str_len
= strlenW( str
);
323 while (isdigit(*format
)) max
= max
* 10 + *format
++ - '0';
324 if (max
> str_len
) max
= str_len
;
328 if (*format
== 'h' || *format
== 'l') format
++;
330 assert( *format
== 's' );
332 if (!left_align
&& width
> max
)
334 if ((count
+= width
- max
) >= len
) return -1;
335 for (i
= 0; i
< width
- max
; i
++) *buffer
++ = ' ';
338 if ((count
+= max
) >= len
) return -1;
339 memcpy( buffer
, str
, max
* sizeof(WCHAR
) );
342 if (left_align
&& width
> max
)
344 if ((count
+= width
- max
) >= len
) return -1;
345 for (i
= 0; i
< width
- max
; i
++) *buffer
++ = ' ';
350 int vsnprintfW(WCHAR
*str
, size_t len
, const WCHAR
*format
, va_list valist
)
352 unsigned int written
= 0;
353 const WCHAR
*iter
= format
;
354 char bufa
[512], fmtbufa
[64], *fmta
;
358 while (*iter
&& *iter
!= '%')
360 if (written
++ >= len
)
368 if (written
++ >= len
)
370 *str
++ = '%'; /* "%%"->'%' */
377 while (*iter
== '0' ||
386 char *buffiter
= bufa
;
387 int fieldlen
= va_arg(valist
, int);
388 sprintf(buffiter
, "%d", fieldlen
);
390 *fmta
++ = *buffiter
++;
397 while (isdigit(*iter
))
405 char *buffiter
= bufa
;
406 int fieldlen
= va_arg(valist
, int);
407 sprintf(buffiter
, "%d", fieldlen
);
409 *fmta
++ = *buffiter
++;
413 while (isdigit(*iter
))
416 if (*iter
== 'h' || *iter
== 'l')
423 static const WCHAR none
[] = { '(','n','u','l','l',')',0 };
424 const WCHAR
*wstr
= va_arg(valist
, const WCHAR
*);
429 count
= format_string( str
, len
- written
, fmtbufa
, wstr
? wstr
: none
, -1 );
430 if (count
== -1) return -1;
442 wstr
= va_arg(valist
, int);
445 count
= format_string( str
, len
- written
, fmtbufa
, &wstr
, 1 );
446 if (count
== -1) return -1;
455 /* For non wc types, use system sprintf and append to wide char output */
456 /* FIXME: for unrecognised types, should ignore % when printing */
457 char *bufaiter
= bufa
;
459 sprintf(bufaiter
, "%0*lX", 2 * (int)sizeof(void*),
460 (unsigned long)va_arg(valist
, void *));
465 if (*iter
== 'a' || *iter
== 'A' ||
466 *iter
== 'e' || *iter
== 'E' ||
467 *iter
== 'f' || *iter
== 'F' ||
468 *iter
== 'g' || *iter
== 'G')
469 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, double));
472 /* FIXME: On 32 bit systems this doesn't handle int 64's. */
473 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, void *));
478 if (written
++ >= len
)
480 *str
++ = *bufaiter
++;
494 int vsprintfW( WCHAR
*str
, const WCHAR
*format
, va_list valist
)
496 return vsnprintfW( str
, INT_MAX
, format
, valist
);
499 int snprintfW( WCHAR
*str
, size_t len
, const WCHAR
*format
, ...)
503 va_start(valist
, format
);
504 retval
= vsnprintfW(str
, len
, format
, valist
);
509 int sprintfW( WCHAR
*str
, const WCHAR
*format
, ...)
513 va_start(valist
, format
);
514 retval
= vsnprintfW(str
, INT_MAX
, format
, valist
);