mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
When building on Linux, the definition of `swift_snprintf_l` would cause an unused function warning. Expand the scope of the preprocessor guard to encompass the function for the single use. This avoids the unused function warning.
459 lines
13 KiB
C++
459 lines
13 KiB
C++
//===--- Stubs.cpp - Swift Language ABI Runtime Stubs ---------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Misc stubs for functions which should be defined in the core standard
|
|
// library, but are difficult or impossible to write in Swift at the
|
|
// moment.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#if defined(__FreeBSD__)
|
|
#define _WITH_GETLINE
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
#define WIN32_LEAN_AND_MEAN
|
|
// Avoid defining macro max(), min() which conflict with std::max(), std::min()
|
|
#define NOMINMAX
|
|
#include <windows.h>
|
|
#else
|
|
#if !defined(__HAIKU__)
|
|
#include <sys/errno.h>
|
|
#else
|
|
#include <errno.h>
|
|
#endif
|
|
#include <sys/resource.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <climits>
|
|
#include <clocale>
|
|
#include <cstdarg>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#if defined(__CYGWIN__) || defined(_WIN32) || defined(__HAIKU__)
|
|
#include <sstream>
|
|
#include <cmath>
|
|
#elif defined(__ANDROID__)
|
|
#include <locale.h>
|
|
|
|
#include <android/api-level.h>
|
|
|
|
#if __ANDROID_API__ < 21 // Introduced in Android API 21 - L
|
|
static inline long double swift_strtold_l(const char *nptr, char **endptr,
|
|
locale_t) {
|
|
return strtod(nptr, endptr);
|
|
}
|
|
#define strtold_l swift_strtold_l
|
|
#endif
|
|
|
|
#if __ANDROID_API__ < 26 // Introduced in Android API 26 - O
|
|
static double swift_strtod_l(const char *nptr, char **endptr, locale_t loc) {
|
|
return strtod(nptr, endptr);
|
|
}
|
|
static float swift_strtof_l(const char *nptr, char **endptr, locale_t loc) {
|
|
return strtof(nptr, endptr);
|
|
}
|
|
#define strtod_l swift_strtod_l
|
|
#define strtof_l swift_strtof_l
|
|
#endif
|
|
#elif defined(__linux__)
|
|
#include <locale.h>
|
|
#else
|
|
#include <xlocale.h>
|
|
#endif
|
|
#include <limits>
|
|
#include <thread>
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "swift/Runtime/Debug.h"
|
|
#include "swift/Runtime/SwiftDtoa.h"
|
|
#include "swift/Basic/Lazy.h"
|
|
|
|
#include "../SwiftShims/LibcShims.h"
|
|
#include "../SwiftShims/RuntimeShims.h"
|
|
#include "../SwiftShims/RuntimeStubs.h"
|
|
|
|
static uint64_t uint64ToStringImpl(char *Buffer, uint64_t Value,
|
|
int64_t Radix, bool Uppercase,
|
|
bool Negative) {
|
|
char *P = Buffer;
|
|
uint64_t Y = Value;
|
|
|
|
if (Y == 0) {
|
|
*P++ = '0';
|
|
} else if (Radix == 10) {
|
|
while (Y) {
|
|
*P++ = '0' + char(Y % 10);
|
|
Y /= 10;
|
|
}
|
|
} else {
|
|
unsigned Radix32 = Radix;
|
|
while (Y) {
|
|
*P++ = llvm::hexdigit(Y % Radix32, !Uppercase);
|
|
Y /= Radix32;
|
|
}
|
|
}
|
|
|
|
if (Negative)
|
|
*P++ = '-';
|
|
std::reverse(Buffer, P);
|
|
return size_t(P - Buffer);
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
uint64_t swift_int64ToString(char *Buffer, size_t BufferLength,
|
|
int64_t Value, int64_t Radix,
|
|
bool Uppercase) {
|
|
if ((Radix >= 10 && BufferLength < 32) || (Radix < 10 && BufferLength < 65))
|
|
swift::crash("swift_int64ToString: insufficient buffer size");
|
|
|
|
if (Radix == 0 || Radix > 36)
|
|
swift::crash("swift_int64ToString: invalid radix for string conversion");
|
|
|
|
bool Negative = Value < 0;
|
|
|
|
// Compute an absolute value safely, without using unary negation on INT_MIN,
|
|
// which is undefined behavior.
|
|
uint64_t UnsignedValue = Value;
|
|
if (Negative) {
|
|
// Assumes two's complement representation.
|
|
UnsignedValue = ~UnsignedValue + 1;
|
|
}
|
|
|
|
return uint64ToStringImpl(Buffer, UnsignedValue, Radix, Uppercase,
|
|
Negative);
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
uint64_t swift_uint64ToString(char *Buffer, intptr_t BufferLength,
|
|
uint64_t Value, int64_t Radix,
|
|
bool Uppercase) {
|
|
if ((Radix >= 10 && BufferLength < 32) || (Radix < 10 && BufferLength < 64))
|
|
swift::crash("swift_int64ToString: insufficient buffer size");
|
|
|
|
if (Radix == 0 || Radix > 36)
|
|
swift::crash("swift_int64ToString: invalid radix for string conversion");
|
|
|
|
return uint64ToStringImpl(Buffer, Value, Radix, Uppercase,
|
|
/*Negative=*/false);
|
|
}
|
|
|
|
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__ANDROID__)
|
|
static inline locale_t getCLocale() {
|
|
// On these platforms convenience functions from xlocale.h interpret nullptr
|
|
// as C locale.
|
|
return nullptr;
|
|
}
|
|
#elif defined(__CYGWIN__) || defined(_WIN32) || defined(__HAIKU__)
|
|
// In Cygwin, getCLocale() is not used.
|
|
#else
|
|
static locale_t makeCLocale() {
|
|
locale_t CLocale = newlocale(LC_ALL_MASK, "C", nullptr);
|
|
if (!CLocale) {
|
|
swift::crash("makeCLocale: newlocale() returned a null pointer");
|
|
}
|
|
return CLocale;
|
|
}
|
|
|
|
static locale_t getCLocale() {
|
|
return SWIFT_LAZY_CONSTANT(makeCLocale());
|
|
}
|
|
#endif
|
|
|
|
#if !SWIFT_DTOA_FLOAT80_SUPPORT
|
|
#if defined(__APPLE__)
|
|
#define swift_snprintf_l snprintf_l
|
|
#elif defined(__CYGWIN__) || defined(_WIN32) || defined(__HAIKU__)
|
|
// swift_snprintf_l() is not used.
|
|
#else
|
|
static int swift_snprintf_l(char *Str, size_t StrSize, locale_t Locale,
|
|
const char *Format, ...) {
|
|
if (Locale == nullptr) {
|
|
Locale = getCLocale();
|
|
}
|
|
locale_t OldLocale = uselocale(Locale);
|
|
|
|
va_list Args;
|
|
va_start(Args, Format);
|
|
int Result = std::vsnprintf(Str, StrSize, Format, Args);
|
|
va_end(Args);
|
|
|
|
uselocale(OldLocale);
|
|
|
|
return Result;
|
|
}
|
|
#endif
|
|
|
|
template <typename T>
|
|
static uint64_t swift_floatingPointToString(char *Buffer, size_t BufferLength,
|
|
T Value, const char *Format,
|
|
bool Debug) {
|
|
if (BufferLength < 32)
|
|
swift::crash("swift_floatingPointToString: insufficient buffer size");
|
|
|
|
int Precision = std::numeric_limits<T>::digits10;
|
|
if (Debug) {
|
|
Precision = std::numeric_limits<T>::max_digits10;
|
|
}
|
|
|
|
#if defined(__CYGWIN__) || defined(_WIN32) || defined(__HAIKU__)
|
|
// Cygwin does not support uselocale(), but we can use the locale feature
|
|
// in stringstream object.
|
|
std::ostringstream ValueStream;
|
|
ValueStream.width(0);
|
|
ValueStream.precision(Precision);
|
|
ValueStream.imbue(std::locale::classic());
|
|
ValueStream << Value;
|
|
std::string ValueString(ValueStream.str());
|
|
size_t i = ValueString.length();
|
|
|
|
if (i < BufferLength) {
|
|
std::copy(ValueString.begin(), ValueString.end(), Buffer);
|
|
Buffer[i] = '\0';
|
|
} else {
|
|
swift::crash("swift_floatingPointToString: insufficient buffer size");
|
|
}
|
|
#else
|
|
// Pass a null locale to use the C locale.
|
|
int i = swift_snprintf_l(Buffer, BufferLength, /*Locale=*/nullptr, Format,
|
|
Precision, Value);
|
|
|
|
if (i < 0)
|
|
swift::crash(
|
|
"swift_floatingPointToString: unexpected return value from sprintf");
|
|
if (size_t(i) >= BufferLength)
|
|
swift::crash("swift_floatingPointToString: insufficient buffer size");
|
|
#endif
|
|
|
|
// Add ".0" to a float that (a) is not in scientific notation, (b) does not
|
|
// already have a fractional part, (c) is not infinite, and (d) is not a NaN
|
|
// value.
|
|
if (strchr(Buffer, 'e') == nullptr && strchr(Buffer, '.') == nullptr &&
|
|
strchr(Buffer, 'n') == nullptr) {
|
|
Buffer[i++] = '.';
|
|
Buffer[i++] = '0';
|
|
}
|
|
|
|
return i;
|
|
}
|
|
#endif
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
uint64_t swift_float32ToString(char *Buffer, size_t BufferLength,
|
|
float Value, bool Debug) {
|
|
return swift_format_float(Value, Buffer, BufferLength);
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
uint64_t swift_float64ToString(char *Buffer, size_t BufferLength,
|
|
double Value, bool Debug) {
|
|
return swift_format_double(Value, Buffer, BufferLength);
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
uint64_t swift_float80ToString(char *Buffer, size_t BufferLength,
|
|
long double Value, bool Debug) {
|
|
#if SWIFT_DTOA_FLOAT80_SUPPORT
|
|
return swift_format_float80(Value, Buffer, BufferLength);
|
|
#else
|
|
// Use this when 'long double' is not true Float80
|
|
return swift_floatingPointToString<long double>(Buffer, BufferLength, Value,
|
|
"%0.*Lg", Debug);
|
|
#endif
|
|
|
|
}
|
|
|
|
/// \param[out] LinePtr Replaced with the pointer to the malloc()-allocated
|
|
/// line. Can be NULL if no characters were read. This buffer should be
|
|
/// freed by the caller if this function returns a positive value.
|
|
///
|
|
/// \returns Size of character data returned in \c LinePtr, or -1
|
|
/// if an error occurred, or EOF was reached.
|
|
swift::__swift_ssize_t
|
|
swift::swift_stdlib_readLine_stdin(unsigned char **LinePtr) {
|
|
#if defined(_WIN32)
|
|
if (LinePtr == nullptr)
|
|
return -1;
|
|
|
|
ssize_t Capacity = 0;
|
|
ssize_t Pos = 0;
|
|
unsigned char *ReadBuf = nullptr;
|
|
|
|
_lock_file(stdin);
|
|
|
|
for (;;) {
|
|
int ch = _fgetc_nolock(stdin);
|
|
|
|
if (ferror(stdin) || (ch == EOF && Pos == 0)) {
|
|
if (ReadBuf)
|
|
free(ReadBuf);
|
|
_unlock_file(stdin);
|
|
return -1;
|
|
}
|
|
|
|
if (Capacity - Pos <= 1) {
|
|
// Capacity changes to 128, 128*2, 128*4, 128*8, ...
|
|
Capacity = Capacity ? Capacity * 2 : 128;
|
|
unsigned char *NextReadBuf =
|
|
static_cast<unsigned char *>(realloc(ReadBuf, Capacity));
|
|
if (NextReadBuf == nullptr) {
|
|
if (ReadBuf)
|
|
free(ReadBuf);
|
|
_unlock_file(stdin);
|
|
return -1;
|
|
}
|
|
ReadBuf = NextReadBuf;
|
|
}
|
|
|
|
if (ch == EOF)
|
|
break;
|
|
ReadBuf[Pos++] = ch;
|
|
if (ch == '\n')
|
|
break;
|
|
}
|
|
|
|
ReadBuf[Pos] = '\0';
|
|
*LinePtr = ReadBuf;
|
|
_unlock_file(stdin);
|
|
return Pos;
|
|
#else
|
|
size_t Capacity = 0;
|
|
return getline((char **)LinePtr, &Capacity, stdin);
|
|
#endif
|
|
}
|
|
|
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
|
#define strcasecmp _stricmp
|
|
#endif
|
|
|
|
static bool swift_stringIsSignalingNaN(const char *nptr) {
|
|
if (nptr[0] == '+' || nptr[0] == '-') {
|
|
nptr++;
|
|
}
|
|
|
|
return strcasecmp(nptr, "snan") == 0;
|
|
}
|
|
|
|
#if defined(__CYGWIN__) || defined(_WIN32) || defined(__HAIKU__)
|
|
// Cygwin does not support uselocale(), but we can use the locale feature
|
|
// in stringstream object.
|
|
template <typename T>
|
|
static const char *_swift_stdlib_strtoX_clocale_impl(
|
|
const char *nptr, T *outResult) {
|
|
if (swift_stringIsSignalingNaN(nptr)) {
|
|
*outResult = std::numeric_limits<T>::signaling_NaN();
|
|
return nptr + std::strlen(nptr);
|
|
}
|
|
|
|
std::istringstream ValueStream(nptr);
|
|
ValueStream.imbue(std::locale::classic());
|
|
T ParsedValue;
|
|
ValueStream >> ParsedValue;
|
|
*outResult = ParsedValue;
|
|
|
|
std::streamoff pos = ValueStream.tellg();
|
|
if (ValueStream.eof())
|
|
pos = static_cast<std::streamoff>(strlen(nptr));
|
|
if (pos <= 0)
|
|
return nullptr;
|
|
|
|
return nptr + pos;
|
|
}
|
|
|
|
const char *swift::_swift_stdlib_strtold_clocale(
|
|
const char *nptr, void *outResult) {
|
|
return _swift_stdlib_strtoX_clocale_impl(
|
|
nptr, static_cast<long double*>(outResult));
|
|
}
|
|
|
|
const char *swift::_swift_stdlib_strtod_clocale(
|
|
const char * nptr, double *outResult) {
|
|
return _swift_stdlib_strtoX_clocale_impl(nptr, outResult);
|
|
}
|
|
|
|
const char *swift::_swift_stdlib_strtof_clocale(
|
|
const char * nptr, float *outResult) {
|
|
return _swift_stdlib_strtoX_clocale_impl(nptr, outResult);
|
|
}
|
|
#else
|
|
|
|
// We can't return Float80, but we can receive a pointer to one, so
|
|
// switch the return type and the out parameter on strtold.
|
|
template <typename T>
|
|
static const char *_swift_stdlib_strtoX_clocale_impl(
|
|
const char * nptr, T* outResult, T huge,
|
|
T (*posixImpl)(const char *, char **, locale_t)
|
|
) {
|
|
if (swift_stringIsSignalingNaN(nptr)) {
|
|
// TODO: ensure that the returned sNaN bit pattern matches that of sNaNs
|
|
// produced by Swift.
|
|
*outResult = std::numeric_limits<T>::signaling_NaN();
|
|
return nptr + std::strlen(nptr);
|
|
}
|
|
|
|
char *EndPtr;
|
|
errno = 0;
|
|
const auto result = posixImpl(nptr, &EndPtr, getCLocale());
|
|
*outResult = result;
|
|
if (result == huge || result == -huge || result == 0.0 || result == -0.0) {
|
|
if (errno == ERANGE)
|
|
EndPtr = nullptr;
|
|
}
|
|
return EndPtr;
|
|
}
|
|
|
|
const char *swift::_swift_stdlib_strtold_clocale(
|
|
const char * nptr, void *outResult) {
|
|
return _swift_stdlib_strtoX_clocale_impl(
|
|
nptr, static_cast<long double*>(outResult), HUGE_VALL, strtold_l);
|
|
}
|
|
|
|
const char *swift::_swift_stdlib_strtod_clocale(
|
|
const char * nptr, double *outResult) {
|
|
return _swift_stdlib_strtoX_clocale_impl(
|
|
nptr, outResult, HUGE_VAL, strtod_l);
|
|
}
|
|
|
|
const char *swift::_swift_stdlib_strtof_clocale(
|
|
const char * nptr, float *outResult) {
|
|
return _swift_stdlib_strtoX_clocale_impl(
|
|
nptr, outResult, HUGE_VALF, strtof_l);
|
|
}
|
|
#endif
|
|
|
|
void swift::_swift_stdlib_flockfile_stdout() {
|
|
#if defined(_WIN32)
|
|
_lock_file(stdout);
|
|
#else
|
|
flockfile(stdout);
|
|
#endif
|
|
}
|
|
|
|
void swift::_swift_stdlib_funlockfile_stdout() {
|
|
#if defined(_WIN32)
|
|
_unlock_file(stdout);
|
|
#else
|
|
funlockfile(stdout);
|
|
#endif
|
|
}
|
|
|
|
int swift::_swift_stdlib_putc_stderr(int C) {
|
|
return putc(C, stderr);
|
|
}
|
|
|
|
size_t swift::_swift_stdlib_getHardwareConcurrency() {
|
|
return std::thread::hardware_concurrency();
|
|
}
|
|
|