output: Remove PostScript driver.
[pspp-builds.git] / src / output / output.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <ctype.h>
20 #include <errno.h>
21 #if HAVE_LC_PAPER
22 #include <langinfo.h>
23 #endif
24 #include <locale.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <data/file-name.h>
29 #include <data/settings.h>
30 #include <libpspp/misc.h>
31 #include <libpspp/str.h>
32 #include <output/htmlP.h>
33 #include <output/output.h>
34
35 #include "error.h"
36 #include "intprops.h"
37 #include "xalloc.h"
38
39 #include "gettext.h"
40 #define _(msgid) gettext (msgid)
41
42 /* Where the output driver name came from. */
43 enum
44   {
45     OUTP_S_COMMAND_LINE,        /* Specified by the user. */
46     OUTP_S_INIT_FILE            /* `default' or the init file. */
47   };
48
49 /* Names the output drivers to be used. */
50 struct outp_names
51   {
52     char *name;                 /* Name of the output driver. */
53     int source;                 /* OUTP_S_* */
54     struct outp_names *next, *prev;
55   };
56
57 /* Defines an init file macro. */
58 struct outp_defn
59   {
60     char *key;
61     struct string value;
62     struct outp_defn *next, *prev;
63   };
64
65 static struct outp_defn *outp_macros;
66 static struct outp_names *outp_configure_vec;
67
68 /* A list of driver classes. */
69 struct outp_driver_class_list
70   {
71     const struct outp_class *class;
72     struct outp_driver_class_list *next;
73   };
74
75 static struct outp_driver_class_list *outp_class_list;
76 static struct ll_list outp_driver_list = LL_INITIALIZER (outp_driver_list);
77
78 char *outp_title;
79 char *outp_subtitle;
80
81 /* A set of OUTP_DEV_* bits indicating the devices that are
82    disabled. */
83 static int disabled_devices;
84
85 static void destroy_driver (struct outp_driver *);
86 static void configure_driver (const struct substring, const struct substring,
87                               const struct substring, const struct substring);
88
89 /* Add a class to the class list. */
90 static void
91 add_class (const struct outp_class *class)
92 {
93   struct outp_driver_class_list *new_list = xmalloc (sizeof *new_list);
94
95   new_list->class = class;
96
97   if (!outp_class_list)
98     {
99       outp_class_list = new_list;
100       new_list->next = NULL;
101     }
102   else
103     {
104       new_list->next = outp_class_list;
105       outp_class_list = new_list;
106     }
107 }
108
109 /* Finds the outp_names in outp_configure_vec with name between BP and
110    EP exclusive. */
111 static struct outp_names *
112 search_names (char *bp, char *ep)
113 {
114   struct outp_names *n;
115
116   for (n = outp_configure_vec; n; n = n->next)
117     if ((int) strlen (n->name) == ep - bp && !memcmp (n->name, bp, ep - bp))
118       return n;
119   return NULL;
120 }
121
122 /* Deletes outp_names NAME from outp_configure_vec. */
123 static void
124 delete_name (struct outp_names * n)
125 {
126   free (n->name);
127   if (n->prev)
128     n->prev->next = n->next;
129   if (n->next)
130     n->next->prev = n->prev;
131   if (n == outp_configure_vec)
132     outp_configure_vec = n->next;
133   free (n);
134 }
135
136 /* Adds the name between BP and EP exclusive to list
137    outp_configure_vec with source SOURCE. */
138 static void
139 add_name (char *bp, char *ep, int source)
140 {
141   struct outp_names *n = xmalloc (sizeof *n);
142   n->name = xmalloc (ep - bp + 1);
143   memcpy (n->name, bp, ep - bp);
144   n->name[ep - bp] = 0;
145   n->source = source;
146   n->next = outp_configure_vec;
147   n->prev = NULL;
148   if (outp_configure_vec)
149     outp_configure_vec->prev = n;
150   outp_configure_vec = n;
151 }
152
153 /* Checks that outp_configure_vec is empty, complains and clears
154    it if it isn't. */
155 static void
156 check_configure_vec (void)
157 {
158   struct outp_names *n;
159
160   for (n = outp_configure_vec; n; n = n->next)
161     if (n->source == OUTP_S_COMMAND_LINE)
162       error (0, 0, _("unknown output driver `%s'"), n->name);
163     else
164       error (0, 0, _("output driver `%s' referenced but never defined"),
165              n->name);
166   outp_configure_clear ();
167 }
168
169 /* Searches outp_configure_vec for the name between BP and EP
170    exclusive.  If found, it is deleted, then replaced by the names
171    given in EP+1, if any. */
172 static void
173 expand_name (char *bp, char *ep)
174 {
175   struct outp_names *n = search_names (bp, ep);
176   if (!n)
177     return;
178   delete_name (n);
179
180   bp = ep + 1;
181   for (;;)
182     {
183       while (isspace ((unsigned char) *bp))
184         bp++;
185       ep = bp;
186       while (*ep && !isspace ((unsigned char) *ep))
187         ep++;
188       if (bp == ep)
189         return;
190       if (!search_names (bp, ep))
191         add_name (bp, ep, OUTP_S_INIT_FILE);
192       bp = ep;
193     }
194 }
195
196 /* Looks for a macro with key KEY, and returns the corresponding value
197    if found, or NULL if not. */
198 static const char *
199 find_defn_value (const char *key)
200 {
201   static char buf[INT_STRLEN_BOUND (int) + 1];
202   struct outp_defn *d;
203
204   for (d = outp_macros; d; d = d->next)
205     if (!strcmp (key, d->key))
206       return ds_cstr (&d->value);
207   if (!strcmp (key, "viewwidth"))
208     {
209       sprintf (buf, "%d", settings_get_viewwidth ());
210       return buf;
211     }
212   else if (!strcmp (key, "viewlength"))
213     {
214       sprintf (buf, "%d", settings_get_viewlength ());
215       return buf;
216     }
217   else
218     return getenv (key);
219 }
220
221 static void
222 insert_defn_value (const char *var, struct string *dst, void *aux UNUSED)
223 {
224   const char *value = find_defn_value (var);
225   if (value != NULL)
226     ds_put_cstr (dst, value);
227 }
228
229 /* Initializes global variables. */
230 void
231 outp_init (void)
232 {
233   char def[] = "default";
234
235   add_class (&html_class);
236   add_class (&ascii_class);
237 #ifdef HAVE_CAIRO
238   add_class (&cairo_class);
239 #endif
240   add_class (&odt_class);
241
242   add_name (def, &def[strlen (def)], OUTP_S_INIT_FILE);
243 }
244
245 /* Deletes all the output macros. */
246 static void
247 delete_macros (void)
248 {
249   struct outp_defn *d, *next;
250
251   for (d = outp_macros; d; d = next)
252     {
253       next = d->next;
254       free (d->key);
255       ds_destroy (&d->value);
256       free (d);
257     }
258 }
259
260 static void
261 init_default_drivers (void)
262 {
263   error (0, 0, _("using default output driver configuration"));
264   configure_driver (ss_cstr ("list"),
265                     ss_cstr ("ascii"),
266                     ss_cstr ("listing"),
267                     ss_cstr ("length=66 width=79 output-file=\"pspp.list\""));
268 }
269
270 /* Reads the initialization file; initializes
271    outp_driver_list. */
272 void
273 outp_read_devices (void)
274 {
275   int result = 0;
276
277   char *init_fn;
278
279   FILE *f = NULL;
280   struct string line;
281   int line_number;
282
283   init_fn = fn_search_path (fn_getenv_default ("STAT_OUTPUT_INIT_FILE",
284                                                "devices"),
285                             fn_getenv_default ("STAT_OUTPUT_INIT_PATH",
286                                                config_path));
287
288   ds_init_empty (&line);
289
290   if (init_fn == NULL)
291     {
292       error (0, 0, _("cannot find output initialization file "
293                      "(use `-vv' to view search path)"));
294       goto exit;
295     }
296
297   f = fopen (init_fn, "r");
298   if (f == NULL)
299     {
300       error (0, errno, _("cannot open \"%s\""), init_fn);
301       goto exit;
302     }
303
304   line_number = 0;
305   for (;;)
306     {
307       char *cp;
308
309       if (!ds_read_config_line (&line, &line_number, f))
310         {
311           if (ferror (f))
312             error (0, errno, _("reading \"%s\""), init_fn);
313           break;
314         }
315       for (cp = ds_cstr (&line); isspace ((unsigned char) *cp); cp++);
316       if (!strncmp ("define", cp, 6) && isspace ((unsigned char) cp[6]))
317         outp_configure_macro (&cp[7]);
318       else if (*cp)
319         {
320           char *ep;
321           for (ep = cp; *ep && *ep != ':' && *ep != '='; ep++);
322           if (*ep == '=')
323             expand_name (cp, ep);
324           else if (*ep == ':')
325             {
326               struct outp_names *n = search_names (cp, ep);
327               if (n)
328                 {
329                   outp_configure_driver_line (ds_ss (&line));
330                   delete_name (n);
331                 }
332             }
333           else
334             error_at_line (0, 0, init_fn, line_number, _("syntax error"));
335         }
336     }
337   result = 1;
338
339   check_configure_vec ();
340
341 exit:
342   if (f && -1 == fclose (f))
343     error (0, errno, _("error closing \"%s\""), init_fn);
344   free (init_fn);
345   ds_destroy (&line);
346   delete_macros ();
347
348   if (result)
349     {
350       if (ll_is_empty (&outp_driver_list))
351         error (0, 0, _("no active output drivers"));
352     }
353   else
354     error (0, 0, _("error reading device definition file"));
355
356   if (!result || ll_is_empty (&outp_driver_list))
357     init_default_drivers ();
358 }
359
360 /* Clear the list of drivers to configure. */
361 void
362 outp_configure_clear (void)
363 {
364   struct outp_names *n, *next;
365
366   for (n = outp_configure_vec; n; n = next)
367     {
368       next = n->next;
369       free (n->name);
370       free (n);
371     }
372   outp_configure_vec = NULL;
373 }
374
375 /* Adds the name BP to the list of drivers to configure into
376    outp_driver_list. */
377 void
378 outp_configure_add (char *bp)
379 {
380   char *ep = &bp[strlen (bp)];
381   if (!search_names (bp, ep))
382     add_name (bp, ep, OUTP_S_COMMAND_LINE);
383 }
384
385 /* Defines one configuration macro based on the text in BP, which
386    should be of the form `KEY=VALUE'. */
387 void
388 outp_configure_macro (char *bp)
389 {
390   struct outp_defn *d;
391   char *ep;
392
393   while (isspace ((unsigned char) *bp))
394     bp++;
395   ep = bp;
396   while (*ep && !isspace ((unsigned char) *ep) && *ep != '=')
397     ep++;
398
399   d = xmalloc (sizeof *d);
400   d->key = xmalloc (ep - bp + 1);
401   memcpy (d->key, bp, ep - bp);
402   d->key[ep - bp] = 0;
403
404   /* Earlier definitions for a particular KEY override later ones. */
405   if (find_defn_value (d->key))
406     {
407       free (d->key);
408       free (d);
409       return;
410     }
411
412   if (*ep == '=')
413     ep++;
414   while (isspace ((unsigned char) *ep))
415     ep++;
416
417   ds_init_cstr (&d->value, ep);
418   fn_interp_vars (ds_ss (&d->value), insert_defn_value, NULL, &d->value);
419   d->next = outp_macros;
420   d->prev = NULL;
421   if (outp_macros)
422     outp_macros->prev = d;
423   outp_macros = d;
424 }
425
426 /* Closes all the output drivers. */
427 void
428 outp_done (void)
429 {
430   struct outp_driver_class_list *n = outp_class_list ;
431   outp_configure_clear ();
432   while (!ll_is_empty (&outp_driver_list))
433     {
434       struct outp_driver *d = ll_data (ll_head (&outp_driver_list),
435                                        struct outp_driver, node);
436       destroy_driver (d);
437     }
438
439   while (n)
440     {
441       struct outp_driver_class_list *next = n->next;
442       free(n);
443       n = next;
444     }
445   outp_class_list = NULL;
446
447   free (outp_title);
448   outp_title = NULL;
449
450   free (outp_subtitle);
451   outp_subtitle = NULL;
452 }
453
454 /* Display on stdout a list of all registered driver classes. */
455 void
456 outp_list_classes (void)
457 {
458   int width = settings_get_viewwidth ();
459   struct outp_driver_class_list *c;
460
461   printf (_("Driver classes:\n\t"));
462   width -= 8;
463   for (c = outp_class_list; c; c = c->next)
464     {
465       if ((int) strlen (c->class->name) + 1 > width)
466         {
467           printf ("\n\t");
468           width = settings_get_viewwidth () - 8;
469         }
470       else
471         putc (' ', stdout);
472       fputs (c->class->name, stdout);
473     }
474   putc('\n', stdout);
475 }
476
477 /* Obtains a token from S and advances its position.  Errors are
478    reported against the given DRIVER_NAME.
479    The token is stored in TOKEN.  Returns true if successful,
480    false on syntax error.
481
482    Caller is responsible for skipping leading spaces. */
483 static bool
484 get_option_token (struct substring *s, const char *driver_name,
485                   struct string *token)
486 {
487   int c;
488
489   ds_clear (token);
490   c = ss_get_char (s);
491   if (c == EOF)
492     {
493       error (0, 0, _("syntax error parsing options for \"%s\" driver"),
494              driver_name);
495       return false;
496     }
497   else if (c == '\'' || c == '"')
498     {
499       int quote = c;
500
501       for (;;)
502         {
503           c = ss_get_char (s);
504           if (c == quote)
505             break;
506           else if (c == EOF)
507             {
508               error (0, 0,
509                      _("reached end of options inside quoted string "
510                        "parsing options for \"%s\" driver"),
511                      driver_name);
512               return false;
513             }
514           else if (c != '\\')
515             ds_put_char (token, c);
516           else
517             {
518               int out;
519
520               c = ss_get_char (s);
521               switch (c)
522                 {
523                 case '\'':
524                   out = '\'';
525                   break;
526                 case '"':
527                   out = '"';
528                   break;
529                 case '\\':
530                   out = '\\';
531                   break;
532                 case 'a':
533                   out = '\a';
534                   break;
535                 case 'b':
536                   out = '\b';
537                   break;
538                 case 'f':
539                   out = '\f';
540                   break;
541                 case 'n':
542                   out = '\n';
543                   break;
544                 case 'r':
545                   out = '\r';
546                   break;
547                 case 't':
548                   out = '\t';
549                   break;
550                 case 'v':
551                   out = '\v';
552                   break;
553                 case '0':
554                 case '1':
555                 case '2':
556                 case '3':
557                 case '4':
558                 case '5':
559                 case '6':
560                 case '7':
561                   out = c - '0';
562                   while (ss_first (*s) >= '0' && ss_first (*s) <= '7')
563                     out = out * 8 + (ss_get_char (s) - '0');
564                   break;
565                 case 'x':
566                 case 'X':
567                   out = 0;
568                   while (isxdigit (ss_first (*s)))
569                     {
570                       c = ss_get_char (s);
571                       out *= 16;
572                       if (isdigit (c))
573                         out += c - '0';
574                       else
575                         out += tolower (c) - 'a' + 10;
576                     }
577                   break;
578                 default:
579                   error (0, 0, _("syntax error in string constant "
580                                  "parsing options for \"%s\" driver"),
581                          driver_name);
582                   return false;
583                 }
584               ds_put_char (token, out);
585             }
586         }
587     }
588   else
589     {
590       for (;;)
591         {
592           ds_put_char (token, c);
593
594           c = ss_first (*s);
595           if (c == EOF || c == '=' || isspace (c))
596             break;
597           ss_advance (s, 1);
598         }
599     }
600
601   return 1;
602 }
603
604 bool
605 outp_parse_options (const char *driver_name, struct substring options,
606                     bool (*callback) (void *aux, const char *key,
607                                       const struct string *value), void *aux)
608 {
609   struct string key = DS_EMPTY_INITIALIZER;
610   struct string value = DS_EMPTY_INITIALIZER;
611   struct substring left = options;
612   bool ok = true;
613
614   do
615     {
616       ss_ltrim (&left, ss_cstr (CC_SPACES));
617       if (ss_is_empty (left))
618         break;
619
620       if (!get_option_token (&left, driver_name, &key))
621         break;
622
623       ss_ltrim (&left, ss_cstr (CC_SPACES));
624       if (!ss_match_char (&left, '='))
625         {
626           error (0, 0, _("syntax error expecting `=' "
627                          "parsing options for driver \"%s\""),
628                  driver_name);
629           break;
630         }
631
632       ss_ltrim (&left, ss_cstr (CC_SPACES));
633       if (!get_option_token (&left, driver_name, &value))
634         break;
635
636       ok = callback (aux, ds_cstr (&key), &value);
637     }
638   while (ok);
639
640   ds_destroy (&key);
641   ds_destroy (&value);
642
643   return ok;
644 }
645
646 /* Find the driver in outp_driver_list with name NAME. */
647 static struct outp_driver *
648 find_driver (char *name)
649 {
650   struct outp_driver *d;
651   ll_for_each (d, struct outp_driver, node, &outp_driver_list)
652     if (!strcmp (d->name, name))
653       return d;
654   return NULL;
655 }
656
657 /* Adds a driver to outp_driver_list pursuant to the
658    specification provided.  */
659 static void
660 configure_driver (struct substring driver_name, struct substring class_name,
661                   struct substring device_type, struct substring options)
662 {
663   struct outp_driver_class_list *c;
664   struct substring token;
665   size_t save_idx = 0;
666   char *name;
667   int device;
668
669   /* Find class. */
670   for (c = outp_class_list; c; c = c->next)
671     if (!ss_compare (ss_cstr (c->class->name), class_name))
672       break;
673   if (c == NULL)
674     {
675       error (0, 0, _("unknown output driver class `%.*s'"),
676              (int) ss_length (class_name), ss_data (class_name));
677       return;
678     }
679
680   /* Parse device type. */
681   device = 0;
682   while (ss_tokenize (device_type, ss_cstr (CC_SPACES), &save_idx, &token))
683     if (!ss_compare (token, ss_cstr ("listing")))
684       device |= OUTP_DEV_LISTING;
685     else if (!ss_compare (token, ss_cstr ("screen")))
686       device |= OUTP_DEV_SCREEN;
687     else if (!ss_compare (token, ss_cstr ("printer")))
688       device |= OUTP_DEV_PRINTER;
689     else
690       error (0, 0, _("unknown device type `%.*s'"),
691              (int) ss_length (token), ss_data (token));
692
693   /* Open driver. */
694   name = ss_xstrdup (driver_name);
695   if (!c->class->open_driver (name, device, options))
696     error (0, 0, _("cannot initialize output driver `%s' of class `%s'"),
697            name, c->class->name);
698   free (name);
699 }
700
701 /* Allocates and returns a new outp_driver for a device with the
702    given NAME and CLASS and the OUTP_DEV_* type(s) in TYPES
703
704    This function is intended to be used by output drivers, not
705    by their clients. */
706 struct outp_driver *
707 outp_allocate_driver (const struct outp_class *class,
708                       const char *name, int types)
709 {
710   struct outp_driver *d = xmalloc (sizeof *d);
711   d->class = class;
712   d->name = xstrdup (name);
713   d->page_open = false;
714   d->device = types;
715   d->cp_x = d->cp_y = 0;
716   d->ext = NULL;
717   return d;
718 }
719
720 /* Frees driver D and the data that it owns directly.  The
721    driver's class must already have unregistered D (if it was
722    registered) and freed data private to its class.
723
724    This function is intended to be used by output drivers, not
725    by their clients. */
726 void
727 outp_free_driver (struct outp_driver *d)
728 {
729   free (d->name);
730   free (d);
731 }
732
733 /* Adds D to the list of drivers that will be used for output. */
734 void
735 outp_register_driver (struct outp_driver *d)
736 {
737   struct outp_driver *victim;
738
739   /* Find like-named driver and delete. */
740   victim = find_driver (d->name);
741   if (victim != NULL)
742     destroy_driver (victim);
743
744   /* Add D to list. */
745   ll_push_tail (&outp_driver_list, &d->node);
746 }
747
748 /* Remove driver D from the list of drivers that will be used for
749    output. */
750 void
751 outp_unregister_driver (struct outp_driver *d)
752 {
753   ll_remove (&d->node);
754 }
755
756 /* String LINE is in format:
757    DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS
758    Adds a driver to outp_driver_list pursuant to the specification
759    provided.  */
760 void
761 outp_configure_driver_line (struct substring line_)
762 {
763   struct string line = DS_EMPTY_INITIALIZER;
764   struct substring tokens[4];
765   size_t save_idx;
766   size_t i;
767
768   fn_interp_vars (line_, insert_defn_value, NULL, &line);
769
770   save_idx = 0;
771   for (i = 0; i < 4; i++)
772     {
773       struct substring *token = &tokens[i];
774       ds_separate (&line, ss_cstr (i < 3 ? ":" : ""), &save_idx, token);
775       ss_trim (token, ss_cstr (CC_SPACES));
776     }
777
778   if (!ss_is_empty (tokens[0]) && !ss_is_empty (tokens[1]))
779     configure_driver (tokens[0], tokens[1], tokens[2], tokens[3]);
780   else
781     error (0, 0,
782            _("driver definition line missing driver name or class name"));
783
784   ds_destroy (&line);
785 }
786
787 /* Destroys output driver D. */
788 static void
789 destroy_driver (struct outp_driver *d)
790 {
791   outp_close_page (d);
792   if (d->class && d->class->close_driver)
793     d->class->close_driver (d);
794   outp_unregister_driver (d);
795   outp_free_driver (d);
796 }
797
798 /* Tries to match S as one of the keywords in TAB, with
799    corresponding information structure INFO.  Returns category
800    code and stores subcategory in *SUBCAT on success.  Returns -1
801    on failure. */
802 int
803 outp_match_keyword (const char *s, const struct outp_option *tab, int *subcat)
804 {
805   for (; tab->keyword != NULL; tab++)
806     if (!strcmp (s, tab->keyword))
807       {
808         *subcat = tab->subcat;
809         return tab->cat;
810       }
811   return -1;
812 }
813
814 /* Parses UNIT as a dimensional unit.  Returns the multiplicative
815    factor needed to change a quantity measured in that unit into
816    1/72000" units.  If UNIT is empty, it is treated as
817    millimeters.  If the unit is unrecognized, returns 0. */
818 static double
819 parse_unit (const char *unit)
820 {
821   struct unit
822     {
823       char name[3];
824       double factor;
825     };
826
827   static const struct unit units[] =
828     {
829       {"pt", 72000 / 72},
830       {"pc", 72000 / 72 * 12.0},
831       {"in", 72000},
832       {"cm", 72000 / 2.54},
833       {"mm", 72000 / 25.4},
834       {"", 72000 / 25.4},
835     };
836
837   const struct unit *p;
838
839   unit += strspn (unit, CC_SPACES);
840   for (p = units; p < units + sizeof units / sizeof *units; p++)
841     if (!strcasecmp (unit, p->name))
842       return p->factor;
843   return 0.0;
844 }
845
846 /* Determines the size of a dimensional measurement and returns
847    the size in units of 1/72000".  Units are assumed to be
848    millimeters unless otherwise specified.  Returns 0 on
849    error. */
850 int
851 outp_evaluate_dimension (const char *dimen)
852 {
853   double raw, factor;
854   char *tail;
855
856   /* Number. */
857   raw = strtod (dimen, &tail);
858   if (raw <= 0.0)
859     goto syntax_error;
860
861   /* Unit. */
862   factor = parse_unit (tail);
863   if (factor == 0.0)
864     goto syntax_error;
865
866   return raw * factor;
867
868 syntax_error:
869   error (0, 0, _("`%s' is not a valid length."), dimen);
870   return 0;
871 }
872
873 /* Stores the dimensions in 1/72000" units of paper identified by
874    SIZE, which is of form `HORZ x VERT [UNIT]' where HORZ and
875    VERT are numbers and UNIT is an optional unit of measurement,
876    into *H and *V.  Return true on success. */
877 static bool
878 parse_paper_size (const char *size, int *h, int *v)
879 {
880   double raw_h, raw_v, factor;
881   char *tail;
882
883   /* Width. */
884   raw_h = strtod (size, &tail);
885   if (raw_h <= 0.0)
886     return false;
887
888   /* Delimiter. */
889   tail += strspn (tail, CC_SPACES "x,");
890
891   /* Length. */
892   raw_v = strtod (tail, &tail);
893   if (raw_v <= 0.0)
894     return false;
895
896   /* Unit. */
897   factor = parse_unit (tail);
898   if (factor == 0.0)
899     return false;
900
901   *h = raw_h * factor + .5;
902   *v = raw_v * factor + .5;
903   return true;
904 }
905
906 static bool
907 get_standard_paper_size (struct substring name, int *h, int *v)
908 {
909   static const char *sizes[][2] =
910     {
911       {"a0", "841 x 1189 mm"},
912       {"a1", "594 x 841 mm"},
913       {"a2", "420 x 594 mm"},
914       {"a3", "297 x 420 mm"},
915       {"a4", "210 x 297 mm"},
916       {"a5", "148 x 210 mm"},
917       {"b5", "176 x 250 mm"},
918       {"a6", "105 x 148 mm"},
919       {"a7", "74 x 105 mm"},
920       {"a8", "52 x 74 mm"},
921       {"a9", "37 x 52 mm"},
922       {"a10", "26 x 37 mm"},
923       {"b0", "1000 x 1414 mm"},
924       {"b1", "707 x 1000 mm"},
925       {"b2", "500 x 707 mm"},
926       {"b3", "353 x 500 mm"},
927       {"b4", "250 x 353 mm"},
928       {"letter", "612 x 792 pt"},
929       {"legal", "612 x 1008 pt"},
930       {"executive", "522 x 756 pt"},
931       {"note", "612 x 792 pt"},
932       {"11x17", "792 x 1224 pt"},
933       {"tabloid", "792 x 1224 pt"},
934       {"statement", "396 x 612 pt"},
935       {"halfletter", "396 x 612 pt"},
936       {"halfexecutive", "378 x 522 pt"},
937       {"folio", "612 x 936 pt"},
938       {"quarto", "610 x 780 pt"},
939       {"ledger", "1224 x 792 pt"},
940       {"archA", "648 x 864 pt"},
941       {"archB", "864 x 1296 pt"},
942       {"archC", "1296 x 1728 pt"},
943       {"archD", "1728 x 2592 pt"},
944       {"archE", "2592 x 3456 pt"},
945       {"flsa", "612 x 936 pt"},
946       {"flse", "612 x 936 pt"},
947       {"csheet", "1224 x 1584 pt"},
948       {"dsheet", "1584 x 2448 pt"},
949       {"esheet", "2448 x 3168 pt"},
950     };
951
952   size_t i;
953
954   for (i = 0; i < sizeof sizes / sizeof *sizes; i++)
955     if (ss_equals_case (ss_cstr (sizes[i][0]), name))
956       {
957         bool ok = parse_paper_size (sizes[i][1], h, v);
958         assert (ok);
959         return ok;
960       }
961   error (0, 0, _("unknown paper type `%.*s'"),
962          (int) ss_length (name), ss_data (name));
963   return false;
964 }
965
966 /* Reads file FILE_NAME to find a paper size.  Stores the
967    dimensions, in 1/72000" units, into *H and *V.  Returns true
968    on success, false on failure. */
969 static bool
970 read_paper_conf (const char *file_name, int *h, int *v)
971 {
972   struct string line = DS_EMPTY_INITIALIZER;
973   int line_number = 0;
974   FILE *file;
975
976   file = fopen (file_name, "r");
977   if (file == NULL)
978     {
979       error (0, errno, _("error opening \"%s\""), file_name);
980       return false;
981     }
982
983   for (;;)
984     {
985       struct substring name;
986
987       if (!ds_read_config_line (&line, &line_number, file))
988         {
989           if (ferror (file))
990             error (0, errno, _("error reading \"%s\""), file_name);
991           break;
992         }
993
994       name = ds_ss (&line);
995       ss_trim (&name, ss_cstr (CC_SPACES));
996       if (!ss_is_empty (name))
997         {
998           bool ok = get_standard_paper_size (name, h, v);
999           fclose (file);
1000           ds_destroy (&line);
1001           return ok;
1002         }
1003     }
1004
1005   fclose (file);
1006   ds_destroy (&line);
1007   error (0, 0, _("paper size file \"%s\" does not state a paper size"),
1008          file_name);
1009   return false;
1010 }
1011
1012 /* The user didn't specify a paper size, so let's choose a
1013    default based on his environment.  Stores the
1014    dimensions, in 1/72000" units, into *H and *V.  Returns true
1015    on success, false on failure. */
1016 static bool
1017 get_default_paper_size (int *h, int *v)
1018 {
1019   /* libpaper in Debian (and other distributions?) allows the
1020      paper size to be specified in $PAPERSIZE or in a file
1021      specified in $PAPERCONF. */
1022   if (getenv ("PAPERSIZE") != NULL)
1023     return get_standard_paper_size (ss_cstr (getenv ("PAPERSIZE")), h, v);
1024   if (getenv ("PAPERCONF") != NULL)
1025     return read_paper_conf (getenv ("PAPERCONF"), h, v);
1026
1027 #if HAVE_LC_PAPER
1028   /* LC_PAPER is a non-standard glibc extension. */
1029   *h = (int) nl_langinfo(_NL_PAPER_WIDTH) * (72000 / 25.4);
1030   *v = (int) nl_langinfo(_NL_PAPER_HEIGHT) * (72000 / 25.4);
1031   if (*h > 0 && *v > 0)
1032      return true;
1033 #endif
1034
1035   /* libpaper defaults to /etc/papersize. */
1036   if (fn_exists ("/etc/papersize"))
1037     return read_paper_conf ("/etc/papersize", h, v);
1038
1039   /* Can't find a default. */
1040   return false;
1041 }
1042
1043 /* Stores the dimensions, in 1/72000" units, of paper identified
1044    by SIZE into *H and *V.  SIZE can be the name of a kind of
1045    paper ("a4", "letter", ...) or a pair of dimensions
1046    ("210x297", "8.5x11in", ...).  Returns true on success, false
1047    on failure.  On failure, *H and *V are set for A4 paper. */
1048 bool
1049 outp_get_paper_size (const char *size, int *h, int *v)
1050 {
1051   struct substring s;
1052   bool ok;
1053
1054   s = ss_cstr (size);
1055   ss_trim (&s, ss_cstr (CC_SPACES));
1056
1057   if (ss_is_empty (s))
1058     {
1059       /* Treat empty string as default paper size. */
1060       ok = get_default_paper_size (h, v);
1061     }
1062   else if (isdigit (ss_first (s)))
1063     {
1064       /* Treat string that starts with digit as explicit size. */
1065       ok = parse_paper_size (size, h, v);
1066       if (!ok)
1067         error (0, 0, _("syntax error in paper size `%s'"), size);
1068     }
1069   else
1070     {
1071       /* Check against standard paper sizes. */
1072       ok = get_standard_paper_size (s, h, v);
1073     }
1074
1075   /* Default to A4 on error. */
1076   if (!ok)
1077     {
1078       *h = 210 * (72000 / 25.4);
1079       *v = 297 * (72000 / 25.4);
1080     }
1081   return ok;
1082 }
1083
1084 /* If D is NULL, returns the first enabled driver if any, NULL if
1085    none.  Otherwise D must be the last driver returned by this
1086    function, in which case the next enabled driver is returned or NULL
1087    if that was the last. */
1088 struct outp_driver *
1089 outp_drivers (struct outp_driver *d)
1090 {
1091   do
1092     {
1093       struct ll *next;
1094
1095       next = d == NULL ? ll_head (&outp_driver_list) : ll_next (&d->node);
1096       if (next == ll_null (&outp_driver_list))
1097         return NULL;
1098
1099       d = ll_data (next, struct outp_driver, node);
1100     }
1101   while (d->device != 0 && (d->device & disabled_devices) == d->device);
1102
1103   return d;
1104 }
1105
1106 /* Enables (if ENABLE is true) or disables (if ENABLE is false) the
1107    device(s) given in mask DEVICE. */
1108 void
1109 outp_enable_device (bool enable, int device)
1110 {
1111   if (enable)
1112     disabled_devices &= ~device;
1113   else
1114     disabled_devices |= device;
1115 }
1116
1117 /* Opens a page on driver D (if one is not open). */
1118 void
1119 outp_open_page (struct outp_driver *d)
1120 {
1121   if (!d->page_open)
1122     {
1123       d->cp_x = d->cp_y = 0;
1124
1125       d->page_open = true;
1126       if (d->class->open_page != NULL)
1127         d->class->open_page (d);
1128     }
1129 }
1130
1131 /* Closes the page on driver D (if one is open). */
1132 void
1133 outp_close_page (struct outp_driver *d)
1134 {
1135   if (d->page_open)
1136     {
1137       if (d->class->close_page != NULL)
1138         d->class->close_page (d);
1139       d->page_open = false;
1140     }
1141 }
1142
1143 /* Ejects the page on device D, if a page is open and non-blank,
1144    and opens a new page.  */
1145 void
1146 outp_eject_page (struct outp_driver *d)
1147 {
1148   if (d->page_open && d->cp_y != 0)
1149     outp_close_page (d);
1150   outp_open_page (d);
1151 }
1152
1153 /* Flushes output to screen devices, so that the user can see
1154    output that doesn't fill up an entire page. */
1155 void
1156 outp_flush (struct outp_driver *d)
1157 {
1158   if (d->device & OUTP_DEV_SCREEN && d->class->flush != NULL)
1159     {
1160       outp_close_page (d);
1161       d->class->flush (d);
1162     }
1163 }
1164
1165 /* Returns the width of string S, in device units, when output on
1166    device D. */
1167 int
1168 outp_string_width (struct outp_driver *d, const char *s, enum outp_font font)
1169 {
1170   struct outp_text text;
1171   int width;
1172
1173   text.font = font;
1174   text.justification = OUTP_LEFT;
1175   text.string = ss_cstr (s);
1176   text.h = text.v = INT_MAX;
1177   d->class->text_metrics (d, &text, &width, NULL);
1178
1179   return width;
1180 }