output: Make allocating and freeing drivers independent of configuration.
authorBen Pfaff <blp@gnu.org>
Wed, 17 Jun 2009 05:34:16 +0000 (22:34 -0700)
committerBen Pfaff <blp@gnu.org>
Wed, 17 Jun 2009 05:34:16 +0000 (22:34 -0700)
Until now, the output subsystem has taken responsibility for
allocating, freeing, registering, and unregistering output drivers.
This is usually what we want it to do, but PSPPIRE will soon want to
register an output driver of its own, independent of the main driver
configuration mechanism.  This commit refactors the output driver
subsystem slightly to make this possible.

src/output/ascii.c
src/output/cairo.c
src/output/html.c
src/output/output.c
src/output/output.h
src/output/postscript.c

index 29d7b76b2940d76dbc0af108827922785f8e71ce..c6a808e83b488b7009ce83f90df5ba8278fd27e0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 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
@@ -137,11 +137,13 @@ static bool handle_option (struct outp_driver *this, const char *key,
                            const struct string *val);
 
 static bool
-ascii_open_driver (struct outp_driver *this, struct substring options)
+ascii_open_driver (const char *name, int types, struct substring options)
 {
+  struct outp_driver *this;
   struct ascii_driver_ext *x;
   int i;
 
+  this = outp_allocate_driver (&ascii_class, name, types);
   this->width = 79;
   this->font_height = 1;
   this->prop_em_width = 1;
@@ -189,10 +191,13 @@ ascii_open_driver (struct outp_driver *this, struct substring options)
         x->box[i] = pool_strdup (x->pool, s);
       }
 
+  outp_register_driver (this);
+
   return true;
 
  error:
   pool_destroy (x->pool);
+  outp_free_driver (this);
   return false;
 }
 
index 048ac7e9cd057a5600cb5186770edbaf11a0792d..53c454c2daeaa0bfe04e9821b58fb08d7b3749ac 100644 (file)
@@ -135,14 +135,16 @@ static int text_width (struct outp_driver *, const char *, enum outp_font);
 /* Driver initialization. */
 
 static bool
-xr_open_driver (struct outp_driver *this, struct substring options)
+xr_open_driver (const char *name, int types, struct substring options)
 {
   cairo_surface_t *surface;
   cairo_status_t status;
+  struct outp_driver *this;
   struct xr_driver_ext *x;
   double width_pt, length_pt;
   size_t i;
 
+  this = outp_allocate_driver (&cairo_class, name, types);
   this->width = this->length = 0;
   this->font_height = XR_POINT * 10;
 
@@ -240,10 +242,12 @@ xr_open_driver (struct outp_driver *this, struct substring options)
   memcpy (this->vert_line_width, this->horiz_line_width,
           sizeof this->vert_line_width);
 
+  outp_register_driver (this);
   return true;
 
  error:
   this->class->close_driver (this);
+  outp_free_driver (this);
   return false;
 }
 
index 893c18527b7ff30e431762ede6658332e6fc5e46..08931f52e1c477e927228f3f56882bf4add6b22e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -53,10 +53,12 @@ static void print_title_tag (FILE *file, const char *name,
                              const char *content);
 
 static bool
-html_open_driver (struct outp_driver *this, struct substring options)
+html_open_driver (const char *name, int types, struct substring options)
 {
+  struct outp_driver *this;
   struct html_driver_ext *x;
 
+  this = outp_allocate_driver (&html_class, name, types);
   this->ext = x = xmalloc (sizeof *x);
   x->file_name = xstrdup ("pspp.html");
   x->chart_file_name = xstrdup ("pspp-#.png");
@@ -89,10 +91,12 @@ html_open_driver (struct outp_driver *this, struct substring options)
   print_title_tag (x->file, "H1", outp_title);
   print_title_tag (x->file, "H2", outp_subtitle);
 
+  outp_register_driver (this);
   return true;
 
  error:
   this->class->close_driver (this);
+  outp_free_driver (this);
   return false;
 }
 
index 4dc9902c35452c880252ffe4bc42a80f4e107724..6082d2490c0e6091477cebd67f1e26f0d8219709 100644 (file)
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* FIXME? Should the output configuration format be changed to
-   drivername:classname:devicetype:options, where devicetype is zero
-   or more of screen, printer, listing? */
-
-/* FIXME: Have the reentrancy problems been solved? */
-
 /* Where the output driver name came from. */
 enum
   {
@@ -79,7 +73,7 @@ struct outp_driver_class_list
   };
 
 static struct outp_driver_class_list *outp_class_list;
-static struct outp_driver *outp_driver_list;
+static struct ll_list outp_driver_list = LL_INITIALIZER (outp_driver_list);
 
 char *outp_title;
 char *outp_subtitle;
@@ -228,12 +222,6 @@ find_defn_value (const char *key)
 void
 outp_init (void)
 {
-  extern struct outp_class ascii_class;
-  extern struct outp_class postscript_class;
-#ifdef HAVE_CAIRO
-  extern struct outp_class cairo_class;
-#endif
-
   char def[] = "default";
 
   add_class (&html_class);
@@ -351,13 +339,13 @@ exit:
 
   if (result)
     {
-      if (outp_driver_list == NULL)
+      if (ll_is_empty (&outp_driver_list))
         error (0, 0, _("no active output drivers"));
     }
   else
     error (0, 0, _("error reading device definition file"));
 
-  if (!result || outp_driver_list == NULL)
+  if (!result || ll_is_empty (&outp_driver_list))
     init_default_drivers ();
 }
 
@@ -427,29 +415,18 @@ outp_configure_macro (char *bp)
   outp_macros = d;
 }
 
-/* Destroys all the drivers in driver list *DL and sets *DL to
-   NULL. */
-static void
-destroy_list (struct outp_driver ** dl)
-{
-  struct outp_driver *d, *next;
-
-  for (d = *dl; d; d = next)
-    {
-      destroy_driver (d);
-      next = d->next;
-      free (d);
-    }
-  *dl = NULL;
-}
-
 /* Closes all the output drivers. */
 void
 outp_done (void)
 {
   struct outp_driver_class_list *n = outp_class_list ;
   outp_configure_clear ();
-  destroy_list (&outp_driver_list);
+  while (!ll_is_empty (&outp_driver_list))
+    {
+      struct outp_driver *d = ll_data (ll_head (&outp_driver_list),
+                                       struct outp_driver, node);
+      destroy_driver (d);
+    }
 
   while (n)
     {
@@ -664,8 +641,7 @@ static struct outp_driver *
 find_driver (char *name)
 {
   struct outp_driver *d;
-
-  for (d = outp_driver_list; d; d = d->next)
+  ll_for_each (d, struct outp_driver, node, &outp_driver_list)
     if (!strcmp (d->name, name))
       return d;
   return NULL;
@@ -677,11 +653,10 @@ static void
 configure_driver (struct substring driver_name, struct substring class_name,
                   struct substring device_type, struct substring options)
 {
-  struct outp_driver *d, *iter;
   struct outp_driver_class_list *c;
-
   struct substring token;
   size_t save_idx = 0;
+  char *name;
   int device;
 
   /* Find class. */
@@ -708,38 +683,68 @@ configure_driver (struct substring driver_name, struct substring class_name,
       error (0, 0, _("unknown device type `%.*s'"),
              (int) ss_length (token), ss_data (token));
 
-  /* Open the device. */
-  d = xmalloc (sizeof *d);
-  d->next = d->prev = NULL;
-  d->class = c->class;
-  d->name = ss_xstrdup (driver_name);
+  /* Open driver. */
+  name = ss_xstrdup (driver_name);
+  if (!c->class->open_driver (name, device, options))
+    error (0, 0, _("cannot initialize output driver `%s' of class `%s'"),
+           name, c->class->name);
+  free (name);
+}
+
+/* Allocates and returns a new outp_driver for a device with the
+   given NAME and CLASS and the OUTP_DEV_* type(s) in TYPES
+
+   This function is intended to be used by output drivers, not
+   by their clients. */
+struct outp_driver *
+outp_allocate_driver (const struct outp_class *class,
+                      const char *name, int types)
+{
+  struct outp_driver *d = xmalloc (sizeof *d);
+  d->class = class;
+  d->name = xstrdup (name);
   d->page_open = false;
-  d->device = device;
+  d->device = types;
   d->cp_x = d->cp_y = 0;
   d->ext = NULL;
   d->prc = NULL;
+  return d;
+}
 
-  /* Open driver. */
-  if (!d->class->open_driver (d, options))
-    {
-      error (0, 0, _("cannot initialize output driver `%s' of class `%s'"),
-             d->name, d->class->name);
-      free (d->name);
-      free (d);
-      return;
-    }
+/* Frees driver D and the data that it owns directly.  The
+   driver's class must already have unregistered D (if it was
+   registered) and freed data private to its class.
+
+   This function is intended to be used by output drivers, not
+   by their clients. */
+void
+outp_free_driver (struct outp_driver *d)
+{
+  free (d->name);
+  free (d);
+}
+
+/* Adds D to the list of drivers that will be used for output. */
+void
+outp_register_driver (struct outp_driver *d)
+{
+  struct outp_driver *victim;
 
   /* Find like-named driver and delete. */
-  iter = find_driver (d->name);
-  if (iter != NULL)
-    destroy_driver (iter);
+  victim = find_driver (d->name);
+  if (victim != NULL)
+    destroy_driver (victim);
 
-  /* Add to list. */
-  d->next = outp_driver_list;
-  d->prev = NULL;
-  if (outp_driver_list != NULL)
-    outp_driver_list->prev = d;
-  outp_driver_list = d;
+  /* Add D to list. */
+  ll_push_tail (&outp_driver_list, &d->node);
+}
+
+/* Remove driver D from the list of drivers that will be used for
+   output. */
+void
+outp_unregister_driver (struct outp_driver *d)
+{
+  ll_remove (&d->node);
 }
 
 /* String LINE is in format:
@@ -778,26 +783,10 @@ static void
 destroy_driver (struct outp_driver *d)
 {
   outp_close_page (d);
-  if (d->class)
-    {
-      struct outp_driver_class_list *c;
-
-      d->class->close_driver (d);
-
-      for (c = outp_class_list; c; c = c->next)
-       if (c->class == d->class)
-         break;
-      assert (c != NULL);
-    }
-  free (d->name);
-
-  /* Remove this driver from the global driver list. */
-  if (d->prev)
-    d->prev->next = d->next;
-  if (d->next)
-    d->next->prev = d->prev;
-  if (d == outp_driver_list)
-    outp_driver_list = d->next;
+  if (d->class && d->class->close_driver)
+    d->class->close_driver (d);
+  outp_unregister_driver (d);
+  outp_free_driver (d);
 }
 
 /* Tries to match S as one of the keywords in TAB, with
@@ -1093,17 +1082,17 @@ outp_get_paper_size (const char *size, int *h, int *v)
 struct outp_driver *
 outp_drivers (struct outp_driver *d)
 {
-  for (;;)
+  do
     {
-      if (d == NULL)
-       d = outp_driver_list;
-      else
-       d = d->next;
+      struct ll *next;
+
+      next = d == NULL ? ll_head (&outp_driver_list) : ll_next (&d->node);
+      if (next == ll_null (&outp_driver_list))
+        return NULL;
 
-      if (d == NULL
-         || (d->device == 0 || (d->device & disabled_devices) != d->device))
-       break;
+      d = ll_data (next, struct outp_driver, node);
     }
+  while (d->device != 0 && (d->device & disabled_devices) == d->device);
 
   return d;
 }
index fc66874068da031cafef1743406131c486ee504d..47680fee39183cfbf3aa1f39cc7398e95b4427d3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 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
@@ -17,9 +17,9 @@
 #ifndef OUTPUT_OUTPUT_H
 #define OUTPUT_OUTPUT_H 1
 
+#include <libpspp/ll.h>
 #include <libpspp/str.h>
 
-
 /* Line styles.  */
 enum outp_line_style
   {
@@ -65,7 +65,8 @@ struct outp_class
     const char *name;          /* Name of this driver class. */
     int special;               /* Boolean value. */
 
-    bool (*open_driver) (struct outp_driver *, struct substring options);
+    bool (*open_driver) (const char *name, int types,
+                         struct substring options);
     bool (*close_driver) (struct outp_driver *);
 
     void (*open_page) (struct outp_driver *);
@@ -99,7 +100,7 @@ enum
 /* Defines the configuration of an output driver. */
 struct outp_driver
   {
-    struct outp_driver *next, *prev; /* List of drivers. */
+    struct ll node;             /* Node in list of drivers. */
     const struct outp_class *class;    /* Driver class. */
     char *name;                        /* Name of this driver. */
     bool page_open;            /* 1=page is open, 0=page is closed. */
@@ -131,9 +132,15 @@ extern char *outp_title;
 extern char *outp_subtitle;
 
 void outp_init (void);
+void outp_done (void);
 void outp_read_devices (void);
 void outp_configure_driver_line (struct substring);
-void outp_done (void);
+
+struct outp_driver *outp_allocate_driver (const struct outp_class *class,
+                                          const char *name, int types);
+void outp_free_driver (struct outp_driver *);
+void outp_register_driver (struct outp_driver *);
+void outp_unregister_driver (struct outp_driver *);
 
 void outp_configure_clear (void);
 void outp_configure_add (char *);
@@ -163,4 +170,11 @@ int outp_string_width (struct outp_driver *, const char *, enum outp_font);
 /* Imported from som-frnt.c. */
 void som_destroy_driver (struct outp_driver *);
 
+/* Common drivers. */
+extern const struct outp_class ascii_class;
+extern const struct outp_class postscript_class;
+#ifdef HAVE_CAIRO
+extern const struct outp_class cairo_class;
+#endif
+
 #endif /* output/output.h */
index 11116b9b6d7a0d3b49db98dda6c7eb455043e5ca..4f486ccaadc9909c739fb926b50b298e23ac44aa 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 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
@@ -125,11 +125,13 @@ static void setup_font (struct outp_driver *this, struct font *, int index);
 /* Driver initialization. */
 
 static bool
-ps_open_driver (struct outp_driver *this, struct substring options)
+ps_open_driver (const char *name, int types, struct substring options)
 {
+  struct outp_driver *this;
   struct ps_driver_ext *x;
   size_t i;
 
+  this = outp_allocate_driver (&postscript_class, name, types);
   this->width = this->length = 0;
   this->font_height = PSUS * 10 / 72;
 
@@ -219,10 +221,12 @@ ps_open_driver (struct outp_driver *this, struct substring options)
 
   write_ps_prologue (this);
 
+  outp_register_driver (this);
   return true;
 
  error:
   this->class->close_driver (this);
+  outp_free_driver (this);
   return false;
 }