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