Fixed bug reporting the significance of paired value t-test.
[pspp-builds.git] / src / libpspp / str.c
index 225c559d2d32c2e3cb1b51d12a9c75e7a140191a..552968b5c837d02411e4e101a7ba419b1b0d7a32 100644 (file)
@@ -26,6 +26,7 @@
 #include <libpspp/message.h>
 #include <libpspp/pool.h>
 
+#include <relocatable.h>
 #include "minmax.h"
 #include "xalloc.h"
 #include "xsize.h"
@@ -252,6 +253,41 @@ str_lowercase (char *s)
     *s = tolower ((unsigned 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.
+
+   26-adic notation is "spreadsheet column numbering": 1 = A, 2 =
+   B, 3 = C, ... 26 = Z, 27 = AA, 28 = AB, 29 = AC, ...
+
+   26-adic notation is the special case of a k-adic numeration
+   system (aka bijective base-k numeration) with k=26.  In k-adic
+   numeration, the digits are {1, 2, 3, ..., k} (there is no
+   digit 0), and integer 0 is represented by the empty string.
+   For more information, see
+   http://en.wikipedia.org/wiki/Bijective_numeration. */
+bool
+str_format_26adic (unsigned long int number, char buffer[], size_t size)
+{
+  size_t length = 0;
+
+  while (number-- > 0)
+    {
+      if (length >= size)
+        return false;
+      buffer[length++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[number % 26];
+      number /= 26;
+    }
+
+  if (length >= size)
+    return false;
+  buffer[length] = '\0';
+
+  buf_reverse (buffer, length);
+  return true;
+}
+
 /* Formats FORMAT into DST, as with sprintf(), and returns the
    address of the terminating null written to DST. */
 char *
@@ -511,6 +547,23 @@ ss_match_char (struct substring *ss, char c)
     return false;
 }
 
+/* If the first character in SS is in MATCH, removes it and
+   returns the character that was removed.
+   Otherwise, returns EOF without changing the string. */
+int
+ss_match_char_in (struct substring *ss, struct substring match)
+{
+  int c = EOF;
+  if (ss->length > 0
+      && memchr (match.string, ss->string[0], match.length) != NULL)
+    {
+      c = ss->string[0];
+      ss->string++;
+      ss->length--;
+    }
+  return c;
+}
+
 /* If SS begins with TARGET, removes it and returns true.
    Otherwise, returns false without changing SS. */
 bool
@@ -1135,30 +1188,47 @@ ds_cstr (const struct string *st_)
   return st->ss.string;
 }
 
-/* Appends to ST a newline-terminated line read from STREAM.
-   Newline is the last character of ST on return, unless an I/O error
-   or end of file is encountered after reading some characters.
-   Returns true if a line is successfully read, false if no characters at
-   all were read before an I/O error or end of file was
-   encountered. */
+/* Appends to ST a newline-terminated line read from STREAM, but
+   no more than MAX_LENGTH characters.
+   Newline is the last character of ST on return, if encountering
+   a newline was the reason for terminating.
+   Returns true if at least one character was read from STREAM
+   and appended to ST, false if no characters at all were read
+   before an I/O error or end of file was encountered (or
+   MAX_LENGTH was 0). */
 bool
-ds_read_line (struct string *st, FILE *stream)
+ds_read_line (struct string *st, FILE *stream, size_t max_length)
 {
-  int c;
+  if (!st->ss.length && max_length == SIZE_MAX)
+    {
+      size_t capacity = st->capacity ? st->capacity + 1 : 0;
+      ssize_t n = getline (&st->ss.string, &capacity, stream);
+      if (capacity)
+        st->capacity = capacity - 1;
+      if (n > 0)
+        {
+          st->ss.length = n;
+          return true;
+        }
+      else
+        return false;
+    }
+  else
+    {
+      size_t length;
 
-  c = getc (stream);
-  if (c == EOF)
-    return false;
+      for (length = 0; length < max_length; length++)
+        {
+          int c = getc (stream);
+          if (c == EOF)
+            break;
 
-  for (;;)
-    {
-      ds_put_char (st, c);
-      if (c == '\n')
-       return true;
+          ds_put_char (st, c);
+          if (c == '\n')
+            return true;
+        }
 
-      c = getc (stream);
-      if (c == EOF)
-       return true;
+      return length > 0;
     }
 }
 
@@ -1205,7 +1275,7 @@ ds_read_config_line (struct string *st, int *line_number, FILE *stream)
   ds_clear (st);
   do
     {
-      if (!ds_read_line (st, stream))
+      if (!ds_read_line (st, stream, SIZE_MAX))
         return false;
       (*line_number)++;
       ds_rtrim (st, ss_cstr (CC_SPACES));
@@ -1327,3 +1397,20 @@ ds_put_char_multiple (struct string *st, int ch, size_t cnt)
 {
   memset (ds_put_uninit (st, cnt), ch, cnt);
 }
+
+
+/* If relocation has been enabled, replace ST,
+   with its relocated version */
+void
+ds_relocate (struct string *st)
+{
+  const char *orig = ds_cstr (st);
+  const char *rel = relocate (orig);
+
+  if ( orig != rel)
+    {
+      ds_clear (st);
+      ds_put_cstr (st, rel);
+      free ((char *) rel);
+    }
+}