summaryrefslogtreecommitdiff
path: root/src/pal/src/safecrt
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/safecrt')
-rw-r--r--src/pal/src/safecrt/cruntime.h98
-rw-r--r--src/pal/src/safecrt/input.inl1314
-rw-r--r--src/pal/src/safecrt/internal.h1097
-rw-r--r--src/pal/src/safecrt/internal_securecrt.h292
-rw-r--r--src/pal/src/safecrt/makepath_s.c31
-rw-r--r--src/pal/src/safecrt/mbusafecrt.c254
-rw-r--r--src/pal/src/safecrt/mbusafecrt_internal.h88
-rw-r--r--src/pal/src/safecrt/memcpy_s.c82
-rw-r--r--src/pal/src/safecrt/memmove_s.c69
-rw-r--r--src/pal/src/safecrt/output.inl1624
-rw-r--r--src/pal/src/safecrt/safecrt_input_s.c46
-rw-r--r--src/pal/src/safecrt/safecrt_output_l.c1467
-rw-r--r--src/pal/src/safecrt/safecrt_output_s.c46
-rw-r--r--src/pal/src/safecrt/safecrt_winput_s.c55
-rw-r--r--src/pal/src/safecrt/safecrt_woutput_s.c59
-rw-r--r--src/pal/src/safecrt/snprintf.c18
-rw-r--r--src/pal/src/safecrt/splitpath_s.c31
-rw-r--r--src/pal/src/safecrt/sprintf.c98
-rw-r--r--src/pal/src/safecrt/sscanf.c249
-rw-r--r--src/pal/src/safecrt/strcat_s.c33
-rw-r--r--src/pal/src/safecrt/strcpy_s.c29
-rw-r--r--src/pal/src/safecrt/strlen_s.c58
-rw-r--r--src/pal/src/safecrt/strncat_s.c31
-rw-r--r--src/pal/src/safecrt/strncpy_s.c30
-rw-r--r--src/pal/src/safecrt/strtok_s.c27
-rw-r--r--src/pal/src/safecrt/swprintf.c120
-rw-r--r--src/pal/src/safecrt/tcscat_s.inl51
-rw-r--r--src/pal/src/safecrt/tcscpy_s.inl39
-rw-r--r--src/pal/src/safecrt/tcsncat_s.inl81
-rw-r--r--src/pal/src/safecrt/tcsncpy_s.inl71
-rw-r--r--src/pal/src/safecrt/tcstok_s.inl71
-rw-r--r--src/pal/src/safecrt/tmakepath_s.inl116
-rw-r--r--src/pal/src/safecrt/tsplitpath_s.inl280
-rw-r--r--src/pal/src/safecrt/vsprintf.c268
-rw-r--r--src/pal/src/safecrt/vswprint.c282
-rw-r--r--src/pal/src/safecrt/wcscat_s.c36
-rw-r--r--src/pal/src/safecrt/wcscpy_s.c33
-rw-r--r--src/pal/src/safecrt/wcslen_s.c58
-rw-r--r--src/pal/src/safecrt/wcsncat_s.c35
-rw-r--r--src/pal/src/safecrt/wcsncpy_s.c34
-rw-r--r--src/pal/src/safecrt/wcstok_s.c27
-rw-r--r--src/pal/src/safecrt/wmakepath_s.c30
-rw-r--r--src/pal/src/safecrt/wsplitpath_s.c30
-rw-r--r--src/pal/src/safecrt/xtoa_s.c29
-rw-r--r--src/pal/src/safecrt/xtow_s.c28
-rw-r--r--src/pal/src/safecrt/xtox_s.inl450
46 files changed, 9395 insertions, 0 deletions
diff --git a/src/pal/src/safecrt/cruntime.h b/src/pal/src/safecrt/cruntime.h
new file mode 100644
index 0000000000..cdad474e53
--- /dev/null
+++ b/src/pal/src/safecrt/cruntime.h
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*cruntime.h - definitions specific to the target operating system and hardware
+*
+
+*
+*Purpose:
+* This header file contains widely used definitions specific to the
+* host operating system and hardware. It is included by every C source
+* and most every other header file.
+*
+* [Internal]
+*
+****/
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#ifndef _INC_CRUNTIME
+#define _INC_CRUNTIME
+
+#ifndef _CRTBLD
+/*
+ * This is an internal C runtime header file. It is used when building
+ * the C runtimes only. It is not to be used as a public header file.
+ */
+#error ERROR: Use of C runtime library internal header file.
+#endif /* _CRTBLD */
+
+#if defined (_SYSCRT) && defined (_WIN64)
+#define _USE_OLD_STDCPP 1
+#endif /* defined (_SYSCRT) && defined (_WIN64) */
+
+#if !defined (UNALIGNED)
+#if defined (_M_IA64) || defined (_M_AMD64)
+#define UNALIGNED __unaligned
+#else /* defined (_M_IA64) || defined (_M_AMD64) */
+#define UNALIGNED
+#endif /* defined (_M_IA64) || defined (_M_AMD64) */
+#endif /* !defined (UNALIGNED) */
+
+#ifdef _M_IX86
+/*
+ * 386/486
+ */
+#define REG1 register
+#define REG2 register
+#define REG3 register
+#define REG4
+#define REG5
+#define REG6
+#define REG7
+#define REG8
+#define REG9
+
+#elif defined (_M_IA64) || defined (_M_AMD64)
+/*
+ * IA64
+ */
+#define REG1 register
+#define REG2 register
+#define REG3 register
+#define REG4 register
+#define REG5 register
+#define REG6 register
+#define REG7 register
+#define REG8 register
+#define REG9 register
+
+#else /* defined (_M_IA64) || defined (_M_AMD64) */
+
+#pragma message ("Machine register set not defined")
+
+/*
+ * Unknown machine
+ */
+
+#define REG1
+#define REG2
+#define REG3
+#define REG4
+#define REG5
+#define REG6
+#define REG7
+#define REG8
+#define REG9
+
+#endif /* defined (_M_IA64) || defined (_M_AMD64) */
+
+/*
+ * Are the macro definitions below still needed in this file?
+ */
+
+#endif /* _INC_CRUNTIME */
diff --git a/src/pal/src/safecrt/input.inl b/src/pal/src/safecrt/input.inl
new file mode 100644
index 0000000000..eaad174ff5
--- /dev/null
+++ b/src/pal/src/safecrt/input.inl
@@ -0,0 +1,1314 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*input.c - C formatted input, used by scanf, etc.
+*
+
+*
+*Purpose:
+* defines _input() to do formatted input; called from scanf(),
+* etc. functions. This module defines _cscanf() instead when
+* CPRFLAG is defined. The file cscanf.c defines that symbol
+* and then includes this file in order to implement _cscanf().
+*
+*Note:
+* this file is included in safecrt.lib build directly, plese refer
+* to safecrt_[w]input_s.c
+*
+*******************************************************************************/
+
+
+#define ALLOW_RANGE /* enable "%[a-z]"-style scansets */
+
+
+/* temporary work-around for compiler without 64-bit support */
+
+#ifndef _INTEGRAL_MAX_BITS
+#define _INTEGRAL_MAX_BITS 64
+#endif /* _INTEGRAL_MAX_BITS */
+
+// typedef __int64_t __int64;
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define UNALIGNED
+
+#define _BEGIN_SECURE_CRT_DEPRECATION_DISABLE
+#define _END_SECURE_CRT_DEPRECATION_DISABLE
+
+#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */
+
+//#include <cruntime.h>
+//#include <stdio.h>
+//#include <ctype.h>
+//#include <cvt.h>
+//#include <conio.h>
+//#include <stdarg.h>
+//#include <string.h>
+//#include <internal.h>
+//#include <fltintrn.h>
+//#include <malloc.h>
+//#include <locale.h>
+//#include <mtdll.h>
+//#include <stdlib.h>
+//#include <setlocal.h>
+//#include <dbgint.h>
+
+//#ifndef _INC_INTERNAL_SAFECRT
+//#include <internal_securecrt.h>
+//#endif /* _INC_INTERNAL_SAFECRT */
+
+//#ifdef _MBCS
+//#undef _MBCS
+//#endif /* _MBCS */
+//#include <tchar.h>
+
+#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y )
+
+#define _istspace(x) isspace((unsigned char)x)
+
+#define _malloc_crt PAL_malloc
+#define _realloc_crt PAL_realloc
+#define _free_crt PAL_free
+
+#define _FASSIGN(flag, argument, number, dec_point, locale) _safecrt_fassign((flag), (argument), (number))
+#define _WFASSIGN(flag, argument, number, dec_point, locale) _safecrt_wfassign((flag), (argument), (number))
+
+#if defined (UNICODE)
+#define ALLOC_TABLE 1
+#else /* defined (UNICODE) */
+#define ALLOC_TABLE 0
+#endif /* defined (UNICODE) */
+
+#define HEXTODEC(chr) _hextodec(chr)
+
+#define LEFT_BRACKET ('[' | ('a' - 'A')) /* 'lowercase' version */
+
+static int __cdecl _hextodec(_TCHAR);
+#ifdef CPRFLAG
+
+#define INC() (++charcount, _inc())
+#define UN_INC(chr) (--charcount, _un_inc(chr))
+#define EAT_WHITE() _whiteout(&charcount)
+
+static int __cdecl _inc(void);
+static void __cdecl _un_inc(int);
+static int __cdecl _whiteout(int *);
+
+#else /* CPRFLAG */
+
+#define INC() (++charcount, _inc(stream))
+#define UN_INC(chr) (--charcount, _un_inc(chr, stream))
+#define EAT_WHITE() _whiteout(&charcount, stream)
+
+static int __cdecl _inc(miniFILE *);
+static void __cdecl _un_inc(int, miniFILE *);
+static int __cdecl _whiteout(int *, miniFILE *);
+
+#endif /* CPRFLAG */
+
+#ifndef _UNICODE
+#define _ISDIGIT(chr) isdigit((unsigned char)chr)
+#define _ISXDIGIT(chr) isxdigit((unsigned char)chr)
+#else /* _UNICODE */
+#define _ISDIGIT(chr) ( !(chr & 0xff00) && isdigit( ((chr) & 0x00ff) ) )
+#define _ISXDIGIT(chr) ( !(chr & 0xff00) && isxdigit( ((chr) & 0x00ff) ) )
+#endif /* _UNICODE */
+
+#define MUL10(x) ( (((x)<<2) + (x))<<1 )
+
+
+#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64
+ 0 means long long is same as long */
+
+/***
+* int __check_float_string(size_t,size_t *, _TCHAR**, _TCHAR*, int*)
+*
+* Purpose:
+* Check if there is enough space insert onemore character in the given
+* block, if not then allocate more memory.
+*
+* Return:
+* FALSE if more memory needed and the reallocation failed.
+*
+*******************************************************************************/
+
+static int __check_float_string(size_t nFloatStrUsed,
+ size_t *pnFloatStrSz,
+ _TCHAR **pFloatStr,
+ _TCHAR *floatstring,
+ int *pmalloc_FloatStrFlag)
+{
+ void *tmpPointer;
+ _ASSERTE(nFloatStrUsed<=(*pnFloatStrSz));
+ if (nFloatStrUsed==(*pnFloatStrSz))
+ {
+ size_t newSize;
+
+ // Will (*pnFloatStrSz) * 2 * sizeof(_TCHAR) overflow?
+ if ( *pnFloatStrSz > (SIZE_T_MAX / 2 / sizeof(_TCHAR)))
+ {
+ return FALSE;
+ }
+
+ newSize = *pnFloatStrSz * 2 * sizeof(_TCHAR);
+
+ if ((*pFloatStr)==floatstring)
+ {
+ if (((*pFloatStr)=(_TCHAR *)_malloc_crt(newSize))==NULL)
+ {
+ return FALSE;
+ }
+
+ (*pmalloc_FloatStrFlag)=1;
+
+ memcpy((*pFloatStr),floatstring,(*pnFloatStrSz)*sizeof(_TCHAR));
+ (*pnFloatStrSz)*=2;
+ }
+ else
+ {
+ if ((tmpPointer=(_TCHAR *)_realloc_crt((*pFloatStr), newSize))==NULL)
+ {
+ return FALSE;
+ }
+ (*pFloatStr)=(_TCHAR *)(tmpPointer);
+ (*pnFloatStrSz)*=2;
+ }
+ }
+ return TRUE;
+}
+
+
+#define ASCII 32 /* # of bytes needed to hold 256 bits */
+
+#define SCAN_SHORT 0 /* also for FLOAT */
+#define SCAN_LONG 1 /* also for DOUBLE */
+#define SCAN_L_DOUBLE 2 /* only for LONG DOUBLE */
+
+#define SCAN_NEAR 0
+#define SCAN_FAR 1
+
+#ifndef _UNICODE
+#define TABLESIZE ASCII
+#else /* _UNICODE */
+#define TABLESIZE (ASCII * 256)
+#endif /* _UNICODE */
+
+
+/***
+*int _input(stream, format, arglist), static int input(format, arglist)
+*
+*Purpose:
+* get input items (data items or literal matches) from the input stream
+* and assign them if appropriate to the items thru the arglist. this
+* function is intended for internal library use only, not for the user
+*
+* The _input entry point is for the normal scanf() functions
+* The input entry point is used when compiling for _cscanf() [CPRFLAF
+* defined] and is a static function called only by _cscanf() -- reads from
+* console.
+*
+* This code also defines _input_s, which works differently for %c, %s & %[.
+* For these, _input_s first picks up the next argument from the variable
+* argument list & uses it as the maximum size of the character array pointed
+* to by the next argument in the list.
+*
+*Entry:
+* FILE *stream - file to read from
+* char *format - format string to determine the data to read
+* arglist - list of pointer to data items
+*
+*Exit:
+* returns number of items assigned and fills in data items
+* returns EOF if error or EOF found on stream before 1st data item matched
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+ #define _INTRN_LOCALE_CONV( x ) localeconv()
+
+#ifndef _UNICODE
+ int __cdecl __tinput_s (miniFILE* stream, const _TUCHAR* format, va_list arglist)
+#else
+ int __cdecl __twinput_s (miniFILE* stream, const _TUCHAR* format, va_list arglist)
+#endif /* _UNICODE */
+{
+ _TCHAR floatstring[_CVTBUFSIZE + 1];
+ _TCHAR *pFloatStr=floatstring;
+ size_t nFloatStrUsed=0;
+ size_t nFloatStrSz=sizeof(floatstring)/sizeof(floatstring[0]);
+ int malloc_FloatStrFlag=0;
+
+ unsigned long number; /* temp hold-value */
+#if ALLOC_TABLE
+ char *table = NULL; /* which chars allowed for %[] */
+ int malloc_flag = 0; /* is "table" allocated on the heap? */
+#else /* ALLOC_TABLE */
+ char AsciiTable[TABLESIZE];
+ char *table = AsciiTable;
+#endif /* ALLOC_TABLE */
+
+#if _INTEGRAL_MAX_BITS >= 64
+ uint64_t num64 = 0LL; /* temp for 64-bit integers */
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ void *pointer=NULL; /* points to user data receptacle */
+ void *start; /* indicate non-empty string */
+
+
+#ifndef _UNICODE
+ wchar_t wctemp=L'\0';
+#endif /* _UNICODE */
+ _TUCHAR *scanptr; /* for building "table" data */
+ int ch = 0;
+ int charcount; /* total number of chars read */
+ int comchr; /* holds designator type */
+ int count; /* return value. # of assignments */
+
+ int started; /* indicate good number */
+ int width; /* width of field */
+ int widthset; /* user has specified width */
+#ifdef _SECURE_SCANF
+ size_t array_width = 0;
+ size_t original_array_width = 0;
+ int enomem = 0;
+ int format_error = FALSE;
+#endif /* _SECURE_SCANF */
+
+/* Neither coerceshort nor farone are need for the 386 */
+
+
+ char done_flag; /* general purpose loop monitor */
+ char longone; /* 0 = SHORT, 1 = LONG, 2 = L_DOUBLE */
+#if _INTEGRAL_MAX_BITS >= 64
+ int integer64; /* 1 for 64-bit integer, 0 otherwise */
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ signed char widechar; /* -1 = char, 0 = ????, 1 = wchar_t */
+ char reject; /* %[^ABC] instead of %[ABC] */
+ char negative; /* flag for '-' detected */
+ char suppress; /* don't assign anything */
+ char match; /* flag: !0 if any fields matched */
+ va_list arglistsave; /* save arglist value */
+
+ char fl_wchar_arg; /* flags wide char/string argument */
+
+ _TCHAR decimal;
+
+
+ _TUCHAR rngch;
+ _TUCHAR last;
+ _TUCHAR prevchar;
+ _TCHAR tch;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+#ifndef CPRFLAG
+ _VALIDATE_RETURN( (stream != NULL), EINVAL, EOF);
+#endif /* CPRFLAG */
+
+ /*
+ count = # fields assigned
+ charcount = # chars read
+ match = flag indicating if any fields were matched
+
+ [Note that we need both count and match. For example, a field
+ may match a format but have assignments suppressed. In this case,
+ match will get set, but 'count' will still equal 0. We need to
+ distinguish 'match vs no-match' when terminating due to EOF.]
+ */
+
+ count = charcount = match = 0;
+
+ while (*format) {
+
+ if (_istspace((_TUCHAR)*format)) {
+
+ UN_INC(EAT_WHITE()); /* put first non-space char back */
+
+ do {
+ tch = *++format;
+ } while (_istspace((_TUCHAR)tch));
+
+ continue;
+
+ }
+
+ if (_T('%') == *format) {
+
+ number = 0;
+ prevchar = 0;
+ width = widthset = started = 0;
+#ifdef _SECURE_SCANF
+ original_array_width = array_width = 0;
+ enomem = 0;
+#endif /* _SECURE_SCANF */
+ fl_wchar_arg = done_flag = suppress = negative = reject = 0;
+ widechar = 0;
+
+ longone = 1;
+
+#if _INTEGRAL_MAX_BITS >= 64
+ integer64 = 0;
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ while (!done_flag) {
+
+ comchr = *++format;
+ if (_ISDIGIT((_TUCHAR)comchr)) {
+ ++widthset;
+ width = MUL10(width) + (comchr - _T('0'));
+ } else
+ switch (comchr) {
+ case _T('F') :
+ case _T('N') : /* no way to push NEAR in large model */
+ break; /* NEAR is default in small model */
+ case _T('h') :
+ /* set longone to 0 */
+ --longone;
+ --widechar; /* set widechar = -1 */
+ break;
+
+#if _INTEGRAL_MAX_BITS >= 64
+ case _T('I'):
+ if ( (*(format + 1) == _T('6')) &&
+ (*(format + 2) == _T('4')) )
+ {
+ format += 2;
+ ++integer64;
+ num64 = 0;
+ break;
+ }
+ else if ( (*(format + 1) == _T('3')) &&
+ (*(format + 2) == _T('2')) )
+ {
+ format += 2;
+ break;
+ }
+ else if ( (*(format + 1) == _T('d')) ||
+ (*(format + 1) == _T('i')) ||
+ (*(format + 1) == _T('o')) ||
+ (*(format + 1) == _T('x')) ||
+ (*(format + 1) == _T('X')) )
+ {
+ if (sizeof(void*) == sizeof(__int64))
+ {
+ ++integer64;
+ num64 = 0;
+ }
+ break;
+ }
+ if (sizeof(void*) == sizeof(__int64))
+ {
+ ++integer64;
+ num64 = 0;
+ }
+ goto DEFAULT_LABEL;
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ case _T('L') :
+ /* ++longone; */
+ ++longone;
+ break;
+
+ case _T('q'):
+ ++integer64;
+ num64 = 0;
+ break;
+
+ case _T('l') :
+ if (*(format + 1) == _T('l'))
+ {
+ ++format;
+#ifdef LONGLONG_IS_INT64
+ ++integer64;
+ num64 = 0;
+ break;
+#else /* LONGLONG_IS_INT64 */
+ ++longone;
+ /* NOBREAK */
+#endif /* LONGLONG_IS_INT64 */
+ }
+ else
+ {
+ ++longone;
+ /* NOBREAK */
+ }
+ case _T('w') :
+ ++widechar; /* set widechar = 1 */
+ break;
+
+ case _T('*') :
+ ++suppress;
+ break;
+
+ default:
+DEFAULT_LABEL:
+ ++done_flag;
+ break;
+ }
+ }
+
+ if (!suppress) {
+ va_copy(arglistsave, arglist);
+ pointer = va_arg(arglist,void *);
+ } else {
+ pointer = NULL; // doesn't matter what value we use here - we're only using it as a flag
+ }
+
+ done_flag = 0;
+
+ if (!widechar) { /* use case if not explicitly specified */
+ if ((*format == _T('S')) || (*format == _T('C')))
+#ifdef _UNICODE
+ --widechar;
+ else
+ ++widechar;
+#else /* _UNICODE */
+ ++widechar;
+ else
+ --widechar;
+#endif /* _UNICODE */
+ }
+
+ /* switch to lowercase to allow %E,%G, and to
+ keep the switch table small */
+
+ comchr = *format | (_T('a') - _T('A'));
+
+ if (_T('n') != comchr)
+ {
+ if (_T('c') != comchr && LEFT_BRACKET != comchr)
+ ch = EAT_WHITE();
+ else
+ ch = INC();
+ }
+
+ if (_T('n') != comchr)
+ {
+ if (_TEOF == ch)
+ goto error_return;
+ }
+
+ if (!widthset || width) {
+
+#ifdef _SECURE_SCANF
+ if(!suppress && (comchr == _T('c') || comchr == _T('s') || comchr == LEFT_BRACKET)) {
+
+ va_copy(arglist, arglistsave);
+
+ /* Reinitialize pointer to point to the array to which we write the input */
+ pointer = va_arg(arglist, void*);
+
+ va_copy(arglistsave, arglist);
+
+ /* Get the next argument - size of the array in characters */
+#ifdef _WIN64
+ original_array_width = array_width = (size_t)(va_arg(arglist, unsigned int));
+#else /* _WIN64 */
+ original_array_width = array_width = va_arg(arglist, size_t);
+#endif /* _WIN64 */
+
+ if(array_width < 1) {
+ if (widechar > 0)
+ *(wchar_t UNALIGNED *)pointer = L'\0';
+ else
+ *(char *)pointer = '\0';
+
+ errno = ENOMEM;
+
+ goto error_return;
+ }
+ }
+#endif /* _SECURE_SCANF */
+ switch(comchr) {
+
+ case _T('c'):
+ /* case _T('C'): */
+ if (!widthset) {
+ ++widthset;
+ ++width;
+ }
+ if (widechar > 0)
+ fl_wchar_arg++;
+ goto scanit;
+
+
+ case _T('s'):
+ /* case _T('S'): */
+ if(widechar > 0)
+ fl_wchar_arg++;
+ goto scanit;
+
+
+ case LEFT_BRACKET : /* scanset */
+ if (widechar>0)
+ fl_wchar_arg++;
+ scanptr = (_TUCHAR *)(++format);
+
+ if (_T('^') == *scanptr) {
+ ++scanptr;
+ --reject; /* set reject to 255 */
+ }
+
+ /* Allocate "table" on first %[] spec */
+#if ALLOC_TABLE
+ if (table == NULL) {
+ table = (char*)_malloc_crt(TABLESIZE);
+ if ( table == NULL)
+ goto error_return;
+ malloc_flag = 1;
+ }
+#endif /* ALLOC_TABLE */
+ memset(table, 0, TABLESIZE);
+
+
+ if (LEFT_BRACKET == comchr)
+ if (_T(']') == *scanptr) {
+ prevchar = _T(']');
+ ++scanptr;
+
+ table[ _T(']') >> 3] = 1 << (_T(']') & 7);
+
+ }
+
+ while (_T(']') != *scanptr) {
+
+ rngch = *scanptr++;
+
+ if (_T('-') != rngch ||
+ !prevchar || /* first char */
+ _T(']') == *scanptr) /* last char */
+
+ table[(prevchar = rngch) >> 3] |= 1 << (rngch & 7);
+
+ else { /* handle a-z type set */
+
+ rngch = *scanptr++; /* get end of range */
+
+ if (prevchar < rngch) /* %[a-z] */
+ last = rngch;
+ else { /* %[z-a] */
+ last = prevchar;
+ prevchar = rngch;
+ }
+ for (rngch = prevchar; rngch <= last; ++rngch)
+ table[rngch >> 3] |= 1 << (rngch & 7);
+
+ prevchar = 0;
+
+ }
+ }
+
+
+ if (!*scanptr)
+ goto error_return; /* trunc'd format string */
+
+ /* scanset completed. Now read string */
+
+ if (LEFT_BRACKET == comchr)
+ format = scanptr;
+
+scanit:
+ start = pointer;
+
+ /*
+ * execute the format directive. that is, scan input
+ * characters until the directive is fulfilled, eof
+ * is reached, or a non-matching character is
+ * encountered.
+ *
+ * it is important not to get the next character
+ * unless that character needs to be tested! other-
+ * wise, reads from line-buffered devices (e.g.,
+ * scanf()) would require an extra, spurious, newline
+ * if the first newline completes the current format
+ * directive.
+ */
+ UN_INC(ch);
+
+#ifdef _SECURE_SCANF
+ /* One element is needed for '\0' for %s & %[ */
+ if(comchr != _T('c')) {
+ --array_width;
+ }
+#endif /* _SECURE_SCANF */
+ while ( !widthset || width-- ) {
+
+ ch = INC();
+ if (
+#ifndef CPRFLAG
+ (_TEOF != ch) &&
+#endif /* CPRFLAG */
+ // char conditions
+ ( ( comchr == _T('c')) ||
+ // string conditions !isspace()
+ ( ( comchr == _T('s') &&
+ (!(ch >= _T('\t') && ch <= _T('\r')) &&
+ ch != _T(' ')))) ||
+ // BRACKET conditions
+ ( (comchr == LEFT_BRACKET) &&
+ ((table[ch >> 3] ^ reject) & (1 << (ch & 7)))
+ )
+ )
+ )
+ {
+ if (!suppress) {
+#ifdef _SECURE_SCANF
+ if(!array_width) {
+ /* We have exhausted the user's buffer */
+
+ enomem = 1;
+ break;
+ }
+#endif /* _SECURE_SCANF */
+#ifndef _UNICODE
+ if (fl_wchar_arg) {
+ wctemp = L'?';
+ char temp[2];
+ temp[0] = (char) ch;
+#if 0 // we are not supporting multibyte input strings
+ if (isleadbyte((unsigned char)ch))
+ {
+ temp[1] = (char) INC();
+ }
+#endif /* 0 */
+ _MBTOWC(&wctemp, temp, MB_CUR_MAX);
+ *(wchar_t UNALIGNED *)pointer = wctemp;
+ /* just copy L'?' if mbtowc fails, errno is set by mbtowc */
+ pointer = (wchar_t *)pointer + 1;
+#ifdef _SECURE_SCANF
+ --array_width;
+#endif /* _SECURE_SCANF */
+ } else
+#else /* _UNICODE */
+ if (fl_wchar_arg) {
+ *(wchar_t UNALIGNED *)pointer = ch;
+ pointer = (wchar_t *)pointer + 1;
+#ifdef _SECURE_SCANF
+ --array_width;
+#endif /* _SECURE_SCANF */
+ } else
+#endif /* _UNICODE */
+ {
+#ifndef _UNICODE
+ *(char *)pointer = (char)ch;
+ pointer = (char *)pointer + 1;
+#ifdef _SECURE_SCANF
+ --array_width;
+#endif /* _SECURE_SCANF */
+#else /* _UNICODE */
+ int temp = 0;
+#ifndef _SECURE_SCANF
+ /* convert wide to multibyte */
+ if (_ERRCHECK_EINVAL_ERANGE(wctomb_s(&temp, (char *)pointer, MB_LEN_MAX, ch)) == 0)
+ {
+ /* do nothing if wctomb fails, errno will be set to EILSEQ */
+ pointer = (char *)pointer + temp;
+ }
+#else /* _SECURE_SCANF */
+ /* convert wide to multibyte */
+ if (array_width >= ((size_t)MB_CUR_MAX))
+ {
+_BEGIN_SECURE_CRT_DEPRECATION_DISABLE
+ temp = wctomb((char *)pointer, ch);
+_END_SECURE_CRT_DEPRECATION_DISABLE
+ }
+ else
+ {
+ char tmpbuf[MB_LEN_MAX];
+_BEGIN_SECURE_CRT_DEPRECATION_DISABLE
+ temp = wctomb(tmpbuf, ch);
+_END_SECURE_CRT_DEPRECATION_DISABLE
+ if (temp > 0 && ((size_t)temp) > array_width)
+ {
+ /* We have exhausted the user's buffer */
+ enomem = 1;
+ break;
+ }
+ memcpy(pointer, tmpbuf, temp);
+ }
+ if (temp > 0)
+ {
+ /* do nothing if wctomb fails, errno will be set to EILSEQ */
+ pointer = (char *)pointer + temp;
+ array_width -= temp;
+ }
+#endif /* _SECURE_SCANF */
+#endif /* _UNICODE */
+ }
+ } /* suppress */
+ else {
+ /* just indicate a match */
+ start = (_TCHAR *)start + 1;
+ }
+ }
+ else {
+ UN_INC(ch);
+ break;
+ }
+ }
+
+ /* make sure something has been matched and, if
+ assignment is not suppressed, null-terminate
+ output string if comchr != c */
+
+#ifdef _SECURE_SCANF
+ if(enomem) {
+ errno = ENOMEM;
+ /* In case of error, blank out the input buffer */
+ if (fl_wchar_arg)
+ {
+ _RESET_STRING(((wchar_t UNALIGNED *)start), original_array_width);
+ }
+ else
+ {
+ _RESET_STRING(((char *)start), original_array_width);
+ }
+
+ goto error_return;
+ }
+#endif /* _SECURE_SCANF */
+
+ if (start != pointer) {
+ if (!suppress) {
+ ++count;
+ if ('c' != comchr) /* null-terminate strings */
+ {
+ if (fl_wchar_arg)
+ {
+ *(wchar_t UNALIGNED *)pointer = L'\0';
+#ifdef _SECURE_SCANF
+ _FILL_STRING(((wchar_t UNALIGNED *)start), original_array_width,
+ ((wchar_t UNALIGNED *)pointer - (wchar_t UNALIGNED *)start + 1))
+#endif /* _SECURE_SCANF */
+ }
+ else
+ {
+ *(char *)pointer = '\0';
+#ifdef _SECURE_SCANF
+ _FILL_STRING(((char *)start), original_array_width,
+ ((char *)pointer - (char *)start + 1))
+#endif /* _SECURE_SCANF */
+ }
+ }
+ }
+ else
+ {
+ // supress set, do nothing
+ }
+ }
+ else
+ goto error_return;
+
+ break;
+
+ case _T('i') : /* could be d, o, or x */
+
+ comchr = _T('d'); /* use as default */
+
+ case _T('x'):
+
+ if (_T('-') == ch) {
+ ++negative;
+
+ goto x_incwidth;
+
+ } else if (_T('+') == ch) {
+x_incwidth:
+ if (!--width && widthset)
+ ++done_flag;
+ else
+ ch = INC();
+ }
+
+ if (_T('0') == ch) {
+
+ if (_T('x') == (_TCHAR)(ch = INC()) || _T('X') == (_TCHAR)ch) {
+ ch = INC();
+ if (widthset) {
+ width -= 2;
+ if (width < 1)
+ ++done_flag;
+ }
+ comchr = _T('x');
+ } else {
+ ++started;
+ if (_T('x') != comchr) {
+ if (widthset && !--width)
+ ++done_flag;
+ comchr = _T('o');
+ }
+ else {
+ /* scanning a hex number that starts */
+ /* with a 0. push back the character */
+ /* currently in ch and restore the 0 */
+ UN_INC(ch);
+ ch = _T('0');
+ }
+ }
+ }
+ goto getnum;
+
+ /* NOTREACHED */
+
+ case _T('p') :
+ /* force %hp to be treated as %p */
+ longone = 1;
+#ifdef _WIN64
+ /* force %p to be 64 bit in WIN64 */
+ ++integer64;
+ num64 = 0;
+#endif /* _WIN64 */
+ case _T('o') :
+ case _T('u') :
+ case _T('d') :
+
+ if (_T('-') == ch) {
+ ++negative;
+
+ goto d_incwidth;
+
+ } else if (_T('+') == ch) {
+d_incwidth:
+ if (!--width && widthset)
+ ++done_flag;
+ else
+ ch = INC();
+ }
+
+getnum:
+#if _INTEGRAL_MAX_BITS >= 64
+ if ( integer64 ) {
+
+ while (!done_flag) {
+
+ if (_T('x') == comchr || _T('p') == comchr)
+
+ if (_ISXDIGIT(ch)) {
+ num64 <<= 4;
+ ch = _hextodec(ch);
+ }
+ else
+ ++done_flag;
+
+ else if (_ISDIGIT(ch))
+
+ if (_T('o') == comchr)
+ if (_T('8') > ch)
+ num64 <<= 3;
+ else {
+ ++done_flag;
+ }
+ else /* _T('d') == comchr */
+ num64 = MUL10(num64);
+
+ else
+ ++done_flag;
+
+ if (!done_flag) {
+ ++started;
+ num64 += ch - _T('0');
+
+ if (widthset && !--width)
+ ++done_flag;
+ else
+ ch = INC();
+ } else
+ UN_INC(ch);
+
+ } /* end of WHILE loop */
+
+ if (negative)
+ num64 = (uint64_t )(-(__int64)num64);
+ }
+ else {
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ while (!done_flag) {
+
+ if (_T('x') == comchr || _T('p') == comchr)
+
+ if (_ISXDIGIT(ch)) {
+ number = (number << 4);
+ ch = _hextodec(ch);
+ }
+ else
+ ++done_flag;
+
+ else if (_ISDIGIT(ch))
+
+ if (_T('o') == comchr)
+ if (_T('8') > ch)
+ number = (number << 3);
+ else {
+ ++done_flag;
+ }
+ else /* _T('d') == comchr */
+ number = MUL10(number);
+
+ else
+ ++done_flag;
+
+ if (!done_flag) {
+ ++started;
+ number += ch - _T('0');
+
+ if (widthset && !--width)
+ ++done_flag;
+ else
+ ch = INC();
+ } else
+ UN_INC(ch);
+
+ } /* end of WHILE loop */
+
+ if (negative)
+ number = (unsigned long)(-(long)number);
+#if _INTEGRAL_MAX_BITS >= 64
+ }
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ if (_T('F')==comchr) /* expected ':' in long pointer */
+ started = 0;
+
+ if (started)
+ if (!suppress) {
+
+ ++count;
+assign_num:
+#if _INTEGRAL_MAX_BITS >= 64
+ if ( integer64 )
+ *(__int64 UNALIGNED *)pointer = ( uint64_t )num64;
+ else
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ if (longone)
+ *(int UNALIGNED *)pointer = (unsigned int)number;
+ else
+ *(short UNALIGNED *)pointer = (unsigned short)number;
+
+ } else /*NULL*/;
+ else
+ goto error_return;
+
+ break;
+
+ case _T('n') : /* char count, don't inc return value */
+ number = charcount;
+ if(!suppress)
+ goto assign_num; /* found in number code above */
+ break;
+
+
+ case _T('e') :
+ /* case _T('E') : */
+ case _T('f') :
+ case _T('g') : /* scan a float */
+ /* case _T('G') : */
+ nFloatStrUsed=0;
+
+ if (_T('-') == ch) {
+ pFloatStr[nFloatStrUsed++] = _T('-');
+ goto f_incwidth;
+
+ } else if (_T('+') == ch) {
+f_incwidth:
+ --width;
+ ch = INC();
+ }
+
+ if (!widthset) /* must watch width */
+ width = -1;
+
+
+ /* now get integral part */
+
+ while (_ISDIGIT(ch) && width--) {
+ ++started;
+ pFloatStr[nFloatStrUsed++] = (char)ch;
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+ ch = INC();
+ }
+
+#ifdef _UNICODE
+ /* convert decimal point to wide-char */
+ /* if mbtowc fails (should never happen), we use L'.' */
+ decimal = L'.';
+ _MBTOWC(&decimal, _INTRN_LOCALE_CONV(_loc_update)->decimal_point, MB_CUR_MAX);
+#else /* _UNICODE */
+
+ decimal=*((_INTRN_LOCALE_CONV(_loc_update))->decimal_point);
+#endif /* _UNICODE */
+
+ /* now check for decimal */
+ if (decimal == (char)ch && width--) {
+ ch = INC();
+ pFloatStr[nFloatStrUsed++] = decimal;
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+
+ while (_ISDIGIT(ch) && width--) {
+ ++started;
+ pFloatStr[nFloatStrUsed++] = (_TCHAR)ch;
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+ ch = INC();
+ }
+ }
+
+ /* now check for exponent */
+
+ if (started && (_T('e') == ch || _T('E') == ch) && width--) {
+ pFloatStr[nFloatStrUsed++] = _T('e');
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+
+ if (_T('-') == (ch = INC())) {
+
+ pFloatStr[nFloatStrUsed++] = _T('-');
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+ goto f_incwidth2;
+
+ } else if (_T('+') == ch) {
+f_incwidth2:
+ if (!width--)
+ ++width;
+ else
+ ch = INC();
+ }
+
+
+ while (_ISDIGIT(ch) && width--) {
+ ++started;
+ pFloatStr[nFloatStrUsed++] = (_TCHAR)ch;
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+ ch = INC();
+ }
+
+ }
+
+ UN_INC(ch);
+
+ if (started)
+ if (!suppress) {
+ ++count;
+ pFloatStr[nFloatStrUsed]= _T('\0');
+#ifdef _UNICODE
+ _WFASSIGN( longone-1, pointer, pFloatStr, (char)decimal, _loc_update.GetLocaleT());
+#else /* _UNICODE */
+ _FASSIGN( longone-1, pointer, pFloatStr, (char)decimal, _loc_update.GetLocaleT());
+#endif /* _UNICODE */
+ } else /*NULL */;
+ else
+ goto error_return;
+
+ break;
+
+
+ default: /* either found '%' or something else */
+
+ if ((int)*format != (int)ch) {
+ UN_INC(ch);
+#ifdef _SECURE_SCANF
+ /* error_return ASSERT's if format_error is true */
+ format_error = TRUE;
+#endif /* _SECURE_SCANF */
+ goto error_return;
+ }
+ else
+ match--; /* % found, compensate for inc below */
+
+ if (!suppress)
+ va_copy(arglist, arglistsave);
+
+ } /* SWITCH */
+
+ match++; /* matched a format field - set flag */
+
+ } /* WHILE (width) */
+
+ else { /* zero-width field in format string */
+ UN_INC(ch); /* check for input error */
+ goto error_return;
+ }
+
+ ++format; /* skip to next char */
+
+ } else /* ('%' != *format) */
+ {
+
+ if ((int)*format++ != (int)(ch = INC()))
+ {
+ UN_INC(ch);
+ goto error_return;
+ }
+#if 0 // we are not supporting multibyte input strings
+#ifndef _UNICODE
+ if (isleadbyte((unsigned char)ch))
+ {
+ int ch2;
+ if ((int)*format++ != (ch2=INC()))
+ {
+ UN_INC(ch2);
+ UN_INC(ch);
+ goto error_return;
+ }
+
+ --charcount; /* only count as one character read */
+ }
+#endif /* _UNICODE */
+#endif
+ }
+
+#ifndef CPRFLAG
+ if ( (_TEOF == ch) && ((*format != _T('%')) || (*(format + 1) != _T('n'))) )
+ break;
+#endif /* CPRFLAG */
+
+ } /* WHILE (*format) */
+
+error_return:
+#if ALLOC_TABLE
+ if (malloc_flag == 1)
+ {
+ _free_crt(table);
+ }
+#endif /* ALLOC_TABLE */
+ if (malloc_FloatStrFlag == 1)
+ {
+ _free_crt(pFloatStr);
+ }
+
+#ifndef CPRFLAG
+ if (_TEOF == ch)
+ /* If any fields were matched or assigned, return count */
+ return ( (count || match) ? count : EOF);
+ else
+#endif /* CPRFLAG */
+#ifdef _SECURE_SCANF
+ if(format_error == TRUE) {
+ _VALIDATE_RETURN( ("Invalid Input Format" && 0), EINVAL, count);
+ }
+#endif /* _SECURE_SCANF */
+ return count;
+
+}
+
+/* _hextodec() returns a value of 0-15 and expects a char 0-9, a-f, A-F */
+/* _inc() is the one place where we put the actual getc code. */
+/* _whiteout() returns the first non-blank character, as defined by isspace() */
+
+static int __cdecl _hextodec ( _TCHAR chr)
+{
+ return _ISDIGIT(chr) ? chr : (chr & ~(_T('a') - _T('A'))) - _T('A') + 10 + _T('0');
+}
+
+#ifdef CPRFLAG
+
+static int __cdecl _inc(void)
+{
+ return (_gettche_nolock());
+}
+
+static void __cdecl _un_inc(int chr)
+{
+ if (_TEOF != chr) {
+ _ungettch_nolock(chr);
+ }
+}
+
+static int __cdecl _whiteout(REG1 int* counter)
+{
+ REG2 int ch;
+
+ do
+ {
+ ++*counter;
+ ch = _inc();
+
+ if (ch == _TEOF)
+ {
+ break;
+ }
+ }
+ while(_istspace((_TUCHAR)ch));
+ return ch;
+}
+
+#else /* CPRFLAG */
+
+static int __cdecl _inc(miniFILE* fileptr)
+{
+ return (_gettc_nolock(fileptr));
+}
+
+static void __cdecl _un_inc(int chr, miniFILE* fileptr)
+{
+ if (_TEOF != chr) {
+ _ungettc_nolock(chr,fileptr);
+ }
+}
+
+static int __cdecl _whiteout(int* counter, miniFILE* fileptr)
+{
+ int ch;
+
+ do
+ {
+ ++*counter;
+ ch = _inc(fileptr);
+
+ if (ch == _TEOF)
+ {
+ break;
+ }
+ }
+ while(_istspace((_TUCHAR)ch));
+ return ch;
+}
+
+#endif /* CPRFLAG */
diff --git a/src/pal/src/safecrt/internal.h b/src/pal/src/safecrt/internal.h
new file mode 100644
index 0000000000..f4220c2b68
--- /dev/null
+++ b/src/pal/src/safecrt/internal.h
@@ -0,0 +1,1097 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*internal.h - contains declarations of internal routines and variables
+*
+
+*
+*Purpose:
+* Declares routines and variables used internally by the C run-time.
+*
+* [Internal]
+*
+****/
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#ifndef _INC_INTERNAL
+#define _INC_INTERNAL
+
+#include <crtdefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <cruntime.h>
+#include <limits.h>
+
+/*
+ * Conditionally include windows.h to pick up the definition of
+ * CRITICAL_SECTION.
+ */
+#include <windows.h>
+
+#ifdef _MSC_VER
+#pragma pack(push,_CRT_PACKING)
+#endif /* _MSC_VER */
+
+/* Define function types used in several startup sources */
+
+typedef void (__cdecl *_PVFV)(void);
+typedef int (__cdecl *_PIFV)(void);
+typedef void (__cdecl *_PVFI)(int);
+
+#if _MSC_VER >= 1400 && defined(_M_CEE)
+typedef const void* (__clrcall *_PVFVM)(void);
+typedef int (__clrcall *_PIFVM)(void);
+typedef void (__clrcall *_CPVFV)(void);
+#endif /* _MSC_VER >= 1400 && defined(_M_CEE) */
+
+#if defined (_M_CEE_PURE) || (defined (_DLL) && defined (_M_IX86))
+/* Retained for compatibility with VC++ 5.0 and earlier versions */
+_CRTIMP int * __cdecl __p__commode(void);
+#endif /* defined (_M_CEE_PURE) || (defined (_DLL) && defined (_M_IX86)) */
+#if defined (SPECIAL_CRTEXE) && defined (_DLL)
+ extern int _commode;
+#else /* defined (SPECIAL_CRTEXE) && defined (_DLL) */
+#ifndef _M_CEE_PURE
+_CRTIMP extern int _commode;
+#else /* _M_CEE_PURE */
+#define _commode (*__p___commode())
+#endif /* _M_CEE_PURE */
+#endif /* defined (SPECIAL_CRTEXE) && defined (_DLL) */
+
+#define __IOINFO_TM_ANSI 0 /* Regular Text */
+#define __IOINFO_TM_UTF8 1 /* UTF8 Encoded */
+#define __IOINFO_TM_UTF16LE 2 /* UTF16 Little Endian Encoded */
+
+/*
+ * Control structure for lowio file handles
+ */
+typedef struct {
+ intptr_t osfhnd; /* underlying OS file HANDLE */
+ char osfile; /* attributes of file (e.g., open in text mode?) */
+ char pipech; /* one char buffer for handles opened on pipes */
+ int lockinitflag;
+ CRITICAL_SECTION lock;
+#ifndef _SAFECRT_IMPL
+ /* Not used in the safecrt downlevel. We do not define them, so we cannot use them accidentally */
+ char textmode : 7; /* __IOINFO_TM_ANSI or __IOINFO_TM_UTF8 or __IOINFO_TM_UTF16LE */
+ char unicode : 1; /* Was the file opened as unicode? */
+ char pipech2[2]; /* 2 more peak ahead chars for UNICODE mode */
+#endif /* _SAFECRT_IMPL */
+ } ioinfo;
+
+/*
+ * Definition of IOINFO_L2E, the log base 2 of the number of elements in each
+ * array of ioinfo structs.
+ */
+#define IOINFO_L2E 5
+
+/*
+ * Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array
+ */
+#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
+
+/*
+ * Definition of IOINFO_ARRAYS, maximum number of supported ioinfo arrays.
+ */
+#define IOINFO_ARRAYS 64
+
+#define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
+
+#define _TZ_STRINGS_SIZE 64
+
+/*
+ * Access macros for getting at an ioinfo struct and its fields from a
+ * file handle
+ */
+#define _pioinfo(i) ( __pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - \
+ 1)) )
+#define _osfhnd(i) ( _pioinfo(i)->osfhnd )
+
+#define _osfile(i) ( _pioinfo(i)->osfile )
+
+#define _pipech(i) ( _pioinfo(i)->pipech )
+
+#define _pipech2(i) ( _pioinfo(i)->pipech2 )
+
+#define _textmode(i) ( _pioinfo(i)->textmode )
+
+#define _tm_unicode(i) ( _pioinfo(i)->unicode )
+
+/*
+ * Safer versions of the above macros. Currently, only _osfile_safe is
+ * used.
+ */
+#define _pioinfo_safe(i) ( (((i) != -1) && ((i) != -2)) ? _pioinfo(i) : &__badioinfo )
+
+#define _osfhnd_safe(i) ( _pioinfo_safe(i)->osfhnd )
+
+#define _osfile_safe(i) ( _pioinfo_safe(i)->osfile )
+
+#define _pipech_safe(i) ( _pioinfo_safe(i)->pipech )
+
+#define _pipech2_safe(i) ( _pioinfo_safe(i)->pipech2 )
+
+#ifdef _SAFECRT_IMPL
+/* safecrt does not have support for textmode, so we always return __IOINFO_TM_ANSI */
+#define _textmode_safe(i) __IOINFO_TM_ANSI
+#define _tm_unicode_safe(i) 0
+#else /* _SAFECRT_IMPL */
+#define _textmode_safe(i) ( _pioinfo_safe(i)->textmode )
+#define _tm_unicode_safe(i) ( _pioinfo_safe(i)->unicode )
+#endif /* _SAFECRT_IMPL */
+
+#ifndef _M_CEE_PURE
+#ifdef _SAFECRT_IMPL
+/* We need to get this from the downlevel DLL, even when we build safecrt.lib */
+extern __declspec(dllimport) ioinfo __badioinfo;
+extern __declspec(dllimport) ioinfo * __pioinfo[];
+#else /* _SAFECRT_IMPL */
+/*
+ * Special, static ioinfo structure used only for more graceful handling
+ * of a C file handle value of -1 (results from common errors at the stdio
+ * level).
+ */
+extern _CRTIMP ioinfo __badioinfo;
+
+/*
+ * Array of arrays of control structures for lowio files.
+ */
+extern _CRTIMP ioinfo * __pioinfo[];
+#endif /* _SAFECRT_IMPL */
+#endif /* _M_CEE_PURE */
+
+/*
+ * Current number of allocated ioinfo structures (_NHANDLE_ is the upper
+ * limit).
+ */
+extern int _nhandle;
+
+int __cdecl _alloc_osfhnd(void);
+int __cdecl _free_osfhnd(int);
+int __cdecl _set_osfhnd(int, intptr_t);
+
+/*
+ fileno for stdout, stdin & stderr when there is no console
+*/
+#define _NO_CONSOLE_FILENO (intptr_t)-2
+
+
+extern const char __dnames[];
+extern const char __mnames[];
+
+extern int _days[];
+extern int _lpdays[];
+
+extern __time32_t __cdecl __loctotime32_t(int, int, int, int, int, int, int);
+extern __time64_t __cdecl __loctotime64_t(int, int, int, int, int, int, int);
+
+#ifdef _TM_DEFINED
+extern int __cdecl _isindst(__in struct tm * _Time);
+#endif /* _TM_DEFINED */
+
+extern void __cdecl __tzset(void);
+
+extern int __cdecl _validdrive(unsigned);
+
+/*
+ * If we are only interested in years between 1901 and 2099, we could use this:
+ *
+ * #define IS_LEAP_YEAR(y) (y % 4 == 0)
+ */
+
+#define IS_LEAP_YEAR(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+
+/*
+ * get the buffer used by gmtime
+ */
+struct tm * __cdecl __getgmtimebuf ();
+
+/*
+ * This variable is in the C start-up; the length must be kept synchronized
+ * It is used by the *cenvarg.c modules
+ */
+
+extern char _acfinfo[]; /* "_C_FILE_INFO=" */
+
+#define CFI_LENGTH 12 /* "_C_FILE_INFO" is 12 bytes long */
+
+
+/*
+ * stdio internals
+ */
+#ifndef _FILE_DEFINED
+struct _iobuf {
+ char *_ptr;
+ int _cnt;
+ char *_base;
+ int _flag;
+ int _file;
+ int _charbuf;
+ int _bufsiz;
+ char *_tmpfname;
+ };
+typedef struct _iobuf FILE;
+#define _FILE_DEFINED
+#endif /* _FILE_DEFINED */
+
+#if !defined (_FILEX_DEFINED) && defined (_WINDOWS_)
+
+/*
+ * Variation of FILE type used for the dynamically allocated portion of
+ * __piob[]. For single thread, _FILEX is the same as FILE. For multithread
+ * models, _FILEX has two fields: the FILE struct and the CRITICAL_SECTION
+ * struct used to serialize access to the FILE.
+ */
+
+typedef struct {
+ FILE f;
+ CRITICAL_SECTION lock;
+ } _FILEX;
+
+
+#define _FILEX_DEFINED
+#endif /* !defined (_FILEX_DEFINED) && defined (_WINDOWS_) */
+
+/*
+ * Number of entries supported in the array pointed to by __piob[]. That is,
+ * the number of stdio-level files which may be open simultaneously. This
+ * is normally set to _NSTREAM_ by the stdio initialization code.
+ */
+extern int _nstream;
+
+/*
+ * Pointer to the array of pointers to FILE/_FILEX structures that are used
+ * to manage stdio-level files.
+ */
+extern void **__piob;
+
+FILE * __cdecl _getstream(void);
+FILE * __cdecl _openfile(__in_z const char * _Filename, __in_z const char * _Mode, __in int _ShFlag, __out FILE * _File);
+FILE * __cdecl _wopenfile(__in_z const wchar_t * _Filename, __in_z const wchar_t * _Mode, __in int _ShFlag, __out FILE * _File);
+void __cdecl _getbuf(__out FILE * _File);
+int __cdecl _filwbuf (__inout FILE * _File);
+int __cdecl _flswbuf(__in int _Ch, __inout FILE * _File);
+void __cdecl _freebuf(__inout FILE * _File);
+int __cdecl _stbuf(__inout FILE * _File);
+void __cdecl _ftbuf(int _Flag, __inout FILE * _File);
+
+#ifdef _SAFECRT_IMPL
+
+int __cdecl _output(__inout FILE * _File, __in_z __format_string const char *_Format, va_list _ArgList);
+int __cdecl _woutput(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, va_list _ArgList);
+int __cdecl _output_s(__inout FILE * _File, __in_z __format_string const char *_Format, va_list _ArgList);
+int __cdecl _output_p(__inout FILE * _File, __in_z __format_string const char *_Format, va_list _ArgList);
+int __cdecl _woutput_s(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, va_list _ArgList);
+int __cdecl _woutput_p(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, va_list _ArgList);
+typedef int (*OUTPUTFN)(FILE *, const char *, va_list);
+typedef int (*WOUTPUTFN)(FILE *, const wchar_t *, va_list);
+
+#else /* _SAFECRT_IMPL */
+
+int __cdecl _output_l(__inout FILE * _File, __in_z __format_string const char *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _woutput_l(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _output_s_l(__inout FILE * _File, __in_z __format_string const char *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _output_p_l(__inout FILE * _File, __in_z __format_string const char *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _woutput_s_l(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _woutput_p_l(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+typedef int (*OUTPUTFN)(__inout FILE * _File, const char *, _locale_t, va_list);
+typedef int (*WOUTPUTFN)(__inout FILE * _File, const wchar_t *, _locale_t, va_list);
+
+#endif /* _SAFECRT_IMPL */
+
+#ifdef _SAFECRT_IMPL
+
+int __cdecl _input(__in FILE * _File, __in_z __format_string const unsigned char * _Format, va_list _ArgList);
+int __cdecl _winput(__in FILE * _File, __in_z __format_string const wchar_t * _Format, va_list _ArgList);
+int __cdecl _input_s(__in FILE * _File, __in_z __format_string const unsigned char * _Format, va_list _ArgList);
+int __cdecl _winput_s(__in FILE * _File, __in_z __format_string const wchar_t * _Format, va_list _ArgList);
+typedef int (*INPUTFN)(FILE *, const unsigned char *, va_list);
+typedef int (*WINPUTFN)(FILE *, const wchar_t *, va_list);
+
+#else /* _SAFECRT_IMPL */
+
+int __cdecl _input_l(__inout FILE * _File, __in_z __format_string const unsigned char *, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _winput_l(__inout FILE * _File, __in_z __format_string const wchar_t *, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _input_s_l(__inout FILE * _File, __in_z __format_string const unsigned char *, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _winput_s_l(__inout FILE * _File, __in_z __format_string const wchar_t *, __in_opt _locale_t _Locale, va_list _ArgList);
+typedef int (*INPUTFN)(FILE *, const unsigned char *, _locale_t, va_list);
+typedef int (*WINPUTFN)(FILE *, const wchar_t *, _locale_t, va_list);
+
+#ifdef _UNICODE
+#define TINPUTFN WINPUTFN
+#else /* _UNICODE */
+#define TINPUTFN INPUTFN
+#endif /* _UNICODE */
+
+#endif /* _SAFECRT_IMPL */
+
+int __cdecl _flush(__inout FILE * _File);
+void __cdecl _endstdio(void);
+
+errno_t __cdecl _sopen_helper(__in_z const char * _Filename,
+ __in int _OFlag, __in int _ShFlag, __in int _PMode,
+ __out int * _PFileHandle, int _BSecure);
+errno_t __cdecl _wsopen_helper(__in_z const wchar_t * _Filename,
+ __in int _OFlag, __in int _ShFlag, __in int _PMode,
+ __out int * _PFileHandle, int _BSecure);
+
+#ifndef CRTDLL
+extern int _cflush;
+#endif /* CRTDLL */
+
+extern unsigned int _tempoff;
+
+extern unsigned int _old_pfxlen;
+
+extern int _umaskval; /* the umask value */
+
+extern char _pipech[]; /* pipe lookahead */
+
+extern char _exitflag; /* callable termination flag */
+
+extern int _C_Termination_Done; /* termination done flag */
+
+char * __cdecl _getpath(__in_z const char * _Src, __out_ecount_z(_SizeInChars) char * _Dst, __in size_t _SizeInChars);
+wchar_t * __cdecl _wgetpath(__in_z const wchar_t * _Src, __out_ecount_z(_SizeInWords) wchar_t * _Dst, __in size_t _SizeInWords);
+
+extern int _dowildcard; /* flag to enable argv[] wildcard expansion */
+
+#ifndef _PNH_DEFINED
+typedef int (__cdecl * _PNH)( size_t );
+#define _PNH_DEFINED
+#endif /* _PNH_DEFINED */
+
+#if _MSC_VER >= 1400 && defined(_M_CEE)
+#ifndef __MPNH_DEFINED
+typedef int (__clrcall * __MPNH)( size_t );
+#define __MPNH_DEFINED
+#endif /* __MPNH_DEFINED */
+#endif /* _MSC_VER >= 1400 && defined(_M_CEE) */
+
+
+/* calls the currently installed new handler */
+int __cdecl _callnewh(__in size_t _Size);
+
+extern int _newmode; /* malloc new() handler mode */
+
+/* pointer to initial environment block that is passed to [w]main */
+#ifndef _M_CEE_PURE
+extern _CRTIMP wchar_t **__winitenv;
+extern _CRTIMP char **__initenv;
+#endif /* _M_CEE_PURE */
+
+/* _calloca helper */
+#define _calloca(count, size) ((count<=0 || size<=0 || ((((size_t)_HEAP_MAXREQ) / ((size_t)count)) < ((size_t)size)))? NULL : _malloca(count * size))
+
+/* startup set values */
+extern char *_aenvptr; /* environment ptr */
+extern wchar_t *_wenvptr; /* wide environment ptr */
+
+/* command line */
+
+#if defined (_DLL)
+_CRTIMP char ** __cdecl __p__acmdln(void);
+_CRTIMP wchar_t ** __cdecl __p__wcmdln(void);
+#endif /* defined (_DLL) */
+#ifndef _M_CEE_PURE
+_CRTIMP extern char *_acmdln;
+_CRTIMP extern wchar_t *_wcmdln;
+#else /* _M_CEE_PURE */
+#define _acmdln (*__p__acmdln())
+#define _wcmdln (*__p__wcmdln())
+#endif /* _M_CEE_PURE */
+
+/*
+ * prototypes for internal startup functions
+ */
+int __cdecl _cwild(void); /* wild.c */
+int __cdecl _wcwild(void); /* wwild.c */
+int __cdecl _mtinit(void); /* tidtable.c */
+void __cdecl _mtterm(void); /* tidtable.c */
+int __cdecl _mtinitlocks(void); /* mlock.c */
+void __cdecl _mtdeletelocks(void); /* mlock.c */
+int __cdecl _mtinitlocknum(int); /* mlock.c */
+
+/* Wrapper for InitializeCriticalSection API, with default spin count */
+int __cdecl __crtInitCritSecAndSpinCount(PCRITICAL_SECTION, DWORD);
+#define _CRT_SPINCOUNT 4000
+
+/*
+ * C source build only!!!!
+ *
+ * more prototypes for internal startup functions
+ */
+void __cdecl _amsg_exit(int); /* crt0.c */
+void __cdecl __crtExitProcess(int); /* crt0dat.c */
+void __cdecl __crtCorExitProcess(int); /* crt0dat.c */
+void __cdecl __crtdll_callstaticterminators(void); /* crt0dat.c */
+
+/*
+_cinit now allows the caller to suppress floating point precision init
+This allows the DLLs that use the CRT to not initialise FP precision,
+allowing the EXE's setting to persist even when a DLL is loaded
+*/
+int __cdecl _cinit(int /* initFloatingPrecision */); /* crt0dat.c */
+void __cdecl __doinits(void); /* astart.asm */
+void __cdecl __doterms(void); /* astart.asm */
+void __cdecl __dopreterms(void); /* astart.asm */
+void __cdecl _FF_MSGBANNER(void);
+void __cdecl _fpmath(int /*initPrecision*/);
+void __cdecl _fpclear(void);
+void __cdecl _fptrap(void); /* crt0fp.c */
+int __cdecl _heap_init(int);
+void __cdecl _heap_term(void);
+void __cdecl _heap_abort(void);
+void __cdecl __initconin(void); /* initcon.c */
+void __cdecl __initconout(void); /* initcon.c */
+int __cdecl _ioinit(void); /* crt0.c, crtlib.c */
+void __cdecl _ioterm(void); /* crt0.c, crtlib.c */
+char * __cdecl _GET_RTERRMSG(int);
+void __cdecl _NMSG_WRITE(int);
+int __CRTDECL _setargv(void); /* setargv.c, stdargv.c */
+int __CRTDECL __setargv(void); /* stdargv.c */
+int __CRTDECL _wsetargv(void); /* wsetargv.c, wstdargv.c */
+int __CRTDECL __wsetargv(void); /* wstdargv.c */
+int __cdecl _setenvp(void); /* stdenvp.c */
+int __cdecl _wsetenvp(void); /* wstdenvp.c */
+void __cdecl __setmbctable(unsigned int); /* mbctype.c */
+
+#ifdef MRTDLL
+_MRTIMP int __cdecl _onexit_process(_CPVFV);
+_MRTIMP int __cdecl _onexit_app_domain(_CPVFV);
+#endif /* MRTDLL */
+
+#ifdef _MBCS
+int __cdecl __initmbctable(void); /* mbctype.c */
+#endif /* _MBCS */
+
+#ifndef _MANAGED_MAIN
+int __CRTDECL main(__in int _Argc, __in_ecount_z(_Argc) char ** _Argv, __in_z char ** _Env);
+int __CRTDECL wmain(__in int _Argc, __in_ecount_z(_Argc) wchar_t ** _Argv, __in_z wchar_t ** _Env);
+#endif /* _MANAGED_MAIN */
+
+/* helper functions for wide/multibyte environment conversion */
+int __cdecl __mbtow_environ (void);
+int __cdecl __wtomb_environ (void);
+
+/* These two functions take a char ** for the environment option
+ At some point during their execution, they take ownership of the
+ memory block passed in using option. At this point, they
+ NULL out the incoming char * / wchar_t * to ensure there is no
+ double-free
+*/
+int __cdecl __crtsetenv (__deref_inout_opt char ** _POption, __in const int _Primary);
+int __cdecl __crtwsetenv (__deref_inout_opt wchar_t ** _POption, __in const int _Primary);
+
+#ifndef _M_CEE_PURE
+_CRTIMP extern void (__cdecl * _aexit_rtn)(int);
+#endif /* _M_CEE_PURE */
+
+#if defined (_DLL) || defined (CRTDLL)
+
+#ifndef _STARTUP_INFO_DEFINED
+typedef struct
+{
+ int newmode;
+} _startupinfo;
+#define _STARTUP_INFO_DEFINED
+#endif /* _STARTUP_INFO_DEFINED */
+
+_CRTIMP int __cdecl __getmainargs(__out int * _Argc, __deref_out_ecount(*_Argc) char *** _Argv,
+ __deref_out_opt char *** _Env, __in int _DoWildCard,
+ __in _startupinfo * _StartInfo);
+
+_CRTIMP int __cdecl __wgetmainargs(__out int * _Argc, __deref_out_ecount(*_Argc)wchar_t *** _Argv,
+ __deref_out_opt wchar_t *** _Env, __in int _DoWildCard,
+ __in _startupinfo * _StartInfo);
+
+#endif /* defined (_DLL) || defined (CRTDLL) */
+
+/*
+ * Prototype, variables and constants which determine how error messages are
+ * written out.
+ */
+#define _UNKNOWN_APP 0
+#define _CONSOLE_APP 1
+#define _GUI_APP 2
+
+extern int __app_type;
+
+#if !defined (_M_CEE_PURE)
+
+extern Volatile<void*> __native_startup_lock;
+
+#define __NO_REASON UINT_MAX
+extern Volatile<unsigned int> __native_dllmain_reason;
+extern Volatile<unsigned int> __native_vcclrit_reason;
+
+#if defined (__cplusplus)
+
+#pragma warning(push)
+#pragma warning(disable: 4483)
+#if _MSC_FULL_VER >= 140050415
+#define _NATIVE_STARTUP_NAMESPACE __identifier("<CrtImplementationDetails>")
+#else /* _MSC_FULL_VER >= 140050415 */
+#define _NATIVE_STARTUP_NAMESPACE __CrtImplementationDetails
+#endif /* _MSC_FULL_VER >= 140050415 */
+
+namespace _NATIVE_STARTUP_NAMESPACE
+{
+ class NativeDll
+ {
+ private:
+ static const unsigned int ProcessDetach = 0;
+ static const unsigned int ProcessAttach = 1;
+ static const unsigned int ThreadAttach = 2;
+ static const unsigned int ThreadDetach = 3;
+ static const unsigned int ProcessVerifier = 4;
+
+ public:
+
+ inline static bool IsInDllMain()
+ {
+ return (__native_dllmain_reason != __NO_REASON);
+ }
+
+ inline static bool IsInProcessAttach()
+ {
+ return (__native_dllmain_reason == ProcessAttach);
+ }
+
+ inline static bool IsInProcessDetach()
+ {
+ return (__native_dllmain_reason == ProcessDetach);
+ }
+
+ inline static bool IsInVcclrit()
+ {
+ return (__native_vcclrit_reason != __NO_REASON);
+ }
+
+ inline static bool IsSafeForManagedCode()
+ {
+ if (!IsInDllMain())
+ {
+ return true;
+ }
+
+ if (IsInVcclrit())
+ {
+ return true;
+ }
+
+ return !IsInProcessAttach() && !IsInProcessDetach();
+ }
+ };
+}
+#pragma warning(pop)
+
+#endif /* defined (__cplusplus) */
+
+#endif /* !defined (_M_CEE_PURE) */
+
+extern int __error_mode;
+
+_CRTIMP void __cdecl __set_app_type(int);
+#if defined (CRTDLL) && !defined (_SYSCRT)
+/*
+ * All these function pointer are used for creating global state of CRT
+ * functions. Either all of them will be set or all of them will be NULL
+ */
+typedef void (__cdecl *_set_app_type_function)(int);
+typedef int (__cdecl *_get_app_type_function)();
+extern _set_app_type_function __set_app_type_server;
+extern _get_app_type_function __get_app_type_server;
+#endif /* defined (CRTDLL) && !defined (_SYSCRT) */
+
+/*
+ * C source build only!!!!
+ *
+ * map Win32 errors into Xenix errno values -- for modules written in C
+ */
+_CRTIMP void __cdecl _dosmaperr(unsigned long);
+extern int __cdecl _get_errno_from_oserr(unsigned long);
+
+/*
+ * internal routines used by the exec/spawn functions
+ */
+
+extern intptr_t __cdecl _dospawn(__in int _Mode, __in_z_opt const char * _Name, __inout_z char * _Cmd, __in_z_opt char * _Env);
+extern intptr_t __cdecl _wdospawn(__in int _Mode, __in_z_opt const wchar_t * _Name, __inout_z wchar_t * _Cmd, __in_z_opt wchar_t * _Env);
+extern int __cdecl _cenvarg(__in_z const char * const * _Argv, __in_z_opt const char * const * _Env,
+ __deref_out_opt char ** _ArgBlk, __deref_out_opt char ** _EnvBlk, __in_z const char *_Name);
+extern int __cdecl _wcenvarg(__in_z const wchar_t * const * _Argv, __in_z_opt const wchar_t * const * _Env,
+ __deref_out_opt wchar_t ** _ArgBlk, __deref_out_opt wchar_t ** _EnvBlk, __in_z const wchar_t * _Name);
+#ifndef _M_IX86
+extern char ** _capture_argv(__in va_list *, __in_z const char * _FirstArg, __out_ecount_z(_MaxCount) char ** _Static_argv, __in size_t _MaxCount);
+extern wchar_t ** _wcapture_argv(__in va_list *, __in_z const wchar_t * _FirstArg, __out_ecount_z(_MaxCount) wchar_t ** _Static_argv, __in size_t _MaxCount);
+#endif /* _M_IX86 */
+
+/*
+ * internal routine used by the abort
+ */
+
+extern _PHNDLR __cdecl __get_sigabrt(void);
+
+/*
+ * Type from ntdef.h
+ */
+
+typedef LONG NTSTATUS;
+
+/*
+ * Exception code used in _invalid_parameter
+ */
+
+#ifndef STATUS_INVALID_PARAMETER
+#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
+#endif /* STATUS_INVALID_PARAMETER */
+
+/*
+ * Exception code used for abort and _CALL_REPORTFAULT
+ */
+
+#ifndef STATUS_FATAL_APP_EXIT
+#define STATUS_FATAL_APP_EXIT ((NTSTATUS)0x40000015L)
+#endif /* STATUS_FATAL_APP_EXIT */
+
+/*
+ * Validate functions
+ */
+#include <crtdbg.h> /* _ASSERTE */
+#include <errno.h>
+
+#define __STR2WSTR(str) L##str
+
+#define _STR2WSTR(str) __STR2WSTR(str)
+
+#define __FILEW__ _STR2WSTR(__FILE__)
+#define __FUNCTIONW__ _STR2WSTR(__FUNCTION__)
+
+/* We completely fill the buffer only in debug (see _SECURECRT__FILL_STRING
+ * and _SECURECRT__FILL_BYTE macros).
+ */
+#if !defined (_SECURECRT_FILL_BUFFER)
+#ifdef _DEBUG
+#define _SECURECRT_FILL_BUFFER 1
+#else /* _DEBUG */
+#define _SECURECRT_FILL_BUFFER 0
+#endif /* _DEBUG */
+#endif /* !defined (_SECURECRT_FILL_BUFFER) */
+
+#ifndef _SAFECRT_IMPL
+/* _invalid_parameter is already defined in safecrt.h and safecrt.lib */
+#if !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE)
+extern "C++"
+#endif /* !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) */
+_CRTIMP
+#endif /* _SAFECRT_IMPL */
+void __cdecl _invalid_parameter(__in_z_opt const wchar_t *, __in_z_opt const wchar_t *, __in_z_opt const wchar_t *, unsigned int, uintptr_t);
+
+#if !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE)
+extern "C++"
+#endif /* !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) */
+_CRTIMP
+void __cdecl _invoke_watson(__in_z_opt const wchar_t *, __in_z_opt const wchar_t *, __in_z_opt const wchar_t *, unsigned int, uintptr_t);
+
+#ifndef _DEBUG
+#if !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE)
+extern "C++"
+#endif /* !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) */
+_CRTIMP
+void __cdecl _invalid_parameter_noinfo(void);
+#endif /* _DEBUG */
+
+/* Invoke Watson if _ExpressionError is not 0; otherwise simply return _EspressionError */
+__forceinline
+void _invoke_watson_if_error(
+ errno_t _ExpressionError,
+ const wchar_t *_Expression,
+ const wchar_t *_Function,
+ const wchar_t *_File,
+ unsigned int _Line,
+ uintptr_t _Reserved
+ )
+{
+ if (_ExpressionError == 0)
+ {
+ return;
+ }
+ _invoke_watson(_Expression, _Function, _File, _Line, _Reserved);
+}
+
+/* Invoke Watson if _ExpressionError is not 0 and equal to _ErrorValue1 or _ErrorValue2; otherwise simply return _EspressionError */
+__forceinline
+errno_t _invoke_watson_if_oneof(
+ errno_t _ExpressionError,
+ errno_t _ErrorValue1,
+ errno_t _ErrorValue2,
+ const wchar_t *_Expression,
+ const wchar_t *_Function,
+ const wchar_t *_File,
+ unsigned int _Line,
+ uintptr_t _Reserved
+ )
+{
+ if (_ExpressionError == 0 || (_ExpressionError != _ErrorValue1 && _ExpressionError != _ErrorValue2))
+ {
+ return _ExpressionError;
+ }
+ _invoke_watson(_Expression, _Function, _File, _Line, _Reserved);
+ return _ExpressionError;
+}
+
+/*
+ * Assert in debug builds.
+ * set errno and return
+ *
+ */
+#ifdef _DEBUG
+#define _CALL_INVALID_PARAMETER_FUNC(funcname, expr) funcname(expr, __FUNCTIONW__, __FILEW__, __LINE__, 0)
+#define _INVOKE_WATSON_IF_ERROR(expr) _invoke_watson_if_error((expr), __STR2WSTR(#expr), __FUNCTIONW__, __FILEW__, __LINE__, 0)
+#define _INVOKE_WATSON_IF_ONEOF(expr, errvalue1, errvalue2) _invoke_watson_if_oneof(expr, (errvalue1), (errvalue2), __STR2WSTR(#expr), __FUNCTIONW__, __FILEW__, __LINE__, 0)
+#else /* _DEBUG */
+#define _CALL_INVALID_PARAMETER_FUNC(funcname, expr) funcname(NULL, NULL, NULL, 0, 0)
+#define _INVOKE_WATSON_IF_ERROR(expr) _invoke_watson_if_error(expr, NULL, NULL, NULL, 0, 0)
+#define _INVOKE_WATSON_IF_ONEOF(expr, errvalue1, errvalue2) _invoke_watson_if_oneof((expr), (errvalue1), (errvalue2), NULL, NULL, NULL, 0, 0)
+#endif /* _DEBUG */
+
+#define _INVALID_PARAMETER(expr) _CALL_INVALID_PARAMETER_FUNC(_invalid_parameter, expr)
+
+#define _VALIDATE_RETURN_VOID( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return; \
+ } \
+ }
+
+/*
+ * Assert in debug builds.
+ * set errno and return value
+ */
+
+#ifndef _VALIDATE_RETURN
+#define _VALIDATE_RETURN( expr, errorcode, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr) ); \
+ return ( retexpr ); \
+ } \
+ }
+#endif /* _VALIDATE_RETURN */
+
+#ifndef _VALIDATE_RETURN_NOEXC
+#define _VALIDATE_RETURN_NOEXC( expr, errorcode, retexpr ) \
+ { \
+ if ( !(expr) ) \
+ { \
+ errno = errorcode; \
+ return ( retexpr ); \
+ } \
+ }
+#endif /* _VALIDATE_RETURN_NOEXC */
+
+/*
+ * Assert in debug builds.
+ * set errno and set retval for later usage
+ */
+
+#define _VALIDATE_SETRET( expr, errorcode, retval, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ retval=( retexpr ); \
+ } \
+ }
+
+#define _CHECK_FH_RETURN( handle, errorcode, retexpr ) \
+ { \
+ if(handle == _NO_CONSOLE_FILENO) \
+ { \
+ errno = errorcode; \
+ return ( retexpr ); \
+ } \
+ }
+
+/*
+ We use _VALIDATE_STREAM_ANSI_RETURN to ensure that ANSI file operations(
+ fprintf etc) aren't called on files opened as UNICODE. We do this check
+ only if it's an actual FILE pointer & not a string
+*/
+
+#define _VALIDATE_STREAM_ANSI_RETURN( stream, errorcode, retexpr ) \
+ { \
+ FILE *_Stream=stream; \
+ _VALIDATE_RETURN(( (_Stream->_flag & _IOSTRG) || \
+ ( (_textmode_safe(_fileno(_Stream)) == __IOINFO_TM_ANSI) && \
+ !_tm_unicode_safe(_fileno(_Stream)))), \
+ errorcode, retexpr) \
+ }
+
+/*
+ We use _VALIDATE_STREAM_ANSI_SETRET to ensure that ANSI file operations(
+ fprintf etc) aren't called on files opened as UNICODE. We do this check
+ only if it's an actual FILE pointer & not a string. It doesn't actually return
+ immediately
+*/
+
+#define _VALIDATE_STREAM_ANSI_SETRET( stream, errorcode, retval, retexpr) \
+ { \
+ FILE *_Stream=stream; \
+ _VALIDATE_SETRET(( (_Stream->_flag & _IOSTRG) || \
+ ( (_textmode_safe(_fileno(_Stream)) == __IOINFO_TM_ANSI) && \
+ !_tm_unicode_safe(_fileno(_Stream)))), \
+ errorcode, retval, retexpr) \
+ }
+
+/*
+ * Assert in debug builds.
+ * Return value (do not set errno)
+ */
+
+#define _VALIDATE_RETURN_NOERRNO( expr, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return ( retexpr ); \
+ } \
+ }
+
+/*
+ * Assert in debug builds.
+ * set errno and return errorcode
+ */
+
+#define _VALIDATE_RETURN_ERRCODE( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return ( errorcode ); \
+ } \
+ }
+
+#define _VALIDATE_RETURN_ERRCODE_NOEXC( expr, errorcode ) \
+ { \
+ if (!(expr)) \
+ { \
+ errno = errorcode; \
+ return ( errorcode ); \
+ } \
+ }
+
+#define _VALIDATE_CLEAR_OSSERR_RETURN( expr, errorcode, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ _doserrno = 0L; \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr) ); \
+ return ( retexpr ); \
+ } \
+ }
+
+#define _CHECK_FH_CLEAR_OSSERR_RETURN( handle, errorcode, retexpr ) \
+ { \
+ if(handle == _NO_CONSOLE_FILENO) \
+ { \
+ _doserrno = 0L; \
+ errno = errorcode; \
+ return ( retexpr ); \
+ } \
+ }
+
+#define _VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ _doserrno = 0L; \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return ( errorcode ); \
+ } \
+ }
+
+#define _CHECK_FH_CLEAR_OSSERR_RETURN_ERRCODE( handle, retexpr ) \
+ { \
+ if(handle == _NO_CONSOLE_FILENO) \
+ { \
+ _doserrno = 0L; \
+ return ( retexpr ); \
+ } \
+ }
+
+#ifdef _DEBUG
+extern size_t __crtDebugFillThreshold;
+#endif /* _DEBUG */
+
+#if !defined (_SECURECRT_FILL_BUFFER_THRESHOLD)
+#ifdef _DEBUG
+#define _SECURECRT_FILL_BUFFER_THRESHOLD __crtDebugFillThreshold
+#else /* _DEBUG */
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)0)
+#endif /* _DEBUG */
+#endif /* !defined (_SECURECRT_FILL_BUFFER_THRESHOLD) */
+
+#if _SECURECRT_FILL_BUFFER
+#define _SECURECRT__FILL_STRING(_String, _Size, _Offset) \
+ if ((_Size) != ((size_t)-1) && (_Size) != INT_MAX && \
+ ((size_t)(_Offset)) < (_Size)) \
+ { \
+ memset((_String) + (_Offset), \
+ _SECURECRT_FILL_BUFFER_PATTERN, \
+ (_SECURECRT_FILL_BUFFER_THRESHOLD < ((size_t)((_Size) - (_Offset))) ? \
+ _SECURECRT_FILL_BUFFER_THRESHOLD : \
+ ((_Size) - (_Offset))) * sizeof(*(_String))); \
+ }
+#else /* _SECURECRT_FILL_BUFFER */
+#define _SECURECRT__FILL_STRING(_String, _Size, _Offset)
+#endif /* _SECURECRT_FILL_BUFFER */
+
+#if _SECURECRT_FILL_BUFFER
+#define _SECURECRT__FILL_BYTE(_Position) \
+ if (_SECURECRT_FILL_BUFFER_THRESHOLD > 0) \
+ { \
+ (_Position) = _SECURECRT_FILL_BUFFER_PATTERN; \
+ }
+#else /* _SECURECRT_FILL_BUFFER */
+#define _SECURECRT__FILL_BYTE(_Position)
+#endif /* _SECURECRT_FILL_BUFFER */
+
+#ifdef __cplusplus
+#define _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE extern "C"
+#else /* __cplusplus */
+#define _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE
+#endif /* __cplusplus */
+
+/* helper macros to redirect an mbs function to the corresponding _l version */
+#define _REDIRECT_TO_L_VERSION_1(_ReturnType, _FunctionName, _Type1) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1) \
+ { \
+ return _FunctionName##_l(_Arg1, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_2(_ReturnType, _FunctionName, _Type1, _Type2) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_3(_ReturnType, _FunctionName, _Type1, _Type2, _Type3) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, _Arg3, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_4(_ReturnType, _FunctionName, _Type1, _Type2, _Type3, _Type4) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3, _Type4 _Arg4) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, _Arg3, _Arg4, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_5(_ReturnType, _FunctionName, _Type1, _Type2, _Type3, _Type4, _Type5) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3, _Type4 _Arg4, _Type5 _Arg5) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, _Arg3, _Arg4, _Arg5, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_6(_ReturnType, _FunctionName, _Type1, _Type2, _Type3, _Type4, _Type5, _Type6) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3, _Type4 _Arg4, _Type5 _Arg5, _Type6 _Arg6) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, _Arg3, _Arg4, _Arg5, _Arg6, NULL); \
+ }
+
+/* internal helper functions for encoding and decoding pointers */
+void __cdecl _init_pointers();
+_CRTIMP void * __cdecl _encode_pointer(void *);
+_CRTIMP void * __cdecl _encoded_null();
+_CRTIMP void * __cdecl _decode_pointer(void *);
+
+/* internal helper function for communicating with the debugger */
+BOOL DebuggerKnownHandle();
+
+/* Macros to simplify the use of Secure CRT in the CRT itself.
+ * We should use [_BEGIN/_END]_SECURE_CRT_DEPRECATION_DISABLE sparingly.
+ */
+#define _BEGIN_SECURE_CRT_DEPRECATION_DISABLE \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4996))
+
+#define _END_SECURE_CRT_DEPRECATION_DISABLE \
+ __pragma(warning(pop))
+
+#define _ERRCHECK(e) \
+ _INVOKE_WATSON_IF_ERROR(e)
+
+#define _ERRCHECK_EINVAL(e) \
+ _INVOKE_WATSON_IF_ONEOF(e, EINVAL, EINVAL)
+
+#define _ERRCHECK_EINVAL_ERANGE(e) \
+ _INVOKE_WATSON_IF_ONEOF(e, EINVAL, ERANGE)
+
+#define _ERRCHECK_SPRINTF(_PrintfCall) \
+ { \
+ errno_t _SaveErrno = errno; \
+ errno = 0; \
+ if ( ( _PrintfCall ) < 0) \
+ { \
+ _ERRCHECK_EINVAL_ERANGE(errno); \
+ } \
+ errno = _SaveErrno; \
+ }
+
+/* internal helper function to access environment variable in read-only mode */
+const wchar_t * __cdecl _wgetenv_helper_nolock(const wchar_t *);
+const char * __cdecl _getenv_helper_nolock(const char *);
+
+/* internal helper routines used to query a PE image header. */
+BOOL __cdecl _ValidateImageBase(PBYTE pImageBase);
+PIMAGE_SECTION_HEADER __cdecl _FindPESection(PBYTE pImageBase, DWORD_PTR rva);
+BOOL __cdecl _IsNonwritableInCurrentImage(PBYTE pTarget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#endif /* _INC_INTERNAL */
diff --git a/src/pal/src/safecrt/internal_securecrt.h b/src/pal/src/safecrt/internal_securecrt.h
new file mode 100644
index 0000000000..c38bc4613b
--- /dev/null
+++ b/src/pal/src/safecrt/internal_securecrt.h
@@ -0,0 +1,292 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*internal_securecrt.h - contains declarations of internal routines and variables for securecrt
+*
+
+*
+*Purpose:
+* Declares routines and variables used internally in the SecureCRT implementation.
+* In this include file we define the macros needed to implement the secure functions
+* inlined in the *.inl files like tcscpy_s.inl, etc.
+* Note that this file is used for the CRT implementation, while internal_safecrt is used
+* to build the downlevel library safecrt.lib.
+*
+* [Internal]
+*
+****/
+
+#pragma once
+
+#ifndef _INC_INTERNAL_SECURECRT
+#define _INC_INTERNAL_SECURECRT
+
+/* more VS specific goodness */
+#define __out_ecount_z( x )
+#define __out_ecount( x )
+#define __in_opt
+#define __in_z_opt
+#define __out_ecount_z_opt( x )
+#define __in_z
+#define __in
+
+/*
+ * The original SafeCRT implemention allows runtine control over buffer checking.
+ * For now we'll key this off the debug flag.
+ */
+#ifdef _DEBUG
+ #define _CrtGetCheckCount() ((int)1)
+#else
+ #define _CrtGetCheckCount() ((int)0)
+#endif
+
+/* Assert message and Invalid parameter */
+#ifdef _DEBUG
+ #define _ASSERT_EXPR( val, exp ) \
+ { \
+ if ( ( val ) == 0 ) \
+ { \
+ if ( sMBUSafeCRTAssertFunc != NULL ) \
+ { \
+ ( *sMBUSafeCRTAssertFunc )( #exp, "SafeCRT assert failed", __FILE__, __LINE__ ); \
+ } \
+ } \
+ }
+ #define _INVALID_PARAMETER( exp ) _ASSERT_EXPR( 0, exp )
+ #define _ASSERTE( exp ) _ASSERT_EXPR( exp, exp )
+#else
+ #define _ASSERT_EXPR( val, expr )
+ #define _INVALID_PARAMETER( exp )
+ #define _ASSERTE( exp )
+#endif
+
+/* _TRUNCATE */
+#if !defined (_TRUNCATE)
+#define _TRUNCATE ((size_t)-1)
+#endif /* !defined (_TRUNCATE) */
+
+/* #include <internal.h> */
+
+#define _VALIDATE_RETURN_VOID( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), #expr ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(#expr); \
+ return; \
+ } \
+ }
+
+/*
+ * Assert in debug builds.
+ * set errno and return value
+ */
+
+#ifndef _VALIDATE_RETURN
+#define _VALIDATE_RETURN( expr, errorcode, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), #expr ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(#expr ); \
+ return ( retexpr ); \
+ } \
+ }
+#endif /* _VALIDATE_RETURN */
+
+#ifndef _VALIDATE_RETURN_NOEXC
+#define _VALIDATE_RETURN_NOEXC( expr, errorcode, retexpr ) \
+ { \
+ if ( !(expr) ) \
+ { \
+ errno = errorcode; \
+ return ( retexpr ); \
+ } \
+ }
+#endif /* _VALIDATE_RETURN_NOEXC */
+
+/*
+ * Assert in debug builds.
+ * set errno and return errorcode
+ */
+
+#define _VALIDATE_RETURN_ERRCODE( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return ( errorcode ); \
+ } \
+ }
+
+/* We completely fill the buffer only in debug (see _SECURECRT__FILL_STRING
+ * and _SECURECRT__FILL_BYTE macros).
+ */
+#if !defined (_SECURECRT_FILL_BUFFER)
+#ifdef _DEBUG
+#define _SECURECRT_FILL_BUFFER 1
+#else /* _DEBUG */
+#define _SECURECRT_FILL_BUFFER 0
+#endif /* _DEBUG */
+#endif /* !defined (_SECURECRT_FILL_BUFFER) */
+
+/* _SECURECRT_FILL_BUFFER_PATTERN is the same as _bNoMansLandFill */
+#define _SECURECRT_FILL_BUFFER_PATTERN 0xFD
+
+#if !defined (_SECURECRT_FILL_BUFFER_THRESHOLD)
+#ifdef _DEBUG
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+#else /* _DEBUG */
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)0)
+#endif /* _DEBUG */
+#endif /* !defined (_SECURECRT_FILL_BUFFER_THRESHOLD) */
+
+#if _SECURECRT_FILL_BUFFER
+#define _SECURECRT__FILL_STRING(_String, _Size, _Offset) \
+ if ((_Size) != ((size_t)-1) && (_Size) != INT_MAX && \
+ ((size_t)(_Offset)) < (_Size)) \
+ { \
+ memset((_String) + (_Offset), \
+ _SECURECRT_FILL_BUFFER_PATTERN, \
+ (_SECURECRT_FILL_BUFFER_THRESHOLD < ((size_t)((_Size) - (_Offset))) ? \
+ _SECURECRT_FILL_BUFFER_THRESHOLD : \
+ ((_Size) - (_Offset))) * sizeof(*(_String))); \
+ }
+#else /* _SECURECRT_FILL_BUFFER */
+#define _SECURECRT__FILL_STRING(_String, _Size, _Offset)
+#endif /* _SECURECRT_FILL_BUFFER */
+
+#if _SECURECRT_FILL_BUFFER
+#define _SECURECRT__FILL_BYTE(_Position) \
+ if (_SECURECRT_FILL_BUFFER_THRESHOLD > 0) \
+ { \
+ (_Position) = _SECURECRT_FILL_BUFFER_PATTERN; \
+ }
+#else /* _SECURECRT_FILL_BUFFER */
+#define _SECURECRT__FILL_BYTE(_Position)
+#endif /* _SECURECRT_FILL_BUFFER */
+
+/* string resetting */
+#define _FILL_STRING _SECURECRT__FILL_STRING
+
+#define _FILL_BYTE _SECURECRT__FILL_BYTE
+
+#define _RESET_STRING(_String, _Size) \
+ { \
+ *(_String) = 0; \
+ _FILL_STRING((_String), (_Size), 1); \
+ }
+
+/* validations */
+#define _VALIDATE_STRING_ERROR(_String, _Size, _Ret) \
+ _VALIDATE_RETURN((_String) != NULL && (_Size) > 0, EINVAL, (_Ret))
+
+#define _VALIDATE_STRING(_String, _Size) \
+ _VALIDATE_STRING_ERROR((_String), (_Size), EINVAL)
+
+#define _VALIDATE_POINTER_ERROR_RETURN(_Pointer, _ErrorCode, _Ret) \
+ _VALIDATE_RETURN((_Pointer) != NULL, (_ErrorCode), (_Ret))
+
+#define _VALIDATE_POINTER_ERROR(_Pointer, _Ret) \
+ _VALIDATE_POINTER_ERROR_RETURN((_Pointer), EINVAL, (_Ret))
+
+#define _VALIDATE_POINTER(_Pointer) \
+ _VALIDATE_POINTER_ERROR((_Pointer), EINVAL)
+
+#define _VALIDATE_CONDITION_ERROR_RETURN(_Condition, _ErrorCode, _Ret) \
+ _VALIDATE_RETURN((_Condition), (_ErrorCode), (_Ret))
+
+#define _VALIDATE_CONDITION_ERROR(_Condition, _Ret) \
+ _VALIDATE_CONDITION_ERROR_RETURN((_Condition), EINVAL, (_Ret))
+
+#define _VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, _Ret) \
+ if ((_Pointer) == NULL) \
+ { \
+ _RESET_STRING((_String), (_Size)); \
+ _VALIDATE_POINTER_ERROR_RETURN((_Pointer), EINVAL, (_Ret)) \
+ }
+
+#define _VALIDATE_POINTER_RESET_STRING(_Pointer, _String, _Size) \
+ _VALIDATE_POINTER_RESET_STRING_ERROR((_Pointer), (_String), (_Size), EINVAL)
+
+#define _RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, _Ret) \
+ _VALIDATE_RETURN(("Buffer is too small" && 0), ERANGE, _Ret)
+
+#define _RETURN_BUFFER_TOO_SMALL(_String, _Size) \
+ _RETURN_BUFFER_TOO_SMALL_ERROR((_String), (_Size), ERANGE)
+
+#define _RETURN_DEST_NOT_NULL_TERMINATED(_String, _Size) \
+ _VALIDATE_RETURN(("String is not null terminated" && 0), EINVAL, EINVAL)
+
+#define _RETURN_EINVAL \
+ _VALIDATE_RETURN(("Invalid parameter" && 0), EINVAL, EINVAL)
+
+#define _RETURN_ERROR(_Msg, _Ret) \
+ _VALIDATE_RETURN(((_Msg), 0), EINVAL, _Ret)
+
+/* returns without calling _invalid_parameter */
+#define _RETURN_NO_ERROR \
+ return 0
+
+/* Note that _RETURN_TRUNCATE does not set errno */
+#define _RETURN_TRUNCATE \
+ return STRUNCATE
+
+#define _SET_MBCS_ERROR \
+ (errno = EILSEQ)
+
+#define _RETURN_MBCS_ERROR \
+ return _SET_MBCS_ERROR
+
+/* locale dependent */
+#define _LOCALE_ARG \
+ _LocInfo
+
+#define _LOCALE_ARG_DECL \
+ _locale_t _LOCALE_ARG
+
+#define _LOCALE_UPDATE \
+ _LocaleUpdate _LocUpdate(_LOCALE_ARG)
+
+#define _ISMBBLEAD(_Character) \
+ _ismbblead_l((_Character), _LocUpdate.GetLocaleT())
+
+#define _MBSDEC(_String, _Current) \
+ _mbsdec((_String), (_Current))
+
+#define _ISMBBLEADPREFIX(_Result, _StringStart, _BytePtr) \
+ { \
+ unsigned char *_Tmp_VAR, *_StringStart_VAR, *_BytePtr_VAR; \
+ \
+ _StringStart_VAR = (_StringStart); \
+ _BytePtr_VAR = (_BytePtr); \
+ _Tmp_VAR = _BytePtr_VAR; \
+ while ((_Tmp_VAR >= _StringStart_VAR) && _ISMBBLEAD(*_Tmp_VAR)) \
+ { \
+ _Tmp_VAR--; \
+ } \
+ (_Result) = ((_BytePtr_VAR - _Tmp_VAR) & 1) != 0; \
+ }
+
+#define _LOCALE_SHORTCUT_TEST \
+ _LocUpdate.GetLocaleT()->mbcinfo->ismbcodepage == 0
+
+#define _USE_LOCALE_ARG 1
+
+/* misc */
+#define _ASSIGN_IF_NOT_NULL(_Pointer, _Value) \
+ if ((_Pointer) != NULL) \
+ { \
+ *(_Pointer) = (_Value); \
+ }
+
+#endif /* _INC_INTERNAL_SECURECRT */
diff --git a/src/pal/src/safecrt/makepath_s.c b/src/pal/src/safecrt/makepath_s.c
new file mode 100644
index 0000000000..4342685b9c
--- /dev/null
+++ b/src/pal/src/safecrt/makepath_s.c
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*makepath_s.c - create path name from components
+*
+
+*
+*Purpose:
+* To provide support for creation of full path names from components
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME _makepath_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _T(_Character) _Character
+
+#define _MBS_SUPPORT 0
+
+#include "tmakepath_s.inl"
diff --git a/src/pal/src/safecrt/mbusafecrt.c b/src/pal/src/safecrt/mbusafecrt.c
new file mode 100644
index 0000000000..ca853d9269
--- /dev/null
+++ b/src/pal/src/safecrt/mbusafecrt.c
@@ -0,0 +1,254 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+* mbusafecrt.c - implementaion of support functions and data for MBUSafeCRT
+*
+
+*
+* Purpose:
+* This file contains the implementation of support functions and
+* data for MBUSafeCRT declared in mbusafecrt.h and mbusafecrt_internal.h.
+****/
+
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "mbusafecrt_internal.h"
+
+/* global data */
+tSafeCRT_AssertFuncPtr sMBUSafeCRTAssertFunc = NULL;
+
+/***
+* MBUSafeCRTSetAssertFunc - Set the function called when an assert fails.
+****/
+
+void MBUSafeCRTSetAssertFunc( tSafeCRT_AssertFuncPtr inAssertFuncPtr )
+{
+ /* set it */
+ sMBUSafeCRTAssertFunc = inAssertFuncPtr;
+}
+
+/***
+* _putc_nolock - putc for the miniFILE stream.
+****/
+
+int _putc_nolock( char inChar, miniFILE* inStream )
+{
+ int returnValue = EOF;
+
+ inStream->_cnt -= sizeof( char );
+
+ if ( ( inStream->_cnt ) >= 0 )
+ {
+ *( inStream->_ptr ) = inChar;
+ inStream->_ptr += sizeof( char );
+ returnValue = ( int )inChar;
+ }
+
+ return returnValue;
+}
+
+/***
+* _putwc_nolock - putwc for the miniFILE stream.
+****/
+
+int _putwc_nolock( wchar_t inChar, miniFILE* inStream )
+{
+ int returnValue = WEOF;
+
+ inStream->_cnt -= sizeof( wchar_t );
+
+ if ( ( inStream->_cnt ) >= 0 )
+ {
+ *( ( wchar_t* )( inStream->_ptr ) ) = inChar;
+ inStream->_ptr += sizeof( wchar_t );
+ returnValue = ( int )inChar;
+ }
+
+ return returnValue;
+}
+
+/***
+* _getc_nolock - getc for the miniFILE stream.
+****/
+
+int _getc_nolock( miniFILE* inStream )
+{
+ int returnValue = EOF;
+
+ if ( ( inStream->_cnt ) >= ( int )( sizeof( char ) ) )
+ {
+ inStream->_cnt -= sizeof( char );
+ returnValue = ( int )( *( inStream->_ptr ) );
+ inStream->_ptr += sizeof( char );
+ }
+
+ return returnValue;
+}
+
+/***
+* _getwc_nolock - getc for the miniFILE stream.
+****/
+
+int _getwc_nolock( miniFILE* inStream )
+{
+ int returnValue = EOF;
+
+ if ( ( inStream->_cnt ) >= ( int )( sizeof( wchar_t ) ) )
+ {
+ inStream->_cnt -= sizeof( wchar_t );
+ returnValue = ( int )( *( ( wchar_t* )( inStream->_ptr ) ) );
+ inStream->_ptr += sizeof( wchar_t );
+ }
+
+ return returnValue;
+}
+
+/***
+* _ungetc_nolock - ungetc for the miniFILE stream.
+****/
+
+int _ungetc_nolock( char inChar, miniFILE* inStream )
+{
+ int returnValue = EOF;
+
+ if ( ( size_t )( ( inStream->_ptr ) - ( inStream->_base ) ) >= ( sizeof( char ) ) )
+ {
+ inStream->_cnt += sizeof( char );
+ inStream->_ptr -= sizeof( char );
+ return ( int )inChar;
+ }
+
+ return returnValue;
+}
+
+/***
+* _ungetwc_nolock - ungetwc for the miniFILE stream.
+****/
+
+int _ungetwc_nolock( wchar_t inChar, miniFILE* inStream )
+{
+ int returnValue = WEOF;
+
+ if ( ( size_t )( ( inStream->_ptr ) - ( inStream->_base ) ) >= ( sizeof( wchar_t ) ) )
+ {
+ inStream->_cnt += sizeof( wchar_t );
+ inStream->_ptr -= sizeof( wchar_t );
+ returnValue = ( unsigned short )inChar;
+ }
+
+ return returnValue;
+}
+
+
+/***
+* _safecrt_cfltcvt - convert a float to an ascii string.
+* Uses sprintf - this usage is OK.
+****/
+
+/* routine used for floating-point output */
+#define FORMATSIZE 30
+
+#define _snprintf snprintf
+
+// taken from output.inl
+#define FL_ALTERNATE 0x00080 /* alternate form requested */
+
+errno_t _safecrt_cfltcvt(double *arg, char *buffer, size_t sizeInBytes, int type, int precision, int flags)
+{
+ char format[FORMATSIZE];
+ size_t formatlen = 0;
+ int retvalue;
+
+ if (flags & 1)
+ {
+ type -= 'a' - 'A';
+ }
+ formatlen = 0;
+ format[formatlen++] = '%';
+ if (flags & FL_ALTERNATE)
+ {
+ format[formatlen++] = '#';
+ }
+ format[formatlen++] = '.';
+ _itoa_s(precision, format + formatlen, FORMATSIZE - formatlen, 10);
+ formatlen = strlen(format);
+ format[formatlen++] = (char)type;
+ format[formatlen] = 0;
+
+ buffer[sizeInBytes - 1] = 0;
+ retvalue = _snprintf(buffer, sizeInBytes, format, *arg);
+ if (buffer[sizeInBytes - 1] != 0 || retvalue <= 0)
+ {
+ buffer[0] = 0;
+ return EINVAL;
+ }
+ return 0;
+}
+
+
+/***
+* _safecrt_fassign - convert a string into a float or double.
+****/
+
+void _safecrt_fassign(int flag, void* argument, char* number )
+{
+ if ( flag != 0 ) // double
+ {
+ double dblValue = 0.0;
+ (void)sscanf( number, "%lf", &dblValue );
+ *( ( double* )argument ) = dblValue;
+ }
+ else // float
+ {
+ float fltValue = 0.0;
+ (void)sscanf( number, "%f", &fltValue );
+ *( ( float* )argument ) = fltValue;
+ }
+}
+
+
+/***
+* _safecrt_wfassign - convert a wchar_t string into a float or double.
+****/
+
+void _safecrt_wfassign(int flag, void* argument, wchar_t* number )
+{
+ // We cannot use system functions for this - they
+ // assume that wchar_t is four bytes, while we assume
+ // two. So, we need to convert to a regular char string
+ // without using any system functions. To do this,
+ // we'll assume that the numbers are in the 0-9 range and
+ // do a simple conversion.
+
+ char* numberAsChars = ( char* )number;
+ int position = 0;
+
+ // do the convert
+ while ( number[ position ] != 0 )
+ {
+ numberAsChars[ position ] = ( char )( number[ position ] & 0x00FF );
+ position++;
+ }
+ numberAsChars[ position ] = ( char )( number[ position ] & 0x00FF );
+
+ // call the normal char version
+ _safecrt_fassign( flag, argument, numberAsChars );
+}
+
+
+/***
+* _minimal_chartowchar - do a simple char to wchar conversion.
+****/
+
+int _minimal_chartowchar( wchar_t* outWChar, const char* inChar )
+{
+ *outWChar = ( wchar_t )( ( unsigned short )( ( unsigned char )( *inChar ) ) );
+ return 1;
+}
+
+
diff --git a/src/pal/src/safecrt/mbusafecrt_internal.h b/src/pal/src/safecrt/mbusafecrt_internal.h
new file mode 100644
index 0000000000..9a3aa1ca90
--- /dev/null
+++ b/src/pal/src/safecrt/mbusafecrt_internal.h
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+* mbusafecrt_internal.h - internal declarations for SafeCRT functions
+*
+
+*
+* Purpose:
+* This file contains the internal declarations SafeCRT
+* functions ported to MacOS. These are the safe versions of
+* functions standard functions banned by SWI
+****/
+
+/* shields! */
+
+#ifndef MBUSAFECRT_INTERNAL_H
+#define MBUSAFECRT_INTERNAL_H
+
+#include "pal_char16.h"
+#include "pal_mstypes.h"
+
+typedef __builtin_va_list va_list;
+
+// The ifdef below are to accommodate Unix build
+// that complains about them being declared in stdarg.h already.
+#ifndef va_start
+#define va_start __builtin_va_start
+#endif
+#ifndef va_end
+#define va_end __builtin_va_end
+#endif
+
+#include "mbusafecrt.h"
+
+#ifdef EOF
+#undef EOF
+#endif
+#define EOF -1
+
+#ifdef WEOF
+#undef WEOF
+#endif
+#define WEOF -1
+
+#define CASSERT(p) extern int sanity_check_dummy[1+((!(p))*(-2))];
+
+extern tSafeCRT_AssertFuncPtr sMBUSafeCRTAssertFunc;
+
+typedef struct miniFILE_struct
+{
+ char* _ptr;
+ int _cnt;
+ char* _base;
+ int _flag;
+} miniFILE;
+
+#define _IOSTRG 1
+#define _IOWRT 2
+#define _IOREAD 4
+#define _IOMYBUF 8
+
+int _putc_nolock( char inChar, miniFILE* inStream );
+int _putwc_nolock( wchar_t inChar, miniFILE* inStream );
+int _getc_nolock( miniFILE* inStream );
+int _getwc_nolock( miniFILE* inStream );
+int _ungetc_nolock( char inChar, miniFILE* inStream );
+int _ungetwc_nolock( wchar_t inChar, miniFILE* inStream );
+
+errno_t _safecrt_cfltcvt(double *arg, char *buffer, size_t sizeInBytes, int type, int precision, int flags);
+
+void _safecrt_fassign(int flag, void* argument, char * number );
+void _safecrt_wfassign(int flag, void* argument, wchar_t * number );
+
+int _minimal_chartowchar( wchar_t* outWChar, const char* inChar );
+
+int _output_s( miniFILE* outfile, const char* _Format, va_list _ArgList);
+int _woutput_s( miniFILE* outfile, const wchar_t* _Format, va_list _ArgList);
+int _output( miniFILE *outfile, const char* _Format, va_list _ArgList);
+
+int _soutput_s( char *_Dst, size_t _Size, const char *_Format, va_list _ArgList );
+int _swoutput_s( wchar_t *_Dst, size_t _Size, const wchar_t *_Format, va_list _ArgList );
+
+int __tinput_s( miniFILE* inFile, const unsigned char * inFormat, va_list inArgList );
+int __twinput_s( miniFILE* inFile, const wchar_t * inFormat, va_list inArgList );
+
+#endif /* MBUSAFECRT_INTERNAL_H */
diff --git a/src/pal/src/safecrt/memcpy_s.c b/src/pal/src/safecrt/memcpy_s.c
new file mode 100644
index 0000000000..27aeb79665
--- /dev/null
+++ b/src/pal/src/safecrt/memcpy_s.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*memcpy_s.c - contains memcpy_s routine
+*
+
+*
+*Purpose:
+* memcpy_s() copies a source memory buffer to a destination buffer.
+* Overlapping buffers are not treated specially, so propagation may occur.
+*
+*Revision History:
+* 10-07-03 AC Module created.
+* 03-10-04 AC Return ERANGE when buffer is too small
+* 01-14-05 AC Prefast (espx) fixes
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include "internal_securecrt.h"
+#include "mbusafecrt_internal.h"
+
+/***
+*memcpy_s - Copy source buffer to destination buffer
+*
+*Purpose:
+* memcpy_s() copies a source memory buffer to a destination memory buffer.
+* This routine does NOT recognize overlapping buffers, and thus can lead
+* to propagation.
+*
+* For cases where propagation must be avoided, memmove_s() must be used.
+*
+*Entry:
+* void *dst = pointer to destination buffer
+* size_t sizeInBytes = size in bytes of the destination buffer
+* const void *src = pointer to source buffer
+* size_t count = number of bytes to copy
+*
+*Exit:
+* Returns 0 if everything is ok, else return the error code.
+*
+*Exceptions:
+* Input parameters are validated. Refer to the validation section of the function.
+* On error, the error code is returned and the destination buffer is zeroed.
+*
+*******************************************************************************/
+
+errno_t __cdecl memcpy_s(
+ void * dst,
+ size_t sizeInBytes,
+ const void * src,
+ size_t count
+)
+{
+ if (count == 0)
+ {
+ /* nothing to do */
+ return 0;
+ }
+
+ /* validation section */
+ _VALIDATE_RETURN_ERRCODE(dst != NULL, EINVAL);
+ if (src == NULL || sizeInBytes < count)
+ {
+ /* zeroes the destination buffer */
+ memset(dst, 0, sizeInBytes);
+
+ _VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(sizeInBytes >= count, ERANGE);
+ /* useless, but prefast is confused */
+ return EINVAL;
+ }
+
+ UINT_PTR x = (UINT_PTR)dst, y = (UINT_PTR)src;
+ assert((x + count <= y) || (y + count <= x));
+ memcpy(dst, src, count);
+ return 0;
+}
diff --git a/src/pal/src/safecrt/memmove_s.c b/src/pal/src/safecrt/memmove_s.c
new file mode 100644
index 0000000000..a0ae5f7ea6
--- /dev/null
+++ b/src/pal/src/safecrt/memmove_s.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*memmove_s.c - contains memmove_s routine
+*
+
+*
+*Purpose:
+* memmove_s() copies a source memory buffer to a destination buffer.
+* Overlapping buffers are treated specially, to avoid propagation.
+*
+*Revision History:
+* 10-07-03 AC Module created.
+* 03-10-04 AC Return ERANGE when buffer is too small
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include "internal_securecrt.h"
+#include "mbusafecrt_internal.h"
+
+/***
+*memmove - Copy source buffer to destination buffer
+*
+*Purpose:
+* memmove() copies a source memory buffer to a destination memory buffer.
+* This routine recognize overlapping buffers to avoid propagation.
+*
+* For cases where propagation is not a problem, memcpy_s() can be used.
+*
+*Entry:
+* void *dst = pointer to destination buffer
+* size_t sizeInBytes = size in bytes of the destination buffer
+* const void *src = pointer to source buffer
+* size_t count = number of bytes to copy
+*
+*Exit:
+* Returns 0 if everything is ok, else return the error code.
+*
+*Exceptions:
+* Input parameters are validated. Refer to the validation section of the function.
+* On error, the error code is returned. Nothing is written to the destination buffer.
+*
+*******************************************************************************/
+
+errno_t __cdecl memmove_s(
+ void * dst,
+ size_t sizeInBytes,
+ const void * src,
+ size_t count
+)
+{
+ if (count == 0)
+ {
+ /* nothing to do */
+ return 0;
+ }
+
+ /* validation section */
+ _VALIDATE_RETURN_ERRCODE(dst != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(sizeInBytes >= count, ERANGE);
+
+ memmove(dst, src, count);
+ return 0;
+}
diff --git a/src/pal/src/safecrt/output.inl b/src/pal/src/safecrt/output.inl
new file mode 100644
index 0000000000..ae0692efc5
--- /dev/null
+++ b/src/pal/src/safecrt/output.inl
@@ -0,0 +1,1624 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*output.c - printf style output to a FILE
+*
+
+*
+*Purpose:
+* This file contains the code that does all the work for the
+* printf family of functions. It should not be called directly, only
+* by the *printf functions. We don't make any assumtions about the
+* sizes of ints, longs, shorts, or long doubles, but if types do overlap,
+* we also try to be efficient. We do assume that pointers are the same
+* size as either ints or longs.
+* If CPRFLAG is defined, defines _cprintf instead.
+* **** DOESN'T CURRENTLY DO MTHREAD LOCKING ****
+*
+*Note:
+* this file is included in safecrt.lib build directly, plese refer
+* to safecrt_[w]output_s.c
+*
+*******************************************************************************/
+
+
+//typedef __int64_t __int64;
+
+
+#define FORMAT_VALIDATIONS
+
+typedef double _CRT_DOUBLE;
+
+//typedef int* intptr_t;
+
+/*
+Buffer size required to be passed to _gcvt, fcvt and other fp conversion routines
+*/
+#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */
+
+/* temporary work-around for compiler without 64-bit support */
+#ifndef _INTEGRAL_MAX_BITS
+#define _INTEGRAL_MAX_BITS 64
+#endif /* _INTEGRAL_MAX_BITS */
+
+//#include <mtdll.h>
+//#include <cruntime.h>
+//#include <limits.h>
+//#include <string.h>
+//#include <stddef.h>
+//#include <crtdefs.h>
+//#include <stdio.h>
+//#include <stdarg.h>
+//#include <cvt.h>
+//#include <conio.h>
+//#include <internal.h>
+//#include <fltintrn.h>
+//#include <stdlib.h>
+//#include <ctype.h>
+//#include <dbgint.h>
+//#include <setlocal.h>
+
+#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y )
+
+#ifndef _WCTOMB_S
+#define _WCTOMB_S wctomb_s
+#endif /* _WCTOMB_S */
+
+#undef _malloc_crt
+#define _malloc_crt malloc
+
+#undef _free_crt
+#define _free_crt free
+
+/* Wrapper for _output_s so that we do not expose FILE in the _output_s signature.
+ * Always ensure null-termination. Returns the number of written chars, not including the terminating null.
+ * Returns -1 if something went wrong during the formatting (in _output_s), e.g. mbcs conversions.
+ * Returns -2 if the string has been truncated.
+ * _output_s calls _invalid_parameter (and returns -1, possibly) if the format string is malformed.
+ */
+#ifndef _UNICODE
+int __cdecl _soutput_s(char *_Dst, size_t _Size, const char *_Format, va_list _ArgList)
+#else /* _UNICODE */
+int __cdecl _swoutput_s(wchar_t *_Dst, size_t _Size, const wchar_t *_Format, va_list _ArgList)
+#endif /* _UNICODE */
+{
+ miniFILE stream;
+ miniFILE *outfile = &stream;
+ int written = -1;
+
+ /* validation section */
+#ifndef _UNICODE
+ if(_Size==SIZE_MAX)
+ {
+ /* user is attempting to make us unbounded, but we don't fit that much */
+ outfile->_cnt = INT_MAX;
+ }
+ else
+ {
+ _VALIDATE_RETURN(_Size <= INT_MAX, EINVAL, -1);
+ outfile->_cnt = (int)_Size;
+ }
+ outfile->_ptr = outfile->_base = _Dst;
+#else /* _UNICODE */
+ if(_Size==SIZE_MAX)
+ {
+ /* user is attempting to make us unbounded, but we don't fit that much */
+ outfile->_cnt = INT_MAX;
+ }
+ else if(_Size>(INT_MAX/sizeof(wchar_t)))
+ {
+ /* we can't represent the amount of output the user asked for */
+ _VALIDATE_RETURN( 0 /* FALSE */, EINVAL, -1 );
+ }
+ else
+ {
+ outfile->_cnt = (int)(_Size*sizeof(wchar_t));
+ }
+ outfile->_ptr = outfile->_base = (char*)_Dst;
+#endif /* _UNICODE */
+ outfile->_flag = _IOWRT | _IOSTRG;
+
+#ifndef _UNICODE
+ written = _output_s(outfile, _Format, _ArgList);
+#else /* _UNICODE */
+ written = _woutput_s(outfile, _Format, _ArgList);
+#endif /* _UNICODE */
+ _Dst[_Size - 1] = 0;
+ if (written < 0)
+ {
+ if (outfile->_cnt < 0)
+ {
+ /* the buffer was too small; we return -2 to indicate truncation */
+ return -2;
+ }
+ /* otherwise, something else failed: we reset the string and we return */
+ if (_Dst != NULL && _Size > 0)
+ {
+ *_Dst = 0;
+ }
+ return written;
+ }
+
+#ifndef _UNICODE
+ if ((_putc_nolock('\0', outfile) != EOF))
+#else /* _UNICODE */
+ if ((_putc_nolock('\0', outfile) != EOF) && (_putc_nolock('\0', outfile) != EOF))
+#endif /* _UNICODE */
+ {
+ return written;
+ }
+ /* the last putc failed, so it means there is not enough space in the buffer */
+ return -2;
+}
+
+
+#ifndef _CFLTCVT
+#define _CFLTCVT _cfltcvt
+#endif /* _CFLTCVT */
+
+#ifndef _CLDCVT
+#define _CLDCVT _cldcvt
+#endif /* _CLDCVT */
+
+#ifdef _MBCS
+#undef _MBCS
+#endif /* _MBCS */
+//#include <tchar.h>
+
+/* this macro defines a function which is private and as fast as possible: */
+/* for example, in C 6.0, it might be static _fastcall <type> near. */
+#define LOCAL(x) static x __cdecl
+
+/* int/long/short/pointer sizes */
+
+/* the following should be set depending on the sizes of various types */
+#if __LP64__
+ #define LONG_IS_INT 0
+ CASSERT(sizeof(long) > sizeof(int));
+#else
+ #define LONG_IS_INT 1 /* 1 means long is same size as int */
+ CASSERT(sizeof(long) == sizeof(int));
+#endif
+
+#define SHORT_IS_INT 0 /* 1 means short is same size as int */
+#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64 */
+#if defined (_WIN64)
+ #define PTR_IS_INT 0 /* 1 means ptr is same size as int */
+ CASSERT(sizeof(void *) != sizeof(int));
+ #if __LP64__
+ #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) == sizeof(long));
+ #else
+ #define PTR_IS_LONG 0 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) != sizeof(long));
+ #endif
+ #define PTR_IS_INT64 1 /* 1 means ptr is same size as int64 */
+ CASSERT(sizeof(void *) == sizeof(int64_t));
+#else /* defined (_WIN64) */
+ #define PTR_IS_INT 1 /* 1 means ptr is same size as int */
+ CASSERT(sizeof(void *) == sizeof(int));
+ #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) == sizeof(long));
+ #define PTR_IS_INT64 0 /* 1 means ptr is same size as int64 */
+ CASSERT(sizeof(void *) != sizeof(int64_t));
+#endif /* defined (_WIN64) */
+
+/* CONSTANTS */
+
+/* size of conversion buffer (ANSI-specified minimum is 509) */
+
+#define BUFFERSIZE 512
+#define MAXPRECISION BUFFERSIZE
+
+#if BUFFERSIZE < _CVTBUFSIZE + 6
+/*
+ * Buffer needs to be big enough for default minimum precision
+ * when converting floating point needs bigger buffer, and malloc
+ * fails
+ */
+#error Conversion buffer too small for max double.
+#endif /* BUFFERSIZE < _CVTBUFSIZE + 6 */
+
+/* flag definitions */
+#define FL_SIGN 0x00001 /* put plus or minus in front */
+#define FL_SIGNSP 0x00002 /* put space or minus in front */
+#define FL_LEFT 0x00004 /* left justify */
+#define FL_LEADZERO 0x00008 /* pad with leading zeros */
+#define FL_LONG 0x00010 /* long value given */
+#define FL_SHORT 0x00020 /* short value given */
+#define FL_SIGNED 0x00040 /* signed data given */
+#define FL_ALTERNATE 0x00080 /* alternate form requested */
+#define FL_NEGATIVE 0x00100 /* value is negative */
+#define FL_FORCEOCTAL 0x00200 /* force leading '0' for octals */
+#define FL_LONGDOUBLE 0x00400 /* long double value given */
+#define FL_WIDECHAR 0x00800 /* wide characters */
+#define FL_LONGLONG 0x01000 /* long long value given */
+#define FL_I64 0x08000 /* __int64 value given */
+
+/* state definitions */
+enum STATE {
+ ST_NORMAL, /* normal state; outputting literal chars */
+ ST_PERCENT, /* just read '%' */
+ ST_FLAG, /* just read flag character */
+ ST_WIDTH, /* just read width specifier */
+ ST_DOT, /* just read '.' */
+ ST_PRECIS, /* just read precision specifier */
+ ST_SIZE, /* just read size specifier */
+ ST_TYPE /* just read type specifier */
+#ifdef FORMAT_VALIDATIONS
+ ,ST_INVALID /* Invalid format */
+#endif /* FORMAT_VALIDATIONS */
+
+};
+
+#ifdef FORMAT_VALIDATIONS
+#define NUMSTATES (ST_INVALID + 1)
+#else /* FORMAT_VALIDATIONS */
+#define NUMSTATES (ST_TYPE + 1)
+#endif /* FORMAT_VALIDATIONS */
+
+/* character type values */
+enum CHARTYPE {
+ CH_OTHER, /* character with no special meaning */
+ CH_PERCENT, /* '%' */
+ CH_DOT, /* '.' */
+ CH_STAR, /* '*' */
+ CH_ZERO, /* '0' */
+ CH_DIGIT, /* '1'..'9' */
+ CH_FLAG, /* ' ', '+', '-', '#' */
+ CH_SIZE, /* 'h', 'l', 'L', 'N', 'F', 'w' */
+ CH_TYPE /* type specifying character */
+};
+
+/* static data (read only, since we are re-entrant) */
+//#if defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS)
+//extern const char __nullstring[]; /* string to print on null ptr */
+//extern const wchar_t __wnullstring[]; /* string to print on null ptr */
+//#else /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
+static const char __nullstring[] = "(null)"; /* string to print on null ptr */
+static const wchar_t __wnullstring[] = {'(', 'n', 'u', 'l', 'l', ')', '\0'};/* string to print on null ptr */
+//#endif /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
+
+/* The state table. This table is actually two tables combined into one. */
+/* The lower nybble of each byte gives the character class of any */
+/* character; while the uper nybble of the byte gives the next state */
+/* to enter. See the macros below the table for details. */
+/* */
+/* The table is generated by maketabc.c -- use this program to make */
+/* changes. */
+
+#ifndef FORMAT_VALIDATIONS
+
+//#if defined (_UNICODE) || defined (CPRFLAG)
+//extern const char __lookuptable[];
+//#else /* defined (_UNICODE) || defined (CPRFLAG) */
+extern const char __lookuptable[] = {
+ /* ' ' */ 0x06,
+ /* '!' */ 0x00,
+ /* '"' */ 0x00,
+ /* '#' */ 0x06,
+ /* '$' */ 0x00,
+ /* '%' */ 0x01,
+ /* '&' */ 0x00,
+ /* ''' */ 0x00,
+ /* '(' */ 0x10,
+ /* ')' */ 0x00,
+ /* '*' */ 0x03,
+ /* '+' */ 0x06,
+ /* ',' */ 0x00,
+ /* '-' */ 0x06,
+ /* '.' */ 0x02,
+ /* '/' */ 0x10,
+ /* '0' */ 0x04,
+ /* '1' */ 0x45,
+ /* '2' */ 0x45,
+ /* '3' */ 0x45,
+ /* '4' */ 0x05,
+ /* '5' */ 0x05,
+ /* '6' */ 0x05,
+ /* '7' */ 0x05,
+ /* '8' */ 0x05,
+ /* '9' */ 0x35,
+ /* ':' */ 0x30,
+ /* ';' */ 0x00,
+ /* '<' */ 0x50,
+ /* '=' */ 0x00,
+ /* '>' */ 0x00,
+ /* '?' */ 0x00,
+ /* '@' */ 0x00,
+ /* 'A' */ 0x20, // Disable %A format
+ /* 'B' */ 0x20,
+ /* 'C' */ 0x38,
+ /* 'D' */ 0x50,
+ /* 'E' */ 0x58,
+ /* 'F' */ 0x07,
+ /* 'G' */ 0x08,
+ /* 'H' */ 0x00,
+ /* 'I' */ 0x37,
+ /* 'J' */ 0x30,
+ /* 'K' */ 0x30,
+ /* 'L' */ 0x57,
+ /* 'M' */ 0x50,
+ /* 'N' */ 0x07,
+ /* 'O' */ 0x00,
+ /* 'P' */ 0x00,
+ /* 'Q' */ 0x20,
+ /* 'R' */ 0x20,
+ /* 'S' */ 0x08,
+ /* 'T' */ 0x00,
+ /* 'U' */ 0x00,
+ /* 'V' */ 0x00,
+ /* 'W' */ 0x00,
+ /* 'X' */ 0x08,
+ /* 'Y' */ 0x60,
+ /* 'Z' */ 0x68,
+ /* '[' */ 0x60,
+ /* '\' */ 0x60,
+ /* ']' */ 0x60,
+ /* '^' */ 0x60,
+ /* '_' */ 0x00,
+ /* '`' */ 0x00,
+ /* 'a' */ 0x70, // Disable %a format
+ /* 'b' */ 0x70,
+ /* 'c' */ 0x78,
+ /* 'd' */ 0x78,
+ /* 'e' */ 0x78,
+ /* 'f' */ 0x78,
+ /* 'g' */ 0x08,
+ /* 'h' */ 0x07,
+ /* 'i' */ 0x08,
+ /* 'j' */ 0x00,
+ /* 'k' */ 0x00,
+ /* 'l' */ 0x07,
+ /* 'm' */ 0x00,
+ /* 'n' */ 0x00, // Disable %n format
+ /* 'o' */ 0x08,
+ /* 'p' */ 0x08,
+ /* 'q' */ 0x00,
+ /* 'r' */ 0x00,
+ /* 's' */ 0x08,
+ /* 't' */ 0x00,
+ /* 'u' */ 0x08,
+ /* 'v' */ 0x00,
+ /* 'w' */ 0x07,
+ /* 'x' */ 0x08
+};
+
+//#endif /* defined (_UNICODE) || defined (CPRFLAG) */
+
+#else /* FORMAT_VALIDATIONS */
+
+//#if defined (_UNICODE) || defined (CPRFLAG)
+//extern const unsigned char __lookuptable_s[];
+//#else /* defined (_UNICODE) || defined (CPRFLAG) */
+static const unsigned char __lookuptable_s[] = {
+ /* ' ' */ 0x06,
+ /* '!' */ 0x80,
+ /* '"' */ 0x80,
+ /* '#' */ 0x86,
+ /* '$' */ 0x80,
+ /* '%' */ 0x81,
+ /* '&' */ 0x80,
+ /* ''' */ 0x00,
+ /* '(' */ 0x00,
+ /* ')' */ 0x10,
+ /* '*' */ 0x03,
+ /* '+' */ 0x86,
+ /* ',' */ 0x80,
+ /* '-' */ 0x86,
+ /* '.' */ 0x82,
+ /* '/' */ 0x80,
+ /* '0' */ 0x14,
+ /* '1' */ 0x05,
+ /* '2' */ 0x05,
+ /* '3' */ 0x45,
+ /* '4' */ 0x45,
+ /* '5' */ 0x45,
+ /* '6' */ 0x85,
+ /* '7' */ 0x85,
+ /* '8' */ 0x85,
+ /* '9' */ 0x05,
+ /* ':' */ 0x00,
+ /* ';' */ 0x00,
+ /* '<' */ 0x30,
+ /* '=' */ 0x30,
+ /* '>' */ 0x80,
+ /* '?' */ 0x50,
+ /* '@' */ 0x80,
+ /* 'A' */ 0x80, // Disable %A format
+ /* 'B' */ 0x00,
+ /* 'C' */ 0x08,
+ /* 'D' */ 0x00,
+ /* 'E' */ 0x28,
+ /* 'F' */ 0x27,
+ /* 'G' */ 0x38,
+ /* 'H' */ 0x50,
+ /* 'I' */ 0x57,
+ /* 'J' */ 0x80,
+ /* 'K' */ 0x00,
+ /* 'L' */ 0x07,
+ /* 'M' */ 0x00,
+ /* 'N' */ 0x37,
+ /* 'O' */ 0x30,
+ /* 'P' */ 0x30,
+ /* 'Q' */ 0x50,
+ /* 'R' */ 0x50,
+ /* 'S' */ 0x88,
+ /* 'T' */ 0x00,
+ /* 'U' */ 0x00,
+ /* 'V' */ 0x00,
+ /* 'W' */ 0x20,
+ /* 'X' */ 0x28,
+ /* 'Y' */ 0x80,
+ /* 'Z' */ 0x88,
+ /* '[' */ 0x80,
+ /* '\' */ 0x80,
+ /* ']' */ 0x00,
+ /* '^' */ 0x00,
+ /* '_' */ 0x00,
+ /* '`' */ 0x60,
+ /* 'a' */ 0x60, // Disable %a format
+ /* 'b' */ 0x60,
+ /* 'c' */ 0x68,
+ /* 'd' */ 0x68,
+ /* 'e' */ 0x68,
+ /* 'f' */ 0x08,
+ /* 'g' */ 0x08,
+ /* 'h' */ 0x07,
+ /* 'i' */ 0x78,
+ /* 'j' */ 0x70,
+ /* 'k' */ 0x70,
+ /* 'l' */ 0x77,
+ /* 'm' */ 0x70,
+ /* 'n' */ 0x70,
+ /* 'o' */ 0x08,
+ /* 'p' */ 0x08,
+ /* 'q' */ 0x00,
+ /* 'r' */ 0x00,
+ /* 's' */ 0x08,
+ /* 't' */ 0x00,
+ /* 'u' */ 0x08,
+ /* 'v' */ 0x00,
+ /* 'w' */ 0x07,
+ /* 'x' */ 0x08
+};
+//#endif /* defined (_UNICODE) || defined (CPRFLAG) */
+
+#endif /* FORMAT_VALIDATIONS */
+
+#define FIND_CHAR_CLASS(lookuptbl, c) \
+ ((c) < _T(' ') || (c) > _T('x') ? \
+ CH_OTHER \
+ : \
+ (enum CHARTYPE)(lookuptbl[(c)-_T(' ')] & 0xF))
+
+#define FIND_NEXT_STATE(lookuptbl, class, state) \
+ (enum STATE)(lookuptbl[(class) * NUMSTATES + (state)] >> 4)
+
+/*
+ * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive.
+ */
+
+/* prototypes */
+
+#ifdef CPRFLAG
+
+#define WRITE_CHAR(ch, pnw) write_char(ch, pnw)
+#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, pnw)
+#define WRITE_STRING(s, len, pnw) write_string(s, len, pnw)
+
+LOCAL(void) write_char(_TCHAR ch, int *pnumwritten);
+LOCAL(void) write_multi_char(_TCHAR ch, int num, int *pnumwritten);
+LOCAL(void) write_string(const _TCHAR *string, int len, int *numwritten);
+
+#else /* CPRFLAG */
+
+#define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw)
+#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw)
+#define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw)
+
+LOCAL(void) write_char(_TCHAR ch, miniFILE *f, int *pnumwritten);
+LOCAL(void) write_multi_char(_TCHAR ch, int num, miniFILE *f, int *pnumwritten);
+LOCAL(void) write_string(const _TCHAR *string, int len, miniFILE *f, int *numwritten);
+
+#endif /* CPRFLAG */
+
+#define get_int_arg(list) va_arg(*list, int)
+#define get_long_arg(list) va_arg(*list, long)
+#define get_long_long_arg(list) va_arg(*list, long long)
+#define get_int64_arg(list) va_arg(*list, __int64)
+#define get_crtdouble_arg(list) va_arg(*list, _CRT_DOUBLE)
+#define get_ptr_arg(list) va_arg(*list, void *)
+
+#ifdef CPRFLAG
+LOCAL(int) output(const _TCHAR *, _locale_t , va_list);
+_CRTIMP int __cdecl _vtcprintf_l (const _TCHAR *, _locale_t, va_list);
+_CRTIMP int __cdecl _vtcprintf_s_l (const _TCHAR *, _locale_t, va_list);
+_CRTIMP int __cdecl _vtcprintf_p_l (const _TCHAR *, _locale_t, va_list);
+
+
+/***
+*int _cprintf(format, arglist) - write formatted output directly to console
+*
+*Purpose:
+* Writes formatted data like printf, but uses console I/O functions.
+*
+*Entry:
+* char *format - format string to determine data formats
+* arglist - list of POINTERS to where to put data
+*
+*Exit:
+* returns number of characters written
+*
+*Exceptions:
+*
+*******************************************************************************/
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _tcprintf_l (
+ const _TCHAR * format,
+ _locale_t plocinfo,
+ ...
+ )
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _tcprintf_s_l (
+ const _TCHAR * format,
+ _locale_t plocinfo,
+ ...
+ )
+#endif /* FORMAT_VALIDATIONS */
+
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, plocinfo);
+
+#ifndef FORMAT_VALIDATIONS
+ ret = _vtcprintf_l(format, plocinfo, arglist);
+#else /* FORMAT_VALIDATIONS */
+ ret = _vtcprintf_s_l(format, plocinfo, arglist);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ va_end(arglist);
+
+ return ret;
+}
+
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _tcprintf (
+ const _TCHAR * format,
+ ...
+ )
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _tcprintf_s (
+ const _TCHAR * format,
+ ...
+ )
+#endif /* FORMAT_VALIDATIONS */
+
+{
+ int ret;
+ va_list arglist;
+
+ va_start(arglist, format);
+
+#ifndef FORMAT_VALIDATIONS
+ ret = _vtcprintf_l(format, NULL, arglist);
+#else /* FORMAT_VALIDATIONS */
+ ret = _vtcprintf_s_l(format, NULL, arglist);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ va_end(arglist);
+
+ return ret;
+}
+
+#endif /* CPRFLAG */
+
+
+/***
+*int _output(stream, format, argptr), static int output(format, argptr)
+*
+*Purpose:
+* Output performs printf style output onto a stream. It is called by
+* printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
+* work. In multi-thread situations, _output assumes that the given
+* stream is already locked.
+*
+* Algorithm:
+* The format string is parsed by using a finite state automaton
+* based on the current state and the current character read from
+* the format string. Thus, looping is on a per-character basis,
+* not a per conversion specifier basis. Once the format specififying
+* character is read, output is performed.
+*
+*Entry:
+* FILE *stream - stream for output
+* char *format - printf style format string
+* va_list argptr - pointer to list of subsidiary arguments
+*
+*Exit:
+* Returns the number of characters written, or -1 if an output error
+* occurs.
+*ifdef _UNICODE
+* The wide-character flavour returns the number of wide-characters written.
+*endif
+*
+*Exceptions:
+*
+*******************************************************************************/
+#ifdef CPRFLAG
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _vtcprintf (
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ return _vtcprintf_l(format, NULL, argptr);
+}
+
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _vtcprintf_s (
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ return _vtcprintf_s_l(format, NULL, argptr);
+}
+
+#endif /* FORMAT_VALIDATIONS */
+#endif /* CPRFLAG */
+
+#ifdef CPRFLAG
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _vtcprintf_l (
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _vtcprintf_s_l (
+#endif /* FORMAT_VALIDATIONS */
+#else /* CPRFLAG */
+
+#ifdef _UNICODE
+#ifndef FORMAT_VALIDATIONS
+int __cdecl _woutput (
+ miniFILE *stream,
+#else /* FORMAT_VALIDATIONS */
+int __cdecl _woutput_s (
+ miniFILE *stream,
+#endif /* FORMAT_VALIDATIONS */
+#else /* _UNICODE */
+#ifndef FORMAT_VALIDATIONS
+int __cdecl _output (
+ miniFILE *stream,
+#else /* FORMAT_VALIDATIONS */
+ int __cdecl _output_s (
+ miniFILE *stream,
+
+#endif /* FORMAT_VALIDATIONS */
+#endif /* _UNICODE */
+
+#endif /* CPRFLAG */
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ int hexadd=0; /* offset to add to number to get 'a'..'f' */
+ TCHAR ch; /* character just read */
+ int flags=0; /* flag word -- see #defines above for flag values */
+ enum STATE state; /* current state */
+ enum CHARTYPE chclass; /* class of current character */
+ int radix; /* current conversion radix */
+ int charsout; /* characters currently written so far, -1 = IO error */
+ int fldwidth = 0; /* selected field width -- 0 means default */
+ int precision = 0; /* selected precision -- -1 means default */
+ TCHAR prefix[2]; /* numeric prefix -- up to two characters */
+ int prefixlen=0; /* length of prefix -- 0 means no prefix */
+ int capexp = 0; /* non-zero = 'E' exponent signifient, zero = 'e' */
+ int no_output=0; /* non-zero = prodcue no output for this specifier */
+ union {
+ const char *sz; /* pointer text to be printed, not zero terminated */
+ const wchar_t *wz;
+ } text;
+
+ int textlen; /* length of the text in bytes/wchars to be printed.
+ textlen is in multibyte or wide chars if _UNICODE */
+ union {
+ char sz[BUFFERSIZE];
+#ifdef _UNICODE
+ wchar_t wz[BUFFERSIZE];
+#endif /* _UNICODE */
+ } buffer;
+ wchar_t wchar; /* temp wchar_t */
+ int buffersize; /* size of text.sz (used only for the call to _cfltcvt) */
+ int bufferiswide=0; /* non-zero = buffer contains wide chars already */
+
+#ifndef CPRFLAG
+ _VALIDATE_RETURN( (stream != NULL), EINVAL, -1);
+#endif /* CPRFLAG */
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ charsout = 0; /* no characters written yet */
+ textlen = 0; /* no text yet */
+ state = ST_NORMAL; /* starting state */
+ buffersize = 0;
+
+ /* main loop -- loop while format character exist and no I/O errors */
+ while ((ch = *format++) != _T('\0') && charsout >= 0) {
+#ifndef FORMAT_VALIDATIONS
+ chclass = FIND_CHAR_CLASS(__lookuptable, ch); /* find character class */
+ state = FIND_NEXT_STATE(__lookuptable, chclass, state); /* find next state */
+#else /* FORMAT_VALIDATIONS */
+ chclass = FIND_CHAR_CLASS(__lookuptable_s, ch); /* find character class */
+ state = FIND_NEXT_STATE(__lookuptable_s, chclass, state); /* find next state */
+
+ _VALIDATE_RETURN((state != ST_INVALID), EINVAL, -1);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ /* execute code for each state */
+ switch (state) {
+
+ case ST_NORMAL:
+
+ NORMAL_STATE:
+
+ /* normal state -- just write character */
+#ifdef _UNICODE
+ bufferiswide = 1;
+#else /* _UNICODE */
+ bufferiswide = 0;
+#endif /* _UNICODE */
+ WRITE_CHAR(ch, &charsout);
+ break;
+
+ case ST_PERCENT:
+ /* set default value of conversion parameters */
+ prefixlen = fldwidth = no_output = capexp = 0;
+ flags = 0;
+ precision = -1;
+ bufferiswide = 0; /* default */
+ break;
+
+ case ST_FLAG:
+ /* set flag based on which flag character */
+ switch (ch) {
+ case _T('-'):
+ flags |= FL_LEFT; /* '-' => left justify */
+ break;
+ case _T('+'):
+ flags |= FL_SIGN; /* '+' => force sign indicator */
+ break;
+ case _T(' '):
+ flags |= FL_SIGNSP; /* ' ' => force sign or space */
+ break;
+ case _T('#'):
+ flags |= FL_ALTERNATE; /* '#' => alternate form */
+ break;
+ case _T('0'):
+ flags |= FL_LEADZERO; /* '0' => pad with leading zeros */
+ break;
+ }
+ break;
+
+ case ST_WIDTH:
+ /* update width value */
+ if (ch == _T('*')) {
+ /* get width from arg list */
+ fldwidth = get_int_arg(&argptr);
+ if (fldwidth < 0) {
+ /* ANSI says neg fld width means '-' flag and pos width */
+ flags |= FL_LEFT;
+ fldwidth = -fldwidth;
+ }
+ }
+ else {
+ /* add digit to current field width */
+ fldwidth = fldwidth * 10 + (ch - _T('0'));
+ }
+ break;
+
+ case ST_DOT:
+ /* zero the precision, since dot with no number means 0
+ not default, according to ANSI */
+ precision = 0;
+ break;
+
+ case ST_PRECIS:
+ /* update precison value */
+ if (ch == _T('*')) {
+ /* get precision from arg list */
+ precision = get_int_arg(&argptr);
+ if (precision < 0)
+ precision = -1; /* neg precision means default */
+ }
+ else {
+ /* add digit to current precision */
+ precision = precision * 10 + (ch - _T('0'));
+ }
+ break;
+
+ case ST_SIZE:
+ /* just read a size specifier, set the flags based on it */
+ switch (ch) {
+ case _T('l'):
+ /*
+ * In order to handle the ll case, we depart from the
+ * simple deterministic state machine.
+ */
+ if (*format == _T('l'))
+ {
+ ++format;
+ flags |= FL_LONGLONG; /* 'll' => long long */
+ }
+ else
+ {
+ flags |= FL_LONG; /* 'l' => long int or wchar_t */
+ }
+ break;
+
+ case _T('I'):
+ /*
+ * In order to handle the I, I32, and I64 size modifiers, we
+ * depart from the simple deterministic state machine. The
+ * code below scans for characters following the 'I',
+ * and defaults to 64 bit on WIN64 and 32 bit on WIN32
+ */
+#if PTR_IS_INT64
+ flags |= FL_I64; /* 'I' => __int64 on WIN64 systems */
+#endif /* PTR_IS_INT64 */
+ if ( (*format == _T('6')) && (*(format + 1) == _T('4')) )
+ {
+ format += 2;
+ flags |= FL_I64; /* I64 => __int64 */
+ }
+ else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) )
+ {
+ format += 2;
+ flags &= ~FL_I64; /* I32 => __int32 */
+ }
+ else if ( (*format == _T('d')) ||
+ (*format == _T('i')) ||
+ (*format == _T('o')) ||
+ (*format == _T('u')) ||
+ (*format == _T('x')) ||
+ (*format == _T('X')) )
+ {
+ /*
+ * Nothing further needed. %Id (et al) is
+ * handled just like %d, except that it defaults to 64 bits
+ * on WIN64. Fall through to the next iteration.
+ */
+ }
+ else {
+ state = ST_NORMAL;
+ goto NORMAL_STATE;
+ }
+ break;
+
+ case _T('h'):
+ flags |= FL_SHORT; /* 'h' => short int or char */
+ break;
+
+ case _T('w'):
+ flags |= FL_WIDECHAR; /* 'w' => wide character */
+ break;
+
+ }
+ break;
+
+ case ST_TYPE:
+ /* we have finally read the actual type character, so we */
+ /* now format and "print" the output. We use a big switch */
+ /* statement that sets 'text' to point to the text that should */
+ /* be printed, and 'textlen' to the length of this text. */
+ /* Common code later on takes care of justifying it and */
+ /* other miscellaneous chores. Note that cases share code, */
+ /* in particular, all integer formatting is done in one place. */
+ /* Look at those funky goto statements! */
+
+ switch (ch) {
+
+ case _T('C'): /* ISO wide character */
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+#ifdef _UNICODE
+ flags |= FL_SHORT;
+#else /* _UNICODE */
+ flags |= FL_WIDECHAR; /* ISO std. */
+#endif /* _UNICODE */
+ /* fall into 'c' case */
+
+ case _T('c'): {
+ /* print a single character specified by int argument */
+#ifdef _UNICODE
+ bufferiswide = 1;
+ wchar = (wchar_t) get_int_arg(&argptr);
+ if (flags & FL_SHORT) {
+ /* format multibyte character */
+ /* this is an extension of ANSI */
+ char tempchar[2];
+ {
+ tempchar[0] = (char)(wchar & 0x00ff);
+ tempchar[1] = '\0';
+ }
+
+ if (_MBTOWC(buffer.wz,tempchar, MB_CUR_MAX) < 0)
+ {
+ /* ignore if conversion was unsuccessful */
+ no_output = 1;
+ }
+ } else {
+ buffer.wz[0] = wchar;
+ }
+ text.wz = buffer.wz;
+ textlen = 1; /* print just a single character */
+#else /* _UNICODE */
+ if (flags & (FL_LONG|FL_WIDECHAR)) {
+ wchar = (wchar_t) get_int_arg(&argptr);
+ no_output = 1;
+ } else {
+ /* format multibyte character */
+ /* this is an extension of ANSI */
+ unsigned short temp;
+ wchar = (wchar_t)get_int_arg(&argptr);
+ temp = (unsigned short)wchar;
+ {
+ buffer.sz[0] = (char) temp;
+ textlen = 1;
+ }
+ }
+ text.sz = buffer.sz;
+#endif /* _UNICODE */
+ }
+ break;
+
+ case _T('Z'): {
+ /* print a Counted String */
+ struct _count_string {
+ short Length;
+ short MaximumLength;
+ char *Buffer;
+ } *pstr;
+
+ pstr = (struct _count_string *)get_ptr_arg(&argptr);
+ if (pstr == NULL || pstr->Buffer == NULL) {
+ /* null ptr passed, use special string */
+ text.sz = __nullstring;
+ textlen = (int)strlen(text.sz);
+ } else {
+ if (flags & FL_WIDECHAR) {
+ text.wz = (wchar_t *)pstr->Buffer;
+ textlen = pstr->Length / (int)sizeof(wchar_t);
+ bufferiswide = 1;
+ } else {
+ bufferiswide = 0;
+ text.sz = pstr->Buffer;
+ textlen = pstr->Length;
+ }
+ }
+ }
+ break;
+
+ case _T('S'): /* ISO wide character string */
+#ifndef _UNICODE
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+ flags |= FL_WIDECHAR;
+#else /* _UNICODE */
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+ flags |= FL_SHORT;
+#endif /* _UNICODE */
+
+ case _T('s'): {
+ /* print a string -- */
+ /* ANSI rules on how much of string to print: */
+ /* all if precision is default, */
+ /* min(precision, length) if precision given. */
+ /* prints '(null)' if a null string is passed */
+
+ int i;
+ const char *p; /* temps */
+ const wchar_t *pwch;
+
+ /* At this point it is tempting to use strlen(), but */
+ /* if a precision is specified, we're not allowed to */
+ /* scan past there, because there might be no null */
+ /* at all. Thus, we must do our own scan. */
+
+ i = (precision == -1) ? INT_MAX : precision;
+ text.sz = (char *)get_ptr_arg(&argptr);
+
+ /* scan for null upto i characters */
+#ifdef _UNICODE
+ if (flags & FL_SHORT) {
+ if (text.sz == NULL) /* NULL passed, use special string */
+ text.sz = __nullstring;
+ p = text.sz;
+ for (textlen=0; textlen<i && *p; textlen++) {
+ ++p;
+ }
+ /* textlen now contains length in multibyte chars */
+ } else {
+ if (text.wz == NULL) /* NULL passed, use special string */
+ text.wz = __wnullstring;
+ bufferiswide = 1;
+ pwch = text.wz;
+ while (i-- && *pwch)
+ ++pwch;
+ textlen = (int)(pwch - text.wz); /* in wchar_ts */
+ /* textlen now contains length in wide chars */
+ }
+#else /* _UNICODE */
+ if (flags & (FL_LONG|FL_WIDECHAR)) {
+ if (text.wz == NULL) /* NULL passed, use special string */
+ text.wz = __wnullstring;
+ bufferiswide = 1;
+ pwch = text.wz;
+ while ( i-- && *pwch )
+ ++pwch;
+ textlen = (int)(pwch - text.wz);
+ /* textlen now contains length in wide chars */
+ } else {
+ if (text.sz == NULL) /* NULL passed, use special string */
+ text.sz = __nullstring;
+ p = text.sz;
+ while (i-- && *p)
+ ++p;
+ textlen = (int)(p - text.sz); /* length of the string */
+ }
+
+#endif /* _UNICODE */
+ }
+ break;
+
+
+ case _T('n'): {
+ /* write count of characters seen so far into */
+ /* short/int/long thru ptr read from args */
+
+ void *p; /* temp */
+
+ p = get_ptr_arg(&argptr);
+
+ /* %n is disabled */
+ _VALIDATE_RETURN(("'n' format specifier disabled" && 0), EINVAL, -1);
+ break;
+
+ /* store chars out into short/long/int depending on flags */
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ *(long *)p = charsout;
+ else
+#endif /* !LONG_IS_INT */
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT)
+ *(short *)p = (short) charsout;
+ else
+#endif /* !SHORT_IS_INT */
+ *(int *)p = charsout;
+
+ no_output = 1; /* force no output */
+ }
+ break;
+
+ case _T('E'):
+ case _T('G'):
+ case _T('A'):
+ capexp = 1; /* capitalize exponent */
+ ch += _T('a') - _T('A'); /* convert format char to lower */
+ /* DROP THROUGH */
+ case _T('e'):
+ case _T('f'):
+ case _T('g'):
+ case _T('a'): {
+ /* floating point conversion -- we call cfltcvt routines */
+ /* to do the work for us. */
+ flags |= FL_SIGNED; /* floating point is signed conversion */
+ text.sz = buffer.sz; /* put result in buffer */
+ buffersize = BUFFERSIZE;
+
+ /* compute the precision value */
+ if (precision < 0)
+ precision = 6; /* default precision: 6 */
+ else if (precision == 0 && ch == _T('g'))
+ precision = 1; /* ANSI specified */
+ else if (precision > MAXPRECISION)
+ precision = MAXPRECISION;
+
+ if (precision > BUFFERSIZE - _CVTBUFSIZE) {
+ /* cap precision further */
+ precision = BUFFERSIZE - _CVTBUFSIZE;
+ }
+
+ /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */
+ if (flags & FL_ALTERNATE)
+ {
+ capexp |= FL_ALTERNATE;
+ }
+
+ _CRT_DOUBLE tmp;
+ tmp=va_arg(argptr, _CRT_DOUBLE);
+ /* Note: assumes ch is in ASCII range */
+ /* In safecrt, we provide a special version of _cfltcvt which internally calls printf (see safecrt_output_s.c) */
+ _CFLTCVT(&tmp, buffer.sz, buffersize, (char)ch, precision, capexp);
+
+ /* check if result was negative, save '-' for later */
+ /* and point to positive part (this is for '0' padding) */
+ if (*text.sz == '-') {
+ flags |= FL_NEGATIVE;
+ ++text.sz;
+ }
+
+ textlen = (int)strlen(text.sz); /* compute length of text */
+ }
+ break;
+
+ case _T('d'):
+ case _T('i'):
+ /* signed decimal output */
+ flags |= FL_SIGNED;
+ radix = 10;
+ goto COMMON_INT;
+
+ case _T('u'):
+ radix = 10;
+ goto COMMON_INT;
+
+ case _T('p'):
+ /* write a pointer -- this is like an integer or long */
+ /* except we force precision to pad with zeros and */
+ /* output in big hex. */
+
+ precision = 2 * sizeof(void *); /* number of hex digits needed */
+#if PTR_IS_INT64
+ flags |= FL_I64; /* assume we're converting an int64 */
+#elif !PTR_IS_INT
+ flags |= FL_LONG; /* assume we're converting a long */
+#endif /* !PTR_IS_INT */
+ /* DROP THROUGH to hex formatting */
+
+ case _T('X'):
+ /* unsigned upper hex output */
+ hexadd = _T('A') - _T('9') - 1; /* set hexadd for uppercase hex */
+ goto COMMON_HEX;
+
+ case _T('x'):
+ /* unsigned lower hex output */
+ hexadd = _T('a') - _T('9') - 1; /* set hexadd for lowercase hex */
+ /* DROP THROUGH TO COMMON_HEX */
+
+ COMMON_HEX:
+ radix = 16;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means '0x' prefix */
+ prefix[0] = _T('0');
+ prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd); /* 'x' or 'X' */
+ prefixlen = 2;
+ }
+ goto COMMON_INT;
+
+ case _T('o'):
+ /* unsigned octal output */
+ radix = 8;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means force a leading 0 */
+ flags |= FL_FORCEOCTAL;
+ }
+ /* DROP THROUGH to COMMON_INT */
+
+ COMMON_INT: {
+ /* This is the general integer formatting routine. */
+ /* Basically, we get an argument, make it positive */
+ /* if necessary, and convert it according to the */
+ /* correct radix, setting text and textlen */
+ /* appropriately. */
+
+#if _INTEGRAL_MAX_BITS >= 64
+ uint64_t number; /* number to convert */
+ int digit; /* ascii value of digit */
+ __int64 l; /* temp long value */
+#else /* _INTEGRAL_MAX_BITS >= 64 */
+ unsigned long number; /* number to convert */
+ int digit; /* ascii value of digit */
+ long l; /* temp long value */
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ /* 1. read argument into l, sign extend as needed */
+#if _INTEGRAL_MAX_BITS >= 64
+ if (flags & FL_I64)
+ l = get_int64_arg(&argptr);
+ else
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ if (flags & FL_LONGLONG)
+ l = get_long_long_arg(&argptr);
+
+ else
+
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ l = get_long_arg(&argptr);
+ else
+#endif /* !LONG_IS_INT */
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT) {
+ if (flags & FL_SIGNED)
+ l = (short) get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/
+
+ } else
+#endif /* !SHORT_IS_INT */
+ {
+ if (flags & FL_SIGNED)
+ l = get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/
+ }
+
+ /* 2. check for negative; copy into number */
+ if ( (flags & FL_SIGNED) && l < 0) {
+ number = -l;
+ flags |= FL_NEGATIVE; /* remember negative sign */
+ } else {
+ number = l;
+ }
+
+#if _INTEGRAL_MAX_BITS >= 64
+ if ( (flags & FL_I64) == 0 && (flags & FL_LONGLONG) == 0 ) {
+ /*
+ * Unless printing a full 64-bit value, insure values
+ * here are not in cananical longword format to prevent
+ * the sign extended upper 32-bits from being printed.
+ */
+ number &= 0xffffffff;
+ }
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ /* 3. check precision value for default; non-default */
+ /* turns off 0 flag, according to ANSI. */
+ if (precision < 0)
+ precision = 1; /* default precision */
+ else {
+ flags &= ~FL_LEADZERO;
+ if (precision > MAXPRECISION)
+ precision = MAXPRECISION;
+ }
+
+ /* 4. Check if data is 0; if so, turn off hex prefix */
+ if (number == 0)
+ prefixlen = 0;
+
+ /* 5. Convert data to ASCII -- note if precision is zero */
+ /* and number is zero, we get no digits at all. */
+
+ char *sz;
+ sz = &buffer.sz[BUFFERSIZE-1]; /* last digit at end of buffer */
+
+ while (precision-- > 0 || number != 0) {
+ digit = (int)(number % radix) + '0';
+ number /= radix; /* reduce number */
+ if (digit > '9') {
+ /* a hex digit, make it a letter */
+ digit += hexadd;
+ }
+ *sz-- = (char)digit; /* store the digit */
+ }
+
+ textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - sz); /* compute length of number */
+ ++sz; /* text points to first digit now */
+
+
+ /* 6. Force a leading zero if FORCEOCTAL flag set */
+ if ((flags & FL_FORCEOCTAL) && (textlen == 0 || sz[0] != '0')) {
+ *--sz = '0';
+ ++textlen; /* add a zero */
+ }
+
+ text.sz = sz;
+ }
+ break;
+ }
+
+
+ /* At this point, we have done the specific conversion, and */
+ /* 'text' points to text to print; 'textlen' is length. Now we */
+ /* justify it, put on prefixes, leading zeros, and then */
+ /* print it. */
+
+ if (!no_output) {
+ int padding; /* amount of padding, negative means zero */
+
+ if (flags & FL_SIGNED) {
+ if (flags & FL_NEGATIVE) {
+ /* prefix is a '-' */
+ prefix[0] = _T('-');
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGN) {
+ /* prefix is '+' */
+ prefix[0] = _T('+');
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGNSP) {
+ /* prefix is ' ' */
+ prefix[0] = _T(' ');
+ prefixlen = 1;
+ }
+ }
+
+ /* calculate amount of padding -- might be negative, */
+ /* but this will just mean zero */
+ padding = fldwidth - textlen - prefixlen;
+
+ /* put out the padding, prefix, and text, in the correct order */
+
+ if (!(flags & (FL_LEFT | FL_LEADZERO))) {
+ /* pad on left with blanks */
+ WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
+ }
+
+ /* write prefix */
+ WRITE_STRING(prefix, prefixlen, &charsout);
+
+ if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
+ /* write leading zeros */
+ WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
+ }
+
+ /* write text */
+#ifndef _UNICODE
+ if (bufferiswide && (textlen > 0)) {
+ charsout = -1;
+ } else {
+ WRITE_STRING(text.sz, textlen, &charsout);
+ }
+#else /* _UNICODE */
+ if (!bufferiswide && textlen > 0) {
+ const char *p;
+ int retval = 0;
+ int count;
+
+ p = text.sz;
+ count = textlen;
+ while (count-- > 0) {
+ retval = _MBTOWC(&wchar, p, MB_CUR_MAX);
+ if (retval <= 0) {
+ charsout = -1;
+ break;
+ }
+ WRITE_CHAR(wchar, &charsout);
+ p += retval;
+ }
+ } else {
+ WRITE_STRING(text.wz, textlen, &charsout);
+ }
+#endif /* _UNICODE */
+
+ if (charsout >= 0 && (flags & FL_LEFT)) {
+ /* pad on right with blanks */
+ WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
+ }
+
+ /* we're done! */
+ }
+ break;
+ case ST_INVALID:
+ _VALIDATE_RETURN(0 /* FALSE */, EINVAL, -1);
+ break;
+ }
+ }
+
+#ifdef FORMAT_VALIDATIONS
+ /* The format string shouldn't be incomplete - i.e. when we are finished
+ with the format string, the last thing we should have encountered
+ should have been a regular char to be output or a type specifier. Else
+ the format string was incomplete */
+ _VALIDATE_RETURN(((state == ST_NORMAL) || (state == ST_TYPE)), EINVAL, -1);
+#endif /* FORMAT_VALIDATIONS */
+
+ return charsout; /* return value = number of characters written */
+}
+
+/*
+ * Future Optimizations for swprintf:
+ * - Don't free the memory used for converting the buffer to wide chars.
+ * Use realloc if the memory is not sufficient. Free it at the end.
+ */
+
+/***
+*void write_char(char ch, int *pnumwritten)
+*ifdef _UNICODE
+*void write_char(wchar_t ch, FILE *f, int *pnumwritten)
+*endif
+*void write_char(char ch, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes a single character to the given file/console. If no error occurs,
+* then *pnumwritten is incremented; otherwise, *pnumwritten is set
+* to -1.
+*
+*Entry:
+* _TCHAR ch - character to write
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+
+LOCAL(void) write_char (
+ _TCHAR ch,
+ int *pnumwritten
+ )
+{
+#ifdef _UNICODE
+ if (_putwch_nolock(ch) == WEOF)
+#else /* _UNICODE */
+ if (_putch_nolock(ch) == EOF)
+#endif /* _UNICODE */
+ *pnumwritten = -1;
+ else
+ ++(*pnumwritten);
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_char (
+ _TCHAR ch,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ if ( (f->_flag & _IOSTRG) && f->_base == NULL)
+ {
+ ++(*pnumwritten);
+ return;
+ }
+#ifdef _UNICODE
+ if (_putwc_nolock(ch, f) == WEOF)
+#else /* _UNICODE */
+ if (_putc_nolock(ch, f) == EOF)
+#endif /* _UNICODE */
+ *pnumwritten = -1;
+ else
+ ++(*pnumwritten);
+}
+
+#endif /* CPRFLAG */
+
+/***
+*void write_multi_char(char ch, int num, int *pnumwritten)
+*ifdef _UNICODE
+*void write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten)
+*endif
+*void write_multi_char(char ch, int num, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes num copies of a character to the given file/console. If no error occurs,
+* then *pnumwritten is incremented by num; otherwise, *pnumwritten is set
+* to -1. If num is negative, it is treated as zero.
+*
+*Entry:
+* _TCHAR ch - character to write
+* int num - number of times to write the characters
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+LOCAL(void) write_multi_char (
+ _TCHAR ch,
+ int num,
+ int *pnumwritten
+ )
+{
+ while (num-- > 0) {
+ write_char(ch, pnumwritten);
+ if (*pnumwritten == -1)
+ break;
+ }
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_multi_char (
+ _TCHAR ch,
+ int num,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ while (num-- > 0) {
+ write_char(ch, f, pnumwritten);
+ if (*pnumwritten == -1)
+ break;
+ }
+}
+
+#endif /* CPRFLAG */
+
+/***
+*void write_string(const char *string, int len, int *pnumwritten)
+*void write_string(const char *string, int len, FILE *f, int *pnumwritten)
+*ifdef _UNICODE
+*void write_string(const wchar_t *string, int len, FILE *f, int *pnumwritten)
+*endif
+*
+*Purpose:
+* Writes a string of the given length to the given file. If no error occurs,
+* then *pnumwritten is incremented by len; otherwise, *pnumwritten is set
+* to -1. If len is negative, it is treated as zero.
+*
+*Entry:
+* _TCHAR *string - string to write (NOT null-terminated)
+* int len - length of string
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+
+LOCAL(void) write_string (
+ const _TCHAR *string,
+ int len,
+ int *pnumwritten
+ )
+{
+ while (len-- > 0) {
+ write_char(*string++, pnumwritten);
+ if (*pnumwritten == -1)
+ {
+ if (errno == EILSEQ)
+ write_char(_T('?'), pnumwritten);
+ else
+ break;
+ }
+ }
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_string (
+ const _TCHAR *string,
+ int len,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ if ( (f->_flag & _IOSTRG) && f->_base == NULL)
+ {
+ (*pnumwritten) += len;
+ return;
+ }
+ while (len-- > 0) {
+ write_char(*string++, f, pnumwritten);
+ if (*pnumwritten == -1)
+ {
+ if (errno == EILSEQ)
+ write_char(_T('?'), f, pnumwritten);
+ else
+ break;
+ }
+ }
+}
+#endif /* CPRFLAG */
diff --git a/src/pal/src/safecrt/safecrt_input_s.c b/src/pal/src/safecrt/safecrt_input_s.c
new file mode 100644
index 0000000000..6ba607c669
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_input_s.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_input_s.c - implementation of the _input family for safecrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _input family for safecrt.lib.
+*
+*Revision History:
+* 07/19/04 AC Created
+*
+****/
+
+#define _SAFECRT_IMPL
+#define _SECURE_SCANF
+
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _TCHAR CRT_TCHAR
+#define TCHAR CRTTCHAR
+
+typedef char _TCHAR;
+typedef char TCHAR;
+typedef unsigned char _TUCHAR;
+#define _T(x) x
+#define _TEOF EOF
+
+#define _gettc_nolock(x) _getc_nolock(x)
+#define _ungettc_nolock(x,y) _ungetc_nolock(x,y)
+
+#include "input.inl"
diff --git a/src/pal/src/safecrt/safecrt_output_l.c b/src/pal/src/safecrt/safecrt_output_l.c
new file mode 100644
index 0000000000..d6844f4f8b
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_output_l.c
@@ -0,0 +1,1467 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_output_l.c - implementation of the _output family for safercrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _output family for safercrt.lib.
+*
+*Revision History:
+* 07-08-04 SJ Stub module created.
+* 07-13-04 AC Added support for floating-point types.
+* 07-29-04 AC Added macros for a safecrt version of mctowc and wctomb, which target ntdll.dll or msvcrt.dll
+* based on the _NTSUBSET_ #define
+* 09-24-04 MSL Prefix disallow NULL deref
+*
+****/
+
+#define _SAFECRT_IMPL
+
+#define __STDC_LIMIT_MACROS
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _CFLTCVT _safecrt_cfltcvt
+
+//typedef __int64_t __int64;
+typedef double _CRT_DOUBLE;
+typedef char _TCHAR;
+typedef char TCHAR;
+#define _T(x) x
+/*
+Buffer size required to be passed to _gcvt, fcvt and other fp conversion routines
+*/
+#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */
+
+//------------------------------------------------------------------------------
+// This code was taken from the 'ouput.c' file located in Visual Studio 8 (i.e. 2005)
+// in the '\Microsoft Visual Studio 8\VC\crt\src' directory. It was moved into
+// this file to support only the '_output' function used by _vscprintf() in vsprintf.c
+// UNUSED / NON-RELEVANT PORTIONS OF THE CODE HAVE BEEN REMOVED - do not try and
+// use it to generate any other safecrt 'output' functions
+//
+// Noteable modifications
+// - changed FILE to miniFILE (defined in mbusafecrt_internal.h)
+// - removed _soutput_s - it was unused in this case and conflicted with output.inl
+// - changed #define SHORT_IS_INT to true varargs promotes shorts to ints in GCC
+// - removed definition of __lookuptable_s when using FORMAT_VALIDATIONS, we don't use them
+
+// 7/03/07 - Created by Stephen Shaw (steshaw)
+//------------------------------------------------------------------------------
+
+
+/* temporary work-around for compiler without 64-bit support */
+#ifndef _INTEGRAL_MAX_BITS
+#define _INTEGRAL_MAX_BITS 64
+#endif /* _INTEGRAL_MAX_BITS */
+
+#include <limits.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y )
+
+#undef _malloc_crt
+#define _malloc_crt malloc
+
+#undef _free_crt
+#define _free_crt free
+
+// SNIP -srs 7/3/07
+
+#ifndef _CFLTCVT
+#define _CFLTCVT _cfltcvt
+#endif /* _CFLTCVT */
+
+#ifndef _CLDCVT
+#define _CLDCVT _cldcvt
+#endif /* _CLDCVT */
+
+#ifdef _MBCS
+#undef _MBCS
+#endif /* _MBCS */
+//#include <tchar.h>
+
+/* this macro defines a function which is private and as fast as possible: */
+/* for example, in C 6.0, it might be static _fastcall <type> near. */
+#define LOCAL(x) static x __cdecl
+
+/* int/long/short/pointer sizes */
+
+/* the following should be set depending on the sizes of various types */
+#if __LP64__
+ #define LONG_IS_INT 0
+ CASSERT(sizeof(long) > sizeof(int));
+#else
+ #define LONG_IS_INT 1 /* 1 means long is same size as int */
+ CASSERT(sizeof(long) == sizeof(int));
+#endif
+
+// GCC: short is not int, but GCC promotes va_arg to int
+#define SHORT_IS_INT 1
+
+#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64 */
+ CASSERT(sizeof(long long) == sizeof(int64_t));
+
+#if defined (_WIN64)
+ #define PTR_IS_INT 0 /* 1 means ptr is same size as int */
+ CASSERT(sizeof(void *) != sizeof(int));
+ #if __LP64__
+ #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) == sizeof(long));
+ #else
+ #define PTR_IS_LONG 0 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) != sizeof(long));
+ #endif
+ #define PTR_IS_INT64 1 /* 1 means ptr is same size as int64 */
+ CASSERT(sizeof(void *) == sizeof(int64_t));
+#else /* defined (_WIN64) */
+ #define PTR_IS_INT 1 /* 1 means ptr is same size as int */
+ CASSERT(sizeof(void *) == sizeof(int));
+ #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) == sizeof(long));
+ #define PTR_IS_INT64 0 /* 1 means ptr is same size as int64 */
+ CASSERT(sizeof(void *) != sizeof(int64_t));
+#endif /* defined (_WIN64) */
+
+/* CONSTANTS */
+
+/* size of conversion buffer (ANSI-specified minimum is 509) */
+
+#define BUFFERSIZE 512
+#define MAXPRECISION BUFFERSIZE
+
+#if BUFFERSIZE < _CVTBUFSIZE + 6
+/*
+ * Buffer needs to be big enough for default minimum precision
+ * when converting floating point needs bigger buffer, and malloc
+ * fails
+ */
+#error Conversion buffer too small for max double.
+#endif /* BUFFERSIZE < _CVTBUFSIZE + 6 */
+
+/* flag definitions */
+#define FL_SIGN 0x00001 /* put plus or minus in front */
+#define FL_SIGNSP 0x00002 /* put space or minus in front */
+#define FL_LEFT 0x00004 /* left justify */
+#define FL_LEADZERO 0x00008 /* pad with leading zeros */
+#define FL_LONG 0x00010 /* long value given */
+#define FL_SHORT 0x00020 /* short value given */
+#define FL_SIGNED 0x00040 /* signed data given */
+#define FL_ALTERNATE 0x00080 /* alternate form requested */
+#define FL_NEGATIVE 0x00100 /* value is negative */
+#define FL_FORCEOCTAL 0x00200 /* force leading '0' for octals */
+#define FL_LONGDOUBLE 0x00400 /* long double value given */
+#define FL_WIDECHAR 0x00800 /* wide characters */
+#define FL_LONGLONG 0x01000 /* long long value given */
+#define FL_I64 0x08000 /* __int64 value given */
+
+/* state definitions */
+enum STATE {
+ ST_NORMAL, /* normal state; outputting literal chars */
+ ST_PERCENT, /* just read '%' */
+ ST_FLAG, /* just read flag character */
+ ST_WIDTH, /* just read width specifier */
+ ST_DOT, /* just read '.' */
+ ST_PRECIS, /* just read precision specifier */
+ ST_SIZE, /* just read size specifier */
+ ST_TYPE /* just read type specifier */
+#ifdef FORMAT_VALIDATIONS
+ ,ST_INVALID /* Invalid format */
+#endif /* FORMAT_VALIDATIONS */
+
+};
+
+#ifdef FORMAT_VALIDATIONS
+#define NUMSTATES (ST_INVALID + 1)
+#else /* FORMAT_VALIDATIONS */
+#define NUMSTATES (ST_TYPE + 1)
+#endif /* FORMAT_VALIDATIONS */
+
+/* character type values */
+enum CHARTYPE {
+ CH_OTHER, /* character with no special meaning */
+ CH_PERCENT, /* '%' */
+ CH_DOT, /* '.' */
+ CH_STAR, /* '*' */
+ CH_ZERO, /* '0' */
+ CH_DIGIT, /* '1'..'9' */
+ CH_FLAG, /* ' ', '+', '-', '#' */
+ CH_SIZE, /* 'h', 'l', 'L', 'N', 'F', 'w' */
+ CH_TYPE /* type specifying character */
+};
+
+/* static data (read only, since we are re-entrant) */
+#if defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS)
+extern const char __nullstring[]; /* string to print on null ptr */
+extern const wchar_t __wnullstring[]; /* string to print on null ptr */
+#else /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
+static const char __nullstring[] = "(null)"; /* string to print on null ptr */
+static const wchar_t __wnullstring[] = { '(', 'n', 'u', 'l', 'l', ')', '\0' };/* string to print on null ptr */
+#endif /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
+
+/* The state table. This table is actually two tables combined into one. */
+/* The lower nybble of each byte gives the character class of any */
+/* character; while the uper nybble of the byte gives the next state */
+/* to enter. See the macros below the table for details. */
+/* */
+/* The table is generated by maketabc.c -- use this program to make */
+/* changes. */
+
+#ifndef FORMAT_VALIDATIONS
+#if defined (_UNICODE) || defined (CPRFLAG)
+extern const char __lookuptable[];
+#else /* defined (_UNICODE) || defined (CPRFLAG) */
+//extern const char __lookuptable[] = {
+const char __lookuptable[] = {
+ /* ' ' */ 0x06,
+ /* '!' */ 0x00,
+ /* '"' */ 0x00,
+ /* '#' */ 0x06,
+ /* '$' */ 0x00,
+ /* '%' */ 0x01,
+ /* '&' */ 0x00,
+ /* ''' */ 0x00,
+ /* '(' */ 0x10,
+ /* ')' */ 0x00,
+ /* '*' */ 0x03,
+ /* '+' */ 0x06,
+ /* ',' */ 0x00,
+ /* '-' */ 0x06,
+ /* '.' */ 0x02,
+ /* '/' */ 0x10,
+ /* '0' */ 0x04,
+ /* '1' */ 0x45,
+ /* '2' */ 0x45,
+ /* '3' */ 0x45,
+ /* '4' */ 0x05,
+ /* '5' */ 0x05,
+ /* '6' */ 0x05,
+ /* '7' */ 0x05,
+ /* '8' */ 0x05,
+ /* '9' */ 0x35,
+ /* ':' */ 0x30,
+ /* ';' */ 0x00,
+ /* '<' */ 0x50,
+ /* '=' */ 0x00,
+ /* '>' */ 0x00,
+ /* '?' */ 0x00,
+ /* '@' */ 0x00,
+ /* 'A' */ 0x20, // Disable %A format
+ /* 'B' */ 0x20,
+ /* 'C' */ 0x38,
+ /* 'D' */ 0x50,
+ /* 'E' */ 0x58,
+ /* 'F' */ 0x07,
+ /* 'G' */ 0x08,
+ /* 'H' */ 0x00,
+ /* 'I' */ 0x37,
+ /* 'J' */ 0x30,
+ /* 'K' */ 0x30,
+ /* 'L' */ 0x57,
+ /* 'M' */ 0x50,
+ /* 'N' */ 0x07,
+ /* 'O' */ 0x00,
+ /* 'P' */ 0x00,
+ /* 'Q' */ 0x20,
+ /* 'R' */ 0x20,
+ /* 'S' */ 0x08,
+ /* 'T' */ 0x00,
+ /* 'U' */ 0x00,
+ /* 'V' */ 0x00,
+ /* 'W' */ 0x00,
+ /* 'X' */ 0x08,
+ /* 'Y' */ 0x60,
+ /* 'Z' */ 0x68,
+ /* '[' */ 0x60,
+ /* '\' */ 0x60,
+ /* ']' */ 0x60,
+ /* '^' */ 0x60,
+ /* '_' */ 0x00,
+ /* '`' */ 0x00,
+ /* 'a' */ 0x70, // Disable %a format
+ /* 'b' */ 0x70,
+ /* 'c' */ 0x78,
+ /* 'd' */ 0x78,
+ /* 'e' */ 0x78,
+ /* 'f' */ 0x78,
+ /* 'g' */ 0x08,
+ /* 'h' */ 0x07,
+ /* 'i' */ 0x08,
+ /* 'j' */ 0x00,
+ /* 'k' */ 0x00,
+ /* 'l' */ 0x07,
+ /* 'm' */ 0x00,
+ /* 'n' */ 0x00, // Disable %n format
+ /* 'o' */ 0x08,
+ /* 'p' */ 0x08,
+ /* 'q' */ 0x00,
+ /* 'r' */ 0x00,
+ /* 's' */ 0x08,
+ /* 't' */ 0x00,
+ /* 'u' */ 0x08,
+ /* 'v' */ 0x00,
+ /* 'w' */ 0x07,
+ /* 'x' */ 0x08
+};
+
+#endif /* defined (_UNICODE) || defined (CPRFLAG) */
+
+#else /* FORMAT_VALIDATIONS */
+// SNIP -srs 7/3/07
+#error code has been removed
+#endif /* FORMAT_VALIDATIONS */
+
+#define FIND_CHAR_CLASS(lookuptbl, c) \
+ ((c) < _T(' ') || (c) > _T('x') ? \
+ CH_OTHER \
+ : \
+ (enum CHARTYPE)(lookuptbl[(c)-_T(' ')] & 0xF))
+
+#define FIND_NEXT_STATE(lookuptbl, class, state) \
+ (enum STATE)(lookuptbl[(class) * NUMSTATES + (state)] >> 4)
+
+/*
+ * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive.
+ */
+
+/* prototypes */
+
+#ifdef CPRFLAG
+
+#define WRITE_CHAR(ch, pnw) write_char(ch, pnw)
+#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, pnw)
+#define WRITE_STRING(s, len, pnw) write_string(s, len, pnw)
+#define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, pnw)
+
+LOCAL(void) write_char(_TCHAR ch, int *pnumwritten);
+LOCAL(void) write_multi_char(_TCHAR ch, int num, int *pnumwritten);
+LOCAL(void) write_string(const _TCHAR *string, int len, int *numwritten);
+LOCAL(void) write_wstring(const wchar_t *string, int len, int *numwritten);
+
+#else /* CPRFLAG */
+
+#define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw)
+#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw)
+#define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw)
+#define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, stream, pnw)
+
+LOCAL(void) write_char(_TCHAR ch, miniFILE *f, int *pnumwritten);
+LOCAL(void) write_multi_char(_TCHAR ch, int num, miniFILE *f, int *pnumwritten);
+LOCAL(void) write_string(const _TCHAR *string, int len, miniFILE *f, int *numwritten);
+//LOCAL(void) write_wstring(const wchar_t *string, int len, miniFILE *f, int *numwritten);
+
+#endif /* CPRFLAG */
+
+#define get_short_arg(list) va_arg(*list, int) // GCC promotes va_arg shorts into int values
+#define get_int_arg(list) va_arg(*list, int)
+#define get_long_arg(list) va_arg(*list, long)
+#define get_long_long_arg(list) va_arg(*list, long long)
+#define get_int64_arg(list) va_arg(*list, __int64)
+#define get_crtdouble_arg(list) va_arg(*list, _CRT_DOUBLE)
+#define get_ptr_arg(list) va_arg(*list, void *)
+
+#ifdef CPRFLAG
+LOCAL(int) output(const _TCHAR *, _locale_t , va_list);
+_CRTIMP int __cdecl _vtcprintf_l (const _TCHAR *, _locale_t, va_list);
+_CRTIMP int __cdecl _vtcprintf_s_l (const _TCHAR *, _locale_t, va_list);
+_CRTIMP int __cdecl _vtcprintf_p_l (const _TCHAR *, _locale_t, va_list);
+
+
+/***
+*int _cprintf(format, arglist) - write formatted output directly to console
+*
+*Purpose:
+* Writes formatted data like printf, but uses console I/O functions.
+*
+*Entry:
+* char *format - format string to determine data formats
+* arglist - list of POINTERS to where to put data
+*
+*Exit:
+* returns number of characters written
+*
+*Exceptions:
+*
+*******************************************************************************/
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _tcprintf_l (
+ const _TCHAR * format,
+ _locale_t plocinfo,
+ ...
+ )
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _tcprintf_s_l (
+ const _TCHAR * format,
+ _locale_t plocinfo,
+ ...
+ )
+#endif /* FORMAT_VALIDATIONS */
+
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, plocinfo);
+
+#ifndef FORMAT_VALIDATIONS
+ ret = _vtcprintf_l(format, plocinfo, arglist);
+#else /* FORMAT_VALIDATIONS */
+ ret = _vtcprintf_s_l(format, plocinfo, arglist);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ va_end(arglist);
+
+ return ret;
+}
+
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _tcprintf (
+ const _TCHAR * format,
+ ...
+ )
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _tcprintf_s (
+ const _TCHAR * format,
+ ...
+ )
+#endif /* FORMAT_VALIDATIONS */
+
+{
+ int ret;
+ va_list arglist;
+
+ va_start(arglist, format);
+
+#ifndef FORMAT_VALIDATIONS
+ ret = _vtcprintf_l(format, NULL, arglist);
+#else /* FORMAT_VALIDATIONS */
+ ret = _vtcprintf_s_l(format, NULL, arglist);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ va_end(arglist);
+
+ return ret;
+}
+
+#endif /* CPRFLAG */
+
+
+/***
+*int _output(stream, format, argptr), static int output(format, argptr)
+*
+*Purpose:
+* Output performs printf style output onto a stream. It is called by
+* printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
+* work. In multi-thread situations, _output assumes that the given
+* stream is already locked.
+*
+* Algorithm:
+* The format string is parsed by using a finite state automaton
+* based on the current state and the current character read from
+* the format string. Thus, looping is on a per-character basis,
+* not a per conversion specifier basis. Once the format specififying
+* character is read, output is performed.
+*
+*Entry:
+* FILE *stream - stream for output
+* char *format - printf style format string
+* va_list argptr - pointer to list of subsidiary arguments
+*
+*Exit:
+* Returns the number of characters written, or -1 if an output error
+* occurs.
+*ifdef _UNICODE
+* The wide-character flavour returns the number of wide-characters written.
+*endif
+*
+*Exceptions:
+*
+*******************************************************************************/
+#ifdef CPRFLAG
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _vtcprintf (
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ return _vtcprintf_l(format, NULL, argptr);
+}
+
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _vtcprintf_s (
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ return _vtcprintf_s_l(format, NULL, argptr);
+}
+
+#endif /* FORMAT_VALIDATIONS */
+#endif /* CPRFLAG */
+
+#ifdef CPRFLAG
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _vtcprintf_l (
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _vtcprintf_s_l (
+#endif /* FORMAT_VALIDATIONS */
+#else /* CPRFLAG */
+
+#ifdef _UNICODE
+#ifndef FORMAT_VALIDATIONS
+int __cdecl _woutput (
+ miniFILE *stream,
+#else /* FORMAT_VALIDATIONS */
+int __cdecl _woutput_s (
+ miniFILE *stream,
+#endif /* FORMAT_VALIDATIONS */
+#else /* _UNICODE */
+#ifndef FORMAT_VALIDATIONS
+int __cdecl _output (
+ miniFILE *stream,
+#else /* FORMAT_VALIDATIONS */
+ int __cdecl _output_s (
+ miniFILE *stream,
+
+#endif /* FORMAT_VALIDATIONS */
+#endif /* _UNICODE */
+
+#endif /* CPRFLAG */
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ int hexadd=0; /* offset to add to number to get 'a'..'f' */
+ TCHAR ch; /* character just read */
+ int flags=0; /* flag word -- see #defines above for flag values */
+ enum STATE state; /* current state */
+ enum CHARTYPE chclass; /* class of current character */
+ int radix; /* current conversion radix */
+ int charsout; /* characters currently written so far, -1 = IO error */
+ int fldwidth = 0; /* selected field width -- 0 means default */
+ int precision = 0; /* selected precision -- -1 means default */
+ TCHAR prefix[2]; /* numeric prefix -- up to two characters */
+ int prefixlen=0; /* length of prefix -- 0 means no prefix */
+ int capexp = 0; /* non-zero = 'E' exponent signifient, zero = 'e' */
+ int no_output=0; /* non-zero = prodcue no output for this specifier */
+ union {
+ const char *sz; /* pointer text to be printed, not zero terminated */
+ const wchar_t *wz;
+ } text;
+
+ int textlen; /* length of the text in bytes/wchars to be printed.
+ textlen is in multibyte or wide chars if _UNICODE */
+ union {
+ char sz[BUFFERSIZE];
+#ifdef _UNICODE
+ wchar_t wz[BUFFERSIZE];
+#endif /* _UNICODE */
+ } buffer;
+ wchar_t wchar; /* temp wchar_t */
+ int buffersize; /* size of text.sz (used only for the call to _cfltcvt) */
+ int bufferiswide=0; /* non-zero = buffer contains wide chars already */
+
+#ifndef CPRFLAG
+ _VALIDATE_RETURN( (stream != NULL), EINVAL, -1);
+#endif /* CPRFLAG */
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ charsout = 0; /* no characters written yet */
+ textlen = 0; /* no text yet */
+ state = ST_NORMAL; /* starting state */
+ buffersize = 0;
+
+ /* main loop -- loop while format character exist and no I/O errors */
+ while ((ch = *format++) != _T('\0') && charsout >= 0) {
+#ifndef FORMAT_VALIDATIONS
+ chclass = FIND_CHAR_CLASS(__lookuptable, ch); /* find character class */
+ state = FIND_NEXT_STATE(__lookuptable, chclass, state); /* find next state */
+#else /* FORMAT_VALIDATIONS */
+ chclass = FIND_CHAR_CLASS(__lookuptable_s, ch); /* find character class */
+ state = FIND_NEXT_STATE(__lookuptable_s, chclass, state); /* find next state */
+
+ _VALIDATE_RETURN((state != ST_INVALID), EINVAL, -1);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ /* execute code for each state */
+ switch (state) {
+
+ case ST_NORMAL:
+
+ NORMAL_STATE:
+
+ /* normal state -- just write character */
+#ifdef _UNICODE
+ bufferiswide = 1;
+#else /* _UNICODE */
+ bufferiswide = 0;
+#endif /* _UNICODE */
+ WRITE_CHAR(ch, &charsout);
+ break;
+
+ case ST_PERCENT:
+ /* set default value of conversion parameters */
+ prefixlen = fldwidth = no_output = capexp = 0;
+ flags = 0;
+ precision = -1;
+ bufferiswide = 0; /* default */
+ break;
+
+ case ST_FLAG:
+ /* set flag based on which flag character */
+ switch (ch) {
+ case _T('-'):
+ flags |= FL_LEFT; /* '-' => left justify */
+ break;
+ case _T('+'):
+ flags |= FL_SIGN; /* '+' => force sign indicator */
+ break;
+ case _T(' '):
+ flags |= FL_SIGNSP; /* ' ' => force sign or space */
+ break;
+ case _T('#'):
+ flags |= FL_ALTERNATE; /* '#' => alternate form */
+ break;
+ case _T('0'):
+ flags |= FL_LEADZERO; /* '0' => pad with leading zeros */
+ break;
+ }
+ break;
+
+ case ST_WIDTH:
+ /* update width value */
+ if (ch == _T('*')) {
+ /* get width from arg list */
+ fldwidth = get_int_arg(&argptr);
+ if (fldwidth < 0) {
+ /* ANSI says neg fld width means '-' flag and pos width */
+ flags |= FL_LEFT;
+ fldwidth = -fldwidth;
+ }
+ }
+ else {
+ /* add digit to current field width */
+ fldwidth = fldwidth * 10 + (ch - _T('0'));
+ }
+ break;
+
+ case ST_DOT:
+ /* zero the precision, since dot with no number means 0
+ not default, according to ANSI */
+ precision = 0;
+ break;
+
+ case ST_PRECIS:
+ /* update precison value */
+ if (ch == _T('*')) {
+ /* get precision from arg list */
+ precision = get_int_arg(&argptr);
+ if (precision < 0)
+ precision = -1; /* neg precision means default */
+ }
+ else {
+ /* add digit to current precision */
+ precision = precision * 10 + (ch - _T('0'));
+ }
+ break;
+
+ case ST_SIZE:
+ /* just read a size specifier, set the flags based on it */
+ switch (ch) {
+ case _T('l'):
+ /*
+ * In order to handle the ll case, we depart from the
+ * simple deterministic state machine.
+ */
+ if (*format == _T('l'))
+ {
+ ++format;
+ flags |= FL_LONGLONG; /* 'll' => long long */
+ }
+ else
+ {
+ flags |= FL_LONG; /* 'l' => long int or wchar_t */
+ }
+ break;
+
+ case _T('I'):
+ /*
+ * In order to handle the I, I32, and I64 size modifiers, we
+ * depart from the simple deterministic state machine. The
+ * code below scans for characters following the 'I',
+ * and defaults to 64 bit on WIN64 and 32 bit on WIN32
+ */
+#if PTR_IS_INT64
+ flags |= FL_I64; /* 'I' => __int64 on WIN64 systems */
+#endif /* PTR_IS_INT64 */
+ if ( (*format == _T('6')) && (*(format + 1) == _T('4')) )
+ {
+ format += 2;
+ flags |= FL_I64; /* I64 => __int64 */
+ }
+ else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) )
+ {
+ format += 2;
+ flags &= ~FL_I64; /* I32 => __int32 */
+ }
+ else if ( (*format == _T('d')) ||
+ (*format == _T('i')) ||
+ (*format == _T('o')) ||
+ (*format == _T('u')) ||
+ (*format == _T('x')) ||
+ (*format == _T('X')) )
+ {
+ /*
+ * Nothing further needed. %Id (et al) is
+ * handled just like %d, except that it defaults to 64 bits
+ * on WIN64. Fall through to the next iteration.
+ */
+ }
+ else {
+ state = ST_NORMAL;
+ goto NORMAL_STATE;
+ }
+ break;
+
+ case _T('h'):
+ flags |= FL_SHORT; /* 'h' => short int or char */
+ break;
+
+ case _T('w'):
+ flags |= FL_WIDECHAR; /* 'w' => wide character */
+ break;
+
+ }
+ break;
+
+ case ST_TYPE:
+ /* we have finally read the actual type character, so we */
+ /* now format and "print" the output. We use a big switch */
+ /* statement that sets 'text' to point to the text that should */
+ /* be printed, and 'textlen' to the length of this text. */
+ /* Common code later on takes care of justifying it and */
+ /* other miscellaneous chores. Note that cases share code, */
+ /* in particular, all integer formatting is done in one place. */
+ /* Look at those funky goto statements! */
+
+ switch (ch) {
+
+ case _T('C'): /* ISO wide character */
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+#ifdef _UNICODE
+ flags |= FL_SHORT;
+#else /* _UNICODE */
+ flags |= FL_WIDECHAR; /* ISO std. */
+#endif /* _UNICODE */
+ /* fall into 'c' case */
+
+ case _T('c'): {
+ /* print a single character specified by int argument */
+#ifdef _UNICODE
+ bufferiswide = 1;
+ wchar = (wchar_t) get_int_arg(&argptr);
+ if (flags & FL_SHORT) {
+ /* format multibyte character */
+ /* this is an extension of ANSI */
+ char tempchar[2];
+ {
+ tempchar[0] = (char)(wchar & 0x00ff);
+ tempchar[1] = '\0';
+ }
+
+ if (_MBTOWC(buffer.wz,tempchar, MB_CUR_MAX) < 0)
+ {
+ /* ignore if conversion was unsuccessful */
+ no_output = 1;
+ }
+ } else {
+ buffer.wz[0] = wchar;
+ }
+ text.wz = buffer.wz;
+ textlen = 1; /* print just a single character */
+#else /* _UNICODE */
+ if (flags & (FL_LONG|FL_WIDECHAR)) {
+ wchar = (wchar_t) get_short_arg(&argptr);
+ no_output = 1;
+ } else {
+ /* format multibyte character */
+ /* this is an extension of ANSI */
+ unsigned short temp;
+ wchar = (wchar_t)get_int_arg(&argptr);
+ temp = (unsigned short)wchar;
+ {
+ buffer.sz[0] = (char) temp;
+ textlen = 1;
+ }
+ }
+ text.sz = buffer.sz;
+#endif /* _UNICODE */
+ }
+ break;
+
+ case _T('Z'): {
+ /* print a Counted String */
+ struct _count_string {
+ short Length;
+ short MaximumLength;
+ char *Buffer;
+ } *pstr;
+
+ pstr = (struct _count_string *)get_ptr_arg(&argptr);
+ if (pstr == NULL || pstr->Buffer == NULL) {
+ /* null ptr passed, use special string */
+ text.sz = __nullstring;
+ textlen = (int)strlen(text.sz);
+ } else {
+ if (flags & FL_WIDECHAR) {
+ text.wz = (wchar_t *)pstr->Buffer;
+ textlen = pstr->Length / (int)sizeof(wchar_t);
+ bufferiswide = 1;
+ } else {
+ bufferiswide = 0;
+ text.sz = pstr->Buffer;
+ textlen = pstr->Length;
+ }
+ }
+ }
+ break;
+
+ case _T('S'): /* ISO wide character string */
+#ifndef _UNICODE
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+ flags |= FL_WIDECHAR;
+#else /* _UNICODE */
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+ flags |= FL_SHORT;
+#endif /* _UNICODE */
+
+ case _T('s'): {
+ /* print a string -- */
+ /* ANSI rules on how much of string to print: */
+ /* all if precision is default, */
+ /* min(precision, length) if precision given. */
+ /* prints '(null)' if a null string is passed */
+
+ int i;
+ const char *p; /* temps */
+ const wchar_t *pwch;
+
+ /* At this point it is tempting to use strlen(), but */
+ /* if a precision is specified, we're not allowed to */
+ /* scan past there, because there might be no null */
+ /* at all. Thus, we must do our own scan. */
+
+ i = (precision == -1) ? INT_MAX : precision;
+ text.sz = (char *)get_ptr_arg(&argptr);
+
+ /* scan for null upto i characters */
+#ifdef _UNICODE
+ if (flags & FL_SHORT) {
+ if (text.sz == NULL) /* NULL passed, use special string */
+ text.sz = __nullstring;
+ p = text.sz;
+ for (textlen=0; textlen<i && *p; textlen++) {
+ ++p;
+ }
+ /* textlen now contains length in multibyte chars */
+ } else {
+ if (text.wz == NULL) /* NULL passed, use special string */
+ text.wz = __wnullstring;
+ bufferiswide = 1;
+ pwch = text.wz;
+ while (i-- && *pwch)
+ ++pwch;
+ textlen = (int)(pwch - text.wz); /* in wchar_ts */
+ /* textlen now contains length in wide chars */
+ }
+#else /* _UNICODE */
+ if (flags & (FL_LONG|FL_WIDECHAR)) {
+ if (text.wz == NULL) /* NULL passed, use special string */
+ text.wz = __wnullstring;
+ bufferiswide = 1;
+ pwch = text.wz;
+ while ( i-- && *pwch )
+ ++pwch;
+ textlen = (int)(pwch - text.wz);
+ /* textlen now contains length in wide chars */
+ } else {
+ if (text.sz == NULL) /* NULL passed, use special string */
+ text.sz = __nullstring;
+ p = text.sz;
+ while (i-- && *p)
+ ++p;
+ textlen = (int)(p - text.sz); /* length of the string */
+ }
+
+#endif /* _UNICODE */
+ }
+ break;
+
+
+ case _T('n'): {
+ /* write count of characters seen so far into */
+ /* short/int/long thru ptr read from args */
+
+ void *p; /* temp */
+
+ p = get_ptr_arg(&argptr);
+
+ /* %n is disabled */
+ _VALIDATE_RETURN(("'n' format specifier disabled" && 0), EINVAL, -1);
+ break;
+
+ /* store chars out into short/long/int depending on flags */
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ *(long *)p = charsout;
+ else
+#endif /* !LONG_IS_INT */
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT)
+ *(short *)p = (short) charsout;
+ else
+#endif /* !SHORT_IS_INT */
+ *(int *)p = charsout;
+
+ no_output = 1; /* force no output */
+ }
+ break;
+
+ case _T('E'):
+ case _T('G'):
+ case _T('A'):
+ capexp = 1; /* capitalize exponent */
+ ch += _T('a') - _T('A'); /* convert format char to lower */
+ /* DROP THROUGH */
+ case _T('e'):
+ case _T('f'):
+ case _T('g'):
+ case _T('a'): {
+ /* floating point conversion -- we call cfltcvt routines */
+ /* to do the work for us. */
+ flags |= FL_SIGNED; /* floating point is signed conversion */
+ text.sz = buffer.sz; /* put result in buffer */
+ buffersize = BUFFERSIZE;
+
+ /* compute the precision value */
+ if (precision < 0)
+ precision = 6; /* default precision: 6 */
+ else if (precision == 0 && ch == _T('g'))
+ precision = 1; /* ANSI specified */
+ else if (precision > MAXPRECISION)
+ precision = MAXPRECISION;
+
+ if (precision > BUFFERSIZE - _CVTBUFSIZE) {
+ precision = BUFFERSIZE - _CVTBUFSIZE;
+ }
+
+ /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */
+ if (flags & FL_ALTERNATE)
+ {
+ capexp |= FL_ALTERNATE;
+ }
+
+ _CRT_DOUBLE tmp;
+ tmp=va_arg(argptr, _CRT_DOUBLE);
+ /* Note: assumes ch is in ASCII range */
+ /* In safecrt, we provide a special version of _cfltcvt which internally calls printf (see safecrt_output_s.c) */
+ _CFLTCVT(&tmp, buffer.sz, buffersize, (char)ch, precision, capexp);
+
+ /* check if result was negative, save '-' for later */
+ /* and point to positive part (this is for '0' padding) */
+ if (*text.sz == '-') {
+ flags |= FL_NEGATIVE;
+ ++text.sz;
+ }
+
+ textlen = (int)strlen(text.sz); /* compute length of text */
+ }
+ break;
+
+ case _T('d'):
+ case _T('i'):
+ /* signed decimal output */
+ flags |= FL_SIGNED;
+ radix = 10;
+ goto COMMON_INT;
+
+ case _T('u'):
+ radix = 10;
+ goto COMMON_INT;
+
+ case _T('p'):
+ /* write a pointer -- this is like an integer or long */
+ /* except we force precision to pad with zeros and */
+ /* output in big hex. */
+
+ precision = 2 * sizeof(void *); /* number of hex digits needed */
+#if PTR_IS_INT64
+ flags |= FL_I64; /* assume we're converting an int64 */
+#elif !PTR_IS_INT
+ flags |= FL_LONG; /* assume we're converting a long */
+#endif /* !PTR_IS_INT */
+ /* DROP THROUGH to hex formatting */
+
+ case _T('X'):
+ /* unsigned upper hex output */
+ hexadd = _T('A') - _T('9') - 1; /* set hexadd for uppercase hex */
+ goto COMMON_HEX;
+
+ case _T('x'):
+ /* unsigned lower hex output */
+ hexadd = _T('a') - _T('9') - 1; /* set hexadd for lowercase hex */
+ /* DROP THROUGH TO COMMON_HEX */
+
+ COMMON_HEX:
+ radix = 16;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means '0x' prefix */
+ prefix[0] = _T('0');
+ prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd); /* 'x' or 'X' */
+ prefixlen = 2;
+ }
+ goto COMMON_INT;
+
+ case _T('o'):
+ /* unsigned octal output */
+ radix = 8;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means force a leading 0 */
+ flags |= FL_FORCEOCTAL;
+ }
+ /* DROP THROUGH to COMMON_INT */
+
+ COMMON_INT: {
+ /* This is the general integer formatting routine. */
+ /* Basically, we get an argument, make it positive */
+ /* if necessary, and convert it according to the */
+ /* correct radix, setting text and textlen */
+ /* appropriately. */
+
+#if _INTEGRAL_MAX_BITS >= 64
+// unsigned __int64 number; /* number to convert */
+ uint64_t number; /* number to convert */
+ int digit; /* ascii value of digit */
+ __int64 l; /* temp long value */
+#else /* _INTEGRAL_MAX_BITS >= 64 */
+ unsigned long number; /* number to convert */
+ int digit; /* ascii value of digit */
+ long l; /* temp long value */
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ /* 1. read argument into l, sign extend as needed */
+#if _INTEGRAL_MAX_BITS >= 64
+ if (flags & FL_I64)
+ l = get_int64_arg(&argptr);
+ else
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ if (flags & FL_LONGLONG)
+ l = get_long_long_arg(&argptr);
+ else
+
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ l = get_long_arg(&argptr);
+ else
+#endif /* !LONG_IS_INT */
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT) {
+ if (flags & FL_SIGNED)
+ l = (short) get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/
+
+ } else
+#endif /* !SHORT_IS_INT */
+ {
+ if (flags & FL_SIGNED)
+ l = get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/
+
+ }
+
+ /* 2. check for negative; copy into number */
+ if ( (flags & FL_SIGNED) && l < 0) {
+ number = -l;
+ flags |= FL_NEGATIVE; /* remember negative sign */
+ } else {
+ number = l;
+ }
+
+#if _INTEGRAL_MAX_BITS >= 64
+ if ( (flags & FL_I64) == 0 && (flags & FL_LONGLONG) == 0 ) {
+ /*
+ * Unless printing a full 64-bit value, insure values
+ * here are not in cananical longword format to prevent
+ * the sign extended upper 32-bits from being printed.
+ */
+ number &= 0xffffffff;
+ }
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ /* 3. check precision value for default; non-default */
+ /* turns off 0 flag, according to ANSI. */
+ if (precision < 0)
+ precision = 1; /* default precision */
+ else {
+ flags &= ~FL_LEADZERO;
+ if (precision > MAXPRECISION)
+ precision = MAXPRECISION;
+ }
+
+ /* 4. Check if data is 0; if so, turn off hex prefix */
+ if (number == 0)
+ prefixlen = 0;
+
+ /* 5. Convert data to ASCII -- note if precision is zero */
+ /* and number is zero, we get no digits at all. */
+
+ char *sz;
+ sz = &buffer.sz[BUFFERSIZE-1]; /* last digit at end of buffer */
+
+ while (precision-- > 0 || number != 0) {
+ digit = (int)(number % radix) + '0';
+ number /= radix; /* reduce number */
+ if (digit > '9') {
+ /* a hex digit, make it a letter */
+ digit += hexadd;
+ }
+ *sz-- = (char)digit; /* store the digit */
+ }
+
+ textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - sz); /* compute length of number */
+ ++sz; /* text points to first digit now */
+
+
+ /* 6. Force a leading zero if FORCEOCTAL flag set */
+ if ((flags & FL_FORCEOCTAL) && (textlen == 0 || sz[0] != '0')) {
+ *--sz = '0';
+ ++textlen; /* add a zero */
+ }
+
+ text.sz = sz;
+ }
+ break;
+ }
+
+
+ /* At this point, we have done the specific conversion, and */
+ /* 'text' points to text to print; 'textlen' is length. Now we */
+ /* justify it, put on prefixes, leading zeros, and then */
+ /* print it. */
+
+ if (!no_output) {
+ int padding; /* amount of padding, negative means zero */
+
+ if (flags & FL_SIGNED) {
+ if (flags & FL_NEGATIVE) {
+ /* prefix is a '-' */
+ prefix[0] = _T('-');
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGN) {
+ /* prefix is '+' */
+ prefix[0] = _T('+');
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGNSP) {
+ /* prefix is ' ' */
+ prefix[0] = _T(' ');
+ prefixlen = 1;
+ }
+ }
+
+ /* calculate amount of padding -- might be negative, */
+ /* but this will just mean zero */
+ padding = fldwidth - textlen - prefixlen;
+
+ /* put out the padding, prefix, and text, in the correct order */
+
+ if (!(flags & (FL_LEFT | FL_LEADZERO))) {
+ /* pad on left with blanks */
+ WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
+ }
+
+ /* write prefix */
+ WRITE_STRING(prefix, prefixlen, &charsout);
+
+ if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
+ /* write leading zeros */
+ WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
+ }
+
+ /* write text */
+#ifndef _UNICODE
+ if (bufferiswide && (textlen > 0)) {
+ charsout = -1;
+ } else {
+ WRITE_STRING(text.sz, textlen, &charsout);
+ }
+#else /* _UNICODE */
+ if (!bufferiswide && textlen > 0) {
+ char *p;
+ int retval = 0
+ int count;
+
+ p = text.sz;
+ count = textlen;
+ while (count-- > 0) {
+ retval = _MBTOWC(&wchar, p, MB_CUR_MAX);
+ if (retval <= 0) {
+ charsout = -1;
+ break;
+ }
+ WRITE_CHAR(wchar, &charsout);
+ p += retval;
+ }
+ } else {
+ WRITE_STRING(text.wz, textlen, &charsout);
+ }
+#endif /* _UNICODE */
+
+ if (charsout >= 0 && (flags & FL_LEFT)) {
+ /* pad on right with blanks */
+ WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
+ }
+
+ /* we're done! */
+ }
+ break;
+ }
+ }
+
+#ifdef FORMAT_VALIDATIONS
+ /* The format string shouldn't be incomplete - i.e. when we are finished
+ with the format string, the last thing we should have encountered
+ should have been a regular char to be output or a type specifier. Else
+ the format string was incomplete */
+ _VALIDATE_RETURN(((state == ST_NORMAL) || (state == ST_TYPE)), EINVAL, -1);
+#endif /* FORMAT_VALIDATIONS */
+
+ return charsout; /* return value = number of characters written */
+}
+
+/*
+ * Future Optimizations for swprintf:
+ * - Don't free the memory used for converting the buffer to wide chars.
+ * Use realloc if the memory is not sufficient. Free it at the end.
+ */
+
+/***
+*void write_char(char ch, int *pnumwritten)
+*ifdef _UNICODE
+*void write_char(wchar_t ch, FILE *f, int *pnumwritten)
+*endif
+*void write_char(char ch, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes a single character to the given file/console. If no error occurs,
+* then *pnumwritten is incremented; otherwise, *pnumwritten is set
+* to -1.
+*
+*Entry:
+* _TCHAR ch - character to write
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+
+LOCAL(void) write_char (
+ _TCHAR ch,
+ int *pnumwritten
+ )
+{
+#ifdef _UNICODE
+ if (_putwch_nolock(ch) == WEOF)
+#else /* _UNICODE */
+ if (_putch_nolock(ch) == EOF)
+#endif /* _UNICODE */
+ *pnumwritten = -1;
+ else
+ ++(*pnumwritten);
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_char (
+ _TCHAR ch,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ if ( (f->_flag & _IOSTRG) && f->_base == NULL)
+ {
+ ++(*pnumwritten);
+ return;
+ }
+#ifdef _UNICODE
+ if (_putwc_nolock(ch, f) == WEOF)
+#else /* _UNICODE */
+ if (_putc_nolock(ch, f) == EOF)
+#endif /* _UNICODE */
+ *pnumwritten = -1;
+ else
+ ++(*pnumwritten);
+}
+
+#endif /* CPRFLAG */
+
+/***
+*void write_multi_char(char ch, int num, int *pnumwritten)
+*ifdef _UNICODE
+*void write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten)
+*endif
+*void write_multi_char(char ch, int num, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes num copies of a character to the given file/console. If no error occurs,
+* then *pnumwritten is incremented by num; otherwise, *pnumwritten is set
+* to -1. If num is negative, it is treated as zero.
+*
+*Entry:
+* _TCHAR ch - character to write
+* int num - number of times to write the characters
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+LOCAL(void) write_multi_char (
+ _TCHAR ch,
+ int num,
+ int *pnumwritten
+ )
+{
+ while (num-- > 0) {
+ write_char(ch, pnumwritten);
+ if (*pnumwritten == -1)
+ break;
+ }
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_multi_char (
+ _TCHAR ch,
+ int num,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ while (num-- > 0) {
+ write_char(ch, f, pnumwritten);
+ if (*pnumwritten == -1)
+ break;
+ }
+}
+
+#endif /* CPRFLAG */
+
+/***
+*void write_string(const char *string, int len, int *pnumwritten)
+*void write_string(const char *string, int len, FILE *f, int *pnumwritten)
+*ifdef _UNICODE
+*void write_string(const wchar_t *string, int len, FILE *f, int *pnumwritten)
+*endif
+*void write_wstring(const wchar_t *string, int len, int *pnumwritten)
+*void write_wstring(const wchar_t *string, int len, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes a string of the given length to the given file. If no error occurs,
+* then *pnumwritten is incremented by len; otherwise, *pnumwritten is set
+* to -1. If len is negative, it is treated as zero.
+*
+*Entry:
+* _TCHAR *string - string to write (NOT null-terminated)
+* int len - length of string
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+
+LOCAL(void) write_string (
+ const _TCHAR *string,
+ int len,
+ int *pnumwritten
+ )
+{
+ while (len-- > 0) {
+ write_char(*string++, pnumwritten);
+ if (*pnumwritten == -1)
+ {
+ if (errno == EILSEQ)
+ write_char(_T('?'), pnumwritten);
+ else
+ break;
+ }
+ }
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_string (
+ const _TCHAR *string,
+ int len,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ if ( (f->_flag & _IOSTRG) && f->_base == NULL)
+ {
+ (*pnumwritten) += len;
+ return;
+ }
+ while (len-- > 0) {
+ write_char(*string++, f, pnumwritten);
+ if (*pnumwritten == -1)
+ {
+ if (errno == EILSEQ)
+ write_char(_T('?'), f, pnumwritten);
+ else
+ break;
+ }
+ }
+}
+#endif /* CPRFLAG */
diff --git a/src/pal/src/safecrt/safecrt_output_s.c b/src/pal/src/safecrt/safecrt_output_s.c
new file mode 100644
index 0000000000..c3e7f91404
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_output_s.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_output_s.c - implementation of the _output family for safercrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _output family for safercrt.lib.
+*
+*Revision History:
+* 07-08-04 SJ Stub module created.
+* 07-13-04 AC Added support for floating-point types.
+* 07-29-04 AC Added macros for a safecrt version of mctowc and wctomb, which target ntdll.dll or msvcrt.dll
+* based on the _NTSUBSET_ #define
+* 09-24-04 MSL Prefix disallow NULL deref
+*
+****/
+
+#define _SAFECRT_IMPL
+
+#define __STDC_LIMIT_MACROS
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define FORMAT_VALIDATIONS
+#define _CFLTCVT _safecrt_cfltcvt
+
+#define _TCHAR CRT_TCHAR
+#define TCHAR CRTTCHAR
+
+typedef char _TCHAR;
+typedef char TCHAR;
+#define _T(x) x
+
+#include "output.inl"
diff --git a/src/pal/src/safecrt/safecrt_winput_s.c b/src/pal/src/safecrt/safecrt_winput_s.c
new file mode 100644
index 0000000000..17a621781b
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_winput_s.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_winput_s.c - implementation of the _winput family for safecrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _winput family for safecrt.lib.
+*
+*Revision History:
+* 07/19/04 AC Created
+*
+****/
+
+
+#ifndef _UNICODE /* CRT flag */
+#define _UNICODE 1
+#endif
+
+#ifndef UNICODE /* NT flag */
+#define UNICODE 1
+#endif
+
+#define _SAFECRT_IMPL
+#define _SECURE_SCANF
+
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _TCHAR CRT_TCHAR
+#define TCHAR CRTTCHAR
+
+typedef wchar_t _TCHAR;
+typedef wchar_t TCHAR;
+typedef wchar_t _TUCHAR;
+#define _T(x) x
+#define _TEOF WEOF
+
+#define _gettc_nolock(x) _getwc_nolock(x)
+#define _ungettc_nolock(x,y) _ungetwc_nolock(x,y)
+
+#include "input.inl"
+
diff --git a/src/pal/src/safecrt/safecrt_woutput_s.c b/src/pal/src/safecrt/safecrt_woutput_s.c
new file mode 100644
index 0000000000..52fe9400d5
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_woutput_s.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_woutput_s.c - implementation of the _woutput family for safercrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _woutput family for safercrt.lib.
+*
+*Revision History:
+* 07-08-04 SJ Stub module created.
+* 07-13-04 AC Added support for floating-point types.
+* 07-29-04 AC Added macros for a safecrt version of mctowc and wctomb, which target ntdll.dll or msvcrt.dll
+* based on the _NTSUBSET_ #define
+*
+****/
+
+#define _SAFECRT_IMPL
+
+#define __STDC_LIMIT_MACROS
+
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#ifndef _UNICODE /* CRT flag */
+#define _UNICODE 1
+#endif
+
+#ifndef UNICODE /* NT flag */
+#define UNICODE 1
+#endif
+
+#define FORMAT_VALIDATIONS
+#if defined(_NTSUBSET_)
+#define _MBTOWC _safecrt_mbtowc
+#endif
+#define _WCTOMB_S _safecrt_wctomb_s
+#define _CFLTCVT _safecrt_cfltcvt
+#define _CLDCVT _safecrt_cldcvt
+
+#define _TCHAR CRT_TCHAR
+#define TCHAR CRTTCHAR
+
+typedef wchar_t _TCHAR;
+typedef wchar_t TCHAR;
+#define _T(x) L##x
+
+#include "output.inl"
diff --git a/src/pal/src/safecrt/snprintf.c b/src/pal/src/safecrt/snprintf.c
new file mode 100644
index 0000000000..c892d1a9b6
--- /dev/null
+++ b/src/pal/src/safecrt/snprintf.c
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*snprintf.c - "Count" version of sprintf
+*
+
+*
+*Purpose:
+* The _snprintf() flavor takes a count argument that is
+* the max number of bytes that should be written to the
+* user's buffer.
+*
+*******************************************************************************/
+
+#define _COUNT_ 1
+#include "sprintf.c"
diff --git a/src/pal/src/safecrt/splitpath_s.c b/src/pal/src/safecrt/splitpath_s.c
new file mode 100644
index 0000000000..cb8a364550
--- /dev/null
+++ b/src/pal/src/safecrt/splitpath_s.c
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*splitpath_s.c - break down path name into components
+*
+
+*
+*Purpose:
+* To provide support for accessing the individual components of an
+* arbitrary path name
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME _splitpath_s
+#define _CHAR char
+#define _TCSNCPY_S strncpy_s
+#define _T(_Character) _Character
+
+#define _MBS_SUPPORT 0
+
+#include "tsplitpath_s.inl"
diff --git a/src/pal/src/safecrt/sprintf.c b/src/pal/src/safecrt/sprintf.c
new file mode 100644
index 0000000000..5454179f8d
--- /dev/null
+++ b/src/pal/src/safecrt/sprintf.c
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*sprintf.c - print formatted to string
+*
+
+*
+*Purpose:
+* defines sprintf() and _snprintf() - print formatted data to string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+
+/***
+*ifndef _COUNT_
+*int sprintf(string, format, ...) - print formatted data to string
+*else
+*int _snprintf(string, cnt, format, ...) - print formatted data to string
+*endif
+*
+*Purpose:
+* Prints formatted data to the using the format string to
+* format data and getting as many arguments as called for
+* Sets up a FILE so file i/o operations can be used, make
+* string look like a huge buffer to it, but _flsbuf will
+* refuse to flush it if it fills up. Appends '\0' to make
+* it a true string. _output does the real work here
+*
+* Allocate the 'fake' _iob[] entry statically instead of on
+* the stack so that other routines can assume that _iob[]
+* entries are in are in DGROUP and, thus, are near.
+*
+*ifdef _COUNT_
+* The _snprintf() flavor takes a count argument that is
+* the max number of bytes that should be written to the
+* user's buffer.
+*endif
+*
+* Multi-thread: (1) Since there is no stream, this routine must
+* never try to get the stream lock (i.e., there is no stream
+* lock either). (2) Also, since there is only one statically
+* allocated 'fake' iob, we must lock/unlock to prevent collisions.
+*
+*Entry:
+* char *string - pointer to place to put output
+*ifdef _COUNT_
+* size_t count - max number of bytes to put in buffer
+*endif
+* char *format - format string to control data format/number
+* of arguments followed by list of arguments, number and type
+* controlled by format string
+*
+*Exit:
+* returns number of characters printed
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int sprintf_s (
+ char *string,
+ size_t sizeInBytes,
+ const char *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = _vsprintf_s(string, sizeInBytes, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
+int _snprintf_s (
+ char *string,
+ size_t sizeInBytes,
+ size_t count,
+ const char *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = _vsnprintf_s(string, sizeInBytes, count, format, arglist);
+ va_end(arglist);
+ return ret;
+}
diff --git a/src/pal/src/safecrt/sscanf.c b/src/pal/src/safecrt/sscanf.c
new file mode 100644
index 0000000000..94b5148875
--- /dev/null
+++ b/src/pal/src/safecrt/sscanf.c
@@ -0,0 +1,249 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*sscanf.c - read formatted data from string
+*
+
+*
+*Purpose:
+* defines scanf() - reads formatted data from string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+typedef int (*INPUTFN)(miniFILE *, const unsigned char*, va_list);
+typedef int (*WINPUTFN)(miniFILE *, const unsigned short*, va_list);
+
+
+/***
+*static int v[nw]scan_fn([w]inputfn, string, [count], format, ...)
+*
+*Purpose:
+* this is a helper function which is called by the other functions
+* in this file - sscanf/swscanf/snscanf etc. It calls either _(w)input or
+* _(w)input_s depending on the first parameter.
+*
+*******************************************************************************/
+
+static int __cdecl vscan_fn (
+ INPUTFN inputfn,
+ const char *string,
+ const char *format,
+ va_list arglist
+ )
+{
+ miniFILE str;
+ miniFILE *infile = &str;
+ int retval;
+ size_t count = strlen(string);
+
+ _VALIDATE_RETURN( (string != NULL), EINVAL, EOF);
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+ infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF;
+ infile->_ptr = infile->_base = (char *) string;
+
+ if(count>(INT_MAX/sizeof(char)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ infile->_cnt = INT_MAX;
+ }
+ else
+ {
+ infile->_cnt = (int)count*sizeof(char);
+ }
+
+ retval = (inputfn(infile, ( const unsigned char* )format, arglist));
+
+ return(retval);
+}
+
+static int __cdecl vnscan_fn (
+ INPUTFN inputfn,
+ const char *string,
+ size_t count,
+ const char *format,
+ va_list arglist
+ )
+{
+ miniFILE str;
+ miniFILE *infile = &str;
+ int retval;
+ size_t length = strlen(string);
+
+ _VALIDATE_RETURN( (string != NULL), EINVAL, EOF);
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+ infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF;
+ infile->_ptr = infile->_base = (char *) string;
+
+ if ( count > length )
+ {
+ count = length;
+ }
+
+ if(count>(INT_MAX/sizeof(char)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ infile->_cnt = INT_MAX;
+ }
+ else
+ {
+ infile->_cnt = (int)count*sizeof(char);
+ }
+
+ retval = (inputfn(infile, ( const unsigned char* )format, arglist));
+
+ return(retval);
+}
+
+static int __cdecl vwscan_fn (
+ WINPUTFN inputfn,
+ const wchar_t *string,
+ const wchar_t *format,
+ va_list arglist
+ )
+{
+ miniFILE str;
+ miniFILE *infile = &str;
+ int retval;
+ size_t count = wcsnlen(string, INT_MAX);
+
+ _VALIDATE_RETURN( (string != NULL), EINVAL, EOF);
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+ infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF;
+ infile->_ptr = infile->_base = (char *) string;
+
+ if(count>(INT_MAX/sizeof(wchar_t)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ infile->_cnt = INT_MAX;
+ }
+ else
+ {
+ infile->_cnt = (int)count*sizeof(wchar_t);
+ }
+
+ retval = (inputfn(infile, format, arglist));
+
+ return(retval);
+}
+
+static int __cdecl vnwscan_fn (
+ WINPUTFN inputfn,
+ const wchar_t *string,
+ size_t count,
+ const wchar_t *format,
+ va_list arglist
+ )
+{
+ miniFILE str;
+ miniFILE *infile = &str;
+ int retval;
+ size_t length = wcsnlen(string, INT_MAX);
+
+ _VALIDATE_RETURN( (string != NULL), EINVAL, EOF);
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+ infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF;
+ infile->_ptr = infile->_base = (char *) string;
+
+ if ( count > length )
+ {
+ count = length;
+ }
+
+ if(count>(INT_MAX/sizeof(wchar_t)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ infile->_cnt = INT_MAX;
+ }
+ else
+ {
+ infile->_cnt = (int)count*sizeof(wchar_t);
+ }
+
+ retval = (inputfn(infile, format, arglist));
+
+ return(retval);
+}
+
+
+/***
+*int sscanf_s(string, format, ...)
+* Same as sscanf above except that it calls _input_s to do the real work.
+*
+*int snscanf_s(string, size, format, ...)
+* Same as snscanf above except that it calls _input_s to do the real work.
+*
+* _input_s has a size check for array parameters.
+*
+*******************************************************************************/
+
+int __cdecl sscanf_s (
+ const char *string,
+ const char *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = vscan_fn(__tinput_s, string, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
+int __cdecl _snscanf_s (
+ const char *string,
+ size_t count,
+ const char *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = vnscan_fn(__tinput_s, string, count, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
+int __cdecl swscanf_s (
+ const wchar_t *string,
+ const wchar_t *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = vwscan_fn(__twinput_s, string, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
+int __cdecl _snwscanf_s (
+ const wchar_t *string,
+ size_t count,
+ const wchar_t *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = vnwscan_fn(__twinput_s, string, count, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
diff --git a/src/pal/src/safecrt/strcat_s.c b/src/pal/src/safecrt/strcat_s.c
new file mode 100644
index 0000000000..4dc2332006
--- /dev/null
+++ b/src/pal/src/safecrt/strcat_s.c
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strcat_s.c - contains strcat_s()
+*
+
+*
+*Purpose:
+* strcat_s() concatenates (appends) a copy of the source string to the
+* end of the destination string.
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strcat_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+
+#include "tcscat_s.inl"
diff --git a/src/pal/src/safecrt/strcpy_s.c b/src/pal/src/safecrt/strcpy_s.c
new file mode 100644
index 0000000000..821dbe85f6
--- /dev/null
+++ b/src/pal/src/safecrt/strcpy_s.c
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strcpy_s.c - contains strcpy_s()
+*
+
+*
+*Purpose:
+* strcpy_s() copies one string onto another.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strcpy_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+
+#include "tcscpy_s.inl"
diff --git a/src/pal/src/safecrt/strlen_s.c b/src/pal/src/safecrt/strlen_s.c
new file mode 100644
index 0000000000..34c1308d5c
--- /dev/null
+++ b/src/pal/src/safecrt/strlen_s.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strlen_s.c - contains strnlen() routine
+*
+
+*
+*Purpose:
+* strnlen returns the length of a null-terminated string,
+* not including the null byte itself, up to the specified max size
+*
+*******************************************************************************/
+
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+/***
+*strnlen - return the length of a null-terminated string
+*
+*Purpose:
+* Finds the length in bytes of the given string, not including
+* the final null character. Only the first maxsize characters
+* are inspected: if the null character is not found, maxsize is
+* returned.
+*
+*Entry:
+* const char * str - string whose length is to be computed
+* size_t maxsize
+*
+*Exit:
+* Length of the string "str", exclusive of the final null byte, or
+* maxsize if the null character is not found.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl strnlen(const char *str, size_t maxsize)
+{
+ size_t n;
+
+ /* Note that we do not check if str == NULL, because we do not
+ * return errno_t...
+ */
+
+ for (n = 0; n < maxsize && *str; n++, str++)
+ ;
+
+ return n;
+}
+
diff --git a/src/pal/src/safecrt/strncat_s.c b/src/pal/src/safecrt/strncat_s.c
new file mode 100644
index 0000000000..ef8c6cfc7f
--- /dev/null
+++ b/src/pal/src/safecrt/strncat_s.c
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strncat_s.c - append n chars of string to new string
+*
+
+*
+*Purpose:
+* defines strncat_s() - appends n characters of string onto
+* end of other string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strncat_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+#define _COUNT _Count
+
+#include "tcsncat_s.inl"
diff --git a/src/pal/src/safecrt/strncpy_s.c b/src/pal/src/safecrt/strncpy_s.c
new file mode 100644
index 0000000000..f819ebb6bb
--- /dev/null
+++ b/src/pal/src/safecrt/strncpy_s.c
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strncpy_s.c - copy at most n characters of string
+*
+
+*
+*Purpose:
+* defines strncpy_s() - copy at most n characters of string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strncpy_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+#define _COUNT _Count
+
+#include "tcsncpy_s.inl"
diff --git a/src/pal/src/safecrt/strtok_s.c b/src/pal/src/safecrt/strtok_s.c
new file mode 100644
index 0000000000..6f1c80633f
--- /dev/null
+++ b/src/pal/src/safecrt/strtok_s.c
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strtok_s.c - tokenize a string with given delimiters
+*
+
+*
+*Purpose:
+* defines strtok_s() - breaks string into series of token
+* via repeated calls.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strtok_s
+#define _CHAR char
+
+#include "tcstok_s.inl"
diff --git a/src/pal/src/safecrt/swprintf.c b/src/pal/src/safecrt/swprintf.c
new file mode 100644
index 0000000000..75004eafe2
--- /dev/null
+++ b/src/pal/src/safecrt/swprintf.c
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*swprintf.c - print formatted to string
+*
+*Purpose:
+* defines _swprintf(), _swprintf_c and _snwprintf() - print formatted data
+* to string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+/***
+*ifndef _COUNT_
+*int _swprintf(string, format, ...) - print formatted data to string
+*else
+*ifndef _SWPRINTFS_ERROR_RETURN_FIX
+*int _snwprintf(string, cnt, format, ...) - print formatted data to string
+*else
+*int _swprintf_c(string, cnt, format, ...) - print formatted data to string
+*endif
+*endif
+*
+*Purpose:
+* Prints formatted data to the using the format string to
+* format data and getting as many arguments as called for
+* Sets up a FILE so file i/o operations can be used, make
+* string look like a huge buffer to it, but _flsbuf will
+* refuse to flush it if it fills up. Appends '\0' to make
+* it a true string. _output does the real work here
+*
+* Allocate the 'fake' _iob[] entry statically instead of on
+* the stack so that other routines can assume that _iob[]
+* entries are in are in DGROUP and, thus, are near.
+*
+* We alias swprintf to _swprintf
+*
+*ifdef _COUNT_
+*ifndef _SWPRINTFS_ERROR_RETURN_FIX
+* The _snwprintf() flavor takes a count argument that is
+* the max number of wide characters that should be written to the
+* user's buffer.
+* We don't expose this function directly in the headers.
+*else
+* The _swprintf_c() flavor does the same thing as the _snwprintf
+* above, but, it also fixes a issue in the return value in the case
+* when there isn't enough space to write the null terminator
+* We don't fix this issue in _snwprintf because of backward
+* compatibility. In new code, however, _snwprintf is #defined to
+* _swprintf_c so users get the fix.
+*
+*endif
+*
+* Multi-thread: (1) Since there is no stream, this routine must
+* never try to get the stream lock (i.e., there is no stream
+* lock either). (2) Also, since there is only one statically
+* allocated 'fake' iob, we must lock/unlock to prevent collisions.
+*
+*Entry:
+* wchar_t *string - pointer to place to put output
+*ifdef _COUNT_
+* size_t count - max number of wide characters to put in buffer
+*endif
+* wchar_t *format - format string to control data format/number
+* of arguments followed by list of arguments, number and type
+* controlled by format string
+*
+*Exit:
+* returns number of wide characters printed
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl swprintf_s (
+ wchar_t *string,
+ size_t sizeInWords,
+ const wchar_t *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+
+ va_start(arglist, format);
+
+ ret = _vswprintf_s(string, sizeInWords, format, arglist);
+
+ va_end(arglist);
+
+ return ret;
+}
+
+int __cdecl _snwprintf_s (
+ wchar_t *string,
+ size_t sizeInWords,
+ size_t count,
+ const wchar_t *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+
+ va_start(arglist, format);
+
+ ret = _vsnwprintf_s(string, sizeInWords, count, format, arglist);
+
+ va_end(arglist);
+
+ return ret;
+}
diff --git a/src/pal/src/safecrt/tcscat_s.inl b/src/pal/src/safecrt/tcscat_s.inl
new file mode 100644
index 0000000000..b6fefdc0ae
--- /dev/null
+++ b/src/pal/src/safecrt/tcscat_s.inl
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcscat_s.inl - general implementation of _tcscpy_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strcat_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)
+{
+ _CHAR *p;
+ size_t available;
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+ _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
+
+ p = _DEST;
+ available = _SIZE;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_DEST_NOT_NULL_TERMINATED(_DEST, _SIZE);
+ }
+
+ while ((*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+ }
+ _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
+ _RETURN_NO_ERROR;
+}
+
diff --git a/src/pal/src/safecrt/tcscpy_s.inl b/src/pal/src/safecrt/tcscpy_s.inl
new file mode 100644
index 0000000000..b1192d8ee7
--- /dev/null
+++ b/src/pal/src/safecrt/tcscpy_s.inl
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcscpy_s.inl - general implementation of _tcscpy_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strcpy_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)
+{
+ _CHAR *p;
+ size_t available;
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+ _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
+
+ p = _DEST;
+ available = _SIZE;
+ while ((*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+ }
+ _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
+ _RETURN_NO_ERROR;
+}
+
diff --git a/src/pal/src/safecrt/tcsncat_s.inl b/src/pal/src/safecrt/tcsncat_s.inl
new file mode 100644
index 0000000000..6de501767d
--- /dev/null
+++ b/src/pal/src/safecrt/tcsncat_s.inl
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcsncat_s.inl - general implementation of _tcscpy_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strncat_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC, size_t _COUNT)
+{
+ _CHAR *p;
+ size_t available;
+
+ if (_COUNT == 0 && _DEST == NULL && _SIZE == 0)
+ {
+ /* this case is allowed; nothing to do */
+ _RETURN_NO_ERROR;
+ }
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+ if (_COUNT != 0)
+ {
+ _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
+ }
+
+ p = _DEST;
+ available = _SIZE;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_DEST_NOT_NULL_TERMINATED(_DEST, _SIZE);
+ }
+
+ if (_COUNT == _TRUNCATE)
+ {
+ while ((*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ _ASSERT_EXPR((!_CrtGetCheckCount() || _COUNT < available), "Buffer is too small");
+
+ while (_COUNT > 0 && (*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ _COUNT--;
+ }
+ if (_COUNT == 0)
+ {
+ *p = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_COUNT == _TRUNCATE)
+ {
+ _DEST[_SIZE - 1] = 0;
+ _RETURN_TRUNCATE;
+ }
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+ }
+ _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
+ _RETURN_NO_ERROR;
+}
+
diff --git a/src/pal/src/safecrt/tcsncpy_s.inl b/src/pal/src/safecrt/tcsncpy_s.inl
new file mode 100644
index 0000000000..54a79a03e7
--- /dev/null
+++ b/src/pal/src/safecrt/tcsncpy_s.inl
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcsncpy_s.inl - general implementation of _tcsncpy_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strncpy_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC, size_t _COUNT)
+{
+ _CHAR *p;
+ size_t available;
+
+ if (_COUNT == 0 && _DEST == NULL && _SIZE == 0)
+ {
+ /* this case is allowed; nothing to do */
+ _RETURN_NO_ERROR;
+ }
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+ if (_COUNT == 0)
+ {
+ /* notice that the source string pointer can be NULL in this case */
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_NO_ERROR;
+ }
+ _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
+
+ p = _DEST;
+ available = _SIZE;
+ if (_COUNT == _TRUNCATE)
+ {
+ while ((*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ _ASSERT_EXPR((!_CrtGetCheckCount() || _COUNT < _SIZE), "Buffer is too small");
+
+ while ((*p++ = *_SRC++) != 0 && --available > 0 && --_COUNT > 0)
+ {
+ }
+ if (_COUNT == 0)
+ {
+ *p = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_COUNT == _TRUNCATE)
+ {
+ _DEST[_SIZE - 1] = 0;
+ _RETURN_TRUNCATE;
+ }
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+ }
+ _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
+ _RETURN_NO_ERROR;
+}
+
diff --git a/src/pal/src/safecrt/tcstok_s.inl b/src/pal/src/safecrt/tcstok_s.inl
new file mode 100644
index 0000000000..29ca5c6858
--- /dev/null
+++ b/src/pal/src/safecrt/tcstok_s.inl
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcstok_s.inl - general implementation of _tcstok_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strtok_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+_CHAR * __cdecl _FUNC_NAME(_CHAR *_String, const _CHAR *_Control, _CHAR **_Context)
+{
+ _CHAR *token;
+ const _CHAR *ctl;
+
+ /* validation section */
+ _VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, NULL);
+ _VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, NULL);
+ _VALIDATE_CONDITION_ERROR_RETURN(_String != NULL || *_Context != NULL, EINVAL, NULL);
+
+ /* If string==NULL, continue with previous string */
+ if (!_String)
+ {
+ _String = *_Context;
+ }
+
+ /* Find beginning of token (skip over leading delimiters). Note that
+ * there is no token iff this loop sets string to point to the terminal null. */
+ for ( ; *_String != 0 ; _String++)
+ {
+ for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
+ ;
+ if (*ctl == 0)
+ {
+ break;
+ }
+ }
+
+ token = _String;
+
+ /* Find the end of the token. If it is not the end of the string,
+ * put a null there. */
+ for ( ; *_String != 0 ; _String++)
+ {
+ for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
+ ;
+ if (*ctl != 0)
+ {
+ *_String++ = 0;
+ break;
+ }
+ }
+
+ /* Update the context */
+ *_Context = _String;
+
+ /* Determine if a token has been found. */
+ if (token == _String)
+ {
+ return NULL;
+ }
+ else
+ {
+ return token;
+ }
+}
diff --git a/src/pal/src/safecrt/tmakepath_s.inl b/src/pal/src/safecrt/tmakepath_s.inl
new file mode 100644
index 0000000000..34c4842c61
--- /dev/null
+++ b/src/pal/src/safecrt/tmakepath_s.inl
@@ -0,0 +1,116 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tmakepath_s.inl - general implementation of _tmakepath_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for _makepath_s and its variants.
+*
+*******************************************************************************/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(__out_ecount_z(_SIZE) _CHAR *_DEST, __in_opt size_t _SIZE, __in_z_opt const _CHAR *_Drive, __in_z_opt const _CHAR *_Dir, __in_z_opt const _CHAR *_Filename, __in_z_opt const _CHAR *_Ext)
+{
+ size_t written;
+ const _CHAR *p;
+ _CHAR *d;
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+
+ /* copy drive */
+ written = 0;
+ d = _DEST;
+ if (_Drive != NULL && *_Drive != 0)
+ {
+ written += 2;
+ if(written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = *_Drive;
+ *d++ = _T(':');
+ }
+
+ /* copy dir */
+ p = _Dir;
+ if (p != NULL && *p != 0)
+ {
+ do {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ } while (*p != 0);
+
+#if _MBS_SUPPORT
+ p = _MBSDEC(_Dir, p);
+#else /* _MBS_SUPPORT */
+ p = p - 1;
+#endif /* _MBS_SUPPORT */
+ if (*p != _T('/') && *p != _T('\\'))
+ {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = _T('\\');
+ }
+ }
+
+ /* copy fname */
+ p = _Filename;
+ if (p != NULL)
+ {
+ while (*p != 0)
+ {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ }
+ }
+
+ /* copy extension; check to see if a '.' needs to be inserted */
+ p = _Ext;
+ if (p != NULL)
+ {
+ if (*p != 0 && *p != _T('.'))
+ {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = _T('.');
+ }
+ while (*p != 0)
+ {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ }
+ }
+
+ if(++written > _SIZE)
+ {
+ goto error_return;
+ }
+ *d = 0;
+ _FILL_STRING(_DEST, _SIZE, written);
+ _RETURN_NO_ERROR;
+
+error_return:
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+
+ /* should never happen, but compiler can't tell */
+ return EINVAL;
+}
diff --git a/src/pal/src/safecrt/tsplitpath_s.inl b/src/pal/src/safecrt/tsplitpath_s.inl
new file mode 100644
index 0000000000..3a14fa5900
--- /dev/null
+++ b/src/pal/src/safecrt/tsplitpath_s.inl
@@ -0,0 +1,280 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tsplitpath_s.inl - general implementation of _tsplitpath_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for _splitpath_s and its variants.
+*
+*******************************************************************************/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(
+ __in_z const _CHAR *_Path,
+ __out_ecount_z_opt(_DriveSize) _CHAR *_Drive, __in size_t _DriveSize,
+ __out_ecount_z_opt(_DirSize) _CHAR *_Dir, __in size_t _DirSize,
+ __out_ecount_z_opt(_FilenameSize) _CHAR *_Filename, __in size_t _FilenameSize,
+ __out_ecount_z_opt(_ExtSize) _CHAR *_Ext, __in size_t _ExtSize
+)
+{
+ const _CHAR *tmp;
+ const _CHAR *last_slash;
+ const _CHAR *dot;
+ int drive_set = 0;
+ size_t length = 0;
+ int bEinval = 0;
+
+ /* validation section */
+ if (_Path == NULL)
+ {
+ goto error_einval;
+ }
+ if ((_Drive == NULL && _DriveSize != 0) || (_Drive != NULL && _DriveSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Dir == NULL && _DirSize != 0) || (_Dir != NULL && _DirSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Filename == NULL && _FilenameSize != 0) || (_Filename != NULL && _FilenameSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Ext == NULL && _ExtSize != 0) || (_Ext != NULL && _ExtSize == 0))
+ {
+ goto error_einval;
+ }
+
+ /* check if _Path begins with the longpath prefix */
+ if (_Path[0] == _T('\\') && _Path[1] == _T('\\') && _Path[2] == _T('?') && _Path[3] == _T('\\'))
+ {
+ _Path += 4;
+ }
+
+ /* extract drive letter and ':', if any */
+ if (!drive_set)
+ {
+// The CorUnix PAL is never built on Windows and thus, the code below
+// for the drive check is not required.
+#if 0
+ size_t skip = _MAX_DRIVE - 2;
+ tmp = _Path;
+ while (skip > 0 && *tmp != 0)
+ {
+ skip--;
+ tmp++;
+ }
+ if (*tmp == _T(':'))
+ {
+ if (_Drive != NULL)
+ {
+ if (_DriveSize < _MAX_DRIVE)
+ {
+ goto error_erange;
+ }
+ _TCSNCPY_S(_Drive, _DriveSize, _Path, _MAX_DRIVE - 1);
+ }
+ _Path = tmp + 1;
+ }
+ else
+#endif
+ {
+ if (_Drive != NULL)
+ {
+ _RESET_STRING(_Drive, _DriveSize);
+ }
+ }
+ }
+
+ /* extract path string, if any. _Path now points to the first character
+ * of the path, if any, or the filename or extension, if no path was
+ * specified. Scan ahead for the last occurence, if any, of a '/' or
+ * '\' path separator character. If none is found, there is no path.
+ * We will also note the last '.' character found, if any, to aid in
+ * handling the extension.
+ */
+ last_slash = NULL;
+ dot = NULL;
+ tmp = _Path;
+ for (; *tmp != 0; ++tmp)
+ {
+#if _MBS_SUPPORT
+#pragma warning(push)
+#pragma warning(disable:4127)
+ if (_ISMBBLEAD(*tmp))
+#pragma warning(pop)
+ {
+ tmp++;
+ }
+ else
+#endif /* _MBS_SUPPORT */
+ {
+ if (*tmp == _T('/') || *tmp == _T('\\'))
+ {
+ /* point to one beyond for later copy */
+ last_slash = tmp + 1;
+ }
+ else if (*tmp == _T('.'))
+ {
+ dot = tmp;
+ }
+ }
+ }
+
+ if (last_slash != NULL)
+ {
+ /* found a path - copy up through last_slash or max characters
+ * allowed, whichever is smaller
+ */
+ if (_Dir != NULL) {
+ length = (size_t)(last_slash - _Path);
+ if (_DirSize <= length)
+ {
+ goto error_erange;
+ }
+ _TCSNCPY_S(_Dir, _DirSize, _Path, length);
+
+ // Normalize the path seperator
+ int iIndex;
+ for(iIndex = 0; iIndex < length; iIndex++)
+ {
+ if (_Dir[iIndex] == _T('\\'))
+ {
+ _Dir[iIndex] = _T('/');
+ }
+ }
+ }
+ _Path = last_slash;
+ }
+ else
+ {
+ /* there is no path */
+ if (_Dir != NULL)
+ {
+ _RESET_STRING(_Dir, _DirSize);
+ }
+ }
+
+ /* extract file name and extension, if any. Path now points to the
+ * first character of the file name, if any, or the extension if no
+ * file name was given. Dot points to the '.' beginning the extension,
+ * if any.
+ */
+ if (dot != NULL && (dot >= _Path))
+ {
+ /* found the marker for an extension - copy the file name up to the '.' */
+ if (_Filename)
+ {
+ length = (size_t)(dot - _Path);
+ if (length == 0)
+ {
+ // At this time, dot will be equal to _Path if string is something like "/."
+ // since _path was set to last_slash, which in turn, was set to "tmp +1"
+ // where "tmp" is the location where "/" was found. See code above for
+ // clarification.
+ //
+ // For such cases, return the "." in filename buffer.
+ //
+ // Thus, if the length is zero, we know its a string like "/." and thus, we
+ // set length to 1 to get the "." in filename buffer.
+ length = 1;
+ }
+
+ if (_FilenameSize <= length)
+ {
+ goto error_erange;
+ }
+ _TCSNCPY_S(_Filename, _FilenameSize, _Path, length);
+ }
+
+ /* now we can get the extension - remember that tmp still points
+ * to the terminating NULL character of path.
+ */
+ if (_Ext)
+ {
+ // At this time, _Path is pointing to the character after the last slash found.
+ // (See comments and code above for clarification).
+ //
+ // Returns extension as empty string for strings like "/.".
+ if (dot > _Path)
+ {
+ length = (size_t)(tmp - dot);
+ if (_ExtSize <= length)
+ {
+ goto error_erange;
+ }
+
+ /* Since dot pointed to the ".", make sure we actually have an extension
+ like ".cmd" and not just ".", OR
+
+ Confirm that its a string like "/.." - for this, return the
+ second "." in the extension part.
+
+ However, for strings like "/myfile.", return empty string
+ in extension buffer.
+ */
+ int fIsDir = (*(dot-1) == _T('.'))?1:0;
+ if (length > 1 || (length == 1 && fIsDir == 1))
+ _TCSNCPY_S(_Ext, _ExtSize, dot, length);
+ else
+ _RESET_STRING(_Ext, _ExtSize);
+ }
+ else
+ _RESET_STRING(_Ext, _ExtSize);
+ }
+ }
+ else
+ {
+ /* found no extension, give empty extension and copy rest of
+ * string into fname.
+ */
+ if (_Filename)
+ {
+ length = (size_t)(tmp - _Path);
+ if (_FilenameSize <= length)
+ {
+ goto error_erange;
+ }
+ _TCSNCPY_S(_Filename, _FilenameSize, _Path, length);
+ }
+ if (_Ext)
+ {
+ _RESET_STRING(_Ext, _ExtSize);
+ }
+ }
+
+ _RETURN_NO_ERROR;
+
+error_einval:
+ bEinval = 1;
+
+error_erange:
+ if (_Drive != NULL && _DriveSize > 0)
+ {
+ _RESET_STRING(_Drive, _DriveSize);
+ }
+ if (_Dir != NULL && _DirSize > 0)
+ {
+ _RESET_STRING(_Dir, _DirSize);
+ }
+ if (_Filename != NULL && _FilenameSize > 0)
+ {
+ _RESET_STRING(_Filename, _FilenameSize);
+ }
+ if (_Ext != NULL && _ExtSize > 0)
+ {
+ _RESET_STRING(_Ext, _ExtSize);
+ }
+
+ _VALIDATE_POINTER(_Path);
+ if (bEinval)
+ {
+ _RETURN_EINVAL;
+ }
+ return (errno = ERANGE);
+}
diff --git a/src/pal/src/safecrt/vsprintf.c b/src/pal/src/safecrt/vsprintf.c
new file mode 100644
index 0000000000..4f2bd9fdeb
--- /dev/null
+++ b/src/pal/src/safecrt/vsprintf.c
@@ -0,0 +1,268 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*vsprintf.c - print formatted data into a string from var arg list
+*
+
+*
+*Purpose:
+* defines vsprintf(), _vsnprintf() and _vsnprintf_s() - print formatted output to
+* a string, get the data from an argument ptr instead of explicit
+* arguments.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+typedef int (*OUTPUTFN)(miniFILE *, const char *, va_list);
+
+static int _vsnprintf_helper( OUTPUTFN outfn, char *string, size_t count, const char *format, va_list ap );
+static int _vscprintf_helper ( OUTPUTFN outfn, const char *format, va_list ap);
+
+/***
+*ifndef _COUNT_
+*int vsprintf(string, format, ap) - print formatted data to string from arg ptr
+*else
+*int _vsnprintf(string, cnt, format, ap) - print formatted data to string from arg ptr
+*endif
+*
+*Purpose:
+* Prints formatted data, but to a string and gets data from an argument
+* pointer.
+* Sets up a FILE so file i/o operations can be used, make string look
+* like a huge buffer to it, but _flsbuf will refuse to flush it if it
+* fills up. Appends '\0' to make it a true string.
+*
+* Allocate the 'fake' _iob[] entryit statically instead of on
+* the stack so that other routines can assume that _iob[] entries are in
+* are in DGROUP and, thus, are near.
+*
+*ifdef _COUNT_
+* The _vsnprintf() flavor takes a count argument that is
+* the max number of bytes that should be written to the
+* user's buffer.
+*endif
+*
+* Multi-thread: (1) Since there is no stream, this routine must never try
+* to get the stream lock (i.e., there is no stream lock either). (2)
+* Also, since there is only one staticly allocated 'fake' iob, we must
+* lock/unlock to prevent collisions.
+*
+*Entry:
+* char *string - place to put destination string
+*ifdef _COUNT_
+* size_t count - max number of bytes to put in buffer
+*endif
+* char *format - format string, describes format of data
+* va_list ap - varargs argument pointer
+*
+*Exit:
+* returns number of characters in string
+* returns -2 if the string has been truncated (only in _vsnprintf_helper)
+* returns -1 in other error cases
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl _vsnprintf_helper (
+ OUTPUTFN outfn,
+ char *string,
+ size_t count,
+ const char *format,
+ va_list ap
+ )
+{
+ miniFILE str;
+ miniFILE *outfile = &str;
+ int retval;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ _VALIDATE_RETURN( (count == 0) || (string != NULL), EINVAL, -1 );
+
+ if(count>INT_MAX)
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ outfile->_cnt = INT_MAX;
+ }
+ else
+ {
+ outfile->_cnt = (int)count;
+ }
+
+ outfile->_flag = _IOWRT|_IOSTRG;
+ outfile->_ptr = outfile->_base = string;
+
+ retval = outfn(outfile, format, ap );
+
+ if ( string==NULL)
+ return(retval);
+
+ if((retval >= 0) && (_putc_nolock('\0',outfile) != EOF))
+ return(retval);
+
+ string[count - 1] = 0;
+
+ if (outfile->_cnt < 0)
+ {
+ /* the buffer was too small; we return -2 to indicate truncation */
+ return -2;
+ }
+ return -1;
+}
+
+int __cdecl _vsprintf_s (
+ char *string,
+ size_t sizeInBytes,
+ const char *format,
+ va_list ap
+ )
+{
+ int retvalue = -1;
+
+ /* validation section */
+ _VALIDATE_RETURN(format != NULL, EINVAL, -1);
+ _VALIDATE_RETURN(string != NULL && sizeInBytes > 0, EINVAL, -1);
+
+ retvalue = _vsnprintf_helper(_output_s, string, sizeInBytes, format, ap);
+ if (retvalue < 0)
+ {
+ string[0] = 0;
+ _SECURECRT__FILL_STRING(string, sizeInBytes, 1);
+ }
+ if (retvalue == -2)
+ {
+ _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
+ }
+ if (retvalue >= 0)
+ {
+ _SECURECRT__FILL_STRING(string, sizeInBytes, retvalue + 1);
+ }
+
+ return retvalue;
+}
+
+int __cdecl _vsnprintf_s (
+ char *string,
+ size_t sizeInBytes,
+ size_t count,
+ const char *format,
+ va_list ap
+ )
+{
+ int retvalue = -1;
+ errno_t save_errno = 0;
+
+ /* validation section */
+ _VALIDATE_RETURN(format != NULL, EINVAL, -1);
+ if (count == 0 && string == NULL && sizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ _VALIDATE_RETURN(string != NULL && sizeInBytes > 0, EINVAL, -1);
+
+ if (sizeInBytes > count)
+ {
+ save_errno = errno;
+ retvalue = _vsnprintf_helper(_output_s, string, count + 1, format, ap);
+ if (retvalue == -2)
+ {
+ /* the string has been truncated, return -1 */
+ _SECURECRT__FILL_STRING(string, sizeInBytes, count + 1);
+ if (errno == ERANGE)
+ {
+ errno = save_errno;
+ }
+ return -1;
+ }
+ }
+ else /* sizeInBytes <= count */
+ {
+ save_errno = errno;
+ retvalue = _vsnprintf_helper(_output_s, string, sizeInBytes, format, ap);
+ string[sizeInBytes - 1] = 0;
+ /* we allow truncation if count == _TRUNCATE */
+ if (retvalue == -2 && count == _TRUNCATE)
+ {
+ if (errno == ERANGE)
+ {
+ errno = save_errno;
+ }
+ return -1;
+ }
+ }
+
+ if (retvalue < 0)
+ {
+ string[0] = 0;
+ _SECURECRT__FILL_STRING(string, sizeInBytes, 1);
+ if (retvalue == -2)
+ {
+ _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
+ }
+ return -1;
+ }
+
+ _SECURECRT__FILL_STRING(string, sizeInBytes, retvalue + 1);
+
+ return (retvalue < 0 ? -1 : retvalue);
+}
+
+/***
+* _vscprintf() - counts the number of character needed to print the formatted
+* data
+*
+*Purpose:
+* Counts the number of characters in the fotmatted data.
+*
+*Entry:
+* char *format - format string, describes format of data
+* va_list ap - varargs argument pointer
+*
+*Exit:
+* returns number of characters needed to print formatted data.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifndef _COUNT_
+
+int __cdecl _vscprintf_helper (
+ OUTPUTFN outfn,
+ const char *format,
+ va_list ap
+ )
+{
+ miniFILE str;
+ miniFILE *outfile = &str;
+ int retval;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ outfile->_cnt = INT_MAX; //MAXSTR;
+ outfile->_flag = _IOWRT|_IOSTRG;
+ outfile->_ptr = outfile->_base = NULL;
+
+ retval = outfn(outfile, format, ap);
+ return(retval);
+}
+
+int __cdecl _vscprintf (
+ const char *format,
+ va_list ap
+ )
+{
+ return _vscprintf_helper(_output, format, ap);
+}
+
+#endif /* _COUNT_ */
diff --git a/src/pal/src/safecrt/vswprint.c b/src/pal/src/safecrt/vswprint.c
new file mode 100644
index 0000000000..77c79b8752
--- /dev/null
+++ b/src/pal/src/safecrt/vswprint.c
@@ -0,0 +1,282 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*vswprint.c - print formatted data into a string from var arg list
+*
+*Purpose:
+* defines vswprintf(), _vswprintf_c and _vsnwprintf() - print formatted output to
+* a string, get the data from an argument ptr instead of explicit
+* arguments.
+*
+*******************************************************************************/
+
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+typedef int (*WOUTPUTFN)(miniFILE *, const wchar_t *, va_list);
+
+static int _vswprintf_helper( WOUTPUTFN outfn, wchar_t *string, size_t count, const wchar_t *format, va_list ap );
+static int _vscwprintf_helper (WOUTPUTFN outfn, const wchar_t *format, va_list ap );
+
+/***
+*ifndef _COUNT_
+*int _vswprintf(string, format, ap) - print formatted data to string from arg ptr
+*else
+*ifndef _SWPRINTFS_ERROR_RETURN_FIX
+*int _vsnwprintf(string, cnt, format, ap) - print formatted data to string from arg ptr
+*else
+*int _vswprintf_c(string, cnt, format, ...) - print formatted data to string
+*endif
+*endif
+*
+*Purpose:
+* Prints formatted data, but to a string and gets data from an argument
+* pointer.
+* Sets up a FILE so file i/o operations can be used, make string look
+* like a huge buffer to it, but _flsbuf will refuse to flush it if it
+* fills up. Appends '\0' to make it a true string.
+*
+* Allocate the 'fake' _iob[] entryit statically instead of on
+* the stack so that other routines can assume that _iob[] entries are in
+* are in DGROUP and, thus, are near.
+*
+*ifdef _COUNT_
+*ifndef _SWPRINTFS_ERROR_RETURN_FIX
+* The _vsnwprintf() flavor takes a count argument that is
+* the max number of bytes that should be written to the
+* user's buffer.
+* We don't expose this function directly in the headers.
+*else
+* The _vswprintf_c() flavor does the same thing as the _snwprintf
+* above, but, it also fixes an issue in the return value in the case
+* when there isn't enough space to write the null terminator
+* We don't fix this issue in _vsnwprintf because of backward
+* compatibility. In new code, however, _vsnwprintf is #defined to
+* _vswprintf_c so users get the fix.
+*
+*endif
+*
+* Multi-thread: (1) Since there is no stream, this routine must never try
+* to get the stream lock (i.e., there is no stream lock either). (2)
+* Also, since there is only one statically allocated 'fake' iob, we must
+* lock/unlock to prevent collisions.
+*
+*Entry:
+* wchar_t *string - place to put destination string
+*ifdef _COUNT_
+* size_t count - max number of bytes to put in buffer
+*endif
+* wchar_t *format - format string, describes format of data
+* va_list ap - varargs argument pointer
+*
+*Exit:
+* returns number of wide characters in string
+* returns -2 if the string has been truncated (only in _vsnprintf_helper)
+* returns -1 in other error cases
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl _vswprintf_helper (
+ WOUTPUTFN woutfn,
+ wchar_t *string,
+ size_t count,
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ miniFILE str;
+ miniFILE *outfile = &str;
+ int retval;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ _VALIDATE_RETURN( (count == 0) || (string != NULL), EINVAL, -1 );
+
+ outfile->_flag = _IOWRT|_IOSTRG;
+ outfile->_ptr = outfile->_base = (char *) string;
+
+ if(count>(INT_MAX/sizeof(wchar_t)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ outfile->_cnt = INT_MAX;
+ }
+ else
+ {
+ outfile->_cnt = (int)(count*sizeof(wchar_t));
+ }
+
+ retval = woutfn(outfile, format, ap );
+
+ if(string==NULL)
+ {
+ return retval;
+ }
+
+ if((retval >= 0) && (_putc_nolock('\0',outfile) != EOF) && (_putc_nolock('\0',outfile) != EOF))
+ return(retval);
+
+ string[count - 1] = 0;
+ if (outfile->_cnt < 0)
+ {
+ /* the buffer was too small; we return -2 to indicate truncation */
+ return -2;
+ }
+ return -1;
+}
+
+int __cdecl _vswprintf_s (
+ wchar_t *string,
+ size_t sizeInWords,
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ int retvalue = -1;
+
+ /* validation section */
+ _VALIDATE_RETURN(format != NULL, EINVAL, -1);
+ _VALIDATE_RETURN(string != NULL && sizeInWords > 0, EINVAL, -1);
+
+ retvalue = _vswprintf_helper(_woutput_s, string, sizeInWords, format, ap);
+ if (retvalue < 0)
+ {
+ string[0] = 0;
+ _SECURECRT__FILL_STRING(string, sizeInWords, 1);
+ }
+ if (retvalue == -2)
+ {
+ _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
+ }
+ if (retvalue >= 0)
+ {
+ _SECURECRT__FILL_STRING(string, sizeInWords, retvalue + 1);
+ }
+
+ return retvalue;
+}
+
+int __cdecl _vsnwprintf_s (
+ wchar_t *string,
+ size_t sizeInWords,
+ size_t count,
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ int retvalue = -1;
+ errno_t save_errno = 0;
+
+ /* validation section */
+ _VALIDATE_RETURN(format != NULL, EINVAL, -1);
+ if (count == 0 && string == NULL && sizeInWords == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ _VALIDATE_RETURN(string != NULL && sizeInWords > 0, EINVAL, -1);
+
+ if (sizeInWords > count)
+ {
+ save_errno = errno;
+ retvalue = _vswprintf_helper(_woutput_s, string, count + 1, format, ap);
+ if (retvalue == -2)
+ {
+ /* the string has been truncated, return -1 */
+ _SECURECRT__FILL_STRING(string, sizeInWords, count + 1);
+ if (errno == ERANGE)
+ {
+ errno = save_errno;
+ }
+ return -1;
+ }
+ }
+ else /* sizeInWords <= count */
+ {
+ save_errno = errno;
+ retvalue = _vswprintf_helper(_woutput_s, string, sizeInWords, format, ap);
+ string[sizeInWords - 1] = 0;
+ /* we allow truncation if count == _TRUNCATE */
+ if (retvalue == -2 && count == _TRUNCATE)
+ {
+ if (errno == ERANGE)
+ {
+ errno = save_errno;
+ }
+ return -1;
+ }
+ }
+
+ if (retvalue < 0)
+ {
+ string[0] = 0;
+ _SECURECRT__FILL_STRING(string, sizeInWords, 1);
+ if (retvalue == -2)
+ {
+ _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
+ }
+ return -1;
+ }
+
+ _SECURECRT__FILL_STRING(string, sizeInWords, retvalue + 1);
+
+ return (retvalue < 0 ? -1 : retvalue);
+}
+
+/***
+* _vscwprintf() - counts the number of character needed to print the formatted
+* data
+*
+*Purpose:
+* Counts the number of characters in the fotmatted data.
+*
+*Entry:
+* wchar_t *format - format string, describes format of data
+* va_list ap - varargs argument pointer
+*
+*Exit:
+* returns number of characters needed to print formatted data.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifndef _COUNT_
+
+int __cdecl _vscwprintf_helper (
+ WOUTPUTFN woutfn,
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ miniFILE str;
+ miniFILE *outfile = &str;
+ int retval;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ outfile->_cnt = INT_MAX; //MAXSTR;
+ outfile->_flag = _IOWRT|_IOSTRG;
+ outfile->_ptr = outfile->_base = NULL;
+
+ retval = woutfn(outfile, format, ap);
+ return(retval);
+}
+
+int __cdecl _vscwprintf (
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ return _vscwprintf_helper(_woutput_s, format, ap);
+}
+
+#endif /* _COUNT_ */
diff --git a/src/pal/src/safecrt/wcscat_s.c b/src/pal/src/safecrt/wcscat_s.c
new file mode 100644
index 0000000000..06179888ff
--- /dev/null
+++ b/src/pal/src/safecrt/wcscat_s.c
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcscat_s.c - contains wcscat_s()
+*
+
+*
+*Purpose:
+* wcscat_s() appends one wchar_t string onto another.
+*
+* wcscat() concatenates (appends) a copy of the source string to the
+* end of the destination string.
+* Strings are wide-character strings.
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcscat_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+
+#include "tcscat_s.inl"
diff --git a/src/pal/src/safecrt/wcscpy_s.c b/src/pal/src/safecrt/wcscpy_s.c
new file mode 100644
index 0000000000..4c60a81489
--- /dev/null
+++ b/src/pal/src/safecrt/wcscpy_s.c
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strcpy_s.c - contains wcscpy_s()
+*
+
+*
+*Purpose:
+* wcscpy_s() copies one string onto another.
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcscpy_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInWords
+#define _SRC _Src
+
+#include "tcscpy_s.inl"
+
diff --git a/src/pal/src/safecrt/wcslen_s.c b/src/pal/src/safecrt/wcslen_s.c
new file mode 100644
index 0000000000..4fd5371035
--- /dev/null
+++ b/src/pal/src/safecrt/wcslen_s.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcslen_s.c - contains wcsnlen() routine
+*
+
+*
+*Purpose:
+* wcslen returns the length of a null-terminated wide-character string,
+* not including the null wchar_t itself.
+*
+*******************************************************************************/
+
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+/***
+*wcsnlen - return the length of a null-terminated wide-character string
+*
+*Purpose:
+* Finds the length in bytes of the given string, not including
+* the final null character. Only the first maxsize characters
+* are inspected: if the null character is not found, maxsize is
+* returned.
+*
+*Entry:
+* const wchar_t * wcs - string whose length is to be computed
+* size_t maxsize
+*
+*Exit:
+* Length of the string "wcs", exclusive of the final null byte, or
+* maxsize if the null character is not found.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl wcsnlen(const wchar_t *wcs, size_t maxsize)
+{
+ size_t n;
+
+ /* Note that we do not check if s == NULL, because we do not
+ * return errno_t...
+ */
+
+ for (n = 0; n < maxsize && *wcs; n++, wcs++)
+ ;
+
+ return n;
+}
+
diff --git a/src/pal/src/safecrt/wcsncat_s.c b/src/pal/src/safecrt/wcsncat_s.c
new file mode 100644
index 0000000000..1ff39d55f3
--- /dev/null
+++ b/src/pal/src/safecrt/wcsncat_s.c
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcsncat_s.c - append n chars of string to new string
+*
+
+*
+*Purpose:
+* defines wcsncat_s() - appends n characters of string onto
+* end of other string
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcsncat_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInWords
+#define _SRC _Src
+#define _COUNT _Count
+
+#include "tcsncat_s.inl"
+
diff --git a/src/pal/src/safecrt/wcsncpy_s.c b/src/pal/src/safecrt/wcsncpy_s.c
new file mode 100644
index 0000000000..7902ded43a
--- /dev/null
+++ b/src/pal/src/safecrt/wcsncpy_s.c
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcsncpy_s.c - copy at most n characters of wide-character string
+*
+
+*
+*Purpose:
+* defines wcsncpy_s() - copy at most n characters of wchar_t string
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcsncpy_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInWords
+#define _SRC _Src
+#define _COUNT _Count
+
+#include "tcsncpy_s.inl"
+
diff --git a/src/pal/src/safecrt/wcstok_s.c b/src/pal/src/safecrt/wcstok_s.c
new file mode 100644
index 0000000000..c99b30c773
--- /dev/null
+++ b/src/pal/src/safecrt/wcstok_s.c
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcstok_s.c - tokenize a wide-character string with given delimiters
+*
+
+*
+*Purpose:
+* defines wcstok_s() - breaks wide-character string into series of token
+* via repeated calls.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcstok_s
+#define _CHAR wchar_t
+
+#include "tcstok_s.inl"
diff --git a/src/pal/src/safecrt/wmakepath_s.c b/src/pal/src/safecrt/wmakepath_s.c
new file mode 100644
index 0000000000..35ab7d386e
--- /dev/null
+++ b/src/pal/src/safecrt/wmakepath_s.c
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wmakepath_s.c - create path name from components
+*
+
+*
+*Purpose:
+* To provide support for creation of full path names from components
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME _wmakepath_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInWords
+#define _T(_Character) L##_Character
+#define _MBS_SUPPORT 0
+
+#include "tmakepath_s.inl"
diff --git a/src/pal/src/safecrt/wsplitpath_s.c b/src/pal/src/safecrt/wsplitpath_s.c
new file mode 100644
index 0000000000..c7fb107803
--- /dev/null
+++ b/src/pal/src/safecrt/wsplitpath_s.c
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wsplitpath_s.c - break down path name into components
+*
+
+*
+*Purpose:
+* To provide support for accessing the individual components of an
+* arbitrary path name
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME _wsplitpath_s
+#define _CHAR wchar_t
+#define _TCSNCPY_S wcsncpy_s
+#define _T(_Character) L##_Character
+#define _MBS_SUPPORT 0
+
+#include "tsplitpath_s.inl"
diff --git a/src/pal/src/safecrt/xtoa_s.c b/src/pal/src/safecrt/xtoa_s.c
new file mode 100644
index 0000000000..42cc5786d1
--- /dev/null
+++ b/src/pal/src/safecrt/xtoa_s.c
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strtok_s.c - tokenize a string with given delimiters
+*
+
+*
+*Purpose:
+* defines strtok_s() - breaks string into series of token
+* via repeated calls.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+//#define __int64 long long
+
+#define _SECURE_ITOA
+
+#define TCHAR char
+#define _T(x) x
+#include "xtox_s.inl"
diff --git a/src/pal/src/safecrt/xtow_s.c b/src/pal/src/safecrt/xtow_s.c
new file mode 100644
index 0000000000..7a02424c85
--- /dev/null
+++ b/src/pal/src/safecrt/xtow_s.c
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strtok_s.c - tokenize a string with given delimiters
+*
+
+*
+*Purpose:
+* defines strtok_s() - breaks string into series of token
+* via repeated calls.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _SECURE_ITOA
+
+#define _UNICODE
+#define TCHAR wchar_t
+#define _T(x) L##x
+#include "xtox_s.inl"
diff --git a/src/pal/src/safecrt/xtox_s.inl b/src/pal/src/safecrt/xtox_s.inl
new file mode 100644
index 0000000000..e07d87adf5
--- /dev/null
+++ b/src/pal/src/safecrt/xtox_s.inl
@@ -0,0 +1,450 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*xtoa.c - convert integers/longs to ASCII string
+*
+
+*
+*Purpose:
+* The module has code to convert integers/longs to ASCII strings. See
+*
+*******************************************************************************/
+
+#ifdef _UNICODE
+#define xtox_s xtow_s
+#define _itox_s _itow_s
+#define _ltox_s _ltow_s
+#define _ultox_s _ultow_s
+#define x64tox_s x64tow_s
+#define _i64tox_s _i64tow_s
+#define _ui64tox_s _ui64tow_s
+#define xtox xtow
+#define _itox _itow
+#define _ltox _ltow
+#define _ultox _ultow
+#define x64tox x64tow
+#define _i64tox _i64tow
+#define _ui64tox _ui64tow
+#else /* _UNICODE */
+#define xtox_s xtoa_s
+#define _itox_s _itoa_s
+#define _ltox_s _ltoa_s
+#define _ultox_s _ultoa_s
+#define x64tox_s x64toa_s
+#define _i64tox_s _i64toa_s
+#define _ui64tox_s _ui64toa_s
+#define xtox xtoa
+#define _itox _itoa
+#define _ltox _ltoa
+#define _ultox _ultoa
+#define x64tox x64toa
+#define _i64tox _i64toa
+#define _ui64tox _ui64toa
+#endif /* _UNICODE */
+
+/***
+*char *_itoa_s, *_ltoa_s, *_ultoa_s(val, buf, sizeInTChars, radix) - convert binary int to ASCII
+* string
+*
+*Purpose:
+* Converts an int to a character string.
+*
+*Entry:
+* val - number to be converted (int, long or unsigned long)
+* char *buf - ptr to buffer to place result
+* size_t sizeInTChars - size of the destination buffer
+* int radix - base to convert into
+*
+*Exit:
+* Fills in space pointed to by buf with string result.
+* Returns the errno_t: err != 0 means that something went wrong, and
+* an empty string (buf[0] = 0) is returned.
+*
+*Exceptions:
+* Input parameters and buffer length are validated.
+* Refer to the validation section of the function.
+*
+*******************************************************************************/
+
+/* helper routine that does the main job. */
+#ifdef _SECURE_ITOA
+static errno_t __stdcall xtox_s
+ (
+ unsigned long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ unsigned radix,
+ int is_neg
+ )
+#else /* _SECURE_ITOA */
+static void __stdcall xtox
+ (
+ unsigned long val,
+ TCHAR *buf,
+ unsigned radix,
+ int is_neg
+ )
+#endif /* _SECURE_ITOA */
+{
+ TCHAR *p; /* pointer to traverse string */
+ TCHAR *firstdig; /* pointer to first digit */
+ TCHAR temp; /* temp char */
+ unsigned digval; /* value of digit */
+#ifdef _SECURE_ITOA
+ size_t length; /* current length of the string */
+
+ /* validation section */
+ _VALIDATE_RETURN_ERRCODE(buf != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(sizeInTChars > 0, EINVAL);
+ _RESET_STRING(buf, sizeInTChars);
+ _VALIDATE_RETURN_ERRCODE(sizeInTChars > (size_t)(is_neg ? 2 : 1), ERANGE);
+ _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL);
+ length = 0;
+
+#endif /* _SECURE_ITOA */
+ p = buf;
+
+ if (is_neg) {
+ /* negative, so output '-' and negate */
+ *p++ = _T('-');
+#ifdef _SECURE_ITOA
+ length++;
+#endif /* _SECURE_ITOA */
+ val = (unsigned long)(-(long)val);
+ }
+
+ firstdig = p; /* save pointer to first digit */
+
+ do {
+ digval = (unsigned) (val % radix);
+ val /= radix; /* get next digit */
+
+ /* convert to ascii and store */
+ if (digval > 9)
+ *p++ = (TCHAR) (digval - 10 + _T('a')); /* a letter */
+ else
+ *p++ = (TCHAR) (digval + _T('0')); /* a digit */
+#ifndef _SECURE_ITOA
+ } while (val > 0);
+#else /* _SECURE_ITOA */
+ length++;
+ } while (val > 0 && length < sizeInTChars);
+
+ /* Check for buffer overrun */
+ if (length >= sizeInTChars)
+ {
+ buf[0] = '\0';
+ _VALIDATE_RETURN_ERRCODE(length < sizeInTChars, ERANGE);
+ }
+#endif /* _SECURE_ITOA */
+ /* We now have the digit of the number in the buffer, but in reverse
+ order. Thus we reverse them now. */
+
+ *p-- = _T('\0'); /* terminate string; p points to last digit */
+
+ do {
+ temp = *p;
+ *p = *firstdig;
+ *firstdig = temp; /* swap *p and *firstdig */
+ --p;
+ ++firstdig; /* advance to next two digits */
+ } while (firstdig < p); /* repeat until halfway */
+#ifdef _SECURE_ITOA
+ return 0;
+#endif /* _SECURE_ITOA */
+}
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+ and return pointer to buffer. */
+
+#ifdef _SECURE_ITOA
+errno_t __cdecl _itox_s (
+ int val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ errno_t e = 0;
+
+ if (radix == 10 && val < 0)
+ e = xtox_s((unsigned long)val, buf, sizeInTChars, radix, 1);
+ else
+ e = xtox_s((unsigned long)(unsigned int)val, buf, sizeInTChars, radix, 0);
+
+ return e;
+}
+
+errno_t __cdecl _ltox_s (
+ long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ return xtox_s((unsigned long)val, buf, sizeInTChars, radix, (radix == 10 && val < 0));
+}
+
+errno_t __cdecl _ultox_s (
+ unsigned long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ return xtox_s(val, buf, sizeInTChars, radix, 0);
+}
+
+#else /* _SECURE_ITOA */
+
+/***
+*char *_itoa, *_ltoa, *_ultoa(val, buf, radix) - convert binary int to ASCII
+* string
+*
+*Purpose:
+* Converts an int to a character string.
+*
+*Entry:
+* val - number to be converted (int, long or unsigned long)
+* int radix - base to convert into
+* char *buf - ptr to buffer to place result
+*
+*Exit:
+* fills in space pointed to by buf with string result
+* returns a pointer to this buffer
+*
+*Exceptions:
+* Input parameters are validated. The buffer is assumed to be big enough to
+* contain the string. Refer to the validation section of the function.
+*
+*******************************************************************************/
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+ and return pointer to buffer. */
+
+TCHAR * __cdecl _itox (
+ int val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ if (radix == 10 && val < 0)
+ xtox((unsigned long)val, buf, radix, 1);
+ else
+ xtox((unsigned long)(unsigned int)val, buf, radix, 0);
+ return buf;
+}
+
+TCHAR * __cdecl _ltox (
+ long val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ xtox((unsigned long)val, buf, radix, (radix == 10 && val < 0));
+ return buf;
+}
+
+TCHAR * __cdecl _ultox (
+ unsigned long val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ xtox(val, buf, radix, 0);
+ return buf;
+}
+
+#endif /* _SECURE_ITOA */
+
+#ifndef _NO_INT64
+
+/***
+*char *_i64toa_s(val, buf, sizeInTChars, radix) - convert binary int to ASCII
+* string
+*
+*Purpose:
+* Converts an int64 to a character string.
+*
+*Entry:
+* val - number to be converted
+* char *buf - ptr to buffer to place result
+* size_t sizeInTChars - size of the destination buffer
+* int radix - base to convert into
+*
+*Exit:
+* Fills in space pointed to by buf with string result.
+* Returns the errno_t: err != 0 means that something went wrong, and
+* an empty string (buf[0] = 0) is returned.
+*
+*Exceptions:
+* Input parameters and buffer length are validated.
+* Refer to the validation section of the function.
+*
+*******************************************************************************/
+
+#ifdef _SECURE_ITOA
+static errno_t __fastcall x64tox_s
+ (/* stdcall is faster and smaller... Might as well use it for the helper. */
+ unsigned __int64 val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ unsigned radix,
+ int is_neg
+ )
+#else /* _SECURE_ITOA */
+static void __fastcall x64tox
+ (/* stdcall is faster and smaller... Might as well use it for the helper. */
+ unsigned __int64 val,
+ TCHAR *buf,
+ unsigned radix,
+ int is_neg
+ )
+#endif /* _SECURE_ITOA */
+{
+ TCHAR *p; /* pointer to traverse string */
+ TCHAR *firstdig; /* pointer to first digit */
+ TCHAR temp; /* temp char */
+ unsigned digval; /* value of digit */
+#ifdef _SECURE_ITOA
+ size_t length; /* current length of the string */
+
+ /* validation section */
+ _VALIDATE_RETURN_ERRCODE(buf != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(sizeInTChars > 0, EINVAL);
+ _RESET_STRING(buf, sizeInTChars);
+ _VALIDATE_RETURN_ERRCODE(sizeInTChars > (size_t)(is_neg ? 2 : 1), ERANGE);
+ _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL);
+ length = 0;
+#endif /* _SECURE_ITOA */
+ p = buf;
+
+ if ( is_neg )
+ {
+ *p++ = _T('-'); /* negative, so output '-' and negate */
+#ifdef _SECURE_ITOA
+ length++;
+#endif /* _SECURE_ITOA */
+ val = (unsigned __int64)(-(__int64)val);
+ }
+
+ firstdig = p; /* save pointer to first digit */
+
+ do {
+ digval = (unsigned) (val % radix);
+ val /= radix; /* get next digit */
+
+ /* convert to ascii and store */
+ if (digval > 9)
+ *p++ = (TCHAR) (digval - 10 + _T('a')); /* a letter */
+ else
+ *p++ = (TCHAR) (digval + _T('0')); /* a digit */
+
+#ifndef _SECURE_ITOA
+ } while (val > 0);
+#else /* _SECURE_ITOA */
+ length++;
+ } while (val > 0 && length < sizeInTChars);
+
+ /* Check for buffer overrun */
+ if (length >= sizeInTChars)
+ {
+ buf[0] = '\0';
+ _VALIDATE_RETURN_ERRCODE(length < sizeInTChars, ERANGE);
+ }
+#endif /* _SECURE_ITOA */
+ /* We now have the digit of the number in the buffer, but in reverse
+ order. Thus we reverse them now. */
+
+ *p-- = _T('\0'); /* terminate string; p points to last digit */
+
+ do {
+ temp = *p;
+ *p = *firstdig;
+ *firstdig = temp; /* swap *p and *firstdig */
+ --p;
+ ++firstdig; /* advance to next two digits */
+ } while (firstdig < p); /* repeat until halfway */
+
+#ifdef _SECURE_ITOA
+ return 0;
+#endif /* _SECURE_ITOA */
+}
+
+#ifdef _SECURE_ITOA
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+ and return pointer to buffer. */
+
+errno_t __cdecl _i64tox_s (
+ long long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ return x64tox_s((unsigned __int64)val, buf, sizeInTChars, radix, (radix == 10 && val < 0));
+}
+
+errno_t __cdecl _ui64tox_s (
+ unsigned long long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ return x64tox_s(val, buf, sizeInTChars, radix, 0);
+}
+
+#else /* _SECURE_ITOA */
+
+/***
+*char *_i64toa(val, buf, radix) - convert binary int to ASCII
+* string
+*
+*Purpose:
+* Converts an int64 to a character string.
+*
+*Entry:
+* val - number to be converted
+* int radix - base to convert into
+* char *buf - ptr to buffer to place result
+*
+*Exit:
+* fills in space pointed to by buf with string result
+* returns a pointer to this buffer
+*
+*Exceptions:
+* Input parameters are validated. The buffer is assumed to be big enough to
+* contain the string. Refer to the validation section of the function.
+*
+*******************************************************************************/
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+ and return pointer to buffer. */
+
+TCHAR * __cdecl _i64tox (
+ __int64 val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ x64tox((unsigned __int64)val, buf, radix, (radix == 10 && val < 0));
+ return buf;
+}
+
+TCHAR * __cdecl _ui64tox (
+ unsigned __int64 val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ x64tox(val, buf, radix, 0);
+ return buf;
+}
+
+#endif /* _SECURE_ITOA */
+
+#endif /* _NO_INT64 */