Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539/* * Unicode string manipulation functions * * Copyright 2000 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
#include <assert.h>#include <errno.h>#include <limits.h>#include <stdio.h>
#include "wine/unicode.h"
#ifdef __REACTOS__#define min(a,b) (((a) < (b)) ? (a) : (b))#endif
int strcmpiW( const WCHAR *str1, const WCHAR *str2 ){ for (;;) { int ret = tolowerW(*str1) - tolowerW(*str2); if (ret || !*str1) return ret; str1++; str2++; }}
int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n ){ int ret = 0; for ( ; n > 0; n--, str1++, str2++) if ((ret = tolowerW(*str1) - tolowerW(*str2)) || !*str1) break; return ret;}
int memicmpW( const WCHAR *str1, const WCHAR *str2, int n ){ int ret = 0; for ( ; n > 0; n--, str1++, str2++) if ((ret = tolowerW(*str1) - tolowerW(*str2))) break; return ret;}
WCHAR *strstrW( const WCHAR *str, const WCHAR *sub ){ while (*str) { const WCHAR *p1 = str, *p2 = sub; while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; } if (!*p2) return (WCHAR *)str; str++; } return NULL;}
/* strtolW and strtoulW implementation based on the GNU C library code *//* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc. */
long int strtolW( const WCHAR *nptr, WCHAR **endptr, int base ){ int negative; register unsigned long int cutoff; register unsigned int cutlim; register unsigned long int i; register const WCHAR *s; register WCHAR c; const WCHAR *save, *end; int overflow;
if (base < 0 || base == 1 || base > 36) return 0;
save = s = nptr;
/* Skip white space. */ while (isspaceW (*s)) ++s; if (!*s) goto noconv;
/* Check for a sign. */ negative = 0; if (*s == '-') { negative = 1; ++s; } else if (*s == '+') ++s;
/* Recognize number prefix and if BASE is zero, figure it out ourselves. */ if (*s == '0') { if ((base == 0 || base == 16) && toupperW(s[1]) == 'X') { s += 2; base = 16; } else if (base == 0) base = 8; } else if (base == 0) base = 10;
/* Save the pointer so we can check later if anything happened. */ save = s; end = NULL;
cutoff = ULONG_MAX / (unsigned long int) base; cutlim = ULONG_MAX % (unsigned long int) base;
overflow = 0; i = 0; c = *s; for (;c != '\0'; c = *++s) { if (s == end) break; if (c >= '0' && c <= '9') c -= '0'; else if (isalphaW (c)) c = toupperW (c) - 'A' + 10; else break; if ((int) c >= base) break; /* Check for overflow. */ if (i > cutoff || (i == cutoff && c > cutlim)) overflow = 1; else { i *= (unsigned long int) base; i += c; } }
/* Check if anything actually happened. */ if (s == save) goto noconv;
/* Store in ENDPTR the address of one character past the last character we converted. */ if (endptr != NULL) *endptr = (WCHAR *)s;
/* Check for a value that is within the range of `unsigned LONG int', but outside the range of `LONG int'. */ if (overflow == 0 && i > (negative ? -((unsigned long int) (LONG_MIN + 1)) + 1 : (unsigned long int) LONG_MAX)) overflow = 1;
if (overflow) { errno = ERANGE; return negative ? LONG_MIN : LONG_MAX; }
/* Return the result of the appropriate sign. */ return negative ? -i : i;
noconv: /* We must handle a special case here: the base is 0 or 16 and the first two characters are '0' and 'x', but the rest are not hexadecimal digits. This is no error case. We return 0 and ENDPTR points to the `x`. */ if (endptr != NULL) { if (save - nptr >= 2 && toupperW (save[-1]) == 'X' && save[-2] == '0') *endptr = (WCHAR *)&save[-1]; else /* There was no number to convert. */ *endptr = (WCHAR *)nptr; }
return 0L;}
unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base ){ int negative; register unsigned long int cutoff; register unsigned int cutlim; register unsigned long int i; register const WCHAR *s; register WCHAR c; const WCHAR *save, *end; int overflow;
if (base < 0 || base == 1 || base > 36) return 0;
save = s = nptr;
/* Skip white space. */ while (isspaceW (*s)) ++s; if (!*s) goto noconv;
/* Check for a sign. */ negative = 0; if (*s == '-') { negative = 1; ++s; } else if (*s == '+') ++s;
/* Recognize number prefix and if BASE is zero, figure it out ourselves. */ if (*s == '0') { if ((base == 0 || base == 16) && toupperW(s[1]) == 'X') { s += 2; base = 16; } else if (base == 0) base = 8; } else if (base == 0) base = 10;
/* Save the pointer so we can check later if anything happened. */ save = s; end = NULL;
cutoff = ULONG_MAX / (unsigned long int) base; cutlim = ULONG_MAX % (unsigned long int) base;
overflow = 0; i = 0; c = *s; for (;c != '\0'; c = *++s) { if (s == end) break; if (c >= '0' && c <= '9') c -= '0'; else if (isalphaW (c)) c = toupperW (c) - 'A' + 10; else break; if ((int) c >= base) break; /* Check for overflow. */ if (i > cutoff || (i == cutoff && c > cutlim)) overflow = 1; else { i *= (unsigned long int) base; i += c; } }
/* Check if anything actually happened. */ if (s == save) goto noconv;
/* Store in ENDPTR the address of one character past the last character we converted. */ if (endptr != NULL) *endptr = (WCHAR *)s;
if (overflow) { errno = ERANGE; return ULONG_MAX; }
/* Return the result of the appropriate sign. */ return negative ? -i : i;
noconv: /* We must handle a special case here: the base is 0 or 16 and the first two characters are '0' and 'x', but the rest are not hexadecimal digits. This is no error case. We return 0 and ENDPTR points to the `x`. */ if (endptr != NULL) { if (save - nptr >= 2 && toupperW (save[-1]) == 'X' && save[-2] == '0') *endptr = (WCHAR *)&save[-1]; else /* There was no number to convert. */ *endptr = (WCHAR *)nptr; }
return 0L;}
/* format a WCHAR string according to a printf format; helper for vsnprintfW */static size_t format_string( WCHAR *buffer, size_t len, const char *format, const WCHAR *str, int str_len ){ size_t count = 0; int i, left_align = 0, width = 0, max = 0;
assert( *format == '%' ); format++; /* skip '%' */
while (*format == '0' || *format == '+' || *format == '-' || *format == ' ' || *format == '#') { if (*format == '-') left_align = 1; format++; }
while (isdigit(*format)) width = width * 10 + *format++ - '0';
if (str_len == -1) str_len = strlenW( str ); if (*format == '.') { format++; while (isdigit(*format)) max = max * 10 + *format++ - '0'; if (max > str_len) max = str_len; } else max = str_len;
if (*format == 'h' || *format == 'l') format++;
assert( *format == 's' );
if (!left_align && width > max) { for (i = 0; i < width - max; i++) { if (count++ < len) *buffer++ = ' '; } }
if (count < len) memcpy( buffer, str, min( max, len - count ) * sizeof(WCHAR) ); count += max; buffer += max;
if (left_align && width > max) { for (i = 0; i < width - max; i++) { if (count++ < len) *buffer++ = ' '; } } return count;}
int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist){ unsigned int written = 0; const WCHAR *iter = format; char bufa[512], fmtbufa[64], *fmta;
while (*iter) { while (*iter && *iter != '%') { if (written++ < len) *str++ = *iter; iter++; } if (*iter == '%') { if (iter[1] == '%') { if (written++ < len) *str++ = '%'; /* "%%"->'%' */ iter += 2; continue; }
fmta = fmtbufa; *fmta++ = *iter++; while (*iter == '0' || *iter == '+' || *iter == '-' || *iter == ' ' || *iter == '*' || *iter == '#') { if (*iter == '*') { char *buffiter = bufa; int fieldlen = va_arg(valist, int); sprintf(buffiter, "%d", fieldlen); while (*buffiter) *fmta++ = *buffiter++; } else *fmta++ = *iter; iter++; }
while (isdigit(*iter)) *fmta++ = *iter++;
if (*iter == '.') { *fmta++ = *iter++; if (*iter == '*') { char *buffiter = bufa; int fieldlen = va_arg(valist, int); sprintf(buffiter, "%d", fieldlen); while (*buffiter) *fmta++ = *buffiter++; iter++; } else while (isdigit(*iter)) *fmta++ = *iter++; } if (*iter == 'h' || *iter == 'l') *fmta++ = *iter++;
switch (*iter) { case 's': { static const WCHAR none[] = { '(','n','u','l','l',')',0 }; const WCHAR *wstr = va_arg(valist, const WCHAR *); size_t remaining = written < len ? len - written : 0; size_t count;
*fmta++ = 's'; *fmta = 0; count = format_string( str, remaining, fmtbufa, wstr ? wstr : none, -1 ); str += min( count, remaining ); written += count; iter++; break; }
case 'c': { WCHAR wstr; size_t remaining = written < len ? len - written : 0; size_t count;
wstr = va_arg(valist, int); *fmta++ = 's'; *fmta = 0; count = format_string( str, remaining, fmtbufa, &wstr, 1 ); str += min( count, remaining ); written += count; iter++; break; }
default: { /* For non wc types, use system sprintf and append to wide char output */ /* FIXME: for unrecognised types, should ignore % when printing */ char *bufaiter = bufa; if (*iter == 'p')#ifdef __REACTOS__ sprintf(bufaiter, "%p", va_arg(valist, void*));#else sprintf(bufaiter, "%0*lX", 2 * (int)sizeof(void*), (unsigned long)va_arg(valist, void *));#endif else { *fmta++ = *iter; *fmta = '\0'; if (*iter == 'a' || *iter == 'A' || *iter == 'e' || *iter == 'E' || *iter == 'f' || *iter == 'F' || *iter == 'g' || *iter == 'G') sprintf(bufaiter, fmtbufa, va_arg(valist, double)); else { /* FIXME: On 32 bit systems this doesn't handle int 64's. */ sprintf(bufaiter, fmtbufa, va_arg(valist, void *)); } } while (*bufaiter) { if (written++ < len) *str++ = *bufaiter; bufaiter++; } iter++; break; } } } } if (len) { if (written >= len) str--; *str++ = 0; }
/* FIXME: POSIX [v]snprintf() returns the equivalent of written, not -1, on short buffer. */ return written < len ? (int)written : -1;}
int vsprintfW( WCHAR *str, const WCHAR *format, va_list valist ){ return vsnprintfW( str, INT_MAX, format, valist );}
int snprintfW( WCHAR *str, size_t len, const WCHAR *format, ...){ int retval; va_list valist; va_start(valist, format); retval = vsnprintfW(str, len, format, valist); va_end(valist); return retval;}
int sprintfW( WCHAR *str, const WCHAR *format, ...){ int retval; va_list valist; va_start(valist, format); retval = vsnprintfW(str, INT_MAX, format, valist); va_end(valist); return retval;}