Added coefficient-handling routines
[pspp-builds.git] / src / output.c
index 86e8534cedad1efcc659f7cc81346406a707887d..c0b849a4b3d8a717496b91f2ab38ac8fde549b7c 100644 (file)
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
 
 #include <config.h>
-#include <assert.h>
+#include "output.h"
+#include "error.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
 #include <ctype.h>
 #include "alloc.h"
-#include "approx.h"
 #include "error.h"
 #include "filename.h"
+#include "htmlP.h"
 #include "lexer.h"
 #include "misc.h"
-#include "output.h"
 #include "settings.h"
 #include "str.h"
 
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
 /* FIXME? Should the output configuration format be changed to
    drivername:classname:devicetype:options, where devicetype is zero
    or more of screen, printer, listing? */
@@ -73,10 +76,12 @@ char *outp_subtitle;
 
 /* A set of OUTP_DEV_* bits indicating the devices that are
    disabled. */
-int disabled_devices;
+static int disabled_devices;
 
 static void destroy_driver (struct outp_driver *);
-static void configure_driver (char *);
+static void configure_driver_line (char *);
+static void configure_driver (const char *, const char *,
+                              const char *, const char *);
 
 #if GLOBAL_DEBUGGING
 /* This mechanism attempts to catch reentrant use of outp_driver_list. */
@@ -194,7 +199,7 @@ expand_name (char *bp, char *ep)
 
 /* Looks for a macro with key KEY, and returns the corresponding value
    if found, or NULL if not. */
-const char *
+static const char *
 find_defn_value (const char *key)
 {
   static char buf[INT_DIGITS + 1];
@@ -205,12 +210,12 @@ find_defn_value (const char *key)
       return d->value;
   if (!strcmp (key, "viewwidth"))
     {
-      sprintf (buf, "%d", set_viewwidth);
+      sprintf (buf, "%d", get_viewwidth ());
       return buf;
     }
   else if (!strcmp (key, "viewlength"))
     {
-      sprintf (buf, "%d", set_viewlength);
+      sprintf (buf, "%d", get_viewlength ());
       return buf;
     }
   else
@@ -218,7 +223,7 @@ find_defn_value (const char *key)
 }
 
 /* Initializes global variables. */
-int
+void
 outp_init (void)
 {
   extern struct outp_class ascii_class;
@@ -242,8 +247,6 @@ outp_init (void)
   add_class (&ascii_class);
 
   add_name (def, &def[strlen (def)], OUTP_S_INIT_FILE);
-
-  return 1;
 }
 
 /* Deletes all the output macros. */
@@ -261,8 +264,19 @@ delete_macros (void)
     }
 }
 
-/* Reads the initialization file; initializes outp_driver_list. */
-int
+static void
+init_default_drivers (void) 
+{
+  msg (MM, _("Using default output driver configuration."));
+  configure_driver ("list-ascii", "ascii", "listing",
+                    "length=66 width=79 char-set=ascii "
+                    "output-file=\"pspp.list\" "
+                    "bold-on=\"\" italic-on=\"\" bold-italic-on=\"\"");
+}
+
+/* Reads the initialization file; initializes
+   outp_driver_list. */
+void
 outp_read_devices (void)
 {
   int result = 0;
@@ -287,12 +301,12 @@ outp_read_devices (void)
   where.line_number = 0;
   err_push_file_locator (&where);
 
-  ds_init (NULL, &line, 128);
+  ds_init (&line, 128);
 
   if (init_fn == NULL)
     {
-      msg (IE, _("Cannot find output initialization file.  Use `-vv' to view "
-          "search path."));
+      msg (IE, _("Cannot find output initialization file.  "
+                 "Use `-vvvvv' to view search path."));
       goto exit;
     }
 
@@ -314,7 +328,7 @@ outp_read_devices (void)
            msg (ME, _("Reading %s: %s."), init_fn, strerror (errno));
          break;
        }
-      for (cp = ds_value (&line); isspace ((unsigned char) *cp); cp++);
+      for (cp = ds_c_str (&line); isspace ((unsigned char) *cp); cp++);
       if (!strncmp ("define", cp, 6) && isspace ((unsigned char) cp[6]))
        outp_configure_macro (&cp[7]);
       else if (*cp)
@@ -328,7 +342,7 @@ outp_read_devices (void)
              struct outp_names *n = search_names (cp, ep);
              if (n)
                {
-                 configure_driver (cp);
+                 configure_driver_line (cp);
                  delete_name (n);
                }
            }
@@ -347,14 +361,18 @@ exit:
   free (init_fn);
   ds_destroy (&line);
   delete_macros ();
-  if (outp_driver_list == NULL)
-    msg (MW, _("No output drivers are active."));
 
-  if (result)
-    msg (VM (2), _("Device definition file read successfully."));
+  if (result) 
+    {
+      msg (VM (2), _("Device definition file read successfully."));
+      if (outp_driver_list == NULL) 
+        msg (MW, _("No output drivers are active.")); 
+    }
   else
     msg (VM (1), _("Error reading device definition file."));
-  return result;
+
+  if (!result || outp_driver_list == NULL)
+    init_default_drivers ();
 }
 
 /* Clear the list of drivers to configure. */
@@ -423,7 +441,7 @@ outp_configure_macro (char *bp)
 
 /* Destroys all the drivers in driver list *DL and sets *DL to
    NULL. */
-void
+static void
 destroy_list (struct outp_driver ** dl)
 {
   struct outp_driver *d, *next;
@@ -438,23 +456,36 @@ destroy_list (struct outp_driver ** dl)
 }
 
 /* Closes all the output drivers. */
-int
+void
 outp_done (void)
 {
+  struct outp_driver_class_list *n = outp_class_list ; 
 #if GLOBAL_DEBUGGING
   if (iterating_driver_list)
     reentrancy ();
 #endif
   destroy_list (&outp_driver_list);
 
-  return 1;
+  while (n) 
+    {
+      struct outp_driver_class_list *next = n->next;
+      free(n);
+      n = next;
+    }
+  outp_class_list = NULL;
+
+  free (outp_title);
+  outp_title = NULL;
+  
+  free (outp_subtitle);
+  outp_subtitle = NULL;
 }
 
 /* Display on stdout a list of all registered driver classes. */
 void
 outp_list_classes (void)
 {
-  int width = set_viewwidth;
+  int width = get_viewwidth();
   struct outp_driver_class_list *c;
 
   printf (_("Driver classes:\n\t"));
@@ -464,7 +495,7 @@ outp_list_classes (void)
       if ((int) strlen (c->class->name) + 1 > width)
        {
          printf ("\n\t");
-         width = set_viewwidth - 8;
+         width = get_viewwidth() - 8;
        }
       else
        putc (' ', stdout);
@@ -475,7 +506,7 @@ outp_list_classes (void)
 
 static int op_token;           /* `=', 'a', 0. */
 static struct string op_tokstr;
-static char *prog;
+static const char *prog;
 
 /* 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,
@@ -510,7 +541,7 @@ tokener (void)
          while (*prog && *prog != quote)
            {
              if (*prog != '\\')
-               ds_putchar (&op_tokstr, *prog++);
+               ds_putc (&op_tokstr, *prog++);
              else
                {
                  int c;
@@ -587,15 +618,16 @@ tokener (void)
                      break;
                    default:
                      msg (IS, _("Syntax error in string constant."));
+                      continue;
                    }
-                 ds_putchar (&op_tokstr, (unsigned char) c);
+                 ds_putc (&op_tokstr, (unsigned char) c);
                }
            }
          prog++;
        }
       else
        while (*prog && !isspace ((unsigned char) *prog) && *prog != '=')
-         ds_putchar (&op_tokstr, *prog++);
+         ds_putc (&op_tokstr, *prog++);
       op_token = 'a';
     }
 
@@ -605,12 +637,12 @@ tokener (void)
 /* Applies the user-specified options in string S to output driver D
    (at configuration time). */
 static void
-parse_options (char *s, struct outp_driver * d)
+parse_options (const char *s, struct outp_driver * d)
 {
   prog = s;
   op_token = -1;
 
-  ds_init (NULL, &op_tokstr, 64);
+  ds_init (&op_tokstr, 64);
   while (tokener ())
     {
       char key[65];
@@ -622,7 +654,7 @@ parse_options (char *s, struct outp_driver * d)
        }
 
       ds_truncate (&op_tokstr, 64);
-      strcpy (key, ds_value (&op_tokstr));
+      strcpy (key, ds_c_str (&op_tokstr));
 
       tokener ();
       if (op_token != '=')
@@ -666,7 +698,7 @@ find_driver (char *name)
    after all fields have been used up.
 
    FIXME: Should ignore colons inside double quotes. */
-static char *
+static const char *
 colon_tokenize (char *s, char **cp)
 {
   char *token;
@@ -694,49 +726,27 @@ colon_tokenize (char *s, char **cp)
    Adds a driver to outp_driver_list pursuant to the specification
    provided.  */
 static void
-configure_driver (char *s)
+configure_driver (const char *driver_name, const char *class_name,
+                  const char *device_type, const char *options)
 {
-  char *token, *cp;
   struct outp_driver *d = NULL, *iter;
   struct outp_driver_class_list *c = NULL;
 
-  s = fn_interp_vars (s, find_defn_value);
-
-  /* Driver name. */
-  token = colon_tokenize (s, &cp);
-  if (!token)
-    {
-      msg (IS, _("Driver name expected."));
-      goto error;
-    }
-
   d = xmalloc (sizeof *d);
-
   d->class = NULL;
-  d->name = xstrdup (token);
+  d->name = xstrdup (driver_name);
   d->driver_open = 0;
   d->page_open = 0;
-
   d->next = d->prev = NULL;
-
   d->device = OUTP_DEV_NONE;
-  
   d->ext = NULL;
 
-  /* Class name. */
-  token = colon_tokenize (NULL, &cp);
-  if (!token)
-    {
-      msg (IS, _("Class name expected."));
-      goto error;
-    }
-
   for (c = outp_class_list; c; c = c->next)
-    if (!strcmp (c->class->name, token))
+    if (!strcmp (c->class->name, class_name))
       break;
   if (!c)
     {
-      msg (IS, _("Unknown output driver class `%s'."), token);
+      msg (IS, _("Unknown output driver class `%s'."), class_name);
       goto error;
     }
   
@@ -756,12 +766,12 @@ configure_driver (char *s)
     }
 
   /* Device types. */
-  token = colon_tokenize (NULL, &cp);
-  if (token)
+  if (device_type != NULL)
     {
+      char *copy = xstrdup (device_type);
       char *sp, *type;
 
-      for (type = strtok_r (token, " \t\r\v", &sp); type;
+      for (type = strtok_r (copy, " \t\r\v", &sp); type;
           type = strtok_r (NULL, " \t\r\v", &sp))
        {
          if (!strcmp (type, "listing"))
@@ -773,15 +783,16 @@ configure_driver (char *s)
          else
            {
              msg (IS, _("Unknown device type `%s'."), type);
+              free (copy);
              goto error;
            }
        }
+      free (copy);
     }
   
   /* Options. */
-  token = colon_tokenize (NULL, &cp);
-  if (token)
-    parse_options (token, d);
+  if (options != NULL)
+    parse_options (options, d);
   if (!d->class->postopen_driver (d))
     {
       msg (IS, _("Can't complete initialization of output driver `%s' of "
@@ -800,13 +811,39 @@ configure_driver (char *s)
   if (outp_driver_list)
     outp_driver_list->prev = d;
   outp_driver_list = d;
-  goto exit;
+  return;
 
 error:
   if (d)
     destroy_driver (d);
-exit:
-  free (s);
+  return;
+}
+
+/* String S is in format:
+   DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS
+   Adds a driver to outp_driver_list pursuant to the specification
+   provided.  */
+static void
+configure_driver_line (char *s)
+{
+  char *cp;
+  const char *driver_name, *class_name, *device_type, *options;
+
+  s = fn_interp_vars (s, find_defn_value);
+
+  /* Driver name. */
+  driver_name = colon_tokenize (s, &cp);
+  class_name = colon_tokenize (NULL, &cp);
+  device_type = colon_tokenize (NULL, &cp);
+  options = colon_tokenize (NULL, &cp);
+  if (driver_name == NULL || class_name == NULL)
+    {
+      msg (IS, _("Driver definition line contains fewer fields "
+                 "than expected"));
+      return;
+    }
+
+  configure_driver (driver_name, class_name, device_type, options);
 }
 
 /* Destroys output driver D. */
@@ -891,7 +928,7 @@ outp_match_keyword (const char *s, struct outp_option *tab,
       *++cp = 0;
 
       info->initial = xstrdup (s);
-      info->options = xmalloc (sizeof *info->options * (cp - s));
+      info->options = xnmalloc (cp - s, sizeof *info->options);
       memcpy (info->options, ptr, sizeof *info->options * (cp - s));
     }
 
@@ -957,7 +994,7 @@ outp_evaluate_dimension (char *dimen, char **tail)
       if (c <= 0.0 || ptail == s)
        goto lossage;
       s = ptail;
-      if (approx_eq (c, 0.0))
+      if (c == 0.0)
        goto lossage;
       if (value > 0)
        value += b / c;
@@ -969,7 +1006,7 @@ outp_evaluate_dimension (char *dimen, char **tail)
       double b;
       s = &ptail[1];
       b = strtod (s, &ptail);
-      if (approx_le (b, 0.0) || ptail == s)
+      if (b <= 0.0 || ptail == s)
        goto lossage;
       s = ptail;
       value /= b;
@@ -1028,7 +1065,7 @@ outp_evaluate_dimension (char *dimen, char **tail)
       ptail += 2;
       value *= factor;
     }
-  if (approx_lt (value, 0.0))
+  if (value <= 0.0)
     goto lossage;
   if (tail)
     *tail = ptail;
@@ -1148,6 +1185,7 @@ outp_get_paper_size (char *size, int *h, int *v)
   where.filename = pprsz_fn;
   where.line_number = 0;
   err_push_file_locator (&where);
+  ds_init (&line, 128);
 
   if (pprsz_fn == NULL)
     {
@@ -1163,7 +1201,6 @@ outp_get_paper_size (char *size, int *h, int *v)
       goto exit;
     }
 
-  ds_init (NULL, &line, 128);
   for (;;)
     {
       char *cp, *bp, *ep;
@@ -1174,7 +1211,7 @@ outp_get_paper_size (char *size, int *h, int *v)
            msg (ME, _("Reading %s: %s."), pprsz_fn, strerror (errno));
          break;
        }
-      for (cp = ds_value (&line); isspace ((unsigned char) *cp); cp++);
+      for (cp = ds_c_str (&line); isspace ((unsigned char) *cp); cp++);
       if (*cp == 0)
        continue;
       if (*cp != '"')