Rewrite expression code.
[pspp-builds.git] / src / ascii.c
index d1818aadf7cdf92ee17edbc32ffcc7d82bb01471..d98ab67b4ed7212036c07d83bf37c47e7036070b 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>
@@ -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
   {
@@ -157,9 +165,9 @@ 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. */
@@ -167,34 +175,38 @@ 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 struct outp_option_info *option_info;
+
 static int
 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)
 {
-  pool_destroy (ascii_pool);
+  free(option_info->initial);
+  free(option_info->options);
+  free(option_info);
+  free(s);
   return 1;
 }
 
@@ -246,11 +258,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 +295,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 +358,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 +396,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);
@@ -444,7 +466,6 @@ static struct outp_option option_tab[] =
     {"squeeze", boolean_arg, 2},
     {"", 0, 0},
   };
-static struct outp_option_info option_info;
 
 static void
 ascii_option (struct outp_driver *this, const char *key,
@@ -454,7 +475,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,11 +489,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:
@@ -578,7 +599,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:
@@ -595,18 +616,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:
@@ -648,9 +670,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));
@@ -663,9 +685,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));
@@ -678,7 +700,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 +711,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 +735,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 +789,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 +824,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 +856,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 +984,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 +1114,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 +1139,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 +1148,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
@@ -1180,12 +1209,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;
            }
@@ -1193,13 +1222,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;
 
@@ -1216,6 +1245,7 @@ output_shorts (struct outp_driver *this,
              break;
            default:
              assert (0);
+              abort ();
            }
          if (!on)
            {
@@ -1244,6 +1274,7 @@ output_shorts (struct outp_driver *this,
                    break;
                  default:
                    assert (0);
+                    abort ();
                  }
              else
                {
@@ -1330,6 +1361,7 @@ return_carriage (struct outp_driver *this, int n_chars)
       break;
     default:
       assert (0);
+      abort ();
     }
 }
 
@@ -1341,7 +1373,7 @@ output_lines (struct outp_driver *this, int first, int count)
   struct ascii_driver_ext *ext = this->ext;
   int line_num;
 
-  struct len_string *newline = &ext->ops[OPS_NEWLINE];
+  struct fixed_string *newline = &ext->ops[OPS_NEWLINE];
 
   int n_chars;
   int n_passes;
@@ -1352,8 +1384,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 +1396,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
@@ -1388,7 +1421,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)
                {
@@ -1403,16 +1436,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)
                {
@@ -1427,9 +1461,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 +1498,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,14 +1523,14 @@ 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));
     }
 }
 
+
 static int
 ascii_close_page (struct outp_driver *this)
 {
-  static unsigned char *s;
   static int s_len;
 
   struct ascii_driver_ext *x = this->ext;
@@ -1519,7 +1555,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 +1585,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 +1598,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,21 +1613,46 @@ 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;
 }
 
+
+
+void ascii_chart_initialise(struct outp_class *c UNUSED, 
+                           struct chart *ch UNUSED);
+
+void ascii_chart_finalise(struct outp_class *c UNUSED, 
+                         struct chart *ch UNUSED);
+
+
+void
+ascii_chart_initialise(struct outp_class *c UNUSED, struct chart *ch )
+{
+  msg(MW, _("Charts are unsupported with ascii drivers."));
+  ch->lp = 0;
+}
+
+void 
+ascii_chart_finalise(struct outp_class *c UNUSED, struct chart *ch UNUSED)
+{
+  
+}
+
 struct outp_class ascii_class =
 {
   "ascii",
@@ -1630,4 +1691,7 @@ struct outp_class ascii_class =
   ascii_text_get_size,
   ascii_text_metrics,
   ascii_text_draw,
+
+  ascii_chart_initialise,
+  ascii_chart_finalise
 };