xref: /freebsd/contrib/mandoc/manpath.c (revision c1c95add8c80843ba15d784f95c361d795b1f593)
1*c1c95addSBrooks Davis /*	$Id: manpath.c,v 1.44 2021/11/05 18:03:08 schwarze Exp $ */
261d06d6bSBaptiste Daroussin /*
345a5aec3SBaptiste Daroussin  * Copyright (c) 2011,2014,2015,2017-2019 Ingo Schwarze <schwarze@openbsd.org>
461d06d6bSBaptiste Daroussin  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
561d06d6bSBaptiste Daroussin  *
661d06d6bSBaptiste Daroussin  * Permission to use, copy, modify, and distribute this software for any
761d06d6bSBaptiste Daroussin  * purpose with or without fee is hereby granted, provided that the above
861d06d6bSBaptiste Daroussin  * copyright notice and this permission notice appear in all copies.
961d06d6bSBaptiste Daroussin  *
1061d06d6bSBaptiste Daroussin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1161d06d6bSBaptiste Daroussin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1261d06d6bSBaptiste Daroussin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1361d06d6bSBaptiste Daroussin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1461d06d6bSBaptiste Daroussin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1561d06d6bSBaptiste Daroussin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1661d06d6bSBaptiste Daroussin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1761d06d6bSBaptiste Daroussin  */
1861d06d6bSBaptiste Daroussin #include "config.h"
1961d06d6bSBaptiste Daroussin 
2061d06d6bSBaptiste Daroussin #include <sys/types.h>
2161d06d6bSBaptiste Daroussin #include <sys/stat.h>
2261d06d6bSBaptiste Daroussin 
2361d06d6bSBaptiste Daroussin #include <ctype.h>
2445a5aec3SBaptiste Daroussin #include <errno.h>
2561d06d6bSBaptiste Daroussin #include <limits.h>
2661d06d6bSBaptiste Daroussin #include <stdio.h>
2761d06d6bSBaptiste Daroussin #include <stdlib.h>
2861d06d6bSBaptiste Daroussin #include <string.h>
2961d06d6bSBaptiste Daroussin 
3061d06d6bSBaptiste Daroussin #include "mandoc_aux.h"
3145a5aec3SBaptiste Daroussin #include "mandoc.h"
3261d06d6bSBaptiste Daroussin #include "manconf.h"
3361d06d6bSBaptiste Daroussin 
34*c1c95addSBrooks Davis static	void	 manconf_file(struct manconf *, const char *, int);
3545a5aec3SBaptiste Daroussin static	void	 manpath_add(struct manpaths *, const char *, char);
3645a5aec3SBaptiste Daroussin static	void	 manpath_parseline(struct manpaths *, char *, char);
3761d06d6bSBaptiste Daroussin 
3861d06d6bSBaptiste Daroussin 
3961d06d6bSBaptiste Daroussin void
manconf_parse(struct manconf * conf,const char * file,char * pend,char * pbeg)40*c1c95addSBrooks Davis manconf_parse(struct manconf *conf, const char *file, char *pend, char *pbeg)
4161d06d6bSBaptiste Daroussin {
42*c1c95addSBrooks Davis 	int use_path_from_file = 1;
4361d06d6bSBaptiste Daroussin 
4461d06d6bSBaptiste Daroussin 	/* Always prepend -m. */
45*c1c95addSBrooks Davis 	manpath_parseline(&conf->manpath, pbeg, 'm');
4661d06d6bSBaptiste Daroussin 
47*c1c95addSBrooks Davis 	if (pend != NULL && *pend != '\0') {
4861d06d6bSBaptiste Daroussin 		/* If -M is given, it overrides everything else. */
49*c1c95addSBrooks Davis 		manpath_parseline(&conf->manpath, pend, 'M');
50*c1c95addSBrooks Davis 		use_path_from_file = 0;
51*c1c95addSBrooks Davis 		pbeg = pend = NULL;
52*c1c95addSBrooks Davis 	} else if ((pbeg = getenv("MANPATH")) == NULL || *pbeg == '\0') {
5361d06d6bSBaptiste Daroussin 		/* No MANPATH; use man.conf(5) only. */
54*c1c95addSBrooks Davis 		pbeg = pend = NULL;
55*c1c95addSBrooks Davis 	} else if (*pbeg == ':') {
5661d06d6bSBaptiste Daroussin 		/* Prepend man.conf(5) to MANPATH. */
57*c1c95addSBrooks Davis 		pend = pbeg + 1;
58*c1c95addSBrooks Davis 		pbeg = NULL;
59*c1c95addSBrooks Davis 	} else if ((pend = strstr(pbeg, "::")) != NULL) {
6061d06d6bSBaptiste Daroussin 		/* Insert man.conf(5) into MANPATH. */
61*c1c95addSBrooks Davis 		*pend = '\0';
62*c1c95addSBrooks Davis 		pend += 2;
63*c1c95addSBrooks Davis 	} else if (pbeg[strlen(pbeg) - 1] == ':') {
64*c1c95addSBrooks Davis 		/* Append man.conf(5) to MANPATH. */
65*c1c95addSBrooks Davis 		pend = NULL;
66*c1c95addSBrooks Davis 	} else {
67*c1c95addSBrooks Davis 		/* MANPATH overrides man.conf(5) completely. */
68*c1c95addSBrooks Davis 		use_path_from_file = 0;
69*c1c95addSBrooks Davis 		pend = NULL;
7061d06d6bSBaptiste Daroussin 	}
7161d06d6bSBaptiste Daroussin 
72*c1c95addSBrooks Davis 	manpath_parseline(&conf->manpath, pbeg, '\0');
73*c1c95addSBrooks Davis 
74*c1c95addSBrooks Davis 	if (file == NULL)
75*c1c95addSBrooks Davis 		file = MAN_CONF_FILE;
76*c1c95addSBrooks Davis 	manconf_file(conf, file, use_path_from_file);
77*c1c95addSBrooks Davis 
78*c1c95addSBrooks Davis 	manpath_parseline(&conf->manpath, pend, '\0');
7961d06d6bSBaptiste Daroussin }
8061d06d6bSBaptiste Daroussin 
8161d06d6bSBaptiste Daroussin void
manpath_base(struct manpaths * dirs)8261d06d6bSBaptiste Daroussin manpath_base(struct manpaths *dirs)
8361d06d6bSBaptiste Daroussin {
8461d06d6bSBaptiste Daroussin 	char path_base[] = MANPATH_BASE;
8545a5aec3SBaptiste Daroussin 	manpath_parseline(dirs, path_base, '\0');
8661d06d6bSBaptiste Daroussin }
8761d06d6bSBaptiste Daroussin 
8861d06d6bSBaptiste Daroussin /*
8961d06d6bSBaptiste Daroussin  * Parse a FULL pathname from a colon-separated list of arrays.
9061d06d6bSBaptiste Daroussin  */
9161d06d6bSBaptiste Daroussin static void
manpath_parseline(struct manpaths * dirs,char * path,char option)9245a5aec3SBaptiste Daroussin manpath_parseline(struct manpaths *dirs, char *path, char option)
9361d06d6bSBaptiste Daroussin {
9461d06d6bSBaptiste Daroussin 	char	*dir;
9561d06d6bSBaptiste Daroussin 
9661d06d6bSBaptiste Daroussin 	if (NULL == path)
9761d06d6bSBaptiste Daroussin 		return;
9861d06d6bSBaptiste Daroussin 
9961d06d6bSBaptiste Daroussin 	for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
10045a5aec3SBaptiste Daroussin 		manpath_add(dirs, dir, option);
10161d06d6bSBaptiste Daroussin }
10261d06d6bSBaptiste Daroussin 
10361d06d6bSBaptiste Daroussin /*
10461d06d6bSBaptiste Daroussin  * Add a directory to the array, ignoring bad directories.
10561d06d6bSBaptiste Daroussin  * Grow the array one-by-one for simplicity's sake.
10661d06d6bSBaptiste Daroussin  */
10761d06d6bSBaptiste Daroussin static void
manpath_add(struct manpaths * dirs,const char * dir,char option)10845a5aec3SBaptiste Daroussin manpath_add(struct manpaths *dirs, const char *dir, char option)
10961d06d6bSBaptiste Daroussin {
11061d06d6bSBaptiste Daroussin 	char		 buf[PATH_MAX];
11161d06d6bSBaptiste Daroussin 	struct stat	 sb;
11261d06d6bSBaptiste Daroussin 	char		*cp;
11361d06d6bSBaptiste Daroussin 	size_t		 i;
11461d06d6bSBaptiste Daroussin 
11545a5aec3SBaptiste Daroussin 	if ((cp = realpath(dir, buf)) == NULL)
11645a5aec3SBaptiste Daroussin 		goto fail;
11761d06d6bSBaptiste Daroussin 
11861d06d6bSBaptiste Daroussin 	for (i = 0; i < dirs->sz; i++)
11945a5aec3SBaptiste Daroussin 		if (strcmp(dirs->paths[i], dir) == 0)
12061d06d6bSBaptiste Daroussin 			return;
12161d06d6bSBaptiste Daroussin 
12245a5aec3SBaptiste Daroussin 	if (stat(cp, &sb) == -1)
12345a5aec3SBaptiste Daroussin 		goto fail;
12461d06d6bSBaptiste Daroussin 
12561d06d6bSBaptiste Daroussin 	dirs->paths = mandoc_reallocarray(dirs->paths,
12645a5aec3SBaptiste Daroussin 	    dirs->sz + 1, sizeof(*dirs->paths));
12761d06d6bSBaptiste Daroussin 	dirs->paths[dirs->sz++] = mandoc_strdup(cp);
12845a5aec3SBaptiste Daroussin 	return;
12945a5aec3SBaptiste Daroussin 
13045a5aec3SBaptiste Daroussin fail:
13145a5aec3SBaptiste Daroussin 	if (option != '\0')
13245a5aec3SBaptiste Daroussin 		mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0,
13345a5aec3SBaptiste Daroussin 		    "-%c %s: %s", option, dir, strerror(errno));
13461d06d6bSBaptiste Daroussin }
13561d06d6bSBaptiste Daroussin 
13661d06d6bSBaptiste Daroussin void
manconf_free(struct manconf * conf)13761d06d6bSBaptiste Daroussin manconf_free(struct manconf *conf)
13861d06d6bSBaptiste Daroussin {
13961d06d6bSBaptiste Daroussin 	size_t		 i;
14061d06d6bSBaptiste Daroussin 
14161d06d6bSBaptiste Daroussin 	for (i = 0; i < conf->manpath.sz; i++)
14261d06d6bSBaptiste Daroussin 		free(conf->manpath.paths[i]);
14361d06d6bSBaptiste Daroussin 
14461d06d6bSBaptiste Daroussin 	free(conf->manpath.paths);
14561d06d6bSBaptiste Daroussin 	free(conf->output.includes);
14661d06d6bSBaptiste Daroussin 	free(conf->output.man);
14761d06d6bSBaptiste Daroussin 	free(conf->output.paper);
14861d06d6bSBaptiste Daroussin 	free(conf->output.style);
14961d06d6bSBaptiste Daroussin }
15061d06d6bSBaptiste Daroussin 
15161d06d6bSBaptiste Daroussin static void
manconf_file(struct manconf * conf,const char * file,int use_path_from_file)152*c1c95addSBrooks Davis manconf_file(struct manconf *conf, const char *file, int use_path_from_file)
15361d06d6bSBaptiste Daroussin {
1546d38604fSBaptiste Daroussin 	const char *const toks[] = { "manpath", "output" };
15561d06d6bSBaptiste Daroussin 	char manpath_default[] = MANPATH_DEFAULT;
15661d06d6bSBaptiste Daroussin 
15761d06d6bSBaptiste Daroussin 	FILE		*stream;
15861d06d6bSBaptiste Daroussin 	char		*line, *cp, *ep;
15961d06d6bSBaptiste Daroussin 	size_t		 linesz, tok, toklen;
16061d06d6bSBaptiste Daroussin 	ssize_t		 linelen;
16161d06d6bSBaptiste Daroussin 
16261d06d6bSBaptiste Daroussin 	if ((stream = fopen(file, "r")) == NULL)
16361d06d6bSBaptiste Daroussin 		goto out;
16461d06d6bSBaptiste Daroussin 
16561d06d6bSBaptiste Daroussin 	line = NULL;
16661d06d6bSBaptiste Daroussin 	linesz = 0;
16761d06d6bSBaptiste Daroussin 
16861d06d6bSBaptiste Daroussin 	while ((linelen = getline(&line, &linesz, stream)) != -1) {
16961d06d6bSBaptiste Daroussin 		cp = line;
17061d06d6bSBaptiste Daroussin 		ep = cp + linelen - 1;
17161d06d6bSBaptiste Daroussin 		while (ep > cp && isspace((unsigned char)*ep))
17261d06d6bSBaptiste Daroussin 			*ep-- = '\0';
17361d06d6bSBaptiste Daroussin 		while (isspace((unsigned char)*cp))
17461d06d6bSBaptiste Daroussin 			cp++;
17561d06d6bSBaptiste Daroussin 		if (cp == ep || *cp == '#')
17661d06d6bSBaptiste Daroussin 			continue;
17761d06d6bSBaptiste Daroussin 
17861d06d6bSBaptiste Daroussin 		for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
17961d06d6bSBaptiste Daroussin 			toklen = strlen(toks[tok]);
18061d06d6bSBaptiste Daroussin 			if (cp + toklen < ep &&
18161d06d6bSBaptiste Daroussin 			    isspace((unsigned char)cp[toklen]) &&
18261d06d6bSBaptiste Daroussin 			    strncmp(cp, toks[tok], toklen) == 0) {
18361d06d6bSBaptiste Daroussin 				cp += toklen;
18461d06d6bSBaptiste Daroussin 				while (isspace((unsigned char)*cp))
18561d06d6bSBaptiste Daroussin 					cp++;
18661d06d6bSBaptiste Daroussin 				break;
18761d06d6bSBaptiste Daroussin 			}
18861d06d6bSBaptiste Daroussin 		}
18961d06d6bSBaptiste Daroussin 
19061d06d6bSBaptiste Daroussin 		switch (tok) {
19161d06d6bSBaptiste Daroussin 		case 0:  /* manpath */
192*c1c95addSBrooks Davis 			if (use_path_from_file)
19345a5aec3SBaptiste Daroussin 				manpath_add(&conf->manpath, cp, '\0');
19461d06d6bSBaptiste Daroussin 			*manpath_default = '\0';
19561d06d6bSBaptiste Daroussin 			break;
19661d06d6bSBaptiste Daroussin 		case 1:  /* output */
19761d06d6bSBaptiste Daroussin 			manconf_output(&conf->output, cp, 1);
19861d06d6bSBaptiste Daroussin 			break;
19961d06d6bSBaptiste Daroussin 		default:
20061d06d6bSBaptiste Daroussin 			break;
20161d06d6bSBaptiste Daroussin 		}
20261d06d6bSBaptiste Daroussin 	}
20361d06d6bSBaptiste Daroussin 	free(line);
20461d06d6bSBaptiste Daroussin 	fclose(stream);
20561d06d6bSBaptiste Daroussin 
20661d06d6bSBaptiste Daroussin out:
207*c1c95addSBrooks Davis 	if (use_path_from_file && *manpath_default != '\0')
20845a5aec3SBaptiste Daroussin 		manpath_parseline(&conf->manpath, manpath_default, '\0');
20961d06d6bSBaptiste Daroussin }
21061d06d6bSBaptiste Daroussin 
21161d06d6bSBaptiste Daroussin int
manconf_output(struct manoutput * conf,const char * cp,int fromfile)21261d06d6bSBaptiste Daroussin manconf_output(struct manoutput *conf, const char *cp, int fromfile)
21361d06d6bSBaptiste Daroussin {
21461d06d6bSBaptiste Daroussin 	const char *const toks[] = {
2156d38604fSBaptiste Daroussin 	    /* Tokens requiring an argument. */
2167295610fSBaptiste Daroussin 	    "includes", "man", "paper", "style", "indent", "width",
2176d38604fSBaptiste Daroussin 	    "outfilename", "tagfilename",
2186d38604fSBaptiste Daroussin 	    /* Token taking an optional argument. */
2196d38604fSBaptiste Daroussin 	    "tag",
2206d38604fSBaptiste Daroussin 	    /* Tokens not taking arguments. */
2216d38604fSBaptiste Daroussin 	    "fragment", "mdoc", "noval", "toc"
22261d06d6bSBaptiste Daroussin 	};
22345a5aec3SBaptiste Daroussin 	const size_t ntoks = sizeof(toks) / sizeof(toks[0]);
22461d06d6bSBaptiste Daroussin 
22561d06d6bSBaptiste Daroussin 	const char	*errstr;
22661d06d6bSBaptiste Daroussin 	char		*oldval;
22761d06d6bSBaptiste Daroussin 	size_t		 len, tok;
22861d06d6bSBaptiste Daroussin 
22945a5aec3SBaptiste Daroussin 	for (tok = 0; tok < ntoks; tok++) {
23061d06d6bSBaptiste Daroussin 		len = strlen(toks[tok]);
23145a5aec3SBaptiste Daroussin 		if (strncmp(cp, toks[tok], len) == 0 &&
23261d06d6bSBaptiste Daroussin 		    strchr(" =	", cp[len]) != NULL) {
23361d06d6bSBaptiste Daroussin 			cp += len;
23461d06d6bSBaptiste Daroussin 			if (*cp == '=')
23561d06d6bSBaptiste Daroussin 				cp++;
23661d06d6bSBaptiste Daroussin 			while (isspace((unsigned char)*cp))
23761d06d6bSBaptiste Daroussin 				cp++;
23861d06d6bSBaptiste Daroussin 			break;
23961d06d6bSBaptiste Daroussin 		}
24061d06d6bSBaptiste Daroussin 	}
24161d06d6bSBaptiste Daroussin 
2426d38604fSBaptiste Daroussin 	if (tok < 8 && *cp == '\0') {
24345a5aec3SBaptiste Daroussin 		mandoc_msg(MANDOCERR_BADVAL_MISS, 0, 0, "-O %s=?", toks[tok]);
24461d06d6bSBaptiste Daroussin 		return -1;
24561d06d6bSBaptiste Daroussin 	}
2466d38604fSBaptiste Daroussin 	if (tok > 8 && tok < ntoks && *cp != '\0') {
24745a5aec3SBaptiste Daroussin 		mandoc_msg(MANDOCERR_BADVAL, 0, 0, "-O %s=%s", toks[tok], cp);
24861d06d6bSBaptiste Daroussin 		return -1;
24961d06d6bSBaptiste Daroussin 	}
25061d06d6bSBaptiste Daroussin 
25161d06d6bSBaptiste Daroussin 	switch (tok) {
25261d06d6bSBaptiste Daroussin 	case 0:
25361d06d6bSBaptiste Daroussin 		if (conf->includes != NULL) {
25461d06d6bSBaptiste Daroussin 			oldval = mandoc_strdup(conf->includes);
25561d06d6bSBaptiste Daroussin 			break;
25661d06d6bSBaptiste Daroussin 		}
25761d06d6bSBaptiste Daroussin 		conf->includes = mandoc_strdup(cp);
25861d06d6bSBaptiste Daroussin 		return 0;
25961d06d6bSBaptiste Daroussin 	case 1:
26061d06d6bSBaptiste Daroussin 		if (conf->man != NULL) {
26161d06d6bSBaptiste Daroussin 			oldval = mandoc_strdup(conf->man);
26261d06d6bSBaptiste Daroussin 			break;
26361d06d6bSBaptiste Daroussin 		}
26461d06d6bSBaptiste Daroussin 		conf->man = mandoc_strdup(cp);
26561d06d6bSBaptiste Daroussin 		return 0;
26661d06d6bSBaptiste Daroussin 	case 2:
26761d06d6bSBaptiste Daroussin 		if (conf->paper != NULL) {
26861d06d6bSBaptiste Daroussin 			oldval = mandoc_strdup(conf->paper);
26961d06d6bSBaptiste Daroussin 			break;
27061d06d6bSBaptiste Daroussin 		}
27161d06d6bSBaptiste Daroussin 		conf->paper = mandoc_strdup(cp);
27261d06d6bSBaptiste Daroussin 		return 0;
27361d06d6bSBaptiste Daroussin 	case 3:
27461d06d6bSBaptiste Daroussin 		if (conf->style != NULL) {
27561d06d6bSBaptiste Daroussin 			oldval = mandoc_strdup(conf->style);
27661d06d6bSBaptiste Daroussin 			break;
27761d06d6bSBaptiste Daroussin 		}
27861d06d6bSBaptiste Daroussin 		conf->style = mandoc_strdup(cp);
27961d06d6bSBaptiste Daroussin 		return 0;
28061d06d6bSBaptiste Daroussin 	case 4:
28161d06d6bSBaptiste Daroussin 		if (conf->indent) {
28261d06d6bSBaptiste Daroussin 			mandoc_asprintf(&oldval, "%zu", conf->indent);
28361d06d6bSBaptiste Daroussin 			break;
28461d06d6bSBaptiste Daroussin 		}
28561d06d6bSBaptiste Daroussin 		conf->indent = strtonum(cp, 0, 1000, &errstr);
28661d06d6bSBaptiste Daroussin 		if (errstr == NULL)
28761d06d6bSBaptiste Daroussin 			return 0;
28845a5aec3SBaptiste Daroussin 		mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0,
28945a5aec3SBaptiste Daroussin 		    "-O indent=%s is %s", cp, errstr);
29061d06d6bSBaptiste Daroussin 		return -1;
29161d06d6bSBaptiste Daroussin 	case 5:
29261d06d6bSBaptiste Daroussin 		if (conf->width) {
29361d06d6bSBaptiste Daroussin 			mandoc_asprintf(&oldval, "%zu", conf->width);
29461d06d6bSBaptiste Daroussin 			break;
29561d06d6bSBaptiste Daroussin 		}
29661d06d6bSBaptiste Daroussin 		conf->width = strtonum(cp, 1, 1000, &errstr);
29761d06d6bSBaptiste Daroussin 		if (errstr == NULL)
29861d06d6bSBaptiste Daroussin 			return 0;
29945a5aec3SBaptiste Daroussin 		mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0,
30045a5aec3SBaptiste Daroussin 		    "-O width=%s is %s", cp, errstr);
30161d06d6bSBaptiste Daroussin 		return -1;
30261d06d6bSBaptiste Daroussin 	case 6:
3036d38604fSBaptiste Daroussin 		if (conf->outfilename != NULL) {
3046d38604fSBaptiste Daroussin 			oldval = mandoc_strdup(conf->outfilename);
3056d38604fSBaptiste Daroussin 			break;
3066d38604fSBaptiste Daroussin 		}
3076d38604fSBaptiste Daroussin 		conf->outfilename = mandoc_strdup(cp);
3086d38604fSBaptiste Daroussin 		return 0;
3096d38604fSBaptiste Daroussin 	case 7:
3106d38604fSBaptiste Daroussin 		if (conf->tagfilename != NULL) {
3116d38604fSBaptiste Daroussin 			oldval = mandoc_strdup(conf->tagfilename);
3126d38604fSBaptiste Daroussin 			break;
3136d38604fSBaptiste Daroussin 		}
3146d38604fSBaptiste Daroussin 		conf->tagfilename = mandoc_strdup(cp);
3156d38604fSBaptiste Daroussin 		return 0;
3166d38604fSBaptiste Daroussin 	/*
3176d38604fSBaptiste Daroussin 	 * If the index of the following token changes,
3186d38604fSBaptiste Daroussin 	 * do not forget to adjust the range check above the switch.
3196d38604fSBaptiste Daroussin 	 */
3206d38604fSBaptiste Daroussin 	case 8:
3217295610fSBaptiste Daroussin 		if (conf->tag != NULL) {
3227295610fSBaptiste Daroussin 			oldval = mandoc_strdup(conf->tag);
3237295610fSBaptiste Daroussin 			break;
3247295610fSBaptiste Daroussin 		}
3257295610fSBaptiste Daroussin 		conf->tag = mandoc_strdup(cp);
32661d06d6bSBaptiste Daroussin 		return 0;
3276d38604fSBaptiste Daroussin 	case 9:
3287295610fSBaptiste Daroussin 		conf->fragment = 1;
32961d06d6bSBaptiste Daroussin 		return 0;
3306d38604fSBaptiste Daroussin 	case 10:
3317295610fSBaptiste Daroussin 		conf->mdoc = 1;
3327295610fSBaptiste Daroussin 		return 0;
3336d38604fSBaptiste Daroussin 	case 11:
33461d06d6bSBaptiste Daroussin 		conf->noval = 1;
33561d06d6bSBaptiste Daroussin 		return 0;
3366d38604fSBaptiste Daroussin 	case 12:
3377295610fSBaptiste Daroussin 		conf->toc = 1;
3387295610fSBaptiste Daroussin 		return 0;
33961d06d6bSBaptiste Daroussin 	default:
34045a5aec3SBaptiste Daroussin 		mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, "-O %s", cp);
34161d06d6bSBaptiste Daroussin 		return -1;
34261d06d6bSBaptiste Daroussin 	}
34345a5aec3SBaptiste Daroussin 	if (fromfile) {
34445a5aec3SBaptiste Daroussin 		free(oldval);
34545a5aec3SBaptiste Daroussin 		return 0;
34645a5aec3SBaptiste Daroussin 	} else {
34745a5aec3SBaptiste Daroussin 		mandoc_msg(MANDOCERR_BADVAL_DUPE, 0, 0,
34845a5aec3SBaptiste Daroussin 		    "-O %s=%s: already set to %s", toks[tok], cp, oldval);
34961d06d6bSBaptiste Daroussin 		free(oldval);
35061d06d6bSBaptiste Daroussin 		return -1;
35161d06d6bSBaptiste Daroussin 	}
35245a5aec3SBaptiste Daroussin }
353