From f75d96d09553928fb3c5461a2e75efdd6f9e76e1 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 16 Jun 2009 22:34:16 -0700 Subject: [PATCH] output: Make allocating and freeing drivers independent of configuration. 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 | 9 ++- src/output/cairo.c | 6 +- src/output/html.c | 8 +- src/output/output.c | 165 +++++++++++++++++++--------------------- src/output/output.h | 24 ++++-- src/output/postscript.c | 8 +- 6 files changed, 120 insertions(+), 100 deletions(-) diff --git a/src/output/ascii.c b/src/output/ascii.c index 29d7b76b..c6a808e8 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -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; } diff --git a/src/output/cairo.c b/src/output/cairo.c index 048ac7e9..53c454c2 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -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; } diff --git a/src/output/html.c b/src/output/html.c index 893c1852..08931f52 100644 --- a/src/output/html.c +++ b/src/output/html.c @@ -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; } diff --git a/src/output/output.c b/src/output/output.c index 4dc9902c..6082d249 100644 --- a/src/output/output.c +++ b/src/output/output.c @@ -39,12 +39,6 @@ #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; } diff --git a/src/output/output.h b/src/output/output.h index fc668740..47680fee 100644 --- a/src/output/output.h +++ b/src/output/output.h @@ -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 #include - /* 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 */ diff --git a/src/output/postscript.c b/src/output/postscript.c index 11116b9b..4f486cca 100644 --- a/src/output/postscript.c +++ b/src/output/postscript.c @@ -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; } -- 2.30.2