update wine's unicode app to 1.2rc6. (Samuel Serapion)
[reactos.git] / reactos / tools / unicode / string.c
1 /*
2 * Unicode string manipulation functions
3 *
4 * Copyright 2000 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <assert.h>
22 #include <limits.h>
23 #include <stdio.h>
24
25 #define WINE_UNICODE_INLINE /* nothing */
26 #include "wine/unicode.h"
27
28 int strcmpiW( const WCHAR *str1, const WCHAR *str2 )
29 {
30 for (;;)
31 {
32 int ret = tolowerW(*str1) - tolowerW(*str2);
33 if (ret || !*str1) return ret;
34 str1++;
35 str2++;
36 }
37 }
38
39 int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n )
40 {
41 int ret = 0;
42 for ( ; n > 0; n--, str1++, str2++)
43 if ((ret = tolowerW(*str1) - tolowerW(*str2)) || !*str1) break;
44 return ret;
45 }
46
47 int memicmpW( const WCHAR *str1, const WCHAR *str2, int n )
48 {
49 int ret = 0;
50 for ( ; n > 0; n--, str1++, str2++)
51 if ((ret = tolowerW(*str1) - tolowerW(*str2))) break;
52 return ret;
53 }
54
55 WCHAR *strstrW( const WCHAR *str, const WCHAR *sub )
56 {
57 while (*str)
58 {
59 const WCHAR *p1 = str, *p2 = sub;
60 while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
61 if (!*p2) return (WCHAR *)str;
62 str++;
63 }
64 return NULL;
65 }
66
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. */
69
70 long int strtolW( const WCHAR *nptr, WCHAR **endptr, int base )
71 {
72 int negative;
73 register unsigned long int cutoff;
74 register unsigned int cutlim;
75 register unsigned long int i;
76 register const WCHAR *s;
77 register WCHAR c;
78 const WCHAR *save, *end;
79 int overflow;
80
81 if (base < 0 || base == 1 || base > 36) return 0;
82
83 save = s = nptr;
84
85 /* Skip white space. */
86 while (isspaceW (*s))
87 ++s;
88 if (!*s) goto noconv;
89
90 /* Check for a sign. */
91 negative = 0;
92 if (*s == '-')
93 {
94 negative = 1;
95 ++s;
96 }
97 else if (*s == '+')
98 ++s;
99
100 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
101 if (*s == '0')
102 {
103 if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
104 {
105 s += 2;
106 base = 16;
107 }
108 else if (base == 0)
109 base = 8;
110 }
111 else if (base == 0)
112 base = 10;
113
114 /* Save the pointer so we can check later if anything happened. */
115 save = s;
116 end = NULL;
117
118 cutoff = ULONG_MAX / (unsigned long int) base;
119 cutlim = ULONG_MAX % (unsigned long int) base;
120
121 overflow = 0;
122 i = 0;
123 c = *s;
124 for (;c != '\0'; c = *++s)
125 {
126 if (s == end)
127 break;
128 if (c >= '0' && c <= '9')
129 c -= '0';
130 else if (isalphaW (c))
131 c = toupperW (c) - 'A' + 10;
132 else
133 break;
134 if ((int) c >= base)
135 break;
136 /* Check for overflow. */
137 if (i > cutoff || (i == cutoff && c > cutlim))
138 overflow = 1;
139 else
140 {
141 i *= (unsigned long int) base;
142 i += c;
143 }
144 }
145
146 /* Check if anything actually happened. */
147 if (s == save)
148 goto noconv;
149
150 /* Store in ENDPTR the address of one character
151 past the last character we converted. */
152 if (endptr != NULL)
153 *endptr = (WCHAR *)s;
154
155 /* Check for a value that is within the range of
156 `unsigned LONG int', but outside the range of `LONG int'. */
157 if (overflow == 0
158 && i > (negative
159 ? -((unsigned long int) (LONG_MIN + 1)) + 1
160 : (unsigned long int) LONG_MAX))
161 overflow = 1;
162
163 if (overflow)
164 {
165 return negative ? LONG_MIN : LONG_MAX;
166 }
167
168 /* Return the result of the appropriate sign. */
169 return negative ? -i : i;
170
171 noconv:
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`. */
176 if (endptr != NULL)
177 {
178 if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
179 && save[-2] == '0')
180 *endptr = (WCHAR *)&save[-1];
181 else
182 /* There was no number to convert. */
183 *endptr = (WCHAR *)nptr;
184 }
185
186 return 0L;
187 }
188
189
190 unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base )
191 {
192 int negative;
193 register unsigned long int cutoff;
194 register unsigned int cutlim;
195 register unsigned long int i;
196 register const WCHAR *s;
197 register WCHAR c;
198 const WCHAR *save, *end;
199 int overflow;
200
201 if (base < 0 || base == 1 || base > 36) return 0;
202
203 save = s = nptr;
204
205 /* Skip white space. */
206 while (isspaceW (*s))
207 ++s;
208 if (!*s) goto noconv;
209
210 /* Check for a sign. */
211 negative = 0;
212 if (*s == '-')
213 {
214 negative = 1;
215 ++s;
216 }
217 else if (*s == '+')
218 ++s;
219
220 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
221 if (*s == '0')
222 {
223 if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
224 {
225 s += 2;
226 base = 16;
227 }
228 else if (base == 0)
229 base = 8;
230 }
231 else if (base == 0)
232 base = 10;
233
234 /* Save the pointer so we can check later if anything happened. */
235 save = s;
236 end = NULL;
237
238 cutoff = ULONG_MAX / (unsigned long int) base;
239 cutlim = ULONG_MAX % (unsigned long int) base;
240
241 overflow = 0;
242 i = 0;
243 c = *s;
244 for (;c != '\0'; c = *++s)
245 {
246 if (s == end)
247 break;
248 if (c >= '0' && c <= '9')
249 c -= '0';
250 else if (isalphaW (c))
251 c = toupperW (c) - 'A' + 10;
252 else
253 break;
254 if ((int) c >= base)
255 break;
256 /* Check for overflow. */
257 if (i > cutoff || (i == cutoff && c > cutlim))
258 overflow = 1;
259 else
260 {
261 i *= (unsigned long int) base;
262 i += c;
263 }
264 }
265
266 /* Check if anything actually happened. */
267 if (s == save)
268 goto noconv;
269
270 /* Store in ENDPTR the address of one character
271 past the last character we converted. */
272 if (endptr != NULL)
273 *endptr = (WCHAR *)s;
274
275 if (overflow)
276 {
277 return ULONG_MAX;
278 }
279
280 /* Return the result of the appropriate sign. */
281 return negative ? -i : i;
282
283 noconv:
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`. */
288 if (endptr != NULL)
289 {
290 if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
291 && save[-2] == '0')
292 *endptr = (WCHAR *)&save[-1];
293 else
294 /* There was no number to convert. */
295 *endptr = (WCHAR *)nptr;
296 }
297
298 return 0L;
299 }
300
301
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 )
304 {
305 size_t count = 0;
306 int i, left_align = 0, width = 0, max = 0;
307
308 assert( *format == '%' );
309 format++; /* skip '%' */
310
311 while (*format == '0' || *format == '+' || *format == '-' || *format == ' ' || *format == '#')
312 {
313 if (*format == '-') left_align = 1;
314 format++;
315 }
316
317 while (isdigit(*format)) width = width * 10 + *format++ - '0';
318
319 if (*format == '.')
320 {
321 format++;
322 while (isdigit(*format)) max = max * 10 + *format++ - '0';
323 for (i = 0; i < max; i++) if (!str[i]) max = i;
324 }
325 else max = strlenW(str);
326
327 if (*format == 'h' || *format == 'l') format++;
328
329 assert( *format == 's' );
330
331 if (!left_align && width > max)
332 {
333 if ((count += width - max) >= len) return -1;
334 for (i = 0; i < width - max; i++) *buffer++ = ' ';
335 }
336
337 if ((count += max) >= len) return -1;
338 memcpy( buffer, str, max * sizeof(WCHAR) );
339 buffer += max;
340
341 if (left_align && width > max)
342 {
343 if ((count += width - max) >= len) return -1;
344 for (i = 0; i < width - max; i++) *buffer++ = ' ';
345 }
346 return count;
347 }
348
349 int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
350 {
351 unsigned int written = 0;
352 const WCHAR *iter = format;
353 char bufa[256], fmtbufa[64], *fmta;
354
355 while (*iter)
356 {
357 while (*iter && *iter != '%')
358 {
359 if (written++ >= len)
360 return -1;
361 *str++ = *iter++;
362 }
363 if (*iter == '%')
364 {
365 if (iter[1] == '%')
366 {
367 if (written++ >= len)
368 return -1;
369 *str++ = '%'; /* "%%"->'%' */
370 iter += 2;
371 continue;
372 }
373
374 fmta = fmtbufa;
375 *fmta++ = *iter++;
376 while (*iter == '0' ||
377 *iter == '+' ||
378 *iter == '-' ||
379 *iter == ' ' ||
380 *iter == '*' ||
381 *iter == '#')
382 {
383 if (*iter == '*')
384 {
385 char *buffiter = bufa;
386 int fieldlen = va_arg(valist, int);
387 sprintf(buffiter, "%d", fieldlen);
388 while (*buffiter)
389 *fmta++ = *buffiter++;
390 }
391 else
392 *fmta++ = *iter;
393 iter++;
394 }
395
396 while (isdigit(*iter))
397 *fmta++ = *iter++;
398
399 if (*iter == '.')
400 {
401 *fmta++ = *iter++;
402 if (*iter == '*')
403 {
404 char *buffiter = bufa;
405 int fieldlen = va_arg(valist, int);
406 sprintf(buffiter, "%d", fieldlen);
407 while (*buffiter)
408 *fmta++ = *buffiter++;
409 iter++;
410 }
411 else
412 while (isdigit(*iter))
413 *fmta++ = *iter++;
414 }
415 if (*iter == 'h' || *iter == 'l')
416 *fmta++ = *iter++;
417
418 switch (*iter)
419 {
420 case 's':
421 {
422 static const WCHAR none[] = { '(','n','u','l','l',')',0 };
423 const WCHAR *wstr = va_arg(valist, const WCHAR *);
424 int count;
425
426 *fmta++ = 's';
427 *fmta = 0;
428 count = format_string( str, len - written, fmtbufa, wstr ? wstr : none );
429 if (count == -1) return -1;
430 str += count;
431 written += count;
432 iter++;
433 break;
434 }
435
436 case 'c':
437 {
438 WCHAR wstr[2];
439 int count;
440
441 wstr[0] = va_arg(valist, int);
442 wstr[1] = 0;
443 *fmta++ = 's';
444 *fmta = 0;
445 count = format_string( str, len - written, fmtbufa, wstr );
446 if (count == -1) return -1;
447 str += count;
448 written += count;
449 iter++;
450 break;
451 }
452
453 default:
454 {
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;
458 if (*iter == 'p')
459 sprintf(bufaiter, "%0*lX", 2 * (int)sizeof(void*),
460 (unsigned long)va_arg(valist, void *));
461 else
462 {
463 *fmta++ = *iter;
464 *fmta = '\0';
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));
470 else
471 {
472 /* FIXME: On 32 bit systems this doesn't handle int 64's. */
473 sprintf(bufaiter, fmtbufa, va_arg(valist, void *));
474 }
475 }
476 while (*bufaiter)
477 {
478 if (written++ >= len)
479 return -1;
480 *str++ = *bufaiter++;
481 }
482 iter++;
483 break;
484 }
485 }
486 }
487 }
488 if (written >= len)
489 return -1;
490 *str++ = 0;
491 return (int)written;
492 }
493
494 int vsprintfW( WCHAR *str, const WCHAR *format, va_list valist )
495 {
496 return vsnprintfW( str, INT_MAX, format, valist );
497 }
498
499 int snprintfW( WCHAR *str, size_t len, const WCHAR *format, ...)
500 {
501 int retval;
502 va_list valist;
503 va_start(valist, format);
504 retval = vsnprintfW(str, len, format, valist);
505 va_end(valist);
506 return retval;
507 }
508
509 int sprintfW( WCHAR *str, const WCHAR *format, ...)
510 {
511 int retval;
512 va_list valist;
513 va_start(valist, format);
514 retval = vsnprintfW(str, INT_MAX, format, valist);
515 va_end(valist);
516 return retval;
517 }