output: Modernize how drivers are initialized.
[pspp] / src / output / ascii.c
index a6bcb106d68effd619d93ebdb559cac0dd06f09e..b94d4941c2362d05a198e844e9685d02bce79e7b 100644 (file)
@@ -173,7 +173,7 @@ get_unicode_box (void)
     {
       /* r  b  l   t:   _       d       S       D */
       .c[_][_][_] = { 0x0020, 0x2575, 0x2575, 0x2551, }, /*  ╵╵║ */
-      .c[_][_][d] = { 0x2574, 0x256f, 0x256f, 0x255c, }, /* ╴╯╯╜ */
+      .c[_][_][d] = { 0x254c, 0x256f, 0x256f, 0x255c, }, /* ╴╯╯╜ */
       .c[_][_][S] = { 0x2574, 0x256f, 0x256f, 0x255c, }, /* ╴╯╯╜ */
       .c[_][_][D] = { 0x2550, 0x255b, 0x255b, 0x255d, }, /* ═╛╛╝ */
       .c[_][S][_] = { 0x2577, 0x2502, 0x2502, 0x2551, }, /* ╷││║ */
@@ -188,7 +188,7 @@ get_unicode_box (void)
       .c[_][D][d] = { 0x2556, 0x2562, 0x2562, 0x2562, }, /* ╖╢╢╢ */
       .c[_][D][S] = { 0x2556, 0x2562, 0x2562, 0x2562, }, /* ╖╢╢╢ */
       .c[_][D][D] = { 0x2557, 0x2563, 0x2563, 0x2563, }, /* ╗╣╣╣ */
-      .c[d][_][_] = { 0x2576, 0x2570, 0x2570, 0x2559, }, /* ╶╰╰╙ */
+      .c[d][_][_] = { 0x254c, 0x2570, 0x2570, 0x2559, }, /* ╶╰╰╙ */
       .c[d][_][d] = { 0x254c, 0x2534, 0x2534, 0x2568, }, /* ╌┴┴╨ */
       .c[d][_][S] = { 0x2500, 0x2534, 0x2534, 0x2568, }, /* ─┴┴╨ */
       .c[d][_][D] = { 0x2550, 0x2567, 0x2567, 0x2569, }, /* ═╧╧╩ */
@@ -245,18 +245,18 @@ ascii_line_from_render_line (int render_line)
 {
   switch (render_line)
     {
-    case RENDER_LINE_NONE:
+    case TABLE_STROKE_NONE:
       return ASCII_LINE_NONE;
 
-    case RENDER_LINE_DASHED:
+    case TABLE_STROKE_DASHED:
       return ASCII_LINE_DASHED;
 
-    case RENDER_LINE_SINGLE:
-    case RENDER_LINE_THICK:
-    case RENDER_LINE_THIN:
+    case TABLE_STROKE_SOLID:
+    case TABLE_STROKE_THICK:
+    case TABLE_STROKE_THIN:
       return ASCII_LINE_SINGLE;
 
-    case RENDER_LINE_DOUBLE:
+    case TABLE_STROKE_DOUBLE:
       return ASCII_LINE_DOUBLE;
 
     default:
@@ -278,13 +278,20 @@ box_get (const struct box_chars *box,
   return box->c[right][bottom][left][top];
 }
 
+/* How the page width is determined. */
+enum ascii_width_mode
+  {
+    FIXED_WIDTH,              /* Specified by configuration. */
+    VIEW_WIDTH,               /* From SET WIDTH. */
+    TERMINAL_WIDTH            /* From the terminal's width. */
+  };
+
 /* ASCII output driver. */
 struct ascii_driver
   {
     struct output_driver driver;
 
     /* User parameters. */
-    bool append;                /* Append if output file already exists? */
     bool emphasis;              /* Enable bold and underline in output? */
     char *chart_file_name;      /* Name of files used for charts. */
 
@@ -293,11 +300,7 @@ struct ascii_driver
     struct cell_color bg;
 
     /* How the page width is determined: */
-    enum {
-      FIXED_WIDTH,              /* Specified by configuration. */
-      VIEW_WIDTH,               /* From SET WIDTH. */
-      TERMINAL_WIDTH            /* From the terminal's width. */
-    } width_mode;
+    enum ascii_width_mode width_mode;
     int width;                  /* Page width. */
 
     int min_hbreak;             /* Min cell size to break across pages. */
@@ -310,8 +313,8 @@ struct ascii_driver
     bool error;                 /* Output error? */
     struct u8_line *lines;      /* Page content. */
     int allocated_lines;        /* Number of lines allocated. */
-    int chart_cnt;              /* Number of charts so far. */
-    int object_cnt;             /* Number of objects so far. */
+    int n_charts;               /* Number of charts so far. */
+    int n_objects;              /* Number of objects so far. */
     const struct pivot_table *pt;
     struct render_params params;
   };
@@ -326,8 +329,7 @@ static bool update_page_size (struct ascii_driver *, bool issue_error);
 static int parse_page_size (struct driver_option *);
 
 static void ascii_draw_line (void *, int bb[TABLE_N_AXES][2],
-                             enum render_line_style styles[TABLE_N_AXES][2],
-                             struct cell_color colors[TABLE_N_AXES][2]);
+                             const struct table_border_style[TABLE_N_AXES][2]);
 static void ascii_measure_cell_width (void *, const struct table_cell *,
                                       int *min, int *max);
 static int ascii_measure_cell_height (void *, const struct table_cell *,
@@ -345,10 +347,9 @@ ascii_driver_cast (struct output_driver *driver)
 }
 
 static struct driver_option *
-opt (struct output_driver *d, struct string_map *options, const char *key,
-     const char *default_value)
+opt (struct string_map *options, const char *key, const char *default_value)
 {
-  return driver_option_get (d, options, key, default_value);
+  return driver_option_get ("ascii", options, key, default_value);
 }
 
 /* Return true iff the terminal appears to be an xterm with
@@ -368,43 +369,25 @@ static struct output_driver *
 ascii_create (struct  file_handle *fh, enum settings_output_devices device_type,
               struct string_map *o)
 {
-  enum { BOX_ASCII, BOX_UNICODE } box;
-  struct output_driver *d;
-  struct ascii_driver *a = XZALLOC (struct ascii_driver);
-  d = &a->driver;
-  output_driver_init (&a->driver, &ascii_driver_class, fh_get_file_name (fh), device_type);
-  a->append = parse_boolean (opt (d, o, "append", "false"));
-  a->emphasis = parse_boolean (opt (d, o, "emphasis", "false"));
-
-  a->chart_file_name = parse_chart_file_name (opt (d, o, "charts", fh_get_file_name (fh)));
-  a->handle = fh;
-
+  bool append = parse_boolean (opt (o, "append", "false"));
+  FILE *file = fn_open (fh, append ? "a" : "w");
+  if (!file)
+    {
+      msg_error (errno, _("ascii: opening output file `%s'"),
+                 fh_get_file_name (fh));
+      return NULL;
+    }
 
+  int width = parse_page_size (opt (o, "width", "-1"));
   bool terminal = !strcmp (fh_get_file_name (fh), "-") && isatty (1);
-  a->width = parse_page_size (opt (d, o, "width", "-1"));
-  a->width_mode = (a->width > 0 ? FIXED_WIDTH
-                   : terminal ? TERMINAL_WIDTH
-                   : VIEW_WIDTH);
-  a->min_hbreak = parse_int (opt (d, o, "min-hbreak", "-1"), -1, INT_MAX);
-
-  a->bg = parse_color (opt (d, o, "background-color", "#FFFFFFFFFFFF"));
-  a->fg = parse_color (opt (d, o, "foreground-color", "#000000000000"));
 
   const char *default_box = (terminal && (!strcmp (locale_charset (), "UTF-8")
                                           || term_is_utf8_xterm ())
                              ? "unicode" : "ascii");
-  box = parse_enum (opt (d, o, "box", default_box),
-                    "ascii", BOX_ASCII,
-                    "unicode", BOX_UNICODE,
-                    NULL_SENTINEL);
-  a->box = box == BOX_ASCII ? get_ascii_box () : get_unicode_box ();
-
-  a->file = NULL;
-  a->error = false;
-  a->lines = NULL;
-  a->allocated_lines = 0;
-  a->chart_cnt = 0;
-  a->object_cnt = 0;
+  enum { BOX_ASCII, BOX_UNICODE } box = parse_enum (opt (o, "box", default_box),
+                                                    "ascii", BOX_ASCII,
+                                                    "unicode", BOX_UNICODE,
+                                                    NULL_SENTINEL);
 
   static const struct render_ops ascii_render_ops = {
     .draw_line = ascii_draw_line,
@@ -413,41 +396,61 @@ ascii_create (struct  file_handle *fh, enum settings_output_devices device_type,
     .adjust_break = NULL,
     .draw_cell = ascii_draw_cell,
   };
-  a->params.ops = &ascii_render_ops;
-  a->params.aux = a;
-  a->params.size[H] = a->width;
-  a->params.size[V] = INT_MAX;
-  a->params.font_size[H] = 1;
-  a->params.font_size[V] = 1;
-
-  static const int ascii_line_widths[RENDER_N_LINES] = {
-    [RENDER_LINE_NONE] = 0,
-    [RENDER_LINE_SINGLE] = 1,
-    [RENDER_LINE_DASHED] = 1,
-    [RENDER_LINE_THICK] = 1,
-    [RENDER_LINE_THIN] = 1,
-    [RENDER_LINE_DOUBLE] = 1,
+
+  static const int ascii_line_widths[TABLE_N_STROKES] = {
+    [TABLE_STROKE_NONE] = 0,
+    [TABLE_STROKE_SOLID] = 1,
+    [TABLE_STROKE_DASHED] = 1,
+    [TABLE_STROKE_THICK] = 1,
+    [TABLE_STROKE_THIN] = 1,
+    [TABLE_STROKE_DOUBLE] = 1,
+  };
+
+  struct ascii_driver *a = xmalloc (sizeof *a);
+  *a = (struct ascii_driver) {
+    .driver = {
+      .class = &ascii_driver_class,
+      .name = xstrdup (fh_get_file_name (fh)),
+      .device_type = device_type
+    },
+
+    .emphasis = parse_boolean (opt (o, "emphasis", "false")),
+    .chart_file_name = parse_chart_file_name (opt (o, "charts",
+                                                   fh_get_file_name (fh))),
+
+    .fg = parse_color (opt (o, "foreground-color", "#000000000000")),
+    .bg = parse_color (opt (o, "background-color", "#FFFFFFFFFFFF")),
+
+    .width_mode = (width > 0 ? FIXED_WIDTH
+                   : terminal ? TERMINAL_WIDTH
+                   : VIEW_WIDTH),
+    .width = width,
+
+    .min_hbreak = parse_int (opt (o, "min-hbreak", "-1"), -1, INT_MAX),
+
+    .box = box == BOX_ASCII ? get_ascii_box () : get_unicode_box (),
+
+    .handle = fh,
+    .file = file,
+
+    .params = (struct render_params) {
+      .ops = &ascii_render_ops,
+      .aux = a,
+      .size = { [H] = a->width, [V] = INT_MAX },
+      .font_size = { [H] = 1, [V] = 1 },
+      .line_widths = ascii_line_widths,
+      .rtl = render_direction_rtl (),
+      .printing = true,
+    },
   };
-  a->params.line_widths = ascii_line_widths;
-  a->params.supports_margins = false;
-  a->params.rtl = render_direction_rtl ();
-  a->params.printing = true;
 
   if (!update_page_size (a, true))
     goto error;
 
-  a->file = fn_open (a->handle, a->append ? "a" : "w");
-  if (!a->file)
-    {
-      msg_error (errno, _("ascii: opening output file `%s'"),
-                 fh_get_file_name (a->handle));
-      goto error;
-    }
-
-  return d;
+  return &a->driver;
 
 error:
-  output_driver_destroy (d);
+  output_driver_destroy (&a->driver);
   return NULL;
 }
 
@@ -559,7 +562,7 @@ ascii_output_table_item (struct ascii_driver *a,
                                                     layer_indexes);
       for (int i = 0; render_pager_has_next (p); i++)
         {
-          if (a->object_cnt++)
+          if (a->n_objects++)
             putc ('\n', a->file);
 
           ascii_output_lines (a, render_pager_draw_next (p, INT_MAX));
@@ -595,7 +598,7 @@ ascii_submit (struct output_driver *driver, const struct output_item *item)
       if (a->chart_file_name != NULL)
         {
           char *file_name = xr_write_png_image (
-            item->image, a->chart_file_name, ++a->chart_cnt);
+            item->image, a->chart_file_name, ++a->n_charts);
           if (file_name != NULL)
             {
               struct output_item *text_item = text_item_create_nocopy (
@@ -614,7 +617,7 @@ ascii_submit (struct output_driver *driver, const struct output_item *item)
       if (a->chart_file_name != NULL)
         {
           char *file_name = xr_draw_png_chart (
-            item->chart, a->chart_file_name, ++a->chart_cnt, &a->fg, &a->bg);
+            item->chart, a->chart_file_name, ++a->n_charts, &a->fg, &a->bg);
           if (file_name != NULL)
             {
               struct output_item *text_item = text_item_create_nocopy (
@@ -673,8 +676,7 @@ static void ascii_layout_cell (struct ascii_driver *,
 
 static void
 ascii_draw_line (void *a_, int bb[TABLE_N_AXES][2],
-                 enum render_line_style styles[TABLE_N_AXES][2],
-                 struct cell_color colors[TABLE_N_AXES][2] UNUSED)
+                 const struct table_border_style styles[TABLE_N_AXES][2])
 {
   struct ascii_driver *a = a_;
   char mbchar[6];
@@ -692,7 +694,11 @@ ascii_draw_line (void *a_, int bb[TABLE_N_AXES][2],
     return;
 
   /* Draw. */
-  uc = box_get (a->box, styles[V][0], styles[V][1], styles[H][0], styles[H][1]);
+  enum table_stroke v0 = styles[V][0].stroke;
+  enum table_stroke v1 = styles[V][1].stroke;
+  enum table_stroke h0 = styles[H][0].stroke;
+  enum table_stroke h1 = styles[H][1].stroke;
+  uc = box_get (a->box, v0, v1, h0, h1);
   mblen = u8_uctomb (CHAR_CAST (uint8_t *, mbchar), uc, 6);
   for (y = y0; y < y1; y++)
     {