Thu Jan 1 23:16:41 2004 Ben Pfaff <blp@gnu.org>
authorBen Pfaff <blp@gnu.org>
Fri, 2 Jan 2004 07:28:39 +0000 (07:28 +0000)
committerBen Pfaff <blp@gnu.org>
Fri, 2 Jan 2004 07:28:39 +0000 (07:28 +0000)
* html.c: (change_attributes) Dead code, removed.
(escape_string) Eliminate code to call change_attributes() that
never actually called it.
(output_tab_table) Get rid of dependence on tab_hit
and struct tab_joined_cell's hit member, which are abominations.

* tab.c: (tab_output_text) Don't call
d->class->text_set_font_by_name if it's a null pointer.
(macro UNROLL_LOOP) Eliminate.
(macro UNROLL_3_LOOPS) Eliminate
(tabi_render) Rewrite not to use the above macros.

Thu Jan  1 23:09:07 2004  Ben Pfaff  <blp@gnu.org>

Start working on a new output driver system, one that doesn't suck
so much, by adding a "device-independent" output driver.  The idea
is to write out only a single output stream, then use separate
processes to translate them into whatever formats we want.  This
is similar to how "groff" works with its various output drivers
(grops, grotty, grodvi, ...).

* Makefile.am: (pspp_SOURCES) Add devind.c, devind.h.

* list.q: (write_all_headers) Stub out devind class.
(clean_up) Ditto.
(determine_layout) Ditto.
(list_cases) Ditto.

* output.c: (outp_init) Add devind class.

* devind.c: New file.

* devind.h: New file.

Thu Jan  1 23:08:14 2004  Ben Pfaff  <blp@gnu.org>

* frequencies.q: (hash_value_alpha) Fixed up the previous change
to use the proper string length.

src/ChangeLog
src/Makefile.am
src/devind.c [new file with mode: 0644]
src/devind.h [new file with mode: 0644]
src/frequencies.q
src/html.c
src/list.q
src/output.c
src/tab.c

index 4eb438ae0fd3977f4baf8d02c6e72bc25f8e54b3..e656ecd0b51ec176bc3c9dd30298b3d25daa30ac 100644 (file)
@@ -1,3 +1,44 @@
+Thu Jan  1 23:16:41 2004  Ben Pfaff  <blp@gnu.org>
+
+       * html.c: (change_attributes) Dead code, removed.
+       (escape_string) Eliminate code to call change_attributes() that
+       never actually called it.
+       (output_tab_table) Get rid of dependence on tab_hit
+       and struct tab_joined_cell's hit member, which are abominations.
+
+       * tab.c: (tab_output_text) Don't call
+       d->class->text_set_font_by_name if it's a null pointer.
+       (macro UNROLL_LOOP) Eliminate.
+       (macro UNROLL_3_LOOPS) Eliminate
+       (tabi_render) Rewrite not to use the above macros.
+
+Thu Jan  1 23:09:07 2004  Ben Pfaff  <blp@gnu.org>
+
+       Start working on a new output driver system, one that doesn't suck
+       so much, by adding a "device-independent" output driver.  The idea
+       is to write out only a single output stream, then use separate
+       processes to translate them into whatever formats we want.  This
+       is similar to how "groff" works with its various output drivers
+       (grops, grotty, grodvi, ...).
+       
+       * Makefile.am: (pspp_SOURCES) Add devind.c, devind.h.
+
+       * list.q: (write_all_headers) Stub out devind class.
+       (clean_up) Ditto.
+       (determine_layout) Ditto.
+       (list_cases) Ditto.
+
+       * output.c: (outp_init) Add devind class.
+
+       * devind.c: New file.
+
+       * devind.h: New file.
+
+Thu Jan  1 23:08:14 2004  Ben Pfaff  <blp@gnu.org>
+
+       * frequencies.q: (hash_value_alpha) Fixed up the previous change
+       to use the proper string length.
+
 Wed Dec 31 16:27:33 WAST 2003 John Darrington <john@darrington.wattle.id.au>
 
        * Fixed bug where FREQ would crash on alpha values
index 329711e2a51379c464992cdb8e2f2e8ff311c078..2442ca990c75fcff7a10b8ff060b4c804d42edf1 100644 (file)
@@ -36,22 +36,22 @@ pspp_SOURCES = aggregate.c algorithm.c algorithm.h alloc.c alloc.h  \
 apply-dict.c approx.h ascii.c autorecode.c bitvector.h cases.c cases.h \
 cmdline.c cmdline.h command.c command.def command.h compute.c          \
 correlations.c count.c crosstabs.c data-in.c data-in.h data-list.c     \
-data-out.c debug-print.h descript.c dfm.c dfm.h dictionary.c do-if.c   \
-do-ifP.h error.c error.h expr-evl.c expr-opt.c expr-prs.c expr.h       \
-exprP.h file-handle.c file-handle.h file-type.c filename.c filename.h  \
-flip.c font.h format.c format.def format.h formats.c frequencies.c     \
-get.c getline.c getline.h glob.c glob.h groff-font.c hash.c hash.h     \
-heap.c heap.h html.c htmlP.h include.c inpt-pgm.c lexer.c lexer.h      \
-list.c log.h loop.c magic.c magic.h main.c main.h matrix-data.c                \
-matrix.c matrix.h means.c mis-val.c misc.c misc.h modify-vars.c                \
-numeric.c output.c output.h pfm-read.c pfm-write.c pfm.h pool.c pool.h \
-postscript.c print.c random.c random.h recode.c rename-vars.c repeat.c \
-repeat.h sample.c sel-if.c set.c settings.h sfm-read.c sfm-write.c     \
-sfm.h sfmP.h som.c som.h sort.c sort.h split-file.c stat.h stats.c     \
-stats.h str.c str.h sysfile-info.c tab.c tab.h temporary.c title.c     \
-t-test.c val-labs.c value-labels.c value-labels.h var-labs.c var.h     \
-vars-atr.c vars-prs.c vector.c version.c version.h vfm.c vfm.h vfmP.h  \
-weight.c
+data-out.c debug-print.h descript.c devind.c devind.h dfm.c dfm.h      \
+dictionary.c do-if.c do-ifP.h error.c error.h expr-evl.c expr-opt.c    \
+expr-prs.c expr.h exprP.h file-handle.c file-handle.h file-type.c      \
+filename.c filename.h flip.c font.h format.c format.def format.h       \
+formats.c frequencies.c get.c getline.c getline.h glob.c glob.h                \
+groff-font.c hash.c hash.h heap.c heap.h html.c htmlP.h include.c      \
+inpt-pgm.c lexer.c lexer.h list.c log.h loop.c magic.c magic.h main.c  \
+main.h matrix-data.c matrix.c matrix.h means.c mis-val.c misc.c misc.h \
+modify-vars.c numeric.c output.c output.h pfm-read.c pfm-write.c pfm.h \
+pool.c pool.h postscript.c print.c random.c random.h recode.c          \
+rename-vars.c repeat.c repeat.h sample.c sel-if.c set.c settings.h     \
+sfm-read.c sfm-write.c sfm.h sfmP.h som.c som.h sort.c sort.h          \
+split-file.c stat.h stats.c stats.h str.c str.h sysfile-info.c tab.c   \
+tab.h temporary.c title.c t-test.c val-labs.c value-labels.c           \
+value-labels.h var-labs.c var.h vars-atr.c vars-prs.c vector.c         \
+version.c version.h vfm.c vfm.h vfmP.h weight.c
 
 pspp_LDADD =   ../lib/julcal/libjulcal.a               \
        ../lib/misc/libmisc.a                   \
diff --git a/src/devind.c b/src/devind.c
new file mode 100644 (file)
index 0000000..8432ea8
--- /dev/null
@@ -0,0 +1,477 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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. */
+
+/* Device-independent output format.  Eventually I intend for all
+   PSPP output to work this way, but adding it as an available
+   format is a first step.
+
+   Each line in the output is a command.  The first character on
+   the line is the command name, and the rest of the line is the
+   command arguments.  The commands are described below as Perl
+   regular expressions:
+
+   #.*          comment
+
+   s            starts a new table
+   S[rc]\d+     table size in rows or columns (optional)
+   H[lrtb]\d+   number of left/right/top/bottom header rows/columns
+   B(\d+)-(\d+)/(\d+)
+                allow column breaks every \3 rows from \1 to \2 exclusive
+   T.*          table title
+   C.*          table caption (not yet supported)
+   t(\d+)(-\d+)?,(\d+)(-\d+)?[wn][hb][lcr][tmb]:.*
+                text for cells in rows (\1-\2) inclusive and
+                columns (\3-\4) inclusive,
+                wrappable/nonwrappable, header/body,
+                left/center/right justified, top/middle/bottom
+                justified
+   l[hv][sdtn](\d+),(\d+)-(\d+)
+                horiz/vert line in single/double/thick/none
+                style, running across columns/rows \2 to \3
+                inclusive at offset \1 from top/left side of
+                table
+   b[sdtno]{4}(\d+)-(\d+),(\d+)-(\d+)
+                box across columns \1 to \2 inclusive and rows \3
+                to \4 inclusive with
+                single/double/thick/none/omit style for horiz &
+                vert frame and horiz & vert interior lines
+   f(\d+),(\d+):.*
+                add footnote for cell \1, \2
+   e            end table
+
+   v(\d(.\d+)+) insert \1 lines of blank space
+
+   p:.*         plain text
+   m[ewmlu]:(.*),(\d+),((\d+)(-\d+)?)?:(.*)
+                error/warning/message/listing/user class message
+                for file \1, line \2, columns \4 to \5, actual
+                message \6
+
+   q            end of file
+
+   Text tokens are free-form, except that they are terminated by
+   commas and new-lines.  The following escapes are allowed:
+
+   \\n          line break
+   \\c          comma
+   \\s          non-breaking space
+   \\[0-7]{3}   octal escape
+   \\B          toggle subscript
+   \\P          toggle superscript
+   \\e          toggle emphasis
+   \\E          toggle strong emphasis
+   \\v          toggle variable name font
+   \\F          toggle file name font
+   \\p          toggle fixed-pitch text font (default: proportional)
+   \\n\((\d+)?(\.\d+)?(-?\d+(\.\d+)?+(e-?\d+))?\)
+                number \3 (sysmis if not provided) in \1.\2 format
+   \\f\(([A-Z]*(\d+)?(\.\d+)?)(-?\d+(\.\d+)?+(e-?\d+))?\)
+                number \1 in \4 format
+
+*/
+
+#include <config.h>
+#include "devind.h"
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "alloc.h"
+#include "error.h"
+#include "filename.h"
+#include "getline.h"
+#include "output.h"
+#include "som.h"
+#include "tab.h"
+#include "version.h"
+
+/* Device-independent output driver extension record. */
+struct devind_driver_ext
+  {
+    /* Internal state. */
+    struct file_ext file;      /* Output file. */
+    int sequence_no;           /* Sequence number. */
+  };
+
+static int
+devind_open_global (struct outp_class *this unused)
+{
+  return 1;
+}
+
+static int
+devind_close_global (struct outp_class *this unused)
+{
+  return 1;
+}
+
+static int
+devind_preopen_driver (struct outp_driver *this)
+{
+  struct devind_driver_ext *x;
+
+  assert (this->driver_open == 0);
+  msg (VM (1), _("DEVIND driver initializing as `%s'..."), this->name);
+
+  this->ext = x = xmalloc (sizeof *x);
+  this->res = 0;
+  this->horiz = this->vert = 0;
+  this->width = this->length = 0;
+
+  this->cp_x = this->cp_y = 0;
+
+  x->file.filename = NULL;
+  x->file.mode = "w";
+  x->file.file = NULL;
+  x->file.sequence_no = &x->sequence_no;
+  x->file.param = this;
+  x->file.postopen = NULL;
+  x->file.preclose = NULL;
+
+  x->sequence_no = 0;
+
+  return 1;
+}
+
+static int
+devind_postopen_driver (struct outp_driver *this)
+{
+  struct devind_driver_ext *x = this->ext;
+
+  assert (this->driver_open == 0);
+  if (NULL == x->file.filename)
+    x->file.filename = xstrdup ("pspp.devind");
+       
+  msg (VM (2), _("%s: Initialization complete."), this->name);
+  this->driver_open = 1;
+
+  return 1;
+}
+
+static int
+devind_close_driver (struct outp_driver *this)
+{
+  struct devind_driver_ext *x = this->ext;
+
+  assert (this->driver_open);
+  msg (VM (2), _("%s: Beginning closing..."), this->name);
+  fputs ("q\n", x->file.file);
+  fn_close_ext (&x->file);
+  free (x->file.filename);
+  free (x);
+  msg (VM (3), _("%s: Finished closing."), this->name);
+  this->driver_open = 0;
+  
+  return 1;
+}
+
+/* Generic option types. */
+enum
+{
+  boolean_arg = -10,
+  string_arg,
+  nonneg_int_arg
+};
+
+/* All the options that the DEVIND driver supports. */
+static struct outp_option option_tab[] =
+{
+  /* *INDENT-OFF* */
+  {"output-file",              1,              0},
+  {"", 0, 0},
+  /* *INDENT-ON* */
+};
+static struct outp_option_info option_info;
+
+static void
+devind_option (struct outp_driver *this, const char *key, const struct string *val)
+{
+  struct devind_driver_ext *x = this->ext;
+  int cat, subcat;
+
+  cat = outp_match_keyword (key, option_tab, &option_info, &subcat);
+  switch (cat)
+    {
+    case 0:
+      msg (SE, _("Unknown configuration parameter `%s' for DEVIND device "
+          "driver."), key);
+      break;
+    case 1:
+      free (x->file.filename);
+      x->file.filename = xstrdup (ds_value (val));
+      break;
+    default:
+      assert (0);
+    }
+}
+
+static int
+devind_open_page (struct outp_driver *this)
+{
+  struct devind_driver_ext *x = this->ext;
+
+  assert (this->driver_open && this->page_open == 0);
+  x->sequence_no++;
+  if (!fn_open_ext (&x->file))
+    {
+      if (errno)
+       msg (ME, _("DEVIND output driver: %s: %s"), x->file.filename,
+            strerror (errno));
+      return 0;
+    }
+
+  if (!ferror (x->file.file))
+    this->page_open = 1;
+  return !ferror (x->file.file);
+}
+
+static int
+devind_close_page (struct outp_driver *this)
+{
+  struct devind_driver_ext *x = this->ext;
+
+  assert (this->driver_open && this->page_open);
+  this->page_open = 0;
+  return !ferror (x->file.file);
+}
+
+static void output_tab_table (struct outp_driver *, struct tab_table *);
+
+static void
+devind_submit (struct outp_driver *this, struct som_table *s)
+{
+  extern struct som_table_class tab_table_class;
+  struct devind_driver_ext *x = this->ext;
+  
+  assert (this->driver_open && this->page_open);
+  if (x->sequence_no == 0 && !devind_open_page (this))
+    {
+      msg (ME, _("Cannot open first page on DEVIND device %s."), this->name);
+      return;
+    }
+
+  if (s->class == &tab_table_class)
+    output_tab_table (this, s->ext);
+  else
+    assert (0);
+}
+
+/* Write string S of length LEN to file F, escaping characters as
+   necessary for DEVIND. */
+static void
+escape_string (FILE *f, char *s, int len)
+{
+  char *ep = &s[len];
+  char *bp, *cp;
+
+  putc (':', f);
+
+  for (bp = cp = s; bp < ep; bp = cp)
+    {
+      while (cp < ep && *cp != ',' && *cp != '\n' && *cp)
+       cp++;
+      if (cp > bp)
+       fwrite (bp, 1, cp - bp, f);
+      if (cp < ep)
+       switch (*cp++)
+         {
+         case ',':
+           fputs ("\\c", f);
+           break;
+         case '\n':
+           fputs ("\\n", f);
+           break;
+         case 0:
+           break;
+         default:
+           assert (0);
+         }
+    }
+}
+  
+/* Write table T to THIS output driver. */
+static void
+output_tab_table (struct outp_driver *this, struct tab_table *t)
+{
+  struct devind_driver_ext *x = this->ext;
+  
+  if (t->nr == 1 && t->nc == 1)
+    {
+      fputs ("p:", x->file.file);
+      escape_string (x->file.file, ls_value (t->cc), ls_length (t->cc));
+      putc ('\n', x->file.file);
+      
+      return;
+    }
+
+  /* Start table. */
+  fprintf (x->file.file, "s\n");
+
+  /* Table size. */
+  fprintf (x->file.file, "Sr%d\n", t->nr);
+  fprintf (x->file.file, "Sc%d\n", t->nc);
+
+  /* Table headers. */
+  if (t->l != 0)
+    fprintf (x->file.file, "Hl%d\n", t->l);
+  if (t->r != 0)
+    fprintf (x->file.file, "Hr%d\n", t->r);
+  if (t->t != 0)
+    fprintf (x->file.file, "Ht%d\n", t->t);
+  if (t->b != 0)
+    fprintf (x->file.file, "Hb%d\n", t->b);
+
+  /* Title. */
+  if (!ls_empty_p (&t->title))
+    {
+      putc ('T', x->file.file);
+      escape_string (x->file.file, ls_value (&t->title),
+                    ls_length (&t->title));
+      putc ('\n', x->file.file);
+    }
+
+  /* Column breaks. */
+  if (t->col_style == TAB_COL_DOWN) 
+    fprintf (x->file.file, "B%d-%d/%d\n", t->t, t->nr - t->b, t->col_group);
+
+  /* Table text. */
+  {
+    int r;
+    unsigned char *ct = t->ct;
+
+    for (r = 0; r < t->nr; r++)
+      {
+       int c;
+       
+       for (c = 0; c < t->nc; c++, ct++)
+         {
+            struct len_string *cc;
+            struct tab_joined_cell *j;
+
+            if (*ct == TAB_EMPTY)
+              continue;
+            
+            cc = t->cc + c + r * t->nc;
+           if (*ct & TAB_JOIN) 
+              {
+                j = (struct tab_joined_cell *) ls_value (cc);
+                cc = &j->contents;
+                if (c != j->x1 || r != j->y1)
+                  continue;
+              }
+            else
+              j = NULL;
+
+            putc ('t', x->file.file);
+            if (j == NULL) 
+              fprintf (x->file.file, "%d,%d", r, c);
+            else
+              fprintf (x->file.file, "%d-%d,%d-%d",
+                       j->y1, j->y2, j->x1, j->x2);
+            putc ((*ct & TAT_NOWRAP) ? 'n' : 'w', x->file.file);
+            putc ((*ct & TAT_TITLE) ? 'h' : 'b', x->file.file);
+            if ((*ct & TAB_ALIGN_MASK) == TAB_RIGHT)
+              putc ('r', x->file.file);
+            else if ((*ct & TAB_ALIGN_MASK) == TAB_LEFT)
+              putc ('l', x->file.file);
+            else
+              putc ('c', x->file.file);
+            putc ('t', x->file.file);
+            escape_string (x->file.file, ls_value (cc), ls_length (cc));
+            putc ('\n', x->file.file);
+          }
+      }
+  }
+
+  /* Horizontal lines. */
+  {
+    int r, c;
+
+    for (r = 0; r <= t->nr; r++)
+      for (c = 0; c < t->nc; c++) 
+        {
+          int rule = t->rh[c + r * t->nc];
+          if (rule != 0)
+            fprintf (x->file.file, "lh%c%d,%d-%d\n", "nsdt"[rule], r, c, c);
+        }
+  }
+
+  /* Vertical lines. */
+  {
+    int r, c;
+
+    for (r = 0; r < t->nr; r++)
+      for (c = 0; c <= t->nc; c++) 
+        {
+          int rule = t->rv[c + r * (t->nc + 1)];
+          if (rule != 0)
+            fprintf (x->file.file, "lv%c%d,%d-%d\n", "nsdt"[rule], c, r, r);
+        }
+  }
+
+  /* End of table. */
+  fputs ("e\n", x->file.file);
+}
+
+/* DEVIND driver class. */
+struct outp_class devind_class =
+{
+  "devind",
+  0xb1e7,
+  1,
+
+  devind_open_global,
+  devind_close_global,
+  NULL,
+
+  devind_preopen_driver,
+  devind_option,
+  devind_postopen_driver,
+  devind_close_driver,
+
+  devind_open_page,
+  devind_close_page,
+
+  devind_submit,
+
+  NULL,
+  NULL,
+  NULL,
+
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
diff --git a/src/devind.h b/src/devind.h
new file mode 100644 (file)
index 0000000..e8abafd
--- /dev/null
@@ -0,0 +1,27 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Written by Ben Pfaff <blp@gnu.org>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   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. */
+
+#ifndef INCLUDED_DEVIND_H
+#define INCLUDED_DEVIND_H 1
+
+#include "output.h"
+
+extern struct outp_class devind_class;
+
+#endif /* devind.h */
index a9c5850d7ba29f6f3031b0dea7146629443e97a3..3f5224d67984fc1cce593be1e2193d3f7384fc96 100644 (file)
@@ -833,13 +833,12 @@ hash_value_numeric (const void *value_, void *foo unused)
 
 /* Hash of string values. */
 static unsigned
-hash_value_alpha (const void *value_, void *len_ unused)
+hash_value_alpha (const void *value_, void *v_)
 {
   const struct freq *value = value_;
+  struct variable *v = v_;
 
-  static int len = MAX_SHORT_STRING;
-
-  return hsh_hash_bytes (value->v.s, len);
+  return hsh_hash_bytes (value->v.s, v->width);
 }
 
 /* Ascending numeric compare of values. */
index 3f7416290b070d92c94db48c8f8dbf7688fa03b8..53add68cd5dacd51e2afd3d4ec23f0fb439571df 100644 (file)
@@ -409,26 +409,6 @@ html_submit (struct outp_driver *this, struct som_table *s)
     assert (0);
 }
 
-/* Emit HTML to FILE to change from *OLD_ATTR attributes to NEW_ATTR.
-   Sets *OLD_ATTR to NEW_ATTR when done. */
-static void
-change_attributes (FILE *f, int *old_attr, int new_attr)
-{
-  if (*old_attr == new_attr)
-    return;
-
-  if (*old_attr & OUTP_F_B)
-    fputs ("</B>", f);
-  if (*old_attr & OUTP_F_I)
-    fputs ("</I>", f);
-  if (new_attr & OUTP_F_I)
-    fputs ("<I>", f);
-  if (new_attr & OUTP_F_B)
-    fputs ("<B>", f);
-
-  *old_attr = new_attr;
-}
-
 /* Write string S of length LEN to file F, escaping characters as
    necessary for HTML. */
 static void
@@ -436,7 +416,6 @@ escape_string (FILE *f, char *s, int len)
 {
   char *ep = &s[len];
   char *bp, *cp;
-  int attr = 0;
 
   for (bp = cp = s; bp < ep; bp = cp)
     {
@@ -462,9 +441,6 @@ escape_string (FILE *f, char *s, int len)
            assert (0);
          }
     }
-
-  if (attr)
-    change_attributes (f, &attr, 0);
 }
   
 /* Write table T to THIS output driver. */
@@ -473,8 +449,6 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
 {
   struct html_driver_ext *x = this->ext;
   
-  tab_hit++;
-
   if (t->nr == 1 && t->nc == 1)
     {
       fputs ("<P>", x->file.file);
@@ -497,7 +471,6 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
   
   {
     int r;
-    struct len_string *cc = t->cc;
     unsigned char *ct = t->ct;
 
     for (r = 0; r < t->nr; r++)
@@ -505,15 +478,22 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
        int c;
        
        fputs ("  <TR>\n", x->file.file);
-       for (c = 0; c < t->nc; c++, cc++, ct++)
+       for (c = 0; c < t->nc; c++, ct++)
          {
+            struct len_string *cc;
            int tag;
            char header[128];
            char *cp;
+            struct tab_joined_cell *j = NULL;
 
-           if ((*ct & TAB_JOIN)
-               && ((struct tab_joined_cell *) ls_value (cc))->hit == tab_hit)
-             continue;
+            cc = t->cc + c + r * t->nc;
+           if (*ct & TAB_JOIN) 
+              {
+                j = (struct tab_joined_cell *) ls_value (cc);
+                cc = &j->contents;
+                if (j->x1 != c || j->y1 != r)
+                  continue; 
+              }
 
            if (r < t->t || r >= t->nr - t->b
                || c < t->l || c >= t->nc - t->r)
@@ -539,14 +519,12 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
 
            if (*ct & TAB_JOIN)
              {
-               struct tab_joined_cell *j =
-                 (struct tab_joined_cell *) ls_value (cc);
-               j->hit = tab_hit;
-               
                if (j->x2 - j->x1 > 1)
                  cp = spprintf (cp, " COLSPAN=%d", j->x2 - j->x1);
                if (j->y2 - j->y1 > 1)
                  cp = spprintf (cp, " ROWSPAN=%d", j->y2 - j->y1);
+
+                cc = &j->contents;
              }
            
            strcpy (cp, ">");
index dbdacb573c3a6ad856c3a8062a9370094687d6ae..578cfe5d0abaca0c0fc4e542b97a9051b0cc1381 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include "alloc.h"
 #include "command.h"
+#include "devind.h"
 #include "lexer.h"
 #include "error.h"
 #include "magic.h"
@@ -30,6 +31,7 @@
 #include "htmlP.h"
 #include "output.h"
 #include "som.h"
+#include "tab.h"
 #include "var.h"
 #include "vfm.h"
 #include "format.h"
@@ -271,6 +273,10 @@ write_all_headers (void)
 
          fputs ("  <TR>\n", x->file.file);
        }
+      else if (d->class == &devind_class) 
+        {
+          /* FIXME */
+        }
       else
        assert (0);
     }
@@ -389,6 +395,10 @@ clean_up (void)
            fputs ("</TABLE>\n", x->file.file);
          }
       }
+    else if (d->class == &devind_class) 
+      {
+        /* FIXME */
+      }
     else
       assert (0);
   
@@ -520,6 +530,12 @@ determine_layout (void)
 
       if (d->class == &html_class)
        continue;
+      else if (d->class == &devind_class) 
+        {
+          /* FIXME */
+          tab_output_text (TAT_NONE, "(devind not supported on LIST yet)");
+          continue;
+        }
       
       assert (d->class->special == 0);
 
@@ -709,6 +725,10 @@ list_cases (struct ccase *c)
          
        fputs ("  </TR>\n", x->file.file);
       }
+    else if (d->class == &devind_class) 
+      {
+        /* FIXME */
+      }
     else
       assert (0);
 
index f3e0da7ea392f28a7bec0cdb3b0cc5d3d0b87c76..b804978d6d1d4567be2f56b4938ea1a94e8951f7 100644 (file)
 #include <ctype.h>
 #include "alloc.h"
 #include "approx.h"
+#include "devind.h"
 #include "error.h"
 #include "filename.h"
+#include "htmlP.h"
 #include "lexer.h"
 #include "misc.h"
 #include "settings.h"
@@ -226,9 +228,8 @@ outp_init (void)
   extern struct outp_class postscript_class;
   extern struct outp_class epsf_class;
 #endif
-#if !NO_HTML
   extern struct outp_class html_class;
-#endif
+  extern struct outp_class devind_class;
 
   char def[] = "default";
 
@@ -239,6 +240,7 @@ outp_init (void)
   add_class (&epsf_class);
   add_class (&postscript_class);
 #endif
+  add_class (&devind_class);
   add_class (&ascii_class);
 
   add_name (def, &def[strlen (def)], OUTP_S_INIT_FILE);
index acfe3525063c543a901adf2cefdc079e690a8982..8dc704ffe665d63eb8c2f4da6a92e4c48ca81feb 100644 (file)
--- a/src/tab.c
+++ b/src/tab.c
@@ -802,8 +802,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 +825,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)
@@ -1147,50 +1157,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 =