xref: /openbsd-src/usr.bin/mandoc/roff_validate.c (revision 7ebbefbe9236f57753e8e49c11f1ddcad05041dc)
1*7ebbefbeSschwarze /*	$OpenBSD: roff_validate.c,v 1.19 2020/02/27 01:25:58 schwarze Exp $ */
2c4d3fa85Sschwarze /*
3*7ebbefbeSschwarze  * Copyright (c) 2010, 2017, 2018, 2020 Ingo Schwarze <schwarze@openbsd.org>
4c4d3fa85Sschwarze  *
5c4d3fa85Sschwarze  * Permission to use, copy, modify, and distribute this software for any
6c4d3fa85Sschwarze  * purpose with or without fee is hereby granted, provided that the above
7c4d3fa85Sschwarze  * copyright notice and this permission notice appear in all copies.
8c4d3fa85Sschwarze  *
9c4d3fa85Sschwarze  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c4d3fa85Sschwarze  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c4d3fa85Sschwarze  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c4d3fa85Sschwarze  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c4d3fa85Sschwarze  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c4d3fa85Sschwarze  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c4d3fa85Sschwarze  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c4d3fa85Sschwarze  */
17c4d3fa85Sschwarze #include <sys/types.h>
18c4d3fa85Sschwarze 
19c4d3fa85Sschwarze #include <assert.h>
20e501e731Sschwarze #include <stdio.h>
219b153f25Sschwarze #include <string.h>
22c4d3fa85Sschwarze 
23c4d3fa85Sschwarze #include "mandoc.h"
24c4d3fa85Sschwarze #include "roff.h"
25c4d3fa85Sschwarze #include "libmandoc.h"
26c4d3fa85Sschwarze #include "roff_int.h"
27c4d3fa85Sschwarze 
28c4d3fa85Sschwarze #define	ROFF_VALID_ARGS struct roff_man *man, struct roff_node *n
29c4d3fa85Sschwarze 
30c4d3fa85Sschwarze typedef	void	(*roff_valid_fp)(ROFF_VALID_ARGS);
31c4d3fa85Sschwarze 
328251afdeSschwarze static	void	  roff_valid_br(ROFF_VALID_ARGS);
330438bfdfSschwarze static	void	  roff_valid_fi(ROFF_VALID_ARGS);
34c4d3fa85Sschwarze static	void	  roff_valid_ft(ROFF_VALID_ARGS);
350438bfdfSschwarze static	void	  roff_valid_nf(ROFF_VALID_ARGS);
368251afdeSschwarze static	void	  roff_valid_sp(ROFF_VALID_ARGS);
37c4d3fa85Sschwarze 
38c4d3fa85Sschwarze static	const roff_valid_fp roff_valids[ROFF_MAX] = {
398251afdeSschwarze 	roff_valid_br,  /* br */
40e13b4195Sschwarze 	NULL,  /* ce */
410438bfdfSschwarze 	roff_valid_fi,  /* fi */
42c4d3fa85Sschwarze 	roff_valid_ft,  /* ft */
43644b390bSschwarze 	NULL,  /* ll */
4424f1eaadSschwarze 	NULL,  /* mc */
450438bfdfSschwarze 	roff_valid_nf,  /* nf */
46af1e8f15Sschwarze 	NULL,  /* po */
476de096f4Sschwarze 	NULL,  /* rj */
488251afdeSschwarze 	roff_valid_sp,  /* sp */
49f7242c43Sschwarze 	NULL,  /* ta */
5011d70615Sschwarze 	NULL,  /* ti */
51c4d3fa85Sschwarze };
52c4d3fa85Sschwarze 
53c4d3fa85Sschwarze 
54c4d3fa85Sschwarze void
roff_validate(struct roff_man * man)55c4d3fa85Sschwarze roff_validate(struct roff_man *man)
56c4d3fa85Sschwarze {
57c4d3fa85Sschwarze 	struct roff_node	*n;
58c4d3fa85Sschwarze 
59c4d3fa85Sschwarze 	n = man->last;
60c4d3fa85Sschwarze 	assert(n->tok < ROFF_MAX);
61c4d3fa85Sschwarze 	if (roff_valids[n->tok] != NULL)
62c4d3fa85Sschwarze 		(*roff_valids[n->tok])(man, n);
63c4d3fa85Sschwarze }
64c4d3fa85Sschwarze 
65c4d3fa85Sschwarze static void
roff_valid_br(ROFF_VALID_ARGS)668251afdeSschwarze roff_valid_br(ROFF_VALID_ARGS)
678251afdeSschwarze {
688251afdeSschwarze 	struct roff_node	*np;
698251afdeSschwarze 
704a0fe8a5Sschwarze 	if (n->next != NULL && n->next->type == ROFFT_TEXT &&
714a0fe8a5Sschwarze 	    *n->next->string == ' ') {
72a5a5f808Sschwarze 		mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
734a0fe8a5Sschwarze 		    "br before text line with leading blank");
744a0fe8a5Sschwarze 		roff_node_delete(man, n);
754a0fe8a5Sschwarze 		return;
764a0fe8a5Sschwarze 	}
774a0fe8a5Sschwarze 
78*7ebbefbeSschwarze 	if ((np = roff_node_prev(n)) == NULL)
798251afdeSschwarze 		return;
808251afdeSschwarze 
818251afdeSschwarze 	switch (np->tok) {
828251afdeSschwarze 	case ROFF_br:
838251afdeSschwarze 	case ROFF_sp:
848251afdeSschwarze 	case MDOC_Pp:
85a5a5f808Sschwarze 		mandoc_msg(MANDOCERR_PAR_SKIP,
868251afdeSschwarze 		    n->line, n->pos, "br after %s", roff_name[np->tok]);
878251afdeSschwarze 		roff_node_delete(man, n);
888251afdeSschwarze 		break;
898251afdeSschwarze 	default:
908251afdeSschwarze 		break;
918251afdeSschwarze 	}
928251afdeSschwarze }
938251afdeSschwarze 
948251afdeSschwarze static void
roff_valid_fi(ROFF_VALID_ARGS)950438bfdfSschwarze roff_valid_fi(ROFF_VALID_ARGS)
960438bfdfSschwarze {
977faedc4aSschwarze 	if ((n->flags & NODE_NOFILL) == 0)
980438bfdfSschwarze 		mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "fi");
990438bfdfSschwarze }
1000438bfdfSschwarze 
1010438bfdfSschwarze static void
roff_valid_ft(ROFF_VALID_ARGS)102c4d3fa85Sschwarze roff_valid_ft(ROFF_VALID_ARGS)
103c4d3fa85Sschwarze {
1049b153f25Sschwarze 	const char		*cp;
105c4d3fa85Sschwarze 
106c4d3fa85Sschwarze 	if (n->child == NULL) {
107c4d3fa85Sschwarze 		man->next = ROFF_NEXT_CHILD;
108c4d3fa85Sschwarze 		roff_word_alloc(man, n->line, n->pos, "P");
109c4d3fa85Sschwarze 		man->last = n;
110c4d3fa85Sschwarze 		return;
111c4d3fa85Sschwarze 	}
112c4d3fa85Sschwarze 
113c4d3fa85Sschwarze 	cp = n->child->string;
1142e362670Sschwarze 	if (mandoc_font(cp, (int)strlen(cp)) != ESCAPE_ERROR)
115c4d3fa85Sschwarze 		return;
116a5a5f808Sschwarze 	mandoc_msg(MANDOCERR_FT_BAD, n->line, n->pos, "ft %s", cp);
117c4d3fa85Sschwarze 	roff_node_delete(man, n);
118c4d3fa85Sschwarze }
1198251afdeSschwarze 
1208251afdeSschwarze static void
roff_valid_nf(ROFF_VALID_ARGS)1210438bfdfSschwarze roff_valid_nf(ROFF_VALID_ARGS)
1220438bfdfSschwarze {
123072e1378Sschwarze 	if (n->flags & NODE_NOFILL)
1240438bfdfSschwarze 		mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "nf");
1250438bfdfSschwarze }
1260438bfdfSschwarze 
1270438bfdfSschwarze static void
roff_valid_sp(ROFF_VALID_ARGS)1288251afdeSschwarze roff_valid_sp(ROFF_VALID_ARGS)
1298251afdeSschwarze {
1308251afdeSschwarze 	struct roff_node	*np;
1318251afdeSschwarze 
132*7ebbefbeSschwarze 	if ((np = roff_node_prev(n)) == NULL)
1338251afdeSschwarze 		return;
1348251afdeSschwarze 
1358251afdeSschwarze 	switch (np->tok) {
1368251afdeSschwarze 	case ROFF_br:
137a5a5f808Sschwarze 		mandoc_msg(MANDOCERR_PAR_SKIP,
1388251afdeSschwarze 		    np->line, np->pos, "br before sp");
1398251afdeSschwarze 		roff_node_delete(man, np);
1408251afdeSschwarze 		break;
1418251afdeSschwarze 	case MDOC_Pp:
142a5a5f808Sschwarze 		mandoc_msg(MANDOCERR_PAR_SKIP,
1438251afdeSschwarze 		    n->line, n->pos, "sp after Pp");
1448251afdeSschwarze 		roff_node_delete(man, n);
1458251afdeSschwarze 		break;
1468251afdeSschwarze 	default:
1478251afdeSschwarze 		break;
1488251afdeSschwarze 	}
1498251afdeSschwarze }
150