1*260e9a87SYuri Pankov /* $Id: tbl_opts.c,v 1.20 2015/01/28 17:32:07 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 395c635efSGarrett D'Amore * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*260e9a87SYuri Pankov * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #include "config.h" 19*260e9a87SYuri Pankov 20*260e9a87SYuri Pankov #include <sys/types.h> 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <ctype.h> 2395c635efSGarrett D'Amore #include <stdio.h> 2495c635efSGarrett D'Amore #include <stdlib.h> 2595c635efSGarrett D'Amore #include <string.h> 2695c635efSGarrett D'Amore 2795c635efSGarrett D'Amore #include "mandoc.h" 2895c635efSGarrett D'Amore #include "libmandoc.h" 2995c635efSGarrett D'Amore #include "libroff.h" 3095c635efSGarrett D'Amore 31*260e9a87SYuri Pankov #define KEY_DPOINT 0 32*260e9a87SYuri Pankov #define KEY_DELIM 1 33*260e9a87SYuri Pankov #define KEY_LINESIZE 2 34*260e9a87SYuri Pankov #define KEY_TAB 3 3595c635efSGarrett D'Amore 3695c635efSGarrett D'Amore struct tbl_phrase { 3795c635efSGarrett D'Amore const char *name; 3895c635efSGarrett D'Amore int key; 3995c635efSGarrett D'Amore }; 4095c635efSGarrett D'Amore 41*260e9a87SYuri Pankov static const struct tbl_phrase keys[] = { 42*260e9a87SYuri Pankov {"decimalpoint", 0}, 43*260e9a87SYuri Pankov {"delim", 0}, 44*260e9a87SYuri Pankov {"linesize", 0}, 45*260e9a87SYuri Pankov {"tab", 0}, 46*260e9a87SYuri Pankov {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX}, 47*260e9a87SYuri Pankov {"box", TBL_OPT_BOX}, 48*260e9a87SYuri Pankov {"frame", TBL_OPT_BOX}, 49*260e9a87SYuri Pankov {"center", TBL_OPT_CENTRE}, 50*260e9a87SYuri Pankov {"centre", TBL_OPT_CENTRE}, 51*260e9a87SYuri Pankov {"doublebox", TBL_OPT_DBOX}, 52*260e9a87SYuri Pankov {"doubleframe", TBL_OPT_DBOX}, 53*260e9a87SYuri Pankov {"expand", TBL_OPT_EXPAND}, 54*260e9a87SYuri Pankov {"nokeep", TBL_OPT_NOKEEP}, 55*260e9a87SYuri Pankov {"nospaces", TBL_OPT_NOSPACE}, 56*260e9a87SYuri Pankov {"nowarn", TBL_OPT_NOWARN}, 5795c635efSGarrett D'Amore }; 5895c635efSGarrett D'Amore 59*260e9a87SYuri Pankov #define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0]))) 6095c635efSGarrett D'Amore 61*260e9a87SYuri Pankov static void arg(struct tbl_node *, int, const char *, int *, int); 62*260e9a87SYuri Pankov 63*260e9a87SYuri Pankov 64*260e9a87SYuri Pankov static void 65*260e9a87SYuri Pankov arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) 6695c635efSGarrett D'Amore { 67*260e9a87SYuri Pankov int len, want; 6895c635efSGarrett D'Amore 69*260e9a87SYuri Pankov while (p[*pos] == ' ' || p[*pos] == '\t') 7095c635efSGarrett D'Amore (*pos)++; 7195c635efSGarrett D'Amore 72*260e9a87SYuri Pankov /* Arguments are enclosed in parentheses. */ 7395c635efSGarrett D'Amore 74*260e9a87SYuri Pankov len = 0; 75*260e9a87SYuri Pankov if (p[*pos] == '(') { 76*260e9a87SYuri Pankov (*pos)++; 77*260e9a87SYuri Pankov while (p[*pos + len] != ')') 78*260e9a87SYuri Pankov len++; 7995c635efSGarrett D'Amore } 8095c635efSGarrett D'Amore 8195c635efSGarrett D'Amore switch (key) { 82*260e9a87SYuri Pankov case KEY_DELIM: 83*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse, 84*260e9a87SYuri Pankov ln, *pos, "%.*s", len, p + *pos); 85*260e9a87SYuri Pankov want = 2; 8695c635efSGarrett D'Amore break; 87*260e9a87SYuri Pankov case KEY_TAB: 88*260e9a87SYuri Pankov want = 1; 89*260e9a87SYuri Pankov if (len == want) 90*260e9a87SYuri Pankov tbl->opts.tab = p[*pos]; 9195c635efSGarrett D'Amore break; 92*260e9a87SYuri Pankov case KEY_LINESIZE: 93*260e9a87SYuri Pankov want = 0; 9495c635efSGarrett D'Amore break; 95*260e9a87SYuri Pankov case KEY_DPOINT: 96*260e9a87SYuri Pankov want = 1; 97*260e9a87SYuri Pankov if (len == want) 98*260e9a87SYuri Pankov tbl->opts.decimal = p[*pos]; 9995c635efSGarrett D'Amore break; 10095c635efSGarrett D'Amore default: 10195c635efSGarrett D'Amore abort(); 10295c635efSGarrett D'Amore /* NOTREACHED */ 10395c635efSGarrett D'Amore } 10495c635efSGarrett D'Amore 105*260e9a87SYuri Pankov if (len == 0) 106*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_TBLOPT_NOARG, 107*260e9a87SYuri Pankov tbl->parse, ln, *pos, keys[key].name); 108*260e9a87SYuri Pankov else if (want && len != want) 109*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ, 110*260e9a87SYuri Pankov tbl->parse, ln, *pos, "%s want %d have %d", 111*260e9a87SYuri Pankov keys[key].name, want, len); 11295c635efSGarrett D'Amore 113*260e9a87SYuri Pankov *pos += len; 114*260e9a87SYuri Pankov if (p[*pos] == ')') 115*260e9a87SYuri Pankov (*pos)++; 11695c635efSGarrett D'Amore } 11795c635efSGarrett D'Amore 118*260e9a87SYuri Pankov /* 119*260e9a87SYuri Pankov * Parse one line of options up to the semicolon. 120*260e9a87SYuri Pankov * Each option can be preceded by blanks and/or commas, 121*260e9a87SYuri Pankov * and some options are followed by arguments. 122*260e9a87SYuri Pankov */ 123*260e9a87SYuri Pankov void 124*260e9a87SYuri Pankov tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs) 12595c635efSGarrett D'Amore { 126*260e9a87SYuri Pankov int i, pos, len; 12795c635efSGarrett D'Amore 128*260e9a87SYuri Pankov pos = *offs; 129*260e9a87SYuri Pankov for (;;) { 130*260e9a87SYuri Pankov while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',') 131*260e9a87SYuri Pankov pos++; 13295c635efSGarrett D'Amore 133*260e9a87SYuri Pankov if (p[pos] == ';') { 134*260e9a87SYuri Pankov *offs = pos + 1; 13595c635efSGarrett D'Amore return; 13695c635efSGarrett D'Amore } 13795c635efSGarrett D'Amore 138*260e9a87SYuri Pankov /* Parse one option name. */ 13995c635efSGarrett D'Amore 140*260e9a87SYuri Pankov len = 0; 141*260e9a87SYuri Pankov while (isalpha((unsigned char)p[pos + len])) 142*260e9a87SYuri Pankov len++; 14395c635efSGarrett D'Amore 144*260e9a87SYuri Pankov if (len == 0) { 145*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA, 146*260e9a87SYuri Pankov tbl->parse, ln, pos, "%c", p[pos]); 147*260e9a87SYuri Pankov pos++; 14895c635efSGarrett D'Amore continue; 149*260e9a87SYuri Pankov } 15095c635efSGarrett D'Amore 151*260e9a87SYuri Pankov /* Look up the option name. */ 15295c635efSGarrett D'Amore 153*260e9a87SYuri Pankov i = 0; 154*260e9a87SYuri Pankov while (i < KEY_MAXKEYS && 155*260e9a87SYuri Pankov (strncasecmp(p + pos, keys[i].name, len) || 156*260e9a87SYuri Pankov keys[i].name[len] != '\0')) 157*260e9a87SYuri Pankov i++; 158*260e9a87SYuri Pankov 159*260e9a87SYuri Pankov if (i == KEY_MAXKEYS) { 160*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse, 161*260e9a87SYuri Pankov ln, pos, "%.*s", len, p + pos); 162*260e9a87SYuri Pankov pos += len; 163*260e9a87SYuri Pankov continue; 164*260e9a87SYuri Pankov } 165*260e9a87SYuri Pankov 166*260e9a87SYuri Pankov /* Handle the option. */ 167*260e9a87SYuri Pankov 168*260e9a87SYuri Pankov pos += len; 16995c635efSGarrett D'Amore if (keys[i].key) 17095c635efSGarrett D'Amore tbl->opts.opts |= keys[i].key; 171*260e9a87SYuri Pankov else 172*260e9a87SYuri Pankov arg(tbl, ln, p, &pos, i); 17395c635efSGarrett D'Amore } 17495c635efSGarrett D'Amore } 175