1 /* 2 * PROJECT: ReactOS CRT library 3 * LICENSE: LGPL - See COPYING in the top level directory 4 * FILE: lib/sdk/crt/string/wcs.c 5 * PURPOSE: wcs* CRT functions 6 * PROGRAMMERS: Wine team 7 * Ported to ReactOS by Aleksey Bragin (aleksey@reactos.org) 8 */ 9 10 /* 11 * msvcrt.dll wide-char functions 12 * 13 * Copyright 1999 Alexandre Julliard 14 * Copyright 2000 Jon Griffiths 15 * 16 * This library is free software; you can redistribute it and/or 17 * modify it under the terms of the GNU Lesser General Public 18 * License as published by the Free Software Foundation; either 19 * version 2.1 of the License, or (at your option) any later version. 20 * 21 * This library is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 * Lesser General Public License for more details. 25 * 26 * You should have received a copy of the GNU Lesser General Public 27 * License along with this library; if not, write to the Free Software 28 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 29 */ 30 #include <precomp.h> 31 #include <assert.h> 32 33 #ifndef _LIBCNT_ 34 #include <internal/wine/msvcrt.h> 35 #endif 36 37 #include "wine/unicode.h" 38 #undef sprintf 39 #undef wsprintf 40 #undef snprintf 41 #undef vsnprintf 42 #undef vprintf 43 #undef vwprintf 44 45 #ifdef _MSC_VER 46 #pragma function(_wcsset) 47 #endif 48 49 #ifndef _LIBCNT_ 50 /********************************************************************* 51 * _wcsdup (MSVCRT.@) 52 */ 53 wchar_t* CDECL _wcsdup( const wchar_t* str ) 54 { 55 wchar_t* ret = NULL; 56 if (str) 57 { 58 size_t size = (strlenW(str) + 1) * sizeof(wchar_t); 59 ret = malloc( size ); 60 if (ret) memcpy( ret, str, size ); 61 } 62 return ret; 63 } 64 /********************************************************************* 65 * _wcsicoll (MSVCRT.@) 66 */ 67 INT CDECL _wcsicoll( const wchar_t* str1, const wchar_t* str2 ) 68 { 69 /* FIXME: handle collates */ 70 return strcmpiW( str1, str2 ); 71 } 72 #endif 73 74 /********************************************************************* 75 * _wcsnset (MSVCRT.@) 76 */ 77 wchar_t* CDECL _wcsnset( wchar_t* str, wchar_t c, size_t n ) 78 { 79 wchar_t* ret = str; 80 while ((n-- > 0) && *str) *str++ = c; 81 return ret; 82 } 83 84 /********************************************************************* 85 * _wcsrev (MSVCRT.@) 86 */ 87 wchar_t* CDECL _wcsrev( wchar_t* str ) 88 { 89 wchar_t* ret = str; 90 wchar_t* end = str + strlenW(str) - 1; 91 while (end > str) 92 { 93 wchar_t t = *end; 94 *end-- = *str; 95 *str++ = t; 96 } 97 return ret; 98 } 99 100 #ifndef _LIBCNT_ 101 /********************************************************************* 102 * _wcsset (MSVCRT.@) 103 */ 104 wchar_t* CDECL _wcsset( wchar_t* str, wchar_t c ) 105 { 106 wchar_t* ret = str; 107 while (*str) *str++ = c; 108 return ret; 109 } 110 111 /****************************************************************** 112 * _wcsupr_s (MSVCRT.@) 113 * 114 */ 115 INT CDECL _wcsupr_s( wchar_t* str, size_t n ) 116 { 117 wchar_t* ptr = str; 118 119 if (!str || !n) 120 { 121 if (str) *str = '\0'; 122 _set_errno(EINVAL); 123 return EINVAL; 124 } 125 126 while (n--) 127 { 128 if (!*ptr) return 0; 129 *ptr = toupperW(*ptr); 130 ptr++; 131 } 132 133 /* MSDN claims that the function should return and set errno to 134 * ERANGE, which doesn't seem to be true based on the tests. */ 135 *str = '\0'; 136 _set_errno(EINVAL); 137 return EINVAL; 138 } 139 140 /********************************************************************* 141 * wcstod (MSVCRT.@) 142 */ 143 double CDECL wcstod(const wchar_t* lpszStr, wchar_t** end) 144 { 145 const wchar_t* str = lpszStr; 146 int negative = 0; 147 double ret = 0, divisor = 10.0; 148 149 TRACE("(%s,%p) semi-stub\n", debugstr_w(lpszStr), end); 150 151 /* FIXME: 152 * - Should set errno on failure 153 * - Should fail on overflow 154 * - Need to check which input formats are allowed 155 */ 156 while (isspaceW(*str)) 157 str++; 158 159 if (*str == '-') 160 { 161 negative = 1; 162 str++; 163 } 164 165 while (isdigitW(*str)) 166 { 167 ret = ret * 10.0 + (*str - '0'); 168 str++; 169 } 170 if (*str == '.') 171 str++; 172 while (isdigitW(*str)) 173 { 174 ret = ret + (*str - '0') / divisor; 175 divisor *= 10; 176 str++; 177 } 178 179 if (*str == 'E' || *str == 'e' || *str == 'D' || *str == 'd') 180 { 181 int negativeExponent = 0; 182 int exponent = 0; 183 if (*(++str) == '-') 184 { 185 negativeExponent = 1; 186 str++; 187 } 188 while (isdigitW(*str)) 189 { 190 exponent = exponent * 10 + (*str - '0'); 191 str++; 192 } 193 if (exponent != 0) 194 { 195 if (negativeExponent) 196 ret = ret / pow(10.0, exponent); 197 else 198 ret = ret * pow(10.0, exponent); 199 } 200 } 201 202 if (negative) 203 ret = -ret; 204 205 if (end) 206 *end = (wchar_t*)str; 207 208 TRACE("returning %g\n", ret); 209 return ret; 210 } 211 #endif 212 213 /********************************************************************* 214 * wcscoll (MSVCRT.@) 215 */ 216 int CDECL wcscoll( const wchar_t* str1, const wchar_t* str2 ) 217 { 218 /* FIXME: handle collates */ 219 return strcmpW( str1, str2 ); 220 } 221 222 /********************************************************************* 223 * wcspbrk (MSVCRT.@) 224 */ 225 wchar_t* CDECL wcspbrk( const wchar_t* str, const wchar_t* accept ) 226 { 227 const wchar_t* p; 228 while (*str) 229 { 230 for (p = accept; *p; p++) if (*p == *str) return (wchar_t*)str; 231 str++; 232 } 233 return NULL; 234 } 235 236 #ifndef _LIBCNT_ 237 238 /********************************************************************* 239 * wctomb (MSVCRT.@) 240 */ 241 /********************************************************************* 242 * wctomb (MSVCRT.@) 243 */ 244 INT CDECL wctomb( char *dst, wchar_t ch ) 245 { 246 BOOL error; 247 INT size; 248 249 size = WideCharToMultiByte(get_locinfo()->lc_codepage, 0, &ch, 1, dst, dst ? 6 : 0, NULL, &error); 250 if(!size || error) { 251 *_errno() = EINVAL; 252 return EOF; 253 } 254 return size; 255 } 256 257 /********************************************************************* 258 * wcsrtombs_l (INTERNAL) 259 */ 260 static size_t CDECL wcsrtombs_l(char *mbstr, const wchar_t **wcstr, 261 size_t count, _locale_t locale) 262 { 263 MSVCRT_pthreadlocinfo locinfo; 264 size_t tmp = 0; 265 BOOL used_default; 266 267 if(!locale) 268 locinfo = get_locinfo(); 269 else 270 locinfo = ((MSVCRT__locale_t)locale)->locinfo; 271 272 if(!locinfo->lc_codepage) { 273 size_t i; 274 275 if(!mbstr) 276 return strlenW(*wcstr); 277 278 for(i=0; i<count; i++) { 279 if((*wcstr)[i] > 255) { 280 _set_errno(EILSEQ); 281 return -1; 282 } 283 284 mbstr[i] = (*wcstr)[i]; 285 if(!(*wcstr)[i]) break; 286 } 287 return i; 288 } 289 290 if(!mbstr) { 291 tmp = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS, 292 *wcstr, -1, NULL, 0, NULL, &used_default); 293 if(!tmp || used_default) { 294 _set_errno(EILSEQ); 295 return -1; 296 } 297 return tmp-1; 298 } 299 300 while(**wcstr) { 301 char buf[3]; 302 size_t i, size; 303 304 size = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS, 305 *wcstr, 1, buf, 3, NULL, &used_default); 306 if(!size || used_default) { 307 _set_errno(EILSEQ); 308 return -1; 309 } 310 if(tmp+size > count) 311 return tmp; 312 313 for(i=0; i<size; i++) 314 mbstr[tmp++] = buf[i]; 315 (*wcstr)++; 316 } 317 318 if(tmp < count) { 319 mbstr[tmp] = '\0'; 320 *wcstr = NULL; 321 } 322 return tmp; 323 } 324 325 /********************************************************************* 326 * _wcstombs_l (MSVCRT.@) 327 */ 328 size_t CDECL _wcstombs_l(char *mbstr, const wchar_t *wcstr, size_t count, _locale_t locale) 329 { 330 return wcsrtombs_l(mbstr, &wcstr, count, locale); 331 } 332 333 /********************************************************************* 334 * wcstombs (MSVCRT.@) 335 */ 336 size_t CDECL wcstombs(char *mbstr, const wchar_t *wcstr, size_t count) 337 { 338 return wcsrtombs_l(mbstr, &wcstr, count, NULL); 339 } 340 #endif 341 342 /********************************************************************* 343 * wcscpy_s (MSVCRT.@) 344 */ 345 INT CDECL wcscpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc) 346 { 347 size_t size = 0; 348 349 if(!wcDest || !numElement) 350 return EINVAL; 351 352 wcDest[0] = 0; 353 354 if(!wcSrc) 355 { 356 return EINVAL; 357 } 358 359 size = strlenW(wcSrc) + 1; 360 361 if(size > numElement) 362 { 363 return ERANGE; 364 } 365 366 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) ); 367 368 return 0; 369 } 370 371 /****************************************************************** 372 * wcsncpy_s (MSVCRT.@) 373 */ 374 INT CDECL wcsncpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc, 375 size_t count ) 376 { 377 size_t size = 0; 378 379 if (!wcDest || !numElement) 380 return EINVAL; 381 382 wcDest[0] = 0; 383 384 if (!wcSrc) 385 { 386 return EINVAL; 387 } 388 389 size = min(strlenW(wcSrc), count); 390 391 if (size >= numElement) 392 { 393 return ERANGE; 394 } 395 396 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) ); 397 wcDest[size] = '\0'; 398 399 return 0; 400 } 401 402 /****************************************************************** 403 * wcscat_s (MSVCRT.@) 404 * 405 */ 406 INT CDECL wcscat_s(wchar_t* dst, size_t elem, const wchar_t* src) 407 { 408 wchar_t* ptr = dst; 409 410 if (!dst || elem == 0) return EINVAL; 411 if (!src) 412 { 413 dst[0] = '\0'; 414 return EINVAL; 415 } 416 417 /* seek to end of dst string (or elem if no end of string is found */ 418 while (ptr < dst + elem && *ptr != '\0') ptr++; 419 while (ptr < dst + elem) 420 { 421 if ((*ptr++ = *src++) == '\0') return 0; 422 } 423 /* not enough space */ 424 dst[0] = '\0'; 425 return ERANGE; 426 } 427 428 /********************************************************************* 429 * wcsncat_s (MSVCRT.@) 430 * 431 */ 432 INT CDECL wcsncat_s(wchar_t *dst, size_t elem, 433 const wchar_t *src, size_t count) 434 { 435 size_t srclen; 436 wchar_t dststart; 437 INT ret = 0; 438 439 if (!MSVCRT_CHECK_PMT(dst != NULL) || !MSVCRT_CHECK_PMT(elem > 0)) 440 { 441 #ifndef _LIBCNT_ 442 _set_errno(EINVAL); 443 #endif 444 return EINVAL; 445 } 446 if (!MSVCRT_CHECK_PMT(src != NULL || count == 0)) 447 return EINVAL; 448 if (count == 0) 449 return 0; 450 451 for (dststart = 0; dststart < elem; dststart++) 452 { 453 if (dst[dststart] == '\0') 454 break; 455 } 456 if (dststart == elem) 457 { 458 MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n", EINVAL); 459 return EINVAL; 460 } 461 462 if (count == _TRUNCATE) 463 { 464 srclen = strlenW(src); 465 if (srclen >= (elem - dststart)) 466 { 467 srclen = elem - dststart - 1; 468 ret = STRUNCATE; 469 } 470 } 471 else 472 srclen = min(strlenW(src), count); 473 if (srclen < (elem - dststart)) 474 { 475 memcpy(&dst[dststart], src, srclen*sizeof(wchar_t)); 476 dst[dststart+srclen] = '\0'; 477 return ret; 478 } 479 MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE); 480 dst[0] = '\0'; 481 return ERANGE; 482 } 483 484