str: Fix bugs in ds_put_c_vformat().
[pspp] / src / libpspp / str.c
index d7c71b11f5509f15678693555676c54cc4662e3f..57386cbfc4f89e554a8a4a0e7d5e4303a022ccbf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2014 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -189,7 +189,7 @@ buf_copy_rpad (char *dst, size_t dst_size,
 void
 str_copy_rpad (char *dst, size_t dst_size, const char *src)
 {
-  if (dst_size > 0) 
+  if (dst_size > 0)
     {
       size_t src_len = strlen (src);
       if (src_len < dst_size - 1)
@@ -257,9 +257,10 @@ str_lowercase (char *s)
 }
 
 /* Converts NUMBER into a string in 26-adic notation in BUFFER,
-   which has room for SIZE bytes.  Returns true if successful,
-   false if NUMBER, plus a trailing null, is too large to fit in
-   the available space.
+   which has room for SIZE bytes.  Uses uppercase if UPPERCASE is
+   true, otherwise lowercase, Returns true if successful, false
+   if NUMBER, plus a trailing null, is too large to fit in the
+   available space.
 
    26-adic notation is "spreadsheet column numbering": 1 = A, 2 =
    B, 3 = C, ... 26 = Z, 27 = AA, 28 = AB, 29 = AC, ...
@@ -271,15 +272,18 @@ str_lowercase (char *s)
    For more information, see
    http://en.wikipedia.org/wiki/Bijective_numeration. */
 bool
-str_format_26adic (unsigned long int number, char buffer[], size_t size)
+str_format_26adic (unsigned long int number, bool uppercase,
+                   char buffer[], size_t size)
 {
+  const char *alphabet
+    = uppercase ? "ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "abcdefghijklmnopqrstuvwxyz";
   size_t length = 0;
 
   while (number-- > 0)
     {
       if (length >= size)
         goto overflow;
-      buffer[length++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[number % 26];
+      buffer[length++] = alphabet[number % 26];
       number /= 26;
     }
 
@@ -687,6 +691,14 @@ ss_last (struct substring ss)
   return ss.length > 0 ? (unsigned char) ss.string[ss.length - 1] : EOF;
 }
 
+/* Returns true if SS starts with PREFIX, false otherwise. */
+bool
+ss_starts_with (struct substring ss, struct substring prefix)
+{
+  return (ss.length >= prefix.length
+          && !memcmp (ss.string, prefix.string, prefix.length));
+}
+
 /* Returns true if SS ends with SUFFIX, false otherwise. */
 bool
 ss_ends_with (struct substring ss, struct substring suffix)
@@ -729,6 +741,16 @@ ss_find_byte (struct substring ss, char c)
   return p != NULL ? p - ss.string : SIZE_MAX;
 }
 
+/* Returns the offset in HAYSTACK of the first instance of NEEDLE,
+   or SIZE_MAX if NEEDLE does not occur in HAYSTACK. */
+size_t
+ss_find_substring (struct substring haystack, struct substring needle)
+{
+  const char *p = memmem (haystack.string, haystack.length,
+                          needle.string, needle.length);
+  return p != NULL ? p - haystack.string : SIZE_MAX;
+}
+
 /* Compares A and B and returns a strcmp()-type comparison
    result. */
 int
@@ -1518,25 +1540,22 @@ ds_put_c_format (struct string *st, const char *format, ...)
   va_end (args);
 }
 
-
-/* Formats FORMAT as a printf string, using fmt_func (a snprintf like function) 
-   and appends the result to ST. */
-static void
-ds_put_vformat_int (struct string *st, const char *format, va_list args_,
-                   int (*fmt_func) (char *, size_t, const char *, va_list))
+/* Formats FORMAT as a printf string and appends the result to ST. */
+void
+ds_put_vformat (struct string *st, const char *format, va_list args_)
 {
   int avail, needed;
   va_list args;
 
   va_copy (args, args_);
   avail = st->ss.string != NULL ? st->capacity - st->ss.length + 1 : 0;
-  needed = fmt_func (st->ss.string + st->ss.length, avail, format, args);
+  needed = vsnprintf (st->ss.string + st->ss.length, avail, format, args);
   va_end (args);
 
   if (needed >= avail)
     {
       va_copy (args, args_);
-      fmt_func (ds_put_uninit (st, needed), needed + 1, format, args);
+      vsnprintf (ds_put_uninit (st, needed), needed + 1, format, args);
       va_end (args);
     }
   else
@@ -1549,34 +1568,27 @@ ds_put_vformat_int (struct string *st, const char *format, va_list args_,
           avail = st->capacity - st->ss.length + 1;
 
           va_copy (args, args_);
-          needed = fmt_func (ds_end (st), avail, format, args);
+          needed = vsnprintf (ds_end (st), avail, format, args);
           va_end (args);
         }
       st->ss.length += needed;
     }
 }
 
-
-static int
-vasnwrapper (char *str, size_t size,  const char *format, va_list ap)
-{
-  c_vasnprintf (str, &size, format, ap);
-  return size;
-}
-
-/* Formats FORMAT as a printf string and appends the result to ST. */
-void
-ds_put_vformat (struct string *st, const char *format, va_list args_)
-{
-  ds_put_vformat_int (st, format, args_, vsnprintf);
-}
-
-/* Formats FORMAT as a printf string, as if in the C locale, 
+/* Formats FORMAT as a printf string, as if in the C locale,
    and appends the result to ST. */
 void
-ds_put_c_vformat (struct string *st, const char *format, va_list args_)
+ds_put_c_vformat (struct string *st, const char *format, va_list args)
 {
-  ds_put_vformat_int (st, format, args_, vasnwrapper);
+  char buf[128];
+  size_t len = sizeof buf;
+  char *output = c_vasnprintf (buf, &len, format, args);
+  if (output)
+    {
+      ds_put_cstr (st, output);
+      if (output != buf)
+        free (output);
+    }
 }
 
 /* Appends byte CH to ST. */