1*61d06d6bSBaptiste Daroussin /* $Id: tbl_opts.c,v 1.21 2015/09/26 00:54:04 schwarze Exp $ */ 2*61d06d6bSBaptiste Daroussin /* 3*61d06d6bSBaptiste Daroussin * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*61d06d6bSBaptiste Daroussin * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> 5*61d06d6bSBaptiste Daroussin * 6*61d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 7*61d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 8*61d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 9*61d06d6bSBaptiste Daroussin * 10*61d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*61d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*61d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*61d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*61d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*61d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*61d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*61d06d6bSBaptiste Daroussin */ 18*61d06d6bSBaptiste Daroussin #include "config.h" 19*61d06d6bSBaptiste Daroussin 20*61d06d6bSBaptiste Daroussin #include <sys/types.h> 21*61d06d6bSBaptiste Daroussin 22*61d06d6bSBaptiste Daroussin #include <ctype.h> 23*61d06d6bSBaptiste Daroussin #include <stdio.h> 24*61d06d6bSBaptiste Daroussin #include <stdlib.h> 25*61d06d6bSBaptiste Daroussin #include <string.h> 26*61d06d6bSBaptiste Daroussin 27*61d06d6bSBaptiste Daroussin #include "mandoc.h" 28*61d06d6bSBaptiste Daroussin #include "libmandoc.h" 29*61d06d6bSBaptiste Daroussin #include "libroff.h" 30*61d06d6bSBaptiste Daroussin 31*61d06d6bSBaptiste Daroussin #define KEY_DPOINT 0 32*61d06d6bSBaptiste Daroussin #define KEY_DELIM 1 33*61d06d6bSBaptiste Daroussin #define KEY_LINESIZE 2 34*61d06d6bSBaptiste Daroussin #define KEY_TAB 3 35*61d06d6bSBaptiste Daroussin 36*61d06d6bSBaptiste Daroussin struct tbl_phrase { 37*61d06d6bSBaptiste Daroussin const char *name; 38*61d06d6bSBaptiste Daroussin int key; 39*61d06d6bSBaptiste Daroussin }; 40*61d06d6bSBaptiste Daroussin 41*61d06d6bSBaptiste Daroussin static const struct tbl_phrase keys[] = { 42*61d06d6bSBaptiste Daroussin {"decimalpoint", 0}, 43*61d06d6bSBaptiste Daroussin {"delim", 0}, 44*61d06d6bSBaptiste Daroussin {"linesize", 0}, 45*61d06d6bSBaptiste Daroussin {"tab", 0}, 46*61d06d6bSBaptiste Daroussin {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX}, 47*61d06d6bSBaptiste Daroussin {"box", TBL_OPT_BOX}, 48*61d06d6bSBaptiste Daroussin {"frame", TBL_OPT_BOX}, 49*61d06d6bSBaptiste Daroussin {"center", TBL_OPT_CENTRE}, 50*61d06d6bSBaptiste Daroussin {"centre", TBL_OPT_CENTRE}, 51*61d06d6bSBaptiste Daroussin {"doublebox", TBL_OPT_DBOX}, 52*61d06d6bSBaptiste Daroussin {"doubleframe", TBL_OPT_DBOX}, 53*61d06d6bSBaptiste Daroussin {"expand", TBL_OPT_EXPAND}, 54*61d06d6bSBaptiste Daroussin {"nokeep", TBL_OPT_NOKEEP}, 55*61d06d6bSBaptiste Daroussin {"nospaces", TBL_OPT_NOSPACE}, 56*61d06d6bSBaptiste Daroussin {"nowarn", TBL_OPT_NOWARN}, 57*61d06d6bSBaptiste Daroussin }; 58*61d06d6bSBaptiste Daroussin 59*61d06d6bSBaptiste Daroussin #define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0]))) 60*61d06d6bSBaptiste Daroussin 61*61d06d6bSBaptiste Daroussin static void arg(struct tbl_node *, int, const char *, int *, int); 62*61d06d6bSBaptiste Daroussin 63*61d06d6bSBaptiste Daroussin 64*61d06d6bSBaptiste Daroussin static void 65*61d06d6bSBaptiste Daroussin arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) 66*61d06d6bSBaptiste Daroussin { 67*61d06d6bSBaptiste Daroussin int len, want; 68*61d06d6bSBaptiste Daroussin 69*61d06d6bSBaptiste Daroussin while (p[*pos] == ' ' || p[*pos] == '\t') 70*61d06d6bSBaptiste Daroussin (*pos)++; 71*61d06d6bSBaptiste Daroussin 72*61d06d6bSBaptiste Daroussin /* Arguments are enclosed in parentheses. */ 73*61d06d6bSBaptiste Daroussin 74*61d06d6bSBaptiste Daroussin len = 0; 75*61d06d6bSBaptiste Daroussin if (p[*pos] == '(') { 76*61d06d6bSBaptiste Daroussin (*pos)++; 77*61d06d6bSBaptiste Daroussin while (p[*pos + len] != ')') 78*61d06d6bSBaptiste Daroussin len++; 79*61d06d6bSBaptiste Daroussin } 80*61d06d6bSBaptiste Daroussin 81*61d06d6bSBaptiste Daroussin switch (key) { 82*61d06d6bSBaptiste Daroussin case KEY_DELIM: 83*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse, 84*61d06d6bSBaptiste Daroussin ln, *pos, "%.*s", len, p + *pos); 85*61d06d6bSBaptiste Daroussin want = 2; 86*61d06d6bSBaptiste Daroussin break; 87*61d06d6bSBaptiste Daroussin case KEY_TAB: 88*61d06d6bSBaptiste Daroussin want = 1; 89*61d06d6bSBaptiste Daroussin if (len == want) 90*61d06d6bSBaptiste Daroussin tbl->opts.tab = p[*pos]; 91*61d06d6bSBaptiste Daroussin break; 92*61d06d6bSBaptiste Daroussin case KEY_LINESIZE: 93*61d06d6bSBaptiste Daroussin want = 0; 94*61d06d6bSBaptiste Daroussin break; 95*61d06d6bSBaptiste Daroussin case KEY_DPOINT: 96*61d06d6bSBaptiste Daroussin want = 1; 97*61d06d6bSBaptiste Daroussin if (len == want) 98*61d06d6bSBaptiste Daroussin tbl->opts.decimal = p[*pos]; 99*61d06d6bSBaptiste Daroussin break; 100*61d06d6bSBaptiste Daroussin default: 101*61d06d6bSBaptiste Daroussin abort(); 102*61d06d6bSBaptiste Daroussin } 103*61d06d6bSBaptiste Daroussin 104*61d06d6bSBaptiste Daroussin if (len == 0) 105*61d06d6bSBaptiste Daroussin mandoc_msg(MANDOCERR_TBLOPT_NOARG, 106*61d06d6bSBaptiste Daroussin tbl->parse, ln, *pos, keys[key].name); 107*61d06d6bSBaptiste Daroussin else if (want && len != want) 108*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ, 109*61d06d6bSBaptiste Daroussin tbl->parse, ln, *pos, "%s want %d have %d", 110*61d06d6bSBaptiste Daroussin keys[key].name, want, len); 111*61d06d6bSBaptiste Daroussin 112*61d06d6bSBaptiste Daroussin *pos += len; 113*61d06d6bSBaptiste Daroussin if (p[*pos] == ')') 114*61d06d6bSBaptiste Daroussin (*pos)++; 115*61d06d6bSBaptiste Daroussin } 116*61d06d6bSBaptiste Daroussin 117*61d06d6bSBaptiste Daroussin /* 118*61d06d6bSBaptiste Daroussin * Parse one line of options up to the semicolon. 119*61d06d6bSBaptiste Daroussin * Each option can be preceded by blanks and/or commas, 120*61d06d6bSBaptiste Daroussin * and some options are followed by arguments. 121*61d06d6bSBaptiste Daroussin */ 122*61d06d6bSBaptiste Daroussin void 123*61d06d6bSBaptiste Daroussin tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs) 124*61d06d6bSBaptiste Daroussin { 125*61d06d6bSBaptiste Daroussin int i, pos, len; 126*61d06d6bSBaptiste Daroussin 127*61d06d6bSBaptiste Daroussin pos = *offs; 128*61d06d6bSBaptiste Daroussin for (;;) { 129*61d06d6bSBaptiste Daroussin while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',') 130*61d06d6bSBaptiste Daroussin pos++; 131*61d06d6bSBaptiste Daroussin 132*61d06d6bSBaptiste Daroussin if (p[pos] == ';') { 133*61d06d6bSBaptiste Daroussin *offs = pos + 1; 134*61d06d6bSBaptiste Daroussin return; 135*61d06d6bSBaptiste Daroussin } 136*61d06d6bSBaptiste Daroussin 137*61d06d6bSBaptiste Daroussin /* Parse one option name. */ 138*61d06d6bSBaptiste Daroussin 139*61d06d6bSBaptiste Daroussin len = 0; 140*61d06d6bSBaptiste Daroussin while (isalpha((unsigned char)p[pos + len])) 141*61d06d6bSBaptiste Daroussin len++; 142*61d06d6bSBaptiste Daroussin 143*61d06d6bSBaptiste Daroussin if (len == 0) { 144*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA, 145*61d06d6bSBaptiste Daroussin tbl->parse, ln, pos, "%c", p[pos]); 146*61d06d6bSBaptiste Daroussin pos++; 147*61d06d6bSBaptiste Daroussin continue; 148*61d06d6bSBaptiste Daroussin } 149*61d06d6bSBaptiste Daroussin 150*61d06d6bSBaptiste Daroussin /* Look up the option name. */ 151*61d06d6bSBaptiste Daroussin 152*61d06d6bSBaptiste Daroussin i = 0; 153*61d06d6bSBaptiste Daroussin while (i < KEY_MAXKEYS && 154*61d06d6bSBaptiste Daroussin (strncasecmp(p + pos, keys[i].name, len) || 155*61d06d6bSBaptiste Daroussin keys[i].name[len] != '\0')) 156*61d06d6bSBaptiste Daroussin i++; 157*61d06d6bSBaptiste Daroussin 158*61d06d6bSBaptiste Daroussin if (i == KEY_MAXKEYS) { 159*61d06d6bSBaptiste Daroussin mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse, 160*61d06d6bSBaptiste Daroussin ln, pos, "%.*s", len, p + pos); 161*61d06d6bSBaptiste Daroussin pos += len; 162*61d06d6bSBaptiste Daroussin continue; 163*61d06d6bSBaptiste Daroussin } 164*61d06d6bSBaptiste Daroussin 165*61d06d6bSBaptiste Daroussin /* Handle the option. */ 166*61d06d6bSBaptiste Daroussin 167*61d06d6bSBaptiste Daroussin pos += len; 168*61d06d6bSBaptiste Daroussin if (keys[i].key) 169*61d06d6bSBaptiste Daroussin tbl->opts.opts |= keys[i].key; 170*61d06d6bSBaptiste Daroussin else 171*61d06d6bSBaptiste Daroussin arg(tbl, ln, p, &pos, i); 172*61d06d6bSBaptiste Daroussin } 173*61d06d6bSBaptiste Daroussin } 174