454 lines
13 KiB
C
454 lines
13 KiB
C
|
/***
|
||
|
*xtoa.c - convert integers/longs to ASCII string
|
||
|
*
|
||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
*
|
||
|
*Purpose:
|
||
|
* The module has code to convert integers/longs to ASCII strings. See
|
||
|
*
|
||
|
*******************************************************************************/
|
||
|
|
||
|
#include <cruntime.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <limits.h>
|
||
|
#include <tchar.h>
|
||
|
#include <internal.h>
|
||
|
#include <internal_securecrt.h>
|
||
|
|
||
|
#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 (
|
||
|
__int64 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 __int64 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 */
|