summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--man_term.c2
-rw-r--r--mdoc_term.c11
-rw-r--r--term.h15
-rw-r--r--term_ascii.c1
-rw-r--r--term_ps.c192
5 files changed, 153 insertions, 68 deletions
diff --git a/man_term.c b/man_term.c
index b5497e50..e1fc9ac9 100644
--- a/man_term.c
+++ b/man_term.c
@@ -73,9 +73,9 @@ struct termact {
static int a2width(const struct man_node *);
static int a2height(const struct man_node *);
-static void print_man_head(struct termp *, const void *);
static void print_man_nodelist(DECL_ARGS);
static void print_man_node(DECL_ARGS);
+static void print_man_head(struct termp *, const void *);
static void print_man_foot(struct termp *, const void *);
static void print_bvspace(struct termp *,
const struct man_node *);
diff --git a/mdoc_term.c b/mdoc_term.c
index 86a7fdde..35c169d6 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -65,9 +65,9 @@ static void print_bvspace(struct termp *,
const struct mdoc_node *,
const struct mdoc_node *);
static void print_mdoc_node(DECL_ARGS);
-static void print_mdoc_head(struct termp *, const void *);
static void print_mdoc_nodelist(DECL_ARGS);
-static void print_foot(struct termp *, const void *);
+static void print_mdoc_head(struct termp *, const void *);
+static void print_mdoc_foot(struct termp *, const void *);
static void synopsis_pre(struct termp *,
const struct mdoc_node *);
@@ -276,7 +276,8 @@ terminal_mdoc(void *arg, const struct mdoc *mdoc)
p->maxrmargin = p->defrmargin;
p->tabwidth = 5;
- term_begin(p, print_mdoc_head, print_foot, mdoc_meta(mdoc));
+ term_begin(p, print_mdoc_head,
+ print_mdoc_foot, mdoc_meta(mdoc));
if (NULL == p->symtab)
switch (p->enc) {
@@ -348,9 +349,8 @@ print_mdoc_node(DECL_ARGS)
}
-/* ARGSUSED */
static void
-print_foot(struct termp *p, const void *arg)
+print_mdoc_foot(struct termp *p, const void *arg)
{
char buf[DATESIZ], os[BUFSIZ];
const struct mdoc_meta *m;
@@ -400,7 +400,6 @@ print_foot(struct termp *p, const void *arg)
}
-/* ARGSUSED */
static void
print_mdoc_head(struct termp *p, const void *arg)
{
diff --git a/term.h b/term.h
index 54b9d46f..dad0a71d 100644
--- a/term.h
+++ b/term.h
@@ -41,12 +41,15 @@ enum termfont {
typedef void (*term_margin)(struct termp *, const void *);
struct termp_ps {
- int psstate; /* -Tps: state of ps output */
-#define PS_INLINE (1 << 0)
-#define PS_MARGINS (1 << 1)
- size_t pscol; /* -Tps: visible column */
- size_t psrow; /* -Tps: visible row */
- size_t pspage; /* -Tps: current page */
+ int psstate; /* state of ps output */
+#define PS_INLINE (1 << 0) /* we're in a word */
+#define PS_MARGINS (1 << 1) /* we're in the margins */
+ size_t pscol; /* visible column */
+ size_t psrow; /* visible row */
+ char *psmarg; /* margin buf */
+ size_t psmargsz; /* margin buf size */
+ size_t psmargcur; /* current pos in margin buf */
+ size_t pspage; /* current page */
};
struct termp {
diff --git a/term_ascii.c b/term_ascii.c
index 08e2a86c..85c33662 100644
--- a/term_ascii.c
+++ b/term_ascii.c
@@ -87,7 +87,6 @@ static void
ascii_letter(struct termp *p, char c)
{
- /* Just push onto the screen. */
putchar(c);
}
diff --git a/term_ps.c b/term_ps.c
index 23be426d..d795e56d 100644
--- a/term_ps.c
+++ b/term_ps.c
@@ -18,9 +18,13 @@
#include "config.h"
#endif
+#include <sys/param.h>
+
#include <assert.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "out.h"
#include "main.h"
@@ -34,12 +38,28 @@
#define PS_CHAR_BOTMARG 24
#define PS_CHAR_BOT (PS_CHAR_BOTMARG + 36)
+#define PS_BUFSLOP 128
+#define PS_GROWBUF(p, sz) \
+ do if ((p)->engine.ps.psmargcur + (sz) > \
+ (p)->engine.ps.psmargsz) { \
+ (p)->engine.ps.psmargsz += /* CONSTCOND */ \
+ MAX(PS_BUFSLOP, (sz)); \
+ (p)->engine.ps.psmarg = realloc \
+ ((p)->engine.ps.psmarg, \
+ (p)->engine.ps.psmargsz); \
+ if (NULL == (p)->engine.ps.psmarg) { \
+ perror(NULL); \
+ exit(EXIT_FAILURE); \
+ } \
+ } 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_pageopen(struct termp *);
static void ps_advance(struct termp *, size_t);
static void ps_endline(struct termp *);
+static void ps_printf(struct termp *, const char *, ...);
+static void ps_putchar(struct termp *, char);
void *
@@ -63,8 +83,68 @@ ps_alloc(void)
void
ps_free(void *arg)
{
+ struct termp *p;
+
+ p = (struct termp *)arg;
+
+ if (p->engine.ps.psmarg)
+ free(p->engine.ps.psmarg);
+
+ term_free(p);
+}
+
+
+static void
+ps_printf(struct termp *p, const char *fmt, ...)
+{
+ va_list ap;
+ int pos;
+
+ va_start(ap, fmt);
+
+ /*
+ * If we're running in regular mode, then pipe directly into
+ * vprintf(). If we're processing margins, then push the data
+ * into our growable margin buffer.
+ */
+
+ if ( ! (PS_MARGINS & p->engine.ps.psstate)) {
+ vprintf(fmt, ap);
+ va_end(ap);
+ return;
+ }
+
+ /*
+ * XXX: I assume that the in-margin print won't exceed
+ * PS_BUFSLOP (128 bytes), which is reasonable but still an
+ * assumption that will cause pukeage if it's not the case.
+ */
+
+ PS_GROWBUF(p, PS_BUFSLOP);
+
+ pos = (int)p->engine.ps.psmargcur;
+ vsnprintf(&p->engine.ps.psmarg[pos], PS_BUFSLOP, fmt, ap);
+ p->engine.ps.psmargcur = strlen(p->engine.ps.psmarg);
+}
+
+
+static void
+ps_putchar(struct termp *p, char c)
+{
+ int pos;
+
+ /* See ps_printf(). */
+
+ if ( ! (PS_MARGINS & p->engine.ps.psstate)) {
+ putchar(c);
+ return;
+ }
+
+ PS_GROWBUF(p, 2);
- term_free((struct termp *)arg);
+ pos = (int)p->engine.ps.psmargcur++;
+ p->engine.ps.psmarg[pos] = c;
+ p->engine.ps.psmarg[pos] = '\0';
}
@@ -73,6 +153,15 @@ static void
ps_end(struct termp *p)
{
+ /*
+ * At the end of the file, do one last showpage. This is the
+ * same behaviour as groff(1) and works for multiple pages as
+ * well as just one.
+ */
+
+ assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
+ printf("%s", p->engine.ps.psmarg);
+ printf("showpage\n");
printf("%s\n", "%%EOF");
}
@@ -90,9 +179,47 @@ ps_begin(struct termp *p)
printf("%s\n", "/Courier");
printf("%s\n", "10 selectfont");
- p->engine.ps.pspage = 1;
p->engine.ps.psstate = 0;
- ps_pageopen(p);
+
+ 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.pscol = PS_CHAR_LEFT;
+ p->engine.ps.psrow = PS_CHAR_TOPMARG;
+
+ p->engine.ps.psstate |= PS_MARGINS;
+
+ (*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);
+
+ 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]);
}
@@ -105,10 +232,9 @@ ps_letter(struct termp *p, char c)
* If we're not in a PostScript "word" context, then
* open one now at the current cursor.
*/
- printf("%zu %zu moveto\n",
+ ps_printf(p, "%zu %zu moveto\n(",
p->engine.ps.pscol,
p->engine.ps.psrow);
- putchar('(');
p->engine.ps.psstate |= PS_INLINE;
}
@@ -125,64 +251,25 @@ ps_letter(struct termp *p, char c)
case (')'):
/* FALLTHROUGH */
case ('\\'):
- putchar('\\');
+ ps_putchar(p, '\\');
break;
default:
break;
}
/* Write the character and adjust where we are on the page. */
- putchar(c);
+ ps_putchar(p, c);
p->engine.ps.pscol += PS_CHAR_WIDTH;
}
-/*
- * Open a page. This is only used for -Tps at the moment. It opens a
- * page context, printing the header and the footer. THE OUTPUT BUFFER
- * MUST BE EMPTY. If it is not, output will ghost on the next line and
- * we'll be all gross and out of state.
- */
-static void
-ps_pageopen(struct termp *p)
-{
-
- assert(TERMTYPE_PS == p->type);
- assert(0 == p->engine.ps.psstate);
-
- p->engine.ps.pscol = PS_CHAR_LEFT;
- p->engine.ps.psrow = PS_CHAR_TOPMARG;
- p->engine.ps.psstate |= PS_MARGINS;
-
- (*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);
-
- p->engine.ps.pscol = PS_CHAR_LEFT;
- p->engine.ps.psrow = PS_CHAR_TOP;
-
-}
-
-
static void
ps_advance(struct termp *p, size_t len)
{
if (PS_INLINE & p->engine.ps.psstate) {
/* Dump out any existing line scope. */
- printf(") show\n");
+ ps_printf(p, ") show\n");
p->engine.ps.psstate &= ~PS_INLINE;
}
@@ -195,7 +282,7 @@ ps_endline(struct termp *p)
{
if (PS_INLINE & p->engine.ps.psstate) {
- printf(") show\n");
+ ps_printf(p, ") show\n");
p->engine.ps.psstate &= ~PS_INLINE;
}
@@ -208,11 +295,8 @@ ps_endline(struct termp *p)
return;
}
- /*
- * XXX: can't run pageopen() until we're certain a flushln() has
- * occured, else the buf will reopen in an awkward state on the
- * next line.
- */
+ assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
+ printf("%s", p->engine.ps.psmarg);
printf("showpage\n");
p->engine.ps.psrow = PS_CHAR_TOP;
}