Annotation of mandoc/tag.c, Revision 1.28
1.28 ! schwarze 1: /* $Id: tag.c,v 1.27 2020/01/20 10:37:15 schwarze Exp $ */
1.1 schwarze 2: /*
1.26 schwarze 3: * Copyright (c) 2015,2016,2018,2019,2020 Ingo Schwarze <schwarze@openbsd.org>
1.1 schwarze 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.
1.28 ! schwarze 16: *
! 17: * Functions to tag syntax tree nodes.
! 18: * For internal use by mandoc(1) validation modules only.
1.1 schwarze 19: */
1.7 schwarze 20: #include "config.h"
21:
1.1 schwarze 22: #include <sys/types.h>
23:
1.27 schwarze 24: #include <assert.h>
1.20 schwarze 25: #include <limits.h>
1.1 schwarze 26: #include <stddef.h>
27: #include <stdlib.h>
28: #include <string.h>
29:
30: #include "mandoc_aux.h"
1.10 schwarze 31: #include "mandoc_ohash.h"
1.28 ! schwarze 32: #include "roff.h"
1.1 schwarze 33: #include "tag.h"
34:
35: struct tag_entry {
1.28 ! schwarze 36: struct roff_node **nodes;
! 37: size_t maxnodes;
! 38: size_t nnodes;
1.4 schwarze 39: int prio;
1.1 schwarze 40: char s[];
41: };
42:
43: static struct ohash tag_data;
44:
45:
46: /*
1.28 ! schwarze 47: * Set up the ohash table to collect nodes
! 48: * where various marked-up terms are documented.
1.1 schwarze 49: */
1.28 ! schwarze 50: void
! 51: tag_alloc(void)
1.1 schwarze 52: {
1.28 ! schwarze 53: mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s));
! 54: }
1.1 schwarze 55:
1.28 ! schwarze 56: void
! 57: tag_free(void)
! 58: {
! 59: struct tag_entry *entry;
! 60: unsigned int slot;
1.12 schwarze 61:
1.28 ! schwarze 62: entry = ohash_first(&tag_data, &slot);
! 63: while (entry != NULL) {
! 64: free(entry->nodes);
! 65: free(entry);
! 66: entry = ohash_next(&tag_data, &slot);
1.22 schwarze 67: }
1.28 ! schwarze 68: ohash_delete(&tag_data);
1.1 schwarze 69: }
70:
71: /*
1.28 ! schwarze 72: * Set a node where a term is defined,
1.20 schwarze 73: * unless it is already defined at a lower priority.
1.1 schwarze 74: */
75: void
1.28 ! schwarze 76: tag_put(const char *s, int prio, struct roff_node *n)
1.1 schwarze 77: {
78: struct tag_entry *entry;
1.20 schwarze 79: const char *se;
1.5 schwarze 80: size_t len;
1.1 schwarze 81: unsigned int slot;
82:
1.27 schwarze 83: assert(prio <= TAG_FALLBACK);
1.20 schwarze 84:
1.28 ! schwarze 85: if (s == NULL) {
! 86: if (n->child == NULL || n->child->type != ROFFT_TEXT)
! 87: return;
! 88: s = n->child->string;
! 89: if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e'))
! 90: s += 2;
! 91: }
1.20 schwarze 92:
93: /*
1.24 schwarze 94: * Skip whitespace and escapes and whatever follows,
1.20 schwarze 95: * and if there is any, downgrade the priority.
96: */
97:
1.24 schwarze 98: len = strcspn(s, " \t\\");
1.20 schwarze 99: if (len == 0)
1.1 schwarze 100: return;
1.14 schwarze 101:
1.20 schwarze 102: se = s + len;
1.27 schwarze 103: if (*se != '\0' && prio < TAG_WEAK)
104: prio = TAG_WEAK;
1.20 schwarze 105:
106: slot = ohash_qlookupi(&tag_data, s, &se);
1.1 schwarze 107: entry = ohash_find(&tag_data, slot);
1.14 schwarze 108:
1.28 ! schwarze 109: /* Build a new entry. */
! 110:
1.1 schwarze 111: if (entry == NULL) {
1.20 schwarze 112: entry = mandoc_malloc(sizeof(*entry) + len + 1);
1.1 schwarze 113: memcpy(entry->s, s, len);
1.20 schwarze 114: entry->s[len] = '\0';
1.28 ! schwarze 115: entry->nodes = NULL;
! 116: entry->maxnodes = entry->nnodes = 0;
1.1 schwarze 117: ohash_insert(&tag_data, slot, entry);
1.28 ! schwarze 118: }
1.14 schwarze 119:
1.28 ! schwarze 120: /*
! 121: * Lower priority numbers take precedence.
! 122: * If a better entry is already present, ignore the new one.
! 123: */
! 124:
! 125: else if (entry->prio < prio)
! 126: return;
! 127:
! 128: /*
! 129: * If the existing entry is worse, clear it.
! 130: * In addition, a tag with priority TAG_FALLBACK
! 131: * is only used if the tag occurs exactly once.
! 132: */
1.14 schwarze 133:
1.28 ! schwarze 134: else if (entry->prio > prio || prio == TAG_FALLBACK) {
! 135: while (entry->nnodes > 0)
! 136: entry->nodes[--entry->nnodes]->flags &= ~NODE_ID;
1.16 schwarze 137:
1.27 schwarze 138: if (prio == TAG_FALLBACK) {
1.28 ! schwarze 139: entry->prio = TAG_DELETE;
1.16 schwarze 140: return;
141: }
1.14 schwarze 142: }
143:
1.28 ! schwarze 144: /* Remember the new node. */
1.14 schwarze 145:
1.28 ! schwarze 146: if (entry->maxnodes == entry->nnodes) {
! 147: entry->maxnodes += 4;
! 148: entry->nodes = mandoc_reallocarray(entry->nodes,
! 149: entry->maxnodes, sizeof(*entry->nodes));
1.14 schwarze 150: }
1.28 ! schwarze 151: entry->nodes[entry->nnodes++] = n;
1.4 schwarze 152: entry->prio = prio;
1.28 ! schwarze 153: n->flags |= NODE_ID;
! 154: if (n->child == NULL || n->child->string != s || *se != '\0') {
! 155: assert(n->string == NULL);
! 156: n->string = mandoc_strndup(s, len);
! 157: }
1.1 schwarze 158: }
159:
1.28 ! schwarze 160: enum tag_result
! 161: tag_check(const char *test_tag)
1.1 schwarze 162: {
1.28 ! schwarze 163: unsigned int slot;
1.1 schwarze 164:
1.28 ! schwarze 165: if (ohash_first(&tag_data, &slot) == NULL)
! 166: return TAG_EMPTY;
! 167: else if (test_tag != NULL && ohash_find(&tag_data,
! 168: ohash_qlookup(&tag_data, test_tag)) == NULL)
! 169: return TAG_MISS;
1.19 schwarze 170: else
1.28 ! schwarze 171: return TAG_OK;
1.1 schwarze 172: }
CVSweb