1 /* $Id: roff_validate.c,v 1.9 2017/06/14 22:51:25 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2010, 2017 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 <sys/types.h> 18 19 #include <assert.h> 20 #include <stddef.h> 21 22 #include "mandoc.h" 23 #include "roff.h" 24 #include "libmandoc.h" 25 #include "roff_int.h" 26 27 #define ROFF_VALID_ARGS struct roff_man *man, struct roff_node *n 28 29 typedef void (*roff_valid_fp)(ROFF_VALID_ARGS); 30 31 static void roff_valid_ft(ROFF_VALID_ARGS); 32 33 static const roff_valid_fp roff_valids[ROFF_MAX] = { 34 NULL, /* br */ 35 NULL, /* ce */ 36 roff_valid_ft, /* ft */ 37 NULL, /* ll */ 38 NULL, /* mc */ 39 NULL, /* po */ 40 NULL, /* rj */ 41 NULL, /* sp */ 42 NULL, /* ta */ 43 NULL, /* ti */ 44 }; 45 46 47 void 48 roff_validate(struct roff_man *man) 49 { 50 struct roff_node *n; 51 52 n = man->last; 53 assert(n->tok < ROFF_MAX); 54 if (roff_valids[n->tok] != NULL) 55 (*roff_valids[n->tok])(man, n); 56 } 57 58 static void 59 roff_valid_ft(ROFF_VALID_ARGS) 60 { 61 char *cp; 62 63 if (n->child == NULL) { 64 man->next = ROFF_NEXT_CHILD; 65 roff_word_alloc(man, n->line, n->pos, "P"); 66 man->last = n; 67 return; 68 } 69 70 cp = n->child->string; 71 switch (*cp) { 72 case '1': 73 case '2': 74 case '3': 75 case '4': 76 case 'I': 77 case 'P': 78 case 'R': 79 if (cp[1] == '\0') 80 return; 81 break; 82 case 'B': 83 if (cp[1] == '\0' || (cp[1] == 'I' && cp[2] == '\0')) 84 return; 85 break; 86 case 'C': 87 if (cp[1] == 'W' && cp[2] == '\0') 88 return; 89 break; 90 default: 91 break; 92 } 93 94 mandoc_vmsg(MANDOCERR_FT_BAD, man->parse, 95 n->line, n->pos, "ft %s", cp); 96 roff_node_delete(man, n); 97 } 98