Adopt use of gnulib for portability.
[pspp-builds.git] / src / postscript.c
index ef6cebe9ae0594c955f4408dd83d7e726eafa01e..11473f6488faaa94de282739ecd556232a3d5ec7 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. */
 
-/* AIX requires this to be the first thing in the file.  */
 #include <config.h>
-#if __GNUC__
-#define alloca __builtin_alloca
-#else
-#if HAVE_ALLOCA_H
-#include <alloca.h>
-#else
-#ifdef _AIX
-#pragma alloca
-#else
-#ifndef alloca                 /* predefined by HP cc +Olibcalls */
-char *alloca ();
-#endif
-#endif
-#endif
-#endif
 
 /*this #if encloses the remainder of the file. */
 #if !NO_POSTSCRIPT
 
 #include <ctype.h>
-#include <assert.h>
+#include "error.h"
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <time.h>
 
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
-#if TIME_WITH_SYS_TIME
-#include <sys/time.h>
-#include <time.h>
-#else
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#else
-#include <time.h>
-#endif
-#endif
-
 #include "alloc.h"
 #include "bitvector.h"
 #include "error.h"
 #include "filename.h"
 #include "font.h"
+#include "getl.h"
 #include "getline.h"
 #include "hash.h"
 #include "main.h"
 #include "misc.h"
 #include "misc.h"
 #include "output.h"
+#include "som.h"
 #include "version.h"
 
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
 /* FIXMEs:
 
    optimize-text-size not implemented.
@@ -283,6 +262,7 @@ static unsigned hash_font_entry (const void *, void *param);
 static void free_font_entry (void *, void *foo);
 static struct font_entry *load_font (struct outp_driver *, const char *dit);
 static void init_fonts (void);
+static void done_fonts (void);
 
 static void dump_lines (struct outp_driver *this);
 
@@ -303,7 +283,7 @@ static char *quote_ps_string (char *dest, const char *string);
 /* Driver initialization. */
 
 static int
-ps_open_global (struct outp_class *this unused)
+ps_open_global (struct outp_class *this UNUSED)
 {
   init_fonts ();
   groff_init ();
@@ -311,13 +291,15 @@ ps_open_global (struct outp_class *this unused)
 }
 
 static int
-ps_close_global (struct outp_class *this unused)
+ps_close_global (struct outp_class *this UNUSED)
 {
+  groff_done ();
+  done_fonts ();
   return 1;
 }
 
 static int *
-ps_font_sizes (struct outp_class *this unused, int *n_valid_sizes)
+ps_font_sizes (struct outp_class *this UNUSED, int *n_valid_sizes)
 {
   /* Allow fonts up to 1" in height. */
   static int valid_sizes[] =
@@ -510,14 +492,14 @@ ps_close_driver (struct outp_driver *this)
 
 /* font_entry comparison function for hash tables. */
 static int
-compare_font_entry (const void *a, const void *b, void *foobar unused)
+compare_font_entry (const void *a, const void *b, void *foobar UNUSED)
 {
   return strcmp (((struct font_entry *) a)->dit, ((struct font_entry *) b)->dit);
 }
 
 /* font_entry hash function for hash tables. */
 static unsigned
-hash_font_entry (const void *fe_, void *foobar unused)
+hash_font_entry (const void *fe_, void *foobar UNUSED)
 {
   const struct font_entry *fe = fe_;
   return hsh_hash_string (fe->dit);
@@ -525,7 +507,7 @@ hash_font_entry (const void *fe_, void *foobar unused)
 
 /* font_entry destructor function for hash tables. */
 static void
-free_font_entry (void *pa, void *foo unused)
+free_font_entry (void *pa, void *foo UNUSED)
 {
   struct font_entry *a = pa;
   free (a->dit);
@@ -583,7 +565,7 @@ ps_option (struct outp_driver *this, const char *key, const struct string *val)
 {
   struct ps_driver_ext *x = this->ext;
   int cat, subcat;
-  char *value = ds_value (val);
+  char *value = ds_c_str (val);
 
   cat = outp_match_keyword (key, option_tab, &option_info, &subcat);
 
@@ -677,6 +659,7 @@ ps_option (struct outp_driver *this, const char *key, const struct string *val)
            break;
          default:
            assert (0);
+            abort ();
          }
        if (setting)
          x->output_options |= mask;
@@ -778,6 +761,7 @@ ps_option (struct outp_driver *this, const char *key, const struct string *val)
            break;
          default:
            assert (0);
+            abort ();
          }
        if (*dest)
          free (*dest);
@@ -872,7 +856,7 @@ find_ps_file (struct outp_driver *this, const char *name)
 
 /* Hash table comparison function for ps_encoding's. */
 static int
-compare_ps_encoding (const void *pa, const void *pb, void *foo unused)
+compare_ps_encoding (const void *pa, const void *pb, void *foo UNUSED)
 {
   const struct ps_encoding *a = pa;
   const struct ps_encoding *b = pb;
@@ -882,7 +866,7 @@ compare_ps_encoding (const void *pa, const void *pb, void *foo unused)
 
 /* Hash table hash function for ps_encoding's. */
 static unsigned
-hash_ps_encoding (const void *pa, void *foo unused)
+hash_ps_encoding (const void *pa, void *foo UNUSED)
 {
   const struct ps_encoding *a = pa;
 
@@ -891,7 +875,7 @@ hash_ps_encoding (const void *pa, void *foo unused)
 
 /* Hash table free function for ps_encoding's. */
 static void
-free_ps_encoding (void *pa, void *foo unused)
+free_ps_encoding (void *pa, void *foo UNUSED)
 {
   struct ps_encoding *a = pa;
 
@@ -912,8 +896,8 @@ output_encodings (struct outp_driver *this)
 
   struct string line, buf;
 
-  ds_init (NULL, &line, 128);
-  ds_init (NULL, &buf, 128);
+  ds_init (&line, 128);
+  ds_init (&buf, 128);
   for (pe = hsh_first (x->encodings, &iter); pe != NULL;
        pe = hsh_next (x->encodings, &iter)) 
     {
@@ -960,7 +944,7 @@ output_encodings (struct outp_driver *this)
              if (buf.length == 0) 
                continue;
 
-             pschar = strtok_r (ds_value (&buf), " \t\r\n", &sp);
+             pschar = strtok_r (ds_c_str (&buf), " \t\r\n", &sp);
              code = strtok_r (NULL, " \t\r\n", &sp);
              if (*pschar == 0 || *code == 0)
                continue;
@@ -998,14 +982,14 @@ output_encodings (struct outp_driver *this)
              
              if (ds_length (&line) + strlen (temp) > 70)
                {
-                 ds_concat (&line, x->eol);
-                 fputs (ds_value (&line), x->file.file);
+                 ds_puts (&line, x->eol);
+                 fputs (ds_c_str (&line), x->file.file);
                  ds_clear (&line);
                }
-             ds_concat (&line, temp);
+             ds_puts (&line, temp);
            }
-         ds_concat (&line, x->eol);
-         fputs (ds_value (&line), x->file.file);
+         ds_puts (&line, x->eol);
+         fputs (ds_c_str (&line), x->file.file);
 
          if (fclose (f) == EOF)
            msg (MW, _("PostScript driver: Error closing encoding file `%s'."),
@@ -1118,12 +1102,10 @@ read_ps_encodings (struct outp_driver *this)
   where.line_number = 0;
   err_push_file_locator (&where);
 
-  ds_init (NULL, &line, 128);
+  ds_init (&line, 128);
     
   for (;;)
     {
-      char *bp;
-
       if (!ds_get_config_line (f, &line, &where))
        {
          if (ferror (f))
@@ -1131,7 +1113,7 @@ read_ps_encodings (struct outp_driver *this)
          break;
        }
 
-      add_encoding (this, bp);
+      add_encoding (this, line.string);
     }
 
   ds_destroy (&line);
@@ -1464,7 +1446,7 @@ postopen (struct file_ext *f)
          char *beg;
          beg = buf2 = fn_interp_vars (buf, ps_get_var);
          len = strlen (buf2);
-         while (isspace (*beg))
+         while (isspace ((unsigned char) *beg))
            beg++, len--;
          if (beg[len - 1] == '\n')
            len--;
@@ -1706,6 +1688,8 @@ ps_open_page (struct outp_driver *this)
        draw_headers (this);
     }
 
+  this->cp_y = 0;
+
   return !ferror (x->file.file);
 }
 
@@ -1727,6 +1711,19 @@ ps_close_page (struct outp_driver *this)
   this->page_open = 0;
   return !ferror (x->file.file);
 }
+
+static void
+ps_submit (struct outp_driver *this UNUSED, struct som_entity *s)
+{
+  switch (s->type) 
+    {
+    case SOM_CHART:
+      break;
+    default:
+      assert(0);
+      break;
+    }
+}
 \f
 /* Lines. */
 
@@ -1742,7 +1739,7 @@ int_2_compare (const void *a_, const void *b_)
 
 /* Hash table comparison function for cached lines. */
 static int
-compare_line (const void *a_, const void *b_, void *foo unused)
+compare_line (const void *a_, const void *b_, void *foo UNUSED)
 {
   const struct line_form *a = a_;
   const struct line_form *b = b_;
@@ -1752,7 +1749,7 @@ compare_line (const void *a_, const void *b_, void *foo unused)
 
 /* Hash table hash function for cached lines. */
 static unsigned
-hash_line (const void *pa, void *foo unused)
+hash_line (const void *pa, void *foo UNUSED)
 {
   const struct line_form *a = pa;
 
@@ -1761,7 +1758,7 @@ hash_line (const void *pa, void *foo unused)
 
 /* Hash table free function for cached lines. */
 static void
-free_line (void *pa, void *foo unused)
+free_line (void *pa, void *foo UNUSED)
 {
   free (pa);
 }
@@ -1914,7 +1911,7 @@ line (struct outp_driver *this, int type, int ind, int dep1, int dep2)
 
 static void
 ps_line_horz (struct outp_driver *this, const struct rect *r,
-             const struct color *c unused, int style)
+             const struct color *c UNUSED, int style)
 {
   /* Must match output.h:OUTP_L_*. */
   static const int types[OUTP_L_COUNT] =
@@ -1931,7 +1928,7 @@ ps_line_horz (struct outp_driver *this, const struct rect *r,
 
 static void
 ps_line_vert (struct outp_driver *this, const struct rect *r,
-             const struct color *c unused, int style)
+             const struct color *c UNUSED, int style)
 {
   /* Must match output.h:OUTP_L_*. */
   static const int types[OUTP_L_COUNT] =
@@ -1953,7 +1950,7 @@ ps_line_vert (struct outp_driver *this, const struct rect *r,
 
 static void
 ps_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 ps_driver_ext *ext = this->ext;
@@ -2034,25 +2031,25 @@ ps_line_intersection (struct outp_driver *this, const struct rect *r,
 }
 
 static void
-ps_box (struct outp_driver *this unused, const struct rect *r unused,
-       const struct color *bord unused, const struct color *fill unused)
+ps_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);
 }
 
 static void 
-ps_polyline_begin (struct outp_driver *this unused,
-                  const struct color *c unused)
+ps_polyline_begin (struct outp_driver *this UNUSED,
+                  const struct color *c UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
 static void 
-ps_polyline_point (struct outp_driver *this unused, int x unused, int y unused)
+ps_polyline_point (struct outp_driver *this UNUSED, int x UNUSED, int y UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
 static void 
-ps_polyline_end (struct outp_driver *this unused)
+ps_polyline_end (struct outp_driver *this UNUSED)
 {
   assert (this->driver_open && this->page_open);
 }
@@ -2286,7 +2283,7 @@ struct output_char
 
 /* Hash table comparison function for ps_combo structs. */
 static int
-compare_ps_combo (const void *pa, const void *pb, void *foo unused)
+compare_ps_combo (const void *pa, const void *pb, void *foo UNUSED)
 {
   const struct ps_font_combo *a = pa;
   const struct ps_font_combo *b = pb;
@@ -2296,7 +2293,7 @@ compare_ps_combo (const void *pa, const void *pb, void *foo unused)
 
 /* Hash table hash function for ps_combo structs. */
 static unsigned
-hash_ps_combo (const void *pa, void *foo unused)
+hash_ps_combo (const void *pa, void *foo UNUSED)
 {
   const struct ps_font_combo *a = pa;
   unsigned name_hash = hsh_hash_string (a->font->font->internal_name);
@@ -2305,7 +2302,7 @@ hash_ps_combo (const void *pa, void *foo unused)
 
 /* Hash table free function for ps_combo structs. */
 static void
-free_ps_combo (void *a, void *foo unused)
+free_ps_combo (void *a, void *foo UNUSED)
 {
   free (a);
 }
@@ -2404,7 +2401,7 @@ switch_font (struct outp_driver *this, const struct output_char *cp)
 static void
 write_text (struct outp_driver *this,
            const struct output_char *cp, const struct output_char *end,
-           struct outp_text *t, int width unused, int width_left)
+           struct outp_text *t, int width UNUSED, int width_left)
 {
   struct ps_driver_ext *ext = this->ext;
   int ofs;
@@ -2426,6 +2423,9 @@ write_text (struct outp_driver *this,
     case OUTP_T_JUST_CENTER:
       ofs = width_left / 2;
       break;
+    default:
+      assert (0);
+      abort ();
     }
 
   lp = line;
@@ -2556,18 +2556,23 @@ text (struct outp_driver *this, struct outp_text *t, int draw)
   buf_loc = buf;
 
   assert (!ls_null_p (&t->s));
-  cp = ls_value (&t->s);
+  cp = ls_c_str (&t->s);
   end = ls_end (&t->s);
   if (draw)
     {
       x = t->x;
       y = t->y;
     }
+  else
+    x = y = 0;
   width = width_left = (t->options & OUTP_T_HORZ) ? t->h : INT_MAX;
   height_left = (t->options & OUTP_T_VERT) ? t->v : INT_MAX;
   max_height = 0;
   prev_char = -1;
   space_char = NULL;
+  space_buf_loc = NULL;
+  space_width_left = 0;
+  
 
   if (!width || !height_left)
     goto exit;
@@ -2582,9 +2587,12 @@ text (struct outp_driver *this, struct outp_text *t, int draw)
 
       /* Set char_name to the name of the character or ligature at
          *cp. */
+      local_char_name[0] = *cp;
+      char_name = local_char_name;
       if (ext->current->font->ligatures && *cp == 'f')
        {
          int lig = 0;
+          char_name = NULL;
 
          if (cp < end - 1)
            switch (cp[1])
@@ -2612,11 +2620,9 @@ text (struct outp_driver *this, struct outp_text *t, int draw)
              }
          if ((lig & ext->current->font->ligatures) == 0)
            {
-             local_char_name[0] = *cp++;       /* 'f' */
+             local_char_name[0] = *cp; /* 'f' */
              char_name = local_char_name;
            }
-         else
-           cp += strlen (char_name);
        }
       else if (*cp == '\n')
        {
@@ -2639,11 +2645,7 @@ text (struct outp_driver *this, struct outp_text *t, int draw)
             set separate to 1. */
          continue;
        }
-      else
-       {
-         local_char_name[0] = *cp++;
-         char_name = local_char_name;
-       }
+      cp += strlen (char_name);
 
       /* Figure out what size this character is, and what kern
          adjustment we need. */
@@ -2803,7 +2805,7 @@ static struct hsh_table *ps_fonts;
 
 /* Hash table comparison function for filename2font structs. */
 static int
-compare_filename2font (const void *a, const void *b, void *param unused)
+compare_filename2font (const void *a, const void *b, void *param UNUSED)
 {
   return strcmp (((struct filename2font *) a)->filename,
                 ((struct filename2font *) b)->filename);
@@ -2811,7 +2813,7 @@ compare_filename2font (const void *a, const void *b, void *param unused)
 
 /* Hash table hash function for filename2font structs. */
 static unsigned
-hash_filename2font (const void *f2f_, void *param unused)
+hash_filename2font (const void *f2f_, void *param UNUSED)
 {
   const struct filename2font *f2f = f2f_;
   return hsh_hash_string (f2f->filename);
@@ -2826,6 +2828,12 @@ init_fonts (void)
                         NULL, NULL);
 }
 
+static void
+done_fonts (void)
+{
+ hsh_destroy (ps_fonts);
+}
+
 /* Loads the font having Groff name DIT into THIS driver instance.
    Specifically, adds it into the THIS driver's `loaded' hash
    table. */
@@ -2873,6 +2881,86 @@ load_font (struct outp_driver *this, const char *dit)
   return fe;
 }
 
+static void
+ps_chart_initialise (struct outp_driver *this UNUSED, struct chart *ch)
+{
+#ifdef NO_CHARTS
+  ch->lp = NULL;
+#else
+  struct ps_driver_ext *x = this->ext;
+  char page_size[128];
+  int size;
+  int x_origin, y_origin;
+
+  ch->file = tmpfile ();
+  if (ch->file == NULL) 
+    {
+      ch->lp = NULL;
+      return;
+    }
+  
+  size = this->width < this->length ? this->width : this->length;
+  x_origin = x->left_margin + (size - this->width) / 2;
+  y_origin = x->bottom_margin + (size - this->length) / 2;
+
+  snprintf (page_size, sizeof page_size,
+            "a,xsize=%.3f,ysize=%.3f,xorigin=%.3f,yorigin=%.3f",
+            (double) size / PSUS, (double) size / PSUS,
+            (double) x_origin / PSUS, (double) y_origin / PSUS);
+
+  ch->pl_params = pl_newplparams ();
+  pl_setplparam (ch->pl_params, "PAGESIZE", page_size);
+  ch->lp = pl_newpl_r ("ps", NULL, ch->file, stderr, ch->pl_params);
+#endif
+}
+
+static void 
+ps_chart_finalise (struct outp_driver *this UNUSED, struct chart *ch UNUSED)
+{
+#ifndef NO_CHARTS
+  struct ps_driver_ext *x = this->ext;
+  char buf[BUFSIZ];
+  static int doc_num = 0;
+
+  if (this->page_open) 
+    {
+      this->class->close_page (this);
+      this->page_open = 0; 
+    }
+  this->class->open_page (this);
+  fprintf (x->file.file,
+           "/sp save def%s"
+           "%d %d translate 1000 dup scale%s"
+           "userdict begin%s"
+           "/showpage { } def%s"
+           "0 setgray 0 setlinecap 1 setlinewidth%s"
+           "0 setlinejoin 10 setmiterlimit [ ] 0 setdash newpath clear%s"
+           "%%%%BeginDocument: %d%s",
+           x->eol,
+           -x->left_margin, -x->bottom_margin, x->eol,
+           x->eol,
+           x->eol,
+           x->eol,
+           x->eol,
+           doc_num++, x->eol);
+
+  rewind (ch->file);
+  while (fwrite (buf, 1, fread (buf, 1, sizeof buf, ch->file), x->file.file))
+    continue;
+  fclose (ch->file);
+
+  fprintf (x->file.file,
+           "%%%%EndDocument%s"
+           "end%s"
+           "sp restore%s",
+           x->eol,
+           x->eol,
+           x->eol);
+  this->class->close_page (this);
+  this->page_open = 0;
+#endif
+}
+
 /* PostScript driver class. */
 struct outp_class postscript_class =
 {
@@ -2892,7 +2980,7 @@ struct outp_class postscript_class =
   ps_open_page,
   ps_close_page,
 
-  NULL,
+  ps_submit,
 
   ps_line_horz,
   ps_line_vert,
@@ -2912,6 +3000,9 @@ struct outp_class postscript_class =
   ps_text_get_size,
   ps_text_metrics,
   ps_text_draw,
+
+  ps_chart_initialise,
+  ps_chart_finalise
 };
 
 /* EPSF driver class.  FIXME: Probably doesn't work right. */
@@ -2933,7 +3024,7 @@ struct outp_class epsf_class =
   ps_open_page,
   ps_close_page,
 
-  NULL,
+  ps_submit,
 
   ps_line_horz,
   ps_line_vert,
@@ -2953,6 +3044,10 @@ struct outp_class epsf_class =
   ps_text_get_size,
   ps_text_metrics,
   ps_text_draw,
+
+  ps_chart_initialise,
+  ps_chart_finalise
+
 };
 
 #endif /* NO_POSTSCRIPT */