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