X-Git-Url: https://git.cameronkatri.com/mandoc.git/blobdiff_plain/bd329dd8fae21fc03372e563b33ef77a421e7ea9..4ecd5f379a9ede899bebfe6091fd0b1acba5a49c:/mdoc_term.c

diff --git a/mdoc_term.c b/mdoc_term.c
index 9b40a4ca..e7329d2a 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -1,20 +1,18 @@
-/* $Id: mdoc_term.c,v 1.3 2009/03/26 16:23:22 kristaps Exp $ */
+/*	$Id: mdoc_term.c,v 1.20 2009/07/04 11:07:34 kristaps Exp $ */
 /*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
+ * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies.
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include <sys/types.h>
 
@@ -88,10 +86,10 @@ struct	termpair {
 	struct termpair	 *ppair;
 	int		  type;
 #define	TERMPAIR_FLAG	 (1 << 0)
-	int	  	  flag;
-	size_t	  	  offset;
-	size_t	  	  rmargin;
-	int		  count;
+	int	  	  flag;		/* Whether being used. */
+	size_t	  	  offset;	/* Left margin. */
+	size_t	  	  rmargin;	/* Right margin. */
+	int		  count;	/* Enum count. */
 };
 
 #define	TERMPAIR_SETFLAG(termp, p, fl) \
@@ -185,7 +183,7 @@ struct	termact {
 };
 
 static const struct termact termacts[MDOC_MAX] = {
-	{ NULL, NULL }, /* \" */
+	{ termp_ap_pre, NULL }, /* Ap */
 	{ NULL, NULL }, /* Dd */
 	{ NULL, NULL }, /* Dt */
 	{ NULL, NULL }, /* Os */
@@ -292,8 +290,7 @@ static const struct termact termacts[MDOC_MAX] = {
 	{ NULL, NULL }, /* Fr */
 	{ termp_ud_pre, NULL }, /* Ud */
 	{ termp_lb_pre, termp_lb_post }, /* Lb */
-	{ termp_ap_pre, NULL }, /* Lb */
-	{ termp_pp_pre, NULL }, /* Pp */ 
+	{ termp_pp_pre, NULL }, /* Lp */ 
 	{ termp_lk_pre, NULL }, /* Lk */ 
 	{ termp_mt_pre, NULL }, /* Mt */ 
 	{ termp_brq_pre, termp_brq_post }, /* Brq */ 
@@ -307,8 +304,8 @@ static const struct termact termacts[MDOC_MAX] = {
 };
 
 #ifdef __linux__
-extern	size_t		  strlcpy(char *, const char *, size_t);
-extern	size_t		  strlcat(char *, const char *, size_t);
+extern	size_t	  strlcpy(char *, const char *, size_t);
+extern	size_t	  strlcat(char *, const char *, size_t);
 #endif
 
 static	int	  arg_hasattr(int, const struct mdoc_node *);
@@ -327,15 +324,21 @@ static	void	  print_head(struct termp *,
 static	void	  print_body(DECL_ARGS);
 static	void	  print_foot(struct termp *, 
 			const struct mdoc_meta *);
-static	void	  sanity(const struct mdoc_node *);
 
 
 int
 mdoc_run(struct termp *p, const struct mdoc *m)
 {
+	/*
+	 * Main output function.  When this is called, assume that the
+	 * tree is properly formed.
+	 */
 
 	print_head(p, mdoc_meta(m));
-	print_body(p, NULL, mdoc_meta(m), mdoc_node(m));
+	assert(mdoc_node(m));
+	assert(MDOC_ROOT == mdoc_node(m)->type);
+	if (mdoc_node(m)->child)
+		print_body(p, NULL, mdoc_meta(m), mdoc_node(m)->child);
 	print_foot(p, mdoc_meta(m));
 	return(1);
 }
@@ -358,10 +361,6 @@ print_node(DECL_ARGS)
 	int		 dochild;
 	struct termpair	 npair;
 
-	/* Some quick sanity-checking. */
-
-	sanity(node);
-
 	/* Pre-processing. */
 
 	dochild = 1;
@@ -403,6 +402,14 @@ print_foot(struct termp *p, const struct mdoc_meta *meta)
 	struct tm	*tm;
 	char		*buf, *os;
 
+	/* 
+	 * Output the footer in new-groff style, that is, three columns
+	 * with the middle being the manual date and flanking columns
+	 * being the operating system:
+	 *
+	 * SYSTEM                  DATE                    SYSTEM
+	 */
+
 	if (NULL == (buf = malloc(p->rmargin)))
 		err(1, "malloc");
 	if (NULL == (os = malloc(p->rmargin)))
@@ -410,39 +417,39 @@ print_foot(struct termp *p, const struct mdoc_meta *meta)
 
 	tm = localtime(&meta->date);
 
-#ifdef __OpenBSD__
-	if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))
-#else
 	if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))
-#endif
 		err(1, "strftime");
 
 	(void)strlcpy(os, meta->os, p->rmargin);
 
-	/*
-	 * This is /slightly/ different from regular groff output
-	 * because we don't have page numbers.  Print the following:
-	 *
-	 * OS                                            MDOCDATE
-	 */
-
 	term_vspace(p);
 
-	p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
-	p->rmargin = p->maxrmargin - strlen(buf);
 	p->offset = 0;
+	p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
+	p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
 
 	term_word(p, os);
 	term_flushln(p);
 
+	p->offset = p->rmargin;
+	p->rmargin = p->maxrmargin - strlen(os);
 	p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
+
+	term_word(p, buf);
+	term_flushln(p);
+
 	p->offset = p->rmargin;
 	p->rmargin = p->maxrmargin;
 	p->flags &= ~TERMP_NOBREAK;
+	p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
 
-	term_word(p, buf);
+	term_word(p, os);
 	term_flushln(p);
 
+	p->offset = 0;
+	p->rmargin = p->maxrmargin;
+	p->flags = 0;
+
 	free(buf);
 	free(os);
 }
@@ -487,15 +494,15 @@ print_head(struct termp *p, const struct mdoc_meta *meta)
 			meta->title, meta->msec);
 
 	p->offset = 0;
-	p->rmargin = (p->maxrmargin - strlen(buf)) / 2;
+	p->rmargin = (p->maxrmargin - strlen(buf) + 1) / 2;
 	p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
 
 	term_word(p, title);
 	term_flushln(p);
 
-	p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
 	p->offset = p->rmargin;
 	p->rmargin = p->maxrmargin - strlen(title);
+	p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;
 
 	term_word(p, buf);
 	term_flushln(p);
@@ -508,8 +515,8 @@ print_head(struct termp *p, const struct mdoc_meta *meta)
 	term_word(p, title);
 	term_flushln(p);
 
-	p->rmargin = p->maxrmargin;
 	p->offset = 0;
+	p->rmargin = p->maxrmargin;
 	p->flags &= ~TERMP_NOSPACE;
 
 	free(title);
@@ -517,119 +524,6 @@ print_head(struct termp *p, const struct mdoc_meta *meta)
 }
 
 
-static void
-sanity(const struct mdoc_node *n)
-{
-	char		*p;
-
-	p = "regular form violated";
-
-	switch (n->type) {
-	case (MDOC_TEXT):
-		if (n->child) 
-			errx(1, p);
-		if (NULL == n->parent) 
-			errx(1, p);
-		if (NULL == n->string)
-			errx(1, p);
-		switch (n->parent->type) {
-		case (MDOC_TEXT):
-			/* FALLTHROUGH */
-		case (MDOC_ROOT):
-			errx(1, p);
-			/* NOTREACHED */
-		default:
-			break;
-		}
-		break;
-	case (MDOC_ELEM):
-		if (NULL == n->parent)
-			errx(1, p);
-		switch (n->parent->type) {
-		case (MDOC_TAIL):
-			/* FALLTHROUGH */
-		case (MDOC_BODY):
-			/* FALLTHROUGH */
-		case (MDOC_HEAD):
-			break;
-		default:
-			errx(1, p);
-			/* NOTREACHED */
-		}
-		if (n->child) switch (n->child->type) {
-		case (MDOC_TEXT):
-			break;
-		default:
-			errx(1, p);
-			/* NOTREACHED */
-		}
-		break;
-	case (MDOC_HEAD):
-		/* FALLTHROUGH */
-	case (MDOC_BODY):
-		/* FALLTHROUGH */
-	case (MDOC_TAIL):
-		if (NULL == n->parent)
-			errx(1, p);
-		if (MDOC_BLOCK != n->parent->type)
-			errx(1, p);
-		if (n->child) switch (n->child->type) {
-		case (MDOC_BLOCK):
-			/* FALLTHROUGH */
-		case (MDOC_ELEM):
-			/* FALLTHROUGH */
-		case (MDOC_TEXT):
-			break;
-		default:
-			errx(1, p);
-			/* NOTREACHED */
-		}
-		break;
-	case (MDOC_BLOCK):
-		if (NULL == n->parent)
-			errx(1, p);
-		if (NULL == n->child)
-			errx(1, p);
-		switch (n->parent->type) {
-		case (MDOC_ROOT):
-			/* FALLTHROUGH */
-		case (MDOC_HEAD):
-			/* FALLTHROUGH */
-		case (MDOC_BODY):
-			/* FALLTHROUGH */
-		case (MDOC_TAIL):
-			break;
-		default:
-			errx(1, p);
-			/* NOTREACHED */
-		}
-		switch (n->child->type) {
-		case (MDOC_ROOT):
-			/* FALLTHROUGH */
-		case (MDOC_ELEM):
-			errx(1, p);
-			/* NOTREACHED */
-		default:
-			break;
-		}
-		break;
-	case (MDOC_ROOT):
-		if (n->parent)
-			errx(1, p);
-		if (NULL == n->child)
-			errx(1, p);
-		switch (n->child->type) {
-		case (MDOC_BLOCK):
-			break;
-		default:
-			errx(1, p);
-			/* NOTREACHED */
-		}
-		break;
-	}
-}
-
-
 static size_t
 arg_width(const struct mdoc_argv *arg, int pos)
 {
@@ -639,9 +533,9 @@ arg_width(const struct mdoc_argv *arg, int pos)
 	assert(pos < (int)arg->sz && pos >= 0);
 	assert(arg->value[pos]);
 	if (0 == strcmp(arg->value[pos], "indent"))
-		return(INDENT);
+		return(INDENT + 3);
 	if (0 == strcmp(arg->value[pos], "indent-two"))
-		return(INDENT * 2);
+		return(INDENT * 2 + 2);
 
 	if (0 == (len = (int)strlen(arg->value[pos])))
 		return(0);
@@ -651,13 +545,14 @@ arg_width(const struct mdoc_argv *arg, int pos)
 			break;
 
 	if (i == len - 1) {
-		if ('n' == arg->value[pos][len - 1]) {
+		if ('n' == arg->value[pos][len - 1] ||
+				'm' == arg->value[pos][len - 1]) {
 			v = (size_t)atoi(arg->value[pos]);
-			return(v);
+			return(v + 2);
 		}
 
 	}
-	return(strlen(arg->value[pos]) + 1);
+	return(strlen(arg->value[pos]) + 2);
 }
 
 
@@ -696,6 +591,8 @@ arg_listtype(const struct mdoc_node *n)
 			break;
 		}
 
+	/* FIXME: mandated by parser. */
+
 	errx(1, "list type not supported");
 	/* NOTREACHED */
 }
@@ -706,10 +603,15 @@ arg_offset(const struct mdoc_argv *arg)
 {
 
 	assert(*arg->value);
+	if (0 == strcmp(*arg->value, "left"))
+		return(0);
 	if (0 == strcmp(*arg->value, "indent"))
-		return(INDENT);
+		return(INDENT + 1);
 	if (0 == strcmp(*arg->value, "indent-two"))
-		return(INDENT * 2);
+		return((INDENT + 1) * 2);
+
+	/* FIXME: needs to support field-widths (10n, etc.). */
+
 	return(strlen(*arg->value));
 }
 
@@ -813,7 +715,7 @@ termp_it_pre(DECL_ARGS)
 {
 	const struct mdoc_node *bl, *n;
 	char		        buf[7];
-	int		        i, type, keys[3], vals[3];
+	int		        i, type, keys[3], vals[3], sv;
 	size_t		        width, offset;
 
 	if (MDOC_BLOCK == node->type)
@@ -859,7 +761,7 @@ termp_it_pre(DECL_ARGS)
 		if (vals[0] >= 0) 
 			width = arg_width(&bl->args->argv[vals[0]], 0);
 		if (vals[1] >= 0) 
-			offset = arg_offset(&bl->args->argv[vals[1]]);
+			offset += arg_offset(&bl->args->argv[vals[1]]);
 		break;
 	}
 
@@ -874,12 +776,14 @@ termp_it_pre(DECL_ARGS)
 		/* FALLTHROUGH */
 	case (MDOC_Dash):
 		/* FALLTHROUGH */
-	case (MDOC_Enum):
-		/* FALLTHROUGH */
 	case (MDOC_Hyphen):
 		if (width < 4)
 			width = 4;
 		break;
+	case (MDOC_Enum):
+		if (width < 5)
+			width = 5;
+		break;
 	case (MDOC_Tag):
 		if (0 == width)
 			width = 10;
@@ -889,11 +793,13 @@ termp_it_pre(DECL_ARGS)
 	}
 
 	/* 
-	 * Whitespace control.  Inset bodies need an initial space.
+	 * Whitespace control.  Inset bodies need an initial space,
+	 * while diagonal bodies need two.
 	 */
 
 	switch (type) {
 	case (MDOC_Diag):
+		term_word(p, "\\ ");
 		/* FALLTHROUGH */
 	case (MDOC_Inset):
 		if (MDOC_BODY == node->type) 
@@ -997,17 +903,20 @@ termp_it_pre(DECL_ARGS)
 
 	/* 
 	 * The dash, hyphen, bullet and enum lists all have a special
-	 * HEAD character.  Print it now.
+	 * HEAD character (temporarily bold, in some cases).  
 	 */
 
+	sv = p->flags;
 	if (MDOC_HEAD == node->type)
 		switch (type) {
 		case (MDOC_Bullet):
+			p->flags |= TERMP_BOLD;
 			term_word(p, "\\[bu]");
 			break;
 		case (MDOC_Dash):
 			/* FALLTHROUGH */
 		case (MDOC_Hyphen):
+			p->flags |= TERMP_BOLD;
 			term_word(p, "\\-");
 			break;
 		case (MDOC_Enum):
@@ -1020,6 +929,8 @@ termp_it_pre(DECL_ARGS)
 			break;
 		}
 
+	p->flags = sv; /* Restore saved flags. */
+
 	/* 
 	 * If we're not going to process our children, indicate so here.
 	 */
@@ -1171,6 +1082,8 @@ termp_rv_pre(DECL_ARGS)
 {
 	int		 i;
 
+	/* FIXME: mandated by parser. */
+
 	if (-1 == (i = arg_getattr(MDOC_Std, node)))
 		errx(1, "expected -std argument");
 	if (1 != node->args->argv[i].sz)
@@ -1204,6 +1117,8 @@ termp_ex_pre(DECL_ARGS)
 {
 	int		 i;
 
+	/* FIXME: mandated by parser? */
+
 	if (-1 == (i = arg_getattr(MDOC_Std, node)))
 		errx(1, "expected -std argument");
 	if (1 != node->args->argv[i].sz)
@@ -1257,8 +1172,9 @@ termp_xr_pre(DECL_ARGS)
 {
 	const struct mdoc_node *n;
 
-	if (NULL == (n = node->child))
-		errx(1, "expected text line argument");
+	assert(node->child && MDOC_TEXT == node->child->type);
+	n = node->child;
+
 	term_word(p, n->string);
 	if (NULL == (n = n->next)) 
 		return(0);
@@ -1392,9 +1308,9 @@ termp_lb_pre(DECL_ARGS)
 {
 	const char	*lb;
 
-	if (NULL == node->child)
-		errx(1, "expected text line argument");
-	if ((lb = mdoc_a2lib(node->child->string))) {
+	assert(node->child && MDOC_TEXT == node->child->type);
+	lb = mdoc_a2lib(node->child->string);
+	if (lb) {
 		term_word(p, lb);
 		return(0);
 	}
@@ -1427,10 +1343,11 @@ static int
 termp_d1_pre(DECL_ARGS)
 {
 
-	if (MDOC_BODY != node->type)
+	if (MDOC_BLOCK != node->type)
 		return(1);
 	term_newln(p);
-	p->offset += (pair->offset = INDENT);
+	pair->offset = INDENT + 1;
+	p->offset += pair->offset;
 	return(1);
 }
 
@@ -1440,7 +1357,7 @@ static void
 termp_d1_post(DECL_ARGS)
 {
 
-	if (MDOC_BODY != node->type) 
+	if (MDOC_BLOCK != node->type) 
 		return;
 	term_newln(p);
 	p->offset -= pair->offset;
@@ -1501,8 +1418,7 @@ termp_fn_pre(DECL_ARGS)
 {
 	const struct mdoc_node *n;
 
-	if (NULL == node->child)
-		errx(1, "expected text line arguments");
+	assert(node->child && MDOC_TEXT == node->child->type);
 
 	/* FIXME: can be "type funcname" "type varname"... */
 
@@ -1609,6 +1525,8 @@ termp_bd_pre(DECL_ARGS)
 	else if (MDOC_BODY != node->type)
 		return(1);
 
+	/* FIXME: display type should be mandated by parser. */
+
 	if (NULL == node->parent->args)
 		errx(1, "missing display type");
 
@@ -1842,7 +1760,7 @@ termp_ss_pre(DECL_ARGS)
 		break;
 	case (MDOC_HEAD):
 		TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SSECTION]);
-		p->offset = INDENT / 2;
+		p->offset = HALFINDENT;
 		break;
 	default:
 		break;
@@ -2057,8 +1975,7 @@ termp_fo_pre(DECL_ARGS)
 
 	p->flags |= ttypes[TTYPE_FUNC_NAME];
 	for (n = node->child; n; n = n->next) {
-		if (MDOC_TEXT != n->type)
-			errx(1, "expected text line argument");
+		assert(MDOC_TEXT == n->type);
 		term_word(p, n->string);
 	}
 	p->flags &= ~ttypes[TTYPE_FUNC_NAME];
@@ -2102,9 +2019,7 @@ termp_bf_pre(DECL_ARGS)
 		return(1);
 	} 
 
-	if (MDOC_TEXT != n->type)
-		errx(1, "expected text line arguments");
-
+	assert(MDOC_TEXT == n->type);
 	if (0 == strcmp("Em", n->string))
 		TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
 	else if (0 == strcmp("Sy", n->string))
@@ -2140,9 +2055,7 @@ static int
 termp_sm_pre(DECL_ARGS)
 {
 
-	if (NULL == node->child || MDOC_TEXT != node->child->type)
-		errx(1, "expected boolean line argument");
-
+	assert(node->child && MDOC_TEXT == node->child->type);
 	if (0 == strcmp("on", node->child->string)) {
 		p->flags &= ~TERMP_NONOSPACE;
 		p->flags &= ~TERMP_NOSPACE;
@@ -2213,21 +2126,25 @@ termp_lk_pre(DECL_ARGS)
 {
 	const struct mdoc_node *n;
 
-	if (NULL == (n = node->child))
-		errx(1, "expected line argument");
+	assert(node->child);
+	n = node->child;
+
+	if (NULL == n->next) {
+		TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_LINK_ANCHOR]);
+		return(1);
+	}
 
 	p->flags |= ttypes[TTYPE_LINK_ANCHOR];
 	term_word(p, n->string);
-	p->flags &= ~ttypes[TTYPE_LINK_ANCHOR];
 	p->flags |= TERMP_NOSPACE;
 	term_word(p, ":");
+	p->flags &= ~ttypes[TTYPE_LINK_ANCHOR];
 
 	p->flags |= ttypes[TTYPE_LINK_TEXT];
-	for ( ; n; n = n->next) {
+	for (n = n->next; n; n = n->next) 
 		term_word(p, n->string);
-	}
-	p->flags &= ~ttypes[TTYPE_LINK_TEXT];
 
+	p->flags &= ~ttypes[TTYPE_LINK_TEXT];
 	return(0);
 }