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 #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
))
166 return negative
? LONG_MIN
: LONG_MAX
;
169 /* Return the result of the appropriate sign. */
170 return negative
? -i
: i
;
173 /* We must handle a special case here: the base is 0 or 16 and the
174 first two characters are '0' and 'x', but the rest are not
175 hexadecimal digits. This is no error case. We return 0 and
176 ENDPTR points to the `x`. */
179 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
181 *endptr
= (WCHAR
*)&save
[-1];
183 /* There was no number to convert. */
184 *endptr
= (WCHAR
*)nptr
;
191 unsigned long int strtoulW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
194 register unsigned long int cutoff
;
195 register unsigned int cutlim
;
196 register unsigned long int i
;
197 register const WCHAR
*s
;
199 const WCHAR
*save
, *end
;
202 if (base
< 0 || base
== 1 || base
> 36) return 0;
206 /* Skip white space. */
207 while (isspaceW (*s
))
209 if (!*s
) goto noconv
;
211 /* Check for a sign. */
221 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
224 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
235 /* Save the pointer so we can check later if anything happened. */
239 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
240 cutlim
= ULONG_MAX
% (unsigned long int) base
;
245 for (;c
!= '\0'; c
= *++s
)
249 if (c
>= '0' && c
<= '9')
251 else if (isalphaW (c
))
252 c
= toupperW (c
) - 'A' + 10;
257 /* Check for overflow. */
258 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
262 i
*= (unsigned long int) base
;
267 /* Check if anything actually happened. */
271 /* Store in ENDPTR the address of one character
272 past the last character we converted. */
274 *endptr
= (WCHAR
*)s
;
282 /* Return the result of the appropriate sign. */
283 return negative
? -i
: i
;
286 /* We must handle a special case here: the base is 0 or 16 and the
287 first two characters are '0' and 'x', but the rest are not
288 hexadecimal digits. This is no error case. We return 0 and
289 ENDPTR points to the `x`. */
292 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
294 *endptr
= (WCHAR
*)&save
[-1];
296 /* There was no number to convert. */
297 *endptr
= (WCHAR
*)nptr
;
304 /* format a WCHAR string according to a printf format; helper for vsnprintfW */
305 static size_t format_string( WCHAR
*buffer
, size_t len
, const char *format
, const WCHAR
*str
, int str_len
)
308 int i
, left_align
= 0, width
= 0, max
= 0;
310 assert( *format
== '%' );
311 format
++; /* skip '%' */
313 while (*format
== '0' || *format
== '+' || *format
== '-' || *format
== ' ' || *format
== '#')
315 if (*format
== '-') left_align
= 1;
319 while (isdigit(*format
)) width
= width
* 10 + *format
++ - '0';
321 if (str_len
== -1) str_len
= strlenW( str
);
325 while (isdigit(*format
)) max
= max
* 10 + *format
++ - '0';
326 if (max
> str_len
) max
= str_len
;
330 if (*format
== 'h' || *format
== 'l') format
++;
332 assert( *format
== 's' );
334 if (!left_align
&& width
> max
)
336 for (i
= 0; i
< width
- max
; i
++)
344 memcpy( buffer
, str
, min( max
, len
- count
) * sizeof(WCHAR
) );
348 if (left_align
&& width
> max
)
350 for (i
= 0; i
< width
- max
; i
++)
359 int vsnprintfW(WCHAR
*str
, size_t len
, const WCHAR
*format
, va_list valist
)
361 unsigned int written
= 0;
362 const WCHAR
*iter
= format
;
363 char bufa
[512], fmtbufa
[64], *fmta
;
367 while (*iter
&& *iter
!= '%')
378 *str
++ = '%'; /* "%%"->'%' */
385 while (*iter
== '0' ||
394 char *buffiter
= bufa
;
395 int fieldlen
= va_arg(valist
, int);
396 sprintf(buffiter
, "%d", fieldlen
);
398 *fmta
++ = *buffiter
++;
405 while (isdigit(*iter
))
413 char *buffiter
= bufa
;
414 int fieldlen
= va_arg(valist
, int);
415 sprintf(buffiter
, "%d", fieldlen
);
417 *fmta
++ = *buffiter
++;
421 while (isdigit(*iter
))
424 if (*iter
== 'h' || *iter
== 'l')
431 static const WCHAR none
[] = { '(','n','u','l','l',')',0 };
432 const WCHAR
*wstr
= va_arg(valist
, const WCHAR
*);
433 size_t remaining
= written
< len
? len
- written
: 0;
438 count
= format_string( str
, remaining
, fmtbufa
, wstr
? wstr
: none
, -1 );
439 str
+= min( count
, remaining
);
448 size_t remaining
= written
< len
? len
- written
: 0;
451 wstr
= va_arg(valist
, int);
454 count
= format_string( str
, remaining
, fmtbufa
, &wstr
, 1 );
455 str
+= min( count
, remaining
);
463 /* For non wc types, use system sprintf and append to wide char output */
464 /* FIXME: for unrecognised types, should ignore % when printing */
465 char *bufaiter
= bufa
;
467 sprintf(bufaiter
, "%0*lX", 2 * (int)sizeof(void*),
468 (unsigned long)va_arg(valist
, void *));
473 if (*iter
== 'a' || *iter
== 'A' ||
474 *iter
== 'e' || *iter
== 'E' ||
475 *iter
== 'f' || *iter
== 'F' ||
476 *iter
== 'g' || *iter
== 'G')
477 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, double));
480 /* FIXME: On 32 bit systems this doesn't handle int 64's. */
481 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, void *));
503 /* FIXME: POSIX [v]snprintf() returns the equivalent of written, not -1, on short buffer. */
504 return written
< len
? (int)written
: -1;
507 int vsprintfW( WCHAR
*str
, const WCHAR
*format
, va_list valist
)
509 return vsnprintfW( str
, INT_MAX
, format
, valist
);
512 int snprintfW( WCHAR
*str
, size_t len
, const WCHAR
*format
, ...)
516 va_start(valist
, format
);
517 retval
= vsnprintfW(str
, len
, format
, valist
);
522 int sprintfW( WCHAR
*str
, const WCHAR
*format
, ...)
526 va_start(valist
, format
);
527 retval
= vsnprintfW(str
, INT_MAX
, format
, valist
);