Changed a lot of ints to bools.
[pspp-builds.git] / src / output / output.c
index 0ea8ea49ad3230d091cbc0df06c4426a5e08db6c..a63f1171a446e0a42fb5c1f691a8adada0078f68 100644 (file)
 
 #include <config.h>
 #include "output.h"
-#include <libpspp/message.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
 #include <ctype.h>
 #include <libpspp/alloc.h>
-#include <libpspp/message.h>
-#include <data/filename.h>
+#include <data/file-name.h>
 #include "htmlP.h"
 #include "intprops.h"
 #include <libpspp/misc.h>
 #include <data/settings.h>
 #include <libpspp/str.h>
+#include "error.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -86,9 +85,9 @@ char *outp_subtitle;
 static int disabled_devices;
 
 static void destroy_driver (struct outp_driver *);
-static void configure_driver_line (struct string *);
-static void configure_driver (const struct string *, const struct string *,
-                              const struct string *, const struct string *);
+static void configure_driver_line (struct substring);
+static void configure_driver (const struct substring, const struct substring,
+                              const struct substring, const struct substring);
 
 /* Add a class to the class list. */
 static void
@@ -163,9 +162,10 @@ check_configure_vec (void)
 
   for (n = outp_configure_vec; n; n = n->next)
     if (n->source == OUTP_S_COMMAND_LINE)
-      msg (ME, _("Unknown output driver `%s'."), n->name);
+      error (0, 0, _("unknown output driver `%s'"), n->name);
     else
-      msg (IE, _("Output driver `%s' referenced but never defined."), n->name);
+      error (0, 0, _("output driver `%s' referenced but never defined"),
+             n->name);
   outp_configure_clear ();
 }
 
@@ -206,7 +206,7 @@ find_defn_value (const char *key)
 
   for (d = outp_macros; d; d = d->next)
     if (!strcmp (key, d->key))
-      return ds_c_str(&d->value);
+      return ds_cstr (&d->value);
   if (!strcmp (key, "viewwidth"))
     {
       sprintf (buf, "%d", get_viewwidth ());
@@ -256,15 +256,11 @@ delete_macros (void)
 static void
 init_default_drivers (void) 
 {
-  struct string s;
-
-  msg (MM, _("Using default output driver configuration."));
-
-  ds_create (&s,
-             "list:ascii:listing:"
-             "length=66 width=79 output-file=\"pspp.list\"");
-  configure_driver_line (&s);
-  ds_destroy (&s);
+  error (0, 0, _("using default output driver configuration"));
+  configure_driver (ss_cstr ("list"),
+                    ss_cstr ("ascii"),
+                    ss_cstr ("listing"),
+                    ss_cstr ("length=66 width=79 output-file=\"pspp.list\""));
 }
 
 /* Reads the initialization file; initializes
@@ -278,44 +274,42 @@ outp_read_devices (void)
 
   FILE *f = NULL;
   struct string line;
-  struct file_locator where;
+  int line_number;
 
   init_fn = fn_search_path (fn_getenv_default ("STAT_OUTPUT_INIT_FILE",
                                               "devices"),
                            fn_getenv_default ("STAT_OUTPUT_INIT_PATH",
                                               config_path),
                            NULL);
-  where.filename = init_fn;
-  where.line_number = 0;
-  err_push_file_locator (&where);
 
-  ds_init (&line, 128);
+  ds_init_empty (&line);
 
   if (init_fn == NULL)
     {
-      msg (IE, _("Cannot find output initialization file.  "
-                 "Use `-vvvvv' to view search path."));
+      error (0, 0, _("cannot find output initialization file "
+                     "(use `-vv' to view search path)"));
       goto exit;
     }
 
   f = fopen (init_fn, "r");
   if (f == NULL)
     {
-      msg (IE, _("Opening %s: %s."), init_fn, strerror (errno));
+      error (0, errno, _("cannot open \"%s\""), init_fn);
       goto exit;
     }
 
+  line_number = 0;
   for (;;)
     {
       char *cp;
 
-      if (!ds_get_config_line (f, &line, &where.line_number))
+      if (!ds_read_config_line (&line, &line_number, f))
        {
          if (ferror (f))
-           msg (ME, _("Reading %s: %s."), init_fn, strerror (errno));
+           error (0, errno, _("reading \"%s\""), init_fn);
          break;
        }
-      for (cp = ds_c_str (&line); isspace ((unsigned char) *cp); cp++);
+      for (cp = ds_cstr (&line); isspace ((unsigned char) *cp); cp++);
       if (!strncmp ("define", cp, 6) && isspace ((unsigned char) cp[6]))
        outp_configure_macro (&cp[7]);
       else if (*cp)
@@ -329,12 +323,12 @@ outp_read_devices (void)
              struct outp_names *n = search_names (cp, ep);
              if (n)
                {
-                 configure_driver_line (&line);
+                 configure_driver_line (ds_ss (&line));
                  delete_name (n);
                }
            }
          else
-           msg (IS, _("Syntax error."));
+           error_at_line (0, 0, init_fn, line_number, _("syntax error"));
        }
     }
   result = 1;
@@ -342,9 +336,8 @@ outp_read_devices (void)
   check_configure_vec ();
 
 exit:
-  err_pop_file_locator (&where);
   if (f && -1 == fclose (f))
-    msg (MW, _("Closing %s: %s."), init_fn, strerror (errno));
+    error (0, errno, _("error closing \"%s\""), init_fn);
   free (init_fn);
   ds_destroy (&line);
   delete_macros ();
@@ -352,10 +345,10 @@ exit:
   if (result) 
     {
       if (outp_driver_list == NULL) 
-        msg (MW, _("No output drivers are active.")); 
+        error (0, 0, _("no active output drivers")); 
     }
   else
-    msg (VM (1), _("Error reading device definition file."));
+    error (0, 0, _("error reading device definition file"));
 
   if (!result || outp_driver_list == NULL)
     init_default_drivers ();
@@ -418,8 +411,8 @@ outp_configure_macro (char *bp)
   while (isspace ((unsigned char) *ep))
     ep++;
 
-  ds_create(&d->value, ep);
-  fn_interp_vars(&d->value, find_defn_value);
+  ds_init_cstr (&d->value, ep);
+  fn_interp_vars (ds_ss (&d->value), find_defn_value, &d->value);
   d->next = outp_macros;
   d->prev = NULL;
   if (outp_macros)
@@ -488,177 +481,172 @@ outp_list_classes (void)
   putc('\n', stdout);
 }
 
-static int op_token;           /* `=', 'a', 0. */
-static struct string op_tokstr;
-static const char *prog;
+/* Obtains a token from S and advances its position.  Errors are
+   reported against the given DRIVER_NAME.
+   The token is stored in TOKEN.  Returns true if successful,
+   false on syntax error.
 
-/* Parses a token from prog into op_token, op_tokstr.  Sets op_token
-   to '=' on an equals sign, to 'a' on a string or identifier token,
-   or to 0 at end of line.  Returns the new op_token. */
-static int
-tokener (void)
+   Caller is responsible for skipping leading spaces. */
+static bool
+get_option_token (struct substring *s, const char *driver_name,
+                  struct string *token)
 {
-  if (op_token == 0)
+  int c;
+  
+  ds_clear (token);
+  c = ss_get_char (s);
+  if (c == EOF)
     {
-      msg (IS, _("Syntax error."));
-      return 0;
+      error (0, 0, _("syntax error parsing options for \"%s\" driver"),
+             driver_name);
+      return false;
     }
-
-  while (isspace ((unsigned char) *prog))
-    prog++;
-  if (!*prog)
+  else if (c == '\'' || c == '"')
     {
-      op_token = 0;
-      return 0;
-    }
+      int quote = c;
 
-  if (*prog == '=')
-    op_token = *prog++;
-  else
+      for (;;)
+        {
+          c = ss_get_char (s);
+          if (c == quote)
+            break;
+          else if (c == EOF) 
+            {
+              error (0, 0,
+                     _("reached end of options inside quoted string "
+                       "parsing options for \"%s\" driver"),
+                     driver_name);
+              return false;
+            }
+          else if (c != '\\')
+            ds_put_char (token, c);
+          else
+            {
+              int out;
+
+              c = ss_get_char (s);
+              switch (c)
+                {
+                case '\'':
+                  out = '\'';
+                  break;
+                case '"':
+                  out = '"';
+                  break;
+                case '\\':
+                  out = '\\';
+                  break;
+                case 'a':
+                  out = '\a';
+                  break;
+                case 'b':
+                  out = '\b';
+                  break;
+                case 'f':
+                  out = '\f';
+                  break;
+                case 'n':
+                  out = '\n';
+                  break;
+                case 'r':
+                  out = '\r';
+                  break;
+                case 't':
+                  out = '\t';
+                  break;
+                case 'v':
+                  out = '\v';
+                  break;
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                  out = c - '0';
+                  while (ss_first (*s) >= '0' && ss_first (*s) <= '7')
+                    out = c * 8 + (ss_get_char (s) - '0');
+                  break;
+                case 'x':
+                case 'X':
+                  out = 0;
+                  while (isxdigit (ss_first (*s)))
+                    {
+                      c = ss_get_char (s);
+                      out *= 16;
+                      if (isdigit (c))
+                        out += c - '0';
+                      else
+                        out += tolower (c) - 'a' + 10;
+                    }
+                  break;
+                default:
+                  error (0, 0, _("syntax error in string constant "
+                                 "parsing options for \"%s\" driver"),
+                         driver_name);
+                  return false;
+                }
+              ds_put_char (token, out);
+            }
+        }
+    }
+  else 
     {
-      ds_clear (&op_tokstr);
-
-      if (*prog == '\'' || *prog == '"')
-       {
-         int quote = *prog++;
+      for (;;)
+        {
+          ds_put_char (token, c);
 
-         while (*prog && *prog != quote)
-           {
-             if (*prog != '\\')
-               ds_putc (&op_tokstr, *prog++);
-             else
-               {
-                 int c;
-                 
-                 prog++;
-                 assert ((int) *prog); /* How could a line end in `\'? */
-                 switch (*prog++)
-                   {
-                   case '\'':
-                     c = '\'';
-                     break;
-                   case '"':
-                     c = '"';
-                     break;
-                   case '?':
-                     c = '?';
-                     break;
-                   case '\\':
-                     c = '\\';
-                     break;
-                   case '}':
-                     c = '}';
-                     break;
-                   case 'a':
-                     c = '\a';
-                     break;
-                   case 'b':
-                     c = '\b';
-                     break;
-                   case 'f':
-                     c = '\f';
-                     break;
-                   case 'n':
-                     c = '\n';
-                     break;
-                   case 'r':
-                     c = '\r';
-                     break;
-                   case 't':
-                     c = '\t';
-                     break;
-                   case 'v':
-                     c = '\v';
-                     break;
-                   case '0':
-                   case '1':
-                   case '2':
-                   case '3':
-                   case '4':
-                   case '5':
-                   case '6':
-                   case '7':
-                     {
-                       c = prog[-1] - '0';
-                       while (*prog >= '0' && *prog <= '7')
-                         c = c * 8 + *prog++ - '0';
-                     }
-                     break;
-                   case 'x':
-                   case 'X':
-                     {
-                       c = 0;
-                       while (isxdigit ((unsigned char) *prog))
-                         {
-                           c *= 16;
-                           if (isdigit ((unsigned char) *prog))
-                             c += *prog - '0';
-                           else
-                             c += (tolower ((unsigned char) (*prog))
-                                   - 'a' + 10);
-                           prog++;
-                         }
-                     }
-                     break;
-                   default:
-                     msg (IS, _("Syntax error in string constant."));
-                      continue;
-                   }
-                 ds_putc (&op_tokstr, (unsigned char) c);
-               }
-           }
-         prog++;
-       }
-      else
-       while (*prog && !isspace ((unsigned char) *prog) && *prog != '=')
-         ds_putc (&op_tokstr, *prog++);
-      op_token = 'a';
+          c = ss_first (*s);
+          if (c == EOF || c == '=' || isspace (c))
+            break;
+          ss_advance (s, 1);
+        }
     }
-
+  
   return 1;
 }
 
 bool
-outp_parse_options (const char *options,
+outp_parse_options (struct substring options,
                     bool (*callback) (struct outp_driver *, const char *key,
                                       const struct string *value),
                     struct outp_driver *driver)
 {
+  struct string key = DS_EMPTY_INITIALIZER;
+  struct string value = DS_EMPTY_INITIALIZER;
+  struct substring left = options;
   bool ok = true;
 
-  prog = options;
-  op_token = -1;
-
-  ds_init (&op_tokstr, 64);
-  while (ok && tokener ())
+  do
     {
-      char key[65];
-
-      if (op_token != 'a')
+      ss_ltrim (&left, ss_cstr (CC_SPACES));
+      if (ss_is_empty (left))
+        break;
+      
+      if (!get_option_token (&left, driver->name, &key))
+        break;
+
+      ss_ltrim (&left, ss_cstr (CC_SPACES));
+      if (!ss_match_char (&left, '='))
        {
-         msg (IS, _("Syntax error in options."));
+         error (0, 0, _("syntax error expecting `=' "
+                         "parsing options for driver \"%s\""),
+                 driver->name);
          break;
        }
 
-      ds_truncate (&op_tokstr, 64);
-      strcpy (key, ds_c_str (&op_tokstr));
-
-      tokener ();
-      if (op_token != '=')
-       {
-         msg (IS, _("Syntax error in options (`=' expected)."));
-         break;
-       }
+      ss_ltrim (&left, ss_cstr (CC_SPACES));
+      if (!get_option_token (&left, driver->name, &value))
+        break;
 
-      tokener ();
-      if (op_token != 'a')
-       {
-         msg (IS, _("Syntax error in options (value expected after `=')."));
-         break;
-       }
-      ok = callback (driver, key, &op_tokstr);
+      ok = callback (driver, ds_cstr (&key), &value);
     }
-  ds_destroy (&op_tokstr);
+  while (ok);
+  
+  ds_destroy (&key);
+  ds_destroy (&value);
 
   return ok;
 }
@@ -675,57 +663,48 @@ find_driver (char *name)
   return NULL;
 }
 
-/* String S is in format:
-   DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS
-   Adds a driver to outp_driver_list pursuant to the specification
-   provided.  */
+/* Adds a driver to outp_driver_list pursuant to the
+   specification provided.  */
 static void
-configure_driver (const struct string *driver_name,
-                  const struct string *class_name,
-                  const struct string *device_type,
-                  const struct string *options)
+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;
   int device;
 
   /* Find class. */
   for (c = outp_class_list; c; c = c->next)
-    if (!strcmp (c->class->name, ds_c_str (class_name)))
+    if (!ss_compare (ss_cstr (c->class->name), class_name))
       break;
   if (c == NULL)
     {
-      msg (IS, _("Unknown output driver class `%s'."), ds_c_str (class_name));
+      error (0, 0, _("unknown output driver class `%.*s'"),
+             (int) ss_length (class_name), ss_data (class_name));
       return;
     }
   
   /* Parse device type. */
   device = 0;
-  if (device_type != NULL)
-    {
-      struct string token = DS_INITIALIZER;
-      size_t save_idx = 0;
-
-      while (ds_tokenize (device_type, &token, " \t\r\v", &save_idx)) 
-        {
-          const char *type = ds_c_str (&token);
-         if (!strcmp (type, "listing"))
-           device |= OUTP_DEV_LISTING;
-         else if (!strcmp (type, "screen"))
-           device |= OUTP_DEV_SCREEN;
-         else if (!strcmp (type, "printer"))
-           device |= OUTP_DEV_PRINTER;
-         else
-            msg (IS, _("Unknown device type `%s'."), type);
-       }
-      ds_destroy (&token);
-    }
+  while (ss_tokenize (device_type, ss_cstr (CC_SPACES), &save_idx, &token))
+    if (!ss_compare (token, ss_cstr ("listing")))
+      device |= OUTP_DEV_LISTING;
+    else if (!ss_compare (token, ss_cstr ("screen")))
+      device |= OUTP_DEV_SCREEN;
+    else if (!ss_compare (token, ss_cstr ("printer")))
+      device |= OUTP_DEV_PRINTER;
+    else
+      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 = xstrdup (ds_c_str (driver_name));
+  d->name = ss_xstrdup (driver_name);
   d->page_open = false;
   d->device = OUTP_DEV_NONE;
   d->cp_x = d->cp_y = 0;
@@ -733,10 +712,10 @@ configure_driver (const struct string *driver_name,
   d->prc = NULL;
 
   /* Open driver. */
-  if (!d->class->open_driver (d, ds_c_str (options)))
+  if (!d->class->open_driver (d, options))
     {
-      msg (IS, _("Can't initialize output driver `%s' of class `%s'."),
-          d->name, d->class->name);
+      error (0, 0, _("cannot initialize output driver `%s' of class `%s'"),
+             d->name, d->class->name);
       free (d->name);
       free (d);
       return;
@@ -760,30 +739,30 @@ configure_driver (const struct string *driver_name,
    Adds a driver to outp_driver_list pursuant to the specification
    provided.  */
 static void
-configure_driver_line (struct string *line)
+configure_driver_line (struct substring line_)
 {
-  struct string tokens[4];
+  struct string line = DS_EMPTY_INITIALIZER;
+  struct substring tokens[4];
   size_t save_idx;
   size_t i;
 
-  fn_interp_vars (line, find_defn_value);
+  fn_interp_vars (line_, find_defn_value, &line);
 
   save_idx = 0;
   for (i = 0; i < 4; i++) 
     {
-      struct string *token = &tokens[i];
-      ds_init (token, 0);
-      ds_separate (line, token, i < 3 ? ":" : "", &save_idx);
-      ds_trim_spaces (token);
+      struct substring *token = &tokens[i];
+      ds_separate (&line, ss_cstr (i < 3 ? ":" : ""), &save_idx, token);
+      ss_trim (token, ss_cstr (CC_SPACES));
     }
 
-  if (!ds_is_empty (&tokens[0]) && !ds_is_empty (&tokens[1]))
-    configure_driver (&tokens[0], &tokens[1], &tokens[2], &tokens[3]);
+  if (!ss_is_empty (tokens[0]) && !ss_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"));
+    error (0, 0,
+           _("driver definition line missing driver name or class name"));
 
-  for (i = 0; i < 4; i++) 
-    ds_destroy (&tokens[i]);
+  ds_destroy (&line);
 }
 
 /* Destroys output driver D. */
@@ -926,7 +905,8 @@ outp_evaluate_dimension (char *dimen, char **tail)
            factor = 72000 / 72.27 / 65536.0;
            break;
          default:
-           msg (SE, _("Unit \"%s\" is unknown in dimension \"%s\"."), s, dimen);
+           error (0, 0,
+                   _("unit \"%s\" is unknown in dimension \"%s\""), s, dimen);
            *tail = NULL;
            return 0;
          }
@@ -941,15 +921,15 @@ outp_evaluate_dimension (char *dimen, char **tail)
 
 lossage:
   *tail = NULL;
-  msg (SE, _("Bad dimension \"%s\"."), dimen);
+  error (0, 0, _("bad dimension \"%s\""), dimen);
   return 0;
 }
 
 /* Stores the dimensions in 1/72000" units of paper identified by
    SIZE, which is of form `HORZ x VERT' or `HORZ by VERT' where each
-   of HORZ and VERT are dimensions, into *H and *V.  Return nonzero on
+   of HORZ and VERT are dimensions, into *H and *V.  Return true on
    success. */
-static int
+static bool
 internal_get_paper_size (char *size, int *h, int *v)
 {
   char *tail;
@@ -958,7 +938,7 @@ internal_get_paper_size (char *size, int *h, int *v)
     size++;
   *h = outp_evaluate_dimension (size, &tail);
   if (tail == NULL)
-    return 0;
+    return false;
   while (isspace ((unsigned char) *tail))
     tail++;
   if (*tail == 'x')
@@ -967,8 +947,8 @@ internal_get_paper_size (char *size, int *h, int *v)
     tail += 2;
   else
     {
-      msg (SE, _("`x' expected in paper size `%s'."), size);
-      return 0;
+      error (0, 0, _("`x' expected in paper size `%s'"), size);
+      return false;
     }
   *v = outp_evaluate_dimension (tail, &tail);
   if (tail == NULL)
@@ -977,20 +957,20 @@ internal_get_paper_size (char *size, int *h, int *v)
     tail++;
   if (*tail)
     {
-      msg (SE, _("Trailing garbage `%s' on paper size `%s'."), tail, size);
-      return 0;
+      error (0, 0, _("trailing garbage `%s' on paper size `%s'"), tail, size);
+      return false;
     }
   
-  return 1;
+  return true;
 }
 
 /* Stores the dimensions, in 1/72000" units, of paper identified by
    SIZE into *H and *V.  SIZE may be a pair of dimensions of form `H x
    V', or it may be a case-insensitive paper identifier, which is
-   looked up in the `papersize' configuration file.  Returns nonzero
+   looked up in the `papersize' configuration file.  Returns true
    on success.  May modify SIZE. */
 /* Don't read further unless you've got a strong stomach. */
-int
+bool
 outp_get_paper_size (char *size, int *h, int *v)
 {
   struct paper_size
@@ -1000,20 +980,15 @@ outp_get_paper_size (char *size, int *h, int *v)
       int h, v;
     };
 
-  static struct paper_size cache[4];
-  static int use;
-
   FILE *f;
   char *pprsz_fn;
 
   struct string line;
-  struct file_locator where;
+  int line_number = 0;
 
-  int free_it = 0;
-  int result = 0;
-  int min_value, min_index;
+  bool free_it = false;
+  bool result = false;
   char *ep;
-  int i;
 
   while (isspace ((unsigned char) *size))
     size++;
@@ -1026,7 +1001,7 @@ outp_get_paper_size (char *size, int *h, int *v)
     ep--;
   if (ep == size)
     {
-      msg (SE, _("Paper size name must not be empty."));
+      error (0, 0, _("paper size name cannot be empty"));
       return 0;
     }
   
@@ -1034,104 +1009,73 @@ outp_get_paper_size (char *size, int *h, int *v)
   if (*ep)
     *ep = 0;
 
-  use++;
-  for (i = 0; i < 4; i++)
-    if (cache[i].name != NULL && !strcasecmp (cache[i].name, size))
-      {
-       *h = cache[i].h;
-       *v = cache[i].v;
-       cache[i].use = use;
-       return 1;
-      }
-
   pprsz_fn = fn_search_path (fn_getenv_default ("STAT_OUTPUT_PAPERSIZE_FILE",
                                                "papersize"),
                             fn_getenv_default ("STAT_OUTPUT_INIT_PATH",
                                                config_path),
                             NULL);
 
-  where.filename = pprsz_fn;
-  where.line_number = 0;
-  err_push_file_locator (&where);
-  ds_init (&line, 128);
+  ds_init_empty (&line);
 
   if (pprsz_fn == NULL)
     {
-      msg (IE, _("Cannot find `papersize' configuration file."));
+      error (0, 0, _("cannot find `papersize' configuration file"));
       goto exit;
     }
 
   f = fopen (pprsz_fn, "r");
   if (!f)
     {
-      msg (IE, _("Opening %s: %s."), pprsz_fn, strerror (errno));
+      error (0, errno, _("error opening \"%s\""), pprsz_fn);
       goto exit;
     }
 
   for (;;)
     {
-      char *cp, *bp, *ep;
+      struct substring p, name;
 
-      if (!ds_get_config_line (f, &line, &where.line_number))
+      if (!ds_read_config_line (&line, &line_number, f))
        {
          if (ferror (f))
-           msg (ME, _("Reading %s: %s."), pprsz_fn, strerror (errno));
+           error (0, errno, _("error reading \"%s\""), pprsz_fn);
          break;
        }
-      for (cp = ds_c_str (&line); isspace ((unsigned char) *cp); cp++);
-      if (*cp == 0)
-       continue;
-      if (*cp != '"')
-       goto lex_error;
-      for (bp = ep = cp + 1; *ep && *ep != '"'; ep++);
-      if (!*ep)
+
+      p = ds_ss (&line);
+      ss_ltrim (&p, ss_cstr (CC_SPACES));
+      if (!ss_match_char (&p, '"') || !ss_get_until (&p, '"', &name))
        goto lex_error;
-      *ep = 0;
-      if (0 != strcasecmp (bp, size))
+      if (ss_compare (name, ss_cstr (size)))
        continue;
 
-      for (cp = ep + 1; isspace ((unsigned char) *cp); cp++);
-      if (*cp == '=')
+      ss_ltrim (&p, ss_cstr (CC_SPACES));
+      if (ss_match_char (&p, '='))
        {
-         size = xmalloc (ep - bp + 1);
-         strcpy (size, bp);
-         free_it = 1;
+          if (free_it)
+            free (size);
+          ss_trim (&p, ss_cstr (CC_SPACES));
+          size = ss_xstrdup (p);
+         free_it = true;
          continue;
        }
-      size = &ep[1];
+      size = ss_data (p);
       break;
 
     lex_error:
-      msg (IE, _("Syntax error in paper size definition."));
+      error_at_line (0, 0, pprsz_fn, line_number,
+                     _("syntax error in paper size definition"));
     }
 
   /* We found the one we want! */
   result = internal_get_paper_size (size, h, v);
-  if (result)
-    {
-      min_value = cache[0].use;
-      min_index = 0;
-      for (i = 1; i < 4; i++)
-       if (cache[0].use < min_value)
-         {
-           min_value = cache[i].use;
-           min_index = i;
-         }
-      free (cache[min_index].name);
-      cache[min_index].name = xstrdup (size);
-      cache[min_index].use = use;
-      cache[min_index].h = *h;
-      cache[min_index].v = *v;
-    }
 
 exit:
-  err_pop_file_locator (&where);
   ds_destroy (&line);
   if (free_it)
     free (size);
 
   if (!result)
-    msg (VM (1), _("Error reading paper size definition file."));
+    error (0, 0, _("error reading paper size definition file"));
   
   return result;
 }
@@ -1143,10 +1087,6 @@ exit:
 struct outp_driver *
 outp_drivers (struct outp_driver *d)
 {
-#if DEBUGGING
-  struct outp_driver *orig_d = d;
-#endif
-
   for (;;)
     {
       if (d == NULL)
@@ -1199,16 +1139,14 @@ outp_close_page (struct outp_driver *d)
     }
 }
 
-/* Ejects the paper on device D, if a page is open and is not
-   blank. */
+/* Ejects the page on device D, if a page is open and non-blank,
+   and opens a new page.  */
 void
 outp_eject_page (struct outp_driver *d)
 {
   if (d->page_open && d->cp_y != 0)
-    {
-      outp_close_page (d);
-      outp_open_page (d);
-    }
+    outp_close_page (d);
+  outp_open_page (d);
 }
 
 /* Returns the width of string S, in device units, when output on
@@ -1221,7 +1159,7 @@ outp_string_width (struct outp_driver *d, const char *s, enum outp_font font)
   
   text.font = font;
   text.justification = OUTP_LEFT;
-  ls_init (&text.string, (char *) s, strlen (s));
+  text.string = ss_cstr (s);
   text.h = text.v = INT_MAX;
   d->class->text_metrics (d, &text, &width, NULL);