work
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 31 Dec 2020 00:09:27 +0000 (16:09 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 31 Dec 2020 03:58:11 +0000 (19:58 -0800)
src/output/cairo-fsm.c
src/output/csv.c
src/output/html.c
src/output/odt.c
src/output/pivot-output.c
src/output/pivot-output.h
src/output/render.c
src/output/render.h
src/output/tex.c
tests/output/pivot-table-test.c

index 698141e080fbb4550885cf73131c8d607c48dcc6..179d7a812c14986870671e550c2858dba77c2c79 100644 (file)
@@ -1066,6 +1066,7 @@ xr_fsm_create (const struct output_item *item_,
       .min_break = { [H] = style->min_break[H], [V] = style->min_break[V] },
       .supports_margins = true,
       .rtl = render_direction_rtl (),
+      .printing = print,
     }
   };
 
index e4b1000769e32c158afd0aabd99ae90403f3e545..3940ebe1977c7f47a78f9830a00696c8fa345acd 100644 (file)
@@ -251,7 +251,7 @@ csv_output_table_layer (struct csv_driver *csv, const struct pivot_table *pt,
                         const size_t *layer_indexes)
 {
   struct table *title, *layers, *body, *caption, *footnotes;
-  pivot_output (pt, layer_indexes, &title, &layers, &body,
+  pivot_output (pt, layer_indexes, true, &title, &layers, &body,
                 &caption, &footnotes, NULL, NULL);
 
   csv_put_separator (csv);
index 2dcdf52f0663fb18b47401b8ecbd3763928be28f..740d04257d2306cf0f863b177cc92cc32b763e6d 100644 (file)
@@ -623,7 +623,7 @@ html_output_table_layer (struct html_driver *html, const struct pivot_table *pt,
                          const size_t *layer_indexes)
 {
   struct table *title, *layers, *body, *caption, *footnotes;
-  pivot_output (pt, layer_indexes, &title, &layers, &body,
+  pivot_output (pt, layer_indexes, true, &title, &layers, &body,
                 &caption, &footnotes, NULL, NULL);
 
   fputs ("<table", html->file);
index 8d890e87e0311e23e3b9d6bde1f1b7abd48059ba..1d8127b96ac02a62d706f1fba6f09b8ffca21496 100644 (file)
@@ -468,7 +468,7 @@ write_table_layer (struct odt_driver *odt, const struct pivot_table *pt,
                    const size_t *layer_indexes)
 {
   struct table *title, *layers, *body, *caption, *footnotes;
-  pivot_output (pt, layer_indexes, &title, &layers, &body,
+  pivot_output (pt, layer_indexes, true, &title, &layers, &body,
                 &caption, &footnotes, NULL, NULL);
 
   /* Write a heading for the table */
index a1fba1a3baf5ef5211cb5ebd7e5630ba244ba9be..6e31a7aab7918770be52053f1f793bac279a1c86 100644 (file)
@@ -382,6 +382,7 @@ collect_footnotes (const struct pivot_table *pt,
 void
 pivot_output (const struct pivot_table *pt,
               const size_t *layer_indexes,
+              bool printing UNUSED,
               struct table **titlep,
               struct table **layersp,
               struct table **bodyp,
@@ -409,6 +410,13 @@ pivot_output (const struct pivot_table *pt,
     body->styles[i] = table_area_style_override (
       body->container, &pt->look->areas[i], NULL, NULL, false);
 
+  struct table_border_style borders[PIVOT_N_BORDERS];
+  memcpy (borders, pt->look->borders, sizeof borders);
+  if (!printing && pt->show_grid_lines)
+    for (int b = 0; b < PIVOT_N_BORDERS; b++)
+      if (borders[b].stroke == TABLE_STROKE_NONE)
+        borders[b].stroke = TABLE_STROKE_DASHED;
+
   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
     {
       const struct table_border_style *in = &pt->look->borders[i];
@@ -419,7 +427,7 @@ pivot_output (const struct pivot_table *pt,
 
   compose_headings (body,
                     &pt->axes[PIVOT_AXIS_COLUMN], H, &pt->axes[PIVOT_AXIS_ROW],
-                    pt->look->borders,
+                    borders,
                     PIVOT_BORDER_DIM_COL_HORZ,
                     PIVOT_BORDER_DIM_COL_VERT,
                     PIVOT_BORDER_CAT_COL_HORZ,
@@ -433,7 +441,7 @@ pivot_output (const struct pivot_table *pt,
 
   compose_headings (body,
                     &pt->axes[PIVOT_AXIS_ROW], V, &pt->axes[PIVOT_AXIS_COLUMN],
-                    pt->look->borders,
+                    borders,
                     PIVOT_BORDER_DIM_ROW_VERT,
                     PIVOT_BORDER_DIM_ROW_HORZ,
                     PIVOT_BORDER_CAT_ROW_VERT,
@@ -479,25 +487,25 @@ pivot_output (const struct pivot_table *pt,
   if (body->n[H] && body->n[V])
     {
       table_hline (
-        body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_TOP),
+        body, get_table_rule (borders, PIVOT_BORDER_INNER_TOP),
         0, body->n[H] - 1, 0);
       table_hline (
-        body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_BOTTOM),
+        body, get_table_rule (borders, PIVOT_BORDER_INNER_BOTTOM),
         0, body->n[H] - 1, body->n[V]);
       table_vline (
-        body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_LEFT),
+        body, get_table_rule (borders, PIVOT_BORDER_INNER_LEFT),
         0, 0, body->n[V] - 1);
       table_vline (
-        body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_RIGHT),
+        body, get_table_rule (borders, PIVOT_BORDER_INNER_RIGHT),
         body->n[H], 0, body->n[V] - 1);
 
       if (stub[V])
         table_hline (
-          body, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_TOP),
+          body, get_table_rule (borders, PIVOT_BORDER_DATA_TOP),
           0, body->n[H] - 1, stub[V]);
       if (stub[H])
         table_vline (
-          body, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_LEFT),
+          body, get_table_rule (borders, PIVOT_BORDER_DATA_LEFT),
           stub[H], 0, body->n[V] - 1);
 
     }
@@ -506,7 +514,7 @@ pivot_output (const struct pivot_table *pt,
 
   /* Title. */
   struct table *title;
-  if (pt->title && titlep)
+  if (pt->title && pt->show_title && titlep)
     {
       title = create_aux_table (pt, 1, 1, PIVOT_AREA_TITLE);
       fill_cell (title, 0, 0, 0, 0,
@@ -552,7 +560,7 @@ pivot_output (const struct pivot_table *pt,
 
   /* Caption. */
   struct table *caption;
-  if (pt->caption && captionp)
+  if (pt->caption && pt->show_caption && captionp)
     {
       caption = create_aux_table (pt, 1, 1, PIVOT_AREA_CAPTION);
       fill_cell (caption, 0, 0, 0, 0,
index 17118dfb21a8d0786575be74dc15547ac4e1e905..f2feeb9599ef4ecf89f78d1d550cc50323d2ab50 100644 (file)
@@ -32,6 +32,7 @@ size_t *pivot_output_next_layer (const struct pivot_table *,
 
 void pivot_output (const struct pivot_table *,
                    const size_t *layer_indexes,
+                   bool printing,
                    struct table **titlep,
                    struct table **layersp,
                    struct table **bodyp,
index b4c22b516306b761b459d986693b09c237b32c83..23b43f21823be7b09aa11d4dac8f7e0e09408e40 100644 (file)
@@ -1523,8 +1523,8 @@ render_pager_create (const struct render_params *params,
     layer_indexes = pt->current_layer;
 
   struct table *title, *layers, *body, *caption, *footnotes;
-  pivot_output (pt, layer_indexes, &title, &layers, &body, &caption,
-                &footnotes, NULL, NULL);
+  pivot_output (pt, layer_indexes, params->printing,
+                &title, &layers, &body, &caption, &footnotes, NULL, NULL);
 
   /* Figure out the width of the body of the table.  Use this to determine the
      base scale. */
index ff73c4e35af9896d0ad59ddf16a2694f7a1423ab..bc8db241f88ce91b88db1808367c742e2686df8c 100644 (file)
@@ -79,6 +79,10 @@ struct render_params
     /* True if the local language has a right-to-left direction, otherwise
        false.  (Use render_direction_rtl() to find out.) */
     bool rtl;
+
+    /* True if the table is being rendered for printing (as opposed to
+       on-screen display). */
+    bool printing;
   };
 
 struct render_ops
index bf5eb7115ea540a7e65cbd4debb33970d26b32f3..684c5db4688302a88af9dcf5b3f179a22a9af7e9 100644 (file)
@@ -413,7 +413,7 @@ tex_output_table_layer (struct tex_driver *tex, const struct pivot_table *pt,
   struct table *title, *layers, *body, *caption;
   struct pivot_footnote **footnotes;
   size_t n_footnotes;
-  pivot_output (pt, layer_indexes, &title, &layers, &body,
+  pivot_output (pt, layer_indexes, true, &title, &layers, &body,
                 &caption, NULL, &footnotes, &n_footnotes);
 
   shipout (&tex->token_list, "\n{\\parindent=0pt\n");
index 8200c18737b3daadd0585c5d4d4bb6b1c32baf8c..44347fb4f2009874d2ccbdd0bb1e384f2121d595 100644 (file)
@@ -30,6 +30,8 @@
 #include "libpspp/i18n.h"
 #include "libpspp/string-map.h"
 #include "output/driver.h"
+#include "output/message-item.h"
+#include "output/options.h"
 #include "output/pivot-table.h"
 #include "output/table-item.h"
 
@@ -50,6 +52,7 @@ static const char *output_base = "render";
 static const char *parse_options (int argc, char **argv);
 static void usage (void) NO_RETURN;
 static struct pivot_table *read_table (struct lexer *);
+static void output_msg (const struct msg *, void *);
 
 int
 main (int argc, char **argv)
@@ -70,6 +73,7 @@ main (int argc, char **argv)
     exit (1);
 
   struct lexer *lexer = lex_create ();
+  msg_set_handler (output_msg, lexer);
   lex_include (lexer, reader);
   lex_get (lexer);
 
@@ -169,6 +173,7 @@ parse_options (int argc, char **argv)
         OPT_MIN_BREAK,
         OPT_EMPHASIS,
         OPT_BOX,
+        OPT_TABLE_LOOK,
         OPT_HELP
       };
       static const struct option options[] =
@@ -179,6 +184,7 @@ parse_options (int argc, char **argv)
           {"emphasis", no_argument, NULL, OPT_EMPHASIS},
           {"box", required_argument, NULL, OPT_BOX},
           {"output", required_argument, NULL, 'o'},
+          {"table-look", required_argument, NULL, OPT_TABLE_LOOK},
           {"help", no_argument, NULL, OPT_HELP},
           {NULL, 0, NULL, 0},
         };
@@ -213,6 +219,17 @@ parse_options (int argc, char **argv)
           output_base = optarg;
           break;
 
+        case OPT_TABLE_LOOK:
+          {
+            struct pivot_table_look *look;
+            char *err = pivot_table_look_read (optarg, &look);
+            if (err)
+              error (1, 0, "%s", err);
+            pivot_table_look_set_default (look);
+            pivot_table_look_unref (look);
+          }
+          break;
+
         case OPT_HELP:
           usage ();
 
@@ -333,6 +350,32 @@ read_dimension (struct lexer *lexer, struct pivot_table *pt,
   read_group (lexer, pt, dim->root);
 }
 
+static bool
+parse_bool_setting (struct lexer *lexer, const char *name,
+                    const char *true_kw, const char *false_kw,
+                    bool *out)
+{
+  if (lex_match_id (lexer, name))
+    {
+      if (!lex_force_match (lexer, T_EQUALS))
+        exit (1);
+
+      if (lex_match_id (lexer, true_kw))
+        *out = true;
+      else if (lex_match_id (lexer, false_kw))
+        *out = false;
+      else
+        {
+          lex_error_expecting (lexer, true_kw, false_kw);
+          exit (1);
+        }
+
+      return true;
+    }
+  else
+    return false;
+}
+
 static void
 read_look (struct lexer *lexer, struct pivot_table *pt)
 {
@@ -347,10 +390,121 @@ read_look (struct lexer *lexer, struct pivot_table *pt)
           msg (SE, "%s", error);
           exit (1);
         }
+      lex_get (lexer);
 
       pivot_table_set_look (pt, look);
       pivot_table_look_unref (look);
     }
+
+  struct pivot_table_look *look = pivot_table_look_unshare (
+    pivot_table_look_ref (pt->look));
+  for (;;)
+    {
+      if (!parse_bool_setting (lexer, "EMPTY", "HIDE", "SHOW",
+                               &look->omit_empty)
+          && !parse_bool_setting (lexer, "ROWLABELS", "CORNER", "NESTED",
+                                  &look->row_labels_in_corner)
+          && !parse_bool_setting (lexer, "MARKERS", "NUMERIC", "ALPHA",
+                                  &look->show_numeric_markers)
+          && !parse_bool_setting (lexer, "LEVEL", "SUPER", "SUB",
+                                  &look->footnote_marker_superscripts)
+          && !parse_bool_setting (lexer, "LAYERS", "CURRENT", "ALL",
+                                  &look->print_all_layers)
+          && !parse_bool_setting (lexer, "PAGINATELAYERS", "YES", "NO",
+                                  &look->paginate_layers)
+          && !parse_bool_setting (lexer, "HSHRINK", "YES", "NO",
+                                  &look->shrink_to_fit[TABLE_HORZ])
+          && !parse_bool_setting (lexer, "VSHRINK", "YES", "NO",
+                                  &look->shrink_to_fit[TABLE_VERT])
+          && !parse_bool_setting (lexer, "TOPCONTINUATION", "YES", "NO",
+                                  &look->top_continuation)
+          && !parse_bool_setting (lexer, "BOTTOMCONTINUATION", "YES", "NO",
+                                  &look->bottom_continuation))
+        break;
+    }
+  pivot_table_set_look (pt, look);
+  pivot_table_look_unref (look);
+}
+
+static enum table_stroke
+read_stroke (struct lexer *lexer)
+{
+  for (int stroke = 0; stroke < TABLE_N_STROKES; stroke++)
+    if (lex_match_id (lexer, table_stroke_to_string (stroke)))
+      return stroke;
+
+  lex_error (lexer, "expecting stroke");
+  exit (1);
+}
+
+static void
+read_border (struct lexer *lexer, struct pivot_table *pt)
+{
+  static const char *const pivot_border_ids[PIVOT_N_BORDERS] = {
+    [PIVOT_BORDER_TITLE] = "title",
+    [PIVOT_BORDER_OUTER_LEFT] = "outer-left",
+    [PIVOT_BORDER_OUTER_TOP] = "outer-top",
+    [PIVOT_BORDER_OUTER_RIGHT] = "outer-right",
+    [PIVOT_BORDER_OUTER_BOTTOM] = "outer-bottom",
+    [PIVOT_BORDER_INNER_LEFT] = "inner-left",
+    [PIVOT_BORDER_INNER_TOP] = "inner-top",
+    [PIVOT_BORDER_INNER_RIGHT] = "inner-right",
+    [PIVOT_BORDER_INNER_BOTTOM] = "inner-bottom",
+    [PIVOT_BORDER_DATA_LEFT] = "data-left",
+    [PIVOT_BORDER_DATA_TOP] = "data-top",
+    [PIVOT_BORDER_DIM_ROW_HORZ] = "dim-row-horz",
+    [PIVOT_BORDER_DIM_ROW_VERT] = "dim-row-vert",
+    [PIVOT_BORDER_DIM_COL_HORZ] = "dim-col-horz",
+    [PIVOT_BORDER_DIM_COL_VERT] = "dim-col-vert",
+    [PIVOT_BORDER_CAT_ROW_HORZ] = "cat-row-horz",
+    [PIVOT_BORDER_CAT_ROW_VERT] = "cat-row-vert",
+    [PIVOT_BORDER_CAT_COL_HORZ] = "cat-col-horz",
+    [PIVOT_BORDER_CAT_COL_VERT] = "cat-col-vert",
+  };
+
+  lex_match (lexer, T_EQUALS);
+
+  struct pivot_table_look *look = pivot_table_look_unshare (
+    pivot_table_look_ref (pt->look));
+  while (lex_token (lexer) == T_STRING)
+    {
+      char *s = xstrdup (lex_tokcstr (lexer));
+      lex_get (lexer);
+      if (!lex_force_match (lexer, T_LPAREN))
+        exit (1);
+
+      struct table_border_style style = TABLE_BORDER_STYLE_INITIALIZER;
+      style.stroke = read_stroke (lexer);
+      if (lex_is_string (lexer))
+        {
+          if (!parse_color__ (lex_tokcstr (lexer), &style.color))
+            {
+              msg (SE, "%s: unknown color", lex_tokcstr (lexer));
+              exit (1);
+            }
+          lex_get (lexer);
+        }
+      if (!lex_force_match (lexer, T_RPAREN))
+        exit (1);
+
+      int n = 0;
+      for (int b = 0; b < PIVOT_N_BORDERS; b++)
+        {
+          if (!strncmp (s, pivot_border_ids[b], strlen (s)))
+            {
+              look->borders[b] = style;
+              n++;
+            }
+        }
+      if (!n)
+        {
+          msg (SE, "%s: no matching borders", s);
+          exit (1);
+        }
+      free (s);
+    }
+  pivot_table_set_look (pt, look);
+  pivot_table_look_unref (look);
 }
 
 static struct pivot_table *
@@ -359,6 +513,8 @@ read_table (struct lexer *lexer)
   struct pivot_table *pt = pivot_table_create__ (NULL, NULL);
   while (lex_match (lexer, T_SLASH))
     {
+      assert (!pivot_table_is_shared (pt));
+
       if (lex_match_id (lexer, "ROW"))
         read_dimension (lexer, pt, PIVOT_AXIS_ROW);
       else if (lex_match_id (lexer, "COLUMN"))
@@ -367,6 +523,30 @@ read_table (struct lexer *lexer)
         read_dimension (lexer, pt, PIVOT_AXIS_LAYER);
       else if (lex_match_id (lexer, "LOOK"))
         read_look (lexer, pt);
+      else if (lex_match_id (lexer, "ROTATE"))
+        {
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) == T_ID)
+            if (!parse_bool_setting (lexer, "INNERCOLUMNS", "YES", "NO",
+                                     &pt->rotate_inner_column_labels)
+                && !parse_bool_setting (lexer, "OUTERROWS", "YES", "NO",
+                                        &pt->rotate_outer_row_labels))
+              break;
+        }
+      else if (lex_match_id (lexer, "DISPLAY"))
+        {
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) == T_ID)
+            if (!parse_bool_setting (lexer, "GRID", "YES", "NO",
+                                     &pt->show_grid_lines)
+                && !parse_bool_setting (lexer, "CAPTION", "YES", "NO",
+                                        &pt->show_caption)
+                && !parse_bool_setting (lexer, "TITLE", "YES", "NO",
+                                        &pt->show_caption))
+              break;
+        }
+      else if (lex_match_id (lexer, "BORDER"))
+        read_border (lexer, pt);
       else
         {
           msg (SE, "Expecting keyword");
@@ -378,3 +558,23 @@ read_table (struct lexer *lexer)
     exit (1);
   return pt;
 }
+
+static void
+output_msg (const struct msg *m_, void *lexer_)
+{
+  struct lexer *lexer = lexer_;
+  struct msg m = *m_;
+
+  if (m.file_name == NULL)
+    {
+      m.file_name = CONST_CAST (char *, lex_get_file_name (lexer));
+      m.first_line = lex_get_first_line_number (lexer, 0);
+      m.last_line = lex_get_last_line_number (lexer, 0);
+    }
+
+  m.command_name = output_get_command_name ();
+
+  message_item_submit (message_item_create (&m));
+
+  free (m.command_name);
+}