ntdll: Don't run exception handlers on the signal stack on ARM64.
[wine.git] / libs / port / string.c
blobc3388bcc7dab692cb357f34785bac899c14b0640
1 /*
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
21 #include <assert.h>
22 #include <errno.h>
23 #include <limits.h>
24 #include <stdio.h>
26 #include "wine/unicode.h"
28 int strcmpiW( const WCHAR *str1, const WCHAR *str2 )
30 for (;;)
32 int ret = tolowerW(*str1) - tolowerW(*str2);
33 if (ret || !*str1) return ret;
34 str1++;
35 str2++;
39 int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n )
41 int ret = 0;
42 for ( ; n > 0; n--, str1++, str2++)
43 if ((ret = tolowerW(*str1) - tolowerW(*str2)) || !*str1) break;
44 return ret;
47 int memicmpW( const WCHAR *str1, const WCHAR *str2, int n )
49 int ret = 0;
50 for ( ; n > 0; n--, str1++, str2++)
51 if ((ret = tolowerW(*str1) - tolowerW(*str2))) break;
52 return ret;
55 WCHAR *strstrW( const WCHAR *str, const WCHAR *sub )
57 while (*str)
59 const WCHAR *p1 = str, *p2 = sub;
60 while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
61 if (!*p2) return (WCHAR *)str;
62 str++;
64 return NULL;
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 )
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;
81 if (base < 0 || base == 1 || base > 36) return 0;
83 save = s = nptr;
85 /* Skip white space. */
86 while (isspaceW (*s))
87 ++s;
88 if (!*s) goto noconv;
90 /* Check for a sign. */
91 negative = 0;
92 if (*s == '-')
94 negative = 1;
95 ++s;
97 else if (*s == '+')
98 ++s;
100 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
101 if (*s == '0')
103 if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
105 s += 2;
106 base = 16;
108 else if (base == 0)
109 base = 8;
111 else if (base == 0)
112 base = 10;
114 /* Save the pointer so we can check later if anything happened. */
115 save = s;
116 end = NULL;
118 cutoff = ULONG_MAX / (unsigned long int) base;
119 cutlim = ULONG_MAX % (unsigned long int) base;
121 overflow = 0;
122 i = 0;
123 c = *s;
124 for (;c != '\0'; c = *++s)
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
141 i *= (unsigned long int) base;
142 i += c;
146 /* Check if anything actually happened. */
147 if (s == save)
148 goto noconv;
150 /* Store in ENDPTR the address of one character
151 past the last character we converted. */
152 if (endptr != NULL)
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'. */
157 if (overflow == 0
158 && i > (negative
159 ? -((unsigned long int) (LONG_MIN + 1)) + 1
160 : (unsigned long int) LONG_MAX))
161 overflow = 1;
163 if (overflow)
165 errno = ERANGE;
166 return negative ? LONG_MIN : LONG_MAX;
169 /* Return the result of the appropriate sign. */
170 return negative ? -i : i;
172 noconv:
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`. */
177 if (endptr != NULL)
179 if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
180 && save[-2] == '0')
181 *endptr = (WCHAR *)&save[-1];
182 else
183 /* There was no number to convert. */
184 *endptr = (WCHAR *)nptr;
187 return 0L;
191 unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base )
193 int negative;
194 register unsigned long int cutoff;
195 register unsigned int cutlim;
196 register unsigned long int i;
197 register const WCHAR *s;
198 register WCHAR c;
199 const WCHAR *save, *end;
200 int overflow;
202 if (base < 0 || base == 1 || base > 36) return 0;
204 save = s = nptr;
206 /* Skip white space. */
207 while (isspaceW (*s))
208 ++s;
209 if (!*s) goto noconv;
211 /* Check for a sign. */
212 negative = 0;
213 if (*s == '-')
215 negative = 1;
216 ++s;
218 else if (*s == '+')
219 ++s;
221 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
222 if (*s == '0')
224 if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
226 s += 2;
227 base = 16;
229 else if (base == 0)
230 base = 8;
232 else if (base == 0)
233 base = 10;
235 /* Save the pointer so we can check later if anything happened. */
236 save = s;
237 end = NULL;
239 cutoff = ULONG_MAX / (unsigned long int) base;
240 cutlim = ULONG_MAX % (unsigned long int) base;
242 overflow = 0;
243 i = 0;
244 c = *s;
245 for (;c != '\0'; c = *++s)
247 if (s == end)
248 break;
249 if (c >= '0' && c <= '9')
250 c -= '0';
251 else if (isalphaW (c))
252 c = toupperW (c) - 'A' + 10;
253 else
254 break;
255 if ((int) c >= base)
256 break;
257 /* Check for overflow. */
258 if (i > cutoff || (i == cutoff && c > cutlim))
259 overflow = 1;
260 else
262 i *= (unsigned long int) base;
263 i += c;
267 /* Check if anything actually happened. */
268 if (s == save)
269 goto noconv;
271 /* Store in ENDPTR the address of one character
272 past the last character we converted. */
273 if (endptr != NULL)
274 *endptr = (WCHAR *)s;
276 if (overflow)
278 errno = ERANGE;
279 return ULONG_MAX;
282 /* Return the result of the appropriate sign. */
283 return negative ? -i : i;
285 noconv:
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`. */
290 if (endptr != NULL)
292 if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
293 && save[-2] == '0')
294 *endptr = (WCHAR *)&save[-1];
295 else
296 /* There was no number to convert. */
297 *endptr = (WCHAR *)nptr;
300 return 0L;
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 )
307 size_t count = 0;
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;
316 format++;
319 while (isdigit(*format)) width = width * 10 + *format++ - '0';
321 if (str_len == -1) str_len = strlenW( str );
322 if (*format == '.')
324 format++;
325 while (isdigit(*format)) max = max * 10 + *format++ - '0';
326 if (max > str_len) max = str_len;
328 else 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++)
338 if (count++ < len)
339 *buffer++ = ' ';
343 if (count < len)
344 memcpy( buffer, str, min( max, len - count ) * sizeof(WCHAR) );
345 count += max;
346 buffer += max;
348 if (left_align && width > max)
350 for (i = 0; i < width - max; i++)
352 if (count++ < len)
353 *buffer++ = ' ';
356 return count;
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;
365 while (*iter)
367 while (*iter && *iter != '%')
369 if (written++ < len)
370 *str++ = *iter;
371 iter++;
373 if (*iter == '%')
375 if (iter[1] == '%')
377 if (written++ < len)
378 *str++ = '%'; /* "%%"->'%' */
379 iter += 2;
380 continue;
383 fmta = fmtbufa;
384 *fmta++ = *iter++;
385 while (*iter == '0' ||
386 *iter == '+' ||
387 *iter == '-' ||
388 *iter == ' ' ||
389 *iter == '*' ||
390 *iter == '#')
392 if (*iter == '*')
394 char *buffiter = bufa;
395 int fieldlen = va_arg(valist, int);
396 sprintf(buffiter, "%d", fieldlen);
397 while (*buffiter)
398 *fmta++ = *buffiter++;
400 else
401 *fmta++ = *iter;
402 iter++;
405 while (isdigit(*iter))
406 *fmta++ = *iter++;
408 if (*iter == '.')
410 *fmta++ = *iter++;
411 if (*iter == '*')
413 char *buffiter = bufa;
414 int fieldlen = va_arg(valist, int);
415 sprintf(buffiter, "%d", fieldlen);
416 while (*buffiter)
417 *fmta++ = *buffiter++;
418 iter++;
420 else
421 while (isdigit(*iter))
422 *fmta++ = *iter++;
424 if (*iter == 'h' || *iter == 'l')
425 *fmta++ = *iter++;
427 switch (*iter)
429 case 's':
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;
434 size_t count;
436 *fmta++ = 's';
437 *fmta = 0;
438 count = format_string( str, remaining, fmtbufa, wstr ? wstr : none, -1 );
439 str += min( count, remaining );
440 written += count;
441 iter++;
442 break;
445 case 'c':
447 WCHAR wstr;
448 size_t remaining = written < len ? len - written : 0;
449 size_t count;
451 wstr = va_arg(valist, int);
452 *fmta++ = 's';
453 *fmta = 0;
454 count = format_string( str, remaining, fmtbufa, &wstr, 1 );
455 str += min( count, remaining );
456 written += count;
457 iter++;
458 break;
461 default:
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;
466 if (*iter == 'p')
467 sprintf(bufaiter, "%0*lX", 2 * (int)sizeof(void*),
468 (unsigned long)va_arg(valist, void *));
469 else
471 *fmta++ = *iter;
472 *fmta = '\0';
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));
478 else
480 /* FIXME: On 32 bit systems this doesn't handle int 64's. */
481 sprintf(bufaiter, fmtbufa, va_arg(valist, void *));
484 while (*bufaiter)
486 if (written++ < len)
487 *str++ = *bufaiter;
488 bufaiter++;
490 iter++;
491 break;
496 if (len)
498 if (written >= len)
499 str--;
500 *str++ = 0;
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, ...)
514 int retval;
515 va_list valist;
516 va_start(valist, format);
517 retval = vsnprintfW(str, len, format, valist);
518 va_end(valist);
519 return retval;
522 int sprintfW( WCHAR *str, const WCHAR *format, ...)
524 int retval;
525 va_list valist;
526 va_start(valist, format);
527 retval = vsnprintfW(str, INT_MAX, format, valist);
528 va_end(valist);
529 return retval;