Rework moments routines for improved numerical stability based on
[pspp-builds.git] / src / str.c
index 8912f3e58b6a4ec5921e58a952fd316dcb137560..056ef6fc934a79ecf753ab06ef84fec594d3127b 100644 (file)
--- a/src/str.c
+++ b/src/str.c
@@ -19,7 +19,7 @@
 
 #include <config.h>
 #include "str.h"
-#include <assert.h>
+#include "error.h"
 #include <ctype.h>
 #include <limits.h>
 #include <stdlib.h>
@@ -104,51 +104,36 @@ mm_find_reverse (const char *haystack, size_t haystack_len,
   return 0;
 }
 
-/* Compares S0 of length S0L to S1 of length S1L.  The shorter string
-   is considered to be padded with spaces to the length of the
-   longer. */
+/* Compares A of length A_LEN to B of length B_LEN.  The shorter
+   string is considered to be padded with spaces to the length of
+   the longer. */
 int
-st_compare_pad (const char *s0, int s0l, const char *s1, int s1l)
+st_compare_pad (const char *a, size_t a_len, const char *b, size_t b_len)
 {
-  /* 254 spaces. */
-  static char blanks[254] =
-  "                                                               "
-  "                                                               "
-  "                                                               "
-  "                                                               "
-  "  ";
-
-  int diff = s0l - s1l;
-  int r;
+  size_t min_len;
+  int result;
 
-  if (diff == 0)
-    {
-      if (s0l == 0)
-       return 0;
-      return memcmp (s0, s1, s0l);
-    }
-  else if (diff > 0)
+  min_len = a_len < b_len ? a_len : b_len;
+  result = memcmp (a, b, min_len);
+  if (result != 0)
+    return result;
+  else 
     {
-      /* s0l > s1l */
-      if (s1l)
-       {
-         r = memcmp (s0, s1, s1l);
-         if (r)
-           return r;
-       }
-      return memcmp (&s0[s1l], blanks, diff);
-    }
-  else
-    /* diff<0 */
-    {
-      /* s0l < s1l */
-      if (s0l)
-       {
-         r = memcmp (s0, s1, s0l);
-         if (r)
-           return r;
-       }
-      return memcmp (blanks, &s1[s0l], -diff);
+      size_t idx;
+      
+      if (a_len < b_len) 
+        {
+          for (idx = min_len; idx < b_len; idx++)
+            if (' ' != b[idx])
+              return ' ' > b[idx] ? 1 : -1;
+        }
+      else 
+        {
+          for (idx = min_len; idx < a_len; idx++)
+            if (a[idx] != ' ')
+              return a[idx] > ' ' ? 1 : -1;
+        }
+      return 0;
     }
 }
 
@@ -350,40 +335,50 @@ ds_concat_buffer (struct string *st, const char *buf, size_t len)
   st->length += len;
 }
 
+void ds_vprintf (struct string *st, const char *format, va_list args);
+
+
 /* Formats FORMAT as a printf string and appends the result to ST. */
 void
 ds_printf (struct string *st, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  ds_vprintf(st,format,args);
+  va_end (args);
+
+}
+
+/* Formats FORMAT as a printf string and appends the result to ST. */
+void
+ds_vprintf (struct string *st, const char *format, va_list args)
 {
   /* Fscking glibc silently changed behavior between 2.0 and 2.1.
      Fsck fsck fsck.  Before, it returned -1 on buffer overflow.  Now,
      it returns the number of characters (not bytes) that would have
      been written. */
-  va_list args;
 
   int avail, needed;
 
-  va_start (args, format);
   avail = st->size - st->length + 1;
   needed = vsnprintf (st->string + st->length, avail, format, args);
-  va_end (args);
+
 
   if (needed >= avail)
     {
       ds_extend (st, st->length + needed);
       
-      va_start (args, format);
       vsprintf (st->string + st->length, format, args);
-      va_end (args);
     }
   else
     while (needed == -1)
       {
        ds_extend (st, (st->size + 1) * 2);
        avail = st->size - st->length + 1;
-       
-       va_start (args, format);
+
        needed = vsnprintf (st->string + st->length, avail, format, args);
-       va_end (args);
+
       }
 
   st->length += needed;