summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2010-06-09 08:07:13 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2010-06-09 08:07:13 +0000
commit21a2b28bbf9477322208667281f6c561985a17d7 (patch)
tree357aa266e5748aa0e24241f07ebb47fc556c4474
parent04759c423ec318452d781322725260af09ce908a (diff)
downloadmandoc-21a2b28bbf9477322208667281f6c561985a17d7.tar.gz
Have the standard manpage header and footer print on every page of -Tps
output. This is more tricky than you may think: we can't just call the header function out-of-state (i.e., before a flushln has occured) because we'd clobber our current state. Thus, we call at the beginning and dump the output into an auxiliary buffer. For the record, I don't think there's any other clean way to do this. The only other Way That Works is to copy-aside *all* termp state, zero it, and do the necessary headf/footf. This is just as complex, as memory needs to be alloc'd and free'd per margin. Unfortunately, this prohibits page numbering (the margin is only printed once), so I'll probably end up re-writing this down the line.
-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;
}