Fixed memory leaks resulting from fn_interp_vars et. al.
[pspp-builds.git] / src / output / output.c
index 4a915fe2ef6e3acd2635ada098ccf0b6a0b3f982..716f7c10eac7e81ce428ad9f3ea1857a994c3b1d 100644 (file)
@@ -61,7 +61,7 @@ struct outp_names
 struct outp_defn
   {
     char *key;
-    char *value;
+    struct string value;
     struct outp_defn *next, *prev;
   };
 
@@ -79,7 +79,7 @@ char *outp_subtitle;
 static int disabled_devices;
 
 static void destroy_driver (struct outp_driver *);
-static void configure_driver_line (char *);
+static void configure_driver_line (struct string *);
 static void configure_driver (const char *, const char *,
                               const char *, const char *);
 
@@ -200,7 +200,7 @@ find_defn_value (const char *key)
 
   for (d = outp_macros; d; d = d->next)
     if (!strcmp (key, d->key))
-      return d->value;
+      return ds_c_str(&d->value);
   if (!strcmp (key, "viewwidth"))
     {
       sprintf (buf, "%d", get_viewwidth ());
@@ -244,7 +244,7 @@ delete_macros (void)
     {
       next = d->next;
       free (d->key);
-      free (d->value);
+      ds_destroy (&d->value);
       free (d);
     }
 }
@@ -322,7 +322,7 @@ outp_read_devices (void)
              struct outp_names *n = search_names (cp, ep);
              if (n)
                {
-                 configure_driver_line (cp);
+                 configure_driver_line (&line);
                  delete_name (n);
                }
            }
@@ -411,7 +411,9 @@ outp_configure_macro (char *bp)
     ep++;
   while (isspace ((unsigned char) *ep))
     ep++;
-  d->value = fn_interp_vars (ep, find_defn_value);
+
+  ds_create(&d->value, ep);
+  fn_interp_vars(&d->value, find_defn_value);
   d->next = outp_macros;
   d->prev = NULL;
   if (outp_macros)
@@ -662,37 +664,58 @@ find_driver (char *name)
   return NULL;
 }
 
-/* Tokenize string S into colon-separated fields, removing leading and
-   trailing whitespace on tokens.  Returns a pointer to the
-   null-terminated token, which is formed by setting a NUL character
-   into the string.  After the first call, subsequent calls should set
-   S to NULL.  CP should be consistent across calls.  Returns NULL
-   after all fields have been used up.
+/* 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 const char *
-colon_tokenize (char *s, char **cp)
+static bool
+colon_tokenize(const struct string *src, struct string *dest, 
+                 struct string *cp)
 {
-  char *token;
+  int last;
+
+  if ( src ) 
+    ds_create(cp, ds_c_str(src));
+
+  int first = ds_n_find(cp, "\t ");
+  int delim = ds_find(cp, ":") ;
   
-  if (!s)
+  if ( delim < 0 ) 
+    last = ds_length(cp);
+  else
+    last = delim - 1;
+
+  if ( delim == first) 
     {
-      s = *cp;
-      if (*s == 0)
-       return NULL;
+      ds_create(dest,"");
     }
-  token = s += strspn (s, " \t\v\r");
-  *cp = strchr (s, ':');
-  if (*cp == NULL)
-    s = *cp = strchr (s, 0);
   else
-    s = (*cp)++;
-  while (s > token && strchr (" \t\v\r", s[-1]))
-    s--;
-  *s = 0;
-  return token;
+    {
+      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
@@ -791,31 +814,41 @@ error:
   return;
 }
 
-/* String S is in format:
+/* String LINE is in format:
    DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS
    Adds a driver to outp_driver_list pursuant to the specification
    provided.  */
 static void
-configure_driver_line (char *s)
+configure_driver_line (struct string *line)
 {
-  char *cp;
-  const char *driver_name, *class_name, *device_type, *options;
+  fn_interp_vars(line, find_defn_value);
 
-  s = fn_interp_vars (s, find_defn_value);
+  struct string driver_name;
+  struct string class_name;
+  struct string device_type;
+  struct string options;
 
-  /* Driver name. */
-  driver_name = colon_tokenize (s, &cp);
-  class_name = colon_tokenize (NULL, &cp);
-  device_type = colon_tokenize (NULL, &cp);
-  options = colon_tokenize (NULL, &cp);
-  if (driver_name == NULL || class_name == NULL)
+  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))
     {
       msg (IS, _("Driver definition line contains fewer fields "
                  "than expected"));
       return;
     }
 
-  configure_driver (driver_name, class_name, device_type, options);
+  configure_driver (ds_c_str(&driver_name), ds_c_str(&class_name), 
+                   ds_c_str(&device_type), ds_c_str(&options));
+
+  ds_destroy(&driver_name);
+  ds_destroy(&class_name);
+  ds_destroy(&device_type);
+  ds_destroy(&options);
+  ds_destroy(&sss);
 }
 
 /* Destroys output driver D. */