[BACK]Return to manpath.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mandoc

Annotation of src/usr.bin/mandoc/manpath.c, Revision 1.31

1.31    ! schwarze    1: /* $OpenBSD: manpath.c,v 1.30 2020/08/27 14:59:42 schwarze Exp $ */
1.1       schwarze    2: /*
1.31    ! schwarze    3:  * Copyright (c) 2011,2014,2015,2017-2021 Ingo Schwarze <schwarze@openbsd.org>
1.1       schwarze    4:  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
1.13      schwarze   10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1.1       schwarze   11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1.13      schwarze   12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1.1       schwarze   13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
1.11      schwarze   18: #include <sys/types.h>
                     19: #include <sys/stat.h>
1.3       schwarze   20:
1.1       schwarze   21: #include <ctype.h>
1.27      schwarze   22: #include <errno.h>
1.1       schwarze   23: #include <limits.h>
                     24: #include <stdio.h>
                     25: #include <stdlib.h>
                     26: #include <string.h>
                     27:
1.8       schwarze   28: #include "mandoc_aux.h"
1.27      schwarze   29: #include "mandoc.h"
1.14      schwarze   30: #include "manconf.h"
1.1       schwarze   31:
                     32: #define MAN_CONF_FILE  "/etc/man.conf"
1.22      schwarze   33: #define MANPATH_BASE   "/usr/share/man:/usr/X11R6/man"
1.12      schwarze   34: #define MANPATH_DEFAULT        "/usr/share/man:/usr/X11R6/man:/usr/local/man"
1.1       schwarze   35:
1.31    ! schwarze   36: static void     manconf_file(struct manconf *, const char *, int);
1.27      schwarze   37: static void     manpath_add(struct manpaths *, const char *, char);
                     38: static void     manpath_parseline(struct manpaths *, char *, char);
1.1       schwarze   39:
1.14      schwarze   40:
1.1       schwarze   41: void
1.31    ! schwarze   42: manconf_parse(struct manconf *conf, const char *file, char *pend, char *pbeg)
1.1       schwarze   43: {
1.31    ! schwarze   44:        int use_path_from_file = 1;
1.1       schwarze   45:
1.4       schwarze   46:        /* Always prepend -m. */
1.31    ! schwarze   47:        manpath_parseline(&conf->manpath, pbeg, 'm');
1.1       schwarze   48:
1.31    ! schwarze   49:        if (pend != NULL && *pend != '\0') {
        !            50:                /* If -M is given, it overrides everything else. */
        !            51:                manpath_parseline(&conf->manpath, pend, 'M');
        !            52:                use_path_from_file = 0;
        !            53:                pbeg = pend = NULL;
        !            54:        } else if ((pbeg = getenv("MANPATH")) == NULL || *pbeg == '\0') {
        !            55:                /* No MANPATH; use man.conf(5) only. */
        !            56:                pbeg = pend = NULL;
        !            57:        } else if (*pbeg == ':') {
        !            58:                /* Prepend man.conf(5) to MANPATH. */
        !            59:                pend = pbeg + 1;
        !            60:                pbeg = NULL;
        !            61:        } else if ((pend = strstr(pbeg, "::")) != NULL) {
        !            62:                /* Insert man.conf(5) into MANPATH. */
        !            63:                *pend = '\0';
        !            64:                pend += 2;
        !            65:        } else if (pbeg[strlen(pbeg) - 1] == ':') {
        !            66:                /* Append man.conf(5) to MANPATH. */
        !            67:                pend = NULL;
        !            68:        } else {
        !            69:                /* MANPATH overrides man.conf(5) completely. */
        !            70:                use_path_from_file = 0;
        !            71:                pend = NULL;
1.4       schwarze   72:        }
                     73:
1.31    ! schwarze   74:        manpath_parseline(&conf->manpath, pbeg, '\0');
        !            75:
        !            76:        if (file == NULL)
1.4       schwarze   77:                file = MAN_CONF_FILE;
1.31    ! schwarze   78:        manconf_file(conf, file, use_path_from_file);
1.4       schwarze   79:
1.31    ! schwarze   80:        manpath_parseline(&conf->manpath, pend, '\0');
1.22      schwarze   81: }
                     82:
                     83: void
                     84: manpath_base(struct manpaths *dirs)
                     85: {
                     86:        char path_base[] = MANPATH_BASE;
1.27      schwarze   87:        manpath_parseline(dirs, path_base, '\0');
1.1       schwarze   88: }
                     89:
                     90: /*
                     91:  * Parse a FULL pathname from a colon-separated list of arrays.
                     92:  */
1.3       schwarze   93: static void
1.27      schwarze   94: manpath_parseline(struct manpaths *dirs, char *path, char option)
1.1       schwarze   95: {
                     96:        char    *dir;
                     97:
                     98:        if (NULL == path)
                     99:                return;
                    100:
                    101:        for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
1.27      schwarze  102:                manpath_add(dirs, dir, option);
1.1       schwarze  103: }
                    104:
                    105: /*
                    106:  * Add a directory to the array, ignoring bad directories.
                    107:  * Grow the array one-by-one for simplicity's sake.
                    108:  */
                    109: static void
1.27      schwarze  110: manpath_add(struct manpaths *dirs, const char *dir, char option)
1.1       schwarze  111: {
                    112:        char             buf[PATH_MAX];
1.11      schwarze  113:        struct stat      sb;
1.1       schwarze  114:        char            *cp;
1.6       schwarze  115:        size_t           i;
1.1       schwarze  116:
1.27      schwarze  117:        if ((cp = realpath(dir, buf)) == NULL)
                    118:                goto fail;
1.1       schwarze  119:
                    120:        for (i = 0; i < dirs->sz; i++)
1.27      schwarze  121:                if (strcmp(dirs->paths[i], dir) == 0)
1.1       schwarze  122:                        return;
                    123:
1.27      schwarze  124:        if (stat(cp, &sb) == -1)
                    125:                goto fail;
1.11      schwarze  126:
1.10      schwarze  127:        dirs->paths = mandoc_reallocarray(dirs->paths,
1.27      schwarze  128:            dirs->sz + 1, sizeof(*dirs->paths));
                    129:        dirs->paths[dirs->sz++] = mandoc_strdup(cp);
                    130:        return;
1.1       schwarze  131:
1.27      schwarze  132: fail:
                    133:        if (option != '\0')
                    134:                mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0,
                    135:                    "-%c %s: %s", option, dir, strerror(errno));
1.1       schwarze  136: }
                    137:
                    138: void
1.14      schwarze  139: manconf_free(struct manconf *conf)
1.1       schwarze  140: {
1.6       schwarze  141:        size_t           i;
1.1       schwarze  142:
1.14      schwarze  143:        for (i = 0; i < conf->manpath.sz; i++)
                    144:                free(conf->manpath.paths[i]);
1.1       schwarze  145:
1.14      schwarze  146:        free(conf->manpath.paths);
                    147:        free(conf->output.includes);
                    148:        free(conf->output.man);
                    149:        free(conf->output.paper);
                    150:        free(conf->output.style);
1.1       schwarze  151: }
                    152:
1.14      schwarze  153: static void
1.31    ! schwarze  154: manconf_file(struct manconf *conf, const char *file, int use_path_from_file)
1.1       schwarze  155: {
1.28      schwarze  156:        const char *const toks[] = { "manpath", "output" };
1.15      schwarze  157:        char manpath_default[] = MANPATH_DEFAULT;
1.13      schwarze  158:
1.1       schwarze  159:        FILE            *stream;
1.17      schwarze  160:        char            *line, *cp, *ep;
                    161:        size_t           linesz, tok, toklen;
                    162:        ssize_t          linelen;
1.1       schwarze  163:
1.13      schwarze  164:        if ((stream = fopen(file, "r")) == NULL)
1.15      schwarze  165:                goto out;
1.1       schwarze  166:
1.17      schwarze  167:        line = NULL;
                    168:        linesz = 0;
                    169:
                    170:        while ((linelen = getline(&line, &linesz, stream)) != -1) {
                    171:                cp = line;
1.18      millert   172:                ep = cp + linelen - 1;
                    173:                while (ep > cp && isspace((unsigned char)*ep))
                    174:                        *ep-- = '\0';
1.13      schwarze  175:                while (isspace((unsigned char)*cp))
                    176:                        cp++;
1.18      millert   177:                if (cp == ep || *cp == '#')
1.1       schwarze  178:                        continue;
1.13      schwarze  179:
                    180:                for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) {
1.17      schwarze  181:                        toklen = strlen(toks[tok]);
                    182:                        if (cp + toklen < ep &&
                    183:                            isspace((unsigned char)cp[toklen]) &&
                    184:                            strncmp(cp, toks[tok], toklen) == 0) {
                    185:                                cp += toklen;
1.13      schwarze  186:                                while (isspace((unsigned char)*cp))
                    187:                                        cp++;
                    188:                                break;
                    189:                        }
                    190:                }
                    191:
                    192:                switch (tok) {
                    193:                case 0:  /* manpath */
1.31    ! schwarze  194:                        if (use_path_from_file)
        !           195:                                manpath_add(&conf->manpath, cp, '\0');
1.15      schwarze  196:                        *manpath_default = '\0';
1.14      schwarze  197:                        break;
                    198:                case 1:  /* output */
1.19      schwarze  199:                        manconf_output(&conf->output, cp, 1);
1.13      schwarze  200:                        break;
                    201:                default:
                    202:                        break;
                    203:                }
1.1       schwarze  204:        }
1.17      schwarze  205:        free(line);
1.15      schwarze  206:        fclose(stream);
1.1       schwarze  207:
1.15      schwarze  208: out:
1.31    ! schwarze  209:        if (use_path_from_file && *manpath_default != '\0')
1.27      schwarze  210:                manpath_parseline(&conf->manpath, manpath_default, '\0');
1.14      schwarze  211: }
                    212:
1.19      schwarze  213: int
                    214: manconf_output(struct manoutput *conf, const char *cp, int fromfile)
1.14      schwarze  215: {
                    216:        const char *const toks[] = {
1.30      schwarze  217:            /* Tokens requiring an argument. */
1.24      schwarze  218:            "includes", "man", "paper", "style", "indent", "width",
1.30      schwarze  219:            "outfilename", "tagfilename",
                    220:            /* Token taking an optional argument. */
                    221:            "tag",
                    222:            /* Tokens not taking arguments. */
1.29      schwarze  223:            "fragment", "mdoc", "noval", "toc"
1.14      schwarze  224:        };
1.25      anton     225:        const size_t ntoks = sizeof(toks) / sizeof(toks[0]);
1.14      schwarze  226:
1.19      schwarze  227:        const char      *errstr;
                    228:        char            *oldval;
                    229:        size_t           len, tok;
1.14      schwarze  230:
1.25      anton     231:        for (tok = 0; tok < ntoks; tok++) {
1.14      schwarze  232:                len = strlen(toks[tok]);
1.27      schwarze  233:                if (strncmp(cp, toks[tok], len) == 0 &&
1.14      schwarze  234:                    strchr(" =  ", cp[len]) != NULL) {
                    235:                        cp += len;
                    236:                        if (*cp == '=')
                    237:                                cp++;
                    238:                        while (isspace((unsigned char)*cp))
                    239:                                cp++;
                    240:                        break;
                    241:                }
                    242:        }
                    243:
1.29      schwarze  244:        if (tok < 8 && *cp == '\0') {
1.27      schwarze  245:                mandoc_msg(MANDOCERR_BADVAL_MISS, 0, 0, "-O %s=?", toks[tok]);
1.19      schwarze  246:                return -1;
                    247:        }
1.29      schwarze  248:        if (tok > 8 && tok < ntoks && *cp != '\0') {
1.27      schwarze  249:                mandoc_msg(MANDOCERR_BADVAL, 0, 0, "-O %s=%s", toks[tok], cp);
1.19      schwarze  250:                return -1;
                    251:        }
1.14      schwarze  252:
                    253:        switch (tok) {
                    254:        case 0:
1.19      schwarze  255:                if (conf->includes != NULL) {
                    256:                        oldval = mandoc_strdup(conf->includes);
                    257:                        break;
                    258:                }
                    259:                conf->includes = mandoc_strdup(cp);
                    260:                return 0;
1.14      schwarze  261:        case 1:
1.19      schwarze  262:                if (conf->man != NULL) {
                    263:                        oldval = mandoc_strdup(conf->man);
                    264:                        break;
                    265:                }
                    266:                conf->man = mandoc_strdup(cp);
                    267:                return 0;
1.14      schwarze  268:        case 2:
1.19      schwarze  269:                if (conf->paper != NULL) {
                    270:                        oldval = mandoc_strdup(conf->paper);
                    271:                        break;
                    272:                }
                    273:                conf->paper = mandoc_strdup(cp);
                    274:                return 0;
1.14      schwarze  275:        case 3:
1.19      schwarze  276:                if (conf->style != NULL) {
                    277:                        oldval = mandoc_strdup(conf->style);
                    278:                        break;
                    279:                }
                    280:                conf->style = mandoc_strdup(cp);
                    281:                return 0;
1.14      schwarze  282:        case 4:
1.19      schwarze  283:                if (conf->indent) {
                    284:                        mandoc_asprintf(&oldval, "%zu", conf->indent);
                    285:                        break;
                    286:                }
                    287:                conf->indent = strtonum(cp, 0, 1000, &errstr);
                    288:                if (errstr == NULL)
                    289:                        return 0;
1.27      schwarze  290:                mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0,
                    291:                    "-O indent=%s is %s", cp, errstr);
1.19      schwarze  292:                return -1;
1.14      schwarze  293:        case 5:
1.19      schwarze  294:                if (conf->width) {
                    295:                        mandoc_asprintf(&oldval, "%zu", conf->width);
                    296:                        break;
                    297:                }
1.21      schwarze  298:                conf->width = strtonum(cp, 1, 1000, &errstr);
1.19      schwarze  299:                if (errstr == NULL)
                    300:                        return 0;
1.27      schwarze  301:                mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0,
                    302:                    "-O width=%s is %s", cp, errstr);
1.19      schwarze  303:                return -1;
1.14      schwarze  304:        case 6:
1.29      schwarze  305:                if (conf->outfilename != NULL) {
                    306:                        oldval = mandoc_strdup(conf->outfilename);
                    307:                        break;
                    308:                }
                    309:                conf->outfilename = mandoc_strdup(cp);
                    310:                return 0;
1.30      schwarze  311:        case 7:
1.29      schwarze  312:                if (conf->tagfilename != NULL) {
                    313:                        oldval = mandoc_strdup(conf->tagfilename);
                    314:                        break;
                    315:                }
                    316:                conf->tagfilename = mandoc_strdup(cp);
1.30      schwarze  317:                return 0;
                    318:        /*
                    319:         * If the index of the following token changes,
                    320:         * do not forget to adjust the range check above the switch.
                    321:         */
                    322:        case 8:
                    323:                if (conf->tag != NULL) {
                    324:                        oldval = mandoc_strdup(conf->tag);
                    325:                        break;
                    326:                }
                    327:                conf->tag = mandoc_strdup(cp);
1.29      schwarze  328:                return 0;
                    329:        case 9:
1.14      schwarze  330:                conf->fragment = 1;
1.19      schwarze  331:                return 0;
1.29      schwarze  332:        case 10:
1.14      schwarze  333:                conf->mdoc = 1;
1.20      schwarze  334:                return 0;
1.29      schwarze  335:        case 11:
1.20      schwarze  336:                conf->noval = 1;
1.23      schwarze  337:                return 0;
1.29      schwarze  338:        case 12:
1.23      schwarze  339:                conf->toc = 1;
1.19      schwarze  340:                return 0;
1.14      schwarze  341:        default:
1.27      schwarze  342:                mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, "-O %s", cp);
                    343:                return -1;
                    344:        }
                    345:        if (fromfile) {
                    346:                free(oldval);
                    347:                return 0;
                    348:        } else {
                    349:                mandoc_msg(MANDOCERR_BADVAL_DUPE, 0, 0,
                    350:                    "-O %s=%s: already set to %s", toks[tok], cp, oldval);
                    351:                free(oldval);
1.19      schwarze  352:                return -1;
1.14      schwarze  353:        }
1.1       schwarze  354: }