winemac: Don't use sprintfW in copy_system_cursor_name.
[wine.git] / libs / wine / string.c
blob16bb97bec8e7989f9a64bb3da1b54d68803d3b3e
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 "wine/asm.h"
23 #ifdef __ASM_OBSOLETE
25 #include <assert.h>
26 #include <errno.h>
27 #include <limits.h>
28 #include <stdio.h>
29 #include <stdarg.h>
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winnls.h>
35 WCHAR tolowerW( WCHAR ch )
37 extern const WCHAR wine_casemap_lower[];
38 return ch + wine_casemap_lower[wine_casemap_lower[ch >> 8] + (ch & 0xff)];
41 WCHAR toupperW( WCHAR ch )
43 extern const WCHAR wine_casemap_upper[];
44 return ch + wine_casemap_upper[wine_casemap_upper[ch >> 8] + (ch & 0xff)];
47 /* the character type contains the C1_* flags in the low 12 bits */
48 /* and the C2_* type in the high 4 bits */
49 unsigned short get_char_typeW( WCHAR ch )
51 extern const unsigned short wine_wctype_table[];
52 return wine_wctype_table[wine_wctype_table[ch >> 8] + (ch & 0xff)];
55 int iscntrlW( WCHAR wc )
57 return get_char_typeW(wc) & C1_CNTRL;
60 int ispunctW( WCHAR wc )
62 return get_char_typeW(wc) & C1_PUNCT;
65 int isspaceW( WCHAR wc )
67 return get_char_typeW(wc) & C1_SPACE;
70 int isdigitW( WCHAR wc )
72 return get_char_typeW(wc) & C1_DIGIT;
75 int isxdigitW( WCHAR wc )
77 return get_char_typeW(wc) & C1_XDIGIT;
80 int islowerW( WCHAR wc )
82 return get_char_typeW(wc) & C1_LOWER;
85 int isupperW( WCHAR wc )
87 return get_char_typeW(wc) & C1_UPPER;
90 int isalnumW( WCHAR wc )
92 return get_char_typeW(wc) & (C1_ALPHA|C1_DIGIT|C1_LOWER|C1_UPPER);
95 int isalphaW( WCHAR wc )
97 return get_char_typeW(wc) & (C1_ALPHA|C1_LOWER|C1_UPPER);
100 int isgraphW( WCHAR wc )
102 return get_char_typeW(wc) & (C1_ALPHA|C1_PUNCT|C1_DIGIT|C1_LOWER|C1_UPPER);
105 int isprintW( WCHAR wc )
107 return get_char_typeW(wc) & (C1_ALPHA|C1_BLANK|C1_PUNCT|C1_DIGIT|C1_LOWER|C1_UPPER);
110 unsigned int strlenW( const WCHAR *str )
112 const WCHAR *s = str;
113 while (*s) s++;
114 return s - str;
117 WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
119 WCHAR *p = dst;
120 while ((*p++ = *src++));
121 return dst;
124 int strcmpW( const WCHAR *str1, const WCHAR *str2 )
126 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
127 return *str1 - *str2;
130 int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
132 if (n <= 0) return 0;
133 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
134 return *str1 - *str2;
137 WCHAR *strcatW( WCHAR *dst, const WCHAR *src )
139 strcpyW( dst + strlenW(dst), src );
140 return dst;
143 WCHAR *strchrW( const WCHAR *str, WCHAR ch )
145 do { if (*str == ch) return (WCHAR *)(ULONG_PTR)str; } while (*str++);
146 return NULL;
149 WCHAR *strrchrW( const WCHAR *str, WCHAR ch )
151 WCHAR *ret = NULL;
152 do { if (*str == ch) ret = (WCHAR *)(ULONG_PTR)str; } while (*str++);
153 return ret;
156 WCHAR *strpbrkW( const WCHAR *str, const WCHAR *accept )
158 for ( ; *str; str++) if (strchrW( accept, *str )) return (WCHAR *)(ULONG_PTR)str;
159 return NULL;
162 size_t strspnW( const WCHAR *str, const WCHAR *accept )
164 const WCHAR *ptr;
165 for (ptr = str; *ptr; ptr++) if (!strchrW( accept, *ptr )) break;
166 return ptr - str;
169 size_t strcspnW( const WCHAR *str, const WCHAR *reject )
171 const WCHAR *ptr;
172 for (ptr = str; *ptr; ptr++) if (strchrW( reject, *ptr )) break;
173 return ptr - str;
176 WCHAR *strlwrW( WCHAR *str )
178 WCHAR *ret;
179 for (ret = str; *str; str++) *str = tolowerW(*str);
180 return ret;
183 WCHAR *struprW( WCHAR *str )
185 WCHAR *ret;
186 for (ret = str; *str; str++) *str = toupperW(*str);
187 return ret;
190 WCHAR *memchrW( const WCHAR *ptr, WCHAR ch, size_t n )
192 const WCHAR *end;
193 for (end = ptr + n; ptr < end; ptr++) if (*ptr == ch) return (WCHAR *)(ULONG_PTR)ptr;
194 return NULL;
197 WCHAR *memrchrW( const WCHAR *ptr, WCHAR ch, size_t n )
199 const WCHAR *end;
200 WCHAR *ret = NULL;
201 for (end = ptr + n; ptr < end; ptr++) if (*ptr == ch) ret = (WCHAR *)(ULONG_PTR)ptr;
202 return ret;
205 int strcmpiW( const WCHAR *str1, const WCHAR *str2 )
207 for (;;)
209 int ret = tolowerW(*str1) - tolowerW(*str2);
210 if (ret || !*str1) return ret;
211 str1++;
212 str2++;
216 int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n )
218 int ret = 0;
219 for ( ; n > 0; n--, str1++, str2++)
220 if ((ret = tolowerW(*str1) - tolowerW(*str2)) || !*str1) break;
221 return ret;
224 int memicmpW( const WCHAR *str1, const WCHAR *str2, int n )
226 int ret = 0;
227 for ( ; n > 0; n--, str1++, str2++)
228 if ((ret = tolowerW(*str1) - tolowerW(*str2))) break;
229 return ret;
232 WCHAR *strstrW( const WCHAR *str, const WCHAR *sub )
234 while (*str)
236 const WCHAR *p1 = str, *p2 = sub;
237 while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
238 if (!*p2) return (WCHAR *)str;
239 str++;
241 return NULL;
244 /* strtolW and strtoulW implementation based on the GNU C library code */
245 /* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc. */
247 long int strtolW( const WCHAR *nptr, WCHAR **endptr, int base )
249 int negative;
250 register unsigned long int cutoff;
251 register unsigned int cutlim;
252 register unsigned long int i;
253 register const WCHAR *s;
254 register WCHAR c;
255 const WCHAR *save, *end;
256 int overflow;
258 if (base < 0 || base == 1 || base > 36) return 0;
260 save = s = nptr;
262 /* Skip white space. */
263 while (isspaceW (*s))
264 ++s;
265 if (!*s) goto noconv;
267 /* Check for a sign. */
268 negative = 0;
269 if (*s == '-')
271 negative = 1;
272 ++s;
274 else if (*s == '+')
275 ++s;
277 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
278 if (*s == '0')
280 if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
282 s += 2;
283 base = 16;
285 else if (base == 0)
286 base = 8;
288 else if (base == 0)
289 base = 10;
291 /* Save the pointer so we can check later if anything happened. */
292 save = s;
293 end = NULL;
295 cutoff = ULONG_MAX / (unsigned long int) base;
296 cutlim = ULONG_MAX % (unsigned long int) base;
298 overflow = 0;
299 i = 0;
300 c = *s;
301 for (;c != '\0'; c = *++s)
303 if (s == end)
304 break;
305 if (c >= '0' && c <= '9')
306 c -= '0';
307 else if (isalphaW (c))
308 c = toupperW (c) - 'A' + 10;
309 else
310 break;
311 if ((int) c >= base)
312 break;
313 /* Check for overflow. */
314 if (i > cutoff || (i == cutoff && c > cutlim))
315 overflow = 1;
316 else
318 i *= (unsigned long int) base;
319 i += c;
323 /* Check if anything actually happened. */
324 if (s == save)
325 goto noconv;
327 /* Store in ENDPTR the address of one character
328 past the last character we converted. */
329 if (endptr != NULL)
330 *endptr = (WCHAR *)s;
332 /* Check for a value that is within the range of
333 `unsigned LONG int', but outside the range of `LONG int'. */
334 if (overflow == 0
335 && i > (negative
336 ? -((unsigned long int) (LONG_MIN + 1)) + 1
337 : (unsigned long int) LONG_MAX))
338 overflow = 1;
340 if (overflow)
342 errno = ERANGE;
343 return negative ? LONG_MIN : LONG_MAX;
346 /* Return the result of the appropriate sign. */
347 return negative ? -i : i;
349 noconv:
350 /* We must handle a special case here: the base is 0 or 16 and the
351 first two characters are '0' and 'x', but the rest are not
352 hexadecimal digits. This is no error case. We return 0 and
353 ENDPTR points to the `x`. */
354 if (endptr != NULL)
356 if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
357 && save[-2] == '0')
358 *endptr = (WCHAR *)&save[-1];
359 else
360 /* There was no number to convert. */
361 *endptr = (WCHAR *)nptr;
364 return 0L;
368 unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base )
370 int negative;
371 register unsigned long int cutoff;
372 register unsigned int cutlim;
373 register unsigned long int i;
374 register const WCHAR *s;
375 register WCHAR c;
376 const WCHAR *save, *end;
377 int overflow;
379 if (base < 0 || base == 1 || base > 36) return 0;
381 save = s = nptr;
383 /* Skip white space. */
384 while (isspaceW (*s))
385 ++s;
386 if (!*s) goto noconv;
388 /* Check for a sign. */
389 negative = 0;
390 if (*s == '-')
392 negative = 1;
393 ++s;
395 else if (*s == '+')
396 ++s;
398 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
399 if (*s == '0')
401 if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
403 s += 2;
404 base = 16;
406 else if (base == 0)
407 base = 8;
409 else if (base == 0)
410 base = 10;
412 /* Save the pointer so we can check later if anything happened. */
413 save = s;
414 end = NULL;
416 cutoff = ULONG_MAX / (unsigned long int) base;
417 cutlim = ULONG_MAX % (unsigned long int) base;
419 overflow = 0;
420 i = 0;
421 c = *s;
422 for (;c != '\0'; c = *++s)
424 if (s == end)
425 break;
426 if (c >= '0' && c <= '9')
427 c -= '0';
428 else if (isalphaW (c))
429 c = toupperW (c) - 'A' + 10;
430 else
431 break;
432 if ((int) c >= base)
433 break;
434 /* Check for overflow. */
435 if (i > cutoff || (i == cutoff && c > cutlim))
436 overflow = 1;
437 else
439 i *= (unsigned long int) base;
440 i += c;
444 /* Check if anything actually happened. */
445 if (s == save)
446 goto noconv;
448 /* Store in ENDPTR the address of one character
449 past the last character we converted. */
450 if (endptr != NULL)
451 *endptr = (WCHAR *)s;
453 if (overflow)
455 errno = ERANGE;
456 return ULONG_MAX;
459 /* Return the result of the appropriate sign. */
460 return negative ? -i : i;
462 noconv:
463 /* We must handle a special case here: the base is 0 or 16 and the
464 first two characters are '0' and 'x', but the rest are not
465 hexadecimal digits. This is no error case. We return 0 and
466 ENDPTR points to the `x`. */
467 if (endptr != NULL)
469 if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
470 && save[-2] == '0')
471 *endptr = (WCHAR *)&save[-1];
472 else
473 /* There was no number to convert. */
474 *endptr = (WCHAR *)nptr;
477 return 0L;
480 long int atolW( const WCHAR *str )
482 return strtolW( str, NULL, 10 );
485 int atoiW( const WCHAR *str )
487 return (int)atolW( str );
491 /* format a WCHAR string according to a printf format; helper for vsnprintfW */
492 static size_t format_string( WCHAR *buffer, size_t len, const char *format, const WCHAR *str, int str_len )
494 size_t count = 0;
495 int i, left_align = 0, width = 0, max = 0;
497 assert( *format == '%' );
498 format++; /* skip '%' */
500 while (*format == '0' || *format == '+' || *format == '-' || *format == ' ' || *format == '#')
502 if (*format == '-') left_align = 1;
503 format++;
506 while (isdigit(*format)) width = width * 10 + *format++ - '0';
508 if (str_len == -1) str_len = strlenW( str );
509 if (*format == '.')
511 format++;
512 while (isdigit(*format)) max = max * 10 + *format++ - '0';
513 if (max > str_len) max = str_len;
515 else max = str_len;
517 if (*format == 'h' || *format == 'l') format++;
519 assert( *format == 's' );
521 if (!left_align && width > max)
523 for (i = 0; i < width - max; i++)
525 if (count++ < len)
526 *buffer++ = ' ';
530 if (count < len)
531 memcpy( buffer, str, min( max, len - count ) * sizeof(WCHAR) );
532 count += max;
533 buffer += max;
535 if (left_align && width > max)
537 for (i = 0; i < width - max; i++)
539 if (count++ < len)
540 *buffer++ = ' ';
543 return count;
546 int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
548 unsigned int written = 0;
549 const WCHAR *iter = format;
550 char bufa[512], fmtbufa[64], *fmta;
552 while (*iter)
554 while (*iter && *iter != '%')
556 if (written++ < len)
557 *str++ = *iter;
558 iter++;
560 if (*iter == '%')
562 if (iter[1] == '%')
564 if (written++ < len)
565 *str++ = '%'; /* "%%"->'%' */
566 iter += 2;
567 continue;
570 fmta = fmtbufa;
571 *fmta++ = *iter++;
572 while (*iter == '0' ||
573 *iter == '+' ||
574 *iter == '-' ||
575 *iter == ' ' ||
576 *iter == '*' ||
577 *iter == '#')
579 if (*iter == '*')
581 char *buffiter = bufa;
582 int fieldlen = va_arg(valist, int);
583 sprintf(buffiter, "%d", fieldlen);
584 while (*buffiter)
585 *fmta++ = *buffiter++;
587 else
588 *fmta++ = *iter;
589 iter++;
592 while (isdigit(*iter))
593 *fmta++ = *iter++;
595 if (*iter == '.')
597 *fmta++ = *iter++;
598 if (*iter == '*')
600 char *buffiter = bufa;
601 int fieldlen = va_arg(valist, int);
602 sprintf(buffiter, "%d", fieldlen);
603 while (*buffiter)
604 *fmta++ = *buffiter++;
605 iter++;
607 else
608 while (isdigit(*iter))
609 *fmta++ = *iter++;
611 if (*iter == 'h' || *iter == 'l')
612 *fmta++ = *iter++;
614 switch (*iter)
616 case 's':
618 static const WCHAR none[] = { '(','n','u','l','l',')',0 };
619 const WCHAR *wstr = va_arg(valist, const WCHAR *);
620 size_t remaining = written < len ? len - written : 0;
621 size_t count;
623 *fmta++ = 's';
624 *fmta = 0;
625 count = format_string( str, remaining, fmtbufa, wstr ? wstr : none, -1 );
626 str += min( count, remaining );
627 written += count;
628 iter++;
629 break;
632 case 'c':
634 WCHAR wstr;
635 size_t remaining = written < len ? len - written : 0;
636 size_t count;
638 wstr = va_arg(valist, int);
639 *fmta++ = 's';
640 *fmta = 0;
641 count = format_string( str, remaining, fmtbufa, &wstr, 1 );
642 str += min( count, remaining );
643 written += count;
644 iter++;
645 break;
648 default:
650 /* For non wc types, use system sprintf and append to wide char output */
651 /* FIXME: for unrecognised types, should ignore % when printing */
652 char *bufaiter = bufa;
653 if (*iter == 'p')
654 sprintf(bufaiter, "%0*lX", 2 * (int)sizeof(void*),
655 (unsigned long)va_arg(valist, void *));
656 else
658 *fmta++ = *iter;
659 *fmta = '\0';
660 if (*iter == 'a' || *iter == 'A' ||
661 *iter == 'e' || *iter == 'E' ||
662 *iter == 'f' || *iter == 'F' ||
663 *iter == 'g' || *iter == 'G')
664 sprintf(bufaiter, fmtbufa, va_arg(valist, double));
665 else
667 /* FIXME: On 32 bit systems this doesn't handle int 64's. */
668 sprintf(bufaiter, fmtbufa, va_arg(valist, void *));
671 while (*bufaiter)
673 if (written++ < len)
674 *str++ = *bufaiter;
675 bufaiter++;
677 iter++;
678 break;
683 if (len)
685 if (written >= len)
686 str--;
687 *str++ = 0;
690 /* FIXME: POSIX [v]snprintf() returns the equivalent of written, not -1, on short buffer. */
691 return written < len ? (int)written : -1;
694 int vsprintfW( WCHAR *str, const WCHAR *format, va_list valist )
696 return vsnprintfW( str, INT_MAX, format, valist );
699 int snprintfW( WCHAR *str, size_t len, const WCHAR *format, ...)
701 int retval;
702 va_list valist;
703 va_start(valist, format);
704 retval = vsnprintfW(str, len, format, valist);
705 va_end(valist);
706 return retval;
709 int sprintfW( WCHAR *str, const WCHAR *format, ...)
711 int retval;
712 va_list valist;
713 va_start(valist, format);
714 retval = vsnprintfW(str, INT_MAX, format, valist);
715 va_end(valist);
716 return retval;
719 #endif /* __ASM_OBSOLETE */