Adopt use of gnulib for portability.
[pspp-builds.git] / src / tab.c
index acfe3525063c543a901adf2cefdc079e690a8982..47fd0b92419ad47ae724ed556212d460cce22b3e 100644 (file)
--- a/src/tab.c
+++ b/src/tab.c
 
    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 "tab.h"
 #include <ctype.h>
-#include <assert.h>
 #include <stdarg.h>
 #include <limits.h>
 #include <stdlib.h>
+#include "error.h"
 #include "alloc.h"
 #include "command.h"
 #include "format.h"
 #include "som.h"
 #include "var.h"
 
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
 #include "debug-print.h"
 \f
 struct som_table_class tab_table_class;
 
-#if DEBUGGING
-#define DEFFIRST(NAME, LABEL) LABEL,
-#define DEFTAB(NAME, LABEL) LABEL,
-/*
-static const char *tab_names[] =
-  {
-#include "tab.def"
-  };
-*/
-#undef DEFFIRST
-#undef DEFTAB
-#endif
-
 /* Creates a table with NC columns and NR rows.  If REALLOCABLE is
    nonzero then the table's size can be increased later; otherwise,
    its size can only be reduced. */
@@ -115,6 +105,7 @@ tab_destroy (struct tab_table *t)
 {
   assert (t != NULL);
   pool_destroy (t->container);
+  t=0;
 }
 
 /* Sets the width and height of a table, in columns and rows,
@@ -168,7 +159,7 @@ tab_realloc (struct tab_table *t, int nc, int nr)
       int mr1 = min (nr, t->nr);
       int mc1 = min (nc, t->nc);
       
-      struct len_string *new_cc;
+      struct fixed_string *new_cc;
       unsigned char *new_ct;
       int r;
 
@@ -222,6 +213,12 @@ void
 tab_headers (struct tab_table *table, int l, int r, int t, int b)
 {
   assert (table != NULL);
+  assert (l < table->nc);
+  assert (r < table->nc);
+  assert (t < table->nr);
+  assert (b < table->nr);
+
+
   table->l = l;
   table->r = r;
   table->t = t;
@@ -251,6 +248,7 @@ tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
   int y;
 
   assert (t != NULL);
+
 #if GLOBAL_DEBUGGING
   if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
       || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
@@ -270,6 +268,12 @@ tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
   y1 += t->row_ofs;
   y2 += t->row_ofs;
 
+  assert (x  > 0);
+  assert (x  < t->nc);
+  assert (y1 >= 0);
+  assert (y2 >= y1);
+  assert (y2 <=  t->nr);
+
   if (style != -1)
     {
       if ((style & TAL_SPACING) == 0)
@@ -287,25 +291,17 @@ tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
   int x;
 
   assert (t != NULL);
-#if GLOBAL_DEBUGGING
-  if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc 
-      || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
-      || y + t->row_ofs < 0 || y + t->row_ofs > t->nr)
-    {
-      printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d "
-               "in table size (%d,%d)\n"),
-             x1, t->col_ofs, x1 + t->col_ofs,
-             x2, t->col_ofs, x2 + t->col_ofs,
-             y, t->row_ofs, y + t->row_ofs,
-             t->nc, t->nr);
-      return;
-    }
-#endif
 
   x1 += t->col_ofs;
   x2 += t->col_ofs;
   y += t->row_ofs;
 
+  assert (y >= 0);
+  assert (y < t->nr);
+  assert (x2 >= x1 );
+  assert (x1 >= 0 );
+  assert (x2 < t->nc);
+
   if (style != -1)
     {
       if ((style & TAL_SPACING) == 0)
@@ -326,6 +322,7 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
         int x1, int y1, int x2, int y2)
 {
   assert (t != NULL);
+
 #if GLOBAL_DEBUGGING
   if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc 
       || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
@@ -348,6 +345,13 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
   y1 += t->row_ofs;
   y2 += t->row_ofs;
 
+  assert (x2 >= x1);
+  assert (y2 >= y1);
+  assert (x1 >= 0);
+  assert (y1 >= 0);
+  assert (x2 < t->nc);
+  assert (y2 < t->nr);
+
   if (f_h != -1)
     {
       int x;
@@ -409,7 +413,7 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
    the resultant string into S in TABLE's pool. */
 static void
 text_format (struct tab_table *table, int opt, const char *text, va_list args,
-            struct len_string *s)
+            struct fixed_string *s)
 {
   int len;
   
@@ -425,7 +429,8 @@ text_format (struct tab_table *table, int opt, const char *text, va_list args,
   else
     len = strlen (text);
 
-  ls_create_buffer (table->container, s, text, len);
+  ls_create_buffer (s, text, len);
+  pool_register (table->container, free, s->string);
   
   if (opt & TAT_PRINTF)
     local_free (text);
@@ -563,7 +568,6 @@ tab_value (struct tab_table *table, int c, int r, unsigned char opt,
           const union value *v, const struct fmt_spec *f)
 {
   char *contents;
-  union value temp_val;
 
   assert (table != NULL && v != NULL && f != NULL);
 #if GLOBAL_DEBUGGING
@@ -584,11 +588,6 @@ tab_value (struct tab_table *table, int c, int r, unsigned char opt,
   ls_init (&table->cc[c + r * table->cf], contents, f->w);
   table->ct[c + r * table->cf] = opt;
   
-  if (formats[f->type].cat & FCAT_STRING)
-    {
-      temp_val.c = (char *) v->s;
-      v = &temp_val;
-    }
   data_out (contents, f, v);
 }
 
@@ -602,12 +601,16 @@ tab_float (struct tab_table *table, int c, int r, unsigned char opt,
   char buf[40], *cp;
   
   struct fmt_spec f;
+  union value double_value;
 
   assert (table != NULL && w <= 40);
   
-  f.type = FMT_F;
-  f.w = w;
-  f.d = d;
+  assert (c >= 0);
+  assert (c < table->nc);
+  assert (r >= 0);
+  assert (r < table->nr);
+
+  f = make_output_format (FMT_F, w, d);
   
 #if GLOBAL_DEBUGGING
   if (c + table->col_ofs < 0 || r + table->row_ofs < 0
@@ -623,7 +626,9 @@ tab_float (struct tab_table *table, int c, int r, unsigned char opt,
     }
 #endif
 
-  data_out (buf, &f, (union value *) &val);
+  double_value.f = val;
+  data_out (buf, &f, &double_value);
+
   cp = buf;
   while (isspace ((unsigned char) *cp) && cp < &buf[w])
     cp++;
@@ -643,6 +648,13 @@ tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text,
   va_list args;
 
   assert (table != NULL && text != NULL);
+
+  assert (c >= 0 );
+  assert (r >= 0 );
+  assert (c < table->nc);
+  assert (r < table->nr);
+  
+
 #if GLOBAL_DEBUGGING
   if (c + table->col_ofs < 0 || r + table->row_ofs < 0
       || c + table->col_ofs >= table->nc
@@ -672,6 +684,14 @@ tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
   struct tab_joined_cell *j;
 
   assert (table != NULL && text != NULL);
+
+  assert (x1 + table->col_ofs >= 0);
+  assert (y1 + table->row_ofs >= 0);
+  assert (y2 >= y1);
+  assert (x2 >= x1);
+  assert (y2 + table->row_ofs < table->nr);
+  assert (x2 + table->col_ofs < table->nc);
+
 #if GLOBAL_DEBUGGING
   if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
       || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
@@ -707,7 +727,7 @@ tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
   opt |= TAB_JOIN;
   
   {
-    struct len_string *cc = &table->cc[x1 + y1 * table->cf];
+    struct fixed_string *cc = &table->cc[x1 + y1 * table->cf];
     unsigned char *ct = &table->ct[x1 + y1 * table->cf];
     const int ofs = table->cf - (x2 - x1);
 
@@ -732,7 +752,7 @@ tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
 void
 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
-        struct len_string *string)
+        struct fixed_string *string)
 {
   assert (table != NULL && string != NULL);
   
@@ -802,8 +822,13 @@ tab_output_text (int options, const char *buf, ...)
        {
          if (!d->page_open)
            d->class->open_page (d);
-         
-         d->class->text_set_font_by_name (d, "FIXED");
+
+          if (d->class->text_set_font_by_name != NULL)
+            d->class->text_set_font_by_name (d, "FIXED");
+          else 
+            {
+              /* FIXME */
+            }
        }
     }
 
@@ -820,7 +845,12 @@ tab_output_text (int options, const char *buf, ...)
       struct outp_driver *d;
 
       for (d = outp_drivers (NULL); d; d = outp_drivers (d))
-       d->class->text_set_font_by_name (d, "PROP");
+        if (d->class->text_set_font_by_name != NULL)
+          d->class->text_set_font_by_name (d, "PROP");
+        else 
+          {
+            /* FIXME */
+          }
     }
   
   if (options & TAT_PRINTF)
@@ -839,11 +869,12 @@ tab_flags (struct tab_table *t, unsigned flags)
 void
 tab_submit (struct tab_table *t)
 {
-  struct som_table s;
+  struct som_entity s;
 
   assert (t != NULL);
   s.class = &tab_table_class;
   s.ext = t;
+  s.type = SOM_TABLE;
   som_submit (&s);
   tab_destroy (t);
 }
@@ -898,9 +929,11 @@ int tab_hit;
 
 /* Set the current table to TABLE. */
 static void
-tabi_table (struct som_table *table)
+tabi_table (struct som_entity *table)
 {
   assert (table != NULL);
+  assert (table->type == SOM_TABLE);
+
   t = table->ext;
   tab_offset (t, 0, 0);
   
@@ -1105,6 +1138,45 @@ tabi_flags (unsigned *flags)
   *flags = t->flags;
 }
 
+/* Returns true if the table will fit in the given page WIDTH,
+   false otherwise. */
+static bool
+tabi_fits_width (int width) 
+{
+  int i;
+
+  for (i = t->l; i < t->nc - t->r; i++)
+    if (t->wl + t->wr + t->w[i] > width)
+      return false;
+
+  return true;
+}
+
+/* Returns true if the table will fit in the given page LENGTH,
+   false otherwise. */
+static bool
+tabi_fits_length (int length) 
+{
+  int i;
+
+  for (i = t->t; i < t->nr - t->b; i++)
+    if (t->ht + t->hb + t->h[i] > length)
+      return false;
+
+  return true;
+}
+
+/* Sets the number of header rows/columns on the left, right, top,
+   and bottom sides to HL, HR, HT, and HB, respectively. */
+static void
+tabi_set_headers (int hl, int hr, int ht, int hb)
+{
+  t->l = hl;
+  t->r = hr;
+  t->t = ht;
+  t->b = hb;
+}
+
 /* Render title for current table, with major index X and minor index
    Y.  Y may be zero, or X and Y may be zero, but X should be nonzero
    if Y is nonzero. */
@@ -1127,7 +1199,7 @@ tabi_title (int x, int y)
   cp = stpcpy (cp, ".  ");
   if (!ls_empty_p (&t->title))
     {
-      memcpy (cp, ls_value (&t->title), ls_length (&t->title));
+      memcpy (cp, ls_c_str (&t->title), ls_length (&t->title));
       cp += ls_length (&t->title);
     }
   *cp = 0;
@@ -1147,50 +1219,47 @@ tabi_title (int x, int y)
 
 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
 
-/* Execute BODY for each value of X from A to B exclusive. */
-#define UNROLL_LOOP(X, A, B, BODY)             \
-       do                                      \
-         {                                     \
-           for (X = A; X < B; X++)             \
-             {                                 \
-               BODY                            \
-             }                                 \
-         }                                     \
-       while (0)
-
-/* Execute PREP, then BODY for each specified value of X: A1...A2, B1...B2,
-   C1...C2, in each case not including the second value. */
-#define UNROLL_3_LOOPS(X, A1, A2, B1, B2, C1, C2, BODY)        \
-       do                                              \
-         {                                             \
-           UNROLL_LOOP (X, A1, A2, BODY);              \
-           UNROLL_LOOP (X, B1, B2, BODY);              \
-           UNROLL_LOOP (X, C1, C2, BODY);              \
-         }                                             \
-       while (0)
-
 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
    X2 and row Y2 are not included in the rectangle, at the current
    position on the current output device.  Draws headers as well. */
 static void
 tabi_render (int x1, int y1, int x2, int y2)
 {
-  int y, r;
+  int i, y;
+  int ranges[3][2];
   
   tab_hit++;
+
   y = d->cp_y;
   if (!(t->flags & SOMF_NO_TITLE))
     y += d->font_height;
-  UNROLL_3_LOOPS (r, 0, t->t * 2 + 1, y1 * 2 + 1, y2 * 2,
-                 (t->nr - t->b) * 2, t->nr * 2 + 1,
-
-                 int x = d->cp_x;
-                 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
-                 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
-                 x += render_strip (x, y, r, (t->nc - t->r) * 2,
-                                    t->nc * 2 + 1, y1, y2);
-                 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
-                 );
+
+  /* Top headers. */
+  ranges[0][0] = 0;
+  ranges[0][1] = t->t * 2 + 1;
+
+  /* Requested rows. */
+  ranges[1][0] = y1 * 2 + 1;
+  ranges[1][1] = y2 * 2;
+
+  /* Bottom headers. */
+  ranges[2][0] = (t->nr - t->b) * 2;
+  ranges[2][1] = t->nr * 2 + 1;
+
+  for (i = 0; i < 3; i++) 
+    {
+      int r;
+
+      for (r = ranges[i][0]; r < ranges[i][1]; r++) 
+        {
+          int x = d->cp_x;
+          x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
+          x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
+          x += render_strip (x, y, r, (t->nc - t->r) * 2,
+                             t->nc * 2 + 1, y1, y2);
+          y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2]; 
+        }
+    }
 }
 
 struct som_table_class tab_table_class =
@@ -1208,9 +1277,12 @@ struct som_table_class tab_table_class =
     NULL,
     tabi_cumulate,
     tabi_flags,
+    tabi_fits_width,
+    tabi_fits_length,
     
     NULL,
     NULL,
+    tabi_set_headers,
 
     tabi_title,
     tabi_render,
@@ -1229,7 +1301,7 @@ struct som_table_class tab_table_class =
 
    FIXME: Doesn't use r1?  Huh?  */
 static int
-render_strip (int x, int y, int r, int c1, int c2, int r1 unused, int r2)
+render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
 {
   int x_origin = x;
 
@@ -1305,14 +1377,13 @@ render_strip (int x, int y, int r, int c1, int c2, int r1 unused, int r2)
                    }
                } else {
                  struct tab_joined_cell *j =
-                   (struct tab_joined_cell *) ls_value (&t->cc[index]);
+                   (struct tab_joined_cell *) ls_c_str (&t->cc[index]);
 
                  if (j->hit != tab_hit)
                    {
                      j->hit = tab_hit;
 
-                     if (j->x1 == c / 2 && j->y1 == r / 2
-                         && j->x2 <= c2 && j->y2 <= r2)
+                     if (j->x1 == c / 2 && j->y1 == r / 2)
                        {
                          struct outp_text text;
 
@@ -1326,15 +1397,15 @@ render_strip (int x, int y, int r, int c1, int c2, int r1 unused, int r2)
                            int c;
 
                            for (c = j->x1, text.h = -t->wrv[j->x2];
-                                c < j->x2; c++)
-                             text.h += t->w[c] + t->wrv[c + 1];
+                                c < j->x2 && c < c2 / 2; c++) 
+                                text.h += t->w[c] + t->wrv[c + 1]; 
                          }
                          
                          {
                            int r;
 
                            for (r = j->y1, text.v = -t->hrh[j->y2];
-                                r < j->y2; r++)
+                                r < j->y2 && r < r2 / 2; r++)
                              text.v += t->h[r] + t->hrh[r + 1];
                          }
                          d->class->text_draw (d, &text);