--- old/usr/src/cmd/mandoc/read.c	Wed Jul 30 20:55:11 2014
+++ new/usr/src/cmd/mandoc/read.c	Wed Jul 30 20:55:11 2014
@@ -1,7 +1,7 @@
-/*	$Id: read.c,v 1.28 2012/02/16 20:51:31 joerg Exp $ */
+/*	$Id: read.c,v 1.39 2013/09/16 00:25:07 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -40,10 +40,6 @@
 #include "man.h"
 #include "main.h"
 
-#ifndef MAP_FILE
-#define	MAP_FILE	0
-#endif
-
 #define	REPARSE_LIMIT	1000
 
 struct	buf {
@@ -66,14 +62,16 @@
 	void		 *arg; /* argument to mmsg */
 	const char	 *file; 
 	struct buf	 *secondary;
+	char		 *defos; /* default operating system */
 };
 
 static	void	  resize_buf(struct buf *, size_t);
 static	void	  mparse_buf_r(struct mparse *, struct buf, int);
-static	void	  mparse_readfd_r(struct mparse *, int, const char *, int);
 static	void	  pset(const char *, int, struct mparse *);
 static	int	  read_whole_file(const char *, int, struct buf *, int *);
 static	void	  mparse_end(struct mparse *);
+static	void	  mparse_parse_buffer(struct mparse *, struct buf,
+			const char *);
 
 static	const enum mandocerr	mandoclimits[MANDOCLEVEL_MAX] = {
 	MANDOCERR_OK,
@@ -94,6 +92,7 @@
 	"no title in document",
 	"document title should be all caps",
 	"unknown manual section",
+	"unknown manual volume or arch",
 	"date missing, using today's date",
 	"cannot parse date, using it verbatim",
 	"prologue macros out of order",
@@ -105,14 +104,14 @@
 	".so is fragile, better use ln(1)",
 	"NAME section must come first",
 	"bad NAME section contents",
-	"manual name not yet set",
 	"sections out of conventional order",
 	"duplicate section name",
-	"section not in conventional manual section",
+	"section header suited to sections 2, 3, and 9 only",
 
 	/* related to macros and nesting */
 	"skipping obsolete macro",
 	"skipping paragraph macro",
+	"moving paragraph macro out of list",
 	"skipping no-space macro",
 	"blocks badly nested",
 	"child violates parent syntax",
@@ -173,10 +172,12 @@
 	"input stack limit exceeded, infinite loop?",
 	"skipping bad character",
 	"escaped character not allowed in a name",
+	"manual name not yet set",
 	"skipping text before the first section header",
 	"skipping unknown macro",
 	"NOT IMPLEMENTED, please use groff: skipping request",
 	"argument count wrong",
+	"skipping column outside column list",
 	"skipping end of block that is not open",
 	"missing end of block",
 	"scope open on exit",
@@ -184,6 +185,7 @@
 	"macro requires line argument(s)",
 	"macro requires body argument(s)",
 	"macro requires argument(s)",
+	"request requires a numeric argument",
 	"missing list type",
 	"line argument(s) will be lost",
 	"body argument(s) will be lost",
@@ -247,7 +249,8 @@
 	switch (curp->inttype) {
 	case (MPARSE_MDOC):
 		if (NULL == curp->pmdoc) 
-			curp->pmdoc = mdoc_alloc(curp->roff, curp);
+			curp->pmdoc = mdoc_alloc(curp->roff, curp,
+					curp->defos);
 		assert(curp->pmdoc);
 		curp->mdoc = curp->pmdoc;
 		return;
@@ -263,7 +266,8 @@
 
 	if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3))  {
 		if (NULL == curp->pmdoc) 
-			curp->pmdoc = mdoc_alloc(curp->roff, curp);
+			curp->pmdoc = mdoc_alloc(curp->roff, curp,
+					curp->defos);
 		assert(curp->pmdoc);
 		curp->mdoc = curp->pmdoc;
 		return;
@@ -322,6 +326,15 @@
 				break;
 			}
 
+			/*
+			 * Make sure we have space for at least
+			 * one backslash and one other character
+			 * and the trailing NUL byte.
+			 */
+
+			if (pos + 2 >= (int)ln.sz)
+				resize_buf(&ln, 256);
+
 			/* 
 			 * Warn about bogus characters.  If you're using
 			 * non-ASCII encoding, you're screwing your
@@ -338,8 +351,6 @@
 				mandoc_msg(MANDOCERR_BADCHAR, curp,
 						curp->line, pos, NULL);
 				i++;
-				if (pos >= (int)ln.sz)
-					resize_buf(&ln, 256);
 				ln.buf[pos++] = '?';
 				continue;
 			}
@@ -347,8 +358,6 @@
 			/* Trailing backslash = a plain char. */
 
 			if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
-				if (pos >= (int)ln.sz)
-					resize_buf(&ln, 256);
 				ln.buf[pos++] = blk.buf[i++];
 				continue;
 			}
@@ -390,11 +399,21 @@
 				break;
 			}
 
-			/* Some other escape sequence, copy & cont. */
+			/* Catch escaped bogus characters. */
 
-			if (pos + 1 >= (int)ln.sz)
-				resize_buf(&ln, 256);
+			c = (unsigned char) blk.buf[i+1];
 
+			if ( ! (isascii(c) && 
+					(isgraph(c) || isblank(c)))) {
+				mandoc_msg(MANDOCERR_BADCHAR, curp,
+						curp->line, pos, NULL);
+				i += 2;
+				ln.buf[pos++] = '?';
+				continue;
+			}
+
+			/* Some other escape sequence, copy & cont. */
+
 			ln.buf[pos++] = blk.buf[i++];
 			ln.buf[pos++] = blk.buf[i++];
 		}
@@ -469,7 +488,7 @@
 			 */
 			if (curp->secondary) 
 				curp->secondary->sz -= pos + 1;
-			mparse_readfd_r(curp, -1, ln.buf + of, 1);
+			mparse_readfd(curp, -1, ln.buf + of);
 			if (MANDOCLEVEL_FATAL <= curp->file_status)
 				break;
 			pos = 0;
@@ -575,8 +594,7 @@
 		}
 		*with_mmap = 1;
 		fb->sz = (size_t)st.st_size;
-		fb->buf = mmap(NULL, fb->sz, PROT_READ, 
-				MAP_FILE|MAP_SHARED, fd, 0);
+		fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
 		if (fb->buf != MAP_FAILED)
 			return(1);
 	}
@@ -643,19 +661,25 @@
 }
 
 static void
-mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file,
-		int re)
+mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
 {
 	const char	*svfile;
+	static int	 recursion_depth;
 
+	if (64 < recursion_depth) {
+		mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL);
+		return;
+	}
+
 	/* Line number is per-file. */
 	svfile = curp->file;
 	curp->file = file;
 	curp->line = 1;
+	recursion_depth++;
 
 	mparse_buf_r(curp, blk, 1);
 
-	if (0 == re && MANDOCLEVEL_FATAL > curp->file_status)
+	if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status)
 		mparse_end(curp);
 
 	curp->file = svfile;
@@ -670,12 +694,12 @@
 	blk.buf = UNCONST(buf);
 	blk.sz = len;
 
-	mparse_parse_buffer(curp, blk, file, 0);
+	mparse_parse_buffer(curp, blk, file);
 	return(curp->file_status);
 }
 
-static void
-mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
+enum mandoclevel
+mparse_readfd(struct mparse *curp, int fd, const char *file)
 {
 	struct buf	 blk;
 	int		 with_mmap;
@@ -684,7 +708,7 @@
 		if (-1 == (fd = open(file, O_RDONLY, 0))) {
 			perror(file);
 			curp->file_status = MANDOCLEVEL_SYSERR;
-			return;
+			goto out;
 		}
 	/*
 	 * Run for each opened file; may be called more than once for
@@ -695,10 +719,10 @@
 
 	if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
 		curp->file_status = MANDOCLEVEL_SYSERR;
-		return;
+		goto out;
 	}
 
-	mparse_parse_buffer(curp, blk, file, re);
+	mparse_parse_buffer(curp, blk, file);
 
 #ifdef	HAVE_MMAP
 	if (with_mmap)
@@ -709,18 +733,13 @@
 
 	if (STDIN_FILENO != fd && -1 == close(fd))
 		perror(file);
-}
-
-enum mandoclevel
-mparse_readfd(struct mparse *curp, int fd, const char *file)
-{
-
-	mparse_readfd_r(curp, fd, file, 0);
+out:
 	return(curp->file_status);
 }
 
 struct mparse *
-mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg)
+mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
+		mandocmsg mmsg, void *arg, char *defos)
 {
 	struct mparse	*curp;
 
@@ -732,8 +751,9 @@
 	curp->mmsg = mmsg;
 	curp->arg = arg;
 	curp->inttype = inttype;
+	curp->defos = defos;
 
-	curp->roff = roff_alloc(curp);
+	curp->roff = roff_alloc(inttype, curp);
 	return(curp);
 }
 
