/* * @implemented */ int _ui64tow_s( unsigned __int64 value, wchar_t *str, size_t size, int radix ) { wchar_t buffer[65], *pos; int digit; if (!MSVCRT_CHECK_PMT(str != NULL) || !MSVCRT_CHECK_PMT(size > 0) || !MSVCRT_CHECK_PMT(radix>=2) || !MSVCRT_CHECK_PMT(radix<=36)) { #ifndef _LIBCNT_ *_errno() = EINVAL; #endif return EINVAL; } pos = &buffer[64]; *pos = '\0'; do { digit = value % radix; value = value / radix; if (digit < 10) *--pos = '0' + digit; else *--pos = 'a' + digit - 10; } while (value != 0); if((size_t)(buffer-pos+65) > size) { MSVCRT_INVALID_PMT("str[size] is too small", EINVAL); return EINVAL; } memcpy(str, pos, buffer-pos+65); return 0; }
/********************************************************************* * strncpy_s (MSVCRT.@) */ int CDECL MSVCRT_strncpy_s(char *dest, MSVCRT_size_t numberOfElements, const char *src, MSVCRT_size_t count) { MSVCRT_size_t i, end; TRACE("(%p %lu %s %lu)\n", dest, numberOfElements, debugstr_a(src), count); if(!count) { if(dest && numberOfElements) *dest = 0; return 0; } if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(numberOfElements != 0)) return MSVCRT_EINVAL; if(count!=MSVCRT__TRUNCATE && count<numberOfElements) end = count; else end = numberOfElements-1; for(i=0; i<end && src[i]; i++) dest[i] = src[i]; if(!src[i] || end==count || count==MSVCRT__TRUNCATE) { dest[i] = '\0'; return 0; } MSVCRT_INVALID_PMT("dest[numberOfElements] is too small", MSVCRT_EINVAL); dest[0] = '\0'; return MSVCRT_EINVAL; }
/********************************************************************* * strtok_s (MSVCRT.@) */ char * CDECL strtok_s(char *str, const char *delim, char **ctx) { if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL; if (!MSVCRT_CHECK_PMT(ctx != NULL)) return NULL; if (!MSVCRT_CHECK_PMT(str != NULL || *ctx != NULL)) return NULL; if(!str) str = *ctx; while(*str && strchr(delim, *str)) str++; if(!*str) { *ctx = str; return NULL; } *ctx = str+1; while(**ctx && !strchr(delim, **ctx)) (*ctx)++; if(**ctx) *(*ctx)++ = 0; return str; }
/********************************************************************* * strncpy_s (MSVCRT.@) */ int CDECL strncpy_s(char *dest, size_t numberOfElements, const char *src, size_t count) { size_t i, end; TRACE("(%s %lu %s %lu)\n", dest, numberOfElements, src, count); if(!count) return 0; if (!MSVCRT_CHECK_PMT(dest != NULL) || !MSVCRT_CHECK_PMT(src != NULL) || !MSVCRT_CHECK_PMT(numberOfElements != 0)) { *_errno() = EINVAL; return EINVAL; } if(count!=_TRUNCATE && count<numberOfElements) end = count; else end = numberOfElements-1; for(i=0; i<end && src[i]; i++) dest[i] = src[i]; if(!src[i] || end==count || count==_TRUNCATE) { dest[i] = '\0'; return 0; } MSVCRT_INVALID_PMT("dest[numberOfElements] is too small"); dest[0] = '\0'; *_errno() = EINVAL; return EINVAL; }
/********************************************************************* * _wcserror_s (MSVCRT.@) */ int CDECL MSVCRT__wcserror_s(MSVCRT_wchar_t* buffer, MSVCRT_size_t nc, int err) { if (!MSVCRT_CHECK_PMT(buffer != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(nc > 0)) return MSVCRT_EINVAL; if (err < 0 || err > MSVCRT__sys_nerr) err = MSVCRT__sys_nerr; MultiByteToWideChar(CP_ACP, 0, MSVCRT__sys_errlist[err], -1, buffer, nc); return 0; }
/********************************************************************* * wcsncat_s (MSVCRT.@) * */ INT CDECL wcsncat_s(wchar_t *dst, size_t elem, const wchar_t *src, size_t count) { size_t srclen; wchar_t dststart; INT ret = 0; if (!MSVCRT_CHECK_PMT(dst != NULL) || !MSVCRT_CHECK_PMT(elem > 0)) { #ifndef _LIBCNT_ _set_errno(EINVAL); #endif return EINVAL; } if (!MSVCRT_CHECK_PMT(src != NULL || count == 0)) return EINVAL; if (count == 0) return 0; for (dststart = 0; dststart < elem; dststart++) { if (dst[dststart] == '\0') break; } if (dststart == elem) { MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n", EINVAL); return EINVAL; } if (count == _TRUNCATE) { srclen = strlenW(src); if (srclen >= (elem - dststart)) { srclen = elem - dststart - 1; ret = STRUNCATE; } } else srclen = min(strlenW(src), count); if (srclen < (elem - dststart)) { memcpy(&dst[dststart], src, srclen*sizeof(wchar_t)); dst[dststart+srclen] = '\0'; return ret; } MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE); dst[0] = '\0'; return ERANGE; }
/********************************************************************* * memmove_s (MSVCRT.@) */ int CDECL MSVCRT_memmove_s(void *dest, MSVCRT_size_t numberOfElements, const void *src, MSVCRT_size_t count) { TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count); if(!count) return 0; if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT_ERR( count <= numberOfElements, MSVCRT_ERANGE )) return MSVCRT_ERANGE; memmove(dest, src, count); return 0; }
/* * @implemented */ int CDECL _pclose(FILE* file) { HANDLE h; DWORD i; if (!MSVCRT_CHECK_PMT(file != NULL)) return -1; _mlock(_POPEN_LOCK); for(i=0; i<popen_handles_size; i++) { if (popen_handles[i].f == file) break; } if(i == popen_handles_size) { _munlock(_POPEN_LOCK); *_errno() = EBADF; return -1; } h = popen_handles[i].proc; popen_handles[i].f = NULL; _munlock(_POPEN_LOCK); fclose(file); if(WaitForSingleObject(h, INFINITE)==WAIT_FAILED || !GetExitCodeProcess(h, &i)) { _dosmaperr(GetLastError()); CloseHandle(h); return -1; } CloseHandle(h); return i; }
/*********************************************************************** * _get_pgmptr (MSVCRT.@) */ int CDECL _get_pgmptr(char** p) { if (!MSVCRT_CHECK_PMT(p)) return MSVCRT_EINVAL; *p = MSVCRT__pgmptr; return 0; }
/*********************************************************************** * _get_fmode (MSVCRT.@) */ int CDECL MSVCRT__get_fmode(int *mode) { if(!MSVCRT_CHECK_PMT(mode)) return MSVCRT_EINVAL; *mode = MSVCRT__fmode; return 0; }
/*********************************************************************** * _set_fmode (MSVCRT.@) */ int CDECL MSVCRT__set_fmode(int mode) { /* TODO: support _O_WTEXT */ if(!MSVCRT_CHECK_PMT(mode==MSVCRT__O_TEXT || mode==MSVCRT__O_BINARY)) return MSVCRT_EINVAL; MSVCRT__fmode = mode; return 0; }
/********************************************************************* * _ctime32_s (MSVCRT.@) */ int CDECL MSVCRT__ctime32_s(char *res, MSVCRT_size_t len, const MSVCRT___time32_t *time) { struct MSVCRT_tm *t; if( !MSVCRT_CHECK_PMT( res != NULL ) || !MSVCRT_CHECK_PMT( len >= 26 ) ) { *MSVCRT__errno() = MSVCRT_EINVAL; return MSVCRT_EINVAL; } res[0] = '\0'; if( !MSVCRT_CHECK_PMT( time != NULL ) || !MSVCRT_CHECK_PMT( *time > 0 ) ) { *MSVCRT__errno() = MSVCRT_EINVAL; return MSVCRT_EINVAL; } t = MSVCRT__localtime32( time ); strcpy( res, MSVCRT_asctime( t ) ); return 0; }
/********************************************************************* * MSVCRT_wcsrtombs_s_l (INTERNAL) */ static int MSVCRT_wcsrtombs_s_l(MSVCRT_size_t *ret, char *mbstr, MSVCRT_size_t size, const MSVCRT_wchar_t **wcstr, MSVCRT_size_t count, MSVCRT__locale_t locale) { MSVCRT_size_t conv; if(!mbstr && !size && wcstr) { conv = MSVCRT_wcsrtombs_l(NULL, wcstr, 0, locale); if(ret) *ret = conv+1; return 0; } if (!MSVCRT_CHECK_PMT(wcstr != NULL) || !MSVCRT_CHECK_PMT(*wcstr != NULL) || !MSVCRT_CHECK_PMT(mbstr != NULL)) { if(mbstr && size) mbstr[0] = '\0'; *MSVCRT__errno() = MSVCRT_EINVAL; return MSVCRT_EINVAL; } if(count==MSVCRT__TRUNCATE || size<count) conv = size; else conv = count; conv = MSVCRT_wcsrtombs_l(mbstr, wcstr, conv, locale); if(conv<size) mbstr[conv++] = '\0'; else if(conv==size && (count==MSVCRT__TRUNCATE || mbstr[conv-1]=='\0')) mbstr[conv-1] = '\0'; else { MSVCRT_INVALID_PMT("mbstr[size] is too small"); if(size) mbstr[0] = '\0'; *MSVCRT__errno() = MSVCRT_ERANGE; return MSVCRT_ERANGE; } if(ret) *ret = conv; return 0; }
/********************************************************************* * _ftime32_s (MSVCRT.@) */ int CDECL MSVCRT__ftime32_s(struct MSVCRT___timeb32 *buf) { if( !MSVCRT_CHECK_PMT( buf != NULL ) ) { *MSVCRT__errno() = MSVCRT_EINVAL; return MSVCRT_EINVAL; } MSVCRT__ftime32(buf); return 0; }
/********************************************************************* * wmemmove_s (MSVCR100.@) */ int CDECL wmemmove_s(MSVCRT_wchar_t *dest, MSVCRT_size_t numberOfElements, const MSVCRT_wchar_t *src, MSVCRT_size_t count) { TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count); if (!count) return 0; /* Native does not seem to conform to 6.7.1.2.3 in * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1225.pdf * in that it does not zero the output buffer on constraint violation. */ if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(src != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, MSVCRT_ERANGE)) return MSVCRT_ERANGE; memmove(dest, src, sizeof(MSVCRT_wchar_t)*count); return 0; }
/********************************************************************* * _set_output_format (MSVCRT.@) */ unsigned int CDECL _set_output_format(unsigned int new_output_format) { unsigned int ret = output_format; if(!MSVCRT_CHECK_PMT(new_output_format==0 || new_output_format==MSVCRT__TWO_DIGIT_EXPONENT)) return ret; output_format = new_output_format; return ret; }
/********************************************************************* * qsort_s (MSVCRT.@) * * Based on NTDLL_qsort in dlls/ntdll/misc.c */ void CDECL MSVCRT_qsort_s(void *base, MSVCRT_size_t nmemb, MSVCRT_size_t size, int (CDECL *compar)(void *, const void *, const void *), void *context) { void *secondarr; const size_t total_size = nmemb*size; if (!MSVCRT_CHECK_PMT(base != NULL || (base == NULL && nmemb == 0))) return; if (!MSVCRT_CHECK_PMT(size > 0)) return; if (!MSVCRT_CHECK_PMT(compar != NULL)) return; if (total_size / size != nmemb) return; if (nmemb < 2) return; secondarr = MSVCRT_malloc(total_size); if (!secondarr) return; MSVCRT_mergesort(base, secondarr, size, compar, 0, nmemb-1, context); MSVCRT_free(secondarr); }
size_t CDECL _strxfrm_l( char *dest, const char *src, size_t len, _locale_t locale ) { MSVCRT_pthreadlocinfo locinfo; int ret; if(!MSVCRT_CHECK_PMT(src)) return INT_MAX; if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX; if(len > INT_MAX) { FIXME("len > INT_MAX not supported\n"); len = INT_MAX; } if(!locale) locinfo = get_locinfo(); else locinfo = ((MSVCRT__locale_t)locale)->locinfo; if(!locinfo->lc_handle[MSVCRT_LC_COLLATE]) { strncpy(dest, src, len); return strlen(src); } ret = LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], LCMAP_SORTKEY, src, -1, NULL, 0); if(!ret) { if(len) dest[0] = 0; *_errno() = EILSEQ; return INT_MAX; } if(!len) return ret-1; if(ret > len) { dest[0] = 0; *_errno() = ERANGE; return ret-1; } return LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], LCMAP_SORTKEY, src, -1, dest, len) - 1; }
/********************************************************************* * _strnset_s (MSVCRT.@) */ int CDECL MSVCRT__strnset_s(char *str, MSVCRT_size_t size, int c, MSVCRT_size_t count) { MSVCRT_size_t i; if(!str && !size && !count) return 0; if(!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL; if(!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL; for(i=0; i<size-1 && i<count; i++) { if(!str[i]) return 0; str[i] = c; } for(; i<size; i++) if(!str[i]) return 0; str[0] = 0; MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0); *MSVCRT__errno() = MSVCRT_EINVAL; return MSVCRT_EINVAL; }
/********************************************************************* * wcstok_s (MSVCRT.@) */ wchar_t * CDECL wcstok_s( wchar_t *str, const wchar_t *delim, wchar_t **next_token ) { wchar_t *ret; if (!MSVCRT_CHECK_PMT(delim != NULL) || !MSVCRT_CHECK_PMT(next_token != NULL) || !MSVCRT_CHECK_PMT(str != NULL || *next_token != NULL)) { _set_errno(EINVAL); return NULL; } if (!str) str = *next_token; while (*str && strchrW( delim, *str )) str++; if (!*str) return NULL; ret = str++; while (*str && !strchrW( delim, *str )) str++; if (*str) *str++ = 0; *next_token = str; return ret; }
/********************************************************************* * _aligned_msize (MSVCR100.@) */ size_t CDECL _aligned_msize(void *p, MSVCRT_size_t alignment, MSVCRT_size_t offset) { void **alloc_ptr; if(!MSVCRT_CHECK_PMT(p)) return -1; if(alignment < sizeof(void*)) alignment = sizeof(void*); alloc_ptr = SAVED_PTR(p); return _msize(*alloc_ptr)-alignment-sizeof(void*); }
/********************************************************************* * _lfind_s (MSVCRT.@) */ void* CDECL _lfind_s(const void* match, const void* start, unsigned int* array_size, unsigned int elem_size, int (CDECL *cf)(void*,const void*,const void*), void* context) { unsigned int size; if (!MSVCRT_CHECK_PMT(match != NULL)) return NULL; if (!MSVCRT_CHECK_PMT(array_size != NULL)) return NULL; if (!MSVCRT_CHECK_PMT(start != NULL || *array_size == 0)) return NULL; if (!MSVCRT_CHECK_PMT(cf != NULL)) return NULL; if (!MSVCRT_CHECK_PMT(elem_size != 0)) return NULL; size = *array_size; if (size) do { if (cf(context, match, start) == 0) return (void *)start; /* found */ start = (const char *)start + elem_size; } while (--size); return NULL; }
/********************************************************************* * wmemcpy_s (MSVCR100.@) */ int CDECL wmemcpy_s(MSVCRT_wchar_t *dest, MSVCRT_size_t numberOfElements, const MSVCRT_wchar_t *src, MSVCRT_size_t count) { TRACE("(%p %lu %p %lu)\n", dest, numberOfElements, src, count); if (!count) return 0; if (!MSVCRT_CHECK_PMT(dest != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(src != NULL)) { memset(dest, 0, numberOfElements*sizeof(MSVCRT_wchar_t)); return MSVCRT_EINVAL; } if (!MSVCRT_CHECK_PMT_ERR(count <= numberOfElements, MSVCRT_ERANGE)) { memset(dest, 0, numberOfElements*sizeof(MSVCRT_wchar_t)); return MSVCRT_ERANGE; } memcpy(dest, src, sizeof(MSVCRT_wchar_t)*count); return 0; }
/********************************************************************* * bsearch_s (msvcrt.@) */ void* CDECL MSVCRT_bsearch_s(const void *key, const void *base, MSVCRT_size_t nmemb, MSVCRT_size_t size, int (__cdecl *compare)(void *, const void *, const void *), void *ctx) { ssize_t min = 0; ssize_t max = nmemb - 1; if (!MSVCRT_CHECK_PMT(size != 0)) return NULL; if (!MSVCRT_CHECK_PMT(compare != NULL)) return NULL; while (min <= max) { ssize_t cursor = min + (max - min) / 2; int ret = compare(ctx, key,(const char *)base+(cursor*size)); if (!ret) return (char*)base+(cursor*size); if (ret < 0) max = cursor - 1; else min = cursor + 1; } return NULL; }
int __cdecl vfwprintf_s(FILE* file, const wchar_t *format, va_list argptr) { int ret; if(!MSVCRT_CHECK_PMT( file != NULL)) { _set_errno(EINVAL); return -1; } _lock_file(file); ret = wstreamout(file, format, argptr); _unlock_file(file); return ret; }
/********************************************************************* * _cputs (MSVCRT.@) */ int CDECL _cputs(const char* str) { DWORD count; int len, retval = -1; #ifdef __REACTOS__ /* r54651 */ HANDLE MSVCRT_console_out = GetStdHandle(STD_OUTPUT_HANDLE); #endif if (!MSVCRT_CHECK_PMT(str != NULL)) return -1; len = strlen(str); #ifndef __REACTOS__ /* r54651 */ LOCK_CONSOLE; #endif if (WriteConsoleA(MSVCRT_console_out, str, len, &count, NULL) && count == len) retval = 0; #ifndef __REACTOS__ /* r54651 */ UNLOCK_CONSOLE; #endif return retval; }
/********************************************************************* * _wsearchenv_s (MSVCRT.@) */ int CDECL MSVCRT__wsearchenv_s(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env, MSVCRT_wchar_t *buf, MSVCRT_size_t count) { MSVCRT_wchar_t* envVal, *penv; MSVCRT_wchar_t curPath[MAX_PATH]; if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL; *buf = '\0'; /* Try CWD first */ if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES) { if (GetFullPathNameW( file, count, buf, NULL )) return 0; msvcrt_set_errno(GetLastError()); return 0; } /* Search given environment variable */ envVal = MSVCRT__wgetenv(env); if (!envVal) { *MSVCRT__errno() = MSVCRT_ENOENT; return MSVCRT_ENOENT; } penv = envVal; TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal)); do { MSVCRT_wchar_t *end = penv; while(*end && *end != ';') end++; /* Find end of next path */ if (penv == end || !*penv) { *MSVCRT__errno() = MSVCRT_ENOENT; return MSVCRT_ENOENT; } memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t)); if (curPath[end - penv] != '/' && curPath[end - penv] != '\\') { curPath[end - penv] = '\\'; curPath[end - penv + 1] = '\0'; } else curPath[end - penv] = '\0'; strcatW(curPath, file); TRACE("Checking for file %s\n", debugstr_w(curPath)); if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES) { if (strlenW(curPath) + 1 > count) { MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE); return MSVCRT_ERANGE; } strcpyW(buf, curPath); return 0; } penv = *end ? end + 1 : end; } while(1); }
/********************************************************************* * _get_osplatform (MSVCRT.@) */ int CDECL MSVCRT__get_osplatform(int *pValue) { if (!MSVCRT_CHECK_PMT(pValue != NULL)) return MSVCRT_EINVAL; *pValue = MSVCRT__osplatform; return 0; }
/********************************************************************* * _get_osver (MSVCRT.@) */ int CDECL MSVCRT__get_osver(int* value) { if (!MSVCRT_CHECK_PMT(value != NULL)) return MSVCRT_EINVAL; *value = MSVCRT__osver; return 0; }
/********************************************************************* * _wcstod_l - not exported in native msvcrt */ double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end, MSVCRT__locale_t locale) { MSVCRT_pthreadlocinfo locinfo; unsigned __int64 d=0, hlp; unsigned fpcontrol; int exp=0, sign=1; const MSVCRT_wchar_t *p; double ret; BOOL found_digit = FALSE; if (!MSVCRT_CHECK_PMT(str != NULL)) return 0; if(!locale) locinfo = get_locinfo(); else locinfo = locale->locinfo; p = str; while(isspaceW(*p)) p++; if(*p == '-') { sign = -1; p++; } else if(*p == '+') p++; while(isdigitW(*p)) { found_digit = TRUE; hlp = d*10+*(p++)-'0'; if(d>MSVCRT_UI64_MAX/10 || hlp<d) { exp++; break; } else d = hlp; } while(isdigitW(*p)) { exp++; p++; } if(*p == *locinfo->lconv->decimal_point) p++; while(isdigitW(*p)) { found_digit = TRUE; hlp = d*10+*(p++)-'0'; if(d>MSVCRT_UI64_MAX/10 || hlp<d) break; d = hlp; exp--; } while(isdigitW(*p)) p++; if(!found_digit) { if(end) *end = (MSVCRT_wchar_t*)str; return 0.0; } if(*p=='e' || *p=='E' || *p=='d' || *p=='D') { int e=0, s=1; p++; if(*p == '-') { s = -1; p++; } else if(*p == '+') p++; if(isdigitW(*p)) { while(isdigitW(*p)) { if(e>INT_MAX/10 || (e=e*10+*p-'0')<0) e = INT_MAX; p++; } e *= s; if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN; else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX; else exp += e; } else { if(*p=='-' || *p=='+') p--; p--; } } fpcontrol = _control87(0, 0); _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff); if(exp>0) ret = (double)sign*d*pow(10, exp); else ret = (double)sign*d/pow(10, -exp); _control87(fpcontrol, 0xffffffff); if((d && ret==0.0) || isinf(ret)) *MSVCRT__errno() = MSVCRT_ERANGE; if(end) *end = (MSVCRT_wchar_t*)p; return ret; }