- 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))
- {
- 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 (strlen (dict[17].value) + 30);
- sprintf (cp, "PSPP (%s)", dict[17].value);
- }
- 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;
- char *buf2;
- 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
- {
- char *beg;
- beg = buf2 = fn_interp_vars (buf, ps_get_var);
- len = strlen (buf2);
- while (isspace ((unsigned char) *beg))
- beg++, len--;
- if (beg[len - 1] == '\n')
- len--;
- if (beg[len - 1] == '\r')
- len--;
- fwrite (beg, len, 1, f->file);
- fputs (x->eol, f->file);
- free (buf2);
- }
- }
- 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)
- {
- case SOM_CHART:
- break;
- default:
- assert(0);
- break;
- }
-}
-\f
-/* Lines. */
-
-/* qsort() comparison function for int tuples. */
-static int
-int_2_compare (const void *a_, const void *b_)
-{
- const int *a = a_;
- const int *b = b_;
-
- return *a < *b ? -1 : *a > *b;
-}
-
-/* Hash table comparison function for cached lines. */
-static int
-compare_line (const void *a_, const void *b_, void *foo UNUSED)
-{
- const struct line_form *a = a_;
- const struct line_form *b = b_;
-
- return a->ind < b->ind ? -1 : a->ind > b->ind;
-}
-
-/* Hash table hash function for cached lines. */
-static unsigned
-hash_line (const void *pa, void *foo UNUSED)
-{
- const struct line_form *a = pa;
-
- return a->ind;
-}
-
-/* Hash table free function for cached lines. */
-static void
-free_line (void *pa, void *foo UNUSED)
-{
- free (pa);
-}
-
-/* Writes PostScript code to draw a line from (x1,y1) to (x2,y2) to
- the output file. */
-#define dump_line(x1, y1, x2, y2) \
- fprintf (ext->file.file, "%d %d %d %d L%s", \
- x1, YT (y1), x2, YT (y2), ext->eol)
-
-/* Write PostScript code to draw a thick line from (x1,y1) to (x2,y2)
- to the output file. */
-#define dump_thick_line(x1, y1, x2, y2) \
- fprintf (ext->file.file, "%d %d %d %d TL%s", \
- x1, YT (y1), x2, YT (y2), ext->eol)
-
-/* Writes a line of type TYPE to THIS driver's output file. The line
- (or its center, in the case of double lines) has its independent
- axis coordinate at IND; it extends from DEP1 to DEP2 on the
- dependent axis. */
-static void
-dump_fancy_line (struct outp_driver *this, int type, int ind, int dep1, int dep2)
-{
- struct ps_driver_ext *ext = this->ext;
- int ofs = ext->line_space / 2 + ext->line_width / 2;
-
- switch (type)
- {
- case horz:
- dump_line (dep1, ind, dep2, ind);
- break;
- case dbl_horz:
- if (ext->output_options & OPO_DOUBLE_LINE)
- {
- dump_line (dep1, ind - ofs, dep2, ind - ofs);
- dump_line (dep1, ind + ofs, dep2, ind + ofs);
- }
- else
- dump_thick_line (dep1, ind, dep2, ind);
- break;
- case spl_horz:
- assert (0);
- case vert:
- dump_line (ind, dep1, ind, dep2);
- break;
- case dbl_vert:
- if (ext->output_options & OPO_DOUBLE_LINE)
- {
- dump_line (ind - ofs, dep1, ind - ofs, dep2);
- dump_line (ind + ofs, dep1, ind + ofs, dep2);
- }
- else
- dump_thick_line (ind, dep1, ind, dep2);
- break;
- case spl_vert:
- assert (0);
- default:
- assert (0);
- }
-}
-
-#undef dump_line
-
-/* Writes all the cached lines to the output file, then clears the
- cache. */
-static void
-dump_lines (struct outp_driver *this)
-{
- struct ps_driver_ext *x = this->ext;
-
- struct hsh_iterator iter;
- int type;
-
- for (type = 0; type < n_line_types; type++)
- {
- struct line_form *line;
-
- if (x->lines[type] == NULL)
- continue;
-
- for (line = hsh_first (x->lines[type], &iter); line != NULL;
- line = hsh_next (x->lines[type], &iter))
- {
- int i;
- int lo = INT_MIN, hi;
-
- qsort (line->dep, line->ndep, sizeof *line->dep, int_2_compare);
- lo = line->dep[0][0];
- hi = line->dep[0][1];
- for (i = 1; i < line->ndep; i++)
- if (line->dep[i][0] <= hi + 1)
- {
- int min_hi = line->dep[i][1];
- if (min_hi > hi)
- hi = min_hi;
- }
- else
- {
- dump_fancy_line (this, type, line->ind, lo, hi);
- lo = line->dep[i][0];
- hi = line->dep[i][1];
- }
- dump_fancy_line (this, type, line->ind, lo, hi);
- }
-
- hsh_destroy (x->lines[type]);
- x->lines[type] = NULL;
- }
-}
-
-/* (Same args as dump_fancy_line()). Either dumps the line directly
- to the output file, or adds it to the cache, depending on the
- user-selected line optimization mode. */
-static void
-line (struct outp_driver *this, int type, int ind, int dep1, int dep2)
-{
- struct ps_driver_ext *ext = this->ext;
- struct line_form **f;
-
- assert (dep2 >= dep1);
- if (ext->line_opt == 0)
- {
- dump_fancy_line (this, type, ind, dep1, dep2);
- return;
- }
-
- if (ext->lines[type] == NULL)
- ext->lines[type] = hsh_create (31, compare_line, hash_line,
- free_line, NULL);
- f = (struct line_form **) hsh_probe (ext->lines[type], &ind);
- if (*f == NULL)
- {
- *f = xmalloc (sizeof **f + sizeof (int[15][2]));
- (*f)->ind = ind;
- (*f)->mdep = 16;
- (*f)->ndep = 1;
- (*f)->dep[0][0] = dep1;
- (*f)->dep[0][1] = dep2;
- return;
- }
- if ((*f)->ndep >= (*f)->mdep)
- {
- (*f)->mdep += 16;
- *f = xrealloc (*f, sizeof **f + sizeof (int[2]) * ((*f)->mdep - 1));
- }
- (*f)->dep[(*f)->ndep][0] = dep1;
- (*f)->dep[(*f)->ndep][1] = dep2;
- (*f)->ndep++;
-}
-
-static void
-ps_line_horz (struct outp_driver *this, const struct rect *r,
- const struct color *c UNUSED, int style)
-{
- /* Must match output.h:OUTP_L_*. */
- static const int types[OUTP_L_COUNT] =
- {-1, horz, dbl_horz, spl_horz};
-
- int y = (r->y1 + r->y2) / 2;
-
- assert (this->driver_open && this->page_open);
- assert (style >= 0 && style < OUTP_L_COUNT);
- style = types[style];
- if (style != -1)
- line (this, style, y, r->x1, r->x2);
-}
-
-static void
-ps_line_vert (struct outp_driver *this, const struct rect *r,
- const struct color *c UNUSED, int style)
-{
- /* Must match output.h:OUTP_L_*. */
- static const int types[OUTP_L_COUNT] =
- {-1, vert, dbl_vert, spl_vert};
-
- int x = (r->x1 + r->x2) / 2;
-
- assert (this->driver_open && this->page_open);
- assert (style >= 0 && style < OUTP_L_COUNT);
- style = types[style];
- if (style != -1)
- line (this, style, x, r->y1, r->y2);
-}
-
-#define L (style->l != OUTP_L_NONE)
-#define R (style->r != OUTP_L_NONE)
-#define T (style->t != OUTP_L_NONE)
-#define B (style->b != OUTP_L_NONE)
-
-static void
-ps_line_intersection (struct outp_driver *this, const struct rect *r,
- const struct color *c UNUSED,
- const struct outp_styles *style)
-{
- struct ps_driver_ext *ext = this->ext;
-
- int x = (r->x1 + r->x2) / 2;
- int y = (r->y1 + r->y2) / 2;
- int ofs = (ext->line_space + ext->line_width) / 2;
- int x1 = x - ofs, x2 = x + ofs;
- int y1 = y - ofs, y2 = y + ofs;
-
- assert (this->driver_open && this->page_open);
- assert (!((style->l != style->r && style->l != OUTP_L_NONE
- && style->r != OUTP_L_NONE)
- || (style->t != style->b && style->t != OUTP_L_NONE
- && style->b != OUTP_L_NONE)));
-
- switch ((style->l | style->r) | ((style->t | style->b) << 8))
- {
- case (OUTP_L_SINGLE) | (OUTP_L_SINGLE << 8):
- case (OUTP_L_SINGLE) | (OUTP_L_NONE << 8):
- case (OUTP_L_NONE) | (OUTP_L_SINGLE << 8):
- if (L)
- line (this, horz, y, r->x1, x);
- if (R)
- line (this, horz, y, x, r->x2);
- if (T)
- line (this, vert, x, r->y1, y);
- if (B)
- line (this, vert, x, y, r->y2);
- break;
- case (OUTP_L_SINGLE) | (OUTP_L_DOUBLE << 8):
- case (OUTP_L_NONE) | (OUTP_L_DOUBLE << 8):
- if (L)
- line (this, horz, y, r->x1, x1);
- if (R)
- line (this, horz, y, x2, r->x2);
- if (T)
- line (this, dbl_vert, x, r->y1, y);
- if (B)
- line (this, dbl_vert, x, y, r->y2);
- if ((L && R) && !(T && B))
- line (this, horz, y, x1, x2);
- break;
- case (OUTP_L_DOUBLE) | (OUTP_L_SINGLE << 8):
- case (OUTP_L_DOUBLE) | (OUTP_L_NONE << 8):
- if (L)
- line (this, dbl_horz, y, r->x1, x);
- if (R)
- line (this, dbl_horz, y, x, r->x2);
- if (T)
- line (this, vert, x, r->y1, y);
- if (B)
- line (this, vert, x, y, r->y2);
- if ((T && B) && !(L && R))
- line (this, vert, x, y1, y2);
- break;
- case (OUTP_L_DOUBLE) | (OUTP_L_DOUBLE << 8):
- if (L)
- line (this, dbl_horz, y, r->x1, x);
- if (R)
- line (this, dbl_horz, y, x, r->x2);
- if (T)
- line (this, dbl_vert, x, r->y1, y);
- if (B)
- line (this, dbl_vert, x, y, r->y2);
- if (T && B && !L)
- line (this, vert, x1, y1, y2);
- if (T && B && !R)
- line (this, vert, x2, y1, y2);
- if (L && R && !T)
- line (this, horz, y1, x1, x2);
- if (L && R && !B)
- line (this, horz, y2, x1, x2);
- break;
- default:
- assert (0);
- }
-}
-
-static void
-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)
-{
- assert (this->driver_open && this->page_open);
-}
-static void
-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)
-{
- assert (this->driver_open && this->page_open);
-}
-
-/* Returns the width of string S for THIS driver. */
-static int
-text_width (struct outp_driver *this, char *s)
-{
- struct outp_text text;
-
- text.options = OUTP_T_JUST_LEFT;
- ls_init (&text.s, s, strlen (s));
- this->class->text_metrics (this, &text);
- return text.h;
-}
-
-/* Write string S at location (X,Y) with width W for THIS driver. */
-static void
-out_text_plain (struct outp_driver *this, char *s, int x, int y, int w)
-{
- struct outp_text text;
-
- text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
- ls_init (&text.s, s, strlen (s));
- text.h = w;
- text.v = this->font_height;
- text.x = x;
- text.y = y;
- this->class->text_draw (this, &text);
-}
-
-/* Draw top of page headers for THIS driver. */
-static void
-draw_headers (struct outp_driver *this)
-{
- struct ps_driver_ext *ext = this->ext;
-
- struct font_entry *old_current = ext->current;
- char *old_family = xstrdup (ext->family); /* FIXME */
- int old_size = ext->size;
-
- int fh = this->font_height;
- int y = -3 * fh;
-
- fprintf (ext->file.file, "%d %d %d %d GB%s",
- 0, YT (y), this->width, YT (y + 2 * fh + ext->line_gutter),
- ext->eol);
- this->class->text_set_font_family (this, "T");
-
- y += ext->line_width + ext->line_gutter;
-
- {
- int rh_width;
- char buf[128];
-
- sprintf (buf, _("%s - Page %d"), get_start_date (), ext->page_number);
- rh_width = text_width (this, buf);
-
- out_text_plain (this, buf, this->width - this->prop_em_width - rh_width,
- y, rh_width);
-
- if (outp_title && outp_subtitle)
- out_text_plain (this, outp_title, this->prop_em_width, y,
- this->width - 3 * this->prop_em_width - rh_width);
-
- y += fh;
- }
-
- {
- int rh_width;
- char buf[128];
- char *string = outp_subtitle ? outp_subtitle : outp_title;
-
- sprintf (buf, "%s - %s", version, host_system);
- rh_width = text_width (this, buf);
-
- out_text_plain (this, buf, this->width - this->prop_em_width - rh_width,
- y, rh_width);
-
- if (string)
- out_text_plain (this, string, this->prop_em_width, y,
- this->width - 3 * this->prop_em_width - rh_width);
-
- y += fh;
- }
-
- ext->current = old_current;
- free (ext->family);
- ext->family = old_family;
- ext->size = old_size;
-}
-
-\f
-/* Text. */
-
-static void
-ps_text_set_font_by_name (struct outp_driver *this, const char *dit)
-{
- struct ps_driver_ext *x = this->ext;
- struct font_entry *fe;
-
- assert (this->driver_open && this->page_open);
-
- /* Short-circuit common fonts. */
- if (!strcmp (dit, "PROP"))
- {
- x->current = x->prop;
- x->size = x->font_size;
- return;
- }
- else if (!strcmp (dit, "FIXED"))
- {
- x->current = x->fixed;
- x->size = x->font_size;
- return;
- }
-
- /* Find font_desc corresponding to Groff name dit. */
- fe = hsh_find (x->loaded, &dit);
- if (fe == NULL)
- fe = load_font (this, dit);
- x->current = fe;
-}
-
-static void
-ps_text_set_font_by_position (struct outp_driver *this, int pos)
-{
- struct ps_driver_ext *x = this->ext;
- char *dit;
-
- assert (this->driver_open && this->page_open);
-
- /* Determine font name by suffixing position string to font family
- name. */
- {
- char *cp;
-
- dit = local_alloc (strlen (x->family) + 3);
- cp = stpcpy (dit, x->family);
- switch (pos)
- {
- case OUTP_F_R:
- *cp++ = 'R';
- break;
- case OUTP_F_I:
- *cp++ = 'I';
- break;
- case OUTP_F_B:
- *cp++ = 'B';
- break;
- case OUTP_F_BI:
- *cp++ = 'B';
- *cp++ = 'I';
- break;
- default:
- assert(0);
- }
- *cp++ = 0;
- }
-
- /* Find font_desc corresponding to Groff name dit. */
- {
- struct font_entry *fe = hsh_find (x->loaded, &dit);
- if (fe == NULL)
- fe = load_font (this, dit);
- x->current = fe;
- }
-
- local_free (dit);