summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--html.c15
-rw-r--r--index.74
-rw-r--r--libmdocml.c18
-rw-r--r--literals.c8
-rw-r--r--mdocml.12
-rw-r--r--mlg.c37
-rw-r--r--private.h22
-rw-r--r--roff.c243
9 files changed, 301 insertions, 53 deletions
diff --git a/Makefile b/Makefile
index 12df8b97..b035ff17 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,8 @@ INSTALL = Makefile $(HEADS) $(SRCS) $(MANS)
FAIL = test.0 test.1 test.2 test.3 test.4 test.5 test.6 \
test.15 test.20 test.22 test.24 test.26 test.27 test.30 \
- test.36 test.37 test.40 test.50 test.61
+ test.36 test.37 test.40 test.50 test.61 test.64 test.65 \
+ test.66
SUCCEED = test.7 test.8 test.9 test.10 test.11 test.12 test.13 \
test.14 test.16 test.17 test.18 test.19 test.21 test.23 \
@@ -43,7 +44,7 @@ SUCCEED = test.7 test.8 test.9 test.10 test.11 test.12 test.13 \
test.35 test.38 test.39 test.41 test.42 test.43 test.44 \
test.45 test.46 test.47 test.48 test.49 test.51 test.52 \
test.54 test.55 test.56 test.57 test.58 test.59 test.60 \
- test.62
+ test.62 test.63 test.67
all: mdocml
diff --git a/html.c b/html.c
index 929b2625..615dc743 100644
--- a/html.c
+++ b/html.c
@@ -141,7 +141,6 @@ html_It_headtagname(struct md_mbuf *mbuf, struct htmlq *q,
switch (n->argc[i]) {
case (ROFF_Ohang):
return(ml_nputs(mbuf, "div", 3, res));
-
case (ROFF_Tag):
/* FALLTHROUGH */
case (ROFF_Column):
@@ -151,8 +150,7 @@ html_It_headtagname(struct md_mbuf *mbuf, struct htmlq *q,
}
}
- abort();
- /* NOTREACHED */
+ return(0);
}
@@ -202,10 +200,7 @@ html_It_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
}
assert(i != ROFF_MAXLINEARG);
- abort();
- /* NOTREACHED */
-
- return(1);
+ return(0);
}
@@ -247,8 +242,7 @@ html_Bl_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
}
assert(i != ROFF_MAXLINEARG);
- abort();
- /* NOTREACHED */
+ return(0);
}
@@ -298,8 +292,7 @@ html_It_blocktagname(struct md_mbuf *mbuf, struct htmlq *q,
}
assert(i != ROFF_MAXLINEARG);
- abort();
- /* NOTREACHED */
+ return(0);
}
diff --git a/index.7 b/index.7
index 53b294b4..da0aecd9 100644
--- a/index.7
+++ b/index.7
@@ -54,7 +54,7 @@ scope),
.It
valid predefined characters (such as \\*(>= and \\*q),
.It
-correctly-ordered document prelude,
+correctly-ordered prelude and sections,
.It
sane macro argument values (such as those for
.Sq \&.Dt
@@ -103,7 +103,7 @@ Download
at http://mdocml.bsd.lv/mdocml.tgz
.Ns .
.\" - UPDATE ME WITH EVERY RELEASE. ----------------------------------
-The current version is 1.0.0, dated 08/12/2008.
+The current version is 1.0.1, dated 08/12/2008.
.\" ------------------------------------------------------------------
.Pp
Previous versions are archived as mdocml-x.y.z.tgz, with the appropriate
diff --git a/libmdocml.c b/libmdocml.c
index ba4e850f..5dbc6364 100644
--- a/libmdocml.c
+++ b/libmdocml.c
@@ -28,8 +28,6 @@
#include "libmdocml.h"
#include "private.h"
-#define BUFFER_LINE BUFSIZ /* Default line-buffer size. */
-
static int md_run_enter(const struct md_args *,
struct md_mbuf *, struct md_rbuf *, void *);
static int md_run_leave(const struct md_args *, struct md_mbuf *,
@@ -162,8 +160,8 @@ md_run_enter(const struct md_args *args, struct md_mbuf *mbuf,
struct md_rbuf *rbuf, void *p)
{
ssize_t sz, i;
- char line[BUFFER_LINE];
size_t pos;
+ char line[MD_LINE];
md_line fp;
assert(args);
@@ -192,17 +190,10 @@ again:
return(md_run_leave(args, mbuf, rbuf, 0, p));
for (i = 0; i < sz; i++) {
- /*
- if ( ! isascii(rbuf->buf[i])) {
- warnx("%s: non-ascii char (line %zu, col %zu)",
- rbuf->name, rbuf->line, pos);
- return(md_run_leave(args, mbuf, rbuf, -1, p));
- }
- */
if ('\n' != rbuf->buf[i]) {
- if (pos < BUFFER_LINE) {
+ if (pos < MD_LINE) {
/* LINTED */
- line[pos++] = rbuf->buf[i];
+ rbuf->linebuf[pos++] = rbuf->buf[i];
continue;
}
warnx("%s: line %zu too long",
@@ -210,7 +201,8 @@ again:
return(md_run_leave(args, mbuf, rbuf, -1, p));
}
- line[(int)pos] = 0;
+ rbuf->linebuf[(int)pos] = 0;
+ (void)memcpy(line, rbuf->linebuf, sizeof(line));
if ( ! (*fp)(p, line))
return(md_run_leave(args, mbuf, rbuf, -1, p));
rbuf->line++;
diff --git a/literals.c b/literals.c
index d132c7ea..a55098f9 100644
--- a/literals.c
+++ b/literals.c
@@ -88,7 +88,13 @@ ml_literal(int tok, const int *argc,
assert(ROFF_ARGMAX == *argc);
if (NULL == *morep)
return("AT&amp;T UNIX");
- if (0 == strcmp(*morep, "v6"))
+ if (0 == strcmp(*morep, "v1"))
+ return("Version 1 AT&amp;T UNIX");
+ else if (0 == strcmp(*morep, "v2"))
+ return("Version 2 AT&amp;T UNIX");
+ else if (0 == strcmp(*morep, "v3"))
+ return("Version 3 AT&amp;T UNIX");
+ else if (0 == strcmp(*morep, "v6"))
return("Version 6 AT&amp;T UNIX");
else if (0 == strcmp(*morep, "v7"))
return("Version 7 AT&amp;T UNIX");
diff --git a/mdocml.1 b/mdocml.1
index c96285ba..a40336a1 100644
--- a/mdocml.1
+++ b/mdocml.1
@@ -34,6 +34,8 @@ which may be
for stdout.
.It Fl W
Print warnings to stderr.
+.It Fl v
+Make warning and error messages verbose.
.It Ar infile
Read input from
.Ar infile ,
diff --git a/mlg.c b/mlg.c
index e930b7d0..7c9ab1a7 100644
--- a/mlg.c
+++ b/mlg.c
@@ -543,7 +543,7 @@ mlg_atom_special(struct md_mlg *p, int tok,
if ( ! mlg_string(p, start, *more++))
return(0);
- assert(NULL == *more);
+ /*assert(NULL == *more);*/ /* FIXME: ROFF_Sx */
return(mlg_endtag(p, MD_NS_INLINE, tok));
}
@@ -790,6 +790,8 @@ mlg_msg(struct md_mlg *p, enum roffmsg lvl,
const char *buf, const char *pos, const char *msg)
{
char *level;
+ char b[256];
+ int i;
switch (lvl) {
case (ROFF_WARN):
@@ -803,12 +805,31 @@ mlg_msg(struct md_mlg *p, enum roffmsg lvl,
default:
abort();
}
-
- if (pos)
- (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
- p->rbuf->name, p->rbuf->line, level,
- msg, pos - buf);
- else
- (void)fprintf(stderr, "%s: %s: %s\n",
+
+ if (pos) {
+ assert(pos >= buf);
+ if (0 < p->args->verbosity) {
+ (void)snprintf(b, sizeof(b),
+ "%s:%zu: %s: %s\n",
+ p->rbuf->name, p->rbuf->line,
+ level, msg);
+ (void)strlcat(b, "Error at: ", sizeof(b));
+ (void)strlcat(b, p->rbuf->linebuf, sizeof(b));
+
+ (void)strlcat(b, "\n ", sizeof(b));
+ for (i = 0; i < pos - buf; i++)
+ (void)strlcat(b, " ", sizeof(b));
+ (void)strlcat(b, "^", sizeof(b));
+
+ } else
+ (void)snprintf(b, sizeof(b),
+ "%s:%zu: %s: %s (col %zu)",
+ p->rbuf->name, p->rbuf->line,
+ level, msg, pos - buf);
+ } else
+ (void)snprintf(b, sizeof(b), "%s: %s: %s",
p->rbuf->name, level, msg);
+
+ (void)fprintf(stderr, "%s\n", b);
}
+
diff --git a/private.h b/private.h
index 109417cb..8c5f375c 100644
--- a/private.h
+++ b/private.h
@@ -19,6 +19,7 @@
#ifndef PRIVATE_H
#define PRIVATE_H
+#include <stdio.h>
#include <time.h>
struct md_rbuf {
@@ -27,6 +28,8 @@ struct md_rbuf {
char *buf; /* Buffer. */
size_t bufsz; /* Size of buffer. */
size_t line; /* Current line number. */
+#define MD_LINE (BUFSIZ)
+ char linebuf[MD_LINE];
};
struct md_mbuf {
@@ -266,6 +269,25 @@ enum roffmsec {
ROFF_MSEC_MAX
};
+#define ROFFSec_NMASK (0x07)
+
+#define ROFFSec_NAME (1 << 0)
+#define ROFFSec_SYNOP (1 << 1)
+#define ROFFSec_DESC (1 << 2)
+#define ROFFSec_RETVAL (1 << 3)
+#define ROFFSec_ENV (1 << 4)
+#define ROFFSec_FILES (1 << 5)
+#define ROFFSec_EX (1 << 6)
+#define ROFFSec_DIAG (1 << 7)
+#define ROFFSec_ERRS (1 << 8)
+#define ROFFSec_SEEALSO (1 << 9)
+#define ROFFSec_STAND (1 << 10)
+#define ROFFSec_HIST (1 << 11)
+#define ROFFSec_AUTH (1 << 12)
+#define ROFFSec_CAVEATS (1 << 13)
+#define ROFFSec_BUGS (1 << 14)
+#define ROFFSec_OTHER (1 << 15)
+
struct roffcb {
void (*roffmsg)(void *, enum roffmsg,
const char *, const char *, const char *);
diff --git a/roff.c b/roff.c
index fcb50368..5bcbbdc9 100644
--- a/roff.c
+++ b/roff.c
@@ -35,7 +35,6 @@
/* FIXME: First letters of quoted-text interpreted in rofffindtok. */
/* FIXME: `No' not implemented. */
/* TODO: warn if Pp occurs before/after Sh etc. (see mdoc.samples). */
-/* TODO: warn about "X section only" macros. */
/* TODO: warn about empty lists. */
/* TODO: (warn) some sections need specific elements. */
/* TODO: (warn) NAME section has particular order. */
@@ -67,6 +66,8 @@ struct rofftree {
#define ROFF_BODY (1 << 5) /* In roff body. */
struct roffcb cb; /* Callbacks. */
void *arg; /* Callbacks' arg. */
+ int csec; /* Current section. */
+ int asec; /* Thus-far sections. */
};
static struct roffnode *roffnode_new(int, struct rofftree *);
@@ -81,7 +82,10 @@ static int rofffindtok(const char *);
static int rofffindarg(const char *);
static int rofffindcallable(const char *);
static int roffismsec(const char *);
+static int roffissec(const char **);
static int roffispunct(const char *);
+static int roffchecksec(struct rofftree *,
+ const char *, int);
static int roffargs(const struct rofftree *,
int, char *, char **);
static int roffargok(int, int);
@@ -124,7 +128,12 @@ roff_free(struct rofftree *tree, int flush)
if (ROFF_PRELUDE & tree->state) {
roff_err(tree, NULL, "prelude never finished");
goto end;
- }
+ } else if ( ! (ROFFSec_NAME & tree->asec)) {
+ roff_err(tree, NULL, "missing `NAME' section");
+ goto end;
+ } else if ( ! (ROFFSec_NMASK & tree->asec))
+ roff_warn(tree, NULL, "missing suggested `NAME', "
+ "`SYNOPSIS', `DESCRIPTION' sections");
for (n = tree->last; n; n = n->parent) {
if (0 != tokens[n->tok].ctx)
@@ -328,7 +337,7 @@ roffparse(struct rofftree *tree, char *buf)
return(1);
if (ROFF_MAX == (tok = rofffindtok(buf + 1))) {
- roff_err(tree, buf + 1, "bogus line macro");
+ roff_err(tree, buf, "bogus line macro");
return(0);
} else if ( ! roffargs(tree, tok, buf, argv))
return(0);
@@ -517,6 +526,125 @@ rofffindtok(const char *buf)
static int
+roffchecksec(struct rofftree *tree, const char *start, int sec)
+{
+ int prior;
+
+ switch (sec) {
+ case(ROFFSec_SYNOP):
+ if ((prior = ROFFSec_NAME) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_DESC):
+ if ((prior = ROFFSec_SYNOP) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_RETVAL):
+ if ((prior = ROFFSec_DESC) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_ENV):
+ if ((prior = ROFFSec_RETVAL) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_FILES):
+ if ((prior = ROFFSec_ENV) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_EX):
+ if ((prior = ROFFSec_FILES) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_DIAG):
+ if ((prior = ROFFSec_EX) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_ERRS):
+ if ((prior = ROFFSec_DIAG) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_SEEALSO):
+ if ((prior = ROFFSec_ERRS) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_STAND):
+ if ((prior = ROFFSec_SEEALSO) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_HIST):
+ if ((prior = ROFFSec_STAND) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_AUTH):
+ if ((prior = ROFFSec_HIST) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_CAVEATS):
+ if ((prior = ROFFSec_AUTH) & tree->asec)
+ return(1);
+ break;
+ case(ROFFSec_BUGS):
+ if ((prior = ROFFSec_CAVEATS) & tree->asec)
+ return(1);
+ break;
+ default:
+ return(1);
+ }
+
+ roff_warn(tree, start, "section violates conventional order");
+ return(1);
+}
+
+
+static int
+roffissec(const char **p)
+{
+
+ assert(*p);
+ if (NULL != *(p + 1)) {
+ if (NULL != *(p + 2))
+ return(ROFFSec_OTHER);
+ if (0 == strcmp(*p, "RETURN") &&
+ 0 == strcmp(*(p + 1), "VALUES"))
+ return(ROFFSec_RETVAL);
+ if (0 == strcmp(*p, "SEE") &&
+ 0 == strcmp(*(p + 1), "ALSO"))
+ return(ROFFSec_SEEALSO);
+ return(ROFFSec_OTHER);
+ }
+
+ if (0 == strcmp(*p, "NAME"))
+ return(ROFFSec_NAME);
+ else if (0 == strcmp(*p, "SYNOPSIS"))
+ return(ROFFSec_SYNOP);
+ else if (0 == strcmp(*p, "DESCRIPTION"))
+ return(ROFFSec_DESC);
+ else if (0 == strcmp(*p, "ENVIRONMENT"))
+ return(ROFFSec_ENV);
+ else if (0 == strcmp(*p, "FILES"))
+ return(ROFFSec_FILES);
+ else if (0 == strcmp(*p, "EXAMPLES"))
+ return(ROFFSec_EX);
+ else if (0 == strcmp(*p, "DIAGNOSTICS"))
+ return(ROFFSec_DIAG);
+ else if (0 == strcmp(*p, "ERRORS"))
+ return(ROFFSec_ERRS);
+ else if (0 == strcmp(*p, "STANDARDS"))
+ return(ROFFSec_STAND);
+ else if (0 == strcmp(*p, "HISTORY"))
+ return(ROFFSec_HIST);
+ else if (0 == strcmp(*p, "AUTHORS"))
+ return(ROFFSec_AUTH);
+ else if (0 == strcmp(*p, "CAVEATS"))
+ return(ROFFSec_CAVEATS);
+ else if (0 == strcmp(*p, "BUGS"))
+ return(ROFFSec_BUGS);
+
+ return(ROFFSec_OTHER);
+}
+
+
+static int
roffismsec(const char *p)
{
@@ -660,7 +788,13 @@ roffspecial(struct rofftree *tree, int tok, const char *start,
case (ROFF_At):
if (0 == sz)
break;
- if (0 == strcmp(*ordp, "v6"))
+ if (0 == strcmp(*ordp, "v1"))
+ break;
+ else if (0 == strcmp(*ordp, "v2"))
+ break;
+ else if (0 == strcmp(*ordp, "v3"))
+ break;
+ else if (0 == strcmp(*ordp, "v6"))
break;
else if (0 == strcmp(*ordp, "v7"))
break;
@@ -670,7 +804,7 @@ roffspecial(struct rofftree *tree, int tok, const char *start,
break;
else if (0 == strcmp(*ordp, "V.4"))
break;
- roff_err(tree, start, "invalid `At' arg");
+ roff_err(tree, *ordp, "invalid `At' arg");
return(0);
case (ROFF_Xr):
@@ -683,6 +817,8 @@ roffspecial(struct rofftree *tree, int tok, const char *start,
}
/* FALLTHROUGH */
+ case (ROFF_Sx):
+ /* FALLTHROUGH*/
case (ROFF_Fn):
if (0 != sz)
break;
@@ -704,8 +840,6 @@ roffspecial(struct rofftree *tree, int tok, const char *start,
case (ROFF_Rv):
/* FALLTHROUGH*/
- case (ROFF_Sx):
- /* FALLTHROUGH*/
case (ROFF_Ex):
if (1 == sz)
break;
@@ -1159,6 +1293,20 @@ roff_layout(ROFFCALL_ARGS)
int i, c, argcp[ROFF_MAXLINEARG];
char *argvp[ROFF_MAXLINEARG];
+ /*
+ * The roff_layout function is for multi-line macros. A layout
+ * has a start and end point, which is either declared
+ * explicitly or implicitly. An explicit start and end is
+ * embodied by `.Bl' and `.El', with the former being the start
+ * and the latter being an end. The `.Sh' and `.Ss' tags, on
+ * the other hand, are implicit. The scope of a layout is the
+ * space between start and end. Explicit layouts may not close
+ * out implicit ones and vice versa; implicit layouts may close
+ * out other implicit layouts.
+ */
+
+ assert( ! (ROFF_CALLABLE & tokens[tok].flags));
+
if (ROFF_PRELUDE & tree->state) {
roff_err(tree, *argv, "bad `%s' in prelude",
toknames[tok]);
@@ -1183,11 +1331,56 @@ roff_layout(ROFFCALL_ARGS)
* Layouts have two parts: the layout body and header. The
* layout header is the trailing text of the line macro, while
* the layout body is everything following until termination.
+ * Example:
+ *
+ * .It Fl f ) ;
+ * Bar.
+ *
+ * ...Produces...
+ *
+ * <block>
+ * <head>
+ * <!Fl f!> ;
+ * </head>
+ *
+ * <body>
+ * Bar.
+ * </body>
+ * </block>
*/
if ( ! (*tree->cb.roffblkin)(tree->arg, tok, argcp,
(const char **)argvp))
return(0);
+
+ /* +++ Begin run macro-specific hooks over argv. */
+
+ switch (tok) {
+ case (ROFF_Sh):
+ if (NULL == *argv) {
+ roff_err(tree, *(argv - 1),
+ "`Sh' expects arguments");
+ return(0);
+ }
+ tree->csec = roffissec((const char **)argv);
+ if ( ! (ROFFSec_OTHER & tree->csec) &&
+ tree->asec & tree->csec)
+ roff_warn(tree, *argv, "section repeated");
+ if (0 == tree->asec && ! (ROFFSec_NAME & tree->csec)) {
+ roff_err(tree, *argv, "`NAME' section "
+ "must be first");
+ return(0);
+ } else if ( ! roffchecksec(tree, *argv, tree->csec))
+ return(0);
+
+ tree->asec |= tree->csec;
+ break;
+ default:
+ break;
+ }
+
+ /* --- End run macro-specific hooks over argv. */
+
if (NULL == *argv)
return((*tree->cb.roffblkbodyin)
(tree->arg, tok, argcp,
@@ -1210,8 +1403,7 @@ roff_layout(ROFFCALL_ARGS)
if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
return(0);
- return((*tree->cb.roffblkbodyin)
- (tree->arg, tok, argcp,
+ return((*tree->cb.roffblkbodyin)(tree->arg, tok, argcp,
(const char **)argvp));
}
@@ -1254,12 +1446,10 @@ roff_layout(ROFFCALL_ARGS)
if ( ! roffpurgepunct(tree, argv))
return(0);
-
if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
return(0);
- return((*tree->cb.roffblkbodyin)
- (tree->arg, tok, argcp,
- (const char **)argvp));
+ return((*tree->cb.roffblkbodyin)(tree->arg,
+ tok, argcp, (const char **)argvp));
}
@@ -1271,6 +1461,16 @@ roff_ordered(ROFFCALL_ARGS)
char *ordp[ROFF_MAXLINEARG], *p,
*argvp[ROFF_MAXLINEARG];
+ /*
+ * Ordered macros pass their arguments directly to handlers,
+ * instead of considering it free-form text. Thus, the
+ * following macro looks as follows:
+ *
+ * .Xr foo 1 ) ,
+ *
+ * .Xr arg1 arg2 punctuation
+ */
+
if (ROFF_PRELUDE & tree->state) {
roff_err(tree, *argv, "`%s' disallowed in prelude",
toknames[tok]);
@@ -1279,15 +1479,14 @@ roff_ordered(ROFFCALL_ARGS)
first = (*argv == tree->cur);
p = *argv++;
+ ordp[0] = NULL;
if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
return(0);
- if (NULL == *argv) {
- ordp[0] = NULL;
+ if (NULL == *argv)
return(roffspecial(tree, tok, p, argcp,
(const char **)argvp, 0, ordp));
- }
i = 0;
while (*argv && i < ROFF_MAXLINEARG) {
@@ -1335,6 +1534,18 @@ roff_text(ROFFCALL_ARGS)
int i, j, first, c, argcp[ROFF_MAXLINEARG];
char *argvp[ROFF_MAXLINEARG];
+ /*
+ * Text macros are similar to special tokens, except that
+ * arguments are instead flushed as pure data: we're only
+ * concerned with the macro and its arguments. Example:
+ *
+ * .Fl v W f ;
+ *
+ * ...Produces...
+ *
+ * <fl> v W f </fl> ;
+ */
+
if (ROFF_PRELUDE & tree->state) {
roff_err(tree, *argv, "`%s' disallowed in prelude",
toknames[tok]);