int Str_Vsnprintf(char *str, // OUT size_t size, // IN const char *format, // IN va_list ap) // IN { int retval; ASSERT(str != NULL); ASSERT(format != NULL); #ifndef HAS_BSD_PRINTF retval = vsnprintf(str, size, format, ap); #elif defined __linux__ { va_list aq; va_copy(aq, ap); retval = bsd_vsnprintf(&str, size, format, aq); va_end(aq); } #else retval = bsd_vsnprintf(&str, size, format, ap); #endif /* * Linux glibc 2.0.x returns -1 and null terminates (which we shouldn't * be linking against), but glibc 2.1.x follows c99 and returns * characters that would have been written. * * In the case of Win32 and !HAS_BSD_PRINTF, we are using * _vsnprintf(), which returns -1 on overflow, returns size * when result fits exactly, and does not null terminate in * those cases. */ if ((retval < 0 || retval >= size) && size > 0) { /* Find UTF-8 code point boundary and place NUL termination there */ int trunc = CodeSet_Utf8FindCodePointBoundary(str, size - 1); str[trunc] = '\0'; } if (retval >= size) { return -1; } return retval; }
Bool Unicode_CopyBytes(void *destBuffer, // OUT ConstUnicode srcBuffer, // IN size_t maxLengthInBytes, // IN size_t *retLength, // OUT StringEncoding encoding) // IN { const char *utf8Str = (const char *)srcBuffer; Bool success = FALSE; size_t copyBytes = 0; encoding = Unicode_ResolveEncoding(encoding); switch (encoding) { case STRING_ENCODING_US_ASCII: if (!UnicodeSanityCheck(utf8Str, -1, encoding)) { break; } // fall through case STRING_ENCODING_UTF8: { size_t len = strlen(utf8Str); copyBytes = MIN(len, maxLengthInBytes - 1); memcpy(destBuffer, utf8Str, copyBytes); /* * If we truncated, force a null termination in a UTF-8 safe * manner. */ if (copyBytes >= len) { success = TRUE; } else { if (encoding == STRING_ENCODING_UTF8) { copyBytes = CodeSet_Utf8FindCodePointBoundary(destBuffer, copyBytes); } } ((char*)destBuffer)[copyBytes] = '\0'; } break; case STRING_ENCODING_UTF16_LE: { char *utf16Buf; size_t utf16BufLen; if (!CodeSet_Utf8ToUtf16le(utf8Str, strlen(utf8Str), &utf16Buf, &utf16BufLen)) { // input should be valid UTF-8, no conversion error possible ASSERT_MEM_ALLOC(FALSE); break; } copyBytes = MIN(utf16BufLen, maxLengthInBytes - 2); memcpy(destBuffer, utf16Buf, copyBytes); copyBytes = CodeSet_Utf16FindCodePointBoundary(destBuffer, copyBytes); ((utf16_t*)destBuffer)[copyBytes / 2] = 0; free(utf16Buf); if (copyBytes >= utf16BufLen) { success = TRUE; } break; } default: { char *currentBuf; size_t currentBufSize; if (!CodeSet_GenericToGeneric("UTF-8", utf8Str, strlen(utf8Str), Unicode_EncodingEnumToName(encoding), CSGTG_NORMAL, ¤tBuf, ¤tBufSize)) { // XXX can't distinguish error cause break; } copyBytes = MIN(currentBufSize, maxLengthInBytes - 1); memcpy(destBuffer, currentBuf, copyBytes); free(currentBuf); /* * XXX this isn't quite correct, we still need to truncate on * a code point boundary, based on the current encoding type, * rather than just null terminate blindly. */ ((char*)destBuffer)[copyBytes] = 0; if (copyBytes >= currentBufSize) { success = TRUE; } } break; } if (retLength) { *retLength = copyBytes; } return success; }
const char * Err_Errno2String(Err_Number errorNumber) // IN { HashTable *numTable; HashTable *ptrTable; ErrInfo *info; ErrInfo *oldInfo; Err_Number oldErrno = Err_Errno(); ASSERT(errorNumber != ERR_INVALID); /* * Look up the error in numTable. * Or insert it if it's not there. */ numTable = NUMTABLE(); if (!HashTable_Lookup(numTable, (void *) (uintptr_t) errorNumber, (void **) &info)) { char buf[2048]; const char *p; size_t n; /* * Convert number to string and build the info structure. */ p = ErrErrno2String(errorNumber, buf, sizeof buf); info = Util_SafeMalloc(sizeof *info); info->number = errorNumber; info->string = Util_SafeStrdup(p); /* * To be safe, make sure the end of the string is at * a UTF-8 boundary, but we can only do this when the * string is in our buffer (it may not be). */ n = strlen(info->string); n = CodeSet_Utf8FindCodePointBoundary(info->string, n); info->string[n] = '\0'; /* * Try to insert new info into numTable. * If that fails, then we must have lost out to someone else. * Use theirs in that case. */ oldInfo = HashTable_LookupOrInsert(numTable, (void *) (uintptr_t) errorNumber, info); if (oldInfo != info) { ASSERT(oldInfo->number == info->number); ASSERT(Str_Strcmp(oldInfo->string, info->string) == 0); free(info->string); free(info); info = oldInfo; } } /* * Try to insert info into ptrTable. * We need to do it even if we didn't create this entry, * because we may get here before the other guy (who created * the entry and inserted it into numTable). */ ptrTable = PTRTABLE(); oldInfo = HashTable_LookupOrInsert(ptrTable, info->string, info); ASSERT(oldInfo == info); #if defined VMX86_DEBUG && defined __linux__ { HashTable *strTable = STRTABLE(); ErrInfo *i = HashTable_LookupOrInsert(strTable, info->string, info); ASSERT(i == info); } #endif Err_SetErrno(oldErrno); return info->string; }