extern "C" errno_t __cdecl wcsrtombs_s( size_t *pRetValue, char *dst, size_t sizeInBytes, const wchar_t **src, size_t n, mbstate_t *pmbst ) { size_t retsize; if (pRetValue != NULL) { *pRetValue = -1; } /* validation section */ _VALIDATE_RETURN_ERRCODE((dst == NULL && sizeInBytes == 0) || (dst != NULL && sizeInBytes > 0), EINVAL); if (dst != NULL) { _RESET_STRING(dst, sizeInBytes); } _VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL); /* Call a non-deprecated helper to do the work. */ retsize = _wcsrtombs_helper(dst, src, (n > sizeInBytes ? sizeInBytes : n), pmbst); if (retsize == (size_t)-1) { if (dst != NULL) { _RESET_STRING(dst, sizeInBytes); } return errno; } /* count the null terminator */ retsize++; if (dst != NULL) { /* return error if the string does not fit */ if (retsize > sizeInBytes) { _RESET_STRING(dst, sizeInBytes); _VALIDATE_RETURN_ERRCODE(retsize <= sizeInBytes, ERANGE); } /* ensure the string is null terminated */ dst[retsize - 1] = '\0'; } if (pRetValue != NULL) { *pRetValue = retsize; } return 0; }
extern "C" errno_t __cdecl _wcstombs_s_l( size_t* pConvertedChars, char* dst, size_t sizeInBytes, const wchar_t* src, size_t n, _locale_t plocinfo ) { size_t retsize; errno_t retvalue = 0; /* validation section */ _VALIDATE_RETURN_ERRCODE((dst != NULL && sizeInBytes > 0) || (dst == NULL && sizeInBytes == 0), EINVAL); if (dst != NULL) { _RESET_STRING(dst, sizeInBytes); } if (pConvertedChars != NULL) { *pConvertedChars = 0; } retsize = _wcstombs_l_helper(dst, src, (n > sizeInBytes ? sizeInBytes : n), plocinfo); if (retsize == (size_t) - 1) { if (dst != NULL) { _RESET_STRING(dst, sizeInBytes); } return errno; } /* count the null terminator */ retsize++; if (dst != NULL) { /* return error if the string does not fit, unless n == _TRUNCATE */ if (retsize > sizeInBytes) { if (n != _TRUNCATE) { _RESET_STRING(dst, sizeInBytes); _VALIDATE_RETURN_ERRCODE(sizeInBytes > retsize, ERANGE); } retsize = sizeInBytes; retvalue = STRUNCATE; } /* ensure the string is null terminated */ dst[retsize - 1] = '\0'; } if (pConvertedChars != NULL) { *pConvertedChars = retsize; } return retvalue; }
errno_t __cdecl _mbscpy_s_l(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, _LOCALE_ARG_DECL) { unsigned char *p; size_t available; BOOL fIsLeadPrefix; /* validation section */ _VALIDATE_STRING(_Dst, _SizeInBytes); _VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); _LOCALE_UPDATE; if (_LOCALE_SHORTCUT_TEST) { return strcpy_s((char *)_Dst, _SizeInBytes, (const char *)_Src); } p = _Dst; available = _SizeInBytes; while ((*p++ = *_Src++) != 0 && --available > 0) { } /* * If we ran out of destination bytes then we did so before copying null. * Only exception to that is if last mbc was invalid (leadbyte+null), which * is treated as null. In that case clear the copied lead byte and return ok. */ if (available == 0) { if (*_Src == 0) { _ISMBBLEADPREFIX(fIsLeadPrefix,_Dst,p-1); if (fIsLeadPrefix) { p[-1] = 0; _RETURN_MBCS_ERROR; } } _RESET_STRING(_Dst, _SizeInBytes); _RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); } /* * Otherwise we have space left in the dst buffer and stopped copying because * we saw a null in the src. If null is part of invalid MBC (lead byte + null) * then clear the lead byte also. */ _ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, p-2); if (fIsLeadPrefix && (p - 2) >= _Dst) { p[-2] = 0; available++; _FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); _RETURN_MBCS_ERROR; } _FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); _RETURN_NO_ERROR; }
errno_t __cdecl _tctime64_s ( _TSCHAR * buffer, size_t sizeInChars, const __time64_t *timp ) { struct tm tmtemp; errno_t e; _VALIDATE_RETURN_ERRCODE( ( ( buffer != NULL ) && ( sizeInChars > 0 ) ), EINVAL ) _RESET_STRING(buffer, sizeInChars); _VALIDATE_RETURN_ERRCODE( ( timp != NULL ), EINVAL ) _VALIDATE_RETURN_ERRCODE_NOEXC( ( *timp >= 0 ), EINVAL ) e = _localtime64_s(&tmtemp, timp); if ( e == 0 ) { e = _tasctime_s(buffer, sizeInChars, &tmtemp); } return e; }
extern "C" errno_t __cdecl _mbsupr_s_l( unsigned char *string, size_t sizeInBytes, _locale_t plocinfo ) { size_t stringlen; /* validation section */ _VALIDATE_RETURN_ERRCODE((string != nullptr && sizeInBytes > 0) || (string == nullptr && sizeInBytes == 0), EINVAL); if (string == nullptr) { /* nothing to do */ return 0; } stringlen = strnlen((char *)string, sizeInBytes); if (stringlen >= sizeInBytes) { _RESET_STRING(string, sizeInBytes); _RETURN_DEST_NOT_NULL_TERMINATED(string, sizeInBytes); } _FILL_STRING(string, sizeInBytes, stringlen + 1); unsigned char *cp, *dst; _LocaleUpdate _loc_update(plocinfo); for (cp = string, dst = string; *cp; ++cp) { if ( _ismbblead_l(*cp, _loc_update.GetLocaleT()) ) { int retval; unsigned char ret[4]; if ( (retval = __acrt_LCMapStringA( _loc_update.GetLocaleT(), _loc_update.GetLocaleT()->mbcinfo->mblocalename, LCMAP_UPPERCASE, (const char *)cp, 2, (char *)ret, 2, _loc_update.GetLocaleT()->mbcinfo->mbcodepage, TRUE )) == 0 ) { errno = EILSEQ; _RESET_STRING(string, sizeInBytes); return errno; } *(dst++) = ret[0]; ++cp; if (retval > 1) { *(dst++) = ret[1]; } } else /* single byte, macro version */ *(dst++) = (unsigned char) _mbbtoupper_l(*cp, _loc_update.GetLocaleT()); } /* null terminate the string */ *dst = '\0'; return 0; }
_TCHAR* __cdecl _getts_helper( _TCHAR* string, size_t bufferSize, int earlyOutIfEOFIsFirstChar ) { int ch = 0; _TCHAR* pointer = string; _TCHAR* retval = string; _VALIDATE_RETURN((string != NULL), EINVAL, NULL); _VALIDATE_RETURN((bufferSize > 0), EINVAL, NULL); /* The C Standard states the input buffer should remain unchanged if EOF is encountered immediately. Hence we do not blank out the input buffer here */ _lock_str2(0, stdin); __try { #ifndef _UNICODE _VALIDATE_STREAM_ANSI_SETRET(stdin, EINVAL, retval, NULL); if (retval == NULL) { goto done; } #endif /* _UNICODE */ /* special case: check if the first char is EOF and treat it differently if the user requested so */ ch = _getchar_helper(); if (ch == _TEOF) { retval = NULL; if (earlyOutIfEOFIsFirstChar) { goto done; } } if (bufferSize == (size_t) - 1) { /* insecure case: no buffer size check, no debug filling */ while (ch != _T('\n') && ch != _TEOF) { *pointer++ = (_TCHAR)ch; ch = _getchar_helper(); } *pointer = 0; } else { /* secure case, check buffer size; if buffer overflow, keep on reading until /n or EOF */ size_t available = bufferSize; while (ch != _T('\n') && ch != _TEOF) { if (available > 0) { --available; *pointer++ = (_TCHAR)ch; } ch = _getchar_helper(); } if (available == 0) { _RESET_STRING(string, bufferSize); _RETURN_BUFFER_TOO_SMALL_ERROR(string, bufferSize, NULL); } *pointer = 0; _FILL_STRING(string, bufferSize, bufferSize - available + 1); } /* Common return */ done: ; } __finally { _unlock_str2(0, stdin); } return retval; }
static errno_t __cdecl _wcslwr_s_l_stat ( wchar_t * wsrc, size_t sizeInWords, _locale_t plocinfo ) { wchar_t *p; /* traverses string for C locale conversion */ wchar_t *wdst; /* wide version of string in alternate case */ int dstsize; /* size in wide chars of wdst string buffer (include null) */ errno_t e = 0; size_t stringlen; /* validation section */ _VALIDATE_RETURN_ERRCODE(wsrc != NULL, EINVAL); stringlen = wcsnlen(wsrc, sizeInWords); if (stringlen >= sizeInWords) { _RESET_STRING(wsrc, sizeInWords); _RETURN_DEST_NOT_NULL_TERMINATED(wsrc, sizeInWords); } _FILL_STRING(wsrc, sizeInWords, stringlen + 1); if ( plocinfo->locinfo->locale_name[LC_CTYPE] == NULL) { for ( p = wsrc ; *p ; p++ ) { if ( (*p >= (wchar_t)L'A') && (*p <= (wchar_t)L'Z') ) { *p -= L'A' - L'a'; } } return 0; } /* C locale */ /* Inquire size of wdst string */ if ( (dstsize = __crtLCMapStringW( plocinfo->locinfo->locale_name[LC_CTYPE], LCMAP_LOWERCASE, wsrc, -1, NULL, 0 )) == 0 ) { errno = EILSEQ; return errno; } if (sizeInWords < (size_t)dstsize) { _RESET_STRING(wsrc, sizeInWords); _RETURN_BUFFER_TOO_SMALL(wsrc, sizeInWords); } /* Allocate space for wdst */ wdst = (wchar_t *)_calloca(dstsize, sizeof(wchar_t)); if (wdst == NULL) { errno = ENOMEM; return errno; } /* Map wrc string to wide-character wdst string in alternate case */ if (__crtLCMapStringW( plocinfo->locinfo->locale_name[LC_CTYPE], LCMAP_LOWERCASE, wsrc, -1, wdst, dstsize ) != 0) { /* Copy wdst string to user string */ e = wcscpy_s(wsrc, sizeInWords, wdst); } else { e = errno = EILSEQ; } _freea(wdst); return e; }
extern "C" errno_t __cdecl _gcvt_s ( char *buf, size_t sizeInChars, double value, int ndec ) { STRFLT string; int magnitude; _CRT_DOUBLE *pdvalue = (_CRT_DOUBLE *)&value; char *str; char *stop; errno_t e; _locale_t plocinfo = NULL; _LocaleUpdate _loc_update(plocinfo); struct _strflt strfltstruct; /* temporary buffers */ char resultstring[22 /* MAX_MAN_DIGITS+1 */]; /* validation section */ _VALIDATE_RETURN_ERRCODE(buf != NULL, EINVAL); _VALIDATE_RETURN_ERRCODE(sizeInChars > 0, EINVAL); _RESET_STRING(buf, sizeInChars); _VALIDATE_RETURN_ERRCODE((size_t)ndec < sizeInChars, ERANGE); /* _cftoe and _cftof (used below) are more strict in validating sizeInChars */ /* get the magnitude of the number */ string = _fltout2( *pdvalue, &strfltstruct, resultstring, _countof(resultstring) ); magnitude = string->decpt - 1; /* output the result according to the Fortran G format as outlined in Fortran language specification */ if ( magnitude < -1 || magnitude > ndec-1 ) /* then Ew.d d = ndec */ e = _cftoe( &value, buf, sizeInChars, ndec-1, 0); else /* Fw.d where d = ndec-string->decpt */ e = _cftof( &value, buf, sizeInChars, ndec-string->decpt ); if (e == 0) { /* remove the trailing zeroes before the exponent; we don't need to check for sizeInChars */ str = buf; while (*str && *str != *__LCONV(_loc_update.GetLocaleT()->locinfo)->decimal_point) str++; if (*str++) { while (*str && *str != 'e') str++; stop = str--; while (*str == '0') str--; while (*++str = *stop++) ; } } else { errno = e; } return e; }
errno_t __cdecl _tasctime_s ( _TSCHAR *buffer, size_t sizeInChars, const struct tm *tb ) { _TSCHAR *p = buffer; int day, mon; int i; _VALIDATE_RETURN_ERRCODE( ( buffer != NULL ) && ( sizeInChars > 0 ), EINVAL ) _RESET_STRING(buffer, sizeInChars); _VALIDATE_RETURN_ERRCODE( ( sizeInChars >= _ASCBUFSIZE ), EINVAL ) _VALIDATE_RETURN_ERRCODE( ( tb != NULL ), EINVAL ) _VALIDATE_RETURN_ERRCODE( ( tb->tm_year >= 0 ), EINVAL ) // month 0 based _VALIDATE_RETURN_ERRCODE( ( ( tb->tm_mon >= 0 ) && ( tb->tm_mon <= 11 ) ), EINVAL ) // hour/min/sec 0 based _VALIDATE_RETURN_ERRCODE( ( ( tb->tm_hour >= 0 ) && ( tb->tm_hour <= 23 ) ), EINVAL ) _VALIDATE_RETURN_ERRCODE( ( ( tb->tm_min >= 0 ) && ( tb->tm_min <= 59 ) ), EINVAL ) _VALIDATE_RETURN_ERRCODE( ( ( tb->tm_sec >= 0 ) && ( tb->tm_sec <= 59 ) ), EINVAL ) // day 1 based _VALIDATE_RETURN_ERRCODE( ( ( tb->tm_mday >= 1 ) && ( // Day is in valid range for the month ( ( _days[ tb->tm_mon + 1 ] - _days[ tb->tm_mon ] ) >= tb->tm_mday ) || // Special case for Feb in a leap year ( ( IS_LEAP_YEAR( tb->tm_year + 1900 ) ) && ( tb->tm_mon == 1 ) && ( tb->tm_mday <= 29 ) ) ) ), EINVAL ) // week day 0 based _VALIDATE_RETURN_ERRCODE( ( ( tb->tm_wday >= 0 ) && ( tb->tm_wday <= 6 ) ), EINVAL ) /* copy day and month names into the buffer */ day = tb->tm_wday * 3; /* index to correct day string */ mon = tb->tm_mon * 3; /* index to correct month string */ for (i=0; i < 3; i++,p++) { *p = *(__dnames + day + i); *(p+4) = *(__mnames + mon + i); } *p = _T(' '); /* blank between day and month */ p += 4; *p++ = _T(' '); p = store_dt(p, tb->tm_mday); /* day of the month (1-31) */ *p++ = _T(' '); p = store_dt(p, tb->tm_hour); /* hours (0-23) */ *p++ = _T(':'); p = store_dt(p, tb->tm_min); /* minutes (0-59) */ *p++ = _T(':'); p = store_dt(p, tb->tm_sec); /* seconds (0-59) */ *p++ = _T(' '); p = store_dt(p, 19 + (tb->tm_year/100)); /* year (after 1900) */ p = store_dt(p, tb->tm_year%100); *p++ = _T('\n'); *p = _T('\0'); return 0; }
errno_t __cdecl _cgetws_s ( wchar_t *string, size_t sizeInWords, size_t * pSizeRead ) { ULONG oldstate; ULONG num_read; errno_t err = 0; _VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE((string != NULL), EINVAL); _VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE((sizeInWords > 0), EINVAL); _RESET_STRING(string, sizeInWords); _VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE((pSizeRead != NULL), EINVAL); _mlock(_CONIO_LOCK); /* lock the console */ __TRY /* * We need to decrement sizeInWords because ReadConsole reads as * many characters as the parameter passed, doesn't null terminate */ --sizeInWords; *pSizeRead = 0; /* * If the __console_whcar_buffer_used is set, then first fill the * buffered character and then proceed. */ if (__console_wchar_buffer_used != 0 && sizeInWords > 0) { *string++ = __console_wchar_buffer; __console_wchar_buffer = 0; --sizeInWords; (*pSizeRead)++; if (__console_wchar_buffer == L'\0') sizeInWords = 0; } /* if the user only asked for one character, we have now filled their request */ if (sizeInWords != 0) { /* * _coninpfh, the handle to the console input, is created the first * time that either _getch() or _cgets() or _kbhit() is called. */ if ( _coninpfh == -2 ) __initconin(); if ( _coninpfh != -1 ) { GetConsoleMode( (HANDLE)_coninpfh, &oldstate ); SetConsoleMode( (HANDLE)_coninpfh, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT ); // First try usual way just as _cgets if ( bUseW) { if ( !ReadConsoleW( (HANDLE)_coninpfh, (LPVOID)string, (DWORD)sizeInWords, &num_read, NULL ) ) { if ( bUseW == 2 ) { if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) bUseW = FALSE; else bUseW = TRUE; } } else { bUseW = TRUE; /* set length of string and null terminate it */ if (string[num_read - 2] == L'\r') { (*pSizeRead) += num_read - 2; string[num_read - 2] = L'\0'; } else if ( (num_read == sizeInWords) && (string[num_read - 1] == L'\r') ) { /* special case 1 - \r\n straddles the boundary */ (*pSizeRead) += num_read -1; string[num_read - 1] = L'\0'; } else if ( (num_read == 1) && (string[0] == L'\n') ) { /* special case 2 - read a single '\n'*/ string[0] = L'\0'; (*pSizeRead) += 0; } else { (*pSizeRead) += num_read; string[num_read] = L'\0'; } } } // If ReadConsoleW is not present, use ReadConsoleA and then convert // to Wide Char. if ( !bUseW) { static char AStr[BUF_MAX_LEN +1]; static int in_buff = 0, was_buff_full = 0; unsigned int Copy, Sz, consoleCP; unsigned int last_read = 0, i; consoleCP = GetConsoleCP(); do { if (!in_buff) { if ( ReadConsoleA( (HANDLE)_coninpfh, (LPVOID)AStr, BUF_MAX_LEN, &num_read, NULL) && num_read <= BUF_MAX_LEN ) { if (num_read >= 2 && AStr[num_read -2] == '\r') { AStr[num_read -2] = '\0'; } else if (num_read == BUF_MAX_LEN && AStr[num_read -1] == '\r') AStr[num_read -1] = '\0'; else if (num_read == 1 && AStr[0] == '\n') AStr[0] = '\0'; else AStr[num_read] = '\0'; } else { _dosmaperr(GetLastError()); err = errno; } } for ( i = 0; AStr[i] != '\0' && i < (BUF_MAX_LEN) && last_read < sizeInWords; i += Sz) { // Check if this character is lead byte. If yes, the size // of this character is 2. Else 1. if ( IsDBCSLeadByteEx( GetConsoleCP(), AStr[i])) Sz = 2; else Sz = 1; if ( (Copy = MultiByteToWideChar( consoleCP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, &AStr[i], Sz, &string[last_read], (int)sizeInWords - last_read))) { last_read += Copy; } } // Check if this conversion was from buffer. If yes, was // buffer fully filled when it was first read using // ReadConsoleA. If the buffer not fully filled, we don't need // to read more from buffer. This is necessary to make it // behave same as if we are reading using ReadConsoleW. if ( in_buff && i == strlen(AStr)) { in_buff = 0; if ( was_buff_full) { was_buff_full = 0; continue; } else { break; } } else if ( i < (BUF_MAX_LEN)) break; } while (last_read < sizeInWords); // We save the buffer to be used again. if ( i < strlen(AStr)) { in_buff = 1; if ( strlen(AStr) == (BUF_MAX_LEN)) was_buff_full = 1; memmove(AStr, &AStr[i], BUF_MAX_LEN +1 - i); } string[last_read] = '\0'; (*pSizeRead) += last_read; } SetConsoleMode( (HANDLE)_coninpfh, oldstate ); } else { _dosmaperr(GetLastError()); err = errno; } } __FINALLY _munlock(_CONIO_LOCK); /* unlock the console */ __END_TRY_FINALLY if (err != 0) { errno = err; } return err; }