source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Have the standard manpage header and footer print on every page
@ 2010-06-09  8:07 kristaps
  0 siblings, 0 replies; only message in thread
From: kristaps @ 2010-06-09  8:07 UTC (permalink / raw)
  To: source

Log Message:
-----------
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.

Modified Files:
--------------
    mdocml:
        man_term.c
        mdoc_term.c
        term.h
        term_ascii.c
        term_ps.c

Revision Data
-------------
Index: term.h
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/term.h,v
retrieving revision 1.60
retrieving revision 1.61
diff -Lterm.h -Lterm.h -u -p -r1.60 -r1.61
--- term.h
+++ 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 {
Index: man_term.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/man_term.c,v
retrieving revision 1.73
retrieving revision 1.74
diff -Lman_term.c -Lman_term.c -u -p -r1.73 -r1.74
--- man_term.c
+++ 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 *);
Index: term_ascii.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/term_ascii.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -Lterm_ascii.c -Lterm_ascii.c -u -p -r1.2 -r1.3
--- term_ascii.c
+++ term_ascii.c
@@ -87,7 +87,6 @@ static void
 ascii_letter(struct termp *p, char c)
 {
 	
-	/* Just push onto the screen. */
 	putchar(c);
 }
 
Index: mdoc_term.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/mdoc_term.c,v
retrieving revision 1.144
retrieving revision 1.145
diff -Lmdoc_term.c -Lmdoc_term.c -u -p -r1.144 -r1.145
--- mdoc_term.c
+++ 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 md
 	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 *
 }
 
 
-/* ARGSUSED */
 static void
 print_mdoc_head(struct termp *p, const void *arg)
 {
Index: term_ps.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/term_ps.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -Lterm_ps.c -Lterm_ps.c -u -p -r1.3 -r1.4
--- term_ps.c
+++ 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;
+	}
 
-	term_free((struct termp *)arg);
+	PS_GROWBUF(p, 2);
+
+	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;
 }
--
 To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2010-06-09  8:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-09  8:07 mdocml: Have the standard manpage header and footer print on every page kristaps

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).