1*a5a5f808Sschwarze /* $OpenBSD: tbl_opts.c,v 1.16 2018/12/14 05:17:45 schwarze Exp $ */
22791bd1cSschwarze /*
3ec04407bSschwarze * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4bdf8ed0fSschwarze * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
52791bd1cSschwarze *
62791bd1cSschwarze * Permission to use, copy, modify, and distribute this software for any
72791bd1cSschwarze * purpose with or without fee is hereby granted, provided that the above
82791bd1cSschwarze * copyright notice and this permission notice appear in all copies.
92791bd1cSschwarze *
102791bd1cSschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112791bd1cSschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122791bd1cSschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132791bd1cSschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142791bd1cSschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152791bd1cSschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162791bd1cSschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172791bd1cSschwarze */
1830997c59Sschwarze #include <sys/types.h>
1930997c59Sschwarze
202791bd1cSschwarze #include <ctype.h>
212791bd1cSschwarze #include <stdio.h>
222791bd1cSschwarze #include <stdlib.h>
232791bd1cSschwarze #include <string.h>
242791bd1cSschwarze
252791bd1cSschwarze #include "mandoc.h"
26fae2491eSschwarze #include "tbl.h"
27a35fc07aSschwarze #include "libmandoc.h"
28fb382a01Sschwarze #include "tbl_int.h"
292791bd1cSschwarze
3008d5d28eSschwarze #define KEY_DPOINT 0
3108d5d28eSschwarze #define KEY_DELIM 1
3208d5d28eSschwarze #define KEY_LINESIZE 2
3308d5d28eSschwarze #define KEY_TAB 3
342791bd1cSschwarze
352791bd1cSschwarze struct tbl_phrase {
362791bd1cSschwarze const char *name;
372791bd1cSschwarze int key;
382791bd1cSschwarze };
392791bd1cSschwarze
4008d5d28eSschwarze static const struct tbl_phrase keys[] = {
4108d5d28eSschwarze {"decimalpoint", 0},
4208d5d28eSschwarze {"delim", 0},
4308d5d28eSschwarze {"linesize", 0},
4408d5d28eSschwarze {"tab", 0},
4508d5d28eSschwarze {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX},
4608d5d28eSschwarze {"box", TBL_OPT_BOX},
4708d5d28eSschwarze {"frame", TBL_OPT_BOX},
4808d5d28eSschwarze {"center", TBL_OPT_CENTRE},
4908d5d28eSschwarze {"centre", TBL_OPT_CENTRE},
5008d5d28eSschwarze {"doublebox", TBL_OPT_DBOX},
5108d5d28eSschwarze {"doubleframe", TBL_OPT_DBOX},
5208d5d28eSschwarze {"expand", TBL_OPT_EXPAND},
5308d5d28eSschwarze {"nokeep", TBL_OPT_NOKEEP},
5408d5d28eSschwarze {"nospaces", TBL_OPT_NOSPACE},
5508d5d28eSschwarze {"nowarn", TBL_OPT_NOWARN},
562791bd1cSschwarze };
572791bd1cSschwarze
5808d5d28eSschwarze #define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0])))
5908d5d28eSschwarze
6008d5d28eSschwarze static void arg(struct tbl_node *, int, const char *, int *, int);
612791bd1cSschwarze
6249aff9f8Sschwarze
63bdf8ed0fSschwarze static void
arg(struct tbl_node * tbl,int ln,const char * p,int * pos,int key)6408d5d28eSschwarze arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
652791bd1cSschwarze {
66bdf8ed0fSschwarze int len, want;
672791bd1cSschwarze
6808d5d28eSschwarze while (p[*pos] == ' ' || p[*pos] == '\t')
692791bd1cSschwarze (*pos)++;
702791bd1cSschwarze
71bdf8ed0fSschwarze /* Arguments are enclosed in parentheses. */
722791bd1cSschwarze
73bdf8ed0fSschwarze len = 0;
74bdf8ed0fSschwarze if (p[*pos] == '(') {
752791bd1cSschwarze (*pos)++;
76bdf8ed0fSschwarze while (p[*pos + len] != ')')
77bdf8ed0fSschwarze len++;
78bdf8ed0fSschwarze }
792791bd1cSschwarze
802791bd1cSschwarze switch (key) {
8149aff9f8Sschwarze case KEY_DELIM:
82*a5a5f808Sschwarze mandoc_msg(MANDOCERR_TBLOPT_EQN,
8392ff8da6Sschwarze ln, *pos, "%.*s", len, p + *pos);
84bdf8ed0fSschwarze want = 2;
852791bd1cSschwarze break;
8649aff9f8Sschwarze case KEY_TAB:
87bdf8ed0fSschwarze want = 1;
88bdf8ed0fSschwarze if (len == want)
89bdf8ed0fSschwarze tbl->opts.tab = p[*pos];
902791bd1cSschwarze break;
9149aff9f8Sschwarze case KEY_LINESIZE:
92bdf8ed0fSschwarze want = 0;
932791bd1cSschwarze break;
9449aff9f8Sschwarze case KEY_DPOINT:
95bdf8ed0fSschwarze want = 1;
96bdf8ed0fSschwarze if (len == want)
97bdf8ed0fSschwarze tbl->opts.decimal = p[*pos];
982791bd1cSschwarze break;
992791bd1cSschwarze default:
1002791bd1cSschwarze abort();
1012791bd1cSschwarze }
1022791bd1cSschwarze
103bdf8ed0fSschwarze if (len == 0)
104*a5a5f808Sschwarze mandoc_msg(MANDOCERR_TBLOPT_NOARG, ln, *pos,
105*a5a5f808Sschwarze "%s", keys[key].name);
106bdf8ed0fSschwarze else if (want && len != want)
107*a5a5f808Sschwarze mandoc_msg(MANDOCERR_TBLOPT_ARGSZ, ln, *pos,
108*a5a5f808Sschwarze "%s want %d have %d", keys[key].name, want, len);
1092791bd1cSschwarze
110bdf8ed0fSschwarze *pos += len;
111bdf8ed0fSschwarze if (p[*pos] == ')')
1122791bd1cSschwarze (*pos)++;
1132791bd1cSschwarze }
1142791bd1cSschwarze
1152791bd1cSschwarze /*
116bdf8ed0fSschwarze * Parse one line of options up to the semicolon.
117bdf8ed0fSschwarze * Each option can be preceded by blanks and/or commas,
118bdf8ed0fSschwarze * and some options are followed by arguments.
1192791bd1cSschwarze */
120dca985f9Sschwarze void
tbl_option(struct tbl_node * tbl,int ln,const char * p,int * offs)12139aede77Sschwarze tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
1222791bd1cSschwarze {
123bdf8ed0fSschwarze int i, pos, len;
1242791bd1cSschwarze
12539aede77Sschwarze pos = *offs;
126bdf8ed0fSschwarze for (;;) {
12708d5d28eSschwarze while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',')
128bdf8ed0fSschwarze pos++;
129bdf8ed0fSschwarze
13039aede77Sschwarze if (p[pos] == ';') {
13139aede77Sschwarze *offs = pos + 1;
132bdf8ed0fSschwarze return;
13339aede77Sschwarze }
134bdf8ed0fSschwarze
135bdf8ed0fSschwarze /* Parse one option name. */
136bdf8ed0fSschwarze
137bdf8ed0fSschwarze len = 0;
138bdf8ed0fSschwarze while (isalpha((unsigned char)p[pos + len]))
139bdf8ed0fSschwarze len++;
140bdf8ed0fSschwarze
141bdf8ed0fSschwarze if (len == 0) {
142*a5a5f808Sschwarze mandoc_msg(MANDOCERR_TBLOPT_ALPHA,
143*a5a5f808Sschwarze ln, pos, "%c", p[pos]);
144bdf8ed0fSschwarze pos++;
145bdf8ed0fSschwarze continue;
146bdf8ed0fSschwarze }
147bdf8ed0fSschwarze
148bdf8ed0fSschwarze /* Look up the option name. */
149bdf8ed0fSschwarze
150bdf8ed0fSschwarze i = 0;
151bdf8ed0fSschwarze while (i < KEY_MAXKEYS &&
152bdf8ed0fSschwarze (strncasecmp(p + pos, keys[i].name, len) ||
153bdf8ed0fSschwarze keys[i].name[len] != '\0'))
154bdf8ed0fSschwarze i++;
155bdf8ed0fSschwarze
156bdf8ed0fSschwarze if (i == KEY_MAXKEYS) {
157*a5a5f808Sschwarze mandoc_msg(MANDOCERR_TBLOPT_BAD,
158bdf8ed0fSschwarze ln, pos, "%.*s", len, p + pos);
159bdf8ed0fSschwarze pos += len;
160bdf8ed0fSschwarze continue;
161bdf8ed0fSschwarze }
162bdf8ed0fSschwarze
163bdf8ed0fSschwarze /* Handle the option. */
164bdf8ed0fSschwarze
165bdf8ed0fSschwarze pos += len;
166bdf8ed0fSschwarze if (keys[i].key)
167bdf8ed0fSschwarze tbl->opts.opts |= keys[i].key;
168bdf8ed0fSschwarze else
16908d5d28eSschwarze arg(tbl, ln, p, &pos, i);
170bdf8ed0fSschwarze }
1712791bd1cSschwarze }
172