summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main.c15
-rw-r--r--mandoc.h3
-rw-r--r--roff.c79
3 files changed, 89 insertions, 8 deletions
diff --git a/main.c b/main.c
index dd9da74a..cbcc3762 100644
--- a/main.c
+++ b/main.c
@@ -773,6 +773,14 @@ mwarn(void *arg, int line, int col, const char *msg)
return(1);
}
+static const char * const mandocerrs[MANDOCERR_MAX] = {
+ "ok",
+ "multi-line scope open on exit",
+ "request for scope closure when no matching scope is open",
+ "line arguments will be lost",
+ "memory exhausted"
+};
+
/*
* XXX: this is experimental code that will eventually become the
* generic means of covering all warnings and errors!
@@ -785,7 +793,12 @@ mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg)
cp = (struct curparse *)arg;
- /*fprintf(stderr, "%s:%d:%d: %s\n", cp->file, ln, col + 1, msg);*/
+ fprintf(stderr, "%s:%d:%d: %s", cp->file,
+ ln, col + 1, mandocerrs[t]);
+
+ if (msg)
+ fprintf(stderr, ": %s", msg);
+ fputc('\n', stderr);
return(1);
}
diff --git a/mandoc.h b/mandoc.h
index cfdc4b5b..b0cdf181 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -25,6 +25,9 @@ enum mandocerr {
MANDOCERR_NOSCOPE, /* request scope close w/none open */
#define MANDOCERR_WARNING MANDOCERR_SCOPEEXIT
+ MANDOCERR_ARGSLOST, /* line arguments will be lost */
+#define MANDOCERR_ERROR MANDOCERR_ARGSLOST
+
MANDOCERR_MEM, /* memory exhausted */
#define MANDOCERR_FATAL MANDOCERR_MEM
diff --git a/roff.c b/roff.c
index 0782fd8f..ca9fa9ae 100644
--- a/roff.c
+++ b/roff.c
@@ -44,6 +44,7 @@ struct roff {
struct roffnode {
enum rofft tok; /* type of node */
struct roffnode *parent; /* up one in stack */
+ char *end; /* custom end-token */
int line; /* parse line */
int col; /* parse col */
};
@@ -267,21 +268,52 @@ roff_ignore(ROFF_ARGS)
static enum rofferr
roff_sub_ig(ROFF_ARGS)
{
- enum rofft t;
- int pos;
+ int i, j;
/* Ignore free-text lines. */
if ('.' != (*bufp)[ppos])
return(ROFF_IGN);
- /* Ignore macros unless it's a closing macro. */
+ if (r->last->end) {
+ /*
+ * Allow a macro to break us, if we've defined a special
+ * one for the case. Old groff didn't allow spaces to
+ * buffer the macro, but new groff does. Whee!
+ */
+ i = ppos + 1;
+ while ((*bufp)[i] && ' ' == (*bufp)[i])
+ i++;
+
+ if ('\0' == (*bufp)[i])
+ return(ROFF_IGN);
+
+ for (j = 0; r->last->end[j]; i++, j++)
+ if ((*bufp)[i] != r->last->end[j])
+ return(ROFF_IGN);
+
+ if (r->last->end[j])
+ return(ROFF_IGN);
+ if ((*bufp)[i] && ' ' != (*bufp)[i])
+ return(ROFF_IGN);
- t = roff_parse(*bufp, &pos);
- if (ROFF_close != t)
+ while (' ' == (*bufp)[i])
+ i++;
+ } else if (ROFF_close != roff_parse(*bufp, &i))
return(ROFF_IGN);
+ /*
+ * Pop off the ignoring context and warn if we're going to lose
+ * any of our remaining arguments.
+ */
+
roffnode_pop(r);
+
+ if ('\0' == (*bufp)[i])
+ return(ROFF_IGN);
+ if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, i, NULL))
+ return(ROFF_ERR);
+
return(ROFF_IGN);
}
@@ -303,9 +335,42 @@ roff_new_close(ROFF_ARGS)
static enum rofferr
roff_new_ig(ROFF_ARGS)
{
+ int i;
+
+ if ( ! roffnode_push(r, ROFF_ig, ln, ppos))
+ return(ROFF_ERR);
+
+ i = (int)ppos;
+ while ((*bufp)[i] && ' ' != (*bufp)[i])
+ i++;
+
+ if (i == (int)ppos)
+ return(ROFF_IGN);
+ if ((*bufp)[i])
+ if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, i, NULL))
+ return(ROFF_ERR);
- return(roffnode_push(r, ROFF_ig, ln, ppos) ?
- ROFF_IGN : ROFF_ERR);
+ /*
+ * If `.ig' has arguments, the first argument (up to the next
+ * whitespace) is interpreted as an argument marking the macro
+ * close. Thus, `.ig foo' will close at `.foo'.
+ *
+ * NOTE: the closing macro `.foo' in the above case is not
+ * allowed to have leading spaces with old groff! Thus `.foo'
+ * != `. foo'. Oh yeah, everything after the `.foo' is lost.
+ * Merry fucking Christmas.
+ */
+
+ r->last->end = malloc((size_t)i - ppos + 1);
+ if (NULL == r->last->end) {
+ (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL);
+ return(ROFF_ERR);
+ }
+
+ memcpy(r->last->end, &(*bufp)[ppos], (size_t)i - ppos);
+ r->last->end[(size_t)i - ppos] = '\0';
+
+ return(ROFF_IGN);
}