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[256], 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);