Fully implement arbitrary delimiters on DATA LIST, extending the half
[pspp-builds.git] / src / ascii.c
index 72e536b16b0dbe53af90c9c151e2e258df774340..6fa1573be050ae5ade4cf94ad947f03be6f8a266 100644 (file)
@@ -141,6 +141,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
   {
@@ -167,34 +175,28 @@ struct ascii_driver_ext
     /* 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 int
 ascii_open_global (struct outp_class *this UNUSED)
 {
-  ascii_pool = pool_create ();
   return 1;
 }
 
+
 static int
 ascii_close_global (struct outp_class *this UNUSED)
 {
-  pool_destroy (ascii_pool);
   return 1;
 }
 
@@ -246,11 +248,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;
@@ -286,11 +285,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";
     }
   
@@ -349,7 +348,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);
       }
   }
   
@@ -387,13 +386,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);
@@ -454,7 +466,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;
@@ -468,7 +480,7 @@ 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;
     }
 
@@ -595,18 +607,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:
@@ -650,7 +663,7 @@ postopen (struct file_ext *f)
   struct ascii_driver_ext *x = f->param;
   struct len_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));
@@ -665,7 +678,7 @@ preclose (struct file_ext *f)
   struct ascii_driver_ext *x = f->param;
   struct len_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));
@@ -678,7 +691,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++;
@@ -689,21 +702,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)
+  if (x->l > x->lines_cap)
     {
-      x->page_size = req_page_size;
-      x->page = xrealloc (x->page, sizeof *x->page * req_page_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;
     }
 
-  if (x->l > x->line_len_size)
-    {
-      x->line_len_size = x->l;
-      x->line_len = xrealloc (x->line_len,
-                             sizeof *x->line_len * x->line_len_size);
-    }
-
-  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;
@@ -714,18 +726,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)
@@ -760,7 +780,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++)
@@ -795,7 +815,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++)
@@ -827,7 +847,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);
 }
@@ -955,7 +975,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. */
@@ -1085,9 +1105,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). */
@@ -1110,7 +1130,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);
 
   {
@@ -1119,7 +1139,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
@@ -1185,7 +1205,7 @@ output_shorts (struct outp_driver *this,
 
          if (remaining >= len)
            {
-             memcpy (line_p, ls_value (box), len);
+             memcpy (line_p, ls_c_str (box), len);
              line_p += len;
              remaining -= len;
            }
@@ -1193,7 +1213,7 @@ 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);
            }
        }
@@ -1216,6 +1236,7 @@ output_shorts (struct outp_driver *this,
              break;
            default:
              assert (0);
+              abort ();
            }
          if (!on)
            {
@@ -1244,6 +1265,7 @@ output_shorts (struct outp_driver *this,
                    break;
                  default:
                    assert (0);
+                    abort ();
                  }
              else
                {
@@ -1330,6 +1352,7 @@ return_carriage (struct outp_driver *this, int n_chars)
       break;
     default:
       assert (0);
+      abort ();
     }
 }
 
@@ -1352,8 +1375,9 @@ output_lines (struct outp_driver *this, int first, int count)
   /* Iterate over all the lines to be output. */
   for (line_num = first; line_num < first + count; line_num++)
     {
-      unsigned short *p = &ext->page[ext->w * line_num];
-      unsigned short *end_p = p + ext->line_len[line_num];
+      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;
 
@@ -1363,8 +1387,8 @@ output_lines (struct outp_driver *this, int first, int count)
          requested. */
       if (ext->squeeze_blank_lines
           && line_num > first
-          && ext->line_len[line_num] == 0
-          && ext->line_len[line_num - 1] == 0)
+          && 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
@@ -1403,9 +1427,10 @@ 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. */
@@ -1427,9 +1452,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;
@@ -1463,6 +1489,7 @@ output_lines (struct outp_driver *this, int first, int count)
                  break;
                 default:
                   assert (0);
+                  abort ();
                }
              output_char (this, 1, ch);
              n_chars += ep - bp + 1;
@@ -1487,7 +1514,7 @@ output_lines (struct outp_driver *this, int first, int count)
            }
        }
 
-      output_string (this, ls_value (newline), ls_end (newline));
+      output_string (this, ls_c_str (newline), ls_end (newline));
     }
 }
 
@@ -1519,7 +1546,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]);
@@ -1549,7 +1576,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);
@@ -1562,14 +1589,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;
@@ -1577,17 +1604,15 @@ 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))
     return 0;
 
-  x->n_output = 0;
-  
   this->page_open = 0;
   return 1;
 }