Make the expression code a little nicer and fix bugs found
[pspp-builds.git] / src / ascii.c
index c6f48f00254584f59eaab6187cc09d7ab13966bc..9c0103e0c5e2b044a97f200d5a2acbd1254da62a 100644 (file)
@@ -18,7 +18,7 @@
    02111-1307, USA. */
 
 #include <config.h>
-#include <assert.h>
+#include "error.h"
 #include <ctype.h>
 #include <errno.h>
 #include <limits.h>
@@ -49,6 +49,7 @@
    width=130
    lpi=6                        Only used to determine font size.
    cpi=10                       
+   squeeze=off|on               Squeeze multiple newlines into exactly one.
 
    left-margin=0
    right-margin=0
@@ -161,6 +162,7 @@ struct ascii_driver_ext
     struct len_string fonts[FSTY_COUNT]; /* Font styles; NULL=overstrike. */
     int overstrike_style;      /* OVS_SINGLE or OVS_LINE. */
     int carriage_return_style; /* Carriage return style. */
+    int squeeze_blank_lines;    /* 1=squeeze multiple blank lines into one. */
 
     /* Internal state. */
     struct file_ext file;      /* Output file. */
@@ -182,22 +184,22 @@ static struct pool *ascii_pool;
 static int postopen (struct file_ext *);
 static int preclose (struct file_ext *);
 
-int
-ascii_open_global (struct outp_class *this unused)
+static int
+ascii_open_global (struct outp_class *this UNUSED)
 {
   ascii_pool = pool_create ();
   return 1;
 }
 
-int
-ascii_close_global (struct outp_class *this unused)
+static int
+ascii_close_global (struct outp_class *this UNUSED)
 {
   pool_destroy (ascii_pool);
   return 1;
 }
 
-int *
-ascii_font_sizes (struct outp_class *this unused, int *n_valid_sizes)
+static int *
+ascii_font_sizes (struct outp_class *this UNUSED, int *n_valid_sizes)
 {
   static int valid_sizes[] = {12, 12, 0, 0};
 
@@ -206,7 +208,7 @@ ascii_font_sizes (struct outp_class *this unused, int *n_valid_sizes)
   return valid_sizes;
 }
 
-int
+static int
 ascii_preopen_driver (struct outp_driver *this)
 {
   struct ascii_driver_ext *x;
@@ -235,6 +237,7 @@ ascii_preopen_driver (struct outp_driver *this)
     ls_null (&x->fonts[i]);
   x->overstrike_style = OVS_SINGLE;
   x->carriage_return_style = CRS_BS;
+  x->squeeze_blank_lines = 0;
   x->file.filename = NULL;
   x->file.mode = "wb";
   x->file.file = NULL;
@@ -255,7 +258,7 @@ ascii_preopen_driver (struct outp_driver *this)
   return 1;
 }
 
-int
+static int
 ascii_postopen_driver (struct outp_driver *this)
 {
   struct ascii_driver_ext *x = this->ext;
@@ -380,7 +383,7 @@ ascii_postopen_driver (struct outp_driver *this)
   return 1;
 }
 
-int
+static int
 ascii_close_driver (struct outp_driver *this)
 {
   struct ascii_driver_ext *x = this->ext;
@@ -438,11 +441,12 @@ static struct outp_option option_tab[] =
     {"overstrike-style", 3, 0},
     {"tab-width", nonneg_int_arg, 4},
     {"carriage-return-style", 4, 0},
+    {"squeeze", boolean_arg, 2},
     {"", 0, 0},
   };
 static struct outp_option_info option_info;
 
-void
+static void
 ascii_option (struct outp_driver *this, const char *key,
              const struct string *val)
 {
@@ -469,7 +473,6 @@ ascii_option (struct outp_driver *this, const char *key,
     }
 
   cat = outp_match_keyword (key, option_tab, &option_info, &subcat);
-
   switch (cat)
     {
     case 0:
@@ -592,6 +595,7 @@ ascii_option (struct outp_driver *this, const char *key,
            break;
          default:
            assert (0);
+            abort ();
          }
        ls_create (ascii_pool, s, value);
       }
@@ -623,11 +627,14 @@ ascii_option (struct outp_driver *this, const char *key,
        switch (subcat)
          {
          case 0:
-           x->headers = 0;
+           x->headers = setting;
            break;
          case 1:
            x->paginate = setting;
            break;
+          case 2:
+            x->squeeze_blank_lines = setting;
+            break;
          default:
            assert (0);
          }
@@ -668,7 +675,7 @@ preclose (struct file_ext *f)
   return 1;
 }
 
-int
+static int
 ascii_open_page (struct outp_driver *this)
 {
   struct ascii_driver_ext *x = this->ext;
@@ -727,9 +734,9 @@ expand_line (struct ascii_driver_ext *x, int i, int l)
 #define B(STYLE) (STYLE<<LNS_BOTTOM)
 #define R(STYLE) (STYLE<<LNS_RIGHT)
 
-void
+static void
 ascii_line_horz (struct outp_driver *this, const struct rect *r,
-                const struct color *c unused, int style)
+                const struct color *c UNUSED, int style)
 {
   struct ascii_driver_ext *ext = this->ext;
   int x1 = r->x1 / this->horiz;
@@ -761,9 +768,9 @@ ascii_line_horz (struct outp_driver *this, const struct rect *r,
     draw_line (x, y1, (style << LNS_LEFT) | (style << LNS_RIGHT));
 }
 
-void
+static void
 ascii_line_vert (struct outp_driver *this, const struct rect *r,
-                const struct color *c unused, int style)
+                const struct color *c UNUSED, int style)
 {
   struct ascii_driver_ext *ext = this->ext;
   int x1 = r->x1 / this->horiz;
@@ -796,9 +803,9 @@ ascii_line_vert (struct outp_driver *this, const struct rect *r,
     draw_line (x1, y, (style << LNS_TOP) | (style << LNS_BOTTOM));
 }
 
-void
+static void
 ascii_line_intersection (struct outp_driver *this, const struct rect *r,
-                        const struct color *c unused,
+                        const struct color *c UNUSED,
                         const struct outp_styles *style)
 {
   struct ascii_driver_ext *ext = this->ext;
@@ -826,47 +833,33 @@ ascii_line_intersection (struct outp_driver *this, const struct rect *r,
   draw_line (x, y, l);
 }
 
-void
-ascii_line_width (struct outp_driver *this, int *width, int *height)
-{
-  int i;
-
-  assert (this->driver_open && this->page_open);
-  width[0] = height[0] = 0;
-  for (i = 1; i < OUTP_L_COUNT; i++)
-    {
-      width[i] = this->horiz;
-      height[i] = this->vert;
-    }
-}
-
 /* FIXME: Later we could set this up so that for certain devices it
    performs shading? */
-void
-ascii_box (struct outp_driver *this unused, const struct rect *r unused,
-          const struct color *bord unused, const struct color *fill unused)
+static void
+ascii_box (struct outp_driver *this UNUSED, const struct rect *r UNUSED,
+          const struct color *bord UNUSED, const struct color *fill UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
 
 /* Polylines not supported. */
-void
-ascii_polyline_begin (struct outp_driver *this unused, const struct color *c unused)
+static void
+ascii_polyline_begin (struct outp_driver *this UNUSED, const struct color *c UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
-void
-ascii_polyline_point (struct outp_driver *this unused, int x unused, int y unused)
+static void
+ascii_polyline_point (struct outp_driver *this UNUSED, int x UNUSED, int y UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
-void
-ascii_polyline_end (struct outp_driver *this unused)
+static void
+ascii_polyline_end (struct outp_driver *this UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
 
-void
+static void
 ascii_text_set_font_by_name (struct outp_driver * this, const char *s)
 {
   struct ascii_driver_ext *x = this->ext;
@@ -887,7 +880,7 @@ ascii_text_set_font_by_name (struct outp_driver * this, const char *s)
     x->cur_font = OUTP_F_B;
 }
 
-void
+static void
 ascii_text_set_font_by_position (struct outp_driver *this, int pos)
 {
   struct ascii_driver_ext *x = this->ext;
@@ -895,13 +888,13 @@ ascii_text_set_font_by_position (struct outp_driver *this, int pos)
   x->cur_font = pos >= 0 && pos < 4 ? pos : 0;
 }
 
-void
-ascii_text_set_font_by_family (struct outp_driver *this unused, const char *s unused)
+static void
+ascii_text_set_font_by_family (struct outp_driver *this UNUSED, const char *s UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
 
-const char *
+static const char *
 ascii_text_get_font_name (struct outp_driver *this)
 {
   struct ascii_driver_ext *x = this->ext;
@@ -923,21 +916,21 @@ ascii_text_get_font_name (struct outp_driver *this)
   abort ();
 }
 
-const char *
-ascii_text_get_font_family (struct outp_driver *this unused)
+static const char *
+ascii_text_get_font_family (struct outp_driver *this UNUSED)
 {
   assert (this->driver_open && this->page_open);
   return "";
 }
 
-int
+static int
 ascii_text_set_size (struct outp_driver *this, int size)
 {
   assert (this->driver_open && this->page_open);
   return size == this->vert;
 }
 
-int
+static int
 ascii_text_get_size (struct outp_driver *this, int *em_width)
 {
   assert (this->driver_open && this->page_open);
@@ -1051,7 +1044,7 @@ delineate (struct outp_driver *this, struct outp_text *t, int draw)
   t->v = (temp.y * this->vert) - t->y;
 }
 
-void
+static void
 ascii_text_metrics (struct outp_driver *this, struct outp_text *t)
 {
   assert (this->driver_open && this->page_open);
@@ -1064,7 +1057,7 @@ ascii_text_metrics (struct outp_driver *this, struct outp_text *t)
     delineate (this, t, 0);
 }
 
-void
+static void
 ascii_text_draw (struct outp_driver *this, struct outp_text *t)
 {
   /* FIXME: orientations not supported. */
@@ -1224,6 +1217,7 @@ output_shorts (struct outp_driver *this,
              break;
            default:
              assert (0);
+              abort ();
            }
          if (!on)
            {
@@ -1252,6 +1246,7 @@ output_shorts (struct outp_driver *this,
                    break;
                  default:
                    assert (0);
+                    abort ();
                  }
              else
                {
@@ -1338,6 +1333,7 @@ return_carriage (struct outp_driver *this, int n_chars)
       break;
     default:
       assert (0);
+      abort ();
     }
 }
 
@@ -1347,9 +1343,8 @@ static void
 output_lines (struct outp_driver *this, int first, int count)
 {
   struct ascii_driver_ext *ext = this->ext;
+  int line_num;
 
-  unsigned short *p = &ext->page[ext->w * first];
-  int *len = &ext->line_len[first];
   struct len_string *newline = &ext->ops[OPS_NEWLINE];
 
   int n_chars;
@@ -1358,15 +1353,24 @@ output_lines (struct outp_driver *this, int first, int count)
   if (NULL == ext->file.file)
     return;
 
-  while (count--)              /* Iterate over all the lines to be output. */
+  /* Iterate over all the lines to be output. */
+  for (line_num = first; line_num < first + count; line_num++)
     {
-      unsigned short *end_p;
+      unsigned short *p = &ext->page[ext->w * line_num];
+      unsigned short *end_p = p + ext->line_len[line_num];
       unsigned short *bp, *ep;
       unsigned short attr = 0;
 
-      end_p = p + *len++;
       assert (end_p >= p);
 
+      /* Squeeze multiple blank lines into a single blank line if
+         requested. */
+      if (ext->squeeze_blank_lines
+          && line_num > first
+          && ext->line_len[line_num] == 0
+          && ext->line_len[line_num - 1] == 0)
+        continue;
+
       /* Output every character in the line in the appropriate
          manner. */
       n_passes = 1;
@@ -1403,6 +1407,7 @@ output_lines (struct outp_driver *this, int first, int count)
                  break;
                default:
                  assert (0);
+                  abort ();
                }
              if (off)
                output_string (this, ls_value (off), ls_end (off));
@@ -1427,6 +1432,7 @@ output_lines (struct outp_driver *this, int first, int count)
                  break;
                default:
                  assert (0);
+                  abort ();
                }
              if (on)
                output_string (this, ls_value (on), ls_end (on));
@@ -1461,6 +1467,9 @@ output_lines (struct outp_driver *this, int first, int count)
                  ch = *ep;
                  n_passes = 3;
                  break;
+                default:
+                  assert (0);
+                  abort ();
                }
              output_char (this, 1, ch);
              n_chars += ep - bp + 1;
@@ -1484,13 +1493,12 @@ output_lines (struct outp_driver *this, int first, int count)
              ep = bp;
            }
        }
-      p += ext->w;
 
       output_string (this, ls_value (newline), ls_end (newline));
     }
 }
 
-int
+static int
 ascii_close_page (struct outp_driver *this)
 {
   static unsigned char *s;
@@ -1580,7 +1588,8 @@ ascii_close_page (struct outp_driver *this)
       cp += nl_len;
     }
   memcpy (cp, ls_value (&x->ops[OPS_FORMFEED]), ff_len);
-  output_string (this, s, &s[total_len]);
+  if ( x->paginate ) 
+         output_string (this, s, &s[total_len]);
   if (line_p != line_buf && !commit_line_buf (this))
     return 0;