char *__kmp_env_get(char const *name) { char *result = NULL; #if KMP_OS_UNIX char const *value = getenv(name); if (value != NULL) { size_t len = KMP_STRLEN(value) + 1; result = (char *)KMP_INTERNAL_MALLOC(len); if (result == NULL) { KMP_FATAL(MemoryAllocFailed); } KMP_STRNCPY_S(result, len, value, len); } #elif KMP_OS_WINDOWS /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the act of loading a DLL on Windows* OS makes any user-set environment variables (i.e. with putenv()) unavailable. getenv() apparently gets a clean copy of the env variables as they existed at the start of the run. JH 12/23/2002 */ DWORD rc; rc = GetEnvironmentVariable(name, NULL, 0); if (!rc) { DWORD error = GetLastError(); if (error != ERROR_ENVVAR_NOT_FOUND) { __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); } // Variable is not found, it's ok, just continue. } else { DWORD len = rc; result = (char *)KMP_INTERNAL_MALLOC(len); if (result == NULL) { KMP_FATAL(MemoryAllocFailed); } rc = GetEnvironmentVariable(name, result, len); if (!rc) { // GetEnvironmentVariable() may return 0 if variable is empty. // In such a case GetLastError() returns ERROR_SUCCESS. DWORD error = GetLastError(); if (error != ERROR_SUCCESS) { // Unexpected error. The variable should be in the environment, // and buffer should be large enough. __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); KMP_INTERNAL_FREE((void *)result); result = NULL; } } } #else #error Unknown or unsupported OS. #endif return result; } // func __kmp_env_get
static inline void *allocate(size_t size) { void *ptr = KMP_INTERNAL_MALLOC(size); if (ptr == NULL) { KMP_FATAL(MemoryAllocFailed); } return ptr; } // allocate
char * __kmp_str_format( // Allocated string. char const * format, // Format string. ... // Other parameters. ) { va_list args; int size = 512; char * buffer = NULL; int rc; // Allocate buffer. buffer = (char *) KMP_INTERNAL_MALLOC( size ); if ( buffer == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if for ( ; ; ) { // Try to format string. va_start( args, format ); rc = vsnprintf( buffer, size, format, args ); va_end( args ); // No errors, string has been formatted. if ( rc >= 0 && rc < size ) { break; }; // if // Error occured, buffer is too small. if ( rc >= 0 ) { // C99-conforming implementation of vsnprintf returns required buffer size. size = rc + 1; } else { // Older implementations just return -1. size = size * 2; }; // if // Enlarge buffer and try again. buffer = (char *) KMP_INTERNAL_REALLOC( buffer, size ); if ( buffer == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if }; // forever return buffer; } // func __kmp_str_format
void __kmp_str_buf_detach( kmp_str_buf_t * buffer ) { KMP_STR_BUF_INVARIANT( buffer ); // If internal bulk is used, allocate memory and copy it. if ( buffer->size <= sizeof( buffer->bulk ) ) { buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size ); if ( buffer->str == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if memcpy( buffer->str, buffer->bulk, buffer->used + 1 ); }; // if } // __kmp_str_buf_detach
void __kmp_str_buf_reserve( kmp_str_buf_t * buffer, int size ) { KMP_STR_BUF_INVARIANT( buffer ); KMP_DEBUG_ASSERT( size >= 0 ); if ( buffer->size < size ) { // Calculate buffer size. do { buffer->size *= 2; } while ( buffer->size < size ); // Enlarge buffer. if ( buffer->str == & buffer->bulk[ 0 ] ) { buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size ); if ( buffer->str == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if memcpy( buffer->str, buffer->bulk, buffer->used + 1 ); } else { buffer->str = (char *) KMP_INTERNAL_REALLOC( buffer->str, buffer->size ); if ( buffer->str == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if }; // if }; // if KMP_DEBUG_ASSERT( buffer->size > 0 ); KMP_DEBUG_ASSERT( buffer->size >= size ); KMP_STR_BUF_INVARIANT( buffer ); } // __kmp_str_buf_reserve
static char * sys_error( int err ) { char * message = NULL; #if KMP_OS_WINDOWS LPVOID buffer = NULL; int len; DWORD rc; rc = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language. (LPTSTR) & buffer, 0, NULL ); if ( rc > 0 ) { // Message formatted. Copy it (so we can free it later with normal free(). message = __kmp_str_format( "%s", (char *) buffer ); len = ___strip_crs( message ); // Delete carriage returns if any. // Strip trailing newlines. while ( len > 0 && message[ len - 1 ] == '\n' ) { -- len; }; // while message[ len ] = 0; } else { // FormatMessage() failed to format system error message. GetLastError() would give us // error code, which we would convert to message... this it dangerous recursion, which // cannot clarify original error, so we will not even start it. }; // if if ( buffer != NULL ) { LocalFree( buffer ); }; // if #else // Non-Windows* OS: Linux* OS or OS X* /* There are 2 incompatible versions of strerror_r: char * strerror_r( int, char *, size_t ); // GNU version int strerror_r( int, char *, size_t ); // XSI version */ #if defined(__GLIBC__) && defined(_GNU_SOURCE) // GNU version of strerror_r. char buffer[ 2048 ]; char * const err_msg = strerror_r( err, buffer, sizeof( buffer ) ); // Do not eliminate this assignment to temporary variable, otherwise compiler would // not issue warning if strerror_r() returns `int' instead of expected `char *'. message = __kmp_str_format( "%s", err_msg ); #else // OS X*, FreeBSD* etc. // XSI version of strerror_r. int size = 2048; // TODO: Add checking result of malloc(). char * buffer = (char *) KMP_INTERNAL_MALLOC( size ); int rc; if (buffer == NULL) { KMP_FATAL(MemoryAllocFailed); } rc = strerror_r( err, buffer, size ); if ( rc == -1 ) { rc = errno; // XSI version sets errno. }; // if while ( rc == ERANGE ) { // ERANGE means the buffer is too small. KMP_INTERNAL_FREE( buffer ); size *= 2; buffer = (char *) KMP_INTERNAL_MALLOC( size ); if (buffer == NULL) { KMP_FATAL(MemoryAllocFailed); } rc = strerror_r( err, buffer, size ); if ( rc == -1 ) { rc = errno; // XSI version sets errno. }; // if }; // while if ( rc == 0 ) { message = buffer; } else { // Buffer is unused. Free it. KMP_INTERNAL_FREE( buffer ); }; // if #endif #endif /* KMP_OS_WINDOWS */ if ( message == NULL ) { // TODO: I18n this message. message = __kmp_str_format( "%s", "(No system error message available)" ); }; // if return message; } // sys_error
static char const * ___catgets( kmp_i18n_id_t id ) { char * result = NULL; PVOID addr = NULL; wchar_t * wmsg = NULL; DWORD wlen = 0; char * msg = NULL; int len = 0; int rc; KMP_DEBUG_ASSERT( cat != KMP_I18N_NULLCAT ); wlen = // wlen does *not* include terminating null. FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, cat, id, 0, // LangId (LPWSTR) & addr, 0, // Size in elements, not in bytes. NULL ); if ( wlen <= 0 ) { goto end; }; // if wmsg = (wchar_t *) addr; // Warning: wmsg may be not nul-terminated! // Calculate length of multibyte message. len = // Since wlen does not include terminating null, len does not include it also. WideCharToMultiByte( code_page, 0, // Flags. wmsg, wlen, // Wide buffer and size. NULL, 0, // Buffer and size. NULL, NULL // Default char and used default char. ); if ( len <= 0 ) { goto end; }; // if // Allocate memory. msg = (char *) KMP_INTERNAL_MALLOC( len + 1 ); // Convert wide message to multibyte one. rc = WideCharToMultiByte( code_page, 0, // Flags. wmsg, wlen, // Wide buffer and size. msg, len, // Buffer and size. NULL, NULL // Default char and used default char. ); if ( rc <= 0 || rc > len ) { goto end; }; // if KMP_DEBUG_ASSERT( rc == len ); len = rc; msg[ len ] = 0; // Put terminating null to the end. // Stripping all "\r" before stripping last end-of-line simplifies the task. len = ___strip_crs( msg ); // Every message in catalog is terminated with "\n". Strip it. if ( len >= 1 && msg[ len - 1 ] == '\n' ) { -- len; msg[ len ] = 0; }; // if // Everything looks ok. result = msg; msg = NULL; end: if ( msg != NULL ) { KMP_INTERNAL_FREE( msg ); }; // if if ( wmsg != NULL ) { LocalFree( wmsg ); }; // if return result; } // ___catgets