version 1.110, 2010/12/28 10:59:07 |
version 1.123, 2011/01/22 13:16:02 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
ROFF_ie, |
ROFF_ie, |
ROFF_if, |
ROFF_if, |
ROFF_ig, |
ROFF_ig, |
|
ROFF_it, |
ROFF_ne, |
ROFF_ne, |
ROFF_nh, |
ROFF_nh, |
ROFF_nr, |
ROFF_nr, |
|
|
ROFF_tr, |
ROFF_tr, |
ROFF_TS, |
ROFF_TS, |
ROFF_TE, |
ROFF_TE, |
|
ROFF_T_, |
ROFF_cblock, |
ROFF_cblock, |
ROFF_ccond, /* FIXME: remove this. */ |
ROFF_ccond, /* FIXME: remove this. */ |
ROFF_USERDEF, |
ROFF_USERDEF, |
|
|
struct regset *regs; /* read/writable registers */ |
struct regset *regs; /* read/writable registers */ |
struct roffstr *first_string; /* user-defined strings & macros */ |
struct roffstr *first_string; /* user-defined strings & macros */ |
const char *current_string; /* value of last called user macro */ |
const char *current_string; /* value of last called user macro */ |
struct tbl *tbl; |
struct tbl_node *first_tbl; /* first table parsed */ |
|
struct tbl_node *last_tbl; /* last table parsed */ |
|
struct tbl_node *tbl; /* current table being parsed */ |
}; |
}; |
|
|
struct roffnode { |
struct roffnode { |
Line 131 static enum rofferr roff_cond_sub(ROFF_ARGS); |
|
Line 135 static enum rofferr roff_cond_sub(ROFF_ARGS); |
|
static enum rofferr roff_ds(ROFF_ARGS); |
static enum rofferr roff_ds(ROFF_ARGS); |
static enum roffrule roff_evalcond(const char *, int *); |
static enum roffrule roff_evalcond(const char *, int *); |
static void roff_freestr(struct roff *); |
static void roff_freestr(struct roff *); |
|
static char *roff_getname(struct roff *, char **, int, int); |
static const char *roff_getstrn(const struct roff *, |
static const char *roff_getstrn(const struct roff *, |
const char *, size_t); |
const char *, size_t); |
static enum rofferr roff_line_ignore(ROFF_ARGS); |
static enum rofferr roff_line_ignore(ROFF_ARGS); |
static enum rofferr roff_line_error(ROFF_ARGS); |
|
static enum rofferr roff_nr(ROFF_ARGS); |
static enum rofferr roff_nr(ROFF_ARGS); |
static int roff_res(struct roff *, |
static int roff_res(struct roff *, |
char **, size_t *, int); |
char **, size_t *, int); |
|
static enum rofferr roff_rm(ROFF_ARGS); |
static void roff_setstr(struct roff *, |
static void roff_setstr(struct roff *, |
const char *, const char *, int); |
const char *, const char *, int); |
static enum rofferr roff_so(ROFF_ARGS); |
static enum rofferr roff_so(ROFF_ARGS); |
static enum rofferr roff_TE(ROFF_ARGS); |
static enum rofferr roff_TE(ROFF_ARGS); |
static enum rofferr roff_TS(ROFF_ARGS); |
static enum rofferr roff_TS(ROFF_ARGS); |
|
static enum rofferr roff_T_(ROFF_ARGS); |
static enum rofferr roff_userdef(ROFF_ARGS); |
static enum rofferr roff_userdef(ROFF_ARGS); |
|
|
/* See roff_hash_find() */ |
/* See roff_hash_find() */ |
Line 167 static struct roffmac roffs[ROFF_MAX] = { |
|
Line 173 static struct roffmac roffs[ROFF_MAX] = { |
|
{ "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, |
{ "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, |
{ "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, |
{ "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, |
{ "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
|
{ "it", roff_line_ignore, NULL, NULL, 0, NULL }, |
{ "ne", roff_line_ignore, NULL, NULL, 0, NULL }, |
{ "ne", roff_line_ignore, NULL, NULL, 0, NULL }, |
{ "nh", roff_line_ignore, NULL, NULL, 0, NULL }, |
{ "nh", roff_line_ignore, NULL, NULL, 0, NULL }, |
{ "nr", roff_nr, NULL, NULL, 0, NULL }, |
{ "nr", roff_nr, NULL, NULL, 0, NULL }, |
{ "rm", roff_line_error, NULL, NULL, 0, NULL }, |
{ "rm", roff_rm, NULL, NULL, 0, NULL }, |
{ "so", roff_so, NULL, NULL, 0, NULL }, |
{ "so", roff_so, NULL, NULL, 0, NULL }, |
{ "tr", roff_line_ignore, NULL, NULL, 0, NULL }, |
{ "tr", roff_line_ignore, NULL, NULL, 0, NULL }, |
{ "TS", roff_TS, NULL, NULL, 0, NULL }, |
{ "TS", roff_TS, NULL, NULL, 0, NULL }, |
{ "TE", roff_TE, NULL, NULL, 0, NULL }, |
{ "TE", roff_TE, NULL, NULL, 0, NULL }, |
|
{ "T&", roff_T_, NULL, NULL, 0, NULL }, |
{ ".", roff_cblock, NULL, NULL, 0, NULL }, |
{ ".", roff_cblock, NULL, NULL, 0, NULL }, |
{ "\\}", roff_ccond, NULL, NULL, 0, NULL }, |
{ "\\}", roff_ccond, NULL, NULL, 0, NULL }, |
{ NULL, roff_userdef, NULL, NULL, 0, NULL }, |
{ NULL, roff_userdef, NULL, NULL, 0, NULL }, |
Line 296 roffnode_push(struct roff *r, enum rofft tok, const ch |
|
Line 304 roffnode_push(struct roff *r, enum rofft tok, const ch |
|
static void |
static void |
roff_free1(struct roff *r) |
roff_free1(struct roff *r) |
{ |
{ |
|
struct tbl_node *t; |
|
|
if (r->tbl) { |
while (r->first_tbl) { |
tbl_free(r->tbl); |
t = r->first_tbl; |
r->tbl = NULL; |
r->first_tbl = t->next; |
|
tbl_free(t); |
} |
} |
|
|
|
r->first_tbl = r->last_tbl = r->tbl = NULL; |
|
|
while (r->last) |
while (r->last) |
roffnode_pop(r); |
roffnode_pop(r); |
|
|
Line 506 roff_parseln(struct roff *r, int ln, char **bufp, |
|
Line 518 roff_parseln(struct roff *r, int ln, char **bufp, |
|
} |
} |
|
|
|
|
int |
void |
roff_endparse(struct roff *r) |
roff_endparse(struct roff *r) |
{ |
{ |
|
|
/* FIXME: if r->tbl */ |
|
if (r->last) |
if (r->last) |
(*r->msg)(MANDOCERR_SCOPEEXIT, r->data, |
(*r->msg)(MANDOCERR_SCOPEEXIT, r->data, |
r->last->line, r->last->col, NULL); |
r->last->line, r->last->col, NULL); |
return(1); |
|
|
if (r->tbl) { |
|
(*r->msg)(MANDOCERR_SCOPEEXIT, r->data, |
|
r->tbl->line, r->tbl->pos, NULL); |
|
tbl_end(r->tbl); |
|
r->tbl = NULL; |
|
} |
} |
} |
|
|
|
|
Line 920 static enum rofferr |
|
Line 937 static enum rofferr |
|
roff_line_ignore(ROFF_ARGS) |
roff_line_ignore(ROFF_ARGS) |
{ |
{ |
|
|
return(ROFF_IGN); |
if (ROFF_it == tok) |
} |
(*r->msg)(MANDOCERR_REQUEST, r->data, ln, ppos, "it"); |
|
|
/* ARGSUSED */ |
|
static enum rofferr |
|
roff_line_error(ROFF_ARGS) |
|
{ |
|
|
|
(*r->msg)(MANDOCERR_REQUEST, r->data, ln, ppos, roffs[tok].name); |
|
return(ROFF_IGN); |
return(ROFF_IGN); |
} |
} |
|
|
Line 1042 roff_ds(ROFF_ARGS) |
|
Line 1053 roff_ds(ROFF_ARGS) |
|
* will have `bar " ' as its value. |
* will have `bar " ' as its value. |
*/ |
*/ |
|
|
name = *bufp + pos; |
string = *bufp + pos; |
|
name = roff_getname(r, &string, ln, pos); |
if ('\0' == *name) |
if ('\0' == *name) |
return(ROFF_IGN); |
return(ROFF_IGN); |
|
|
string = name; |
/* Read past initial double-quote. */ |
/* Read until end of name. */ |
if ('"' == *string) |
while (*string && ' ' != *string) |
|
string++; |
string++; |
|
|
/* Nil-terminate name. */ |
|
if (*string) |
|
*(string++) = '\0'; |
|
|
|
/* Read past spaces. */ |
|
while (*string && ' ' == *string) |
|
string++; |
|
|
|
/* Read passed initial double-quote. */ |
|
if (*string && '"' == *string) |
|
string++; |
|
|
|
/* The rest is the value. */ |
/* The rest is the value. */ |
roff_setstr(r, name, string, 0); |
roff_setstr(r, name, string, 0); |
return(ROFF_IGN); |
return(ROFF_IGN); |
Line 1073 roff_ds(ROFF_ARGS) |
|
Line 1072 roff_ds(ROFF_ARGS) |
|
static enum rofferr |
static enum rofferr |
roff_nr(ROFF_ARGS) |
roff_nr(ROFF_ARGS) |
{ |
{ |
const char *key, *val; |
const char *key; |
|
char *val; |
struct reg *rg; |
struct reg *rg; |
|
|
key = &(*bufp)[pos]; |
val = *bufp + pos; |
|
key = roff_getname(r, &val, ln, pos); |
rg = r->regs->regs; |
rg = r->regs->regs; |
|
|
/* Parse register request. */ |
|
while ((*bufp)[pos] && ' ' != (*bufp)[pos]) |
|
pos++; |
|
|
|
/* |
|
* Set our nil terminator. Because this line is going to be |
|
* ignored anyway, we can munge it as we please. |
|
*/ |
|
if ((*bufp)[pos]) |
|
(*bufp)[pos++] = '\0'; |
|
|
|
/* Skip whitespace to register token. */ |
|
while ((*bufp)[pos] && ' ' == (*bufp)[pos]) |
|
pos++; |
|
|
|
val = &(*bufp)[pos]; |
|
|
|
/* Process register token. */ |
|
|
|
if (0 == strcmp(key, "nS")) { |
if (0 == strcmp(key, "nS")) { |
rg[(int)REG_nS].set = 1; |
rg[(int)REG_nS].set = 1; |
if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u)) |
if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u)) |
Line 1109 roff_nr(ROFF_ARGS) |
|
Line 1091 roff_nr(ROFF_ARGS) |
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static enum rofferr |
static enum rofferr |
|
roff_rm(ROFF_ARGS) |
|
{ |
|
const char *name; |
|
char *cp; |
|
|
|
cp = *bufp + pos; |
|
while ('\0' != *cp) { |
|
name = roff_getname(r, &cp, ln, cp - *bufp); |
|
if ('\0' != *name) |
|
roff_setstr(r, name, NULL, 0); |
|
} |
|
return(ROFF_IGN); |
|
} |
|
|
|
/* ARGSUSED */ |
|
static enum rofferr |
roff_TE(ROFF_ARGS) |
roff_TE(ROFF_ARGS) |
{ |
{ |
|
|
if (NULL == r->tbl) |
if (NULL == r->tbl) |
(*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); |
(*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); |
else |
else |
tbl_free(r->tbl); |
tbl_end(r->tbl); |
|
|
r->tbl = NULL; |
r->tbl = NULL; |
return(ROFF_IGN); |
return(ROFF_IGN); |
Line 1123 roff_TE(ROFF_ARGS) |
|
Line 1121 roff_TE(ROFF_ARGS) |
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static enum rofferr |
static enum rofferr |
|
roff_T_(ROFF_ARGS) |
|
{ |
|
|
|
if (NULL == r->tbl) |
|
(*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); |
|
else |
|
tbl_restart(ppos, ln, r->tbl); |
|
|
|
return(ROFF_IGN); |
|
} |
|
|
|
/* ARGSUSED */ |
|
static enum rofferr |
roff_TS(ROFF_ARGS) |
roff_TS(ROFF_ARGS) |
{ |
{ |
|
struct tbl_node *t; |
|
|
if (r->tbl) { |
if (r->tbl) { |
(*r->msg)(MANDOCERR_SCOPEBROKEN, r->data, ln, ppos, NULL); |
(*r->msg)(MANDOCERR_SCOPEBROKEN, r->data, ln, ppos, NULL); |
tbl_reset(r->tbl); |
tbl_end(r->tbl); |
} else |
} |
r->tbl = tbl_alloc(); |
|
|
|
|
t = tbl_alloc(ppos, ln, r->data, r->msg); |
|
|
|
if (r->last_tbl) |
|
r->last_tbl->next = t; |
|
else |
|
r->first_tbl = r->last_tbl = t; |
|
|
|
r->tbl = r->last_tbl = t; |
return(ROFF_IGN); |
return(ROFF_IGN); |
} |
} |
|
|
Line 1166 roff_userdef(ROFF_ARGS) |
|
Line 1185 roff_userdef(ROFF_ARGS) |
|
{ |
{ |
const char *arg[9]; |
const char *arg[9]; |
char *cp, *n1, *n2; |
char *cp, *n1, *n2; |
int i, quoted, pairs; |
int i; |
|
|
/* |
/* |
* Collect pointers to macro argument strings |
* Collect pointers to macro argument strings |
* and null-terminate them. |
* and null-terminate them. |
*/ |
*/ |
cp = *bufp + pos; |
cp = *bufp + pos; |
for (i = 0; i < 9; i++) { |
for (i = 0; i < 9; i++) |
/* Quoting can only start with a new word. */ |
arg[i] = '\0' == *cp ? "" : |
if ('"' == *cp) { |
mandoc_getarg(&cp, r->msg, r->data, ln, &pos); |
quoted = 1; |
|
cp++; |
|
} else |
|
quoted = 0; |
|
arg[i] = cp; |
|
for (pairs = 0; '\0' != *cp; cp++) { |
|
/* Unquoted arguments end at blanks. */ |
|
if (0 == quoted) { |
|
if (' ' == *cp) |
|
break; |
|
continue; |
|
} |
|
/* After pairs of quotes, move left. */ |
|
if (pairs) |
|
cp[-pairs] = cp[0]; |
|
/* Pairs of quotes do not end words, ... */ |
|
if ('"' == cp[0] && '"' == cp[1]) { |
|
pairs++; |
|
cp++; |
|
continue; |
|
} |
|
/* ... but solitary quotes do. */ |
|
if ('"' != *cp) |
|
continue; |
|
if (pairs) |
|
cp[-pairs] = '\0'; |
|
*cp = ' '; |
|
break; |
|
} |
|
/* Last argument; the remaining ones are empty strings. */ |
|
if ('\0' == *cp) |
|
continue; |
|
/* Null-terminate argument and move to the next one. */ |
|
*cp++ = '\0'; |
|
while (' ' == *cp) |
|
cp++; |
|
} |
|
|
|
/* |
/* |
* Expand macro arguments. |
* Expand macro arguments. |
Line 1252 roff_userdef(ROFF_ARGS) |
|
Line 1234 roff_userdef(ROFF_ARGS) |
|
ROFF_REPARSE : ROFF_APPEND); |
ROFF_REPARSE : ROFF_APPEND); |
} |
} |
|
|
|
|
|
static char * |
|
roff_getname(struct roff *r, char **cpp, int ln, int pos) |
|
{ |
|
char *name, *cp; |
|
|
|
name = *cpp; |
|
if ('\0' == *name) |
|
return(name); |
|
|
|
/* Read until end of name. */ |
|
for (cp = name; '\0' != *cp && ' ' != *cp; cp++) { |
|
if ('\\' != *cp) |
|
continue; |
|
cp++; |
|
if ('\\' == *cp) |
|
continue; |
|
(*r->msg)(MANDOCERR_NAMESC, r->data, ln, pos, NULL); |
|
*cp = '\0'; |
|
name = cp; |
|
} |
|
|
|
/* Nil-terminate name. */ |
|
if ('\0' != *cp) |
|
*(cp++) = '\0'; |
|
|
|
/* Read past spaces. */ |
|
while (' ' == *cp) |
|
cp++; |
|
|
|
*cpp = cp; |
|
return(name); |
|
} |
|
|
|
|
/* |
/* |
* Store *string into the user-defined string called *name. |
* Store *string into the user-defined string called *name. |
* In multiline mode, append to an existing entry and append '\n'; |
* In multiline mode, append to an existing entry and append '\n'; |
Line 1348 roff_freestr(struct roff *r) |
|
Line 1365 roff_freestr(struct roff *r) |
|
} |
} |
|
|
r->first_string = NULL; |
r->first_string = NULL; |
|
} |
|
|
|
const struct tbl_span * |
|
roff_span(const struct roff *r) |
|
{ |
|
|
|
return(r->tbl ? tbl_span(r->tbl) : NULL); |
} |
} |