]> git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
Added more validation (parents/msecs).
[mandoc.git] / mdoc.c
1 /* $Id: mdoc.c,v 1.32 2009/01/16 14:04:26 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_constant, MDOC_PROLOGUE }, /* Dd */
89 { macro_constant, MDOC_PROLOGUE }, /* Dt */
90 { macro_constant, 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_scoped_close, MDOC_EXPLICIT }, /* Ed */
98 { macro_scoped, MDOC_EXPLICIT }, /* Bl */
99 { macro_scoped_close, MDOC_EXPLICIT }, /* El */
100 { macro_scoped, MDOC_PARSED | MDOC_TABSEP}, /* It */
101 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
102 { macro_text, 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 | MDOC_QUOTABLE }, /* 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 - .St 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 }, /* %A */
130 { macro_constant, MDOC_QUOTABLE }, /* %B */
131 { macro_constant, MDOC_QUOTABLE }, /* %D */
132 { macro_constant, MDOC_QUOTABLE }, /* %I */
133 { macro_constant, MDOC_QUOTABLE }, /* %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 }, /* %T */
139 { macro_constant, MDOC_QUOTABLE }, /* %V */
140 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
141 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
142 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
143 { macro_constant, 0 }, /* At */
144 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
145 { macro_scoped, MDOC_EXPLICIT }, /* Bf */
146 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* 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_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
152 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
153 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
154 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
155 { macro_scoped_close, MDOC_EXPLICIT }, /* Ef */
156 { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
157 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* 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_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
165 { macro_constant_delimited, MDOC_PARSED }, /* Pf */
166 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
167 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
168 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
169 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
170 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
171 { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
172 { macro_scoped_close, MDOC_EXPLICIT }, /* Re */
173 { macro_scoped, MDOC_EXPLICIT }, /* Rs */
174 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
175 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* 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_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
183 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* 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_scoped_close, MDOC_EXPLICIT | MDOC_PARSED }, /* Fc */
188 { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
189 { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
190 { macro_scoped, MDOC_EXPLICIT }, /* Bk */
191 { macro_scoped_close, MDOC_EXPLICIT }, /* 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 int mdoc_node_append(struct mdoc *,
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->last = xcalloc(1, sizeof(struct mdoc_node));
247 p->last->type = MDOC_ROOT;
248 p->first = p->last;
249
250 p->next = MDOC_NEXT_CHILD;
251 p->htab = mdoc_tokhash_alloc();
252
253 return(p);
254 }
255
256
257 int
258 mdoc_endparse(struct mdoc *mdoc)
259 {
260
261 if (MDOC_HALT & mdoc->flags)
262 return(0);
263 if (NULL == mdoc->first)
264 return(1);
265
266 assert(mdoc->last);
267 if ( ! macro_end(mdoc)) {
268 mdoc->flags |= MDOC_HALT;
269 return(0);
270 }
271 return(1);
272 }
273
274
275 int
276 mdoc_parseln(struct mdoc *mdoc, int line, char *buf)
277 {
278 int c, i;
279 char tmp[5];
280
281 if (MDOC_HALT & mdoc->flags)
282 return(0);
283
284 if ('.' != *buf) {
285 if (SEC_PROLOGUE != mdoc->sec_lastn) {
286 if ( ! mdoc_word_alloc(mdoc, line, 0, buf))
287 return(0);
288 mdoc->next = MDOC_NEXT_SIBLING;
289 return(1);
290 }
291 return(mdoc_perr(mdoc, line, 0, "text disallowed"));
292 }
293
294 if (buf[1] && '\\' == buf[1])
295 if (buf[2] && '\"' == buf[2])
296 return(1);
297
298 i = 1;
299 while (buf[i] && ! isspace(buf[i]) && i < (int)sizeof(tmp))
300 i++;
301
302 if (i == (int)sizeof(tmp)) {
303 mdoc->flags |= MDOC_HALT;
304 return(mdoc_perr(mdoc, line, 1, "unknown macro"));
305 } else if (i <= 2) {
306 mdoc->flags |= MDOC_HALT;
307 return(mdoc_perr(mdoc, line, 1, "unknown macro"));
308 }
309
310 i--;
311
312 (void)memcpy(tmp, buf + 1, (size_t)i);
313 tmp[i++] = 0;
314
315 if (MDOC_MAX == (c = mdoc_find(mdoc, tmp))) {
316 mdoc->flags |= MDOC_HALT;
317 return(mdoc_perr(mdoc, line, 1, "unknown macro"));
318 }
319
320 while (buf[i] && isspace(buf[i]))
321 i++;
322
323 if ( ! mdoc_macro(mdoc, c, line, 1, &i, buf)) {
324 mdoc->flags |= MDOC_HALT;
325 return(0);
326 }
327 return(1);
328 }
329
330
331 void
332 mdoc_vmsg(struct mdoc *mdoc, int ln, int pos, const char *fmt, ...)
333 {
334 char buf[256];
335 va_list ap;
336
337 if (NULL == mdoc->cb.mdoc_msg)
338 return;
339
340 va_start(ap, fmt);
341 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
342 va_end(ap);
343 (*mdoc->cb.mdoc_msg)(mdoc->data, ln, pos, buf);
344 }
345
346
347 int
348 mdoc_verr(struct mdoc *mdoc, int ln, int pos,
349 const char *fmt, ...)
350 {
351 char buf[256];
352 va_list ap;
353
354 if (NULL == mdoc->cb.mdoc_err)
355 return(0);
356
357 va_start(ap, fmt);
358 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
359 va_end(ap);
360 return((*mdoc->cb.mdoc_err)(mdoc->data, ln, pos, buf));
361 }
362
363
364 int
365 mdoc_vwarn(struct mdoc *mdoc, int ln, int pos,
366 enum mdoc_warn type, const char *fmt, ...)
367 {
368 char buf[256];
369 va_list ap;
370
371 if (NULL == mdoc->cb.mdoc_warn)
372 return(0);
373
374 va_start(ap, fmt);
375 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
376 va_end(ap);
377 return((*mdoc->cb.mdoc_warn)(mdoc->data, ln, pos, type, buf));
378 }
379
380
381 int
382 mdoc_macro(struct mdoc *mdoc, int tok,
383 int ln, int ppos, int *pos, char *buf)
384 {
385
386 assert(mdoc_macros[tok].fp);
387
388 if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
389 SEC_PROLOGUE == mdoc->sec_lastn)
390 return(mdoc_perr(mdoc, ln, ppos, "macro disallowed in document prologue"));
391 if (1 != ppos && ! (MDOC_CALLABLE & mdoc_macros[tok].flags))
392 return(mdoc_perr(mdoc, ln, ppos, "macro not callable"));
393 return((*mdoc_macros[tok].fp)(mdoc, tok, ln, ppos, pos, buf));
394 }
395
396
397 static int
398 mdoc_node_append(struct mdoc *mdoc, struct mdoc_node *p)
399 {
400 const char *nn, *nt, *on, *ot, *act;
401
402 assert(mdoc->last);
403 assert(mdoc->first);
404 assert(MDOC_ROOT != p->type);
405
406 if (MDOC_TEXT == mdoc->last->type)
407 on = "<text>";
408 else if (MDOC_ROOT == mdoc->last->type)
409 on = "<root>";
410 else
411 on = mdoc_macronames[mdoc->last->tok];
412
413 if (MDOC_TEXT == p->type)
414 nn = "<text>";
415 else if (MDOC_ROOT == p->type)
416 nn = "<root>";
417 else
418 nn = mdoc_macronames[p->tok];
419
420 ot = mdoc_type2a(mdoc->last->type);
421 nt = mdoc_type2a(p->type);
422
423 switch (mdoc->next) {
424 case (MDOC_NEXT_SIBLING):
425 mdoc->last->next = p;
426 p->prev = mdoc->last;
427 p->parent = mdoc->last->parent;
428 act = "sibling";
429 break;
430 case (MDOC_NEXT_CHILD):
431 mdoc->last->child = p;
432 p->parent = mdoc->last;
433 act = "child";
434 break;
435 default:
436 abort();
437 /* NOTREACHED */
438 }
439
440 if ( ! mdoc_valid_pre(mdoc, p))
441 return(0);
442 if ( ! mdoc_action_pre(mdoc, p))
443 return(0);
444
445 switch (p->type) {
446 case (MDOC_HEAD):
447 assert(MDOC_BLOCK == p->parent->type);
448 p->parent->data.block.head = p;
449 break;
450 case (MDOC_TAIL):
451 assert(MDOC_BLOCK == p->parent->type);
452 p->parent->data.block.tail = p;
453 break;
454 case (MDOC_BODY):
455 assert(MDOC_BLOCK == p->parent->type);
456 p->parent->data.block.body = p;
457 break;
458 default:
459 break;
460 }
461
462 mdoc->last = p;
463 mdoc_msg(mdoc, "parse: %s `%s' %s of %s `%s'",
464 nt, nn, act, ot, on);
465 return(1);
466 }
467
468
469 int
470 mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, int tok)
471 {
472 struct mdoc_node *p;
473
474 assert(mdoc->first);
475 assert(mdoc->last);
476
477 p = xcalloc(1, sizeof(struct mdoc_node));
478
479 p->line = line;
480 p->pos = pos;
481 p->type = MDOC_TAIL;
482 p->tok = tok;
483
484 return(mdoc_node_append(mdoc, p));
485 }
486
487
488 int
489 mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, int tok)
490 {
491 struct mdoc_node *p;
492
493 assert(mdoc->first);
494 assert(mdoc->last);
495
496 p = xcalloc(1, sizeof(struct mdoc_node));
497
498 p->line = line;
499 p->pos = pos;
500 p->type = MDOC_HEAD;
501 p->tok = tok;
502
503 return(mdoc_node_append(mdoc, p));
504 }
505
506
507 int
508 mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, int tok)
509 {
510 struct mdoc_node *p;
511
512 assert(mdoc->first);
513 assert(mdoc->last);
514
515 p = xcalloc(1, sizeof(struct mdoc_node));
516
517 p->line = line;
518 p->pos = pos;
519 p->type = MDOC_BODY;
520 p->tok = tok;
521
522 return(mdoc_node_append(mdoc, p));
523 }
524
525
526 int
527 mdoc_root_alloc(struct mdoc *mdoc)
528 {
529 struct mdoc_node *p;
530
531 p = xcalloc(1, sizeof(struct mdoc_node));
532
533 p->type = MDOC_ROOT;
534
535 return(mdoc_node_append(mdoc, p));
536 }
537
538
539 int
540 mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
541 int tok, size_t argsz, const struct mdoc_arg *args)
542 {
543 struct mdoc_node *p;
544
545 p = xcalloc(1, sizeof(struct mdoc_node));
546
547 p->pos = pos;
548 p->line = line;
549 p->type = MDOC_BLOCK;
550 p->tok = tok;
551 p->data.block.argc = argsz;
552 p->data.block.argv = argdup(argsz, args);
553
554 return(mdoc_node_append(mdoc, p));
555 }
556
557
558 int
559 mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
560 int tok, size_t argsz, const struct mdoc_arg *args)
561 {
562 struct mdoc_node *p;
563
564 p = xcalloc(1, sizeof(struct mdoc_node));
565
566 p->line = line;
567 p->pos = pos;
568 p->type = MDOC_ELEM;
569 p->tok = tok;
570 p->data.elem.argc = argsz;
571 p->data.elem.argv = argdup(argsz, args);
572
573 return(mdoc_node_append(mdoc, p));
574 }
575
576
577 int
578 mdoc_word_alloc(struct mdoc *mdoc,
579 int line, int pos, const char *word)
580 {
581 struct mdoc_node *p;
582
583 p = xcalloc(1, sizeof(struct mdoc_node));
584 p->line = line;
585 p->pos = pos;
586 p->type = MDOC_TEXT;
587 p->data.text.string = xstrdup(word);
588
589 return(mdoc_node_append(mdoc, p));
590 }
591
592
593 static void
594 argfree(size_t sz, struct mdoc_arg *p)
595 {
596 int i, j;
597
598 if (0 == sz)
599 return;
600
601 assert(p);
602 /* LINTED */
603 for (i = 0; i < (int)sz; i++)
604 if (p[i].sz > 0) {
605 assert(p[i].value);
606 /* LINTED */
607 for (j = 0; j < (int)p[i].sz; j++)
608 free(p[i].value[j]);
609 free(p[i].value);
610 }
611 free(p);
612 }
613
614
615 static void
616 mdoc_elem_free(struct mdoc_elem *p)
617 {
618
619 argfree(p->argc, p->argv);
620 }
621
622
623 static void
624 mdoc_block_free(struct mdoc_block *p)
625 {
626
627 argfree(p->argc, p->argv);
628 }
629
630
631 static void
632 mdoc_text_free(struct mdoc_text *p)
633 {
634
635 if (p->string)
636 free(p->string);
637 }
638
639
640 void
641 mdoc_node_free(struct mdoc_node *p)
642 {
643
644 switch (p->type) {
645 case (MDOC_TEXT):
646 mdoc_text_free(&p->data.text);
647 break;
648 case (MDOC_ELEM):
649 mdoc_elem_free(&p->data.elem);
650 break;
651 case (MDOC_BLOCK):
652 mdoc_block_free(&p->data.block);
653 break;
654 default:
655 break;
656 }
657
658 free(p);
659 }
660
661
662 static void
663 mdoc_node_freelist(struct mdoc_node *p)
664 {
665
666 if (p->child)
667 mdoc_node_freelist(p->child);
668 if (p->next)
669 mdoc_node_freelist(p->next);
670
671 mdoc_node_free(p);
672 }
673
674
675 int
676 mdoc_find(const struct mdoc *mdoc, const char *key)
677 {
678
679 return(mdoc_tokhash_find(mdoc->htab, key));
680 }
681
682
683 static void
684 argcpy(struct mdoc_arg *dst, const struct mdoc_arg *src)
685 {
686 int i;
687
688 dst->line = src->line;
689 dst->pos = src->pos;
690 dst->arg = src->arg;
691 if (0 == (dst->sz = src->sz))
692 return;
693 dst->value = xcalloc(dst->sz, sizeof(char *));
694 for (i = 0; i < (int)dst->sz; i++)
695 dst->value[i] = xstrdup(src->value[i]);
696 }
697
698
699 static struct mdoc_arg *
700 argdup(size_t argsz, const struct mdoc_arg *args)
701 {
702 struct mdoc_arg *pp;
703 int i;
704
705 if (0 == argsz)
706 return(NULL);
707
708 pp = xcalloc((size_t)argsz, sizeof(struct mdoc_arg));
709 for (i = 0; i < (int)argsz; i++)
710 argcpy(&pp[i], &args[i]);
711
712 return(pp);
713 }
714