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
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
;
117 WCHAR
*strcpyW( WCHAR
*dst
, const WCHAR
*src
)
120 while ((*p
++ = *src
++));
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
);
143 WCHAR
*strchrW( const WCHAR
*str
, WCHAR ch
)
145 do { if (*str
== ch
) return (WCHAR
*)(ULONG_PTR
)str
; } while (*str
++);
149 WCHAR
*strrchrW( const WCHAR
*str
, WCHAR ch
)
152 do { if (*str
== ch
) ret
= (WCHAR
*)(ULONG_PTR
)str
; } while (*str
++);
156 WCHAR
*strpbrkW( const WCHAR
*str
, const WCHAR
*accept
)
158 for ( ; *str
; str
++) if (strchrW( accept
, *str
)) return (WCHAR
*)(ULONG_PTR
)str
;
162 size_t strspnW( const WCHAR
*str
, const WCHAR
*accept
)
165 for (ptr
= str
; *ptr
; ptr
++) if (!strchrW( accept
, *ptr
)) break;
169 size_t strcspnW( const WCHAR
*str
, const WCHAR
*reject
)
172 for (ptr
= str
; *ptr
; ptr
++) if (strchrW( reject
, *ptr
)) break;
176 WCHAR
*strlwrW( WCHAR
*str
)
179 for (ret
= str
; *str
; str
++) *str
= tolowerW(*str
);
183 WCHAR
*struprW( WCHAR
*str
)
186 for (ret
= str
; *str
; str
++) *str
= toupperW(*str
);
190 WCHAR
*memchrW( const WCHAR
*ptr
, WCHAR ch
, size_t n
)
193 for (end
= ptr
+ n
; ptr
< end
; ptr
++) if (*ptr
== ch
) return (WCHAR
*)(ULONG_PTR
)ptr
;
197 WCHAR
*memrchrW( const WCHAR
*ptr
, WCHAR ch
, size_t n
)
201 for (end
= ptr
+ n
; ptr
< end
; ptr
++) if (*ptr
== ch
) ret
= (WCHAR
*)(ULONG_PTR
)ptr
;
205 int strcmpiW( const WCHAR
*str1
, const WCHAR
*str2
)
209 int ret
= tolowerW(*str1
) - tolowerW(*str2
);
210 if (ret
|| !*str1
) return ret
;
216 int strncmpiW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
219 for ( ; n
> 0; n
--, str1
++, str2
++)
220 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
)) || !*str1
) break;
224 int memicmpW( const WCHAR
*str1
, const WCHAR
*str2
, int n
)
227 for ( ; n
> 0; n
--, str1
++, str2
++)
228 if ((ret
= tolowerW(*str1
) - tolowerW(*str2
))) break;
232 WCHAR
*strstrW( const WCHAR
*str
, const WCHAR
*sub
)
236 const WCHAR
*p1
= str
, *p2
= sub
;
237 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
238 if (!*p2
) return (WCHAR
*)str
;
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
)
250 register unsigned long int cutoff
;
251 register unsigned int cutlim
;
252 register unsigned long int i
;
253 register const WCHAR
*s
;
255 const WCHAR
*save
, *end
;
258 if (base
< 0 || base
== 1 || base
> 36) return 0;
262 /* Skip white space. */
263 while (isspaceW (*s
))
265 if (!*s
) goto noconv
;
267 /* Check for a sign. */
277 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
280 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
291 /* Save the pointer so we can check later if anything happened. */
295 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
296 cutlim
= ULONG_MAX
% (unsigned long int) base
;
301 for (;c
!= '\0'; c
= *++s
)
305 if (c
>= '0' && c
<= '9')
307 else if (isalphaW (c
))
308 c
= toupperW (c
) - 'A' + 10;
313 /* Check for overflow. */
314 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
318 i
*= (unsigned long int) base
;
323 /* Check if anything actually happened. */
327 /* Store in ENDPTR the address of one character
328 past the last character we converted. */
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'. */
336 ? -((unsigned long int) (LONG_MIN
+ 1)) + 1
337 : (unsigned long int) LONG_MAX
))
343 return negative
? LONG_MIN
: LONG_MAX
;
346 /* Return the result of the appropriate sign. */
347 return negative
? -i
: i
;
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`. */
356 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
358 *endptr
= (WCHAR
*)&save
[-1];
360 /* There was no number to convert. */
361 *endptr
= (WCHAR
*)nptr
;
368 unsigned long int strtoulW( const WCHAR
*nptr
, WCHAR
**endptr
, int base
)
371 register unsigned long int cutoff
;
372 register unsigned int cutlim
;
373 register unsigned long int i
;
374 register const WCHAR
*s
;
376 const WCHAR
*save
, *end
;
379 if (base
< 0 || base
== 1 || base
> 36) return 0;
383 /* Skip white space. */
384 while (isspaceW (*s
))
386 if (!*s
) goto noconv
;
388 /* Check for a sign. */
398 /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
401 if ((base
== 0 || base
== 16) && toupperW(s
[1]) == 'X')
412 /* Save the pointer so we can check later if anything happened. */
416 cutoff
= ULONG_MAX
/ (unsigned long int) base
;
417 cutlim
= ULONG_MAX
% (unsigned long int) base
;
422 for (;c
!= '\0'; c
= *++s
)
426 if (c
>= '0' && c
<= '9')
428 else if (isalphaW (c
))
429 c
= toupperW (c
) - 'A' + 10;
434 /* Check for overflow. */
435 if (i
> cutoff
|| (i
== cutoff
&& c
> cutlim
))
439 i
*= (unsigned long int) base
;
444 /* Check if anything actually happened. */
448 /* Store in ENDPTR the address of one character
449 past the last character we converted. */
451 *endptr
= (WCHAR
*)s
;
459 /* Return the result of the appropriate sign. */
460 return negative
? -i
: i
;
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`. */
469 if (save
- nptr
>= 2 && toupperW (save
[-1]) == 'X'
471 *endptr
= (WCHAR
*)&save
[-1];
473 /* There was no number to convert. */
474 *endptr
= (WCHAR
*)nptr
;
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
)
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;
506 while (isdigit(*format
)) width
= width
* 10 + *format
++ - '0';
508 if (str_len
== -1) str_len
= strlenW( str
);
512 while (isdigit(*format
)) max
= max
* 10 + *format
++ - '0';
513 if (max
> str_len
) 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
++)
531 memcpy( buffer
, str
, min( max
, len
- count
) * sizeof(WCHAR
) );
535 if (left_align
&& width
> max
)
537 for (i
= 0; i
< width
- max
; i
++)
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
;
554 while (*iter
&& *iter
!= '%')
565 *str
++ = '%'; /* "%%"->'%' */
572 while (*iter
== '0' ||
581 char *buffiter
= bufa
;
582 int fieldlen
= va_arg(valist
, int);
583 sprintf(buffiter
, "%d", fieldlen
);
585 *fmta
++ = *buffiter
++;
592 while (isdigit(*iter
))
600 char *buffiter
= bufa
;
601 int fieldlen
= va_arg(valist
, int);
602 sprintf(buffiter
, "%d", fieldlen
);
604 *fmta
++ = *buffiter
++;
608 while (isdigit(*iter
))
611 if (*iter
== 'h' || *iter
== 'l')
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;
625 count
= format_string( str
, remaining
, fmtbufa
, wstr
? wstr
: none
, -1 );
626 str
+= min( count
, remaining
);
635 size_t remaining
= written
< len
? len
- written
: 0;
638 wstr
= va_arg(valist
, int);
641 count
= format_string( str
, remaining
, fmtbufa
, &wstr
, 1 );
642 str
+= min( count
, remaining
);
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
;
654 sprintf(bufaiter
, "%0*lX", 2 * (int)sizeof(void*),
655 (unsigned long)va_arg(valist
, void *));
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));
667 /* FIXME: On 32 bit systems this doesn't handle int 64's. */
668 sprintf(bufaiter
, fmtbufa
, va_arg(valist
, void *));
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
, ...)
703 va_start(valist
, format
);
704 retval
= vsnprintfW(str
, len
, format
, valist
);
709 int sprintfW( WCHAR
*str
, const WCHAR
*format
, ...)
713 va_start(valist
, format
);
714 retval
= vsnprintfW(str
, INT_MAX
, format
, valist
);
719 #endif /* __ASM_OBSOLETE */