]> git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
Moved prologue-pruning into action.c.
[mandoc.git] / mdoc.c
1 /* $Id: mdoc.c,v 1.39 2009/01/20 12:51:28 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_delimited, 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 int mdoc_node_append(struct mdoc *,
209 struct mdoc_node *);
210 static void mdoc_elem_free(struct mdoc_elem *);
211 static void mdoc_text_free(struct mdoc_text *);
212
213
214 const struct mdoc_node *
215 mdoc_node(struct mdoc *mdoc)
216 {
217
218 return(mdoc->first);
219 }
220
221
222 const struct mdoc_meta *
223 mdoc_meta(struct mdoc *mdoc)
224 {
225
226 return(&mdoc->meta);
227 }
228
229
230 void
231 mdoc_free(struct mdoc *mdoc)
232 {
233
234 if (mdoc->first)
235 mdoc_node_freelist(mdoc->first);
236 if (mdoc->htab)
237 mdoc_tokhash_free(mdoc->htab);
238 if (mdoc->meta.title)
239 free(mdoc->meta.title);
240 if (mdoc->meta.os)
241 free(mdoc->meta.os);
242 if (mdoc->meta.name)
243 free(mdoc->meta.name);
244
245 free(mdoc);
246 }
247
248
249 struct mdoc *
250 mdoc_alloc(void *data, const struct mdoc_cb *cb)
251 {
252 struct mdoc *p;
253
254 p = xcalloc(1, sizeof(struct mdoc));
255
256 p->data = data;
257 if (cb)
258 (void)memcpy(&p->cb, cb, sizeof(struct mdoc_cb));
259
260 p->last = xcalloc(1, sizeof(struct mdoc_node));
261 p->last->type = MDOC_ROOT;
262 p->first = p->last;
263
264 p->next = MDOC_NEXT_CHILD;
265 p->htab = mdoc_tokhash_alloc();
266
267 return(p);
268 }
269
270
271 int
272 mdoc_endparse(struct mdoc *mdoc)
273 {
274
275 if (MDOC_HALT & mdoc->flags)
276 return(0);
277 if (NULL == mdoc->first)
278 return(1);
279
280 assert(mdoc->last);
281 if ( ! macro_end(mdoc)) {
282 mdoc->flags |= MDOC_HALT;
283 return(0);
284 }
285 return(1);
286 }
287
288
289 int
290 mdoc_parseln(struct mdoc *mdoc, int line, char *buf)
291 {
292 int c, i;
293 char tmp[5];
294
295 if (MDOC_HALT & mdoc->flags)
296 return(0);
297
298 mdoc->linetok = 0;
299
300 if ('.' != *buf) {
301 if ( ! (MDOC_BODYPARSE & mdoc->flags))
302 return(mdoc_perr(mdoc, line, 0, "text disallowed"));
303 if ( ! mdoc_word_alloc(mdoc, line, 0, buf))
304 return(0);
305 mdoc->next = MDOC_NEXT_SIBLING;
306 return(1);
307 }
308
309 if (buf[1] && '\\' == buf[1])
310 if (buf[2] && '\"' == buf[2])
311 return(1);
312
313 i = 1;
314 while (buf[i] && ! isspace(buf[i]) && i < (int)sizeof(tmp))
315 i++;
316
317 if (i == (int)sizeof(tmp)) {
318 mdoc->flags |= MDOC_HALT;
319 return(mdoc_perr(mdoc, line, 1, "unknown macro"));
320 } else if (i <= 2) {
321 mdoc->flags |= MDOC_HALT;
322 return(mdoc_perr(mdoc, line, 1, "unknown macro"));
323 }
324
325 i--;
326
327 (void)memcpy(tmp, buf + 1, (size_t)i);
328 tmp[i++] = 0;
329
330 if (MDOC_MAX == (c = mdoc_find(mdoc, tmp))) {
331 mdoc->flags |= MDOC_HALT;
332 return(mdoc_perr(mdoc, line, 1, "unknown macro"));
333 }
334
335 while (buf[i] && isspace(buf[i]))
336 i++;
337
338 if ( ! mdoc_macro(mdoc, c, line, 1, &i, buf)) {
339 mdoc->flags |= MDOC_HALT;
340 return(0);
341 }
342 return(1);
343 }
344
345
346 void
347 mdoc_vmsg(struct mdoc *mdoc, int ln, int pos, const char *fmt, ...)
348 {
349 char buf[256];
350 va_list ap;
351
352 if (NULL == mdoc->cb.mdoc_msg)
353 return;
354
355 va_start(ap, fmt);
356 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
357 va_end(ap);
358 (*mdoc->cb.mdoc_msg)(mdoc->data, ln, pos, buf);
359 }
360
361
362 int
363 mdoc_verr(struct mdoc *mdoc, int ln, int pos,
364 const char *fmt, ...)
365 {
366 char buf[256];
367 va_list ap;
368
369 if (NULL == mdoc->cb.mdoc_err)
370 return(0);
371
372 va_start(ap, fmt);
373 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
374 va_end(ap);
375 return((*mdoc->cb.mdoc_err)(mdoc->data, ln, pos, buf));
376 }
377
378
379 int
380 mdoc_vwarn(struct mdoc *mdoc, int ln, int pos,
381 enum mdoc_warn type, const char *fmt, ...)
382 {
383 char buf[256];
384 va_list ap;
385
386 if (NULL == mdoc->cb.mdoc_warn)
387 return(0);
388
389 va_start(ap, fmt);
390 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
391 va_end(ap);
392 return((*mdoc->cb.mdoc_warn)(mdoc->data, ln, pos, type, buf));
393 }
394
395
396 int
397 mdoc_macro(struct mdoc *mdoc, int tok,
398 int ln, int ppos, int *pos, char *buf)
399 {
400
401 assert(mdoc_macros[tok].fp);
402
403 if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
404 ! (MDOC_BODYPARSE & mdoc->flags))
405 return(mdoc_perr(mdoc, ln, ppos, "macro disallowed: not in document body"));
406 if (1 != ppos && ! (MDOC_CALLABLE & mdoc_macros[tok].flags))
407 return(mdoc_perr(mdoc, ln, ppos, "macro not callable"));
408 return((*mdoc_macros[tok].fp)(mdoc, tok, ln, ppos, pos, buf));
409 }
410
411
412 static int
413 mdoc_node_append(struct mdoc *mdoc, struct mdoc_node *p)
414 {
415 const char *nn, *nt, *on, *ot, *act;
416
417 assert(mdoc->last);
418 assert(mdoc->first);
419 assert(MDOC_ROOT != p->type);
420
421 /* See if we exceed the suggest line-max. */
422
423 switch (p->type) {
424 case (MDOC_TEXT):
425 /* FALLTHROUGH */
426 case (MDOC_ELEM):
427 /* FALLTHROUGH */
428 case (MDOC_BLOCK):
429 mdoc->linetok++;
430 break;
431 default:
432 break;
433 }
434
435 if (mdoc->linetok > MDOC_LINEARG_SOFTMAX)
436 if ( ! mdoc_nwarn(mdoc, p, WARN_COMPAT,
437 "suggested %d tokens per line exceeded (has %d)",
438 MDOC_LINEARG_SOFTMAX, mdoc->linetok))
439 return(0);
440
441 if (MDOC_TEXT == mdoc->last->type)
442 on = "<text>";
443 else if (MDOC_ROOT == mdoc->last->type)
444 on = "<root>";
445 else
446 on = mdoc_macronames[mdoc->last->tok];
447
448 if (MDOC_TEXT == p->type)
449 nn = "<text>";
450 else if (MDOC_ROOT == p->type)
451 nn = "<root>";
452 else
453 nn = mdoc_macronames[p->tok];
454
455 ot = mdoc_type2a(mdoc->last->type);
456 nt = mdoc_type2a(p->type);
457
458 switch (mdoc->next) {
459 case (MDOC_NEXT_SIBLING):
460 mdoc->last->next = p;
461 p->prev = mdoc->last;
462 p->parent = mdoc->last->parent;
463 act = "sibling";
464 break;
465 case (MDOC_NEXT_CHILD):
466 mdoc->last->child = p;
467 p->parent = mdoc->last;
468 act = "child";
469 break;
470 default:
471 abort();
472 /* NOTREACHED */
473 }
474
475 if ( ! mdoc_valid_pre(mdoc, p))
476 return(0);
477
478 switch (p->type) {
479 case (MDOC_HEAD):
480 assert(MDOC_BLOCK == p->parent->type);
481 p->parent->data.block.head = p;
482 break;
483 case (MDOC_TAIL):
484 assert(MDOC_BLOCK == p->parent->type);
485 p->parent->data.block.tail = p;
486 break;
487 case (MDOC_BODY):
488 assert(MDOC_BLOCK == p->parent->type);
489 p->parent->data.block.body = p;
490 break;
491 default:
492 break;
493 }
494
495 mdoc->last = p;
496 mdoc_msg(mdoc, "parse: %s `%s' %s of %s `%s'",
497 nt, nn, act, ot, on);
498 return(1);
499 }
500
501
502 int
503 mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, int tok)
504 {
505 struct mdoc_node *p;
506
507 assert(mdoc->first);
508 assert(mdoc->last);
509
510 p = xcalloc(1, sizeof(struct mdoc_node));
511
512 p->line = line;
513 p->pos = pos;
514 p->type = MDOC_TAIL;
515 p->tok = tok;
516
517 return(mdoc_node_append(mdoc, p));
518 }
519
520
521 int
522 mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, int tok)
523 {
524 struct mdoc_node *p;
525
526 assert(mdoc->first);
527 assert(mdoc->last);
528
529 p = xcalloc(1, sizeof(struct mdoc_node));
530
531 p->line = line;
532 p->pos = pos;
533 p->type = MDOC_HEAD;
534 p->tok = tok;
535
536 return(mdoc_node_append(mdoc, p));
537 }
538
539
540 int
541 mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, int tok)
542 {
543 struct mdoc_node *p;
544
545 assert(mdoc->first);
546 assert(mdoc->last);
547
548 p = xcalloc(1, sizeof(struct mdoc_node));
549
550 p->line = line;
551 p->pos = pos;
552 p->type = MDOC_BODY;
553 p->tok = tok;
554
555 return(mdoc_node_append(mdoc, p));
556 }
557
558
559 int
560 mdoc_root_alloc(struct mdoc *mdoc)
561 {
562 struct mdoc_node *p;
563
564 p = xcalloc(1, sizeof(struct mdoc_node));
565
566 p->type = MDOC_ROOT;
567
568 return(mdoc_node_append(mdoc, p));
569 }
570
571
572 int
573 mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
574 int tok, size_t argsz, const struct mdoc_arg *args)
575 {
576 struct mdoc_node *p;
577
578 p = xcalloc(1, sizeof(struct mdoc_node));
579
580 p->pos = pos;
581 p->line = line;
582 p->type = MDOC_BLOCK;
583 p->tok = tok;
584 p->data.block.argc = argsz;
585 p->data.block.argv = argdup(argsz, args);
586
587 return(mdoc_node_append(mdoc, p));
588 }
589
590
591 int
592 mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
593 int tok, size_t argsz, const struct mdoc_arg *args)
594 {
595 struct mdoc_node *p;
596
597 p = xcalloc(1, sizeof(struct mdoc_node));
598
599 p->line = line;
600 p->pos = pos;
601 p->type = MDOC_ELEM;
602 p->tok = tok;
603 p->data.elem.argc = argsz;
604 p->data.elem.argv = argdup(argsz, args);
605
606 return(mdoc_node_append(mdoc, p));
607 }
608
609
610 int
611 mdoc_word_alloc(struct mdoc *mdoc,
612 int line, int pos, const char *word)
613 {
614 struct mdoc_node *p;
615
616 p = xcalloc(1, sizeof(struct mdoc_node));
617 p->line = line;
618 p->pos = pos;
619 p->type = MDOC_TEXT;
620 p->data.text.string = xstrdup(word);
621
622 return(mdoc_node_append(mdoc, p));
623 }
624
625
626 static void
627 argfree(size_t sz, struct mdoc_arg *p)
628 {
629 int i, j;
630
631 if (0 == sz)
632 return;
633
634 assert(p);
635 /* LINTED */
636 for (i = 0; i < (int)sz; i++)
637 if (p[i].sz > 0) {
638 assert(p[i].value);
639 /* LINTED */
640 for (j = 0; j < (int)p[i].sz; j++)
641 free(p[i].value[j]);
642 free(p[i].value);
643 }
644 free(p);
645 }
646
647
648 static void
649 mdoc_elem_free(struct mdoc_elem *p)
650 {
651
652 argfree(p->argc, p->argv);
653 }
654
655
656 static void
657 mdoc_block_free(struct mdoc_block *p)
658 {
659
660 argfree(p->argc, p->argv);
661 }
662
663
664 static void
665 mdoc_text_free(struct mdoc_text *p)
666 {
667
668 if (p->string)
669 free(p->string);
670 }
671
672
673 void
674 mdoc_node_free(struct mdoc_node *p)
675 {
676
677 switch (p->type) {
678 case (MDOC_TEXT):
679 mdoc_text_free(&p->data.text);
680 break;
681 case (MDOC_ELEM):
682 mdoc_elem_free(&p->data.elem);
683 break;
684 case (MDOC_BLOCK):
685 mdoc_block_free(&p->data.block);
686 break;
687 default:
688 break;
689 }
690
691 free(p);
692 }
693
694
695 void
696 mdoc_node_freelist(struct mdoc_node *p)
697 {
698
699 if (p->child)
700 mdoc_node_freelist(p->child);
701 if (p->next)
702 mdoc_node_freelist(p->next);
703
704 mdoc_node_free(p);
705 }
706
707
708 int
709 mdoc_find(const struct mdoc *mdoc, const char *key)
710 {
711
712 return(mdoc_tokhash_find(mdoc->htab, key));
713 }
714
715
716 static void
717 argcpy(struct mdoc_arg *dst, const struct mdoc_arg *src)
718 {
719 int i;
720
721 dst->line = src->line;
722 dst->pos = src->pos;
723 dst->arg = src->arg;
724 if (0 == (dst->sz = src->sz))
725 return;
726 dst->value = xcalloc(dst->sz, sizeof(char *));
727 for (i = 0; i < (int)dst->sz; i++)
728 dst->value[i] = xstrdup(src->value[i]);
729 }
730
731
732 static struct mdoc_arg *
733 argdup(size_t argsz, const struct mdoc_arg *args)
734 {
735 struct mdoc_arg *pp;
736 int i;
737
738 if (0 == argsz)
739 return(NULL);
740
741 pp = xcalloc((size_t)argsz, sizeof(struct mdoc_arg));
742 for (i = 0; i < (int)argsz; i++)
743 argcpy(&pp[i], &args[i]);
744
745 return(pp);
746 }
747
748
749 /* FIXME: deprecate. */
750 char *
751 mdoc_node2a(struct mdoc_node *node)
752 {
753 static char buf[64];
754
755 assert(node);
756
757 buf[0] = 0;
758 (void)xstrlcat(buf, mdoc_type2a(node->type), 64);
759 if (MDOC_ROOT == node->type)
760 return(buf);
761 (void)xstrlcat(buf, " `", 64);
762 if (MDOC_TEXT == node->type)
763 (void)xstrlcat(buf, node->data.text.string, 64);
764 else
765 (void)xstrlcat(buf, mdoc_macronames[node->tok], 64);
766 (void)xstrlcat(buf, "'", 64);
767
768 return(buf);
769 }
770
771