version 1.182, 2011/03/07 01:35:51 |
version 1.192, 2011/07/27 07:09:41 |
|
|
#include <string.h> |
#include <string.h> |
#include <time.h> |
#include <time.h> |
|
|
|
#include "mdoc.h" |
#include "mandoc.h" |
#include "mandoc.h" |
#include "libmdoc.h" |
#include "libmdoc.h" |
#include "libmandoc.h" |
#include "libmandoc.h" |
Line 96 static struct mdoc_node *node_alloc(struct mdoc *, int |
|
Line 97 static struct mdoc_node *node_alloc(struct mdoc *, int |
|
enum mdoct, enum mdoc_type); |
enum mdoct, enum mdoc_type); |
static int node_append(struct mdoc *, |
static int node_append(struct mdoc *, |
struct mdoc_node *); |
struct mdoc_node *); |
|
static int mdoc_preptext(struct mdoc *, int, char *, int); |
static int mdoc_ptext(struct mdoc *, int, char *, int); |
static int mdoc_ptext(struct mdoc *, int, char *, int); |
static int mdoc_pmacro(struct mdoc *, int, char *, int); |
static int mdoc_pmacro(struct mdoc *, int, char *, int); |
|
|
Line 138 mdoc_free1(struct mdoc *mdoc) |
|
Line 140 mdoc_free1(struct mdoc *mdoc) |
|
free(mdoc->meta.vol); |
free(mdoc->meta.vol); |
if (mdoc->meta.msec) |
if (mdoc->meta.msec) |
free(mdoc->meta.msec); |
free(mdoc->meta.msec); |
|
if (mdoc->meta.date) |
|
free(mdoc->meta.date); |
} |
} |
|
|
|
|
Line 190 mdoc_free(struct mdoc *mdoc) |
|
Line 194 mdoc_free(struct mdoc *mdoc) |
|
* Allocate volatile and non-volatile parse resources. |
* Allocate volatile and non-volatile parse resources. |
*/ |
*/ |
struct mdoc * |
struct mdoc * |
mdoc_alloc(struct regset *regs, void *data, mandocmsg msg) |
mdoc_alloc(struct roff *roff, struct mparse *parse) |
{ |
{ |
struct mdoc *p; |
struct mdoc *p; |
|
|
p = mandoc_calloc(1, sizeof(struct mdoc)); |
p = mandoc_calloc(1, sizeof(struct mdoc)); |
|
|
p->msg = msg; |
p->parse = parse; |
p->data = data; |
p->roff = roff; |
p->regs = regs; |
|
|
|
mdoc_hash_init(); |
mdoc_hash_init(); |
mdoc_alloc1(p); |
mdoc_alloc1(p); |
Line 231 mdoc_addeqn(struct mdoc *m, const struct eqn *ep) |
|
Line 234 mdoc_addeqn(struct mdoc *m, const struct eqn *ep) |
|
/* No text before an initial macro. */ |
/* No text before an initial macro. */ |
|
|
if (SEC_NONE == m->lastnamed) { |
if (SEC_NONE == m->lastnamed) { |
mdoc_pmsg(m, ep->line, ep->pos, MANDOCERR_NOTEXT); |
mdoc_pmsg(m, ep->ln, ep->pos, MANDOCERR_NOTEXT); |
return(1); |
return(1); |
} |
} |
|
|
n = node_alloc(m, ep->line, ep->pos, MDOC_MAX, MDOC_EQN); |
n = node_alloc(m, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN); |
n->eqn = ep; |
n->eqn = ep; |
|
|
if ( ! node_append(m, n)) |
if ( ! node_append(m, n)) |
Line 288 mdoc_parseln(struct mdoc *m, int ln, char *buf, int of |
|
Line 291 mdoc_parseln(struct mdoc *m, int ln, char *buf, int of |
|
* whether this mode is on or off. |
* whether this mode is on or off. |
* Note that this mode is also switched by the Sh macro. |
* Note that this mode is also switched by the Sh macro. |
*/ |
*/ |
if (m->regs->regs[(int)REG_nS].set) { |
if (roff_regisset(m->roff, REG_nS)) { |
if (m->regs->regs[(int)REG_nS].v.u) |
if (roff_regget(m->roff, REG_nS)) |
m->flags |= MDOC_SYNOPSIS; |
m->flags |= MDOC_SYNOPSIS; |
else |
else |
m->flags &= ~MDOC_SYNOPSIS; |
m->flags &= ~MDOC_SYNOPSIS; |
} |
} |
|
|
return(('.' == buf[offs] || '\'' == buf[offs]) ? |
return(mandoc_getcontrol(buf, &offs) ? |
mdoc_pmacro(m, ln, buf, offs) : |
mdoc_pmacro(m, ln, buf, offs) : |
mdoc_ptext(m, ln, buf, offs)); |
mdoc_preptext(m, ln, buf, offs)); |
} |
} |
|
|
|
|
int |
int |
mdoc_vmsg(struct mdoc *mdoc, enum mandocerr t, |
|
int ln, int pos, const char *fmt, ...) |
|
{ |
|
char buf[256]; |
|
va_list ap; |
|
|
|
va_start(ap, fmt); |
|
vsnprintf(buf, sizeof(buf) - 1, fmt, ap); |
|
va_end(ap); |
|
|
|
return((*mdoc->msg)(t, mdoc->data, ln, pos, buf)); |
|
} |
|
|
|
|
|
int |
|
mdoc_macro(MACRO_PROT_ARGS) |
mdoc_macro(MACRO_PROT_ARGS) |
{ |
{ |
assert(tok < MDOC_MAX); |
assert(tok < MDOC_MAX); |
Line 343 mdoc_macro(MACRO_PROT_ARGS) |
|
Line 330 mdoc_macro(MACRO_PROT_ARGS) |
|
if (NULL == m->meta.os) |
if (NULL == m->meta.os) |
m->meta.os = mandoc_strdup("LOCAL"); |
m->meta.os = mandoc_strdup("LOCAL"); |
if (NULL == m->meta.date) |
if (NULL == m->meta.date) |
m->meta.date = mandoc_normdate(NULL, |
m->meta.date = mandoc_normdate |
m->msg, m->data, line, ppos); |
(m->parse, NULL, line, ppos); |
m->flags |= MDOC_PBODY; |
m->flags |= MDOC_PBODY; |
} |
} |
|
|
Line 664 mdoc_node_delete(struct mdoc *m, struct mdoc_node *p) |
|
Line 651 mdoc_node_delete(struct mdoc *m, struct mdoc_node *p) |
|
mdoc_node_free(p); |
mdoc_node_free(p); |
} |
} |
|
|
|
/* |
|
* 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 *m, 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(m->roff))) |
|
if (NULL != (start = strchr(buf + offs, delim))) |
|
*start++ = '\0'; |
|
|
|
/* Parse text as normal. */ |
|
if ( ! mdoc_ptext(m, 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(m->roff, NULL, line, offs, buf); |
|
|
|
/* Process a finished equation? */ |
|
if (roff_closeeqn(m->roff)) |
|
if ( ! mdoc_addeqn(m, roff_eqn(m->roff))) |
|
return(0); |
|
offs += (end - (buf + offs)); |
|
} |
|
|
|
return(1); |
|
} |
|
|
/* |
/* |
* Parse free-form text, that is, a line that does not begin with the |
* Parse free-form text, that is, a line that does not begin with the |
* control character. |
* control character. |
Line 675 mdoc_ptext(struct mdoc *m, int line, char *buf, int of |
|
Line 713 mdoc_ptext(struct mdoc *m, int line, char *buf, int of |
|
char *c, *ws, *end; |
char *c, *ws, *end; |
struct mdoc_node *n; |
struct mdoc_node *n; |
|
|
/* Ignore bogus comments. */ |
|
|
|
if ('\\' == buf[offs] && |
|
'.' == buf[offs + 1] && |
|
'"' == buf[offs + 2]) { |
|
mdoc_pmsg(m, line, offs, MANDOCERR_BADCOMMENT); |
|
return(1); |
|
} |
|
|
|
/* No text before an initial macro. */ |
/* No text before an initial macro. */ |
|
|
if (SEC_NONE == m->lastnamed) { |
if (SEC_NONE == m->lastnamed) { |
Line 726 mdoc_ptext(struct mdoc *m, int line, char *buf, int of |
|
Line 755 mdoc_ptext(struct mdoc *m, int line, char *buf, int of |
|
ws = NULL; |
ws = NULL; |
for (c = end = buf + offs; *c; c++) { |
for (c = end = buf + offs; *c; c++) { |
switch (*c) { |
switch (*c) { |
case '-': |
|
if (mandoc_hyph(buf + offs, c)) |
|
*c = ASCII_HYPH; |
|
ws = NULL; |
|
break; |
|
case ' ': |
case ' ': |
if (NULL == ws) |
if (NULL == ws) |
ws = c; |
ws = c; |
|
|
mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) |
mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) |
{ |
{ |
enum mdoct tok; |
enum mdoct tok; |
int i, j, sv; |
int i, sv; |
char mac[5]; |
char mac[5]; |
struct mdoc_node *n; |
struct mdoc_node *n; |
|
|
/* Empty lines are ignored. */ |
/* Empty post-control lines are ignored. */ |
|
|
offs++; |
if ('"' == buf[offs]) { |
|
mdoc_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT); |
if ('\0' == buf[offs]) |
|
return(1); |
return(1); |
|
} else if ('\0' == buf[offs]) |
|
return(1); |
|
|
i = offs; |
sv = offs; |
|
|
/* Accept tabs/whitespace after the initial control char. */ |
|
|
|
if (' ' == buf[i] || '\t' == buf[i]) { |
|
i++; |
|
while (buf[i] && (' ' == buf[i] || '\t' == buf[i])) |
|
i++; |
|
if ('\0' == buf[i]) |
|
return(1); |
|
} |
|
|
|
sv = i; |
|
|
|
/* |
/* |
* Copy the first word into a nil-terminated buffer. |
* Copy the first word into a nil-terminated buffer. |
* Stop copying when a tab, space, or eoln is encountered. |
* Stop copying when a tab, space, or eoln is encountered. |
*/ |
*/ |
|
|
j = 0; |
i = 0; |
while (j < 4 && '\0' != buf[i] && ' ' != buf[i] && '\t' != buf[i]) |
while (i < 4 && '\0' != buf[offs] && |
mac[j++] = buf[i++]; |
' ' != buf[offs] && '\t' != buf[offs]) |
mac[j] = '\0'; |
mac[i++] = buf[offs++]; |
|
|
tok = (j > 1 || j < 4) ? mdoc_hash_find(mac) : MDOC_MAX; |
mac[i] = '\0'; |
|
|
|
tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX; |
|
|
if (MDOC_MAX == tok) { |
if (MDOC_MAX == tok) { |
mdoc_vmsg(m, MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1); |
mandoc_vmsg(MANDOCERR_MACRO, m->parse, |
|
ln, sv, "%s", buf + sv - 1); |
return(1); |
return(1); |
} |
} |
|
|
/* Disregard the first trailing tab, if applicable. */ |
/* Disregard the first trailing tab, if applicable. */ |
|
|
if ('\t' == buf[i]) |
if ('\t' == buf[offs]) |
i++; |
offs++; |
|
|
/* Jump to the next non-whitespace word. */ |
/* Jump to the next non-whitespace word. */ |
|
|
while (buf[i] && ' ' == buf[i]) |
while (buf[offs] && ' ' == buf[offs]) |
i++; |
offs++; |
|
|
/* |
/* |
* Trailing whitespace. Note that tabs are allowed to be passed |
* Trailing whitespace. Note that tabs are allowed to be passed |
* into the parser as "text", so we only warn about spaces here. |
* into the parser as "text", so we only warn about spaces here. |
*/ |
*/ |
|
|
if ('\0' == buf[i] && ' ' == buf[i - 1]) |
if ('\0' == buf[offs] && ' ' == buf[offs - 1]) |
mdoc_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE); |
mdoc_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE); |
|
|
/* |
/* |
* If an initial macro or a list invocation, divert directly |
* If an initial macro or a list invocation, divert directly |
Line 875 mdoc_pmacro(struct mdoc *m, int ln, char *buf, int off |
|
Line 892 mdoc_pmacro(struct mdoc *m, int ln, char *buf, int off |
|
*/ |
*/ |
|
|
if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) { |
if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) { |
if ( ! mdoc_macro(m, tok, ln, sv, &i, buf)) |
if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) |
goto err; |
goto err; |
return(1); |
return(1); |
} |
} |
Line 914 mdoc_pmacro(struct mdoc *m, int ln, char *buf, int off |
|
Line 931 mdoc_pmacro(struct mdoc *m, int ln, char *buf, int off |
|
|
|
/* Normal processing of a macro. */ |
/* Normal processing of a macro. */ |
|
|
if ( ! mdoc_macro(m, tok, ln, sv, &i, buf)) |
if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) |
goto err; |
goto err; |
|
|
return(1); |
return(1); |
Line 925 err: /* Error out. */ |
|
Line 942 err: /* Error out. */ |
|
return(0); |
return(0); |
} |
} |
|
|
|
enum mdelim |
|
mdoc_isdelim(const char *p) |
|
{ |
|
|
|
if ('\0' == p[0]) |
|
return(DELIM_NONE); |
|
|
|
if ('\0' == p[1]) |
|
switch (p[0]) { |
|
case('('): |
|
/* FALLTHROUGH */ |
|
case('['): |
|
return(DELIM_OPEN); |
|
case('|'): |
|
return(DELIM_MIDDLE); |
|
case('.'): |
|
/* FALLTHROUGH */ |
|
case(','): |
|
/* FALLTHROUGH */ |
|
case(';'): |
|
/* FALLTHROUGH */ |
|
case(':'): |
|
/* FALLTHROUGH */ |
|
case('?'): |
|
/* FALLTHROUGH */ |
|
case('!'): |
|
/* FALLTHROUGH */ |
|
case(')'): |
|
/* FALLTHROUGH */ |
|
case(']'): |
|
return(DELIM_CLOSE); |
|
default: |
|
return(DELIM_NONE); |
|
} |
|
|
|
if ('\\' != p[0]) |
|
return(DELIM_NONE); |
|
|
|
if (0 == strcmp(p + 1, ".")) |
|
return(DELIM_CLOSE); |
|
if (0 == strcmp(p + 1, "*(Ba")) |
|
return(DELIM_MIDDLE); |
|
|
|
return(DELIM_NONE); |
|
} |