xref: /openbsd-src/usr.bin/mandoc/tbl_opts.c (revision a5a5f808f883658dd10516c3af6729f214a59191)
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