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