]>
git.cameronkatri.com Git - mandoc.git/blob - tag.c
1 /* $Id: tag.c,v 1.34 2020/04/08 11:56:04 schwarze Exp $ */
3 * Copyright (c) 2015,2016,2018,2019,2020 Ingo Schwarze <schwarze@openbsd.org>
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.
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.
17 * Functions to tag syntax tree nodes.
18 * For internal use by mandoc(1) validation modules only.
22 #include <sys/types.h>
31 #include "mandoc_aux.h"
32 #include "mandoc_ohash.h"
38 struct roff_node
**nodes
;
45 static void tag_move_id(struct roff_node
*);
47 static struct ohash tag_data
;
51 * Set up the ohash table to collect nodes
52 * where various marked-up terms are documented.
57 mandoc_ohash_init(&tag_data
, 4, offsetof(struct tag_entry
, s
));
63 struct tag_entry
*entry
;
66 if (tag_data
.info
.free
== NULL
)
68 entry
= ohash_first(&tag_data
, &slot
);
69 while (entry
!= NULL
) {
72 entry
= ohash_next(&tag_data
, &slot
);
74 ohash_delete(&tag_data
);
75 tag_data
.info
.free
= NULL
;
79 * Set a node where a term is defined,
80 * unless it is already defined at a lower priority.
83 tag_put(const char *s
, int prio
, struct roff_node
*n
)
85 struct tag_entry
*entry
;
86 struct roff_node
*nold
;
91 assert(prio
<= TAG_FALLBACK
);
94 if (n
->child
== NULL
|| n
->child
->type
!= ROFFT_TEXT
)
118 * Skip whitespace and escapes and whatever follows,
119 * and if there is any, downgrade the priority.
122 len
= strcspn(s
, " \t\\");
127 if (*se
!= '\0' && prio
< TAG_WEAK
)
130 slot
= ohash_qlookupi(&tag_data
, s
, &se
);
131 entry
= ohash_find(&tag_data
, slot
);
133 /* Build a new entry. */
136 entry
= mandoc_malloc(sizeof(*entry
) + len
+ 1);
137 memcpy(entry
->s
, s
, len
);
138 entry
->s
[len
] = '\0';
140 entry
->maxnodes
= entry
->nnodes
= 0;
141 ohash_insert(&tag_data
, slot
, entry
);
145 * Lower priority numbers take precedence.
146 * If a better entry is already present, ignore the new one.
149 else if (entry
->prio
< prio
)
153 * If the existing entry is worse, clear it.
154 * In addition, a tag with priority TAG_FALLBACK
155 * is only used if the tag occurs exactly once.
158 else if (entry
->prio
> prio
|| prio
== TAG_FALLBACK
) {
159 while (entry
->nnodes
> 0) {
160 nold
= entry
->nodes
[--entry
->nnodes
];
161 nold
->flags
&= ~NODE_ID
;
165 if (prio
== TAG_FALLBACK
) {
166 entry
->prio
= TAG_DELETE
;
171 /* Remember the new node. */
173 if (entry
->maxnodes
== entry
->nnodes
) {
174 entry
->maxnodes
+= 4;
175 entry
->nodes
= mandoc_reallocarray(entry
->nodes
,
176 entry
->maxnodes
, sizeof(*entry
->nodes
));
178 entry
->nodes
[entry
->nnodes
++] = n
;
181 if (n
->child
== NULL
|| n
->child
->string
!= s
|| *se
!= '\0') {
182 assert(n
->tag
== NULL
);
183 n
->tag
= mandoc_strndup(s
, len
);
188 tag_exists(const char *tag
)
190 return ohash_find(&tag_data
, ohash_qlookup(&tag_data
, tag
)) != NULL
;
194 * For in-line elements, move the link target
195 * to the enclosing paragraph when appropriate.
198 tag_move_id(struct roff_node
*n
)
200 struct roff_node
*np
;
204 if (np
->prev
!= NULL
)
206 else if ((np
= np
->parent
) == NULL
)
210 switch (np
->parent
->parent
->norm
->Bl
.type
) {
212 /* Target the ROFFT_BLOCK = <tr>. */
220 /* Target the ROFFT_HEAD = <dt>. */
221 np
= np
->parent
->head
;
224 /* Target the ROFF_BODY = <li>. */
228 case MDOC_Pp
: /* Target the ROFFT_ELEM = <p>. */
229 if (np
->tag
== NULL
) {
230 np
->tag
= mandoc_strdup(n
->tag
== NULL
?
231 n
->child
->string
: n
->tag
);
232 np
->flags
|= NODE_ID
;
233 n
->flags
&= ~NODE_ID
;
243 /* Do not move past major blocks. */
247 * Move past in-line content and partial
248 * blocks, for example .It Xo or .It Bq Er.
256 * When all tags have been set, decide where to put
257 * the associated permalinks, and maybe move some tags
258 * to the beginning of the respective paragraphs.
261 tag_postprocess(struct roff_node
*n
)
263 if (n
->flags
& NODE_ID
) {
268 /* XXX No permalink for now. */
271 if (n
->type
== ROFFT_ELEM
|| n
->tok
== MDOC_Fo
)
273 if (n
->tok
!= MDOC_Tg
)
274 n
->flags
|= NODE_HREF
;
275 else if ((n
->flags
& NODE_ID
) == 0) {
276 n
->flags
|= NODE_NOPRT
;
283 for (n
= n
->child
; n
!= NULL
; n
= n
->next
)