Ask for a meaningful subject line on messages.
[u/mdw/putty] / misc.c
diff --git a/misc.c b/misc.c
index 2d0a463..496d30e 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <ctype.h>
 #include <assert.h>
 #include "putty.h"
 
@@ -8,7 +9,7 @@
  * String handling routines.
  */
 
-char *dupstr(char *s)
+char *dupstr(const char *s)
 {
     int len = strlen(s);
     char *p = smalloc(len + 1);
@@ -17,7 +18,7 @@ char *dupstr(char *s)
 }
 
 /* Allocate the concatenation of N strings. Terminate arg list with NULL. */
-char *dupcat(char *s1, ...)
+char *dupcat(const char *s1, ...)
 {
     int len;
     char *p, *q, *sn;
@@ -50,6 +51,56 @@ char *dupcat(char *s1, ...)
     return p;
 }
 
+/*
+ * Do an sprintf(), but into a custom-allocated buffer.
+ * 
+ * Irritatingly, we don't seem to be able to do this portably using
+ * vsnprintf(), because there appear to be issues with re-using the
+ * same va_list for two calls, and the excellent C99 va_copy is not
+ * yet widespread. Bah. Instead I'm going to do a horrid, horrid
+ * hack, in which I trawl the format string myself, work out the
+ * maximum length of each format component, and resize the buffer
+ * before printing it.
+ */
+char *dupprintf(const char *fmt, ...)
+{
+    char *ret;
+    va_list ap;
+    va_start(ap, fmt);
+    ret = dupvprintf(fmt, ap);
+    va_end(ap);
+    return ret;
+}
+char *dupvprintf(const char *fmt, va_list ap)
+{
+    char *buf;
+    int len, size;
+
+    buf = smalloc(512);
+    size = 512;
+
+    while (1) {
+#ifdef _WINDOWS
+#define vsnprintf _vsnprintf
+#endif
+       len = vsnprintf(buf, size, fmt, ap);
+       if (len >= 0 && len < size) {
+           /* This is the C99-specified criterion for snprintf to have
+            * been completely successful. */
+           return buf;
+       } else if (len > 0) {
+           /* This is the C99 error condition: the returned length is
+            * the required buffer size not counting the NUL. */
+           size = len + 1;
+       } else {
+           /* This is the pre-C99 glibc error condition: <0 means the
+            * buffer wasn't big enough, so we enlarge it a bit and hope. */
+           size += 512;
+       }
+       buf = srealloc(buf, size);
+    }
+}
+
 /* ----------------------------------------------------------------------
  * Base64 encoding routine. This is required in public-key writing
  * but also in HTTP proxy handling, so it's centralised here.
@@ -541,6 +592,7 @@ void safefree(void *ptr)
 
 #ifdef DEBUG
 static FILE *debug_fp = NULL;
+static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
 static int debug_got_console = 0;
 
 static void dputs(char *buf)
@@ -548,15 +600,18 @@ static void dputs(char *buf)
     DWORD dw;
 
     if (!debug_got_console) {
-       AllocConsole();
-       debug_got_console = 1;
+       if (AllocConsole()) {
+           debug_got_console = 1;
+           debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
+       }
     }
     if (!debug_fp) {
        debug_fp = fopen("debug.log", "w");
     }
 
-    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, strlen(buf), &dw,
-             NULL);
+    if (debug_hdl != INVALID_HANDLE_VALUE) {
+       WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
+    }
     fputs(buf, debug_fp);
     fflush(debug_fp);
 }
@@ -564,12 +619,13 @@ static void dputs(char *buf)
 
 void dprintf(char *fmt, ...)
 {
-    char buf[2048];
+    char *buf;
     va_list ap;
 
     va_start(ap, fmt);
-    vsprintf(buf, fmt, ap);
+    buf = dupvprintf(fmt, ap);
     dputs(buf);
+    sfree(buf);
     va_end(ap);
 }