summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2014-10-16 01:11:20 +0000
committerIngo Schwarze <schwarze@openbsd.org>2014-10-16 01:11:20 +0000
commit1355393bef46aede0de7305138dd0b3b3dab287c (patch)
treeaa6c81705b9c2da774d6f10414fe170e7b76162d
parentb53f13bc3058beab88ad98e78c0ce6c0ff5be2a0 (diff)
downloadmandoc-1355393bef46aede0de7305138dd0b3b3dab287c.tar.gz
Implement in-line equations, much needed by Xenocara manuals.
Put the steering into the roff parser rather than into the mdoc parser such that it works for all macro languages and on both text and macro lines. Line breaks and blank characters generated before and after in-line equations are not perfect yet, but let's do one thing at a time.
-rw-r--r--TODO6
-rw-r--r--eqn.c26
-rw-r--r--libmandoc.h6
-rw-r--r--libroff.h24
-rw-r--r--mdoc.c57
-rw-r--r--roff.c69
6 files changed, 101 insertions, 87 deletions
diff --git a/TODO b/TODO
index d077ef26..4af9d6d9 100644
--- a/TODO
+++ b/TODO
@@ -224,9 +224,6 @@ are mere guesses, and some may be wrong.
--- missing eqn features -----------------------------------------------
-- delim
- loc ** exist ** algo ** size * imp ***
-
- The "size" keyword is parsed, but ignored by the formatter.
loc * exist * algo * size * imp *
@@ -515,6 +512,9 @@ are mere guesses, and some may be wrong.
- mention /usr/share/misc/mdoc.template in mdoc(7)?
+- Is all the content from http://www.std.com/obi/BSD/doc/usd/28.tbl/tbl
+ covered in tbl(7)?
+
************************************************************************
* performance issues
************************************************************************
diff --git a/eqn.c b/eqn.c
index 64f2348d..19bd6910 100644
--- a/eqn.c
+++ b/eqn.c
@@ -588,6 +588,30 @@ eqn_box_makebinary(struct eqn_node *ep,
}
/*
+ * Parse the "delim" control statement.
+ */
+static void
+eqn_delim(struct eqn_node *ep)
+{
+ const char *start;
+ size_t sz;
+
+ if ((start = eqn_nextrawtok(ep, &sz)) == NULL)
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "delim");
+ else if (strncmp(start, "off", 3) == 0)
+ ep->delim = 0;
+ else if (strncmp(start, "on", 2) == 0) {
+ if (ep->odelim && ep->cdelim)
+ ep->delim = 1;
+ } else if (start[1] != '\0') {
+ ep->odelim = start[0];
+ ep->cdelim = start[1];
+ ep->delim = 1;
+ }
+}
+
+/*
* Undefine a previously-defined string.
*/
static int
@@ -698,6 +722,8 @@ this_tok:
EQN_MSG(MANDOCERR_EQNEOF, ep);
break;
case (EQN_TOK_DELIM):
+ eqn_delim(ep);
+ break;
case (EQN_TOK_GFONT):
if (eqn_nextrawtok(ep, NULL) == NULL)
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
diff --git a/libmandoc.h b/libmandoc.h
index 4b62b231..d74d1e20 100644
--- a/libmandoc.h
+++ b/libmandoc.h
@@ -78,12 +78,6 @@ char *roff_strdup(const struct roff *, const char *);
int roff_getcontrol(const struct roff *,
const char *, int *);
int roff_getformat(const struct roff *);
-#if 0
-char roff_eqndelim(const struct roff *);
-void roff_openeqn(struct roff *, const char *,
- int, int, const char *);
-int roff_closeeqn(struct roff *);
-#endif
const struct tbl_span *roff_span(const struct roff *);
const struct eqn *roff_eqn(const struct roff *);
diff --git a/libroff.h b/libroff.h
index 465d2da9..03619c82 100644
--- a/libroff.h
+++ b/libroff.h
@@ -1,6 +1,7 @@
/* $Id$ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 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
@@ -43,16 +44,19 @@ struct tbl_node {
};
struct eqn_node {
- struct eqn_def *defs;
- size_t defsz;
- char *data;
- size_t rew;
- size_t cur;
- size_t sz;
- int gsize;
- struct eqn eqn;
- struct mparse *parse;
- struct eqn_node *next;
+ struct eqn eqn; /* syntax tree of this equation */
+ struct mparse *parse; /* main parser, for error reporting */
+ struct eqn_node *next; /* singly linked list of equations */
+ struct eqn_def *defs; /* array of definitions */
+ char *data; /* source code of this equation */
+ size_t defsz; /* number of definitions */
+ size_t sz; /* length of the source code */
+ size_t cur; /* parse point in the source code */
+ size_t rew; /* beginning of the current token */
+ int gsize; /* default point size */
+ int delim; /* in-line delimiters enabled */
+ char odelim; /* in-line opening delimiter */
+ char cdelim; /* in-line closing delimiter */
};
struct eqn_def {
diff --git a/mdoc.c b/mdoc.c
index 4d4f504e..c05834ae 100644
--- a/mdoc.c
+++ b/mdoc.c
@@ -91,9 +91,6 @@ static struct mdoc_node *node_alloc(struct mdoc *, int, int,
enum mdoct, enum mdoc_type);
static int node_append(struct mdoc *,
struct mdoc_node *);
-#if 0
-static int mdoc_preptext(struct mdoc *, int, char *, int);
-#endif
static int mdoc_ptext(struct mdoc *, int, char *, int);
static int mdoc_pmacro(struct mdoc *, int, char *, int);
@@ -609,60 +606,6 @@ mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p)
return(node_append(mdoc, p));
}
-#if 0
-/*
- * Pre-treat a text line.
- * Text lines can consist of equations, which must be handled apart from
- * the regular text.
- * Thus, use this function to step through a line checking if it has any
- * equations embedded in it.
- * This must handle multiple equations AND equations that do not end at
- * the end-of-line, i.e., will re-enter in the next roff parse.
- */
-static int
-mdoc_preptext(struct mdoc *mdoc, int line, char *buf, int offs)
-{
- char *start, *end;
- char delim;
-
- while ('\0' != buf[offs]) {
- /* Mark starting position if eqn is set. */
- start = NULL;
- if ('\0' != (delim = roff_eqndelim(mdoc->roff)))
- if (NULL != (start = strchr(buf + offs, delim)))
- *start++ = '\0';
-
- /* Parse text as normal. */
- if ( ! mdoc_ptext(mdoc, line, buf, offs))
- return(0);
-
- /* Continue only if an equation exists. */
- if (NULL == start)
- break;
-
- /* Read past the end of the equation. */
- offs += start - (buf + offs);
- assert(start == &buf[offs]);
- if (NULL != (end = strchr(buf + offs, delim))) {
- *end++ = '\0';
- while (' ' == *end)
- end++;
- }
-
- /* Parse the equation itself. */
- roff_openeqn(mdoc->roff, NULL, line, offs, buf);
-
- /* Process a finished equation? */
- if (roff_closeeqn(mdoc->roff))
- if ( ! mdoc_addeqn(mdoc, roff_eqn(mdoc->roff)))
- return(0);
- offs += (end - (buf + offs));
- }
-
- return(1);
-}
-#endif
-
/*
* Parse free-form text, that is, a line that does not begin with the
* control character.
diff --git a/roff.c b/roff.c
index 4e5d5024..4bbb48e3 100644
--- a/roff.c
+++ b/roff.c
@@ -120,6 +120,7 @@ struct roff {
struct eqn_node *last_eqn; /* last equation parsed */
struct eqn_node *first_eqn; /* first equation parsed */
struct eqn_node *eqn; /* current equation being parsed */
+ int eqn_inline; /* current equation is inline */
int options; /* parse options */
int rstacksz; /* current size limit of rstack */
int rstackpos; /* position in rstack */
@@ -183,6 +184,8 @@ static enum rofferr roff_cond(ROFF_ARGS);
static enum rofferr roff_cond_text(ROFF_ARGS);
static enum rofferr roff_cond_sub(ROFF_ARGS);
static enum rofferr roff_ds(ROFF_ARGS);
+static enum rofferr roff_eqndelim(struct roff *,
+ char **, size_t *, int);
static int roff_evalcond(const char *, int *);
static int roff_evalnum(const char *, int *, int *, int);
static int roff_evalpar(const char *, int *, int *);
@@ -724,10 +727,17 @@ roff_parseln(struct roff *r, int ln, char **bufp,
enum rofferr e;
int ppos, ctl;
- /*
- * Run the reserved-word filter only if we have some reserved
- * words to fill in.
- */
+ /* Handle in-line equation delimiters. */
+
+ if (r->last_eqn != NULL && r->last_eqn->delim &&
+ (r->eqn == NULL || r->eqn_inline)) {
+ e = roff_eqndelim(r, bufp, szp, pos);
+ if (e == ROFF_REPARSE)
+ return(e);
+ assert(e == ROFF_CONT);
+ }
+
+ /* Expand some escape sequences. */
e = roff_res(r, bufp, szp, ln, pos);
if (ROFF_IGN == e)
@@ -1841,14 +1851,48 @@ roff_T_(ROFF_ARGS)
return(ROFF_IGN);
}
-#if 0
-static int
-roff_closeeqn(struct roff *r)
+/*
+ * Handle in-line equation delimiters.
+ */
+static enum rofferr
+roff_eqndelim(struct roff *r, char **bufp, size_t *szp, int pos)
{
+ char *cp1, *cp2;
- return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0);
+ /*
+ * Outside equations, look for an opening delimiter.
+ * If we are inside an equation, we already know it is
+ * in-line, or this function wouldn't have been called;
+ * so look for a closing delimiter.
+ */
+
+ cp1 = *bufp + pos;
+ cp2 = strchr(cp1, r->eqn == NULL ?
+ r->last_eqn->odelim : r->last_eqn->cdelim);
+ if (cp2 == NULL)
+ return(ROFF_CONT);
+
+ /* Found a delimiter; get rid of surrounding blanks. */
+
+ cp1 = cp2++;
+ while (cp2[0] == ' ')
+ cp2++;
+ while (cp1[-1] == ' ')
+ cp1--;
+ *cp1 = '\0';
+
+ /* Replace the delimiter with an equation macro. */
+
+ *szp = mandoc_asprintf(&cp1, "%s\n.E%c\n\\&%s", *bufp,
+ r->eqn == NULL ? 'Q' : 'N', cp2) + 1;
+ free(*bufp);
+ *bufp = cp1;
+
+ /* Toggle the in-line state of the eqn subsystem. */
+
+ r->eqn_inline = r->eqn == NULL;
+ return(ROFF_REPARSE);
}
-#endif
static void
roff_openeqn(struct roff *r, const char *name, int line,
@@ -1860,9 +1904,12 @@ roff_openeqn(struct roff *r, const char *name, int line,
assert(NULL == r->eqn);
e = eqn_alloc(name, offs, line, r->parse);
- if (r->last_eqn)
+ if (r->last_eqn) {
r->last_eqn->next = e;
- else
+ e->delim = r->last_eqn->delim;
+ e->odelim = r->last_eqn->odelim;
+ e->cdelim = r->last_eqn->cdelim;
+ } else
r->first_eqn = r->last_eqn = e;
r->eqn = r->last_eqn = e;