diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2012-03-03 19:12:06 -0800 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2012-03-03 19:12:06 -0800 |
commit | 0a5680c3e8c41e5f19b3beb4e6ac31a8560f99dd (patch) | |
tree | 95fcb794567dcf8397c42596d2deff994a70de86 /common.cpp | |
parent | 00764406d78eb223b41536ad011b0f31735d532c (diff) |
Rewrite vformat_string to not use string_buffer
Diffstat (limited to 'common.cpp')
-rw-r--r-- | common.cpp | 56 |
1 files changed, 50 insertions, 6 deletions
@@ -449,12 +449,56 @@ wcstring format_string(const wchar_t *format, ...) } wcstring vformat_string(const wchar_t *format, va_list va_orig) -{ - string_buffer_t buffer; - sb_init(&buffer); - sb_vprintf(&buffer, format, va_orig); - wcstring result = (wchar_t *)buffer.buff; - sb_destroy(&buffer); +{ + const int saved_err = errno; + /* + As far as I know, there is no way to check if a + vswprintf-call failed because of a badly formated string + option or because the supplied destination string was to + small. In GLIBC, errno seems to be set to EINVAL either way. + + Because of this, on failiure we try to + increase the buffer size until the free space is + larger than max_size, at which point it will + conclude that the error was probably due to a badly + formated string option, and return an error. Make + sure to null terminate string before that, though. + */ + const size_t max_size = (128*1024*1024); + wchar_t static_buff[256]; + size_t size = 0; + wchar_t *buff = NULL; + int status = -1; + while (status < 0) { + /* Reallocate if necessary */ + if (size == 0) { + buff = static_buff; + size = sizeof static_buff; + } else { + size *= 2; + if (size >= max_size) { + buff[0] = '\0'; + break; + } + buff = (wchar_t *)realloc( (buff == static_buff ? NULL : buff), size); + if (buff == NULL) { + DIE_MEM(); + } + } + + /* Try printing */ + va_list va; + va_copy( va, va_orig ); + status = vswprintf(buff, size / sizeof(wchar_t), format, va); + va_end(va); + } + + wcstring result = wcstring(buff); + + if (buff != static_buff) + free(buff); + + errno = saved_err; return result; } |