New function ltime() returns a struct tm of the current local time.
[sgt/putty] / misc.c
diff --git a/misc.c b/misc.c
index 1bd556e..59e91f2 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -9,6 +9,39 @@
 #include <assert.h>
 #include "putty.h"
 
+/*
+ * Parse a string block size specification. This is approximately a
+ * subset of the block size specs supported by GNU fileutils:
+ *  "nk" = n kilobytes
+ *  "nM" = n megabytes
+ *  "nG" = n gigabytes
+ * All numbers are decimal, and suffixes refer to powers of two.
+ * Case-insensitive.
+ */
+unsigned long parse_blocksize(const char *bs)
+{
+    char *suf;
+    unsigned long r = strtoul(bs, &suf, 10);
+    if (*suf != '\0') {
+       while (isspace(*suf)) suf++;
+       switch (*suf) {
+         case 'k': case 'K':
+           r *= 1024ul;
+           break;
+         case 'm': case 'M':
+           r *= 1024ul * 1024ul;
+           break;
+         case 'g': case 'G':
+           r *= 1024ul * 1024ul * 1024ul;
+           break;
+         case '\0':
+         default:
+           break;
+       }
+    }
+    return r;
+}
+
 /* ----------------------------------------------------------------------
  * String handling routines.
  */
@@ -61,13 +94,46 @@ char *dupcat(const char *s1, ...)
 /*
  * 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.
+ * Currently I'm doing this via vsnprintf. This has worked so far,
+ * but it's not good, because:
+ * 
+ *  - vsnprintf is not available on all platforms. There's an ifdef
+ *    to use `_vsnprintf', which seems to be the local name for it
+ *    on Windows. Other platforms may lack it completely, in which
+ *    case it'll be time to rewrite this function in a totally
+ *    different way.
+ * 
+ *  - technically you can't reuse a va_list like this: it is left
+ *    unspecified whether advancing a va_list pointer modifies its
+ *    value or something it points to, so on some platforms calling
+ *    vsnprintf twice on the same va_list might fail hideously. It
+ *    would be better to use the `va_copy' macro mandated by C99,
+ *    but that too is not yet ubiquitous.
+ * 
+ * The only `properly' portable solution I can think of is to
+ * implement my own format string scanner, which figures out an
+ * upper bound for the length of each formatting directive,
+ * allocates the buffer as it goes along, and calls sprintf() to
+ * actually process each directive. If I ever need to actually do
+ * this, some caveats:
+ * 
+ *  - It's very hard to find a reliable upper bound for
+ *    floating-point values. %f, in particular, when supplied with
+ *    a number near to the upper or lower limit of representable
+ *    numbers, could easily take several hundred characters. It's
+ *    probably feasible to predict this statically using the
+ *    constants in <float.h>, or even to predict it dynamically by
+ *    looking at the exponent of the specific float provided, but
+ *    it won't be fun.
+ * 
+ *  - Don't forget to _check_, after calling sprintf, that it's
+ *    used at most the amount of space we had available.
+ * 
+ *  - Fault any formatting directive we don't fully understand. The
+ *    aim here is to _guarantee_ that we never overflow the buffer,
+ *    because this is a security-critical function. If we see a
+ *    directive we don't know about, we should panic and die rather
+ *    than run any risk.
  */
 char *dupprintf(const char *fmt, ...)
 {
@@ -108,6 +174,29 @@ char *dupvprintf(const char *fmt, va_list ap)
     }
 }
 
+/*
+ * Read an entire line of text from a file. Return a buffer
+ * malloced to be as big as necessary (caller must free).
+ */
+char *fgetline(FILE *fp)
+{
+    char *ret = snewn(512, char);
+    int size = 512, len = 0;
+    while (fgets(ret + len, size - len, fp)) {
+       len += strlen(ret + len);
+       if (ret[len-1] == '\n')
+           break;                     /* got a newline, we're done */
+       size = len + 512;
+       ret = sresize(ret, size, char);
+    }
+    if (len == 0) {                   /* first fgets returned NULL */
+       sfree(ret);
+       return NULL;
+    }
+    ret[len] = '\0';
+    return ret;
+}
+
 /* ----------------------------------------------------------------------
  * Base64 encoding routine. This is required in public-key writing
  * but also in HTTP proxy handling, so it's centralised here.