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