Improve string library.
authorBen Pfaff <blp@gnu.org>
Fri, 31 Mar 2006 00:30:21 +0000 (00:30 +0000)
committerBen Pfaff <blp@gnu.org>
Fri, 31 Mar 2006 00:30:21 +0000 (00:30 +0000)
src/language/control/repeat.c
src/language/data-io/data-reader.c
src/language/lexer/lexer.c
src/libpspp/ChangeLog
src/libpspp/str.c
src/libpspp/str.h
src/output/ChangeLog
src/output/output.c
src/output/postscript.c
src/ui/terminal/read-line.c

index a71501b79c4a3a90bc172da6ff1d8946bb1bdbe5..6cfbb6bba5cbc3ff911f81c09b3828488c8bcb52 100644 (file)
@@ -562,7 +562,7 @@ do_repeat_read (struct string *output, char **file_name, int *line_number,
     }
   line = block->cur_line;
 
-  ds_replace (output, line->line);
+  ds_assign_c_str (output, line->line);
   *file_name = line->file_name;
   *line_number = -line->line_number;
   block->cur_line = line->next;
index c4bdd5389118ed1cf3d71b4479b7951de7fa47a5..6f717fd29c0d0af0457838c66758a916a34a8615 100644 (file)
@@ -187,7 +187,7 @@ read_inline_record (struct dfm_reader *r)
       return false;
     }
 
-  ds_replace (&r->line, ds_c_str (&getl_buf));
+  ds_assign_string (&r->line, &getl_buf);
   return true;
 }
 
index ec8c45103bc9378fa88df355fa18a5c173c07ea0..3d2e29ac92aac6ca2bfd51aa9edfd1caccae7753 100644 (file)
@@ -34,6 +34,8 @@
 #include <data/settings.h>
 #include <libpspp/str.h>
 
+#include "size_max.h"
+
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
@@ -125,7 +127,7 @@ restore_token (void)
 {
   assert (put_token != 0);
   token = put_token;
-  ds_replace (&tokstr, ds_c_str (&put_tokstr));
+  ds_assign_string (&tokstr, &put_tokstr);
   str_copy_trunc (tokid, sizeof tokid, ds_c_str (&tokstr));
   tokval = put_tokval;
   put_token = 0;
@@ -137,7 +139,7 @@ static void
 save_token (void) 
 {
   put_token = token;
-  ds_replace (&put_tokstr, ds_c_str (&tokstr));
+  ds_assign_string (&put_tokstr, &tokstr);
   put_tokval = tokval;
 }
 
@@ -693,7 +695,7 @@ lex_put_back_id (const char *id)
   assert (lex_id_to_token (id, strlen (id)) == T_ID);
   save_token ();
   token = T_ID;
-  ds_replace (&tokstr, id);
+  ds_assign_c_str (&tokstr, id);
   str_copy_trunc (tokid, sizeof tokid, ds_c_str (&tokstr));
 }
 \f
@@ -930,7 +932,7 @@ lex_negative_to_dash (void)
     {
       token = T_POS_NUM;
       tokval = -tokval;
-      ds_replace (&tokstr, ds_c_str (&tokstr) + 1);
+      ds_assign_substring (&tokstr, &tokstr, 1, SIZE_MAX);
       save_token ();
       token = '-';
     }
index 1902d196dc261e9aa784a23c837dd60a3df6f00c..98bd3dd030bc76393c17a8d5cc3abd465b116da1 100644 (file)
@@ -1,3 +1,38 @@
+Thu Mar 30 16:15:37 2006  Ben Pfaff  <blp@gnu.org>
+
+       * str.c: (ds_create) Adjust capacity selection.
+       (ds_init) Use MAX macro for clarity.
+       (ds_create_substr) Rewrote.
+       (ds_replace) Renamed ds_assign_c_str(), reimplemented.  Changed
+       all callers to use a ds_assign_*() function.
+       (ds_init_substring) New function.
+       (ds_assign_string) New function.
+       (ds_assign_substring) New function.
+       (ds_assign_buffer) New function.
+       (ds_assign_c_str) New function.
+       (ds_truncate) Rewrote for clarity.
+       (ds_rpad) Reimplement in terms of ds_putc_multiple().
+       (ds_ltrim_spaces) Reimplement.
+       (ds_trim_spaces) New function.
+       (ds_separate) New function.
+       (ds_c_str) Make tolerant of null pointer, allowing static
+       initialization of strings.
+       (ds_find) Rename ds_span(), change interface.
+       (ds_n_find) Rename ds_cspan(), change interface.
+       (ds_at) New function.
+       (ds_first) Reimplement in terms of ds_at().
+       (remove_comment) New function.
+       (ds_get_config_line) Reimplement in terms of other functions.
+       Change type of LINE_NUMBER parameter.  Updated all callers.
+       (ds_vprintf) Modify for clarity.
+       (ds_putc) Better to be safe than sorry.
+       (ds_putc_multiple) New function.
+
+       * str.h: (struct string) Reorder members.
+       (macro DS_INITIALIZER) New macro that can be used to initialize a
+       string (as empty).
+       (ds_c_str) Remove inline version.
+
 Tue Mar 28 13:49:11 WST 2006 John Darrington <john@darrington.wattle.id.au>
 
        * str.[ch]: New functions ds_create_substr, ds_find, ds_n_find, 
index b8e55344d3a4ae0bc663d00db6735eba3c78c4d5..e84021be4c41b036d7fb8105eec52e2f732d9128 100644 (file)
@@ -25,6 +25,8 @@
 #include <stdlib.h>
 #include "alloc.h"
 #include "message.h"
+#include "minmax.h"
+#include "size_max.h"
 \f
 /* Reverses the order of NBYTES bytes at address P, thus converting
    between little- and big-endian byte orders.  */
@@ -237,66 +239,31 @@ void
 ds_create (struct string *st, const char *s)
 {
   st->length = strlen (s);
-  st->capacity = 8 + st->length * 2;
+  st->capacity = MAX (8, st->length * 2);
   st->string = xmalloc (st->capacity + 1);
   strcpy (st->string, s);
 }
 
-/* Initializes DST with the contents of SRC between characters FIRST and LAST 
-   inclusive */
-void
-ds_create_substr(struct string *dst, const struct string *src, 
-                int first, int last)
-{
-  assert(last >= first);
-  dst->length = last - first + 1;
-  dst->capacity = 8 + dst->length * 2;
-  dst->string = xmalloc (dst->capacity + 1);
-
-  memcpy (dst->string, &src->string[first], dst->length);
-}
-
-
 /* Initializes ST, making room for at least CAPACITY characters. */
 void
 ds_init (struct string *st, size_t capacity)
 {
   st->length = 0;
-  if (capacity > 8)
-    st->capacity = capacity;
-  else
-    st->capacity = 8;
+  st->capacity = MAX (8, capacity);
   st->string = xmalloc (st->capacity + 1);
 }
 
-/* Replaces the contents of ST with STRING.  STRING may overlap with
-   ST. */
+/* Frees ST. */
 void
-ds_replace (struct string *st, const char *string)
+ds_destroy (struct string *st)
 {
-  size_t new_length = strlen (string);
-  if (new_length > st->capacity) 
+  if (st != NULL) 
     {
-      /* The new length is longer than the allocated length, so
-         there can be no overlap. */
+      free (st->string);
+      st->string = NULL;
       st->length = 0;
-      ds_concat (st, string, new_length);
+      st->capacity = 0; 
     }
-  else
-    {
-      /* Overlap is possible, but the new string will fit in the
-         allocated space, so we can just copy data. */
-      st->length = new_length;
-      memmove (st->string, string, st->length);
-    }
-}
-
-/* Frees ST. */
-void
-ds_destroy (struct string *st)
-{
-  free (st->string);
-  st->string = NULL;
 }
 
 /* Swaps the contents of strings A and B. */
@@ -308,6 +275,56 @@ ds_swap (struct string *a, struct string *b)
   *b = tmp;
 }
 
+/* Initializes DST with the CNT characters from SRC starting at
+   position IDX. */
+void
+ds_init_substring (struct string *dst,
+                   const struct string *src, size_t idx, size_t cnt)
+{
+  assert (dst != src);
+  ds_init (dst, cnt);
+  ds_assign_substring (dst, src, idx, cnt);
+}
+
+/* Copies SRC into DST.
+   DST and SRC may be the same string. */
+void
+ds_assign_string (struct string *dst, const struct string *src) 
+{
+  ds_assign_buffer (dst, ds_data (src), ds_length (src));
+}
+
+/* Replaces DST by CNT characters from SRC starting at position
+   IDX.
+   DST and SRC may be the same string. */
+void
+ds_assign_substring (struct string *dst,
+                     const struct string *src, size_t idx, size_t cnt) 
+{
+  if (idx < src->length)
+    ds_assign_buffer (dst, src->string + idx, MIN (cnt, src->length - idx));
+  else 
+    ds_clear (dst);
+}
+
+/* Replaces DST by the LENGTH characters in SRC.
+   SRC may be a substring within DST. */
+void
+ds_assign_buffer (struct string *dst, const char *src, size_t length)
+{
+  dst->length = length;
+  ds_extend (dst, length);
+  memmove (dst->string, src, length);
+}
+
+/* Replaces DST by null-terminated string SRC.  SRC may overlap
+   with DST. */
+void
+ds_assign_c_str (struct string *dst, const char *src)
+{
+  ds_assign_buffer (dst, src, strlen (src));
+}
+
 /* Truncates ST to zero length. */
 void
 ds_clear (struct string *st)
@@ -315,20 +332,48 @@ ds_clear (struct string *st)
   st->length = 0;
 }
 
+/* Ensures that ST can hold at least MIN_CAPACITY characters plus a null
+   terminator. */
+void
+ds_extend (struct string *st, size_t min_capacity)
+{
+  if (min_capacity > st->capacity)
+    {
+      st->capacity *= 2;
+      if (st->capacity < min_capacity)
+       st->capacity = 2 * min_capacity;
+
+      st->string = xrealloc (st->string, st->capacity + 1);
+    }
+}
+
+/* Shrink ST to the minimum capacity need to contain its content. */
+void
+ds_shrink (struct string *st)
+{
+  if (st->capacity != st->length)
+    {
+      st->capacity = st->length;
+      st->string = xrealloc (st->string, st->capacity + 1);
+    }
+}
+
+/* Truncates ST to at most LENGTH characters long. */
+void
+ds_truncate (struct string *st, size_t length)
+{
+  if (st->length > length)
+    st->length = length;
+}
+
 /* Pad ST on the right with copies of PAD until ST is at least
    LENGTH characters in size.  If ST is initially LENGTH
    characters or longer, this is a no-op. */
 void
 ds_rpad (struct string *st, size_t length, char pad) 
 {
-  assert (st != NULL);
-  if (st->length < length) 
-    {
-      if (st->capacity < length)
-        ds_extend (st, length);
-      memset (&st->string[st->length], pad, length - st->length);
-      st->length = length;
-    }
+  if (length > st->length)
+    ds_putc_multiple (st, pad, length - st->length);
 }
 
 /* Removes trailing spaces from ST.
@@ -350,22 +395,21 @@ ds_rtrim_spaces (struct string *st)
 int
 ds_ltrim_spaces (struct string *st) 
 {
-  int idx = ds_n_find(st, "\t ");
-  if (0 == idx)
-    return 0;
-
-  if (idx < 0 ) 
-    {
-      int len = ds_length(st);
-      ds_clear(st);
-      return len;
-    }
-  
-  ds_replace(st, &ds_c_str(st)[idx]);
-    
-  return idx;
+  size_t cnt = 0;
+  while (isspace (ds_at (st, cnt)))
+    cnt++;
+  if (cnt > 0)
+    ds_assign_substring (st, st, cnt, SIZE_MAX);
+  return cnt;
 }
 
+/* Trims leading and trailing spaces from ST. */
+void
+ds_trim_spaces (struct string *st) 
+{
+  ds_rtrim_spaces (st);
+  ds_ltrim_spaces (st);
+}
 
 /* If the last character in ST is C, removes it and returns true.
    Otherwise, returns false without modifying ST. */
@@ -382,39 +426,42 @@ ds_chomp (struct string *st, char c_)
     return false;
 }
 
-/* Ensures that ST can hold at least MIN_CAPACITY characters plus a null
-   terminator. */
-void
-ds_extend (struct string *st, size_t min_capacity)
-{
-  if (min_capacity > st->capacity)
-    {
-      st->capacity *= 2;
-      if (st->capacity < min_capacity)
-       st->capacity = min_capacity * 2;
-      
-      st->string = xrealloc (st->string, st->capacity + 1);
-    }
-}
+/* Divides ST into tokens separated by any of the DELIMITERS.
+   Each call replaces TOKEN by the next token in ST, or by an
+   empty string if no tokens remain.  Returns true if a token was
+   obtained, false otherwise.
 
-/* Shrink ST to the minimum capacity need to contain its content. */
-void
-ds_shrink (struct string *st)
+   Before the first call, initialize *SAVE_IDX to -1.  Do not
+   modify *SAVE_IDX between calls.
+
+   ST divides into exactly one more tokens than it contains
+   delimiters.  That is, a delimiter at the start or end of ST or
+   a pair of adjacent delimiters yields an empty token, and the
+   empty string contains a single token. */
+bool
+ds_separate (const struct string *st, struct string *token,
+             const char *delimiters, int *save_idx)
 {
-  if (st->capacity != st->length)
+  int start_idx;
+
+  ds_clear (token);
+  if (*save_idx < 0) 
     {
-      st->capacity = st->length;
-      st->string = xrealloc (st->string, st->capacity + 1);
+      *save_idx = 0;
+      if (ds_is_empty (st))
+        return true;
     }
-}
+  else if (*save_idx < ds_length (st))
+    ++*save_idx;
+  else
+    return false;
 
-/* Truncates ST to at most LENGTH characters long. */
-void
-ds_truncate (struct string *st, size_t length)
-{
-  if (length >= st->length)
-    return;
-  st->length = length;
+  start_idx = *save_idx;
+  while (*save_idx < ds_length (st)
+         && strchr (delimiters, ds_data (st)[*save_idx]) == NULL)
+    ++*save_idx;
+  ds_assign_substring (token, st, start_idx, *save_idx - start_idx);
+  return true;
 }
 
 /* Returns true if ST is empty, false otherwise. */
@@ -431,72 +478,55 @@ ds_length (const struct string *st)
   return st->length;
 }
 
-/* Returns the allocation size of ST. */
-size_t
-ds_capacity (const struct string *st)
+/* Returns the value of ST as a null-terminated string. */
+char *
+ds_c_str (const struct string *st_)
 {
-  return st->capacity;
+  struct string *st = (struct string *) st_;
+  if (st->string == NULL) 
+    ds_extend (st, 1);
+  st->string[st->length] = '\0';
+  return st->string;
 }
 
-
-/* Returns the index of the first character in ST which 
-   is an element of the set CS.
-   Returns -1 if no characters are found.
-*/
-int
-ds_find(const struct string *st, const char cs[])
+/* Returns the string data inside ST. */
+char *
+ds_data (const struct string *st)
 {
-  int i;
-  int j;
-  for(i = 0; i < st->length ;  ++i)
-    {
-      if ('\0' == st->string[i]) 
-       break;
-      for (j = 0 ; j < strlen(cs) ; ++j)
-       {
-         if ( st->string[i] == cs[j])
-           return i;
-       }
-    }
-  return -1;
+  return st->string;
 }
 
-/* Returns the index of the first character in ST which 
-   is NOT an element of the set CS.
-   Returns -1 if no such character is found.
-*/
-int
-ds_n_find(const struct string *st, const char cs[])
+/* Returns a pointer to the null terminator ST.
+   This might not be an actual null character unless ds_c_str() has
+   been called since the last modification to ST. */
+char *
+ds_end (const struct string *st)
 {
-  int i;
-  int j;
-  for(i = 0; i < st->length ;  ++i)
-    {
-      bool found = false;
-      if ('\0' == st->string[i]) 
-       break;
-      for (j = 0 ; j < strlen(cs) ; ++j)
-       {
-         if ( st->string[i] == cs[j])
-           {
-             found = true;
-             break;
-           }
-       }
-      if ( !found )
-       return i;
-    }
-  return -1;
+  return st->string + st->length;
 }
 
+/* Returns the allocation size of ST. */
+size_t
+ds_capacity (const struct string *st)
+{
+  return st->capacity;
+}
 
+/* Returns the character in position IDX in ST, as a value in the
+   range of unsigned char.  Returns EOF if IDX is out of the
+   range of indexes for ST. */
+int
+ds_at (const struct string *st, size_t idx) 
+{
+  return idx < st->length ? (unsigned char) st->string[idx] : EOF;
+}
 
 /* Returns the first character in ST as a value in the range of
    unsigned char.  Returns EOF if ST is the empty string. */
 int
 ds_first (const struct string *st) 
 {
-  return st->length > 0 ? (unsigned char) st->string[0] : EOF;
+  return ds_at (st, 0);
 }
 
 /* Returns the last character in ST as a value in the range of
@@ -507,28 +537,117 @@ ds_last (const struct string *st)
   return st->length > 0 ? (unsigned char) st->string[st->length - 1] : EOF;
 }
 
-/* Returns the value of ST as a null-terminated string. */
-char *
-ds_c_str (const struct string *st)
+/* Returns the number of consecutive characters starting at OFS
+   in ST that are in SKIP_SET.  (The null terminator is not
+   considered to be part of SKIP_SET.) */
+size_t
+ds_span (const struct string *st, size_t ofs, const char skip_set[])
 {
-  ((char *) st->string)[st->length] = '\0';
-  return st->string;
+  size_t i;
+  for (i = ofs; i < st->length; i++) 
+    {
+      int c = st->string[i];
+      if (strchr (skip_set, c) == NULL || c == '\0')
+        break; 
+    }
+  return i - ofs;
 }
 
-/* Returns the string data inside ST. */
-char *
-ds_data (const struct string *st)
+/* Returns the number of consecutive characters starting at OFS
+   in ST that are not in STOP_SET.  (The null terminator is not
+   considered to be part of STOP_SET.) */
+size_t
+ds_cspan (const struct string *st, size_t ofs, const char stop_set[])
 {
-  return st->string;
+  size_t i;
+  for (i = ofs; i < st->length; i++) 
+    {
+      int c = st->string[i];
+      if (strchr (stop_set, c) != NULL)
+        break; 
+    }
+  return i - ofs;
 }
 
-/* Returns a pointer to the null terminator ST.
-   This might not be an actual null character unless ds_c_str() has
-   been called since the last modification to ST. */
-char *
-ds_end (const struct string *st)
+/* 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. */
+bool
+ds_gets (struct string *st, FILE *stream)
 {
-  return st->string + st->length;
+  int c;
+
+  c = getc (stream);
+  if (c == EOF)
+    return false;
+
+  for (;;)
+    {
+      ds_putc (st, c);
+      if (c == '\n')
+       return true;
+
+      c = getc (stream);
+      if (c == EOF)
+       return true;
+    }
+}
+
+/* Removes a comment introduced by `#' from ST,
+   ignoring occurrences inside quoted strings. */
+static void
+remove_comment (struct string *st)
+{
+  char *cp;
+  int quote = 0;
+      
+  for (cp = ds_c_str (st); cp < ds_end (st); cp++)
+    if (quote)
+      {
+        if (*cp == quote)
+          quote = 0;
+        else if (*cp == '\\')
+          cp++;
+      }
+    else if (*cp == '\'' || *cp == '"')
+      quote = *cp;
+    else if (*cp == '#')
+      {
+        ds_truncate (st, cp - ds_c_str (st));
+        break;
+      }
+}
+
+/* Reads a line from STREAM into ST, then preprocesses as follows:
+
+   - Splices lines terminated with `\'.
+
+   - Deletes comments introduced by `#' outside of single or double
+     quotes.
+
+   - Deletes trailing white space.  
+
+   Returns true if a line was successfully read, false on
+   failure.  If LINE_NUMBER is non-null, then *LINE_NUMBER is
+   incremented by the number of lines read. */
+bool
+ds_get_config_line (FILE *stream, struct string *st, int *line_number)
+{
+  ds_clear (st);
+  do
+    {
+      if (!ds_gets (st, stream))
+        return false;
+      (*line_number)++;
+      ds_rtrim_spaces (st);
+    }
+  while (ds_chomp (st, '\\'));
+  remove_comment (st);
+  return true;
 }
 
 /* Concatenates S onto ST. */
@@ -554,9 +673,6 @@ ds_concat (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, ...)
@@ -564,48 +680,48 @@ ds_printf (struct string *st, const char *format, ...)
   va_list args;
 
   va_start (args, format);
-  ds_vprintf(st,format,args);
+  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)
+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. */
-
   int avail, needed;
-  va_list a1;
+  va_list args;
+
+#ifndef va_copy
+#define va_copy(DST, SRC) (DST) = (SRC)
+#endif
 
-  va_copy(a1, args);
+  va_copy (args, args_);
   avail = st->capacity - st->length + 1;
   needed = vsnprintf (st->string + st->length, avail, format, args);
-
+  va_end (args);
 
   if (needed >= avail)
     {
       ds_extend (st, st->length + needed);
       
-      vsprintf (st->string + st->length, format, a1);
+      va_copy (args, args_);
+      vsprintf (st->string + st->length, format, args);
+      va_end (args);
     }
-  else
-    while (needed == -1)
-      {
-       va_list a2;
-       va_copy(a2, a1);
-
-       ds_extend (st, (st->capacity + 1) * 2);
-       avail = st->capacity - st->length + 1;
-
-       needed = vsnprintf (st->string + st->length, avail, format, a2);
-       va_end(a2);
+  else 
+    {
+      /* Some old libc's returned -1 when the destination string
+         was too short. */
+      while (needed == -1)
+        {
+          ds_extend (st, (st->capacity + 1) * 2);
+          avail = st->capacity - st->length + 1;
 
-      }
-  va_end(a1);
+          va_copy (args, args_);
+          needed = vsnprintf (st->string + st->length, avail, format, args);
+          va_end (args);
+        } 
+    }
 
   st->length += needed;
 }
@@ -614,110 +730,20 @@ ds_vprintf (struct string *st, const char *format, va_list args)
 void
 ds_putc (struct string *st, int ch)
 {
-  if (st->length == st->capacity)
+  if (st->length >= st->capacity)
     ds_extend (st, st->length + 1);
   st->string[st->length++] = ch;
 }
 
-/* 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 1 if a line is successfully read, or 0 if no characters at
-   all were read before an I/O error or end of file was
-   encountered. */
-int
-ds_gets (struct string *st, FILE *stream)
+/* Appends CNT copies of character CH to ST. */
+void
+ds_putc_multiple (struct string *st, int ch, size_t cnt) 
 {
-  int c;
-
-  c = getc (stream);
-  if (c == EOF)
-    return 0;
-
-  for (;;)
-    {
-      ds_putc (st, c);
-      if (c == '\n')
-       return 1;
-
-      c = getc (stream);
-      if (c == EOF)
-       return 1;
-    }
+  ds_extend (st, st->length + cnt);
+  memset (&st->string[st->length], ch, cnt);
+  st->length += cnt;
 }
 
-/* Reads a line from STREAM into ST, then preprocesses as follows:
-
-   - Splices lines terminated with `\'.
-
-   - Deletes comments introduced by `#' outside of single or double
-     quotes.
-
-   - Trailing whitespace will be deleted.  
-
-   Increments cust_ln as appropriate.
-
-   Returns nonzero only if a line was successfully read. */
-int
-ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where)
-{
-  /* Read the first line. */
-  ds_clear (st);
-  where->line_number++;
-  if (!ds_gets (st, stream))
-    return 0;
-
-  /* Read additional lines, if any. */
-  for (;;)
-    {
-      /* Remove trailing whitespace. */
-      {
-       char *s = ds_c_str (st);
-       size_t len = ds_length (st);
-      
-       while (len > 0 && isspace ((unsigned char) s[len - 1]))
-         len--;
-       ds_truncate (st, len);
-      }
-
-      /* Check for trailing \.  Remove if found, bail otherwise. */
-      if (ds_length (st) == 0 || ds_c_str (st)[ds_length (st) - 1] != '\\')
-       break;
-      ds_truncate (st, ds_length (st) - 1);
-
-      /* Append another line and go around again. */
-      {
-       int success = ds_gets (st, stream);
-       where->line_number++;
-       if (!success)
-         return 1;
-      }
-    }
-
-  /* Find a comment and remove. */
-  {
-    char *cp;
-    int quote = 0;
-      
-    for (cp = ds_c_str (st); *cp; cp++)
-      if (quote)
-       {
-         if (*cp == quote)
-           quote = 0;
-         else if (*cp == '\\')
-           cp++;
-       }
-      else if (*cp == '\'' || *cp == '"')
-       quote = *cp;
-      else if (*cp == '#')
-       {
-         ds_truncate (st, cp - ds_c_str (st));
-         break;
-       }
-  }
-
-  return 1;
-}
 \f
 /* Lengthed strings. */
 
index c0643263d36b85075616620a3d2a0662a4e4f4f4..6f34c200d054d59c3da3f453db211d198fd798fe 100644 (file)
@@ -108,30 +108,43 @@ ls_end (const struct fixed_string *st)
 
 struct string
   {
+    char *string;       /* String data, not necessarily null terminated. */
     size_t length;      /* Length, not including a null terminator. */
     size_t capacity;    /* Allocated capacity, not including one
                            extra byte allocated for null terminator. */
-    char *string;       /* String data, not necessarily null
-                           terminated. */
   };
 
+#define DS_INITIALIZER {NULL, 0, 0}
+
 /* Constructors, destructors. */
-void ds_create (struct string *, const char *);
 void ds_init (struct string *, size_t);
+void ds_init_substring (struct string *,
+                        const struct string *src, size_t start, size_t cnt);
+void ds_create (struct string *, const char *);
 void ds_destroy (struct string *);
 void ds_swap (struct string *, struct string *);
 
-/* Copy, shrink, extend. */
-void ds_replace (struct string *, const char *);
+/* Replacement. */
+void ds_assign_string (struct string *, const struct string *);
+void ds_assign_substring (struct string *,
+                          const struct string *, size_t start, size_t cnt);
+void ds_assign_buffer (struct string *, const char *, size_t);
+void ds_assign_c_str (struct string *, const char *);
+
+/* Shrink, extend. */
 void ds_clear (struct string *);
 void ds_extend (struct string *, size_t);
 void ds_shrink (struct string *);
 void ds_truncate (struct string *, size_t);
+
+/* Padding, trimming. */
 void ds_rpad (struct string *, size_t length, char pad);
 int ds_rtrim_spaces (struct string *);
-int ds_ltrim_spaces (struct string *st);
-
+int ds_ltrim_spaces (struct string *);
+void ds_trim_spaces (struct string *);
 bool ds_chomp (struct string *, char);
+bool ds_separate (const struct string *src, struct string *token,
+                  const char *delimiters, int *save_idx);
 
 /* Inspectors. */
 bool ds_is_empty (const struct string *);
@@ -140,16 +153,19 @@ char *ds_c_str (const struct string *);
 char *ds_data (const struct string *);
 char *ds_end (const struct string *);
 size_t ds_capacity (const struct string *);
+int ds_at (const struct string *, size_t idx);
 int ds_first (const struct string *);
 int ds_last (const struct string *);
+size_t ds_span (const struct string *st, size_t ofs, const char skip_set[]);
+size_t ds_cspan (const struct string *st, size_t ofs, const char stop_set[]);
 
 /* File input. */
-struct file_locator;
-int ds_gets (struct string *, FILE *);
-int ds_get_config_line (FILE *, struct string *, struct file_locator *);
+bool ds_gets (struct string *, FILE *);
+bool ds_get_config_line (FILE *, struct string *, int *line_number);
 
 /* Append. */
 void ds_putc (struct string *, int ch);
+void ds_putc_multiple (struct string *, int ch, size_t);
 void ds_puts (struct string *, const char *);
 void ds_concat (struct string *, const char *, size_t);
 void ds_vprintf (struct string *st, const char *, va_list);
@@ -171,14 +187,6 @@ ds_length (const struct string *st)
   return st->length;
 }
 
-extern inline char *
-ds_c_str (const struct string *st)
-{
-  assert(st);
-  ((char *) st->string)[st->length] = '\0';
-  return st->string;
-}
-
 extern inline char *
 ds_data (const struct string *st)
 {
@@ -210,12 +218,7 @@ spprintf (char *dst, const char *format, ...)
   return dst + count;
 }
 
-int ds_find(const struct string *st, const char cs[]);
-
-int ds_n_find(const struct string *st, const char cs[]);
 
-void ds_create_substr(struct string *dst, const struct string *src, 
-                     int first, int last);
 
 
 #endif /* str_h */
index 0560dd88a1428b9844233411d947b15cc4f268bf..7af231d1b8b2ab06fb66fcec5dd8ae34adb28641 100644 (file)
@@ -1,3 +1,8 @@
+Thu Mar 30 16:26:56 2006  Ben Pfaff  <blp@gnu.org>
+
+       * output.c: (colon_tokenize) Removed.
+       (configure_driver_line) Rewrote to use ds_separate().  Fixed leak.
+
 Tue Mar 28 13:50:53 WST 2006 John Darrington <john@darrington.wattle.id.au>
 
        * html.c, postscript.c, output.c:  Changed to fit the new signature 
index 716f7c10eac7e81ce428ad9f3ea1857a994c3b1d..0390e1af73c7f56563def75ca14a9c9f2c6af2f7 100644 (file)
@@ -302,7 +302,7 @@ outp_read_devices (void)
     {
       char *cp;
 
-      if (!ds_get_config_line (f, &line, &where))
+      if (!ds_get_config_line (f, &line, &where.line_number))
        {
          if (ferror (f))
            msg (ME, _("Reading %s: %s."), init_fn, strerror (errno));
@@ -664,58 +664,6 @@ find_driver (char *name)
   return NULL;
 }
 
-/* Tokenize string SRC into colon-separated fields, removing leading and
-   trailing whitespace on tokens.  Tokens are placed into DEST.
-   
-   CP should remain unchanged throughout. 
-   It is the callers responsibility to destroy CP and DEST.
-
-
-   Returns true if there are more fields, false otherwise.
-
-   FIXME: Should ignore colons inside double quotes. */
-static bool
-colon_tokenize(const struct string *src, struct string *dest, 
-                 struct string *cp)
-{
-  int last;
-
-  if ( src ) 
-    ds_create(cp, ds_c_str(src));
-
-  int first = ds_n_find(cp, "\t ");
-  int delim = ds_find(cp, ":") ;
-  
-  if ( delim < 0 ) 
-    last = ds_length(cp);
-  else
-    last = delim - 1;
-
-  if ( delim == first) 
-    {
-      ds_create(dest,"");
-    }
-  else
-    {
-      ds_create_substr(dest, cp, first, last);
-    }
-
-  if ( last < ds_length(cp) ) 
-    {
-      struct string temp;
-      ds_create_substr(&temp, cp, last + 2, ds_length(cp));
-      ds_swap(cp, &temp);
-      ds_destroy(&temp);
-      return true;
-    }
-  else
-    {
-      ds_clear(cp);
-      return false;
-    }
-}
-
-
 /* String S is in format:
    DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS
    Adds a driver to outp_driver_list pursuant to the specification
@@ -821,34 +769,29 @@ error:
 static void
 configure_driver_line (struct string *line)
 {
-  fn_interp_vars(line, find_defn_value);
+  struct string tokens[4];
+  int save_idx;
+  size_t i;
 
-  struct string driver_name;
-  struct string class_name;
-  struct string device_type;
-  struct string options;
+  fn_interp_vars (line, find_defn_value);
 
-  struct string sss;
-  colon_tokenize (line, &driver_name, &sss);
-  colon_tokenize (NULL, &class_name,  &sss);
-  colon_tokenize (NULL, &device_type, &sss);
-  colon_tokenize (NULL, &options, &sss);
-
-  if (ds_is_empty(&driver_name) || ds_is_empty(&class_name))
+  save_idx = -1;
+  for (i = 0; i < 4; i++) 
     {
-      msg (IS, _("Driver definition line contains fewer fields "
-                 "than expected"));
-      return;
+      struct string *token = &tokens[i];
+      ds_init (token, 0);
+      ds_separate (line, token, i < 3 ? ":" : "", &save_idx);
+      ds_trim_spaces (token);
     }
 
-  configure_driver (ds_c_str(&driver_name), ds_c_str(&class_name), 
-                   ds_c_str(&device_type), ds_c_str(&options));
+  if (!ds_is_empty (&tokens[0]) && !ds_is_empty (&tokens[1]))
+    configure_driver (ds_c_str (&tokens[0]), ds_c_str (&tokens[1]), 
+                      ds_c_str (&tokens[2]), ds_c_str (&tokens[3]));
+  else
+    msg (IS, _("Driver definition line missing driver name or class name"));
 
-  ds_destroy(&driver_name);
-  ds_destroy(&class_name);
-  ds_destroy(&device_type);
-  ds_destroy(&options);
-  ds_destroy(&sss);
+  for (i = 0; i < 4; i++) 
+    ds_destroy (&tokens[i]);
 }
 
 /* Destroys output driver D. */
@@ -1210,7 +1153,7 @@ outp_get_paper_size (char *size, int *h, int *v)
     {
       char *cp, *bp, *ep;
 
-      if (!ds_get_config_line (f, &line, &where))
+      if (!ds_get_config_line (f, &line, &where.line_number))
        {
          if (ferror (f))
            msg (ME, _("Reading %s: %s."), pprsz_fn, strerror (errno));
index 5d0d577607687132fb95cf7c5f2db8a23341d215..b26676a92096c441254e9ab67245ad2120792e93 100644 (file)
@@ -935,7 +935,7 @@ output_encodings (struct outp_driver *this)
          where.line_number = 0;
          err_push_file_locator (&where);
 
-         while (ds_get_config_line (f, &buf, &where))
+         while (ds_get_config_line (f, &buf, &where.line_number))
            {
              char *sp; 
 
@@ -1104,7 +1104,7 @@ read_ps_encodings (struct outp_driver *this)
     
   for (;;)
     {
-      if (!ds_get_config_line (f, &line, &where))
+      if (!ds_get_config_line (f, &line, &where.line_number))
        {
          if (ferror (f))
            msg (ME, _("Reading %s: %s."), encoding_fn, strerror (errno));
index e92113514aae370953d1a582322c393b8e690533..7122b78d8777a11cafe644f4e55a25ebf046ea16 100644 (file)
@@ -130,7 +130,7 @@ readln_read (struct string *line, const char *prompt)
     {
       if (string[0])
         add_history (string);
-      ds_replace (line, string);
+      ds_assign_c_str (line, string);
       free (string);
       return true; 
     }