- struct ps_driver_ext *x = this->ext;
-
- /* Encodings file. */
- char *encoding_fn; /* `ps-encodings' filename. */
- FILE *f;
-
- struct string line;
- struct file_locator where;
-
- /* It's okay if there's no list of encodings; not everyone cares. */
- encoding_fn = find_ps_file (this, x->encoding_fn);
- if (encoding_fn == NULL)
- return;
- free (encoding_fn);
-
- msg (VM (1), _("%s: %s: Opening PostScript encoding list file."),
- this->name, encoding_fn);
- f = fopen (encoding_fn, "r");
- if (!f)
- {
- msg (IE, _("Opening %s: %s."), encoding_fn, strerror (errno));
- return;
- }
-
- where.filename = encoding_fn;
- where.line_number = 0;
- err_push_file_locator (&where);
-
- ds_init (&line, 128);
-
- for (;;)
- {
- if (!ds_get_config_line (f, &line, &where.line_number))
- {
- if (ferror (f))
- msg (ME, _("Reading %s: %s."), encoding_fn, strerror (errno));
- break;
- }
-
- add_encoding (this, line.string);
- }
-
- ds_destroy (&line);
- err_pop_file_locator (&where);
-
- if (-1 == fclose (f))
- msg (MW, _("Closing %s: %s."), encoding_fn, strerror (errno));
-
- msg (VM (2), _("%s: PostScript encoding list file read successfully."), this->name);
-}
-
-/* Creates a default encoding for driver D that can be substituted for
- an unavailable encoding. */
-struct ps_encoding *
-default_encoding (struct outp_driver *d)
-{
- struct ps_driver_ext *x = d->ext;
- static struct ps_encoding *enc;
-
- if (!enc)
- {
- enc = xmalloc (sizeof *enc);
- enc->filename = xstrdup (_("<<default encoding>>"));
- enc->index = x->next_encoding++;
- }
- return enc;
-}
-\f
-/* Basic file operations. */
-
-/* Variables for the prologue. */
-struct ps_variable
- {
- const char *key;
- const char *value;
- };
-
-static struct ps_variable *ps_var_tab;
-
-/* Searches ps_var_tab for a ps_variable with key KEY, and returns the
- associated value. */
-static const char *
-ps_get_var (const char *key)
-{
- struct ps_variable *v;
-
- for (v = ps_var_tab; v->key; v++)
- if (!strcmp (key, v->key))
- return v->value;
- return NULL;
-}
-
-/* Writes the PostScript prologue to file F. */
-static int
-postopen (struct file_ext *f)
-{
- static struct ps_variable dict[] =
- {
- {"bounding-box", 0},
- {"creator", 0},
- {"date", 0},
- {"data", 0},
- {"orientation", 0},
- {"user", 0},
- {"host", 0},
- {"prop-font", 0},
- {"fixed-font", 0},
- {"scale-factor", 0},
- {"paper-width", 0},
- {"paper-length", 0},
- {"left-margin", 0},
- {"top-margin", 0},
- {"line-width", 0},
- {"line-width-thick", 0},
- {"title", 0},
- {0, 0},
- };
- char boundbox[INT_STRLEN_BOUND (int) * 4 + 4];
-#if HAVE_UNISTD_H
- char host[128];
-#endif
- char scaling[INT_STRLEN_BOUND (int) + 5];
- time_t curtime;
- struct tm *loctime;
- char *p, *cp;
- char paper_width[INT_STRLEN_BOUND (int) + 1];
- char paper_length[INT_STRLEN_BOUND (int) + 1];
- char left_margin[INT_STRLEN_BOUND (int) + 1];
- char top_margin[INT_STRLEN_BOUND (int) + 1];
- char line_width[INT_STRLEN_BOUND (int) + 1];
- char line_width_thick[INT_STRLEN_BOUND (int) + 1];
-
- struct outp_driver *this = f->param;
- struct ps_driver_ext *x = this->ext;
-
- char *prologue_fn = find_ps_file (this, x->prologue_fn);
- FILE *prologue_file;
-
- char *buf = NULL;
- size_t buf_size = 0;
-
- x->loaded = hsh_create (31, compare_font_entry, hash_font_entry,
- free_font_entry, NULL);
-
- {
- char *font_name = local_alloc (2 + max (strlen (x->prop_family),
- strlen (x->fixed_family)));
-
- strcpy (stpcpy (font_name, x->prop_family), "R");
- x->prop = load_font (this, font_name);
-
- strcpy (stpcpy (font_name, x->fixed_family), "R");
- x->fixed = load_font (this, font_name);
-
- local_free(font_name);
- }
-
- x->current = x->prop;
- x->family = xstrdup (x->prop_family);
- x->size = x->font_size;
-
- {
- int *h = this->horiz_line_width, *v = this->vert_line_width;
-
- this->cp_x = this->cp_y = 0;
- this->font_height = x->font_size;
- {
- struct char_metrics *metric;
-
- metric = font_get_char_metrics (x->prop->font, '0');
- this->prop_em_width = ((metric
- ? metric->width : x->prop->font->space_width)
- * x->font_size / 1000);
-
- metric = font_get_char_metrics (x->fixed->font, '0');
- this->fixed_width = ((metric
- ? metric->width : x->fixed->font->space_width)
- * x->font_size / 1000);
- }
-
- h[0] = v[0] = 0;
- h[1] = v[1] = 2 * x->line_gutter + x->line_width;
- if (x->output_options & OPO_DOUBLE_LINE)
- h[2] = v[2] = 2 * x->line_gutter + 2 * x->line_width + x->line_space;
- else
- h[2] = v[2] = 2 * x->line_gutter + x->line_width_thick;
- h[3] = v[3] = 2 * x->line_gutter + x->line_width;
-
- {
- int i;
-
- for (i = 0; i < (1 << OUTP_L_COUNT); i++)
- {
- int bit;
-
- /* Maximum width of any line type so far. */
- int max = 0;
-
- for (bit = 0; bit < OUTP_L_COUNT; bit++)
- if ((i & (1 << bit)) && h[bit] > max)
- max = h[bit];
- this->horiz_line_spacing[i] = this->vert_line_spacing[i] = max;
- }
- }
- }
-
- if (x->output_options & OPO_AUTO_ENCODE)
- {
- /* It's okay if this is done more than once since add_encoding()
- is idempotent over identical encodings. */
- add_encoding (this, x->prop->font->encoding);
- add_encoding (this, x->fixed->font->encoding);
- }
-
- x->file_page_number = 0;
-
- errno = 0;
- if (prologue_fn == NULL)
- {
- msg (IE, _("Cannot find PostScript prologue. The use of `-vv' "
- "on the command line is suggested as a debugging aid."));
- return 0;
- }
-
- msg (VM (1), _("%s: %s: Opening PostScript prologue..."),
- this->name, prologue_fn);
- prologue_file = fopen (prologue_fn, "rb");
- if (prologue_file == NULL)
- {
- fclose (prologue_file);
- free (prologue_fn);
- msg (IE, "%s: %s", prologue_fn, strerror (errno));
- goto error;
- }
-
- sprintf (boundbox, "0 0 %d %d",
- x->w / (PSUS / 72) + (x->w % (PSUS / 72) > 0),
- x->l / (PSUS / 72) + (x->l % (PSUS / 72) > 0));
- dict[0].value = boundbox;
-
- dict[1].value = (char *) version;
-
- curtime = time (NULL);
- loctime = localtime (&curtime);
- dict[2].value = asctime (loctime);
- cp = strchr (dict[2].value, '\n');
- if (cp)
- *cp = 0;
-
- switch (x->data)
- {
- case ODA_CLEAN7BIT:
- dict[3].value = "Clean7Bit";
- break;
- case ODA_CLEAN8BIT:
- dict[3].value = "Clean8Bit";
- break;
- case ODA_BINARY:
- dict[3].value = "Binary";
- break;
- default:
- assert (0);
- }
-
- if (x->orientation == OTN_PORTRAIT)
- dict[4].value = "Portrait";
- else
- dict[4].value = "Landscape";
-
- /* PORTME: Determine username, net address. */
-#if HAVE_UNISTD_H
- dict[5].value = getenv ("LOGNAME");
- if (!dict[5].value)
- dict[5].value = getlogin ();
- if (!dict[5].value)
- dict[5].value = _("nobody");
-
- if (gethostname (host, 128) == -1)
- {
- if (errno == ENAMETOOLONG)
- host[127] = 0;
- else
- strcpy (host, _("nowhere"));
- }
- dict[6].value = host;
-#else /* !HAVE_UNISTD_H */
- dict[5].value = _("nobody");
- dict[6].value = _("nowhere");
-#endif /* !HAVE_UNISTD_H */
-
- cp = stpcpy (p = local_alloc (288), "font ");
- quote_ps_string (cp, x->prop->font->internal_name);
- dict[7].value = p;
-
- cp = stpcpy (p = local_alloc (288), "font ");
- quote_ps_string (cp, x->fixed->font->internal_name);
- dict[8].value = p;
-
- sprintf (scaling, "%.3f", PSUS / 72.0);
- dict[9].value = scaling;
-
- sprintf (paper_width, "%g", x->w / (PSUS / 72.0));
- dict[10].value = paper_width;
-
- sprintf (paper_length, "%g", x->l / (PSUS / 72.0));
- dict[11].value = paper_length;
-
- sprintf (left_margin, "%d", x->left_margin);
- dict[12].value = left_margin;
-
- sprintf (top_margin, "%d", x->top_margin);
- dict[13].value = top_margin;
-
- sprintf (line_width, "%d", x->line_width);
- dict[14].value = line_width;
-
- sprintf (line_width, "%d", x->line_width_thick);
- dict[15].value = line_width_thick;
-
- if (!outp_title)
- {
- dict[16].value = cp = local_alloc (16);
- strcpy (cp, "PSPP");
- }
- else
- {
- dict[16].value = local_alloc (strlen (outp_title) + 1);
- strcpy ((char *) (dict[16].value), outp_title);
- }
-
- ps_var_tab = dict;
- while (-1 != getline (&buf, &buf_size, prologue_file))
- {
- char *cp;
-
- int len;
-
- cp = strstr (buf, "!eps");
- if (cp)
- {
- if (this->class->magic == MAGIC_PS)
- continue;
- else
- *cp = '\0';
- }
- else
- {
- cp = strstr (buf, "!ps");
- if (cp)
- {
- if (this->class->magic == MAGIC_EPSF)
- continue;
- else
- *cp = '\0';
- } else {
- if (strstr (buf, "!!!"))
- continue;
- }
- }
-
- if (!strncmp (buf, "!encodings", 10))
- output_encodings (this);
- else
- {
- struct string line;
- ds_create(&line, buf);
- fn_interp_vars(&line, ps_get_var);
- ds_ltrim_spaces(&line);
- len = ds_length(&line);
- fwrite (ds_c_str(&line), len, 1, f->file);
-
- ds_destroy(&line);
-
- fputs (x->eol, f->file);
- }
- }
- if (ferror (f->file))
- msg (IE, _("Reading `%s': %s."), prologue_fn, strerror (errno));
- fclose (prologue_file);
-
- free (prologue_fn);
- free (buf);
-
- local_free (dict[7].value);
- local_free (dict[8].value);
- local_free (dict[16].value);
-
- if (ferror (f->file))
- goto error;
-
- msg (VM (2), _("%s: PostScript prologue read successfully."), this->name);
- return 1;
-
-error:
- msg (VM (1), _("%s: Error reading PostScript prologue."), this->name);
- return 0;
-}
-
-/* Writes the string STRING to buffer DEST (of at least 288
- characters) as a PostScript name object. Returns a pointer
- to the null terminator of the resultant string. */
-static char *
-quote_ps_name (char *dest, const char *string)
-{
- const char *sp;
-
- for (sp = string; *sp; sp++)
- switch (*sp)
- {
- case 'a':
- case 'f':
- case 'k':
- case 'p':
- case 'u':
- case 'b':
- case 'g':
- case 'l':
- case 'q':
- case 'v':
- case 'c':
- case 'h':
- case 'm':
- case 'r':
- case 'w':
- case 'd':
- case 'i':
- case 'n':
- case 's':
- case 'x':
- case 'e':
- case 'j':
- case 'o':
- case 't':
- case 'y':
- case 'z':
- case 'A':
- case 'F':
- case 'K':
- case 'P':
- case 'U':
- case 'B':
- case 'G':
- case 'L':
- case 'Q':
- case 'V':
- case 'C':
- case 'H':
- case 'M':
- case 'R':
- case 'W':
- case 'D':
- case 'I':
- case 'N':
- case 'S':
- case 'X':
- case 'E':
- case 'J':
- case 'O':
- case 'T':
- case 'Y':
- case 'Z':
- case '@':
- case '^':
- case '_':
- case '|':
- case '!':
- case '$':
- case '&':
- case ':':
- case ';':
- case '.':
- case ',':
- case '-':
- case '+':
- break;
- default:
- {
- char *dp = dest;
-
- *dp++ = '<';
- for (sp = string; *sp && dp < &dest[256]; sp++)
- {
- sprintf (dp, "%02x", (unsigned char) *sp);
- dp += 2;
- }
- return stpcpy (dp, ">cvn");
- }
- }
- dest[0] = '/';
- return stpcpy (&dest[1], string);
-}
-
-/* Adds the string STRING to buffer DEST as a PostScript quoted
- string; returns a pointer to the null terminator added. Will not
- add more than 235 characters. */
-static char *
-quote_ps_string (char *dest, const char *string)
-{
- const char *sp = string;
- char *dp = dest;
-
- *dp++ = '(';
- for (; *sp && dp < &dest[235]; sp++)
- if (*sp == '(')
- dp = stpcpy (dp, "\\(");
- else if (*sp == ')')
- dp = stpcpy (dp, "\\)");
- else if (*sp < 32 || (unsigned char) *sp > 127)
- dp = spprintf (dp, "\\%3o", *sp);
- else
- *dp++ = *sp;
- return stpcpy (dp, ")");
-}
-
-/* Writes the PostScript epilogue to file F. */
-static int
-preclose (struct file_ext *f)
-{
- struct outp_driver *this = f->param;
- struct ps_driver_ext *x = this->ext;
- struct hsh_iterator iter;
- struct font_entry *fe;
-
- fprintf (f->file,
- ("%%%%Trailer%s"
- "%%%%Pages: %d%s"
- "%%%%DocumentNeededResources:%s"),
- x->eol, x->file_page_number, x->eol, x->eol);
-
- for (fe = hsh_first (x->loaded, &iter); fe != NULL;
- fe = hsh_next (x->loaded, &iter))
- {
- char buf[256], *cp;
-
- cp = stpcpy (buf, "%%+ font ");
- cp = quote_ps_string (cp, fe->font->internal_name);
- strcpy (cp, x->eol);
- fputs (buf, f->file);
- }
-
- hsh_destroy (x->loaded);
- x->loaded = NULL;
- hsh_destroy (x->combos);
- x->combos = NULL;
- x->last_font = NULL;
- x->next_combo = 0;
-
- fprintf (f->file, "%%EOF%s", x->eol);
- if (ferror (f->file))
- return 0;
- return 1;
-}
-
-static int
-ps_open_page (struct outp_driver *this)
-{
- struct ps_driver_ext *x = this->ext;
-
- assert (this->driver_open && !this->page_open);
-
- x->page_number++;
- if (!fn_open_ext (&x->file))
- {
- if (errno)
- msg (ME, _("PostScript output driver: %s: %s"), x->file.filename,
- strerror (errno));
- return 0;
- }
- x->file_page_number++;
-
- hsh_destroy (x->combos);
- x->combos = hsh_create (31, compare_ps_combo, hash_ps_combo,
- free_ps_combo, NULL);
- x->last_font = NULL;
- x->next_combo = 0;
-
- fprintf (x->file.file,
- "%%%%Page: %d %d%s"
- "%%%%BeginPageSetup%s"
- "/pg save def 0.001 dup scale%s",
- x->page_number, x->file_page_number, x->eol,
- x->eol,
- x->eol);
-
- if (x->orientation == OTN_LANDSCAPE)
- fprintf (x->file.file,
- "%d 0 translate 90 rotate%s",
- x->w, x->eol);
-
- if (x->bottom_margin != 0 || x->left_margin != 0)
- fprintf (x->file.file,
- "%d %d translate%s",
- x->left_margin, x->bottom_margin, x->eol);
-
- fprintf (x->file.file,
- "/LW %d def/TW %d def %d setlinewidth%s"
- "%%%%EndPageSetup%s",
- x->line_width, x->line_width_thick, x->line_width, x->eol,
- x->eol);
-
- if (!ferror (x->file.file))
- {
- this->page_open = 1;
- if (x->output_options & OPO_HEADERS)
- draw_headers (this);
- }
-
- this->cp_y = 0;
-
- return !ferror (x->file.file);
-}
-
-static int
-ps_close_page (struct outp_driver *this)
-{
- struct ps_driver_ext *x = this->ext;
-
- assert (this->driver_open && this->page_open);
-
- if (x->line_opt)
- dump_lines (this);
-
- fprintf (x->file.file,
- "%%PageTrailer%s"
- "EP%s",
- x->eol, x->eol);
-
- 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)