static struct outp_defn *outp_macros;
static struct outp_names *outp_configure_vec;
+/* A list of driver classes. */
+struct outp_driver_class_list
+ {
+ struct outp_class *class;
+ struct outp_driver_class_list *next;
+ };
+
struct outp_driver_class_list *outp_class_list;
struct outp_driver *outp_driver_list;
static void destroy_driver (struct outp_driver *);
static void configure_driver_line (struct string *);
-static void configure_driver (const char *, const char *,
- const char *, const char *);
+static void configure_driver (const struct string *, const struct string *,
+ const struct string *, const struct string *);
/* Add a class to the class list. */
static void
struct outp_driver_class_list *new_list = xmalloc (sizeof *new_list);
new_list->class = class;
- new_list->ref_count = 0;
if (!outp_class_list)
{
{
extern struct outp_class ascii_class;
extern struct outp_class postscript_class;
- extern struct outp_class epsf_class;
extern struct outp_class html_class;
char def[] = "default";
add_class (&html_class);
- add_class (&epsf_class);
add_class (&postscript_class);
add_class (&ascii_class);
static void
init_default_drivers (void)
{
+ struct string s;
+
msg (MM, _("Using default output driver configuration."));
- configure_driver ("list-ascii", "ascii", "listing",
- "length=66 width=79 char-set=ascii "
- "output-file=\"pspp.list\" "
- "bold-on=\"\" italic-on=\"\" bold-italic-on=\"\"");
+
+ ds_create (&s,
+ "list:ascii:listing:"
+ "length=66 width=79 output-file=\"pspp.list\"");
+ configure_driver_line (&s);
+ ds_destroy (&s);
}
/* Reads the initialization file; initializes
goto exit;
}
- msg (VM (1), _("%s: Opening device description file..."), init_fn);
f = fopen (init_fn, "r");
if (f == NULL)
{
{
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));
if (result)
{
- msg (VM (2), _("Device definition file read successfully."));
if (outp_driver_list == NULL)
msg (MW, _("No output drivers are active."));
}
return 1;
}
-/* Applies the user-specified options in string S to output driver D
- (at configuration time). */
-static void
-parse_options (const char *s, struct outp_driver * d)
+bool
+outp_parse_options (const char *options,
+ bool (*callback) (struct outp_driver *, const char *key,
+ const struct string *value),
+ struct outp_driver *driver)
{
- prog = s;
+ bool ok = true;
+
+ prog = options;
op_token = -1;
ds_init (&op_tokstr, 64);
- while (tokener ())
+ while (ok && tokener ())
{
char key[65];
msg (IS, _("Syntax error in options (value expected after `=')."));
break;
}
- d->class->option (d, key, &op_tokstr);
+ ok = callback (driver, key, &op_tokstr);
}
ds_destroy (&op_tokstr);
+
+ return ok;
}
/* Find the driver in outp_driver_list with name 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
provided. */
static void
-configure_driver (const char *driver_name, const char *class_name,
- const char *device_type, const char *options)
+configure_driver (const struct string *driver_name,
+ const struct string *class_name,
+ const struct string *device_type,
+ const struct string *options)
{
- struct outp_driver *d = NULL, *iter;
- struct outp_driver_class_list *c = NULL;
-
- d = xmalloc (sizeof *d);
- d->class = NULL;
- d->name = xstrdup (driver_name);
- d->driver_open = 0;
- d->page_open = 0;
- d->next = d->prev = NULL;
- d->device = OUTP_DEV_NONE;
- d->ext = NULL;
+ struct outp_driver *d, *iter;
+ struct outp_driver_class_list *c;
+ int device;
+ /* Find class. */
for (c = outp_class_list; c; c = c->next)
- if (!strcmp (c->class->name, class_name))
+ if (!strcmp (c->class->name, ds_c_str (class_name)))
break;
- if (!c)
+ if (c == NULL)
{
- msg (IS, _("Unknown output driver class `%s'."), class_name);
- goto error;
+ msg (IS, _("Unknown output driver class `%s'."), ds_c_str (class_name));
+ return;
}
- d->class = c->class;
- if (!c->ref_count && !d->class->open_global (d->class))
- {
- msg (IS, _("Can't initialize output driver class `%s'."),
- d->class->name);
- goto error;
- }
- c->ref_count++;
- if (!d->class->preopen_driver (d))
- {
- msg (IS, _("Can't initialize output driver `%s' of class `%s'."),
- d->name, d->class->name);
- goto error;
- }
-
- /* Device types. */
+ /* Parse device type. */
+ device = 0;
if (device_type != NULL)
{
- char *copy = xstrdup (device_type);
- char *sp, *type;
+ struct string token = DS_INITIALIZER;
+ size_t save_idx = 0;
- for (type = strtok_r (copy, " \t\r\v", &sp); type;
- type = strtok_r (NULL, " \t\r\v", &sp))
- {
+ while (ds_tokenize (device_type, &token, " \t\r\v", &save_idx))
+ {
+ const char *type = ds_c_str (&token);
if (!strcmp (type, "listing"))
- d->device |= OUTP_DEV_LISTING;
+ device |= OUTP_DEV_LISTING;
else if (!strcmp (type, "screen"))
- d->device |= OUTP_DEV_SCREEN;
+ device |= OUTP_DEV_SCREEN;
else if (!strcmp (type, "printer"))
- d->device |= OUTP_DEV_PRINTER;
+ device |= OUTP_DEV_PRINTER;
else
- {
- msg (IS, _("Unknown device type `%s'."), type);
- free (copy);
- goto error;
- }
+ msg (IS, _("Unknown device type `%s'."), type);
}
- free (copy);
+ ds_destroy (&token);
}
-
- /* Options. */
- if (options != NULL)
- parse_options (options, d);
- if (!d->class->postopen_driver (d))
+
+ /* Open the device. */
+ d = xmalloc (sizeof *d);
+ d->next = d->prev = NULL;
+ d->class = c->class;
+ d->name = xstrdup (ds_c_str (driver_name));
+ d->page_open = false;
+ d->device = OUTP_DEV_NONE;
+ d->cp_x = d->cp_y = 0;
+ d->ext = NULL;
+ d->prc = NULL;
+
+ /* Open driver. */
+ if (!d->class->open_driver (d, ds_c_str (options)))
{
- msg (IS, _("Can't complete initialization of output driver `%s' of "
- "class `%s'."), d->name, d->class->name);
- goto error;
+ msg (IS, _("Can't initialize output driver `%s' of class `%s'."),
+ d->name, d->class->name);
+ free (d->name);
+ free (d);
+ return;
}
/* Find like-named driver and delete. */
iter = find_driver (d->name);
- if (iter)
+ if (iter != NULL)
destroy_driver (iter);
/* Add to list. */
d->next = outp_driver_list;
d->prev = NULL;
- if (outp_driver_list)
+ if (outp_driver_list != NULL)
outp_driver_list->prev = d;
outp_driver_list = d;
- return;
-
-error:
- if (d)
- destroy_driver (d);
- return;
}
/* String LINE is in format:
static void
configure_driver_line (struct string *line)
{
- fn_interp_vars(line, find_defn_value);
+ struct string tokens[4];
+ size_t 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 = 0;
+ 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 (&tokens[0], &tokens[1], &tokens[2], &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. */
static void
destroy_driver (struct outp_driver *d)
{
- if (d->page_open)
- d->class->close_page (d);
+ outp_close_page (d);
if (d->class)
{
struct outp_driver_class_list *c;
- if (d->driver_open)
- d->class->close_driver (d);
+ d->class->close_driver (d);
for (c = outp_class_list; c; c = c->next)
if (c->class == d->class)
break;
assert (c != NULL);
-
- c->ref_count--;
- if (c->ref_count == 0)
- {
- if (!d->class->close_global (d->class))
- msg (IS, _("Can't deinitialize output driver class `%s'."),
- d->class->name);
- }
}
free (d->name);
outp_driver_list = d->next;
}
-static int
-option_cmp (const void *a, const void *b)
-{
- const struct outp_option *o1 = a;
- const struct outp_option *o2 = b;
- return strcmp (o1->keyword, o2->keyword);
-}
-
-/* Tries to match S as one of the keywords in TAB, with corresponding
- information structure INFO. Returns category code or 0 on failure;
- if category code is negative then stores subcategory in *SUBCAT. */
+/* Tries to match S as one of the keywords in TAB, with
+ corresponding information structure INFO. Returns category
+ code and stores subcategory in *SUBCAT on success. Returns -1
+ on failure. */
int
-outp_match_keyword (const char *s, struct outp_option *tab,
- struct outp_option_info *info, int *subcat)
+outp_match_keyword (const char *s, struct outp_option *tab, int *subcat)
{
- char *cp;
- struct outp_option *oip;
-
- /* Form hash table. */
- if (NULL == info->initial)
- {
- /* Count items. */
- int count, i;
- char s[256], *cp;
- struct outp_option *ptr[255], **oip;
-
- for (count = 0; tab[count].keyword[0]; count++)
- ;
-
- /* Sort items. */
- qsort (tab, count, sizeof *tab, option_cmp);
-
- cp = s;
- oip = ptr;
- *cp = tab[0].keyword[0];
- *oip++ = &tab[0];
- for (i = 0; i < count; i++)
- if (tab[i].keyword[0] != *cp)
- {
- *++cp = tab[i].keyword[0];
- *oip++ = &tab[i];
- }
- *++cp = 0;
-
- info->initial = xstrdup (s);
- info->options = xnmalloc (cp - s, sizeof *info->options);
- memcpy (info->options, ptr, sizeof *info->options * (cp - s));
- }
-
- cp = info->initial;
- oip = *info->options;
-
- if (s[0] == 0)
- return 0;
- cp = strchr (info->initial, s[0]);
- if (!cp)
- return 0;
-#if 0
- printf (_("Trying to find keyword `%s'...\n"), s);
-#endif
- oip = info->options[cp - info->initial];
- while (oip->keyword[0] == s[0])
- {
-#if 0
- printf ("- %s\n", oip->keyword);
-#endif
- if (!strcmp (s, oip->keyword))
- {
- if (oip->cat < 0)
- *subcat = oip->subcat;
- return oip->cat;
- }
- oip++;
- }
-
- return 0;
+ for (; tab->keyword != NULL; tab++)
+ if (!strcmp (s, tab->keyword))
+ {
+ *subcat = tab->subcat;
+ return tab->cat;
+ }
+ return -1;
}
/* Encapsulate two characters in a single int. */
goto exit;
}
- msg (VM (1), _("%s: Opening paper size definition file..."), pprsz_fn);
f = fopen (pprsz_fn, "r");
if (!f)
{
{
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));
if (free_it)
free (size);
- if (result)
- msg (VM (2), _("Paper size definition file read successfully."));
- else
+ if (!result)
msg (VM (1), _("Error reading paper size definition file."));
return result;
d = d->next;
if (d == NULL
- || (d->driver_open
- && (d->device == 0
- || (d->device & disabled_devices) != d->device)))
+ || (d->device == 0 || (d->device & disabled_devices) != d->device))
break;
}
disabled_devices |= device;
}
-/* Ejects the paper on device D, if the page is not blank. */
-int
-outp_eject_page (struct outp_driver *d)
+/* Opens a page on driver D (if one is not open). */
+void
+outp_open_page (struct outp_driver *d)
{
- if (d->page_open == 0)
- return 1;
-
- if (d->cp_y != 0)
+ if (!d->page_open)
{
d->cp_x = d->cp_y = 0;
- if (d->class->close_page (d) == 0)
- msg (ME, _("Error closing page on %s device of %s class."),
- d->name, d->class->name);
- if (d->class->open_page (d) == 0)
- {
- msg (ME, _("Error opening page on %s device of %s class."),
- d->name, d->class->name);
- return 0;
- }
+ d->page_open = true;
+ if (d->class->open_page != NULL)
+ d->class->open_page (d);
+ }
+}
+
+/* Closes the page on driver D (if one is open). */
+void
+outp_close_page (struct outp_driver *d)
+{
+ if (d->page_open)
+ {
+ if (d->class->close_page != NULL)
+ d->class->close_page (d);
+ d->page_open = false;
+ }
+}
+
+/* Ejects the paper on device D, if a page is open and is not
+ blank. */
+void
+outp_eject_page (struct outp_driver *d)
+{
+ if (d->page_open && d->cp_y != 0)
+ {
+ outp_close_page (d);
+ outp_open_page (d);
}
- return 1;
}
/* Returns the width of string S, in device units, when output on
device D. */
int
-outp_string_width (struct outp_driver *d, const char *s)
+outp_string_width (struct outp_driver *d, const char *s, enum outp_font font)
{
struct outp_text text;
+ int width;
+
+ text.font = font;
+ text.justification = OUTP_LEFT;
+ ls_init (&text.string, (char *) s, strlen (s));
+ text.h = text.v = INT_MAX;
+ d->class->text_metrics (d, &text, &width, NULL);
- text.options = OUTP_T_JUST_LEFT;
- ls_init (&text.s, (char *) s, strlen (s));
- d->class->text_metrics (d, &text);
-
- return text.h;
+ return width;
}