X-Git-Url: https://git.cameronkatri.com/mandoc.git/blobdiff_plain/eb23c3ce0ca3852f947adf776def825033852227..04962b24a061ec089915e89b57adf1720bb86670:/mandoc.c?ds=sidebyside

diff --git a/mandoc.c b/mandoc.c
index 604bb67e..420e8aa5 100644
--- a/mandoc.c
+++ b/mandoc.c
@@ -1,7 +1,7 @@
-/*	$Id: mandoc.c,v 1.62 2011/12/03 16:08:51 schwarze Exp $ */
+/*	$Id: mandoc.c,v 1.66 2012/06/12 20:21:04 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012 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
@@ -37,83 +37,38 @@
 
 static	int	 a2time(time_t *, const char *, const char *);
 static	char	*time2a(time_t);
-static	int	 numescape(const char *);
 
-/*
- * Pass over recursive numerical expressions.  This context of this
- * function is important: it's only called within character-terminating
- * escapes (e.g., \s[xxxyyy]), so all we need to do is handle initial
- * recursion: we don't care about what's in these blocks. 
- * This returns the number of characters skipped or -1 if an error
- * occurs (the caller should bail).
- */
-static int
-numescape(const char *start)
-{
-	int		 i;
-	size_t		 sz;
-	const char	*cp;
-
-	i = 0;
-
-	/* The expression consists of a subexpression. */
-
-	if ('\\' == start[i]) {
-		cp = &start[++i];
-		/*
-		 * Read past the end of the subexpression.
-		 * Bail immediately on errors.
-		 */
-		if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL))
-			return(-1);
-		return(i + cp - &start[i]);
-	} 
 
-	if ('(' != start[i++])
-		return(0);
+enum mandoc_esc
+mandoc_escape(const char **end, const char **start, int *sz)
+{
+	const char	*local_start;
+	int		 local_sz;
+	char		 term;
+	enum mandoc_esc	 gly; 
 
 	/*
-	 * A parenthesised subexpression.  Read until the closing
-	 * parenthesis, making sure to handle any nested subexpressions
-	 * that might ruin our parse.
+	 * When the caller doesn't provide return storage,
+	 * use local storage.
 	 */
 
-	while (')' != start[i]) {
-		sz = strcspn(&start[i], ")\\");
-		i += (int)sz;
+	if (NULL == start)
+		start = &local_start;
+	if (NULL == sz)
+		sz = &local_sz;
 
-		if ('\0' == start[i])
-			return(-1);
-		else if ('\\' != start[i])
-			continue;
-
-		cp = &start[++i];
-		if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL))
-			return(-1);
-		i += cp - &start[i];
-	}
-
-	/* Read past the terminating ')'. */
-	return(++i);
-}
-
-enum mandoc_esc
-mandoc_escape(const char **end, const char **start, int *sz)
-{
-	char		 c, term, numeric;
-	int		 i, lim, ssz, rlim;
-	const char	*cp, *rstart;
-	enum mandoc_esc	 gly; 
+	/*
+	 * Beyond the backslash, at least one input character
+	 * is part of the escape sequence.  With one exception
+	 * (see below), that character won't be returned.
+	 */
 
-	cp = *end;
-	rstart = cp;
-	if (start)
-		*start = rstart;
-	i = lim = 0;
 	gly = ESCAPE_ERROR;
-	term = numeric = '\0';
+	*start = ++*end;
+	*sz = 0;
+	term = '\0';
 
-	switch ((c = cp[i++])) {
+	switch ((*start)[-1]) {
 	/*
 	 * First the glyphs.  There are several different forms of
 	 * these, but each eventually returns a substring of the glyph
@@ -121,7 +76,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
 	 */
 	case ('('):
 		gly = ESCAPE_SPECIAL;
-		lim = 2;
+		*sz = 2;
 		break;
 	case ('['):
 		gly = ESCAPE_SPECIAL;
@@ -131,17 +86,27 @@ mandoc_escape(const char **end, const char **start, int *sz)
 		 * Unicode codepoint.  Here, however, only check whether
 		 * it's not a zero-width escape.
 		 */
-		if ('u' == cp[i] && ']' != cp[i + 1])
+		if ('u' == (*start)[0] && ']' != (*start)[1])
 			gly = ESCAPE_UNICODE;
 		term = ']';
 		break;
 	case ('C'):
-		if ('\'' != cp[i])
+		if ('\'' != **start)
 			return(ESCAPE_ERROR);
 		gly = ESCAPE_SPECIAL;
+		*start = ++*end;
 		term = '\'';
 		break;
 
+	/*
+	 * The \z escape is supposed to output the following
+	 * character without advancing the cursor position.  
+	 * Since we are mostly dealing with terminal mode,
+	 * let us just skip the next character.
+	 */
+	case ('z'):
+		return(ESCAPE_SKIPCHAR);
+
 	/*
 	 * Handle all triggers matching \X(xy, \Xx, and \X[xxxx], where
 	 * 'X' is the trigger.  These have opaque sub-strings.
@@ -166,21 +131,17 @@ mandoc_escape(const char **end, const char **start, int *sz)
 	case ('f'):
 		if (ESCAPE_ERROR == gly)
 			gly = ESCAPE_FONT;
-
-		rstart= &cp[i];
-		if (start) 
-			*start = rstart;
-
-		switch (cp[i++]) {
+		switch (**start) {
 		case ('('):
-			lim = 2;
+			*start = ++*end;
+			*sz = 2;
 			break;
 		case ('['):
+			*start = ++*end;
 			term = ']';
 			break;
 		default:
-			lim = 1;
-			i--;
+			*sz = 1;
 			break;
 		}
 		break;
@@ -202,9 +163,10 @@ mandoc_escape(const char **end, const char **start, int *sz)
 	case ('X'):
 		/* FALLTHROUGH */
 	case ('Z'):
-		if ('\'' != cp[i++])
+		if ('\'' != **start)
 			return(ESCAPE_ERROR);
 		gly = ESCAPE_IGNORE;
+		*start = ++*end;
 		term = '\'';
 		break;
 
@@ -230,11 +192,12 @@ mandoc_escape(const char **end, const char **start, int *sz)
 	case ('w'):
 		/* FALLTHROUGH */
 	case ('x'):
+		if ('\'' != **start)
+			return(ESCAPE_ERROR);
 		if (ESCAPE_ERROR == gly)
 			gly = ESCAPE_IGNORE;
-		if ('\'' != cp[i++])
-			return(ESCAPE_ERROR);
-		term = numeric = '\'';
+		*start = ++*end;
+		term = '\'';
 		break;
 
 	/*
@@ -242,17 +205,17 @@ mandoc_escape(const char **end, const char **start, int *sz)
 	 * XXX Do any other escapes need similar handling?
 	 */
 	case ('N'):
-		if ('\0' == cp[i])
+		if ('\0' == **start)
 			return(ESCAPE_ERROR);
-		*end = &cp[++i];
-		if (isdigit((unsigned char)cp[i-1]))
+		(*end)++;
+		if (isdigit((unsigned char)**start)) {
+			*sz = 1;
 			return(ESCAPE_IGNORE);
+		}
+		(*start)++;
 		while (isdigit((unsigned char)**end))
 			(*end)++;
-		if (start)
-			*start = &cp[i];
-		if (sz)
-			*sz = *end - &cp[i];
+		*sz = *end - *start;
 		if ('\0' != **end)
 			(*end)++;
 		return(ESCAPE_NUMBERED);
@@ -263,108 +226,72 @@ mandoc_escape(const char **end, const char **start, int *sz)
 	case ('s'):
 		gly = ESCAPE_IGNORE;
 
-		rstart = &cp[i];
-		if (start) 
-			*start = rstart;
-
 		/* See +/- counts as a sign. */
-		c = cp[i];
-		if ('+' == c || '-' == c || ASCII_HYPH == c)
-			++i;
+		if ('+' == **end || '-' == **end || ASCII_HYPH == **end)
+			(*end)++;
 
-		switch (cp[i++]) {
+		switch (**end) {
 		case ('('):
-			lim = 2;
+			*start = ++*end;
+			*sz = 2;
 			break;
 		case ('['):
-			term = numeric = ']';
+			*start = ++*end;
+			term = ']';
 			break;
 		case ('\''):
-			term = numeric = '\'';
+			*start = ++*end;
+			term = '\'';
 			break;
 		default:
-			lim = 1;
-			i--;
+			*sz = 1;
 			break;
 		}
 
-		/* See +/- counts as a sign. */
-		c = cp[i];
-		if ('+' == c || '-' == c || ASCII_HYPH == c)
-			++i;
-
 		break;
 
 	/*
 	 * Anything else is assumed to be a glyph.
+	 * In this case, pass back the character after the backslash.
 	 */
 	default:
 		gly = ESCAPE_SPECIAL;
-		lim = 1;
-		i--;
+		*start = --*end;
+		*sz = 1;
 		break;
 	}
 
 	assert(ESCAPE_ERROR != gly);
 
-	rstart = &cp[i];
-	if (start)
-		*start = rstart;
-
-	/*
-	 * If a terminating block has been specified, we need to
-	 * handle the case of recursion, which could have their
-	 * own terminating blocks that mess up our parse.  This, by the
-	 * way, means that the "start" and "size" values will be
-	 * effectively meaningless.
-	 */
-
-	ssz = 0;
-	if (numeric && -1 == (ssz = numescape(&cp[i])))
-		return(ESCAPE_ERROR);
-
-	i += ssz;
-	rlim = -1;
-
 	/*
-	 * We have a character terminator.  Try to read up to that
-	 * character.  If we can't (i.e., we hit the nil), then return
-	 * an error; if we can, calculate our length, read past the
-	 * terminating character, and exit.
+	 * Read up to the terminating character,
+	 * paying attention to nested escapes.
 	 */
 
 	if ('\0' != term) {
-		*end = strchr(&cp[i], term);
-		if ('\0' == *end)
+		while (**end != term) {
+			switch (**end) {
+			case ('\0'):
+				return(ESCAPE_ERROR);
+			case ('\\'):
+				(*end)++;
+				if (ESCAPE_ERROR ==
+				    mandoc_escape(end, NULL, NULL))
+					return(ESCAPE_ERROR);
+				break;
+			default:
+				(*end)++;
+				break;
+			}
+		}
+		*sz = (*end)++ - *start;
+	} else {
+		assert(*sz > 0);
+		if ((size_t)*sz > strlen(*start))
 			return(ESCAPE_ERROR);
-
-		rlim = *end - &cp[i];
-		if (sz)
-			*sz = rlim;
-		(*end)++;
-		goto out;
+		*end += *sz;
 	}
 
-	assert(lim > 0);
-
-	/*
-	 * We have a numeric limit.  If the string is shorter than that,
-	 * stop and return an error.  Else adjust our endpoint, length,
-	 * and return the current glyph.
-	 */
-
-	if ((size_t)lim > strlen(&cp[i]))
-		return(ESCAPE_ERROR);
-
-	rlim = lim;
-	if (sz)
-		*sz = rlim;
-
-	*end = &cp[i] + lim;
-
-out:
-	assert(rlim >= 0 && rstart);
-
 	/* Run post-processors. */
 
 	switch (gly) {
@@ -373,12 +300,13 @@ out:
 		 * Pretend that the constant-width font modes are the
 		 * same as the regular font modes.
 		 */
-		if (2 == rlim && 'C' == *rstart)
-			rstart++;
-		else if (1 != rlim)
+		if (2 == *sz && 'C' == **start) {
+			(*start)++;
+			(*sz)--;
+		} else if (1 != *sz)
 			break;
 
-		switch (*rstart) {
+		switch (**start) {
 		case ('3'):
 			/* FALLTHROUGH */
 		case ('B'):
@@ -400,9 +328,7 @@ out:
 		}
 		break;
 	case (ESCAPE_SPECIAL):
-		if (1 != rlim)
-			break;
-		if ('c' == *rstart)
+		if (1 == *sz && 'c' == **start)
 			gly = ESCAPE_NOSPACE;
 		break;
 	default:
@@ -677,32 +603,6 @@ mandoc_eos(const char *p, size_t sz, int enclosed)
 	return(found && !enclosed);
 }
 
-/*
- * Find out whether a line is a macro line or not.  If it is, adjust the
- * current position and return one; if it isn't, return zero and don't
- * change the current position.
- */
-int
-mandoc_getcontrol(const char *cp, int *ppos)
-{
-	int		pos;
-
-	pos = *ppos;
-
-	if ('\\' == cp[pos] && '.' == cp[pos + 1])
-		pos += 2;
-	else if ('.' == cp[pos] || '\'' == cp[pos])
-		pos++;
-	else
-		return(0);
-
-	while (' ' == cp[pos] || '\t' == cp[pos])
-		pos++;
-
-	*ppos = pos;
-	return(1);
-}
-
 /*
  * Convert a string to a long that may not be <0.
  * If the string is invalid, or is less than 0, return -1.