summaryrefslogtreecommitdiffstats
path: root/roff.c
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2012-06-12 20:21:04 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2012-06-12 20:21:04 +0000
commit998c9d785cfa1c8ef5531ee3fdfdf08d5b048264 (patch)
tree4c4a73bfd8209c2ac1c13746a548c2ce4e274b94 /roff.c
parent9dc9bb2f44e3a94b8adc881ca071f6b8aaeae019 (diff)
downloadmandoc-998c9d785cfa1c8ef5531ee3fdfdf08d5b048264.tar.gz
Add `cc' support.
This was reported by espie@ and in the TODO. Caveat: `cc' has buggy behaviour when invoked in groff(1) and followed by a line-breaking control character macro, e.g., in a -man doc, .cc | .B foo 'B foo |cc 'B foo will cause groff(1) to behave properly for `.B' but inline the macro definition for `B' when invoked with the line-breaking macro.
Diffstat (limited to 'roff.c')
-rw-r--r--roff.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/roff.c b/roff.c
index 4f0a392a..0b33a3dc 100644
--- a/roff.c
+++ b/roff.c
@@ -39,6 +39,7 @@ enum rofft {
ROFF_am,
ROFF_ami,
ROFF_am1,
+ ROFF_cc,
ROFF_de,
ROFF_dei,
ROFF_de1,
@@ -105,6 +106,7 @@ struct roff {
struct mparse *parse; /* parse point */
struct roffnode *last; /* leaf of stack */
enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
+ char control; /* control character */
int rstackpos; /* position in rstack */
struct reg regs[REG__MAX];
struct roffkv *strtab; /* user-defined strings & macros */
@@ -169,6 +171,7 @@ static enum rofferr roff_block(ROFF_ARGS);
static enum rofferr roff_block_text(ROFF_ARGS);
static enum rofferr roff_block_sub(ROFF_ARGS);
static enum rofferr roff_cblock(ROFF_ARGS);
+static enum rofferr roff_cc(ROFF_ARGS);
static enum rofferr roff_ccond(ROFF_ARGS);
static enum rofferr roff_cond(ROFF_ARGS);
static enum rofferr roff_cond_text(ROFF_ARGS);
@@ -215,6 +218,7 @@ static struct roffmac roffs[ROFF_MAX] = {
{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "cc", roff_cc, NULL, NULL, 0, NULL },
{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
@@ -392,6 +396,7 @@ roff_reset(struct roff *r)
roff_free1(r);
+ r->control = 0;
memset(&r->regs, 0, sizeof(struct reg) * REG__MAX);
for (i = 0; i < PREDEFS_MAX; i++)
@@ -611,7 +616,7 @@ roff_parseln(struct roff *r, int ln, char **bufp,
assert(ROFF_CONT == e);
ppos = pos;
- ctl = mandoc_getcontrol(*bufp, &pos);
+ ctl = roff_getcontrol(r, *bufp, &pos);
/*
* First, if a scope is open and we're not a macro, pass the
@@ -1363,6 +1368,23 @@ roff_TS(ROFF_ARGS)
/* ARGSUSED */
static enum rofferr
+roff_cc(ROFF_ARGS)
+{
+ const char *p;
+
+ p = *bufp + pos;
+
+ if ('\0' == *p || '.' == (r->control = *p++))
+ r->control = 0;
+
+ if ('\0' != *p)
+ mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
+
+ return(ROFF_IGN);
+}
+
+/* ARGSUSED */
+static enum rofferr
roff_tr(ROFF_ARGS)
{
const char *p, *first, *second;
@@ -1757,3 +1779,38 @@ roff_strdup(const struct roff *r, const char *p)
res[(int)ssz] = '\0';
return(res);
}
+
+/*
+ * 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.
+ * If the control character has been set with `.cc', then let that grain
+ * precedence.
+ * This is slighly contrary to groff, where using the non-breaking
+ * control character when `cc' has been invoked will cause the
+ * non-breaking macro contents to be printed verbatim.
+ */
+int
+roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
+{
+ int pos;
+
+ pos = *ppos;
+
+ if (0 != r->control && cp[pos] == r->control)
+ pos++;
+ else if (0 != r->control)
+ return(0);
+ else 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);
+}