diff options
-rw-r--r-- | Makefile.depend | 4 | ||||
-rw-r--r-- | main.c | 297 | ||||
-rw-r--r-- | mandoc.1 | 51 | ||||
-rw-r--r-- | mandoc.h | 32 | ||||
-rw-r--r-- | mandoc_msg.c | 42 | ||||
-rw-r--r-- | manpath.c | 90 | ||||
-rw-r--r-- | read.c | 33 | ||||
-rw-r--r-- | tag.c | 30 |
8 files changed, 338 insertions, 241 deletions
diff --git a/Makefile.depend b/Makefile.depend index a02a2dc5..81f632d0 100644 --- a/Makefile.depend +++ b/Makefile.depend @@ -46,7 +46,7 @@ mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h manconf.h mansearch.h dba_array.h dba.h -manpath.o: manpath.c config.h mandoc_aux.h manconf.h +manpath.o: manpath.c config.h mandoc_aux.h mandoc.h manconf.h mansearch.o: mansearch.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h @@ -67,7 +67,7 @@ roff_term.o: roff_term.c mandoc.h roff.h out.h term.h roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h soelim.o: soelim.c config.h compat_stringlist.h st.o: st.c config.h mandoc.h roff.h libmdoc.h -tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h +tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h tag.h tbl.o: tbl.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_parse.h tbl_int.h tbl_data.o: tbl_data.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h tbl_html.o: tbl_html.c config.h mandoc.h roff.h tbl.h out.h html.h @@ -98,13 +98,10 @@ static int fs_lookup(const struct manpaths *, static int fs_search(const struct mansearch *, const struct manpaths *, int, char**, struct manpage **, size_t *); -static int koptions(int *, char *); -static void moptions(int *, char *); static void outdata_alloc(struct curparse *); static void parse(struct curparse *, int, const char *); -static void passthrough(const char *, int, int); +static void passthrough(int, int); static pid_t spawn_pager(struct tag_files *); -static int toptions(struct curparse *, char *); static void usage(enum argmode) __attribute__((__noreturn__)); static int woptions(struct curparse *, char *); @@ -155,10 +152,11 @@ main(int argc, char *argv[]) return mandocdb(argc, argv); #if HAVE_PLEDGE - if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, "%s", strerror(errno)); + return mandoc_msg_getrc(); + } #endif - #if HAVE_SANDBOX_INIT if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1) errx((int)MANDOCLEVEL_SYSERR, "sandbox_init"); @@ -222,19 +220,29 @@ main(int argc, char *argv[]) outmode = OUTMODE_ALL; break; case 'I': - if (strncmp(optarg, "os=", 3)) { - warnx("-I %s: Bad argument", optarg); - return (int)MANDOCLEVEL_BADARG; + if (strncmp(optarg, "os=", 3) != 0) { + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, + "-I %s", optarg); + return mandoc_msg_getrc(); } if (curp.os_s != NULL) { - warnx("-I %s: Duplicate argument", optarg); - return (int)MANDOCLEVEL_BADARG; + mandoc_msg(MANDOCERR_BADARG_DUPE, 0, 0, + "-I %s", optarg); + return mandoc_msg_getrc(); } curp.os_s = mandoc_strdup(optarg + 3); break; case 'K': - if ( ! koptions(&options, optarg)) - return (int)MANDOCLEVEL_BADARG; + options &= ~(MPARSE_UTF8 | MPARSE_LATIN1); + if (strcmp(optarg, "utf-8") == 0) + options |= MPARSE_UTF8; + else if (strcmp(optarg, "iso-8859-1") == 0) + options |= MPARSE_LATIN1; + else if (strcmp(optarg, "us-ascii") != 0) { + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, + "-K %s", optarg); + return mandoc_msg_getrc(); + } break; case 'k': search.argmode = ARG_EXPR; @@ -259,12 +267,37 @@ main(int argc, char *argv[]) search.sec = optarg; break; case 'T': - if ( ! toptions(&curp, optarg)) - return (int)MANDOCLEVEL_BADARG; + if (strcmp(optarg, "ascii") == 0) + curp.outtype = OUTT_ASCII; + else if (strcmp(optarg, "lint") == 0) { + curp.outtype = OUTT_LINT; + mandoc_msg_setoutfile(stdout); + mandoc_msg_setmin(MANDOCERR_BASE); + } else if (strcmp(optarg, "tree") == 0) + curp.outtype = OUTT_TREE; + else if (strcmp(optarg, "man") == 0) + curp.outtype = OUTT_MAN; + else if (strcmp(optarg, "html") == 0) + curp.outtype = OUTT_HTML; + else if (strcmp(optarg, "markdown") == 0) + curp.outtype = OUTT_MARKDOWN; + else if (strcmp(optarg, "utf8") == 0) + curp.outtype = OUTT_UTF8; + else if (strcmp(optarg, "locale") == 0) + curp.outtype = OUTT_LOCALE; + else if (strcmp(optarg, "ps") == 0) + curp.outtype = OUTT_PS; + else if (strcmp(optarg, "pdf") == 0) + curp.outtype = OUTT_PDF; + else { + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, + "-T %s", optarg); + return mandoc_msg_getrc(); + } break; case 'W': - if ( ! woptions(&curp, optarg)) - return (int)MANDOCLEVEL_BADARG; + if (woptions(&curp, optarg) == -1) + return mandoc_msg_getrc(); break; case 'w': outmode = OUTMODE_FLN; @@ -302,7 +335,7 @@ main(int argc, char *argv[]) while (oarg != NULL) { if (manconf_output(&conf.output, strsep(&oarg, ","), 0) == -1) - return (int)MANDOCLEVEL_BADARG; + return mandoc_msg_getrc(); } } } @@ -326,9 +359,13 @@ main(int argc, char *argv[]) } #if HAVE_PLEDGE - if (!use_pager) - if (pledge("stdio rpath", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (use_pager == 0) { + if (pledge("stdio rpath", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, + "%s", strerror(errno)); + return mandoc_msg_getrc(); + } + } #endif /* Parse arguments. */ @@ -393,7 +430,7 @@ main(int argc, char *argv[]) usage(search.argmode); if (sz == 0 && search.argmode == ARG_NAME) - fs_search(&search, &conf.manpath, + (void)fs_search(&search, &conf.manpath, argc, argv, &res, &sz); if (search.argmode == ARG_NAME) { @@ -401,7 +438,10 @@ main(int argc, char *argv[]) if (strchr(argv[c], '/') == NULL) continue; if (access(argv[c], R_OK) == -1) { - warn("%s", argv[c]); + mandoc_msg_setinfilename(argv[c]); + mandoc_msg(MANDOCERR_BADARG_BAD, + 0, 0, "%s", strerror(errno)); + mandoc_msg_setinfilename(NULL); continue; } res = mandoc_reallocarray(res, @@ -487,16 +527,26 @@ main(int argc, char *argv[]) #if HAVE_PLEDGE if (use_pager) { - if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, + "%s", strerror(errno)); + return mandoc_msg_getrc(); + } } else { - if (pledge("stdio rpath", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (pledge("stdio rpath", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, + "%s", strerror(errno)); + return mandoc_msg_getrc(); + } } #endif - if (search.argmode == ARG_FILE) - moptions(&options, auxpaths); + if (search.argmode == ARG_FILE && auxpaths != NULL) { + if (strcmp(auxpaths, "doc") == 0) + options |= MPARSE_MDOC; + else if (strcmp(auxpaths, "an") == 0) + options |= MPARSE_MAN; + } mchars_alloc(); curp.mp = mparse_alloc(options, curp.os_e, curp.os_s); @@ -538,6 +588,7 @@ main(int argc, char *argv[]) } else thisarg = *argv; + mandoc_msg_setinfilename(thisarg); fd = mparse_open(curp.mp, thisarg); if (fd != -1) { if (use_pager) { @@ -547,22 +598,21 @@ main(int argc, char *argv[]) tag_files->tagname = conf.output.tag; } - mandoc_msg_setinfilename(thisarg); if (resp == NULL || resp->form == FORM_SRC) parse(&curp, fd, thisarg); else - passthrough(resp->file, fd, - conf.output.synopsisonly); - mandoc_msg_setinfilename(NULL); + passthrough(fd, conf.output.synopsisonly); if (ferror(stdout)) { if (tag_files != NULL) { - warn("%s", tag_files->ofn); + mandoc_msg(MANDOCERR_WRITE, 0, 0, + "%s: %s", tag_files->ofn, + strerror(errno)); tag_unlink(); tag_files = NULL; } else - warn("stdout"); - mandoc_msg_setrc(MANDOCLEVEL_SYSERR); + mandoc_msg(MANDOCERR_WRITE, 0, 0, + "%s", strerror(errno)); break; } @@ -572,8 +622,10 @@ main(int argc, char *argv[]) terminal_sepline(curp.outdata); } } else - mandoc_msg(MANDOCERR_FILE, 0, 0, - "%s: %s", thisarg, strerror(errno)); + mandoc_msg(resp == NULL ? MANDOCERR_BADARG_BAD : + MANDOCERR_OPEN, 0, 0, "%s", strerror(errno)); + + mandoc_msg_setinfilename(NULL); if (curp.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK) break; @@ -665,8 +717,8 @@ out: continue; if (pid == -1) { - warn("wait"); - mandoc_msg_setrc(MANDOCLEVEL_SYSERR); + mandoc_msg(MANDOCERR_WAIT, 0, 0, + "%s", strerror(errno)); break; } if (!WIFSTOPPED(status)) @@ -682,7 +734,6 @@ out: static void usage(enum argmode argmode) { - switch (argmode) { case ARG_FILE: fputs("usage: mandoc [-ac] [-I os=name] " @@ -747,7 +798,8 @@ fs_lookup(const struct manpaths *paths, size_t ipath, paths->paths[ipath], sec, name); globres = glob(file, 0, NULL, &globinfo); if (globres != 0 && globres != GLOB_NOMATCH) - warn("%s: glob", file); + mandoc_msg(MANDOCERR_GLOB, 0, 0, + "%s: %s", file, strerror(errno)); free(file); if (globres == 0) file = mandoc_strdup(*globinfo.gl_pathv); @@ -758,21 +810,21 @@ fs_lookup(const struct manpaths *paths, size_t ipath, free(file); } if (res != NULL || ipath + 1 != paths->sz) - return 0; + return -1; mandoc_asprintf(&file, "%s.%s", name, sec); globres = stat(file, &sb); free(file); - return globres != -1; + return globres; found: warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s", name, sec, BINM_MAKEWHATIS, paths->paths[ipath]); if (res == NULL) { free(file); - return 1; + return 0; } - *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage)); + *res = mandoc_reallocarray(*res, ++*ressz, sizeof(**res)); page = *res + (*ressz - 1); page->file = file; page->names = NULL; @@ -781,7 +833,7 @@ found: page->ipath = ipath; page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10; page->form = form; - return 1; + return 0; } static int @@ -803,14 +855,14 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths, for (ipath = 0; ipath < paths->sz; ipath++) { if (cfg->sec != NULL) { if (fs_lookup(paths, ipath, cfg->sec, - cfg->arch, *argv, res, ressz) && + cfg->arch, *argv, res, ressz) != -1 && cfg->firstmatch) - return 1; + return 0; } else for (isec = 0; isec < nsec; isec++) if (fs_lookup(paths, ipath, sections[isec], - cfg->arch, *argv, res, ressz) && + cfg->arch, *argv, res, ressz) != -1 && cfg->firstmatch) - return 1; + return 0; } if (res != NULL && *ressz == lastsz && strchr(*argv, '/') == NULL) { @@ -829,7 +881,7 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths, argv++; argc--; } - return 0; + return -1; } static void @@ -936,7 +988,7 @@ check_xr(void) search.firstmatch = 1; if (mansearch(&search, &paths, 1, &xr->name, NULL, &sz)) continue; - if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz)) + if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz) != -1) continue; if (xr->count == 1) mandoc_msg(MANDOCERR_XR_BAD, xr->line, @@ -976,34 +1028,34 @@ outdata_alloc(struct curparse *curp) } static void -passthrough(const char *file, int fd, int synopsis_only) +passthrough(int fd, int synopsis_only) { const char synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"; const char synr[] = "SYNOPSIS"; FILE *stream; - const char *syscall; char *line, *cp; size_t linesz; ssize_t len, written; - int print; + int lno, print; + stream = NULL; line = NULL; linesz = 0; if (fflush(stdout) == EOF) { - syscall = "fflush"; - goto fail; + mandoc_msg(MANDOCERR_FFLUSH, 0, 0, "%s", strerror(errno)); + goto done; } - if ((stream = fdopen(fd, "r")) == NULL) { close(fd); - syscall = "fdopen"; - goto fail; + mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno)); + goto done; } - print = 0; + lno = print = 0; while ((len = getline(&line, &linesz, stream)) != -1) { + lno++; cp = line; if (synopsis_only) { if (print) { @@ -1021,94 +1073,20 @@ passthrough(const char *file, int fd, int synopsis_only) } } for (; len > 0; len -= written) { - if ((written = write(STDOUT_FILENO, cp, len)) != -1) - continue; - fclose(stream); - syscall = "write"; - goto fail; + if ((written = write(STDOUT_FILENO, cp, len)) == -1) { + mandoc_msg(MANDOCERR_WRITE, 0, 0, + "%s", strerror(errno)); + goto done; + } } } - - if (ferror(stream)) { - fclose(stream); - syscall = "getline"; - goto fail; - } + if (ferror(stream)) + mandoc_msg(MANDOCERR_GETLINE, lno, 0, "%s", strerror(errno)); done: free(line); - fclose(stream); - return; - -fail: - free(line); - warn("%s: SYSERR: %s", file, syscall); - mandoc_msg_setrc(MANDOCLEVEL_SYSERR); -} - -static int -koptions(int *options, char *arg) -{ - - if ( ! strcmp(arg, "utf-8")) { - *options |= MPARSE_UTF8; - *options &= ~MPARSE_LATIN1; - } else if ( ! strcmp(arg, "iso-8859-1")) { - *options |= MPARSE_LATIN1; - *options &= ~MPARSE_UTF8; - } else if ( ! strcmp(arg, "us-ascii")) { - *options &= ~(MPARSE_UTF8 | MPARSE_LATIN1); - } else { - warnx("-K %s: Bad argument", arg); - return 0; - } - return 1; -} - -static void -moptions(int *options, char *arg) -{ - - if (arg == NULL) - return; - if (strcmp(arg, "doc") == 0) - *options |= MPARSE_MDOC; - else if (strcmp(arg, "an") == 0) - *options |= MPARSE_MAN; -} - -static int -toptions(struct curparse *curp, char *arg) -{ - - if (0 == strcmp(arg, "ascii")) - curp->outtype = OUTT_ASCII; - else if (0 == strcmp(arg, "lint")) { - curp->outtype = OUTT_LINT; - mandoc_msg_setoutfile(stdout); - mandoc_msg_setmin(MANDOCERR_BASE); - } else if (0 == strcmp(arg, "tree")) - curp->outtype = OUTT_TREE; - else if (0 == strcmp(arg, "man")) - curp->outtype = OUTT_MAN; - else if (0 == strcmp(arg, "html")) - curp->outtype = OUTT_HTML; - else if (0 == strcmp(arg, "markdown")) - curp->outtype = OUTT_MARKDOWN; - else if (0 == strcmp(arg, "utf8")) - curp->outtype = OUTT_UTF8; - else if (0 == strcmp(arg, "locale")) - curp->outtype = OUTT_LOCALE; - else if (0 == strcmp(arg, "ps")) - curp->outtype = OUTT_PS; - else if (0 == strcmp(arg, "pdf")) - curp->outtype = OUTT_PDF; - else { - warnx("-T %s: Bad argument", arg); - return 0; - } - - return 1; + if (stream != NULL) + fclose(stream); } static int @@ -1152,7 +1130,7 @@ woptions(struct curparse *curp, char *arg) mandoc_msg_setmin(MANDOCERR_UNSUPP); break; case 7: - mandoc_msg_setmin(MANDOCERR_MAX); + mandoc_msg_setmin(MANDOCERR_BADARG); break; case 8: mandoc_msg_setmin(MANDOCERR_BASE); @@ -1163,11 +1141,11 @@ woptions(struct curparse *curp, char *arg) curp->os_e = MANDOC_OS_NETBSD; break; default: - warnx("-W %s: Bad argument", o); - return 0; + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, "-W %s", o); + return -1; } } - return 1; + return 0; } static pid_t @@ -1232,15 +1210,19 @@ spawn_pager(struct tag_files *tag_files) switch (pager_pid = fork()) { case -1: - err((int)MANDOCLEVEL_SYSERR, "fork"); + mandoc_msg(MANDOCERR_FORK, 0, 0, "%s", strerror(errno)); + exit(mandoc_msg_getrc()); case 0: break; default: (void)setpgid(pager_pid, 0); (void)tcsetpgrp(tag_files->ofd, pager_pid); #if HAVE_PLEDGE - if (pledge("stdio rpath tmppath tty proc", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (pledge("stdio rpath tmppath tty proc", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, + "%s", strerror(errno)); + exit(mandoc_msg_getrc()); + } #endif tag_files->pager_pid = pager_pid; return pager_pid; @@ -1248,8 +1230,10 @@ spawn_pager(struct tag_files *tag_files) /* The child process becomes the pager. */ - if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) - err((int)MANDOCLEVEL_SYSERR, "pager stdout"); + if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); + _exit(mandoc_msg_getrc()); + } close(tag_files->ofd); assert(tag_files->tfd == -1); @@ -1259,5 +1243,6 @@ spawn_pager(struct tag_files *tag_files) nanosleep(&timeout, NULL); execvp(argv[0], argv); - err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]); + mandoc_msg(MANDOCERR_EXEC, 0, 0, "%s: %s", argv[0], strerror(errno)); + _exit(mandoc_msg_getrc()); } @@ -1,7 +1,7 @@ .\" $Id$ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> -.\" Copyright (c) 2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2012, 2014-2019 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -698,7 +698,7 @@ No input files have been read. .It 6 An operating system error occurred, for example exhaustion of memory, file descriptors, or process table entries. -Such errors cause +Such errors may cause .Nm to exit at once, possibly in the middle of parsing or formatting a file. .El @@ -778,6 +778,13 @@ fields. .Pp Message levels have the following meanings: .Bl -tag -width "warning" +.It Cm syserr +An operating system error occurred. +There isn't necessarily anything wrong with the input files. +Output may all the same be missing or incomplete. +.It Cm badarg +Invalid command line arguments were specified. +No input files have been read and no output is produced. .It Cm unsupp An input file uses unsupported low-level .Xr roff 7 @@ -826,8 +833,7 @@ Messages of the .Cm error , and .Cm unsupp -levels except those about non-existent or unreadable input files -are hidden unless their level, or a lower level, is requested using a +levels are hidden unless their level, or a lower level, is requested using a .Fl W option or .Fl T Cm lint @@ -2242,6 +2248,43 @@ macro or of an undefined macro. The macro is ignored, and its arguments are handled as if they were a text line. .El +.Ss Bad command line arguments +.Bl -ohang +.It Sy "bad command line argument" +The argument following one of the +.Fl IKMmOTW +command line options is invalid, or a +.Ar file +given as a command line argument cannot be opened. +.It Sy "duplicate command line argument" +The +.Fl I +command line option was specified twice. +.It Sy "option has a superfluous value" +An argument to the +.Fl O +option has a value but does not accept one. +.It Sy "missing option value" +An argument to the +.Fl O +option has no argument but requires one. +.It Sy "bad option value" +An argument to the +.Fl O +.Cm indent +or +.Cm width +option has an invalid value. +.It Sy "duplicate option value" +The same +.Fl O +option is specified more than once. +.It Sy "no such tag" +The +.Fl O Cm tag +option was specified but the tag was not found in any of the displayed +manual pages. +.El .Sh SEE ALSO .Xr apropos 1 , .Xr man 1 , @@ -1,7 +1,7 @@ /* $Id$ */ /* * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2012-2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2012-2019 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -193,7 +193,6 @@ enum mandocerr { MANDOCERR_TBLDATA_BLK, /* data block open at end of tbl: macro */ /* related to document structure and macros */ - MANDOCERR_FILE, /* cannot open file */ MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */ MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */ MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */ @@ -242,6 +241,35 @@ enum mandocerr { MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */ MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */ + MANDOCERR_BADARG, /* ===== start of bad invocations ===== */ + + MANDOCERR_BADARG_BAD, /* bad argument */ + MANDOCERR_BADARG_DUPE, /* duplicate argument */ + MANDOCERR_BADVAL, /* does not take a value */ + MANDOCERR_BADVAL_MISS, /* missing argument value */ + MANDOCERR_BADVAL_BAD, /* bad argument value */ + MANDOCERR_BADVAL_DUPE, /* duplicate argument value */ + MANDOCERR_TAG, /* no such tag */ + + MANDOCERR_SYSERR, /* ===== start of system errors ===== */ + + MANDOCERR_DUP, + MANDOCERR_EXEC, + MANDOCERR_FDOPEN, + MANDOCERR_FFLUSH, + MANDOCERR_FORK, + MANDOCERR_FSTAT, + MANDOCERR_GETLINE, + MANDOCERR_GLOB, + MANDOCERR_GZCLOSE, + MANDOCERR_GZDOPEN, + MANDOCERR_MKSTEMP, + MANDOCERR_OPEN, + MANDOCERR_PLEDGE, + MANDOCERR_READ, + MANDOCERR_WAIT, + MANDOCERR_WRITE, + MANDOCERR_MAX }; diff --git a/mandoc_msg.c b/mandoc_msg.c index 26ee72a2..4299f2b8 100644 --- a/mandoc_msg.c +++ b/mandoc_msg.c @@ -1,7 +1,7 @@ /* $Id$ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2014-2019 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,8 +29,8 @@ static const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = { MANDOCERR_WARNING, MANDOCERR_ERROR, MANDOCERR_UNSUPP, - MANDOCERR_MAX, - MANDOCERR_MAX + MANDOCERR_BADARG, + MANDOCERR_SYSERR }; static const char *const level_name[MANDOCLEVEL_MAX] = { @@ -193,7 +193,6 @@ static const char *const type_message[MANDOCERR_MAX] = { "data block open at end of tbl", /* related to document structure and macros */ - NULL, "duplicate prologue macro", "skipping late title macro", "input stack limit exceeded, infinite loop?", @@ -240,11 +239,40 @@ static const char *const type_message[MANDOCERR_MAX] = { "eqn delim option in tbl", "unsupported tbl layout modifier", "ignoring macro in table", + + /* bad command line arguments */ + NULL, + "bad command line argument", + "duplicate command line argument", + "option has a superfluous value", + "missing option value", + "bad option value", + "duplicate option value", + "no such tag", + + /* system errors */ + NULL, + "dup", + "exec", + "fdopen", + "fflush", + "fork", + "fstat", + "getline", + "glob", + "gzclose", + "gzdopen", + "mkstemp", + "open", + "pledge", + "read", + "wait", + "write", }; static FILE *fileptr = NULL; static const char *filename = NULL; -static enum mandocerr min_type = MANDOCERR_MAX; +static enum mandocerr min_type = MANDOCERR_BADARG; static enum mandoclevel rc = MANDOCLEVEL_OK; @@ -297,10 +325,10 @@ mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...) va_list ap; enum mandoclevel level; - if (t < min_type && t != MANDOCERR_FILE) + if (t < min_type) return; - level = MANDOCLEVEL_UNSUPP; + level = MANDOCLEVEL_SYSERR; while (t < lowest_type[level]) level--; mandoc_msg_setrc(level); @@ -1,6 +1,6 @@ /* $Id$ */ /* - * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011,2014,2015,2017-2019 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any @@ -21,20 +21,19 @@ #include <sys/stat.h> #include <ctype.h> -#if HAVE_ERR -#include <err.h> -#endif +#include <errno.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "mandoc_aux.h" +#include "mandoc.h" #include "manconf.h" static void manconf_file(struct manconf *, const char *); -static void manpath_add(struct manpaths *, const char *, int); -static void manpath_parseline(struct manpaths *, char *, int); +static void manpath_add(struct manpaths *, const char *, char); +static void manpath_parseline(struct manpaths *, char *, char); void @@ -44,11 +43,11 @@ manconf_parse(struct manconf *conf, const char *file, char *insert; /* Always prepend -m. */ - manpath_parseline(&conf->manpath, auxp, 1); + manpath_parseline(&conf->manpath, auxp, 'm'); /* If -M is given, it overrides everything else. */ if (NULL != defp) { - manpath_parseline(&conf->manpath, defp, 1); + manpath_parseline(&conf->manpath, defp, 'M'); return; } @@ -66,13 +65,13 @@ manconf_parse(struct manconf *conf, const char *file, /* Prepend man.conf(5) to MANPATH. */ if (':' == defp[0]) { manconf_file(conf, file); - manpath_parseline(&conf->manpath, defp, 0); + manpath_parseline(&conf->manpath, defp, '\0'); return; } /* Append man.conf(5) to MANPATH. */ if (':' == defp[strlen(defp) - 1]) { - manpath_parseline(&conf->manpath, defp, 0); + manpath_parseline(&conf->manpath, defp, '\0'); manconf_file(conf, file); return; } @@ -81,28 +80,28 @@ manconf_parse(struct manconf *conf, const char *file, insert = strstr(defp, "::"); if (NULL != insert) { *insert++ = '\0'; - manpath_parseline(&conf->manpath, defp, 0); + manpath_parseline(&conf->manpath, defp, '\0'); manconf_file(conf, file); - manpath_parseline(&conf->manpath, insert + 1, 0); + manpath_parseline(&conf->manpath, insert + 1, '\0'); return; } /* MANPATH overrides man.conf(5) completely. */ - manpath_parseline(&conf->manpath, defp, 0); + manpath_parseline(&conf->manpath, defp, '\0'); } void manpath_base(struct manpaths *dirs) { char path_base[] = MANPATH_BASE; - manpath_parseline(dirs, path_base, 0); + manpath_parseline(dirs, path_base, '\0'); } /* * Parse a FULL pathname from a colon-separated list of arrays. */ static void -manpath_parseline(struct manpaths *dirs, char *path, int complain) +manpath_parseline(struct manpaths *dirs, char *path, char option) { char *dir; @@ -110,7 +109,7 @@ manpath_parseline(struct manpaths *dirs, char *path, int complain) return; for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) - manpath_add(dirs, dir, complain); + manpath_add(dirs, dir, option); } /* @@ -118,33 +117,32 @@ manpath_parseline(struct manpaths *dirs, char *path, int complain) * Grow the array one-by-one for simplicity's sake. */ static void -manpath_add(struct manpaths *dirs, const char *dir, int complain) +manpath_add(struct manpaths *dirs, const char *dir, char option) { char buf[PATH_MAX]; struct stat sb; char *cp; size_t i; - if (NULL == (cp = realpath(dir, buf))) { - if (complain) - warn("manpath: %s", dir); - return; - } + if ((cp = realpath(dir, buf)) == NULL) + goto fail; for (i = 0; i < dirs->sz; i++) - if (0 == strcmp(dirs->paths[i], dir)) + if (strcmp(dirs->paths[i], dir) == 0) return; - if (stat(cp, &sb) == -1) { - if (complain) - warn("manpath: %s", dir); - return; - } + if (stat(cp, &sb) == -1) + goto fail; dirs->paths = mandoc_reallocarray(dirs->paths, - dirs->sz + 1, sizeof(char *)); - + dirs->sz + 1, sizeof(*dirs->paths)); dirs->paths[dirs->sz++] = mandoc_strdup(cp); + return; + +fail: + if (option != '\0') + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, + "-%c %s: %s", option, dir, strerror(errno)); } void @@ -210,7 +208,7 @@ manconf_file(struct manconf *conf, const char *file) *ep = '\0'; /* FALLTHROUGH */ case 0: /* manpath */ - manpath_add(&conf->manpath, cp, 0); + manpath_add(&conf->manpath, cp, '\0'); *manpath_default = '\0'; break; case 1: /* output */ @@ -225,7 +223,7 @@ manconf_file(struct manconf *conf, const char *file) out: if (*manpath_default != '\0') - manpath_parseline(&conf->manpath, manpath_default, 0); + manpath_parseline(&conf->manpath, manpath_default, '\0'); } int @@ -243,7 +241,7 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) for (tok = 0; tok < ntoks; tok++) { len = strlen(toks[tok]); - if ( ! strncmp(cp, toks[tok], len) && + if (strncmp(cp, toks[tok], len) == 0 && strchr(" = ", cp[len]) != NULL) { cp += len; if (*cp == '=') @@ -255,11 +253,11 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) } if (tok < 6 && *cp == '\0') { - warnx("-O %s=?: Missing argument value", toks[tok]); + mandoc_msg(MANDOCERR_BADVAL_MISS, 0, 0, "-O %s=?", toks[tok]); return -1; } if (tok > 6 && tok < ntoks && *cp != '\0') { - warnx("-O %s: Does not take a value: %s", toks[tok], cp); + mandoc_msg(MANDOCERR_BADVAL, 0, 0, "-O %s=%s", toks[tok], cp); return -1; } @@ -300,7 +298,8 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) conf->indent = strtonum(cp, 0, 1000, &errstr); if (errstr == NULL) return 0; - warnx("-O indent=%s is %s", cp, errstr); + mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0, + "-O indent=%s is %s", cp, errstr); return -1; case 5: if (conf->width) { @@ -310,7 +309,8 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) conf->width = strtonum(cp, 1, 1000, &errstr); if (errstr == NULL) return 0; - warnx("-O width=%s is %s", cp, errstr); + mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0, + "-O width=%s is %s", cp, errstr); return -1; case 6: if (conf->tag != NULL) { @@ -332,12 +332,16 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) conf->toc = 1; return 0; default: - warnx("-O %s: Bad argument", cp); + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, "-O %s", cp); + return -1; + } + if (fromfile) { + free(oldval); + return 0; + } else { + mandoc_msg(MANDOCERR_BADVAL_DUPE, 0, 0, + "-O %s=%s: already set to %s", toks[tok], cp, oldval); + free(oldval); return -1; } - if (fromfile == 0) - warnx("-O %s=%s: Option already set to %s", - toks[tok], cp, oldval); - free(oldval); - return -1; } @@ -431,9 +431,8 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) int gzerrnum, retval; if (fstat(fd, &st) == -1) { - mandoc_msg(MANDOCERR_FILE, 0, 0, - "fstat: %s", strerror(errno)); - return 0; + mandoc_msg(MANDOCERR_FSTAT, 0, 0, "%s", strerror(errno)); + return -1; } /* @@ -446,13 +445,13 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) if (curp->gzip == 0 && S_ISREG(st.st_mode)) { if (st.st_size > 0x7fffffff) { mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL); - return 0; + return -1; } *with_mmap = 1; fb->sz = (size_t)st.st_size; fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0); if (fb->buf != MAP_FAILED) - return 1; + return 0; } if (curp->gzip) { @@ -464,15 +463,15 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) * which this function must not do. */ if ((fd = dup(fd)) == -1) { - mandoc_msg(MANDOCERR_FILE, 0, 0, - "dup: %s", strerror(errno)); - return 0; + mandoc_msg(MANDOCERR_DUP, 0, 0, + "%s", strerror(errno)); + return -1; } if ((gz = gzdopen(fd, "rb")) == NULL) { - mandoc_msg(MANDOCERR_FILE, 0, 0, - "gzdopen: %s", strerror(errno)); + mandoc_msg(MANDOCERR_GZDOPEN, 0, 0, + "%s", strerror(errno)); close(fd); - return 0; + return -1; } } else gz = NULL; @@ -484,7 +483,7 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) *with_mmap = 0; off = 0; - retval = 0; + retval = -1; fb->sz = 0; fb->buf = NULL; for (;;) { @@ -500,13 +499,13 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) read(fd, fb->buf + (int)off, fb->sz - off); if (ssz == 0) { fb->sz = off; - retval = 1; + retval = 0; break; } if (ssz == -1) { if (curp->gzip) (void)gzerror(gz, &gzerrnum); - mandoc_msg(MANDOCERR_FILE, 0, 0, "read: %s", + mandoc_msg(MANDOCERR_READ, 0, 0, "%s", curp->gzip && gzerrnum != Z_ERRNO ? zError(gzerrnum) : strerror(errno)); break; @@ -515,10 +514,10 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) } if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK) - mandoc_msg(MANDOCERR_FILE, 0, 0, "gzclose: %s", + mandoc_msg(MANDOCERR_GZCLOSE, 0, 0, "%s", gzerrnum == Z_ERRNO ? strerror(errno) : zError(gzerrnum)); - if (retval == 0) { + if (retval == -1) { free(fb->buf); fb->buf = NULL; } @@ -557,7 +556,7 @@ mparse_readfd(struct mparse *curp, int fd, const char *filename) mandoc_msg(MANDOCERR_ROFFLOOP, curp->line, 0, NULL); return; } - if (read_whole_file(curp, fd, &blk, &with_mmap) == 0) + if (read_whole_file(curp, fd, &blk, &with_mmap) == -1) return; /* @@ -1,6 +1,6 @@ /* $Id$ */ /* - * Copyright (c) 2015, 2016, 2018 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2015, 2016, 2018, 2019 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,9 +18,7 @@ #include <sys/types.h> -#if HAVE_ERR -#include <err.h> -#endif +#include <errno.h> #include <limits.h> #include <signal.h> #include <stddef.h> @@ -32,6 +30,7 @@ #include "mandoc_aux.h" #include "mandoc_ohash.h" +#include "mandoc.h" #include "tag.h" struct tag_entry { @@ -83,8 +82,10 @@ tag_init(void) /* Save the original standard output for use by the pager. */ - if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) + if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); goto fail; + } /* Create both temporary output files. */ @@ -92,12 +93,20 @@ tag_init(void) sizeof(tag_files.ofn)); (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX", sizeof(tag_files.tfn)); - if ((ofd = mkstemp(tag_files.ofn)) == -1) + if ((ofd = mkstemp(tag_files.ofn)) == -1) { + mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, + "%s: %s", tag_files.ofn, strerror(errno)); goto fail; - if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1) + } + if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1) { + mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, + "%s: %s", tag_files.tfn, strerror(errno)); goto fail; - if (dup2(ofd, STDOUT_FILENO) == -1) + } + if (dup2(ofd, STDOUT_FILENO) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); goto fail; + } close(ofd); /* @@ -221,10 +230,11 @@ tag_write(void) return; if (tag_files.tagname != NULL && ohash_find(&tag_data, ohash_qlookup(&tag_data, tag_files.tagname)) == NULL) { - warnx("%s: no such tag", tag_files.tagname); + mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", tag_files.tagname); tag_files.tagname = NULL; } - stream = fdopen(tag_files.tfd, "w"); + if ((stream = fdopen(tag_files.tfd, "w")) == NULL) + mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno)); entry = ohash_first(&tag_data, &slot); while (entry != NULL) { if (stream != NULL && entry->prio >= 0) |