Merge branch 'master'; commit 'origin/stable'
[pspp-builds.git] / src / libpspp / str.c
index b169f0d7613ee556e7a5a32e746a36ac2f06af23..3cff0492c7d508d99d9ce0b5c77c57879bc1faf7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009 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
@@ -26,6 +26,7 @@
 #include <libpspp/message.h>
 #include <libpspp/pool.h>
 
+#include <relocatable.h>
 #include "minmax.h"
 #include "xalloc.h"
 #include "xsize.h"
@@ -194,15 +195,18 @@ buf_copy_rpad (char *dst, size_t dst_size,
 void
 str_copy_rpad (char *dst, size_t dst_size, const char *src)
 {
-  size_t src_len = strlen (src);
-  if (src_len < dst_size - 1)
+  if (dst_size > 0) 
     {
-      memcpy (dst, src, src_len);
-      memset (&dst[src_len], ' ', dst_size - 1 - src_len);
+      size_t src_len = strlen (src);
+      if (src_len < dst_size - 1)
+        {
+          memcpy (dst, src, src_len);
+          memset (&dst[src_len], ' ', dst_size - 1 - src_len);
+        }
+      else
+        memcpy (dst, src, dst_size - 1);
+      dst[dst_size - 1] = 0;
     }
-  else
-    memcpy (dst, src, dst_size - 1);
-  dst[dst_size - 1] = 0;
 }
 
 /* Copies SRC to DST, which is in a buffer DST_SIZE bytes long.
@@ -546,6 +550,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
@@ -1170,31 +1191,42 @@ 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. */
+/* Reads characters from STREAM and appends them to ST, stopping
+   after MAX_LENGTH characters, after appending a newline, or
+   after an I/O error or end of file was encountered, whichever
+   comes first.  Returns true if at least one character was added
+   to ST, false if no characters were read before an I/O error or
+   end of file (or if MAX_LENGTH was 0).
+
+   This function accepts LF, CR LF, and CR sequences as new-line,
+   and translates each of them to a single '\n' new-line
+   character in ST. */
 bool
-ds_read_line (struct string *st, FILE *stream)
+ds_read_line (struct string *st, FILE *stream, size_t max_length)
 {
-  int c;
-
-  c = getc (stream);
-  if (c == EOF)
-    return false;
+  size_t length;
 
-  for (;;)
+  for (length = 0; length < max_length; length++)
     {
+      int c = getc (stream);
+      if (c == EOF)
+        break;
+
+      if (c == '\r')
+        {
+          c = getc (stream);
+          if (c != '\n')
+            {
+              ungetc (c, stream);
+              c = '\n';
+            }
+        }
       ds_put_char (st, c);
       if (c == '\n')
-       return true;
-
-      c = getc (stream);
-      if (c == EOF)
-       return true;
+        return true;
     }
+
+  return length > 0;
 }
 
 /* Removes a comment introduced by `#' from ST,
@@ -1240,7 +1272,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));
@@ -1362,3 +1394,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);
+    }
+}