]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Make htsbuf_vqprintf() work with arbitrary output lengths
authorAndreas Öman <andreas@lonelycoder.com>
Sat, 1 Jan 2011 11:43:37 +0000 (12:43 +0100)
committerAndreas Öman <andreas@lonelycoder.com>
Sat, 1 Jan 2011 11:43:37 +0000 (12:43 +0100)
src/htsbuf.c

index afc88c71e63916e3f60239abf0341c7c0d6f23cf..9dc08e0bc3b6b0cf193211c06043a2b69d857c44 100644 (file)
@@ -241,13 +241,48 @@ htsbuf_drop(htsbuf_queue_t *hq, size_t len)
 }
 
 /**
- *
+ * Inspired by vsnprintf man page
  */
 void
-htsbuf_vqprintf(htsbuf_queue_t *hq, const char *fmt, va_list ap)
+htsbuf_vqprintf(htsbuf_queue_t *hq, const char *fmt, va_list ap0)
 {
-  char buf[5000];
-  htsbuf_append(hq, buf, vsnprintf(buf, sizeof(buf), fmt, ap));
+  // First try to format it on-stack
+  va_list ap;
+  int n, size;
+  char buf[100], *p, *np;
+
+  va_copy(ap, ap0);
+
+  n = vsnprintf(buf, sizeof(buf), fmt, ap);
+  if(n > -1 && n < sizeof(buf)) {
+    htsbuf_append(hq, buf, n);
+    return;
+  }
+
+  // Else, do allocations
+  size = sizeof(buf) * 2;
+
+  p = malloc(size);
+  while (1) {
+    /* Try to print in the allocated space. */
+    va_copy(ap, ap0);
+    n = vsnprintf(p, size, fmt, ap);
+    if(n > -1 && n < size) {
+      htsbuf_append_prealloc(hq, p, n);
+      return;
+    }
+    /* Else try again with more space. */
+    if (n > -1)    /* glibc 2.1 */
+      size = n+1; /* precisely what is needed */
+    else           /* glibc 2.0 */
+      size *= 2;  /* twice the old size */
+    if ((np = realloc (p, size)) == NULL) {
+      free(p);
+      abort();
+    } else {
+      p = np;
+    }
+  }
 }