version 1.175, 2012/11/19 17:57:23 |
version 1.178, 2013/07/13 12:52:07 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2010, 2011, 2012 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2010, 2011, 2012, 2013 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 |
|
|
|
|
#include <assert.h> |
#include <assert.h> |
#include <ctype.h> |
#include <ctype.h> |
|
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
|
Line 186 static void roff_freestr(struct roffkv *); |
|
Line 187 static void roff_freestr(struct roffkv *); |
|
static char *roff_getname(struct roff *, char **, int, int); |
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_it(ROFF_ARGS); |
static enum rofferr roff_line_ignore(ROFF_ARGS); |
static enum rofferr roff_line_ignore(ROFF_ARGS); |
static enum rofferr roff_nr(ROFF_ARGS); |
static enum rofferr roff_nr(ROFF_ARGS); |
static void roff_openeqn(struct roff *, const char *, |
static void roff_openeqn(struct roff *, const char *, |
int, int, const char *); |
int, int, const char *); |
static enum rofft roff_parse(struct roff *, const char *, int *); |
static enum rofft roff_parse(struct roff *, const char *, int *); |
static enum rofferr roff_parsetext(char *); |
static enum rofferr roff_parsetext(char **, size_t *, int, int *); |
static enum rofferr roff_res(struct roff *, |
static enum rofferr roff_res(struct roff *, |
char **, size_t *, int, int); |
char **, size_t *, int, int); |
static enum rofferr roff_rm(ROFF_ARGS); |
static enum rofferr roff_rm(ROFF_ARGS); |
Line 233 static struct roffmac roffs[ROFF_MAX] = { |
|
Line 235 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 }, |
{ "it", roff_it, 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 }, |
Line 295 static const struct predef predefs[PREDEFS_MAX] = { |
|
Line 297 static const struct predef predefs[PREDEFS_MAX] = { |
|
/* See roffhash_find() */ |
/* See roffhash_find() */ |
#define ROFF_HASH(p) (p[0] - ASCII_LO) |
#define ROFF_HASH(p) (p[0] - ASCII_LO) |
|
|
|
static int roffit_lines; /* number of lines to delay */ |
|
static char *roffit_macro; /* nil-terminated macro line */ |
|
|
static void |
static void |
roffhash_init(void) |
roffhash_init(void) |
{ |
{ |
Line 393 roffnode_push(struct roff *r, enum rofft tok, const ch |
|
Line 398 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; |
struct tbl_node *tbl; |
struct eqn_node *e; |
struct eqn_node *e; |
int i; |
int i; |
|
|
while (NULL != (t = r->first_tbl)) { |
while (NULL != (tbl = r->first_tbl)) { |
r->first_tbl = t->next; |
r->first_tbl = tbl->next; |
tbl_free(t); |
tbl_free(tbl); |
} |
} |
|
|
r->first_tbl = r->last_tbl = r->tbl = NULL; |
r->first_tbl = r->last_tbl = r->tbl = NULL; |
|
|
} |
} |
|
|
/* |
/* |
* Process text streams: convert all breakable hyphens into ASCII_HYPH. |
* Process text streams: |
|
* Convert all breakable hyphens into ASCII_HYPH. |
|
* Decrement and spring input line trap. |
*/ |
*/ |
static enum rofferr |
static enum rofferr |
roff_parsetext(char *p) |
roff_parsetext(char **bufp, size_t *szp, int pos, int *offs) |
{ |
{ |
size_t sz; |
size_t sz; |
const char *start; |
const char *start; |
|
char *p; |
|
int isz; |
enum mandoc_esc esc; |
enum mandoc_esc esc; |
|
|
start = p; |
start = p = *bufp + pos; |
|
|
while ('\0' != *p) { |
while ('\0' != *p) { |
sz = strcspn(p, "-\\"); |
sz = strcspn(p, "-\\"); |
Line 633 roff_parsetext(char *p) |
|
Line 642 roff_parsetext(char *p) |
|
p++; |
p++; |
} |
} |
|
|
|
/* Spring the input line trap. */ |
|
if (1 == roffit_lines) { |
|
isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro); |
|
if (-1 == isz) { |
|
perror(NULL); |
|
exit((int)MANDOCLEVEL_SYSERR); |
|
} |
|
free(*bufp); |
|
*bufp = p; |
|
*szp = isz + 1; |
|
*offs = 0; |
|
free(roffit_macro); |
|
roffit_lines = 0; |
|
return(ROFF_REPARSE); |
|
} else if (1 < roffit_lines) |
|
--roffit_lines; |
return(ROFF_CONT); |
return(ROFF_CONT); |
} |
} |
|
|
Line 677 roff_parseln(struct roff *r, int ln, char **bufp, |
|
Line 702 roff_parseln(struct roff *r, int ln, char **bufp, |
|
return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); |
return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); |
if (r->tbl) |
if (r->tbl) |
return(tbl_read(r->tbl, ln, *bufp, pos)); |
return(tbl_read(r->tbl, ln, *bufp, pos)); |
return(roff_parsetext(*bufp + pos)); |
return(roff_parsetext(bufp, szp, pos, offs)); |
} else if ( ! ctl) { |
} else if ( ! ctl) { |
if (r->eqn) |
if (r->eqn) |
return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); |
return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); |
if (r->tbl) |
if (r->tbl) |
return(tbl_read(r->tbl, ln, *bufp, pos)); |
return(tbl_read(r->tbl, ln, *bufp, pos)); |
return(roff_parsetext(*bufp + pos)); |
return(roff_parsetext(bufp, szp, pos, offs)); |
} else if (r->eqn) |
} else if (r->eqn) |
return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); |
return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); |
|
|
Line 1028 roff_cond_sub(ROFF_ARGS) |
|
Line 1053 roff_cond_sub(ROFF_ARGS) |
|
|
|
rr = r->last->rule; |
rr = r->last->rule; |
roffnode_cleanscope(r); |
roffnode_cleanscope(r); |
|
t = roff_parse(r, *bufp, &pos); |
|
|
/* |
/* |
* If the macro is unknown, first check if it contains a closing |
* Fully handle known macros when they are structurally |
* delimiter `\}'. If it does, close out our scope and return |
* required or when the conditional evaluated to true. |
* the currently-scoped rule (ignore or continue). Else, drop |
|
* into the currently-scoped rule. |
|
*/ |
*/ |
|
|
if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) { |
if ((ROFF_MAX != t) && |
ep = &(*bufp)[pos]; |
(ROFF_ccond == t || ROFFRULE_ALLOW == rr || |
for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { |
ROFFMAC_STRUCT & roffs[t].flags)) { |
ep++; |
assert(roffs[t].proc); |
if ('}' != *ep) |
return((*roffs[t].proc)(r, t, bufp, szp, |
continue; |
ln, ppos, pos, offs)); |
|
} |
|
|
/* |
/* Always check for the closing delimiter `\}'. */ |
* Make the \} go away. |
|
* This is a little haphazard, as it's not quite |
|
* clear how nroff does this. |
|
* If we're at the end of line, then just chop |
|
* off the \} and resize the buffer. |
|
* If we aren't, then conver it to spaces. |
|
*/ |
|
|
|
if ('\0' == *(ep + 1)) { |
ep = &(*bufp)[pos]; |
*--ep = '\0'; |
while (NULL != (ep = strchr(ep, '\\'))) { |
*szp -= 2; |
if ('}' != *(++ep)) |
} else |
continue; |
*(ep - 1) = *ep = ' '; |
|
|
|
roff_ccond(r, ROFF_ccond, bufp, szp, |
/* |
ln, pos, pos + 2, offs); |
* If we're at the end of line, then just chop |
break; |
* off the \} and resize the buffer. |
} |
* If we aren't, then convert it to spaces. |
return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); |
*/ |
} |
|
|
|
/* |
if ('\0' == *(ep + 1)) { |
* A denied conditional must evaluate its children if and only |
*--ep = '\0'; |
* if they're either structurally required (such as loops and |
*szp -= 2; |
* conditionals) or a closing macro. |
} else |
*/ |
*(ep - 1) = *ep = ' '; |
|
|
if (ROFFRULE_DENY == rr) |
roff_ccond(r, ROFF_ccond, bufp, szp, |
if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) |
ln, pos, pos + 2, offs); |
if (ROFF_ccond != t) |
break; |
return(ROFF_IGN); |
} |
|
return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); |
assert(roffs[t].proc); |
|
return((*roffs[t].proc)(r, t, bufp, szp, |
|
ln, ppos, pos, offs)); |
|
} |
} |
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
Line 1132 static enum rofferr |
|
Line 1145 static enum rofferr |
|
roff_line_ignore(ROFF_ARGS) |
roff_line_ignore(ROFF_ARGS) |
{ |
{ |
|
|
if (ROFF_it == tok) |
|
mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it"); |
|
|
|
return(ROFF_IGN); |
return(ROFF_IGN); |
} |
} |
|
|
Line 1309 roff_rm(ROFF_ARGS) |
|
Line 1319 roff_rm(ROFF_ARGS) |
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static enum rofferr |
static enum rofferr |
|
roff_it(ROFF_ARGS) |
|
{ |
|
char *cp; |
|
size_t len; |
|
int iv; |
|
|
|
/* Parse the number of lines. */ |
|
cp = *bufp + pos; |
|
len = strcspn(cp, " \t"); |
|
cp[len] = '\0'; |
|
if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) { |
|
mandoc_msg(MANDOCERR_NUMERIC, r->parse, |
|
ln, ppos, *bufp + 1); |
|
return(ROFF_IGN); |
|
} |
|
cp += len + 1; |
|
|
|
/* Arm the input line trap. */ |
|
roffit_lines = iv; |
|
roffit_macro = mandoc_strdup(cp); |
|
return(ROFF_IGN); |
|
} |
|
|
|
/* ARGSUSED */ |
|
static enum rofferr |
roff_Dd(ROFF_ARGS) |
roff_Dd(ROFF_ARGS) |
{ |
{ |
const char *const *cp; |
const char *const *cp; |
Line 1413 roff_EN(ROFF_ARGS) |
|
Line 1448 roff_EN(ROFF_ARGS) |
|
static enum rofferr |
static enum rofferr |
roff_TS(ROFF_ARGS) |
roff_TS(ROFF_ARGS) |
{ |
{ |
struct tbl_node *t; |
struct tbl_node *tbl; |
|
|
if (r->tbl) { |
if (r->tbl) { |
mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL); |
mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL); |
tbl_end(&r->tbl); |
tbl_end(&r->tbl); |
} |
} |
|
|
t = tbl_alloc(ppos, ln, r->parse); |
tbl = tbl_alloc(ppos, ln, r->parse); |
|
|
if (r->last_tbl) |
if (r->last_tbl) |
r->last_tbl->next = t; |
r->last_tbl->next = tbl; |
else |
else |
r->first_tbl = r->last_tbl = t; |
r->first_tbl = r->last_tbl = tbl; |
|
|
r->tbl = r->last_tbl = t; |
r->tbl = r->last_tbl = tbl; |
return(ROFF_IGN); |
return(ROFF_IGN); |
} |
} |
|
|