summaryrefslogtreecommitdiffstats
path: root/dstring.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2020-10-01 10:59:53 -0400
committerTavian Barnes <tavianator@tavianator.com>2020-10-01 10:59:53 -0400
commit345fd739496034fcfccf8fb943765a4e3beaedc4 (patch)
tree45a9f6c0129b537809fc988a641626dfb342b05c /dstring.c
parent958d591c888a4b9ab457ae414ef120dae77ee589 (diff)
downloadbfs-345fd739496034fcfccf8fb943765a4e3beaedc4.tar.xz
dstring: Try to avoid calling vsnprintf() twice in dstrprintf()
Diffstat (limited to 'dstring.c')
-rw-r--r--dstring.c36
1 files changed, 26 insertions, 10 deletions
diff --git a/dstring.c b/dstring.c
index 8b226bc..d370598 100644
--- a/dstring.c
+++ b/dstring.c
@@ -129,28 +129,44 @@ int dstrapp(char **str, char c) {
}
char *dstrprintf(const char *format, ...) {
+ // Guess a length to try to avoid calling vsnprintf() twice
+ int len, cap = 2*strlen(format);
+ char *str = dstralloc(cap);
+ if (!str) {
+ return NULL;
+ }
+
va_list args;
va_start(args, format);
- int len = vsnprintf(NULL, 0, format, args);
+ len = vsnprintf(str, cap + 1, format, args);
va_end(args);
- assert(len > 0);
+ if (len > cap) {
+ if (dstreserve(&str, len) != 0) {
+ goto fail;
+ }
- char *str = dstralloc(len);
- if (!str) {
- return NULL;
+ cap = len;
+
+ va_start(args, format);
+ len = vsnprintf(str, cap + 1, format, args);
+ va_end(args);
+
+ assert(len == cap);
}
- va_start(args, format);
- len = vsnprintf(str, len + 1, format, args);
- va_end(args);
+ if (len < 0) {
+ goto fail;
+ }
struct dstring *header = dstrheader(str);
- assert(len == header->capacity);
header->length = len;
-
return str;
+
+fail:
+ dstrfree(str);
+ return NULL;
}
void dstrfree(char *dstr) {