xref: /illumos-gate/usr/src/cmd/mandoc/mandoc_msg.c (revision bbf21555)
14d131170SRobert Mustacchi /* $OpenBSD: mandoc_msg.c,v 1.8 2020/01/19 17:59:01 schwarze Exp $ */
2cec8643bSMichal Nowak /*
34d131170SRobert Mustacchi  * Copyright (c) 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
4cec8643bSMichal Nowak  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
5cec8643bSMichal Nowak  *
6cec8643bSMichal Nowak  * Permission to use, copy, modify, and distribute this software for any
7cec8643bSMichal Nowak  * purpose with or without fee is hereby granted, provided that the above
8cec8643bSMichal Nowak  * copyright notice and this permission notice appear in all copies.
9cec8643bSMichal Nowak  *
10cec8643bSMichal Nowak  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11cec8643bSMichal Nowak  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12cec8643bSMichal Nowak  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13cec8643bSMichal Nowak  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14cec8643bSMichal Nowak  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15cec8643bSMichal Nowak  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16cec8643bSMichal Nowak  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174d131170SRobert Mustacchi  *
184d131170SRobert Mustacchi  * Implementation of warning and error messages for mandoc(1).
19cec8643bSMichal Nowak  */
20cec8643bSMichal Nowak #include "config.h"
21cec8643bSMichal Nowak 
22cec8643bSMichal Nowak #include <stdarg.h>
23cec8643bSMichal Nowak #include <stdio.h>
24cec8643bSMichal Nowak #include <stdlib.h>
25cec8643bSMichal Nowak 
26cec8643bSMichal Nowak #include "mandoc.h"
27cec8643bSMichal Nowak 
28cec8643bSMichal Nowak static	const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = {
29cec8643bSMichal Nowak 	MANDOCERR_OK,
30cec8643bSMichal Nowak 	MANDOCERR_OK,
31cec8643bSMichal Nowak 	MANDOCERR_WARNING,
32cec8643bSMichal Nowak 	MANDOCERR_ERROR,
33cec8643bSMichal Nowak 	MANDOCERR_UNSUPP,
344d131170SRobert Mustacchi 	MANDOCERR_BADARG,
354d131170SRobert Mustacchi 	MANDOCERR_SYSERR
36cec8643bSMichal Nowak };
37cec8643bSMichal Nowak 
38cec8643bSMichal Nowak static	const char *const level_name[MANDOCLEVEL_MAX] = {
39cec8643bSMichal Nowak 	"SUCCESS",
40cec8643bSMichal Nowak 	"STYLE",
41cec8643bSMichal Nowak 	"WARNING",
42cec8643bSMichal Nowak 	"ERROR",
43cec8643bSMichal Nowak 	"UNSUPP",
44cec8643bSMichal Nowak 	"BADARG",
45cec8643bSMichal Nowak 	"SYSERR"
46cec8643bSMichal Nowak };
47cec8643bSMichal Nowak 
48cec8643bSMichal Nowak static	const char *const type_message[MANDOCERR_MAX] = {
49cec8643bSMichal Nowak 	"ok",
50cec8643bSMichal Nowak 
51cec8643bSMichal Nowak 	"base system convention",
52cec8643bSMichal Nowak 
53cec8643bSMichal Nowak 	"Mdocdate found",
54cec8643bSMichal Nowak 	"Mdocdate missing",
55cec8643bSMichal Nowak 	"unknown architecture",
56cec8643bSMichal Nowak 	"operating system explicitly specified",
57cec8643bSMichal Nowak 	"RCS id missing",
58cec8643bSMichal Nowak 
59cec8643bSMichal Nowak 	"generic style suggestion",
60cec8643bSMichal Nowak 
61*bbf21555SRichard Lowe 	"legacy man(7) date format",
62cec8643bSMichal Nowak 	"normalizing date format to",
63cec8643bSMichal Nowak 	"lower case character in document title",
64cec8643bSMichal Nowak 	"duplicate RCS id",
65cec8643bSMichal Nowak 	"possible typo in section name",
66cec8643bSMichal Nowak 	"unterminated quoted argument",
67cec8643bSMichal Nowak 	"useless macro",
68cec8643bSMichal Nowak 	"consider using OS macro",
69cec8643bSMichal Nowak 	"errnos out of order",
70cec8643bSMichal Nowak 	"duplicate errno",
714d131170SRobert Mustacchi 	"referenced manual not found",
72cec8643bSMichal Nowak 	"trailing delimiter",
73cec8643bSMichal Nowak 	"no blank before trailing delimiter",
74cec8643bSMichal Nowak 	"fill mode already enabled, skipping",
75cec8643bSMichal Nowak 	"fill mode already disabled, skipping",
764d131170SRobert Mustacchi 	"input text line longer than 80 bytes",
77cec8643bSMichal Nowak 	"verbatim \"--\", maybe consider using \\(em",
78cec8643bSMichal Nowak 	"function name without markup",
79cec8643bSMichal Nowak 	"whitespace at end of input line",
80cec8643bSMichal Nowak 	"bad comment style",
81cec8643bSMichal Nowak 
82cec8643bSMichal Nowak 	"generic warning",
83cec8643bSMichal Nowak 
84cec8643bSMichal Nowak 	/* related to the prologue */
85cec8643bSMichal Nowak 	"missing manual title, using UNTITLED",
86cec8643bSMichal Nowak 	"missing manual title, using \"\"",
87cec8643bSMichal Nowak 	"missing manual section, using \"\"",
88cec8643bSMichal Nowak 	"unknown manual section",
894d131170SRobert Mustacchi 	"filename/section mismatch",
904d131170SRobert Mustacchi 	"missing date, using \"\"",
91cec8643bSMichal Nowak 	"cannot parse date, using it verbatim",
92cec8643bSMichal Nowak 	"date in the future, using it anyway",
93cec8643bSMichal Nowak 	"missing Os macro, using \"\"",
94cec8643bSMichal Nowak 	"late prologue macro",
95cec8643bSMichal Nowak 	"prologue macros out of order",
96cec8643bSMichal Nowak 
97cec8643bSMichal Nowak 	/* related to document structure */
98cec8643bSMichal Nowak 	".so is fragile, better use ln(1)",
99cec8643bSMichal Nowak 	"no document body",
100cec8643bSMichal Nowak 	"content before first section header",
101cec8643bSMichal Nowak 	"first section is not \"NAME\"",
102cec8643bSMichal Nowak 	"NAME section without Nm before Nd",
103cec8643bSMichal Nowak 	"NAME section without description",
104cec8643bSMichal Nowak 	"description not at the end of NAME",
105cec8643bSMichal Nowak 	"bad NAME section content",
106cec8643bSMichal Nowak 	"missing comma before name",
107cec8643bSMichal Nowak 	"missing description line, using \"\"",
108cec8643bSMichal Nowak 	"description line outside NAME section",
109cec8643bSMichal Nowak 	"sections out of conventional order",
110cec8643bSMichal Nowak 	"duplicate section title",
111cec8643bSMichal Nowak 	"unexpected section",
112cec8643bSMichal Nowak 	"cross reference to self",
113cec8643bSMichal Nowak 	"unusual Xr order",
114cec8643bSMichal Nowak 	"unusual Xr punctuation",
115cec8643bSMichal Nowak 	"AUTHORS section without An macro",
116cec8643bSMichal Nowak 
117cec8643bSMichal Nowak 	/* related to macros and nesting */
118cec8643bSMichal Nowak 	"obsolete macro",
119cec8643bSMichal Nowak 	"macro neither callable nor escaped",
120cec8643bSMichal Nowak 	"skipping paragraph macro",
121cec8643bSMichal Nowak 	"moving paragraph macro out of list",
122cec8643bSMichal Nowak 	"skipping no-space macro",
123cec8643bSMichal Nowak 	"blocks badly nested",
124cec8643bSMichal Nowak 	"nested displays are not portable",
125cec8643bSMichal Nowak 	"moving content out of list",
126cec8643bSMichal Nowak 	"first macro on line",
127cec8643bSMichal Nowak 	"line scope broken",
128cec8643bSMichal Nowak 	"skipping blank line in line scope",
129cec8643bSMichal Nowak 
130cec8643bSMichal Nowak 	/* related to missing macro arguments */
131cec8643bSMichal Nowak 	"skipping empty request",
132cec8643bSMichal Nowak 	"conditional request controls empty scope",
133cec8643bSMichal Nowak 	"skipping empty macro",
134cec8643bSMichal Nowak 	"empty block",
135cec8643bSMichal Nowak 	"empty argument, using 0n",
136cec8643bSMichal Nowak 	"missing display type, using -ragged",
137cec8643bSMichal Nowak 	"list type is not the first argument",
138cec8643bSMichal Nowak 	"missing -width in -tag list, using 6n",
139cec8643bSMichal Nowak 	"missing utility name, using \"\"",
140cec8643bSMichal Nowak 	"missing function name, using \"\"",
141cec8643bSMichal Nowak 	"empty head in list item",
142cec8643bSMichal Nowak 	"empty list item",
143cec8643bSMichal Nowak 	"missing argument, using next line",
144cec8643bSMichal Nowak 	"missing font type, using \\fR",
145cec8643bSMichal Nowak 	"unknown font type, using \\fR",
146cec8643bSMichal Nowak 	"nothing follows prefix",
147cec8643bSMichal Nowak 	"empty reference block",
148cec8643bSMichal Nowak 	"missing section argument",
149cec8643bSMichal Nowak 	"missing -std argument, adding it",
150cec8643bSMichal Nowak 	"missing option string, using \"\"",
151cec8643bSMichal Nowak 	"missing resource identifier, using \"\"",
152cec8643bSMichal Nowak 	"missing eqn box, using \"\"",
153cec8643bSMichal Nowak 
154cec8643bSMichal Nowak 	/* related to bad macro arguments */
155cec8643bSMichal Nowak 	"duplicate argument",
156cec8643bSMichal Nowak 	"skipping duplicate argument",
157cec8643bSMichal Nowak 	"skipping duplicate display type",
158cec8643bSMichal Nowak 	"skipping duplicate list type",
159cec8643bSMichal Nowak 	"skipping -width argument",
160cec8643bSMichal Nowak 	"wrong number of cells",
161cec8643bSMichal Nowak 	"unknown AT&T UNIX version",
162cec8643bSMichal Nowak 	"comma in function argument",
163cec8643bSMichal Nowak 	"parenthesis in function name",
164cec8643bSMichal Nowak 	"unknown library name",
165cec8643bSMichal Nowak 	"invalid content in Rs block",
166cec8643bSMichal Nowak 	"invalid Boolean argument",
167cec8643bSMichal Nowak 	"argument contains two font escapes",
168cec8643bSMichal Nowak 	"unknown font, skipping request",
169cec8643bSMichal Nowak 	"odd number of characters in request",
170cec8643bSMichal Nowak 
171cec8643bSMichal Nowak 	/* related to plain text */
172cec8643bSMichal Nowak 	"blank line in fill mode, using .sp",
173cec8643bSMichal Nowak 	"tab in filled text",
174cec8643bSMichal Nowak 	"new sentence, new line",
175cec8643bSMichal Nowak 	"invalid escape sequence",
176cec8643bSMichal Nowak 	"undefined escape, printing literally",
177cec8643bSMichal Nowak 	"undefined string, using \"\"",
178cec8643bSMichal Nowak 
179cec8643bSMichal Nowak 	/* related to tables */
180cec8643bSMichal Nowak 	"tbl line starts with span",
181cec8643bSMichal Nowak 	"tbl column starts with span",
182cec8643bSMichal Nowak 	"skipping vertical bar in tbl layout",
183cec8643bSMichal Nowak 
184cec8643bSMichal Nowak 	"generic error",
185cec8643bSMichal Nowak 
186cec8643bSMichal Nowak 	/* related to tables */
187cec8643bSMichal Nowak 	"non-alphabetic character in tbl options",
188cec8643bSMichal Nowak 	"skipping unknown tbl option",
189cec8643bSMichal Nowak 	"missing tbl option argument",
190cec8643bSMichal Nowak 	"wrong tbl option argument size",
191cec8643bSMichal Nowak 	"empty tbl layout",
192cec8643bSMichal Nowak 	"invalid character in tbl layout",
193cec8643bSMichal Nowak 	"unmatched parenthesis in tbl layout",
1944d131170SRobert Mustacchi 	"ignoring excessive spacing in tbl layout",
195cec8643bSMichal Nowak 	"tbl without any data cells",
196cec8643bSMichal Nowak 	"ignoring data in spanned tbl cell",
197cec8643bSMichal Nowak 	"ignoring extra tbl data cells",
198cec8643bSMichal Nowak 	"data block open at end of tbl",
199cec8643bSMichal Nowak 
200cec8643bSMichal Nowak 	/* related to document structure and macros */
201cec8643bSMichal Nowak 	"duplicate prologue macro",
202cec8643bSMichal Nowak 	"skipping late title macro",
203cec8643bSMichal Nowak 	"input stack limit exceeded, infinite loop?",
204cec8643bSMichal Nowak 	"skipping bad character",
205cec8643bSMichal Nowak 	"skipping unknown macro",
206cec8643bSMichal Nowak 	"ignoring request outside macro",
207cec8643bSMichal Nowak 	"skipping insecure request",
208cec8643bSMichal Nowak 	"skipping item outside list",
209cec8643bSMichal Nowak 	"skipping column outside column list",
210cec8643bSMichal Nowak 	"skipping end of block that is not open",
211cec8643bSMichal Nowak 	"fewer RS blocks open, skipping",
212cec8643bSMichal Nowak 	"inserting missing end of block",
213cec8643bSMichal Nowak 	"appending missing end of block",
214cec8643bSMichal Nowak 
215cec8643bSMichal Nowak 	/* related to request and macro arguments */
216cec8643bSMichal Nowak 	"escaped character not allowed in a name",
217cec8643bSMichal Nowak 	"using macro argument outside macro",
218cec8643bSMichal Nowak 	"argument number is not numeric",
219cec8643bSMichal Nowak 	"NOT IMPLEMENTED: Bd -file",
220cec8643bSMichal Nowak 	"skipping display without arguments",
221cec8643bSMichal Nowak 	"missing list type, using -item",
222cec8643bSMichal Nowak 	"argument is not numeric, using 1",
223cec8643bSMichal Nowak 	"argument is not a character",
224cec8643bSMichal Nowak 	"missing manual name, using \"\"",
225cec8643bSMichal Nowak 	"uname(3) system call failed, using UNKNOWN",
226cec8643bSMichal Nowak 	"unknown standard specifier",
227cec8643bSMichal Nowak 	"skipping request without numeric argument",
228cec8643bSMichal Nowak 	"excessive shift",
229cec8643bSMichal Nowak 	"NOT IMPLEMENTED: .so with absolute path or \"..\"",
230cec8643bSMichal Nowak 	".so request failed",
2314d131170SRobert Mustacchi 	"skipping tag containing whitespace",
232cec8643bSMichal Nowak 	"skipping all arguments",
233cec8643bSMichal Nowak 	"skipping excess arguments",
234cec8643bSMichal Nowak 	"divide by zero",
235cec8643bSMichal Nowak 
236cec8643bSMichal Nowak 	"unsupported feature",
237cec8643bSMichal Nowak 	"input too large",
238cec8643bSMichal Nowak 	"unsupported control character",
239cec8643bSMichal Nowak 	"unsupported escape sequence",
240cec8643bSMichal Nowak 	"unsupported roff request",
241cec8643bSMichal Nowak 	"nested .while loops",
242cec8643bSMichal Nowak 	"end of scope with open .while loop",
243cec8643bSMichal Nowak 	"end of .while loop in inner scope",
244cec8643bSMichal Nowak 	"cannot continue this .while loop",
245cec8643bSMichal Nowak 	"eqn delim option in tbl",
246cec8643bSMichal Nowak 	"unsupported tbl layout modifier",
247cec8643bSMichal Nowak 	"ignoring macro in table",
2484d131170SRobert Mustacchi 	"skipping tbl in -Tman mode",
2494d131170SRobert Mustacchi 	"skipping eqn in -Tman mode",
2504d131170SRobert Mustacchi 
2514d131170SRobert Mustacchi 	/* bad command line arguments */
2524d131170SRobert Mustacchi 	NULL,
2534d131170SRobert Mustacchi 	"bad command line argument",
2544d131170SRobert Mustacchi 	"duplicate command line argument",
2554d131170SRobert Mustacchi 	"option has a superfluous value",
2564d131170SRobert Mustacchi 	"missing option value",
2574d131170SRobert Mustacchi 	"bad option value",
2584d131170SRobert Mustacchi 	"duplicate option value",
2594d131170SRobert Mustacchi 	"no such tag",
260*bbf21555SRichard Lowe 	"-Tmarkdown unsupported for man(7) input",
2614d131170SRobert Mustacchi 
2624d131170SRobert Mustacchi 	/* system errors */
2634d131170SRobert Mustacchi 	NULL,
2644d131170SRobert Mustacchi 	"dup",
2654d131170SRobert Mustacchi 	"exec",
2664d131170SRobert Mustacchi 	"fdopen",
2674d131170SRobert Mustacchi 	"fflush",
2684d131170SRobert Mustacchi 	"fork",
2694d131170SRobert Mustacchi 	"fstat",
2704d131170SRobert Mustacchi 	"getline",
2714d131170SRobert Mustacchi 	"glob",
2724d131170SRobert Mustacchi 	"gzclose",
2734d131170SRobert Mustacchi 	"gzdopen",
2744d131170SRobert Mustacchi 	"mkstemp",
2754d131170SRobert Mustacchi 	"open",
2764d131170SRobert Mustacchi 	"pledge",
2774d131170SRobert Mustacchi 	"read",
2784d131170SRobert Mustacchi 	"wait",
2794d131170SRobert Mustacchi 	"write",
280cec8643bSMichal Nowak };
281cec8643bSMichal Nowak 
282cec8643bSMichal Nowak static	FILE		*fileptr = NULL;
283cec8643bSMichal Nowak static	const char	*filename = NULL;
2844d131170SRobert Mustacchi static	enum mandocerr	 min_type = MANDOCERR_BADARG;
285cec8643bSMichal Nowak static	enum mandoclevel rc = MANDOCLEVEL_OK;
286cec8643bSMichal Nowak 
287cec8643bSMichal Nowak 
288cec8643bSMichal Nowak void
mandoc_msg_setoutfile(FILE * fp)289cec8643bSMichal Nowak mandoc_msg_setoutfile(FILE *fp)
290cec8643bSMichal Nowak {
291cec8643bSMichal Nowak 	fileptr = fp;
292cec8643bSMichal Nowak }
293cec8643bSMichal Nowak 
294cec8643bSMichal Nowak const char *
mandoc_msg_getinfilename(void)295cec8643bSMichal Nowak mandoc_msg_getinfilename(void)
296cec8643bSMichal Nowak {
297cec8643bSMichal Nowak 	return filename;
298cec8643bSMichal Nowak }
299cec8643bSMichal Nowak 
300cec8643bSMichal Nowak void
mandoc_msg_setinfilename(const char * fn)301cec8643bSMichal Nowak mandoc_msg_setinfilename(const char *fn)
302cec8643bSMichal Nowak {
303cec8643bSMichal Nowak 	filename = fn;
304cec8643bSMichal Nowak }
305cec8643bSMichal Nowak 
306cec8643bSMichal Nowak enum mandocerr
mandoc_msg_getmin(void)307cec8643bSMichal Nowak mandoc_msg_getmin(void)
308cec8643bSMichal Nowak {
309cec8643bSMichal Nowak 	return min_type;
310cec8643bSMichal Nowak }
311cec8643bSMichal Nowak 
312cec8643bSMichal Nowak void
mandoc_msg_setmin(enum mandocerr t)313cec8643bSMichal Nowak mandoc_msg_setmin(enum mandocerr t)
314cec8643bSMichal Nowak {
315cec8643bSMichal Nowak 	min_type = t;
316cec8643bSMichal Nowak }
317cec8643bSMichal Nowak 
318cec8643bSMichal Nowak enum mandoclevel
mandoc_msg_getrc(void)319cec8643bSMichal Nowak mandoc_msg_getrc(void)
320cec8643bSMichal Nowak {
321cec8643bSMichal Nowak 	return rc;
322cec8643bSMichal Nowak }
323cec8643bSMichal Nowak 
324cec8643bSMichal Nowak void
mandoc_msg_setrc(enum mandoclevel level)325cec8643bSMichal Nowak mandoc_msg_setrc(enum mandoclevel level)
326cec8643bSMichal Nowak {
327cec8643bSMichal Nowak 	if (rc < level)
328cec8643bSMichal Nowak 		rc = level;
329cec8643bSMichal Nowak }
330cec8643bSMichal Nowak 
331cec8643bSMichal Nowak void
mandoc_msg(enum mandocerr t,int line,int col,const char * fmt,...)332cec8643bSMichal Nowak mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...)
333cec8643bSMichal Nowak {
334cec8643bSMichal Nowak 	va_list			 ap;
335cec8643bSMichal Nowak 	enum mandoclevel	 level;
336cec8643bSMichal Nowak 
3374d131170SRobert Mustacchi 	if (t < min_type)
338cec8643bSMichal Nowak 		return;
339cec8643bSMichal Nowak 
3404d131170SRobert Mustacchi 	level = MANDOCLEVEL_SYSERR;
341cec8643bSMichal Nowak 	while (t < lowest_type[level])
342cec8643bSMichal Nowak 		level--;
343cec8643bSMichal Nowak 	mandoc_msg_setrc(level);
344cec8643bSMichal Nowak 
345cec8643bSMichal Nowak 	if (fileptr == NULL)
346cec8643bSMichal Nowak 		return;
347cec8643bSMichal Nowak 
348cec8643bSMichal Nowak 	fprintf(fileptr, "%s:", getprogname());
349cec8643bSMichal Nowak 	if (filename != NULL)
350cec8643bSMichal Nowak 		fprintf(fileptr, " %s:", filename);
351cec8643bSMichal Nowak 
352cec8643bSMichal Nowak 	if (line > 0)
353cec8643bSMichal Nowak 		fprintf(fileptr, "%d:%d:", line, col + 1);
354cec8643bSMichal Nowak 
355cec8643bSMichal Nowak 	fprintf(fileptr, " %s", level_name[level]);
356cec8643bSMichal Nowak 	if (type_message[t] != NULL)
357cec8643bSMichal Nowak 		fprintf(fileptr, ": %s", type_message[t]);
358cec8643bSMichal Nowak 
359cec8643bSMichal Nowak 	if (fmt != NULL) {
360cec8643bSMichal Nowak 		fprintf(fileptr, ": ");
361cec8643bSMichal Nowak 		va_start(ap, fmt);
362cec8643bSMichal Nowak 		vfprintf(fileptr, fmt, ap);
363cec8643bSMichal Nowak 		va_end(ap);
364cec8643bSMichal Nowak 	}
365cec8643bSMichal Nowak 	fputc('\n', fileptr);
366cec8643bSMichal Nowak }
3674d131170SRobert Mustacchi 
3684d131170SRobert Mustacchi void
mandoc_msg_summary(void)3694d131170SRobert Mustacchi mandoc_msg_summary(void)
3704d131170SRobert Mustacchi {
3714d131170SRobert Mustacchi 	if (fileptr != NULL && rc != MANDOCLEVEL_OK)
3724d131170SRobert Mustacchi 		fprintf(fileptr,
3734d131170SRobert Mustacchi 		    "%s: see above the output for %s messages\n",
3744d131170SRobert Mustacchi 		    getprogname(), level_name[rc]);
3754d131170SRobert Mustacchi }
376