Adopt use of gnulib for portability.
[pspp-builds.git] / src / ascii.c
index 10345005275a412eaab903f72c64a137d1353cd9..63aa4c1d82465fa96bc1a0c844c5664db755ea44 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 "error.h"
 #include <ctype.h>
 #include <errno.h>
 #include <limits.h>
@@ -32,6 +32,9 @@
 #include "pool.h"
 #include "version.h"
 
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
 /* ASCII driver options: (defaults listed first)
 
    output-file="pspp.list"
@@ -49,6 +52,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
@@ -140,6 +144,14 @@ enum
     FSTY_COUNT = 6             /* Number of font styles. */
   };
 
+/* A line of text. */
+struct line 
+  {
+    unsigned short *chars;      /* Characters and attributes. */
+    int char_cnt;               /* Length. */
+    int char_cap;               /* Allocated bytes. */
+  };
+
 /* ASCII output driver extension record. */
 struct ascii_driver_ext
   {
@@ -156,48 +168,53 @@ struct ascii_driver_ext
     int bottom_margin;         /* Bottom margin in lines. */
     int paginate;              /* 1=insert formfeeds. */
     int tab_width;             /* Width of a tab; 0 not to use tabs. */
-    struct len_string ops[OPS_COUNT]; /* Basic output strings. */
-    struct len_string box[LNS_COUNT]; /* Line & box drawing characters. */
-    struct len_string fonts[FSTY_COUNT]; /* Font styles; NULL=overstrike. */
+    struct fixed_string ops[OPS_COUNT]; /* Basic output strings. */
+    struct fixed_string box[LNS_COUNT]; /* Line & box drawing characters. */
+    struct fixed_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. */
     int page_number;           /* Current page number. */
-    unsigned short *page;      /* Page content. */
-    int page_size;             /* Number of bytes allocated for page, attr. */
-    int *line_len;             /* Length of each line in page, attr. */
-    int line_len_size;         /* Number of ints allocated for line_len. */
+    struct line *lines;         /* Page content. */
+    int lines_cap;              /* Number of lines allocated. */
     int w, l;                  /* Actual width & length w/o margins, etc. */
-    int n_output;              /* Number of lines output so far. */
     int cur_font;              /* Current font by OUTP_F_*. */
 #if GLOBAL_DEBUGGING
     int debug;                 /* Set by som_text_draw(). */
 #endif
   };
 
-static struct pool *ascii_pool;
-
 static int postopen (struct file_ext *);
 static int preclose (struct file_ext *);
 
+static struct outp_option_info *option_info;
+
 static int
-ascii_open_global (struct outp_class *this unused)
+ascii_open_global (struct outp_class *this UNUSED)
 {
-  ascii_pool = pool_create ();
+  option_info = xmalloc ( sizeof (struct outp_option_info ) ) ;
+  option_info->initial = 0;
+  option_info->options = 0;
   return 1;
 }
 
+
+static unsigned char *s=0;
 static int
-ascii_close_global (struct outp_class *this unused)
+ascii_close_global (struct outp_class *this UNUSED)
 {
-  pool_destroy (ascii_pool);
+  free(option_info->initial);
+  free(option_info->options);
+  free(option_info);
+  free(s);
   return 1;
 }
 
 static int *
-ascii_font_sizes (struct outp_class *this unused, int *n_valid_sizes)
+ascii_font_sizes (struct outp_class *this UNUSED, int *n_valid_sizes)
 {
   static int valid_sizes[] = {12, 12, 0, 0};
 
@@ -235,6 +252,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;
@@ -243,11 +261,8 @@ ascii_preopen_driver (struct outp_driver *this)
   x->file.postopen = postopen;
   x->file.preclose = preclose;
   x->page_number = 0;
-  x->page = NULL;
-  x->page_size = 0;
-  x->line_len = NULL;
-  x->line_len_size = 0;
-  x->n_output = 0;
+  x->lines = NULL;
+  x->lines_cap = 0;
   x->cur_font = OUTP_F_R;
 #if GLOBAL_DEBUGGING
   x->debug = 0;
@@ -283,11 +298,11 @@ ascii_postopen_driver (struct outp_driver *this)
   this->length = x->l * this->vert;
   
   if (ls_null_p (&x->ops[OPS_FORMFEED]))
-    ls_create (ascii_pool, &x->ops[OPS_FORMFEED], "\f");
+    ls_create (&x->ops[OPS_FORMFEED], "\f");
   if (ls_null_p (&x->ops[OPS_NEWLINE])
-      || !strcmp (ls_value (&x->ops[OPS_NEWLINE]), "default"))
+      || !strcmp (ls_c_str (&x->ops[OPS_NEWLINE]), "default"))
     {
-      ls_create (ascii_pool, &x->ops[OPS_NEWLINE], "\n");
+      ls_create (&x->ops[OPS_NEWLINE], "\n");
       x->file.mode = "wt";
     }
   
@@ -346,7 +361,7 @@ ascii_postopen_driver (struct outp_driver *this)
              c[0] = '+';
            break;
          }
-       ls_create (ascii_pool, &x->box[i], c);
+       ls_create (&x->box[i], c);
       }
   }
   
@@ -384,13 +399,26 @@ static int
 ascii_close_driver (struct outp_driver *this)
 {
   struct ascii_driver_ext *x = this->ext;
+  int i;
   
   assert (this->driver_open == 1);
   msg (VM (2), _("%s: Beginning closing..."), this->name);
   
   x = this->ext;
-  free (x->page);
-  free (x->line_len);
+  for (i = 0; i < OPS_COUNT; i++)
+    ls_destroy (&x->ops[i]);
+  for (i = 0; i < LNS_COUNT; i++)
+    ls_destroy (&x->box[i]);
+  for (i = 0; i < FSTY_COUNT; i++)
+    ls_destroy (&x->fonts[i]);
+  if (x->lines != NULL) 
+    {
+      int line;
+      
+      for (line = 0; line < x->lines_cap; line++) 
+        free (x->lines[line].chars);
+      free (x->lines); 
+    }
   fn_close_ext (&x->file);
   free (x->file.filename);
   free (x);
@@ -438,9 +466,9 @@ 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;
 
 static void
 ascii_option (struct outp_driver *this, const char *key,
@@ -450,7 +478,7 @@ ascii_option (struct outp_driver *this, const char *key,
   int cat, subcat;
   const char *value;
 
-  value = ds_value (val);
+  value = ds_c_str (val);
   if (!strncmp (key, "box[", 4))
     {
       char *tail;
@@ -464,11 +492,11 @@ ascii_option (struct outp_driver *this, const char *key,
        }
       if (!ls_null_p (&x->box[indx]))
        msg (SW, _("Duplicate value for key `%s'."), key);
-      ls_create (ascii_pool, &x->box[indx], value);
+      ls_create (&x->box[indx], value);
       return;
     }
 
-  cat = outp_match_keyword (key, option_tab, &option_info, &subcat);
+  cat = outp_match_keyword (key, option_tab, option_info, &subcat);
   switch (cat)
     {
     case 0:
@@ -574,7 +602,7 @@ ascii_option (struct outp_driver *this, const char *key,
       break;
     case string_arg:
       {
-       struct len_string *s;
+       struct fixed_string *s;
        switch (subcat)
          {
          case 0:
@@ -591,18 +619,19 @@ ascii_option (struct outp_driver *this, const char *key,
            break;
          default:
            assert (0);
+            abort ();
          }
-       ls_create (ascii_pool, s, value);
+       ls_create (s, value);
       }
       break;
     case font_string_arg:
       {
        if (!strcmp (value, "overstrike"))
          {
-           ls_destroy (ascii_pool, &x->fonts[subcat]);
+           ls_destroy (&x->fonts[subcat]);
            return;
          }
-       ls_create (ascii_pool, &x->fonts[subcat], value);
+       ls_create (&x->fonts[subcat], value);
       }
       break;
     case boolean_arg:
@@ -622,11 +651,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);
          }
@@ -641,9 +673,9 @@ int
 postopen (struct file_ext *f)
 {
   struct ascii_driver_ext *x = f->param;
-  struct len_string *s = &x->ops[OPS_INIT];
+  struct fixed_string *s = &x->ops[OPS_INIT];
 
-  if (!ls_empty_p (s) && fwrite (ls_value (s), ls_length (s), 1, f->file) < 1)
+  if (!ls_empty_p (s) && fwrite (ls_c_str (s), ls_length (s), 1, f->file) < 1)
     {
       msg (ME, _("ASCII output driver: %s: %s"),
           f->filename, strerror (errno));
@@ -656,9 +688,9 @@ int
 preclose (struct file_ext *f)
 {
   struct ascii_driver_ext *x = f->param;
-  struct len_string *d = &x->ops[OPS_DONE];
+  struct fixed_string *d = &x->ops[OPS_DONE];
 
-  if (!ls_empty_p (d) && fwrite (ls_value (d), ls_length (d), 1, f->file) < 1)
+  if (!ls_empty_p (d) && fwrite (ls_c_str (d), ls_length (d), 1, f->file) < 1)
     {
       msg (ME, _("ASCII output driver: %s: %s"),
           f->filename, strerror (errno));
@@ -671,7 +703,7 @@ static int
 ascii_open_page (struct outp_driver *this)
 {
   struct ascii_driver_ext *x = this->ext;
-  int req_page_size;
+  int i;
 
   assert (this->driver_open && !this->page_open);
   x->page_number++;
@@ -682,21 +714,20 @@ ascii_open_page (struct outp_driver *this)
       return 0;
     }
 
-  req_page_size = x->w * x->l;
-  if (req_page_size > x->page_size || req_page_size / 2 < x->page_size)
-    {
-      x->page_size = req_page_size;
-      x->page = xrealloc (x->page, sizeof *x->page * req_page_size);
-    }
-
-  if (x->l > x->line_len_size)
+  if (x->l > x->lines_cap)
     {
-      x->line_len_size = x->l;
-      x->line_len = xrealloc (x->line_len,
-                             sizeof *x->line_len * x->line_len_size);
+      x->lines = xrealloc (x->lines, sizeof *x->lines * x->l);
+      for (i = x->lines_cap; i < x->l; i++) 
+        {
+          struct line *line = &x->lines[i];
+          line->chars = NULL;
+          line->char_cap = 0;
+        }
+      x->lines_cap = x->l;
     }
 
-  memset (x->line_len, 0, sizeof *x->line_len * x->l);
+  for (i = 0; i < x->l; i++)
+    x->lines[i].char_cnt = 0;
 
   this->page_open = 1;
   return 1;
@@ -707,18 +738,26 @@ ascii_open_page (struct outp_driver *this)
 static inline void
 expand_line (struct ascii_driver_ext *x, int i, int l)
 {
-  int limit = i * x->w + l;
+  struct line *line;
   int j;
 
-  for (j = i * x->w + x->line_len[i]; j < limit; j++)
-    x->page[j] = ' ';
-  x->line_len[i] = l;
+  assert (i < x->lines_cap);
+  line = &x->lines[i];
+  if (l > line->char_cap) 
+    {
+      line->char_cap = l * 2;
+      line->chars = xrealloc (line->chars,
+                              line->char_cap * sizeof *line->chars); 
+    }
+  for (j = line->char_cnt; j < l; j++)
+    line->chars[j] = ' ';
+  line->char_cnt = l;
 }
 
 /* Puts line L at (H,K) in the current output page.  Assumes
    struct ascii_driver_ext named `ext'. */
 #define draw_line(H, K, L)                             \
-       ext->page[ext->w * (K) + (H)] = (L) | 0x800
+        ext->lines[K].chars[H] = (L) | 0x800
 
 /* Line styles for each position. */
 #define T(STYLE) (STYLE<<LNS_TOP)
@@ -728,7 +767,7 @@ expand_line (struct ascii_driver_ext *x, int i, int l)
 
 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;
@@ -753,7 +792,7 @@ ascii_line_horz (struct outp_driver *this, const struct rect *r,
     }
 #endif
 
-  if (ext->line_len[y1] < x2)
+  if (ext->lines[y1].char_cnt < x2)
     expand_line (ext, y1, x2);
 
   for (x = x1; x < x2; x++)
@@ -762,7 +801,7 @@ ascii_line_horz (struct outp_driver *this, const struct rect *r,
 
 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;
@@ -788,7 +827,7 @@ ascii_line_vert (struct outp_driver *this, const struct rect *r,
 #endif
 
   for (y = y1; y < y2; y++)
-    if (ext->line_len[y] <= x1)
+    if (ext->lines[y].char_cnt <= x1)
       expand_line (ext, y, x1 + 1);
 
   for (y = y1; y < y2; y++)
@@ -797,7 +836,7 @@ ascii_line_vert (struct outp_driver *this, const struct rect *r,
 
 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;
@@ -820,7 +859,7 @@ ascii_line_intersection (struct outp_driver *this, const struct rect *r,
   l = ((style->l << LNS_LEFT) | (style->r << LNS_RIGHT)
        | (style->t << LNS_TOP) | (style->b << LNS_BOTTOM));
 
-  if (ext->line_len[y] <= x)
+  if (ext->lines[y].char_cnt <= x)
     expand_line (ext, y, x + 1);
   draw_line (x, y, l);
 }
@@ -828,25 +867,25 @@ ascii_line_intersection (struct outp_driver *this, const struct rect *r,
 /* FIXME: Later we could set this up so that for certain devices it
    performs shading? */
 static void
-ascii_box (struct outp_driver *this unused, const struct rect *r unused,
-          const struct color *bord unused, const struct color *fill unused)
+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. */
 static void
-ascii_polyline_begin (struct outp_driver *this unused, const struct color *c unused)
+ascii_polyline_begin (struct outp_driver *this UNUSED, const struct color *c UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
 static void
-ascii_polyline_point (struct outp_driver *this unused, int x unused, int y unused)
+ascii_polyline_point (struct outp_driver *this UNUSED, int x UNUSED, int y UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
 static void
-ascii_polyline_end (struct outp_driver *this unused)
+ascii_polyline_end (struct outp_driver *this UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
@@ -881,7 +920,7 @@ ascii_text_set_font_by_position (struct outp_driver *this, int pos)
 }
 
 static void
-ascii_text_set_font_by_family (struct outp_driver *this unused, const char *s unused)
+ascii_text_set_font_by_family (struct outp_driver *this UNUSED, const char *s UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
@@ -909,7 +948,7 @@ ascii_text_get_font_name (struct outp_driver *this)
 }
 
 static const char *
-ascii_text_get_font_family (struct outp_driver *this unused)
+ascii_text_get_font_family (struct outp_driver *this UNUSED)
 {
   assert (this->driver_open && this->page_open);
   return "";
@@ -948,7 +987,7 @@ delineate (struct outp_driver *this, struct outp_text *t, int draw)
   int max_y;
 
   /* Current position in string, character following end of string. */
-  const char *s = ls_value (&t->s);
+  const char *s = ls_c_str (&t->s);
   const char *end = ls_end (&t->s);
 
   /* Temporary struct outp_text to pass to low-level function. */
@@ -1078,9 +1117,9 @@ text_draw (struct outp_driver *this, struct outp_text *t)
   unsigned attr = ext->cur_font << 8;
 
   int x = t->x;
-  int y = t->y * ext->w;
+  int y = t->y;
 
-  char *s = ls_value (&t->s);
+  char *s = ls_c_str (&t->s);
 
   /* Expand the line with the assumption that S takes up LEN character
      spaces (sometimes it takes up less). */
@@ -1103,7 +1142,7 @@ text_draw (struct outp_driver *this, struct outp_text *t)
   if (!(t->y < ext->l && x < ext->w))
     return;
   min_len = min (x + ls_length (&t->s), ext->w);
-  if (ext->line_len[t->y] < min_len)
+  if (ext->lines[t->y].char_cnt < min_len)
     expand_line (ext, t->y, min_len);
 
   {
@@ -1112,7 +1151,7 @@ text_draw (struct outp_driver *this, struct outp_text *t)
     if (len + x > ext->w)
       len = ext->w - x;
     while (len--)
-      ext->page[y + x++] = *s++ | attr;
+      ext->lines[y].chars[x++] = *s++ | attr;
   }
 }
 \f
@@ -1173,12 +1212,12 @@ output_shorts (struct outp_driver *this,
     {
       if (*bp & 0x800)
        {
-         struct len_string *box = &ext->box[*bp & 0xff];
+         struct fixed_string *box = &ext->box[*bp & 0xff];
          size_t len = ls_length (box);
 
          if (remaining >= len)
            {
-             memcpy (line_p, ls_value (box), len);
+             memcpy (line_p, ls_c_str (box), len);
              line_p += len;
              remaining -= len;
            }
@@ -1186,13 +1225,13 @@ output_shorts (struct outp_driver *this,
            {
              if (!commit_line_buf (this))
                return 0;
-             output_string (this, ls_value (box), ls_end (box));
+             output_string (this, ls_c_str (box), ls_end (box));
              remaining = LINE_BUF_SIZE - (line_p - line_buf);
            }
        }
       else if (*bp & 0x0300)
        {
-         struct len_string *on;
+         struct fixed_string *on;
          char buf[5];
          int len;
 
@@ -1209,6 +1248,7 @@ output_shorts (struct outp_driver *this,
              break;
            default:
              assert (0);
+              abort ();
            }
          if (!on)
            {
@@ -1237,6 +1277,7 @@ output_shorts (struct outp_driver *this,
                    break;
                  default:
                    assert (0);
+                    abort ();
                  }
              else
                {
@@ -1323,6 +1364,7 @@ return_carriage (struct outp_driver *this, int n_chars)
       break;
     default:
       assert (0);
+      abort ();
     }
 }
 
@@ -1332,10 +1374,9 @@ 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];
+  struct fixed_string *newline = &ext->ops[OPS_NEWLINE];
 
   int n_chars;
   int n_passes;
@@ -1343,15 +1384,25 @@ 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;
+      struct line *line = &ext->lines[line_num];
+      unsigned short *p = line->chars;
+      unsigned short *end_p = p + line->char_cnt;
       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->lines[line_num].char_cnt == 0
+          && ext->lines[line_num - 1].char_cnt == 0)
+        continue;
+
       /* Output every character in the line in the appropriate
          manner. */
       n_passes = 1;
@@ -1373,7 +1424,7 @@ output_lines (struct outp_driver *this, int first, int count)
          /* Turn off old font. */
          if (attr != (OUTP_F_R << 8))
            {
-             struct len_string *off;
+             struct fixed_string *off;
 
              switch (attr)
                {
@@ -1388,16 +1439,17 @@ 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));
+               output_string (this, ls_c_str (off), ls_end (off));
            }
 
          /* Turn on new font. */
          attr = (*bp & 0x0300);
          if (attr != (OUTP_F_R << 8))
            {
-             struct len_string *on;
+             struct fixed_string *on;
 
              switch (attr)
                {
@@ -1412,9 +1464,10 @@ 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));
+               output_string (this, ls_c_str (on), ls_end (on));
            }
 
          ep = bp + 1;
@@ -1446,6 +1499,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;
@@ -1469,16 +1525,15 @@ output_lines (struct outp_driver *this, int first, int count)
              ep = bp;
            }
        }
-      p += ext->w;
 
-      output_string (this, ls_value (newline), ls_end (newline));
+      output_string (this, ls_c_str (newline), ls_end (newline));
     }
 }
 
+
 static int
 ascii_close_page (struct outp_driver *this)
 {
-  static unsigned char *s;
   static int s_len;
 
   struct ascii_driver_ext *x = this->ext;
@@ -1503,7 +1558,7 @@ ascii_close_page (struct outp_driver *this)
        }
       for (cp = s, i = 0; i < x->top_margin; i++)
        {
-         memcpy (cp, ls_value (&x->ops[OPS_NEWLINE]), nl_len);
+         memcpy (cp, ls_c_str (&x->ops[OPS_NEWLINE]), nl_len);
          cp += nl_len;
        }
       output_string (this, s, &s[total_len]);
@@ -1533,7 +1588,7 @@ ascii_close_page (struct outp_driver *this)
          len = min ((int) strlen (outp_title), x->w);
          memcpy (s, outp_title, len);
        }
-      memcpy (&s[x->w], ls_value (&x->ops[OPS_NEWLINE]), nl_len);
+      memcpy (&s[x->w], ls_c_str (&x->ops[OPS_NEWLINE]), nl_len);
       output_string (this, s, &s[total_len]);
 
       memset (s, ' ', x->w);
@@ -1546,14 +1601,14 @@ ascii_close_page (struct outp_driver *this)
          len = min ((int) strlen (string), x->w);
          memcpy (s, string, len);
        }
-      memcpy (&s[x->w], ls_value (&x->ops[OPS_NEWLINE]), nl_len);
+      memcpy (&s[x->w], ls_c_str (&x->ops[OPS_NEWLINE]), nl_len);
       output_string (this, s, &s[total_len]);
       output_string (this, &s[x->w], &s[total_len]);
     }
   if (line_p != line_buf && !commit_line_buf (this))
     return 0;
 
-  output_lines (this, x->n_output, x->l - x->n_output);
+  output_lines (this, 0, x->l);
 
   ff_len = ls_length (&x->ops[OPS_FORMFEED]);
   total_len = x->bottom_margin * nl_len + ff_len;
@@ -1561,21 +1616,39 @@ ascii_close_page (struct outp_driver *this)
     s = xrealloc (s, total_len);
   for (cp = s, i = 0; i < x->bottom_margin; i++)
     {
-      memcpy (cp, ls_value (&x->ops[OPS_NEWLINE]), nl_len);
+      memcpy (cp, ls_c_str (&x->ops[OPS_NEWLINE]), nl_len);
       cp += nl_len;
     }
-  memcpy (cp, ls_value (&x->ops[OPS_FORMFEED]), ff_len);
+  memcpy (cp, ls_c_str (&x->ops[OPS_FORMFEED]), ff_len);
   if ( x->paginate ) 
          output_string (this, s, &s[total_len]);
+
   if (line_p != line_buf && !commit_line_buf (this))
+    {
+    free(s);
+    s=0;
     return 0;
+    }
 
-  x->n_output = 0;
-  
   this->page_open = 0;
   return 1;
 }
 
+
+
+static void
+ascii_chart_initialise(struct outp_driver *d UNUSED, struct chart *ch )
+{
+  msg(MW, _("Charts are unsupported with ascii drivers."));
+  ch->lp = 0;
+}
+
+static void 
+ascii_chart_finalise(struct outp_driver *d UNUSED, struct chart *ch UNUSED)
+{
+  
+}
+
 struct outp_class ascii_class =
 {
   "ascii",
@@ -1614,4 +1687,7 @@ struct outp_class ascii_class =
   ascii_text_get_size,
   ascii_text_metrics,
   ascii_text_draw,
+
+  ascii_chart_initialise,
+  ascii_chart_finalise
 };