Fix numerous memory leaks.
[pspp] / tests / output / render-test.c
index 24443607859caf822f36ef6ea52f8d9c4779d11a..421b9be0663dd6a2abc8793fba4e2e995e239a99 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "data/file-handle-def.h"
 #include "libpspp/assertion.h"
 #include "libpspp/compiler.h"
 #include "libpspp/string-map.h"
@@ -39,7 +40,8 @@
 static int transpose;
 
 /* --emphasis: ASCII driver emphasis option. */
-static char *emphasis;
+static bool bold;
+static bool underline;
 
 /* --box: ASCII driver box option. */
 static char *box;
@@ -47,9 +49,18 @@ static char *box;
 /* --draw-mode: special ASCII driver test mode. */
 static int draw_mode;
 
+/* --no-txt: Whether to render to <base>.txt. */
+static int render_txt = true;
+
+/* --no-stdout: Whether to render to stdout. */
+static int render_stdout = true;
+
 /* --pdf: Also render PDF output. */
 static int render_pdf;
 
+/* --csv: Also render CSV output. */
+static int render_csv;
+
 /* ASCII driver, for ASCII driver test mode. */
 static struct output_driver *ascii_driver;
 
@@ -68,6 +79,7 @@ main (int argc, char **argv)
   FILE *input;
 
   set_program_name (argv[0]);
+  output_engine_push ();
   input_file_name = parse_options (argc, argv);
 
   if (!strcmp (input_file_name, "-"))
@@ -81,14 +93,32 @@ main (int argc, char **argv)
 
   if (!draw_mode)
     {
+      struct table **tables = NULL;
+      size_t allocated_tables = 0;
+      size_t n_tables = 0;
       struct table *table;
 
-      table = read_table (input);
+      for (;;)
+        {
+          int ch;
+
+          if (n_tables >= allocated_tables)
+            tables = x2nrealloc (tables, &allocated_tables, sizeof *tables);
+
+          tables[n_tables] = read_table (input);
+          n_tables++;
+
+          ch = getc (input);
+          if (ch == EOF)
+            break;
+          ungetc (ch, input);
+        }
 
+      table = tables[n_tables - 1];
       if (transpose)
         table = table_transpose (table);
-
-      table_item_submit (table_item_create (table, NULL));
+      table_item_submit (table_item_create (table, NULL, NULL));
+      free (tables);
     }
   else
     draw (input);
@@ -96,7 +126,8 @@ main (int argc, char **argv)
   if (input != stdin)
     fclose (input);
 
-  output_close ();
+  output_engine_pop ();
+  fh_done ();
 
   return 0;
 }
@@ -112,47 +143,49 @@ configure_drivers (int width, int length, int min_break)
   string_map_insert (&options, "output-file", "-");
   string_map_insert_nocopy (&options, xstrdup ("width"),
                             xasprintf ("%d", width));
-  string_map_insert_nocopy (&options, xstrdup ("length"),
-                            xasprintf ("%d", length));
   if (min_break >= 0)
-    {
-      string_map_insert_nocopy (&options, xstrdup ("min-hbreak"),
-                                xasprintf ("%d", min_break));
-      string_map_insert_nocopy (&options, xstrdup ("min-vbreak"),
-                                xasprintf ("%d", min_break));
-    }
-  if (emphasis != NULL)
-    string_map_insert (&options, "emphasis", emphasis);
+    string_map_insert_nocopy (&options, xstrdup ("min-hbreak"),
+                              xasprintf ("%d", min_break));
+  if (bold || underline)
+    string_map_insert (&options, "emphasis", "true");
   if (box != NULL)
     string_map_insert (&options, "box", box);
 
   /* Render to stdout. */
-  string_map_clone (&tmp, &options);
-  ascii_driver = driver = output_driver_create (&tmp);
-  if (driver == NULL)
-    exit (EXIT_FAILURE);
-  output_driver_register (driver);
-  string_map_destroy (&tmp);
+  if (render_stdout)
+    {
+      string_map_clone (&tmp, &options);
+      ascii_driver = driver = output_driver_create (&tmp);
+      if (driver == NULL)
+        exit (EXIT_FAILURE);
+      output_driver_register (driver);
+      string_map_destroy (&tmp);
+    }
 
   if (draw_mode)
    {
-    string_map_destroy (&options);
-    return;
+     string_map_destroy (&options);
+     return;
    }
 
   /* Render to <base>.txt. */
-  string_map_replace_nocopy (&options, xstrdup ("output-file"),
-                             xasprintf ("%s.txt", output_base));
-  driver = output_driver_create (&options);
-  if (driver == NULL)
-    exit (EXIT_FAILURE);
-  output_driver_register (driver);
+  if (render_txt)
+    {
+      string_map_clear (&options);
+      string_map_insert_nocopy (&options, xstrdup ("output-file"),
+                                xasprintf ("%s.txt", output_base));
+      driver = output_driver_create (&options);
+      if (driver == NULL)
+        exit (EXIT_FAILURE);
+      output_driver_register (driver);
+    }
 
 #ifdef HAVE_CAIRO
-  /* Render to <base>.txt. */
+  /* Render to <base>.pdf. */
   if (render_pdf)
     {
-      string_map_replace_nocopy (&options, xstrdup ("output-file"),
+      string_map_clear (&options);
+      string_map_insert_nocopy (&options, xstrdup ("output-file"),
                                  xasprintf ("%s.pdf", output_base));
       string_map_insert (&options, "top-margin", "0");
       string_map_insert (&options, "bottom-margin", "0");
@@ -174,6 +207,18 @@ configure_drivers (int width, int length, int min_break)
     }
 #endif
 
+  /* Render to <base>.csv. */
+  if (render_csv)
+    {
+      string_map_clear (&options);
+      string_map_insert_nocopy (&options, xstrdup ("output-file"),
+                                 xasprintf ("%s.csv", output_base));
+      driver = output_driver_create (&options);
+      if (driver == NULL)
+        exit (EXIT_FAILURE);
+      output_driver_register (driver);
+    }
+
   /* Render to <base>.odt. */
   string_map_replace_nocopy (&options, xstrdup ("output-file"),
                              xasprintf ("%s.odt", output_base));
@@ -211,7 +256,10 @@ parse_options (int argc, char **argv)
           {"emphasis", required_argument, NULL, OPT_EMPHASIS},
           {"box", required_argument, NULL, OPT_BOX},
           {"draw-mode", no_argument, &draw_mode, 1},
+          {"no-txt", no_argument, &render_txt, 0},
+          {"no-stdout", no_argument, &render_stdout, 0},
           {"pdf", no_argument, &render_pdf, 1},
+          {"csv", no_argument, &render_csv, 1},
           {"output", required_argument, NULL, 'o'},
           {"help", no_argument, NULL, OPT_HELP},
           {NULL, 0, NULL, 0},
@@ -236,7 +284,23 @@ parse_options (int argc, char **argv)
           break;
 
         case OPT_EMPHASIS:
-          emphasis = optarg;
+          if (!strcmp (optarg, "bold"))
+            {
+              bold = true;
+              underline = false;
+            }
+          else if (!strcmp (optarg, "underline"))
+            {
+              bold = false;
+              underline = true;
+            }
+          else if (!strcmp (optarg, "none"))
+            {
+              bold = underline = false;
+            }
+          else
+            error (1, 0, "argument to --emphasis must be \"bold\" or "
+                   "\"underline\" or \"none\"");
           break;
 
         case OPT_BOX:
@@ -308,6 +372,7 @@ read_table (FILE *stream)
   int n_input = 0;
   int nr, nc, hl, hr, ht, hb;
   int r, c;
+  size_t n_footnotes = 0;
 
   if (fgets (buffer, sizeof buffer, stream) == NULL
       || (n_input = sscanf (buffer, "%d %d %d %d %d %d",
@@ -328,6 +393,7 @@ read_table (FILE *stream)
     for (c = 0; c < nc; c++)
       if (tab_cell_is_empty (tab, c, r))
         {
+          unsigned int opt;
           char *new_line;
           char *text;
           int rs, cs;
@@ -353,7 +419,8 @@ read_table (FILE *stream)
               cs = 1;
             }
 
-          while (*text && strchr ("<>^,@", *text))
+          opt = 0;
+          while (*text && strchr ("<>^,@()|", *text))
             switch (*text++)
               {
               case '<':
@@ -377,17 +444,44 @@ read_table (FILE *stream)
                          c + cs - 1, r + rs - 1);
                 break;
 
+              case '(':
+                opt &= ~TAB_HALIGN;
+                opt |= TAB_LEFT;
+                break;
+
+              case ')':
+                opt &= ~TAB_HALIGN;
+                opt |= TAB_RIGHT;
+                break;
+
+              case '|':
+                opt &= ~TAB_HALIGN;
+                opt |= TAB_CENTER;
+                break;
+
               default:
                 NOT_REACHED ();
               }
 
           replace_newlines (text);
 
-          tab_joint_text (tab, c, r, c + cs - 1, r + rs - 1, 0, text);
-        }
+          char *pos = text;
+          char *content;
+          int i;
 
-  if (getc (stream) != EOF)
-    error (1, 0, "unread data at end of input");
+          for (i = 0; (content = strsep (&pos, "#")) != NULL; i++)
+            if (!i)
+              tab_joint_text (tab, c, r, c + cs - 1, r + rs - 1, opt,
+                              content);
+            else
+              {
+                char marker[2] = { 'a' + n_footnotes, '\0' };
+                struct footnote *f = tab_create_footnote (
+                  tab, n_footnotes, content, marker, NULL);
+                tab_add_footnote (tab, c, r, f);
+                n_footnotes++;
+              }
+        }
 
   return &tab->table;
 }
@@ -410,10 +504,12 @@ draw (FILE *stream)
         continue;
 
       if (sscanf (buffer, "%d %d %d %[^\n]", &x, &y, &emph, text) == 4)
-        ascii_test_write (ascii_driver, text, x, y, emph ? TAB_EMPH : 0);
+        ascii_test_write (ascii_driver, text, x, y, emph ? bold : false,
+                          emph ? underline : false);
       else if (sscanf (buffer, "set-length %d %d", &y, &length) == 2)
         ascii_test_set_length (ascii_driver, y, length);
       else
         error (1, 0, "line %d has invalid format", line);
     }
+  ascii_test_flush (ascii_driver);
 }