xref: /netbsd-src/external/bsd/mdocml/dist/mandoc_msg.c (revision 544c191c349c1704c9d5e679d12ec15cff579663)
1*544c191cSchristos /*	Id: mandoc_msg.c,v 1.6 2019/03/06 15:55:38 schwarze Exp  */
2*544c191cSchristos /*
3*544c191cSchristos  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*544c191cSchristos  * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
5*544c191cSchristos  *
6*544c191cSchristos  * Permission to use, copy, modify, and distribute this software for any
7*544c191cSchristos  * purpose with or without fee is hereby granted, provided that the above
8*544c191cSchristos  * copyright notice and this permission notice appear in all copies.
9*544c191cSchristos  *
10*544c191cSchristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11*544c191cSchristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*544c191cSchristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13*544c191cSchristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*544c191cSchristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*544c191cSchristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*544c191cSchristos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*544c191cSchristos  */
18*544c191cSchristos #include "config.h"
19*544c191cSchristos 
20*544c191cSchristos #include <stdarg.h>
21*544c191cSchristos #include <stdio.h>
22*544c191cSchristos #include <stdlib.h>
23*544c191cSchristos 
24*544c191cSchristos #include "mandoc.h"
25*544c191cSchristos 
26*544c191cSchristos static	const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = {
27*544c191cSchristos 	MANDOCERR_OK,
28*544c191cSchristos 	MANDOCERR_OK,
29*544c191cSchristos 	MANDOCERR_WARNING,
30*544c191cSchristos 	MANDOCERR_ERROR,
31*544c191cSchristos 	MANDOCERR_UNSUPP,
32*544c191cSchristos 	MANDOCERR_MAX,
33*544c191cSchristos 	MANDOCERR_MAX
34*544c191cSchristos };
35*544c191cSchristos 
36*544c191cSchristos static	const char *const level_name[MANDOCLEVEL_MAX] = {
37*544c191cSchristos 	"SUCCESS",
38*544c191cSchristos 	"STYLE",
39*544c191cSchristos 	"WARNING",
40*544c191cSchristos 	"ERROR",
41*544c191cSchristos 	"UNSUPP",
42*544c191cSchristos 	"BADARG",
43*544c191cSchristos 	"SYSERR"
44*544c191cSchristos };
45*544c191cSchristos 
46*544c191cSchristos static	const char *const type_message[MANDOCERR_MAX] = {
47*544c191cSchristos 	"ok",
48*544c191cSchristos 
49*544c191cSchristos 	"base system convention",
50*544c191cSchristos 
51*544c191cSchristos 	"Mdocdate found",
52*544c191cSchristos 	"Mdocdate missing",
53*544c191cSchristos 	"unknown architecture",
54*544c191cSchristos 	"operating system explicitly specified",
55*544c191cSchristos 	"RCS id missing",
56*544c191cSchristos 	"referenced manual not found",
57*544c191cSchristos 
58*544c191cSchristos 	"generic style suggestion",
59*544c191cSchristos 
60*544c191cSchristos 	"legacy man(7) date format",
61*544c191cSchristos 	"normalizing date format to",
62*544c191cSchristos 	"lower case character in document title",
63*544c191cSchristos 	"duplicate RCS id",
64*544c191cSchristos 	"possible typo in section name",
65*544c191cSchristos 	"unterminated quoted argument",
66*544c191cSchristos 	"useless macro",
67*544c191cSchristos 	"consider using OS macro",
68*544c191cSchristos 	"errnos out of order",
69*544c191cSchristos 	"duplicate errno",
70*544c191cSchristos 	"trailing delimiter",
71*544c191cSchristos 	"no blank before trailing delimiter",
72*544c191cSchristos 	"fill mode already enabled, skipping",
73*544c191cSchristos 	"fill mode already disabled, skipping",
74*544c191cSchristos 	"verbatim \"--\", maybe consider using \\(em",
75*544c191cSchristos 	"function name without markup",
76*544c191cSchristos 	"whitespace at end of input line",
77*544c191cSchristos 	"bad comment style",
78*544c191cSchristos 
79*544c191cSchristos 	"generic warning",
80*544c191cSchristos 
81*544c191cSchristos 	/* related to the prologue */
82*544c191cSchristos 	"missing manual title, using UNTITLED",
83*544c191cSchristos 	"missing manual title, using \"\"",
84*544c191cSchristos 	"missing manual section, using \"\"",
85*544c191cSchristos 	"unknown manual section",
86*544c191cSchristos 	"missing date, using today's date",
87*544c191cSchristos 	"cannot parse date, using it verbatim",
88*544c191cSchristos 	"date in the future, using it anyway",
89*544c191cSchristos 	"missing Os macro, using \"\"",
90*544c191cSchristos 	"late prologue macro",
91*544c191cSchristos 	"prologue macros out of order",
92*544c191cSchristos 
93*544c191cSchristos 	/* related to document structure */
94*544c191cSchristos 	".so is fragile, better use ln(1)",
95*544c191cSchristos 	"no document body",
96*544c191cSchristos 	"content before first section header",
97*544c191cSchristos 	"first section is not \"NAME\"",
98*544c191cSchristos 	"NAME section without Nm before Nd",
99*544c191cSchristos 	"NAME section without description",
100*544c191cSchristos 	"description not at the end of NAME",
101*544c191cSchristos 	"bad NAME section content",
102*544c191cSchristos 	"missing comma before name",
103*544c191cSchristos 	"missing description line, using \"\"",
104*544c191cSchristos 	"description line outside NAME section",
105*544c191cSchristos 	"sections out of conventional order",
106*544c191cSchristos 	"duplicate section title",
107*544c191cSchristos 	"unexpected section",
108*544c191cSchristos 	"cross reference to self",
109*544c191cSchristos 	"unusual Xr order",
110*544c191cSchristos 	"unusual Xr punctuation",
111*544c191cSchristos 	"AUTHORS section without An macro",
112*544c191cSchristos 
113*544c191cSchristos 	/* related to macros and nesting */
114*544c191cSchristos 	"obsolete macro",
115*544c191cSchristos 	"macro neither callable nor escaped",
116*544c191cSchristos 	"skipping paragraph macro",
117*544c191cSchristos 	"moving paragraph macro out of list",
118*544c191cSchristos 	"skipping no-space macro",
119*544c191cSchristos 	"blocks badly nested",
120*544c191cSchristos 	"nested displays are not portable",
121*544c191cSchristos 	"moving content out of list",
122*544c191cSchristos 	"first macro on line",
123*544c191cSchristos 	"line scope broken",
124*544c191cSchristos 	"skipping blank line in line scope",
125*544c191cSchristos 
126*544c191cSchristos 	/* related to missing macro arguments */
127*544c191cSchristos 	"skipping empty request",
128*544c191cSchristos 	"conditional request controls empty scope",
129*544c191cSchristos 	"skipping empty macro",
130*544c191cSchristos 	"empty block",
131*544c191cSchristos 	"empty argument, using 0n",
132*544c191cSchristos 	"missing display type, using -ragged",
133*544c191cSchristos 	"list type is not the first argument",
134*544c191cSchristos 	"missing -width in -tag list, using 6n",
135*544c191cSchristos 	"missing utility name, using \"\"",
136*544c191cSchristos 	"missing function name, using \"\"",
137*544c191cSchristos 	"empty head in list item",
138*544c191cSchristos 	"empty list item",
139*544c191cSchristos 	"missing argument, using next line",
140*544c191cSchristos 	"missing font type, using \\fR",
141*544c191cSchristos 	"unknown font type, using \\fR",
142*544c191cSchristos 	"nothing follows prefix",
143*544c191cSchristos 	"empty reference block",
144*544c191cSchristos 	"missing section argument",
145*544c191cSchristos 	"missing -std argument, adding it",
146*544c191cSchristos 	"missing option string, using \"\"",
147*544c191cSchristos 	"missing resource identifier, using \"\"",
148*544c191cSchristos 	"missing eqn box, using \"\"",
149*544c191cSchristos 
150*544c191cSchristos 	/* related to bad macro arguments */
151*544c191cSchristos 	"duplicate argument",
152*544c191cSchristos 	"skipping duplicate argument",
153*544c191cSchristos 	"skipping duplicate display type",
154*544c191cSchristos 	"skipping duplicate list type",
155*544c191cSchristos 	"skipping -width argument",
156*544c191cSchristos 	"wrong number of cells",
157*544c191cSchristos 	"unknown AT&T UNIX version",
158*544c191cSchristos 	"comma in function argument",
159*544c191cSchristos 	"parenthesis in function name",
160*544c191cSchristos 	"unknown library name",
161*544c191cSchristos 	"invalid content in Rs block",
162*544c191cSchristos 	"invalid Boolean argument",
163*544c191cSchristos 	"argument contains two font escapes",
164*544c191cSchristos 	"unknown font, skipping request",
165*544c191cSchristos 	"odd number of characters in request",
166*544c191cSchristos 
167*544c191cSchristos 	/* related to plain text */
168*544c191cSchristos 	"blank line in fill mode, using .sp",
169*544c191cSchristos 	"tab in filled text",
170*544c191cSchristos 	"new sentence, new line",
171*544c191cSchristos 	"invalid escape sequence",
172*544c191cSchristos 	"undefined escape, printing literally",
173*544c191cSchristos 	"undefined string, using \"\"",
174*544c191cSchristos 
175*544c191cSchristos 	/* related to tables */
176*544c191cSchristos 	"tbl line starts with span",
177*544c191cSchristos 	"tbl column starts with span",
178*544c191cSchristos 	"skipping vertical bar in tbl layout",
179*544c191cSchristos 
180*544c191cSchristos 	"generic error",
181*544c191cSchristos 
182*544c191cSchristos 	/* related to tables */
183*544c191cSchristos 	"non-alphabetic character in tbl options",
184*544c191cSchristos 	"skipping unknown tbl option",
185*544c191cSchristos 	"missing tbl option argument",
186*544c191cSchristos 	"wrong tbl option argument size",
187*544c191cSchristos 	"empty tbl layout",
188*544c191cSchristos 	"invalid character in tbl layout",
189*544c191cSchristos 	"unmatched parenthesis in tbl layout",
190*544c191cSchristos 	"tbl without any data cells",
191*544c191cSchristos 	"ignoring data in spanned tbl cell",
192*544c191cSchristos 	"ignoring extra tbl data cells",
193*544c191cSchristos 	"data block open at end of tbl",
194*544c191cSchristos 
195*544c191cSchristos 	/* related to document structure and macros */
196*544c191cSchristos 	NULL,
197*544c191cSchristos 	"duplicate prologue macro",
198*544c191cSchristos 	"skipping late title macro",
199*544c191cSchristos 	"input stack limit exceeded, infinite loop?",
200*544c191cSchristos 	"skipping bad character",
201*544c191cSchristos 	"skipping unknown macro",
202*544c191cSchristos 	"ignoring request outside macro",
203*544c191cSchristos 	"skipping insecure request",
204*544c191cSchristos 	"skipping item outside list",
205*544c191cSchristos 	"skipping column outside column list",
206*544c191cSchristos 	"skipping end of block that is not open",
207*544c191cSchristos 	"fewer RS blocks open, skipping",
208*544c191cSchristos 	"inserting missing end of block",
209*544c191cSchristos 	"appending missing end of block",
210*544c191cSchristos 
211*544c191cSchristos 	/* related to request and macro arguments */
212*544c191cSchristos 	"escaped character not allowed in a name",
213*544c191cSchristos 	"using macro argument outside macro",
214*544c191cSchristos 	"argument number is not numeric",
215*544c191cSchristos 	"NOT IMPLEMENTED: Bd -file",
216*544c191cSchristos 	"skipping display without arguments",
217*544c191cSchristos 	"missing list type, using -item",
218*544c191cSchristos 	"argument is not numeric, using 1",
219*544c191cSchristos 	"argument is not a character",
220*544c191cSchristos 	"missing manual name, using \"\"",
221*544c191cSchristos 	"uname(3) system call failed, using UNKNOWN",
222*544c191cSchristos 	"unknown standard specifier",
223*544c191cSchristos 	"skipping request without numeric argument",
224*544c191cSchristos 	"excessive shift",
225*544c191cSchristos 	"NOT IMPLEMENTED: .so with absolute path or \"..\"",
226*544c191cSchristos 	".so request failed",
227*544c191cSchristos 	"skipping all arguments",
228*544c191cSchristos 	"skipping excess arguments",
229*544c191cSchristos 	"divide by zero",
230*544c191cSchristos 
231*544c191cSchristos 	"unsupported feature",
232*544c191cSchristos 	"input too large",
233*544c191cSchristos 	"unsupported control character",
234*544c191cSchristos 	"unsupported escape sequence",
235*544c191cSchristos 	"unsupported roff request",
236*544c191cSchristos 	"nested .while loops",
237*544c191cSchristos 	"end of scope with open .while loop",
238*544c191cSchristos 	"end of .while loop in inner scope",
239*544c191cSchristos 	"cannot continue this .while loop",
240*544c191cSchristos 	"eqn delim option in tbl",
241*544c191cSchristos 	"unsupported tbl layout modifier",
242*544c191cSchristos 	"ignoring macro in table",
243*544c191cSchristos };
244*544c191cSchristos 
245*544c191cSchristos static	FILE		*fileptr = NULL;
246*544c191cSchristos static	const char	*filename = NULL;
247*544c191cSchristos static	enum mandocerr	 min_type = MANDOCERR_MAX;
248*544c191cSchristos static	enum mandoclevel rc = MANDOCLEVEL_OK;
249*544c191cSchristos 
250*544c191cSchristos 
251*544c191cSchristos void
mandoc_msg_setoutfile(FILE * fp)252*544c191cSchristos mandoc_msg_setoutfile(FILE *fp)
253*544c191cSchristos {
254*544c191cSchristos 	fileptr = fp;
255*544c191cSchristos }
256*544c191cSchristos 
257*544c191cSchristos const char *
mandoc_msg_getinfilename(void)258*544c191cSchristos mandoc_msg_getinfilename(void)
259*544c191cSchristos {
260*544c191cSchristos 	return filename;
261*544c191cSchristos }
262*544c191cSchristos 
263*544c191cSchristos void
mandoc_msg_setinfilename(const char * fn)264*544c191cSchristos mandoc_msg_setinfilename(const char *fn)
265*544c191cSchristos {
266*544c191cSchristos 	filename = fn;
267*544c191cSchristos }
268*544c191cSchristos 
269*544c191cSchristos enum mandocerr
mandoc_msg_getmin(void)270*544c191cSchristos mandoc_msg_getmin(void)
271*544c191cSchristos {
272*544c191cSchristos 	return min_type;
273*544c191cSchristos }
274*544c191cSchristos 
275*544c191cSchristos void
mandoc_msg_setmin(enum mandocerr t)276*544c191cSchristos mandoc_msg_setmin(enum mandocerr t)
277*544c191cSchristos {
278*544c191cSchristos 	min_type = t;
279*544c191cSchristos }
280*544c191cSchristos 
281*544c191cSchristos enum mandoclevel
mandoc_msg_getrc(void)282*544c191cSchristos mandoc_msg_getrc(void)
283*544c191cSchristos {
284*544c191cSchristos 	return rc;
285*544c191cSchristos }
286*544c191cSchristos 
287*544c191cSchristos void
mandoc_msg_setrc(enum mandoclevel level)288*544c191cSchristos mandoc_msg_setrc(enum mandoclevel level)
289*544c191cSchristos {
290*544c191cSchristos 	if (rc < level)
291*544c191cSchristos 		rc = level;
292*544c191cSchristos }
293*544c191cSchristos 
294*544c191cSchristos void
mandoc_msg(enum mandocerr t,int line,int col,const char * fmt,...)295*544c191cSchristos mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...)
296*544c191cSchristos {
297*544c191cSchristos 	va_list			 ap;
298*544c191cSchristos 	enum mandoclevel	 level;
299*544c191cSchristos 
300*544c191cSchristos 	if (t < min_type && t != MANDOCERR_FILE)
301*544c191cSchristos 		return;
302*544c191cSchristos 
303*544c191cSchristos 	level = MANDOCLEVEL_UNSUPP;
304*544c191cSchristos 	while (t < lowest_type[level])
305*544c191cSchristos 		level--;
306*544c191cSchristos 	mandoc_msg_setrc(level);
307*544c191cSchristos 
308*544c191cSchristos 	if (fileptr == NULL)
309*544c191cSchristos 		return;
310*544c191cSchristos 
311*544c191cSchristos 	fprintf(fileptr, "%s:", getprogname());
312*544c191cSchristos 	if (filename != NULL)
313*544c191cSchristos 		fprintf(fileptr, " %s:", filename);
314*544c191cSchristos 
315*544c191cSchristos 	if (line > 0)
316*544c191cSchristos 		fprintf(fileptr, "%d:%d:", line, col + 1);
317*544c191cSchristos 
318*544c191cSchristos 	fprintf(fileptr, " %s", level_name[level]);
319*544c191cSchristos 	if (type_message[t] != NULL)
320*544c191cSchristos 		fprintf(fileptr, ": %s", type_message[t]);
321*544c191cSchristos 
322*544c191cSchristos 	if (fmt != NULL) {
323*544c191cSchristos 		fprintf(fileptr, ": ");
324*544c191cSchristos 		va_start(ap, fmt);
325*544c191cSchristos 		vfprintf(fileptr, fmt, ap);
326*544c191cSchristos 		va_end(ap);
327*544c191cSchristos 	}
328*544c191cSchristos 	fputc('\n', fileptr);
329*544c191cSchristos }
330