summaryrefslogtreecommitdiff
path: root/usr.bin/mandoc/term_ps.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@cvs.openbsd.org>2010-06-26 17:56:44 +0000
committerIngo Schwarze <schwarze@cvs.openbsd.org>2010-06-26 17:56:44 +0000
commitb8356f8ddb7db759bb2d0127e1d696abbc40a6b7 (patch)
treec6440ef0074ad1cb8ade3e95a121ba58e421aa40 /usr.bin/mandoc/term_ps.c
parent3d32c5d68dc8f6ddc0ced4e6c6b8148e0c22c1cb (diff)
merge release 1.10.2
* bug fixes: - interaction of ASCII_HYPH with special chars (found by Ulrich Spoerlein) - handling of roff conditionals (found by Ulrich Spoerlein) - .Bd -offset will no more default to 6n * maintenance: - more caching of .Bd and .Bl arguments for efficiency - deconstify man(7) validation routines - add FreeBSD library names (provided by Ulrich Spoerlein) * start PostScript font-switching
Diffstat (limited to 'usr.bin/mandoc/term_ps.c')
-rw-r--r--usr.bin/mandoc/term_ps.c203
1 files changed, 163 insertions, 40 deletions
diff --git a/usr.bin/mandoc/term_ps.c b/usr.bin/mandoc/term_ps.c
index 8d887c74d4a..e5b4710eb3b 100644
--- a/usr.bin/mandoc/term_ps.c
+++ b/usr.bin/mandoc/term_ps.c
@@ -1,6 +1,6 @@
-/* $Id: term_ps.c,v 1.1 2010/06/10 22:50:10 schwarze Exp $ */
+/* $Id: term_ps.c,v 1.2 2010/06/26 17:56:43 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
+ * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -53,13 +53,18 @@
} \
} while (/* CONSTCOND */ 0)
+
static void ps_letter(struct termp *, char);
static void ps_begin(struct termp *);
static void ps_end(struct termp *);
static void ps_advance(struct termp *, size_t);
static void ps_endline(struct termp *);
+static void ps_fclose(struct termp *);
+static void ps_pclose(struct termp *);
+static void ps_pletter(struct termp *, char);
static void ps_printf(struct termp *, const char *, ...);
static void ps_putchar(struct termp *, char);
+static void ps_setfont(struct termp *, enum termfont);
void *
@@ -161,6 +166,8 @@ ps_end(struct termp *p)
* well as just one.
*/
+ assert(0 == p->engine.ps.psstate);
+ assert('\0' == p->engine.ps.last);
assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
printf("%s", p->engine.ps.psmarg);
printf("showpage\n");
@@ -172,68 +179,60 @@ static void
ps_begin(struct termp *p)
{
- /*
- * Emit the standard PostScript prologue, set our initial page
- * position, then run pageopen() on the initial page.
+ /*
+ * Print margins into margin buffer. Nothing gets output to the
+ * screen yet, so we don't need to initialise the primary state.
*/
- printf("%s\n", "%!PS");
- printf("%s\n", "/Courier");
- printf("%s\n", "10 selectfont");
-
- p->engine.ps.psstate = 0;
-
if (p->engine.ps.psmarg) {
assert(p->engine.ps.psmargsz);
p->engine.ps.psmarg[0] = '\0';
}
p->engine.ps.psmargcur = 0;
-
- /*
- * Now dump the margins into our margin buffer. If we don't do
- * this, we'd break any current state to run the header and
- * footer with each and evern new page.
- */
-
+ p->engine.ps.psstate = PS_MARGINS;
p->engine.ps.pscol = PS_CHAR_LEFT;
p->engine.ps.psrow = PS_CHAR_TOPMARG;
- p->engine.ps.psstate |= PS_MARGINS;
+ ps_setfont(p, TERMFONT_NONE);
(*p->headf)(p, p->argf);
(*p->endline)(p);
- p->engine.ps.psstate &= ~PS_MARGINS;
- assert(0 == p->engine.ps.psstate);
-
p->engine.ps.pscol = PS_CHAR_LEFT;
p->engine.ps.psrow = PS_CHAR_BOTMARG;
- p->engine.ps.psstate |= PS_MARGINS;
(*p->footf)(p, p->argf);
(*p->endline)(p);
p->engine.ps.psstate &= ~PS_MARGINS;
+
assert(0 == p->engine.ps.psstate);
+ assert(p->engine.ps.psmarg);
+ assert('\0' != p->engine.ps.psmarg[0]);
+ /*
+ * Print header and initialise page state. Following this,
+ * stuff gets printed to the screen, so make sure we're sane.
+ */
+
+ printf("%s\n", "%!PS");
+ ps_setfont(p, TERMFONT_NONE);
p->engine.ps.pscol = PS_CHAR_LEFT;
p->engine.ps.psrow = PS_CHAR_TOP;
-
- assert(p->engine.ps.psmarg);
- assert('\0' != p->engine.ps.psmarg[0]);
}
static void
-ps_letter(struct termp *p, char c)
+ps_pletter(struct termp *p, char c)
{
+ /*
+ * If we're not in a PostScript "word" context, then open one
+ * now at the current cursor.
+ */
+
if ( ! (PS_INLINE & p->engine.ps.psstate)) {
- /*
- * If we're not in a PostScript "word" context, then
- * open one now at the current cursor.
- */
ps_printf(p, "%zu %zu moveto\n(",
p->engine.ps.pscol,
p->engine.ps.psrow);
@@ -260,21 +259,118 @@ ps_letter(struct termp *p, char c)
}
/* Write the character and adjust where we are on the page. */
+
ps_putchar(p, c);
p->engine.ps.pscol += PS_CHAR_WIDTH;
}
static void
-ps_advance(struct termp *p, size_t len)
+ps_pclose(struct termp *p)
{
- if (PS_INLINE & p->engine.ps.psstate) {
- /* Dump out any existing line scope. */
- ps_printf(p, ") show\n");
- p->engine.ps.psstate &= ~PS_INLINE;
+ /*
+ * Spit out that we're exiting a word context (this is a
+ * "partial close" because we don't check the last-char buffer
+ * or anything).
+ */
+
+ if ( ! (PS_INLINE & p->engine.ps.psstate))
+ return;
+
+ ps_printf(p, ") show\n");
+ p->engine.ps.psstate &= ~PS_INLINE;
+}
+
+
+static void
+ps_fclose(struct termp *p)
+{
+
+ /*
+ * Strong closure: if we have a last-char, spit it out after
+ * checking that we're in the right font mode. This will of
+ * course open a new scope, if applicable.
+ *
+ * Following this, close out any scope that's open.
+ */
+
+ if ('\0' != p->engine.ps.last) {
+ if (p->engine.ps.lastf != TERMFONT_NONE) {
+ ps_pclose(p);
+ ps_setfont(p, TERMFONT_NONE);
+ }
+ ps_pletter(p, p->engine.ps.last);
+ p->engine.ps.last = '\0';
}
+ if ( ! (PS_INLINE & p->engine.ps.psstate))
+ return;
+
+ ps_pclose(p);
+}
+
+
+static void
+ps_letter(struct termp *p, char c)
+{
+ char cc;
+
+ /*
+ * State machine dictates whether to buffer the last character
+ * or not. Basically, encoded words are detected by checking if
+ * we're an "8" and switching on the buffer. Then we put "8" in
+ * our buffer, and on the next charater, flush both character
+ * and buffer. Thus, "regular" words are detected by having a
+ * regular character and a regular buffer character.
+ */
+
+ if ('\0' == p->engine.ps.last) {
+ assert(8 != c);
+ p->engine.ps.last = c;
+ return;
+ } else if (8 == p->engine.ps.last) {
+ assert(8 != c);
+ p->engine.ps.last = '\0';
+ } else if (8 == c) {
+ assert(8 != p->engine.ps.last);
+ if ('_' == p->engine.ps.last) {
+ if (p->engine.ps.lastf != TERMFONT_UNDER) {
+ ps_pclose(p);
+ ps_setfont(p, TERMFONT_UNDER);
+ }
+ } else if (p->engine.ps.lastf != TERMFONT_BOLD) {
+ ps_pclose(p);
+ ps_setfont(p, TERMFONT_BOLD);
+ }
+ p->engine.ps.last = c;
+ return;
+ } else {
+ if (p->engine.ps.lastf != TERMFONT_NONE) {
+ ps_pclose(p);
+ ps_setfont(p, TERMFONT_NONE);
+ }
+ cc = p->engine.ps.last;
+ p->engine.ps.last = c;
+ c = cc;
+ }
+
+ ps_pletter(p, c);
+}
+
+
+static void
+ps_advance(struct termp *p, size_t len)
+{
+
+ /*
+ * Advance some spaces. This can probably be made smarter,
+ * i.e., to have multiple space-separated words in the same
+ * scope, but this is easier: just close out the current scope
+ * and readjust our column settings.
+ */
+
+ ps_fclose(p);
p->engine.ps.pscol += len ? len * PS_CHAR_WIDTH : 0;
}
@@ -283,14 +379,24 @@ static void
ps_endline(struct termp *p)
{
- if (PS_INLINE & p->engine.ps.psstate) {
- ps_printf(p, ") show\n");
- p->engine.ps.psstate &= ~PS_INLINE;
- }
+ /* Close out any scopes we have open: we're at eoln. */
+
+ ps_fclose(p);
+
+ /*
+ * If we're in the margin, don't try to recalculate our current
+ * row. XXX: if the column tries to be fancy with multiple
+ * lines, we'll do nasty stuff.
+ */
if (PS_MARGINS & p->engine.ps.psstate)
return;
+ /*
+ * Put us down a line. If we're at the page bottom, spit out a
+ * showpage and restart our row.
+ */
+
p->engine.ps.pscol = PS_CHAR_LEFT;
if (p->engine.ps.psrow >= PS_CHAR_HEIGHT + PS_CHAR_BOT) {
p->engine.ps.psrow -= PS_CHAR_HEIGHT;
@@ -302,3 +408,20 @@ ps_endline(struct termp *p)
printf("showpage\n");
p->engine.ps.psrow = PS_CHAR_TOP;
}
+
+
+static void
+ps_setfont(struct termp *p, enum termfont f)
+{
+
+ if (TERMFONT_BOLD == f)
+ ps_printf(p, "/Courier-Bold\n");
+ else if (TERMFONT_UNDER == f)
+ ps_printf(p, "/Courier-Oblique\n");
+ else
+ ps_printf(p, "/Courier\n");
+
+ ps_printf(p, "10 selectfont\n");
+ p->engine.ps.lastf = f;
+}
+