xref: /netbsd-src/external/bsd/mdocml/dist/roff_validate.c (revision 544c191c349c1704c9d5e679d12ec15cff579663)
1*544c191cSchristos /*	Id: roff_validate.c,v 1.18 2018/12/31 09:02:37 schwarze Exp  */
2c9bcef03Schristos /*
3*544c191cSchristos  * Copyright (c) 2010, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
4c9bcef03Schristos  *
5c9bcef03Schristos  * Permission to use, copy, modify, and distribute this software for any
6c9bcef03Schristos  * purpose with or without fee is hereby granted, provided that the above
7c9bcef03Schristos  * copyright notice and this permission notice appear in all copies.
8c9bcef03Schristos  *
9c9bcef03Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c9bcef03Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c9bcef03Schristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c9bcef03Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c9bcef03Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c9bcef03Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c9bcef03Schristos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c9bcef03Schristos  */
17c9bcef03Schristos #include <sys/types.h>
18c9bcef03Schristos 
19c9bcef03Schristos #include <assert.h>
20*544c191cSchristos #include <stdio.h>
21*544c191cSchristos #include <string.h>
22c9bcef03Schristos 
23c9bcef03Schristos #include "mandoc.h"
24c9bcef03Schristos #include "roff.h"
25c9bcef03Schristos #include "libmandoc.h"
26c9bcef03Schristos #include "roff_int.h"
27c9bcef03Schristos 
28c9bcef03Schristos #define	ROFF_VALID_ARGS struct roff_man *man, struct roff_node *n
29c9bcef03Schristos 
30c9bcef03Schristos typedef	void	(*roff_valid_fp)(ROFF_VALID_ARGS);
31c9bcef03Schristos 
32*544c191cSchristos static	void	  roff_valid_br(ROFF_VALID_ARGS);
33*544c191cSchristos static	void	  roff_valid_fi(ROFF_VALID_ARGS);
34c9bcef03Schristos static	void	  roff_valid_ft(ROFF_VALID_ARGS);
35*544c191cSchristos static	void	  roff_valid_nf(ROFF_VALID_ARGS);
36*544c191cSchristos static	void	  roff_valid_sp(ROFF_VALID_ARGS);
37c9bcef03Schristos 
38c9bcef03Schristos static	const roff_valid_fp roff_valids[ROFF_MAX] = {
39*544c191cSchristos 	roff_valid_br,  /* br */
40c9bcef03Schristos 	NULL,  /* ce */
41*544c191cSchristos 	roff_valid_fi,  /* fi */
42c9bcef03Schristos 	roff_valid_ft,  /* ft */
43c9bcef03Schristos 	NULL,  /* ll */
44c9bcef03Schristos 	NULL,  /* mc */
45*544c191cSchristos 	roff_valid_nf,  /* nf */
46c9bcef03Schristos 	NULL,  /* po */
47c9bcef03Schristos 	NULL,  /* rj */
48*544c191cSchristos 	roff_valid_sp,  /* sp */
49c9bcef03Schristos 	NULL,  /* ta */
50c9bcef03Schristos 	NULL,  /* ti */
51c9bcef03Schristos };
52c9bcef03Schristos 
53c9bcef03Schristos 
54c9bcef03Schristos void
roff_validate(struct roff_man * man)55c9bcef03Schristos roff_validate(struct roff_man *man)
56c9bcef03Schristos {
57c9bcef03Schristos 	struct roff_node	*n;
58c9bcef03Schristos 
59c9bcef03Schristos 	n = man->last;
60c9bcef03Schristos 	assert(n->tok < ROFF_MAX);
61c9bcef03Schristos 	if (roff_valids[n->tok] != NULL)
62c9bcef03Schristos 		(*roff_valids[n->tok])(man, n);
63c9bcef03Schristos }
64c9bcef03Schristos 
65c9bcef03Schristos static void
roff_valid_br(ROFF_VALID_ARGS)66*544c191cSchristos roff_valid_br(ROFF_VALID_ARGS)
67*544c191cSchristos {
68*544c191cSchristos 	struct roff_node	*np;
69*544c191cSchristos 
70*544c191cSchristos 	if (n->next != NULL && n->next->type == ROFFT_TEXT &&
71*544c191cSchristos 	    *n->next->string == ' ') {
72*544c191cSchristos 		mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
73*544c191cSchristos 		    "br before text line with leading blank");
74*544c191cSchristos 		roff_node_delete(man, n);
75*544c191cSchristos 		return;
76*544c191cSchristos 	}
77*544c191cSchristos 
78*544c191cSchristos 	if ((np = n->prev) == NULL)
79*544c191cSchristos 		return;
80*544c191cSchristos 
81*544c191cSchristos 	switch (np->tok) {
82*544c191cSchristos 	case ROFF_br:
83*544c191cSchristos 	case ROFF_sp:
84*544c191cSchristos 	case MDOC_Pp:
85*544c191cSchristos 		mandoc_msg(MANDOCERR_PAR_SKIP,
86*544c191cSchristos 		    n->line, n->pos, "br after %s", roff_name[np->tok]);
87*544c191cSchristos 		roff_node_delete(man, n);
88*544c191cSchristos 		break;
89*544c191cSchristos 	default:
90*544c191cSchristos 		break;
91*544c191cSchristos 	}
92*544c191cSchristos }
93*544c191cSchristos 
94*544c191cSchristos static void
roff_valid_fi(ROFF_VALID_ARGS)95*544c191cSchristos roff_valid_fi(ROFF_VALID_ARGS)
96*544c191cSchristos {
97*544c191cSchristos 	if ((n->flags & NODE_NOFILL) == 0)
98*544c191cSchristos 		mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "fi");
99*544c191cSchristos }
100*544c191cSchristos 
101*544c191cSchristos static void
roff_valid_ft(ROFF_VALID_ARGS)102c9bcef03Schristos roff_valid_ft(ROFF_VALID_ARGS)
103c9bcef03Schristos {
104*544c191cSchristos 	const char		*cp;
105c9bcef03Schristos 
106c9bcef03Schristos 	if (n->child == NULL) {
107c9bcef03Schristos 		man->next = ROFF_NEXT_CHILD;
108c9bcef03Schristos 		roff_word_alloc(man, n->line, n->pos, "P");
109c9bcef03Schristos 		man->last = n;
110c9bcef03Schristos 		return;
111c9bcef03Schristos 	}
112c9bcef03Schristos 
113c9bcef03Schristos 	cp = n->child->string;
114*544c191cSchristos 	if (mandoc_font(cp, (int)strlen(cp)) != ESCAPE_ERROR)
115c9bcef03Schristos 		return;
116*544c191cSchristos 	mandoc_msg(MANDOCERR_FT_BAD, n->line, n->pos, "ft %s", cp);
117*544c191cSchristos 	roff_node_delete(man, n);
118*544c191cSchristos }
119*544c191cSchristos 
120*544c191cSchristos static void
roff_valid_nf(ROFF_VALID_ARGS)121*544c191cSchristos roff_valid_nf(ROFF_VALID_ARGS)
122*544c191cSchristos {
123*544c191cSchristos 	if (n->flags & NODE_NOFILL)
124*544c191cSchristos 		mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "nf");
125*544c191cSchristos }
126*544c191cSchristos 
127*544c191cSchristos static void
roff_valid_sp(ROFF_VALID_ARGS)128*544c191cSchristos roff_valid_sp(ROFF_VALID_ARGS)
129*544c191cSchristos {
130*544c191cSchristos 	struct roff_node	*np;
131*544c191cSchristos 
132*544c191cSchristos 	if ((np = n->prev) == NULL)
133*544c191cSchristos 		return;
134*544c191cSchristos 
135*544c191cSchristos 	switch (np->tok) {
136*544c191cSchristos 	case ROFF_br:
137*544c191cSchristos 		mandoc_msg(MANDOCERR_PAR_SKIP,
138*544c191cSchristos 		    np->line, np->pos, "br before sp");
139*544c191cSchristos 		roff_node_delete(man, np);
140c9bcef03Schristos 		break;
141*544c191cSchristos 	case MDOC_Pp:
142*544c191cSchristos 		mandoc_msg(MANDOCERR_PAR_SKIP,
143*544c191cSchristos 		    n->line, n->pos, "sp after Pp");
144*544c191cSchristos 		roff_node_delete(man, n);
145c9bcef03Schristos 		break;
146c9bcef03Schristos 	default:
147c9bcef03Schristos 		break;
148c9bcef03Schristos 	}
149c9bcef03Schristos }
150