aboutsummaryrefslogtreecommitdiffstatshomepage
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
commitdbcb21471c73a93f9436d4a342a5cc07d74fbf47 (patch)
treeaf1d82c5a84624d1e711a284999c60edd3fff340
parent08669f3b61bca274d2da8109ff9079c3c9d33a6c (diff)
downloadmandoc-dbcb21471c73a93f9436d4a342a5cc07d74fbf47.tar.gz
mandoc-dbcb21471c73a93f9436d4a342a5cc07d74fbf47.tar.zst
mandoc-dbcb21471c73a93f9436d4a342a5cc07d74fbf47.zip
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.c4
-rw-r--r--mdoc_term.c13
-rw-r--r--term.h17
-rw-r--r--term_ascii.c3
-rw-r--r--term_ps.c194
5 files changed, 158 insertions, 73 deletions
diff --git a/man_term.c b/man_term.c
index a7a1a652..bde3aa07 100644
--- a/man_term.c
+++ b/man_term.c
@@ -1,4 +1,4 @@
-/* $Id: man_term.c,v 1.73 2010/06/07 20:57:09 kristaps Exp $ */
+/* $Id: man_term.c,v 1.74 2010/06/09 08:07:13 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
*
@@ -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 915e8994..20ce1076 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_term.c,v 1.144 2010/06/07 20:57:09 kristaps Exp $ */
+/* $Id: mdoc_term.c,v 1.145 2010/06/09 08:07:13 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
*
@@ -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 427610f4..ace4b9ba 100644
--- a/term.h
+++ b/term.h
@@ -1,4 +1,4 @@
-/* $Id: term.h,v 1.60 2010/06/08 15:00:17 kristaps Exp $ */
+/* $Id: term.h,v 1.61 2010/06/09 08:07:13 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
*
@@ -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 d38450e5..017aa417 100644
--- a/term_ascii.c
+++ b/term_ascii.c
@@ -1,4 +1,4 @@
-/* $Id: term_ascii.c,v 1.2 2010/06/08 15:06:01 kristaps Exp $ */
+/* $Id: term_ascii.c,v 1.3 2010/06/09 08:07:13 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
*
@@ -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 1ba93bda..0d424035 100644
--- a/term_ps.c
+++ b/term_ps.c
@@ -1,4 +1,4 @@
-/* $Id: term_ps.c,v 1.3 2010/06/08 15:06:01 kristaps Exp $ */
+/* $Id: term_ps.c,v 1.4 2010/06/09 08:07:13 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
*
@@ -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;
}