version 1.1, 2010/12/28 13:46:07 |
version 1.17, 2015/01/26 00:57:22 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> |
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> |
|
* Copyright (c) 2015 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 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
*/ |
|
#include "config.h" |
|
|
|
#include <sys/types.h> |
|
|
|
#include <ctype.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
|
|
#include "mandoc.h" |
|
#include "libmandoc.h" |
#include "libroff.h" |
#include "libroff.h" |
|
|
enum tbl_ident { |
enum tbl_ident { |
Line 49 struct tbl_phrase { |
|
Line 57 struct tbl_phrase { |
|
static const struct tbl_phrase keys[KEY_MAXKEYS] = { |
static const struct tbl_phrase keys[KEY_MAXKEYS] = { |
{ "center", TBL_OPT_CENTRE, KEY_CENTRE}, |
{ "center", TBL_OPT_CENTRE, KEY_CENTRE}, |
{ "centre", TBL_OPT_CENTRE, KEY_CENTRE}, |
{ "centre", TBL_OPT_CENTRE, KEY_CENTRE}, |
{ "delim", 0, KEY_DELIM}, |
{ "delim", 0, KEY_DELIM}, |
{ "expand", TBL_OPT_EXPAND, KEY_EXPAND}, |
{ "expand", TBL_OPT_EXPAND, KEY_EXPAND}, |
{ "box", TBL_OPT_BOX, KEY_BOX}, |
{ "box", TBL_OPT_BOX, KEY_BOX}, |
{ "doublebox", TBL_OPT_DBOX, KEY_DBOX}, |
{ "doublebox", TBL_OPT_DBOX, KEY_DBOX}, |
{ "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX}, |
{ "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX}, |
{ "frame", TBL_OPT_BOX, KEY_FRAME}, |
{ "frame", TBL_OPT_BOX, KEY_FRAME}, |
{ "doubleframe", TBL_OPT_DBOX, KEY_DFRAME}, |
{ "doubleframe", TBL_OPT_DBOX, KEY_DFRAME}, |
Line 63 static const struct tbl_phrase keys[KEY_MAXKEYS] = { |
|
Line 71 static const struct tbl_phrase keys[KEY_MAXKEYS] = { |
|
{ "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE}, |
{ "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE}, |
}; |
}; |
|
|
static int arg(struct tbl *, int, const char *, int *, int); |
static void arg(struct tbl_node *, int, |
static int opt(struct tbl *, int, const char *, int *); |
const char *, int *, enum tbl_ident); |
|
|
static int |
|
arg(struct tbl *tbl, int ln, const char *p, int *pos, int key) |
static void |
|
arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) |
{ |
{ |
int sv; |
const char *optname; |
|
int len, want; |
|
|
again: |
while (isspace((unsigned char)p[*pos])) |
sv = *pos; |
(*pos)++; |
|
|
switch (tbl_next(tbl, p, pos)) { |
/* Arguments are enclosed in parentheses. */ |
case (TBL_TOK_OPENPAREN): |
|
break; |
|
case (TBL_TOK_SPACE): |
|
/* FALLTHROUGH */ |
|
case (TBL_TOK_TAB): |
|
goto again; |
|
default: |
|
return(0); |
|
} |
|
|
|
sv = *pos; |
len = 0; |
|
if (p[*pos] == '(') { |
switch (tbl_next(tbl, p, pos)) { |
(*pos)++; |
case (TBL_TOK__MAX): |
while (p[*pos + len] != ')') |
break; |
len++; |
default: |
|
return(0); |
|
} |
} |
|
|
switch (key) { |
switch (key) { |
case (KEY_DELIM): |
case KEY_DELIM: |
/* FIXME: cache this value. */ |
optname = "delim"; |
if (2 != strlen(tbl->buf)) |
want = 2; |
return(0); |
|
tbl->delims[0] = tbl->buf[0]; |
|
tbl->delims[1] = tbl->buf[1]; |
|
break; |
break; |
case (KEY_TAB): |
case KEY_TAB: |
/* FIXME: cache this value. */ |
optname = "tab"; |
if (1 != strlen(tbl->buf)) |
want = 1; |
return(0); |
if (len == want) |
tbl->tab = tbl->buf[0]; |
tbl->opts.tab = p[*pos]; |
break; |
break; |
case (KEY_LINESIZE): |
case KEY_LINESIZE: |
if ((tbl->linesize = atoi(tbl->buf)) <= 0) |
optname = "linesize"; |
return(0); |
want = 0; |
break; |
break; |
case (KEY_DPOINT): |
case KEY_DPOINT: |
/* FIXME: cache this value. */ |
optname = "decimalpoint"; |
if (1 != strlen(tbl->buf)) |
want = 1; |
return(0); |
if (len == want) |
tbl->decimal = tbl->buf[0]; |
tbl->opts.decimal = p[*pos]; |
break; |
break; |
default: |
default: |
abort(); |
abort(); |
|
/* NOTREACHED */ |
} |
} |
|
|
sv = *pos; |
if (len == 0) |
|
mandoc_msg(MANDOCERR_TBLOPT_NOARG, |
|
tbl->parse, ln, *pos, optname); |
|
else if (want && len != want) |
|
mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ, |
|
tbl->parse, ln, *pos, |
|
"%s want %d have %d", optname, want, len); |
|
|
switch (tbl_next(tbl, p, pos)) { |
*pos += len; |
case (TBL_TOK_CLOSEPAREN): |
if (p[*pos] == ')') |
break; |
(*pos)++; |
default: |
|
return(0); |
|
} |
|
|
|
return(1); |
|
} |
} |
|
|
|
/* |
static int |
* Parse one line of options up to the semicolon. |
opt(struct tbl *tbl, int ln, const char *p, int *pos) |
* Each option can be preceded by blanks and/or commas, |
|
* and some options are followed by arguments. |
|
*/ |
|
void |
|
tbl_option(struct tbl_node *tbl, int ln, const char *p) |
{ |
{ |
int i, sv; |
int i, pos, len; |
|
|
again: |
pos = 0; |
sv = *pos; |
for (;;) { |
|
while (isspace((unsigned char)p[pos]) || p[pos] == ',') |
|
pos++; |
|
|
/* |
if (p[pos] == ';') |
* EBNF describing this section: |
return; |
* |
|
* options ::= option_list [:space:]* [;][\n] |
|
* option_list ::= option option_tail |
|
* option_tail ::= [:space:]+ option_list | |
|
* ::= epsilon |
|
* option ::= [:alpha:]+ args |
|
* args ::= [:space:]* [(] [:alpha:]+ [)] |
|
*/ |
|
|
|
switch (tbl_next(tbl, p, pos)) { |
/* Parse one option name. */ |
case (TBL_TOK__MAX): |
|
break; |
|
case (TBL_TOK_SPACE): |
|
/* FALLTHROUGH */ |
|
case (TBL_TOK_TAB): |
|
goto again; |
|
case (TBL_TOK_SEMICOLON): |
|
tbl->part = TBL_PART_LAYOUT; |
|
return(1); |
|
default: |
|
return(0); |
|
} |
|
|
|
for (i = 0; i < KEY_MAXKEYS; i++) { |
len = 0; |
/* FIXME: hashtable this? */ |
while (isalpha((unsigned char)p[pos + len])) |
if (strcasecmp(tbl->buf, keys[i].name)) |
len++; |
|
|
|
if (len == 0) { |
|
mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA, |
|
tbl->parse, ln, pos, "%c", p[pos]); |
|
pos++; |
continue; |
continue; |
if (keys[i].key) |
} |
tbl->opts |= keys[i].key; |
|
else if ( ! arg(tbl, ln, p, pos, keys[i].ident)) |
|
return(0); |
|
|
|
break; |
/* Look up the option name. */ |
} |
|
|
|
if (KEY_MAXKEYS == i) |
i = 0; |
return(0); |
while (i < KEY_MAXKEYS && |
|
(strncasecmp(p + pos, keys[i].name, len) || |
|
keys[i].name[len] != '\0')) |
|
i++; |
|
|
return(opt(tbl, ln, p, pos)); |
if (i == KEY_MAXKEYS) { |
} |
mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse, |
|
ln, pos, "%.*s", len, p + pos); |
|
pos += len; |
|
continue; |
|
} |
|
|
int |
/* Handle the option. */ |
tbl_option(struct tbl *tbl, int ln, const char *p) |
|
{ |
|
int pos; |
|
|
|
pos = 0; |
pos += len; |
return(opt(tbl, ln, p, &pos)); |
if (keys[i].key) |
|
tbl->opts.opts |= keys[i].key; |
|
else |
|
arg(tbl, ln, p, &pos, keys[i].ident); |
|
} |
} |
} |