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