]> git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
Memory leak, some mdoc(7) conformities.
[mandoc.git] / mdoc.c
1 /* $Id: mdoc.c,v 1.19 2009/01/06 15:49:44 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
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
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19 #include <assert.h>
20 #include <ctype.h>
21 #include <err.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "private.h"
28
29 const char *const __mdoc_macronames[MDOC_MAX] = {
30 "\\\"", "Dd", "Dt", "Os",
31 "Sh", "Ss", "Pp", "D1",
32 "Dl", "Bd", "Ed", "Bl",
33 "El", "It", "Ad", "An",
34 "Ar", "Cd", "Cm", "Dv",
35 "Er", "Ev", "Ex", "Fa",
36 "Fd", "Fl", "Fn", "Ft",
37 "Ic", "In", "Li", "Nd",
38 "Nm", "Op", "Ot", "Pa",
39 "Rv", "St", "Va", "Vt",
40 /* LINTED */
41 "Xr", "\%A", "\%B", "\%D",
42 /* LINTED */
43 "\%I", "\%J", "\%N", "\%O",
44 /* LINTED */
45 "\%P", "\%R", "\%T", "\%V",
46 "Ac", "Ao", "Aq", "At",
47 "Bc", "Bf", "Bo", "Bq",
48 "Bsx", "Bx", "Db", "Dc",
49 "Do", "Dq", "Ec", "Ef",
50 "Em", "Eo", "Fx", "Ms",
51 "No", "Ns", "Nx", "Ox",
52 "Pc", "Pf", "Po", "Pq",
53 "Qc", "Ql", "Qo", "Qq",
54 "Re", "Rs", "Sc", "So",
55 "Sq", "Sm", "Sx", "Sy",
56 "Tn", "Ux", "Xc", "Xo",
57 "Fo", "Fc", "Oo", "Oc",
58 "Bk", "Ek", "Bt", "Hf",
59 "Fr", "Ud",
60 };
61
62 const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
63 "split", "nosplit", "ragged",
64 "unfilled", "literal", "file",
65 "offset", "bullet", "dash",
66 "hyphen", "item", "enum",
67 "tag", "diag", "hang",
68 "ohang", "inset", "column",
69 "width", "compact", "std",
70 "p1003.1-88", "p1003.1-90", "p1003.1-96",
71 "p1003.1-2001", "p1003.1-2004", "p1003.1",
72 "p1003.1b", "p1003.1b-93", "p1003.1c-95",
73 "p1003.1g-2000", "p1003.2-92", "p1387.2-95",
74 "p1003.2", "p1387.2", "isoC-90",
75 "isoC-amd1", "isoC-tcor1", "isoC-tcor2",
76 "isoC-99", "ansiC", "ansiC-89",
77 "ansiC-99", "ieee754", "iso8802-3",
78 "xpg3", "xpg4", "xpg4.2",
79 "xpg4.3", "xbd5", "xcu5",
80 "xsh5", "xns5", "xns5.2d2.0",
81 "xcurses4.2", "susv2", "susv3",
82 "svid4", "filled", "words",
83 "emphasis", "symbolic",
84 };
85
86 const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
87 { NULL, 0 }, /* \" */
88 { macro_prologue, MDOC_PROLOGUE }, /* Dd */
89 { macro_prologue, MDOC_PROLOGUE }, /* Dt */
90 { macro_prologue, MDOC_PROLOGUE }, /* Os */
91 { macro_scoped, 0 }, /* Sh */
92 { macro_scoped, 0 }, /* Ss */
93 { macro_text, 0 }, /* Pp */
94 { macro_scoped_line, MDOC_PARSED }, /* D1 */
95 { macro_scoped_line, MDOC_PARSED }, /* Dl */
96 { macro_scoped, MDOC_EXPLICIT }, /* Bd */
97 { macro_close_explicit, 0 }, /* Ed */
98 { macro_scoped, MDOC_EXPLICIT }, /* Bl */
99 { macro_close_explicit, 0 }, /* El */
100 { macro_scoped, MDOC_NESTED | MDOC_PARSED }, /* It */
101 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
102 { macro_constant, MDOC_PARSED }, /* An */
103 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
104 { macro_constant, MDOC_QUOTABLE }, /* Cd */
105 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
106 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
107 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
108 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
109 { macro_constant, 0 }, /* Ex */
110 { macro_text, MDOC_CALLABLE | MDOC_QUOTABLE | MDOC_PARSED }, /* Fa */
111 { macro_constant, 0 }, /* Fd */
112 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
113 { macro_text, MDOC_CALLABLE | MDOC_QUOTABLE | MDOC_PARSED }, /* Fn */
114 { macro_text, MDOC_PARSED }, /* Ft */
115 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
116 { macro_constant, 0 }, /* In */
117 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
118 { macro_constant, 0 }, /* Nd */
119 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
120 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
121 { macro_obsolete, 0 }, /* Ot */
122 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
123 { macro_constant, 0 }, /* Rv */
124 /* XXX - supposed to be (but isn't) callable. */
125 { macro_constant_delimited, MDOC_PARSED }, /* St */
126 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
127 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
128 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
129 { macro_constant, MDOC_QUOTABLE | MDOC_PARSED }, /* %A */
130 { macro_constant, MDOC_QUOTABLE | MDOC_PARSED }, /* %B */
131 { macro_constant, MDOC_QUOTABLE }, /* %D */
132 { macro_constant, MDOC_QUOTABLE | MDOC_PARSED }, /* %I */
133 { macro_constant, MDOC_QUOTABLE | MDOC_PARSED }, /* %J */
134 { macro_constant, MDOC_QUOTABLE }, /* %N */
135 { macro_constant, MDOC_QUOTABLE }, /* %O */
136 { macro_constant, MDOC_QUOTABLE }, /* %P */
137 { macro_constant, MDOC_QUOTABLE }, /* %R */
138 { macro_constant, MDOC_QUOTABLE | MDOC_PARSED }, /* %T */
139 { macro_constant, MDOC_QUOTABLE }, /* %V */
140 { macro_close_explicit, MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
141 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED }, /* Ao */
142 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
143 { macro_constant, 0 }, /* At */
144 { macro_close_explicit, MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
145 { macro_scoped, MDOC_EXPLICIT }, /* Bf */
146 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED }, /* Bo */
147 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
148 { macro_constant_delimited, MDOC_PARSED }, /* Bsx */
149 { macro_constant_delimited, MDOC_PARSED }, /* Bx */
150 { macro_constant, 0 }, /* Db */
151 { macro_close_explicit, MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
152 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED }, /* Do */
153 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
154 { macro_close_explicit, MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
155 { macro_close_explicit, 0 }, /* Ef */
156 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
157 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED }, /* Eo */
158 { macro_constant_delimited, MDOC_PARSED }, /* Fx */
159 { macro_text, MDOC_PARSED }, /* Ms */
160 { macro_constant_delimited, MDOC_CALLABLE | MDOC_PARSED }, /* No */
161 { macro_constant_delimited, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */
162 { macro_constant_delimited, MDOC_PARSED }, /* Nx */
163 { macro_constant_delimited, MDOC_PARSED }, /* Ox */
164 { macro_close_explicit, MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
165 { macro_constant, MDOC_PARSED }, /* Pf */
166 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED }, /* Po */
167 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
168 { macro_close_explicit, MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
169 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
170 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED }, /* Qo */
171 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
172 { macro_close_explicit, 0 }, /* Re */
173 { macro_scoped, MDOC_EXPLICIT }, /* Rs */
174 { macro_close_explicit, MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
175 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED }, /* So */
176 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
177 { macro_constant, 0 }, /* Sm */
178 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
179 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
180 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
181 { macro_constant_delimited, MDOC_PARSED }, /* Ux */
182 { macro_close_explicit, MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
183 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED }, /* Xo */
184 /* XXX - .Fo supposed to be (but isn't) callable. */
185 { macro_scoped, MDOC_EXPLICIT | MDOC_PARSED }, /* Fo */
186 /* XXX - .Fc supposed to be (but isn't) callable. */
187 { macro_close_explicit, MDOC_PARSED }, /* Fc */
188 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED }, /* Oo */
189 { macro_close_explicit, MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
190 { macro_scoped, MDOC_EXPLICIT }, /* Bk */
191 { macro_close_explicit, 0 }, /* Ek */
192 { macro_constant, 0 }, /* Bt */
193 { macro_constant, 0 }, /* Hf */
194 { macro_obsolete, 0 }, /* Fr */
195 { macro_constant, 0 }, /* Ud */
196 };
197
198 const char * const *mdoc_macronames = __mdoc_macronames;
199 const char * const *mdoc_argnames = __mdoc_argnames;
200 const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
201
202
203 static struct mdoc_arg *argdup(size_t, const struct mdoc_arg *);
204 static void argfree(size_t, struct mdoc_arg *);
205 static void argcpy(struct mdoc_arg *,
206 const struct mdoc_arg *);
207
208 static void mdoc_node_freelist(struct mdoc_node *);
209 static void mdoc_node_append(struct mdoc *, int,
210 struct mdoc_node *);
211 static void mdoc_elem_free(struct mdoc_elem *);
212 static void mdoc_text_free(struct mdoc_text *);
213
214
215 const struct mdoc_node *
216 mdoc_result(struct mdoc *mdoc)
217 {
218
219 return(mdoc->first);
220 }
221
222
223 void
224 mdoc_free(struct mdoc *mdoc)
225 {
226
227 if (mdoc->first)
228 mdoc_node_freelist(mdoc->first);
229 if (mdoc->htab)
230 mdoc_tokhash_free(mdoc->htab);
231
232 free(mdoc);
233 }
234
235
236 struct mdoc *
237 mdoc_alloc(void *data, const struct mdoc_cb *cb)
238 {
239 struct mdoc *p;
240
241 p = xcalloc(1, sizeof(struct mdoc));
242
243 p->data = data;
244 (void)memcpy(&p->cb, cb, sizeof(struct mdoc_cb));
245
246 p->htab = mdoc_tokhash_alloc();
247 return(p);
248 }
249
250
251 int
252 mdoc_parseln(struct mdoc *mdoc, char *buf)
253 {
254 int c, i;
255 char tmp[5];
256
257 if ('.' != *buf) {
258 if (SEC_PROLOGUE == mdoc->sec_lastn)
259 return(mdoc_err(mdoc, -1, 0, ERR_SYNTAX_NOTEXT));
260 mdoc_word_alloc(mdoc, 0, buf);
261 mdoc->next = MDOC_NEXT_SIBLING;
262 return(1);
263 }
264
265 if (buf[1] && '\\' == buf[1])
266 if (buf[2] && '\"' == buf[2])
267 return(1);
268
269 i = 1;
270 while (buf[i] && ! isspace(buf[i]) && i < (int)sizeof(tmp))
271 i++;
272
273 if (i == (int)sizeof(tmp))
274 return(mdoc_err(mdoc, -1, 1, ERR_MACRO_NOTSUP));
275 else if (i <= 2)
276 return(mdoc_err(mdoc, -1, 1, ERR_MACRO_NOTSUP));
277
278 i--;
279
280 (void)memcpy(tmp, buf + 1, (size_t)i);
281 tmp[i++] = 0;
282
283 if (MDOC_MAX == (c = mdoc_find(mdoc, tmp)))
284 return(mdoc_err(mdoc, c, 1, ERR_MACRO_NOTSUP));
285
286 while (buf[i] && isspace(buf[i]))
287 i++;
288
289 return(mdoc_macro(mdoc, c, 1, &i, buf));
290 }
291
292
293 void
294 mdoc_msg(struct mdoc *mdoc, int pos, const char *fmt, ...)
295 {
296 va_list ap;
297 char buf[256];
298
299 if (NULL == mdoc->cb.mdoc_msg)
300 return;
301
302 va_start(ap, fmt);
303 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
304 va_end(ap);
305
306 (*mdoc->cb.mdoc_msg)(mdoc->data, pos, buf);
307 }
308
309
310 int
311 mdoc_err(struct mdoc *mdoc, int tok, int pos, enum mdoc_err type)
312 {
313
314 if (NULL == mdoc->cb.mdoc_err)
315 return(0);
316 return((*mdoc->cb.mdoc_err)(mdoc->data, tok, pos, type));
317 }
318
319
320 int
321 mdoc_warn(struct mdoc *mdoc, int tok, int pos, enum mdoc_warn type)
322 {
323
324 if (NULL == mdoc->cb.mdoc_warn)
325 return(0);
326 return((*mdoc->cb.mdoc_warn)(mdoc->data, tok, pos, type));
327 }
328
329
330 int
331 mdoc_macro(struct mdoc *mdoc, int tok, int ppos, int *pos, char *buf)
332 {
333
334 if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
335 SEC_PROLOGUE == mdoc->sec_lastn)
336 return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
337
338 if (NULL == (mdoc_macros[tok].fp)) {
339 (void)mdoc_err(mdoc, tok, ppos, ERR_MACRO_NOTSUP);
340 return(0);
341 }
342
343 if (1 != ppos && ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
344 (void)mdoc_err(mdoc, tok, ppos, ERR_MACRO_NOTCALL);
345 return(0);
346 }
347
348 return((*mdoc_macros[tok].fp)(mdoc, tok, ppos, pos, buf));
349 }
350
351
352 static void
353 mdoc_node_append(struct mdoc *mdoc, int pos, struct mdoc_node *p)
354 {
355 const char *nn, *on, *nt, *ot, *act;
356
357 switch (p->type) {
358 case (MDOC_TEXT):
359 nn = p->data.text.string;
360 nt = "text";
361 break;
362 case (MDOC_BODY):
363 nn = mdoc_macronames[p->data.body.tok];
364 nt = "body";
365 break;
366 case (MDOC_ELEM):
367 nn = mdoc_macronames[p->data.elem.tok];
368 nt = "elem";
369 break;
370 case (MDOC_HEAD):
371 nn = mdoc_macronames[p->data.head.tok];
372 nt = "head";
373 break;
374 case (MDOC_TAIL):
375 nn = mdoc_macronames[p->data.tail.tok];
376 nt = "tail";
377 break;
378 case (MDOC_BLOCK):
379 nn = mdoc_macronames[p->data.block.tok];
380 nt = "block";
381 break;
382 default:
383 abort();
384 /* NOTREACHED */
385 }
386
387 if (NULL == mdoc->first) {
388 assert(NULL == mdoc->last);
389 mdoc->first = p;
390 mdoc->last = p;
391 mdoc_msg(mdoc, pos, "parse: root %s `%s'", nt, nn);
392 return;
393 }
394
395 switch (mdoc->last->type) {
396 case (MDOC_TEXT):
397 on = "<text>";
398 ot = "text";
399 break;
400 case (MDOC_BODY):
401 on = mdoc_macronames[mdoc->last->data.body.tok];
402 ot = "body";
403 break;
404 case (MDOC_ELEM):
405 on = mdoc_macronames[mdoc->last->data.elem.tok];
406 ot = "elem";
407 break;
408 case (MDOC_HEAD):
409 on = mdoc_macronames[mdoc->last->data.head.tok];
410 ot = "head";
411 break;
412 case (MDOC_TAIL):
413 on = mdoc_macronames[mdoc->last->data.tail.tok];
414 ot = "tail";
415 break;
416 case (MDOC_BLOCK):
417 on = mdoc_macronames[mdoc->last->data.block.tok];
418 ot = "block";
419 break;
420 default:
421 abort();
422 /* NOTREACHED */
423 }
424
425 switch (mdoc->next) {
426 case (MDOC_NEXT_SIBLING):
427 mdoc->last->next = p;
428 p->prev = mdoc->last;
429 p->parent = mdoc->last->parent;
430 act = "sibling";
431 break;
432 case (MDOC_NEXT_CHILD):
433 mdoc->last->child = p;
434 p->parent = mdoc->last;
435 act = "child";
436 break;
437 default:
438 abort();
439 /* NOTREACHED */
440 }
441
442 mdoc_msg(mdoc, pos, "parse: %s `%s' %s of %s `%s'",
443 nt, nn, act, ot, on);
444
445 mdoc->last = p;
446 }
447
448
449 void
450 mdoc_tail_alloc(struct mdoc *mdoc, int pos, int tok)
451 {
452 struct mdoc_node *p;
453
454 assert(mdoc->first);
455 assert(mdoc->last);
456
457 p = xcalloc(1, sizeof(struct mdoc_node));
458
459 p->type = MDOC_TAIL;
460 p->data.tail.tok = tok;
461
462 mdoc_node_append(mdoc, pos, p);
463 }
464
465
466 void
467 mdoc_head_alloc(struct mdoc *mdoc, int pos, int tok)
468 {
469 struct mdoc_node *p;
470
471 assert(mdoc->first);
472 assert(mdoc->last);
473
474 p = xcalloc(1, sizeof(struct mdoc_node));
475
476 p->type = MDOC_HEAD;
477 p->data.head.tok = tok;
478
479 mdoc_node_append(mdoc, pos, p);
480 }
481
482
483 void
484 mdoc_body_alloc(struct mdoc *mdoc, int pos, int tok)
485 {
486 struct mdoc_node *p;
487
488 assert(mdoc->first);
489 assert(mdoc->last);
490
491 p = xcalloc(1, sizeof(struct mdoc_node));
492
493 p->type = MDOC_BODY;
494 p->data.body.tok = tok;
495
496 mdoc_node_append(mdoc, pos, p);
497 }
498
499
500 void
501 mdoc_block_alloc(struct mdoc *mdoc, int pos, int tok,
502 size_t argsz, const struct mdoc_arg *args)
503 {
504 struct mdoc_node *p;
505
506 p = xcalloc(1, sizeof(struct mdoc_node));
507
508 p->type = MDOC_BLOCK;
509 p->data.block.tok = tok;
510 p->data.block.argc = argsz;
511 p->data.block.argv = argdup(argsz, args);
512
513 mdoc_node_append(mdoc, pos, p);
514 }
515
516
517 void
518 mdoc_elem_alloc(struct mdoc *mdoc, int pos, int tok,
519 size_t argsz, const struct mdoc_arg *args)
520 {
521 struct mdoc_node *p;
522
523 p = xcalloc(1, sizeof(struct mdoc_node));
524 p->type = MDOC_ELEM;
525 p->data.elem.tok = tok;
526 p->data.elem.argc = argsz;
527 p->data.elem.argv = argdup(argsz, args);
528
529 mdoc_node_append(mdoc, pos, p);
530 }
531
532
533 void
534 mdoc_word_alloc(struct mdoc *mdoc, int pos, const char *word)
535 {
536 struct mdoc_node *p;
537
538 p = xcalloc(1, sizeof(struct mdoc_node));
539 p->type = MDOC_TEXT;
540 p->data.text.string = xstrdup(word);
541
542 mdoc_node_append(mdoc, pos, p);
543 }
544
545
546 static void
547 argfree(size_t sz, struct mdoc_arg *p)
548 {
549 int i, j;
550
551 if (0 == sz)
552 return;
553
554 assert(p);
555 /* LINTED */
556 for (i = 0; i < (int)sz; i++)
557 if (p[i].sz > 0) {
558 assert(p[i].value);
559 /* LINTED */
560 for (j = 0; j < (int)p[i].sz; j++)
561 free(p[i].value[j]);
562 free(p[i].value);
563 }
564 free(p);
565 }
566
567
568 static void
569 mdoc_elem_free(struct mdoc_elem *p)
570 {
571
572 argfree(p->argc, p->argv);
573 }
574
575
576 static void
577 mdoc_block_free(struct mdoc_block *p)
578 {
579
580 argfree(p->argc, p->argv);
581 }
582
583
584 static void
585 mdoc_text_free(struct mdoc_text *p)
586 {
587
588 if (p->string)
589 free(p->string);
590 }
591
592
593 void
594 mdoc_node_free(struct mdoc_node *p)
595 {
596
597 switch (p->type) {
598 case (MDOC_TEXT):
599 mdoc_text_free(&p->data.text);
600 break;
601 case (MDOC_ELEM):
602 mdoc_elem_free(&p->data.elem);
603 break;
604 case (MDOC_BLOCK):
605 mdoc_block_free(&p->data.block);
606 break;
607 default:
608 break;
609 }
610
611 free(p);
612 }
613
614
615 static void
616 mdoc_node_freelist(struct mdoc_node *p)
617 {
618
619 if (p->child)
620 mdoc_node_freelist(p->child);
621 if (p->next)
622 mdoc_node_freelist(p->next);
623
624 mdoc_node_free(p);
625 }
626
627
628 int
629 mdoc_find(const struct mdoc *mdoc, const char *key)
630 {
631
632 return(mdoc_tokhash_find(mdoc->htab, key));
633 }
634
635
636 static void
637 argcpy(struct mdoc_arg *dst, const struct mdoc_arg *src)
638 {
639 int i;
640
641 dst->arg = src->arg;
642 if (0 == (dst->sz = src->sz))
643 return;
644 dst->value = xcalloc(dst->sz, sizeof(char *));
645 for (i = 0; i < (int)dst->sz; i++)
646 dst->value[i] = xstrdup(src->value[i]);
647 }
648
649
650 static struct mdoc_arg *
651 argdup(size_t argsz, const struct mdoc_arg *args)
652 {
653 struct mdoc_arg *pp;
654 int i;
655
656 if (0 == argsz)
657 return(NULL);
658
659 pp = xcalloc((size_t)argsz, sizeof(struct mdoc_arg));
660 for (i = 0; i < (int)argsz; i++)
661 argcpy(&pp[i], &args[i]);
662
663 return(pp);
664 }
665