// Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. /* Foreign builtins. */ #include "vg/valgrind.h" #include #include #include #include #include #if !defined(__WIN32__) #include #include #include #include #include #include #else #include #include #include #include #endif #ifdef __APPLE__ #include #include #if !(TARGET_OS_IPHONE) #include #endif #endif #ifdef __ANDROID__ time_t timegm(struct tm *tm) { time_t ret; char *tz; tz = getenv("TZ"); if (tz) tz = strdup(tz); setenv("TZ", "", 1); tzset(); ret = mktime(tm); if (tz) { setenv("TZ", tz, 1); free(tz); } else unsetenv("TZ"); tzset(); return ret; } #endif #ifdef __APPLE__ #if (TARGET_OS_IPHONE) extern char **environ; #endif #endif #if defined(__FreeBSD__) || defined(__linux__) || defined(__ANDROID__) extern char **environ; #endif #if defined(__WIN32__) char** rust_env_pairs() { return 0; } #else char** rust_env_pairs() { #if defined(__APPLE__) && !(TARGET_OS_IPHONE) char **environ = *_NSGetEnviron(); #endif return environ; } #endif char* #if defined(__WIN32__) rust_list_dir_val(WIN32_FIND_DATA* entry_ptr) { return entry_ptr->cFileName; } #else rust_list_dir_val(struct dirent* entry_ptr) { return entry_ptr->d_name; } #endif size_t #if defined(__WIN32__) rust_list_dir_wfd_size() { return sizeof(WIN32_FIND_DATAW); } #else rust_list_dir_wfd_size() { return 0; } #endif void* #if defined(__WIN32__) rust_list_dir_wfd_fp_buf(WIN32_FIND_DATAW* wfd) { if(wfd == NULL) { return 0; } else { return wfd->cFileName; } } #else rust_list_dir_wfd_fp_buf(void* wfd) { return 0; } #endif typedef struct { size_t fill; // in bytes; if zero, heapified size_t alloc; // in bytes uint8_t data[0]; } rust_vec; typedef rust_vec rust_str; typedef struct { int32_t tm_sec; int32_t tm_min; int32_t tm_hour; int32_t tm_mday; int32_t tm_mon; int32_t tm_year; int32_t tm_wday; int32_t tm_yday; int32_t tm_isdst; int32_t tm_gmtoff; rust_str *tm_zone; int32_t tm_nsec; } rust_tm; void rust_tm_to_tm(rust_tm* in_tm, struct tm* out_tm) { memset(out_tm, 0, sizeof(struct tm)); out_tm->tm_sec = in_tm->tm_sec; out_tm->tm_min = in_tm->tm_min; out_tm->tm_hour = in_tm->tm_hour; out_tm->tm_mday = in_tm->tm_mday; out_tm->tm_mon = in_tm->tm_mon; out_tm->tm_year = in_tm->tm_year; out_tm->tm_wday = in_tm->tm_wday; out_tm->tm_yday = in_tm->tm_yday; out_tm->tm_isdst = in_tm->tm_isdst; } void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff, const char *zone, int32_t nsec) { out_tm->tm_sec = in_tm->tm_sec; out_tm->tm_min = in_tm->tm_min; out_tm->tm_hour = in_tm->tm_hour; out_tm->tm_mday = in_tm->tm_mday; out_tm->tm_mon = in_tm->tm_mon; out_tm->tm_year = in_tm->tm_year; out_tm->tm_wday = in_tm->tm_wday; out_tm->tm_yday = in_tm->tm_yday; out_tm->tm_isdst = in_tm->tm_isdst; out_tm->tm_gmtoff = gmtoff; out_tm->tm_nsec = nsec; if (zone != NULL) { size_t size = strlen(zone); assert(out_tm->tm_zone->alloc >= size); memcpy(out_tm->tm_zone->data, zone, size); out_tm->tm_zone->fill = size; } } #if defined(__WIN32__) #define TZSET() _tzset() #if defined(_MSC_VER) && (_MSC_VER >= 1400) #define GMTIME(clock, result) gmtime_s((result), (clock)) #define LOCALTIME(clock, result) localtime_s((result), (clock)) #define TIMEGM(result) _mkgmtime64(result) #else struct tm* GMTIME(const time_t *clock, struct tm *result) { struct tm* t = gmtime(clock); if (t == NULL || result == NULL) { return NULL; } *result = *t; return result; } struct tm* LOCALTIME(const time_t *clock, struct tm *result) { struct tm* t = localtime(clock); if (t == NULL || result == NULL) { return NULL; } *result = *t; return result; } #define TIMEGM(result) mktime((result)) - _timezone #endif #else #define TZSET() tzset() #define GMTIME(clock, result) gmtime_r((clock), (result)) #define LOCALTIME(clock, result) localtime_r((clock), (result)) #define TIMEGM(result) timegm(result) #endif void rust_tzset() { TZSET(); } void rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { struct tm tm; time_t s = sec; GMTIME(&s, &tm); tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec); } void rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { struct tm tm; time_t s = sec; LOCALTIME(&s, &tm); const char* zone = NULL; #if defined(__WIN32__) int32_t gmtoff = -timezone; wchar_t wbuffer[64] = {0}; char buffer[256] = {0}; // strftime("%Z") can contain non-UTF-8 characters on non-English locale (issue #9418), // so time zone should be converted from UTF-16 string. // Since wcsftime depends on setlocale() result, // instead we convert it using MultiByteToWideChar. if (strftime(buffer, sizeof(buffer) / sizeof(char), "%Z", &tm) > 0) { // ANSI -> UTF-16 MultiByteToWideChar(CP_ACP, 0, buffer, -1, wbuffer, sizeof(wbuffer) / sizeof(wchar_t)); // UTF-16 -> UTF-8 WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL); zone = buffer; } #else int32_t gmtoff = tm.tm_gmtoff; zone = tm.tm_zone; #endif tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec); } int64_t rust_timegm(rust_tm* timeptr) { struct tm t; rust_tm_to_tm(timeptr, &t); return TIMEGM(&t); } int64_t rust_mktime(rust_tm* timeptr) { struct tm t; rust_tm_to_tm(timeptr, &t); return mktime(&t); } #ifndef _WIN32 DIR* rust_opendir(char *dirname) { return opendir(dirname); } int rust_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { return readdir_r(dirp, entry, result); } int rust_dirent_t_size() { return sizeof(struct dirent); } #else void rust_opendir() { } void rust_readdir() { } void rust_dirent_t_size() { } #endif uintptr_t rust_running_on_valgrind() { return RUNNING_ON_VALGRIND; } #if defined(__WIN32__) int get_num_cpus() { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); return (int) sysinfo.dwNumberOfProcessors; } #elif defined(__BSD__) int get_num_cpus() { /* swiped from http://stackoverflow.com/questions/150355/ programmatically-find-the-number-of-cores-on-a-machine */ unsigned int numCPU; int mib[4]; size_t len = sizeof(numCPU); /* set the mib for hw.ncpu */ mib[0] = CTL_HW; mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU; /* get the number of CPUs from the system */ sysctl(mib, 2, &numCPU, &len, NULL, 0); if( numCPU < 1 ) { mib[1] = HW_NCPU; sysctl( mib, 2, &numCPU, &len, NULL, 0 ); if( numCPU < 1 ) { numCPU = 1; } } return numCPU; } #elif defined(__GNUC__) int get_num_cpus() { return sysconf(_SC_NPROCESSORS_ONLN); } #endif uintptr_t rust_get_num_cpus() { return get_num_cpus(); } unsigned int rust_valgrind_stack_register(void *start, void *end) { return VALGRIND_STACK_REGISTER(start, end); } void rust_valgrind_stack_deregister(unsigned int id) { VALGRIND_STACK_DEREGISTER(id); } #if defined(__WIN32__) void rust_unset_sigprocmask() { // empty stub for windows to keep linker happy } #else void rust_unset_sigprocmask() { // this can't be safely converted to rust code because the // representation of sigset_t is platform-dependent sigset_t sset; sigemptyset(&sset); sigprocmask(SIG_SETMASK, &sset, NULL); } #endif #if defined(__WIN32__) void win32_require(LPCTSTR fn, BOOL ok) { if (!ok) { LPTSTR buf; DWORD err = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL ); fprintf(stderr, "%s failed with error %ld: %s", fn, err, buf); LocalFree((HLOCAL)buf); abort(); } } void rust_win32_rand_acquire(HCRYPTPROV* phProv) { win32_require (_T("CryptAcquireContext"), // changes to the parameters here should be reflected in the docs of // std::rand::os::OSRng CryptAcquireContext(phProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT|CRYPT_SILENT)); } void rust_win32_rand_gen(HCRYPTPROV hProv, DWORD dwLen, BYTE* pbBuffer) { win32_require (_T("CryptGenRandom"), CryptGenRandom(hProv, dwLen, pbBuffer)); } void rust_win32_rand_release(HCRYPTPROV hProv) { win32_require (_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0)); } #else // these symbols are listed in rustrt.def.in, so they need to exist; but they // should never be called. void rust_win32_rand_acquire() { abort(); } void rust_win32_rand_gen() { abort(); } void rust_win32_rand_release() { abort(); } #endif // // Local Variables: // mode: C++ // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // End: //