Annotation of mandoc/mdoc.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: roff.c,v 1.64 2008/12/12 10:11:10 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: extern int macro_text(struct mdoc *, int, int, int *, char *);
! 30: extern int macro_scoped_implicit(struct mdoc *,
! 31: int, int, int *, char *);
! 32:
! 33: const char *const __mdoc_macronames[MDOC_MAX] = {
! 34: "\\\"", "Dd", "Dt", "Os",
! 35: "Sh", "Ss", "Pp", "D1",
! 36: "Dl", "Bd", "Ed", "Bl",
! 37: "El", "It", "Ad", "An",
! 38: "Ar", "Cd", "Cm", "Dv",
! 39: "Er", "Ev", "Ex", "Fa",
! 40: "Fd", "Fl", "Fn", "Ft",
! 41: "Ic", "In", "Li", "Nd",
! 42: "Nm", "Op", "Ot", "Pa",
! 43: "Rv", "St", "Va", "Vt",
! 44: /* LINTED */
! 45: "Xr", "\%A", "\%B", "\%D",
! 46: /* LINTED */
! 47: "\%I", "\%J", "\%N", "\%O",
! 48: /* LINTED */
! 49: "\%P", "\%R", "\%T", "\%V",
! 50: "Ac", "Ao", "Aq", "At",
! 51: "Bc", "Bf", "Bo", "Bq",
! 52: "Bsx", "Bx", "Db", "Dc",
! 53: "Do", "Dq", "Ec", "Ef",
! 54: "Em", "Eo", "Fx", "Ms",
! 55: "No", "Ns", "Nx", "Ox",
! 56: "Pc", "Pf", "Po", "Pq",
! 57: "Qc", "Ql", "Qo", "Qq",
! 58: "Re", "Rs", "Sc", "So",
! 59: "Sq", "Sm", "Sx", "Sy",
! 60: "Tn", "Ux", "Xc", "Xo",
! 61: "Fo", "Fc", "Oo", "Oc",
! 62: "Bk", "Ek", "Bt", "Hf",
! 63: "Fr", "Ud",
! 64: };
! 65:
! 66: const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
! 67: "split", "nosplit", "ragged",
! 68: "unfilled", "literal", "file",
! 69: "offset", "bullet", "dash",
! 70: "hyphen", "item", "enum",
! 71: "tag", "diag", "hang",
! 72: "ohang", "inset", "column",
! 73: "width", "compact", "std",
! 74: "p1003.1-88", "p1003.1-90", "p1003.1-96",
! 75: "p1003.1-2001", "p1003.1-2004", "p1003.1",
! 76: "p1003.1b", "p1003.1b-93", "p1003.1c-95",
! 77: "p1003.1g-2000", "p1003.2-92", "p1387.2-95",
! 78: "p1003.2", "p1387.2", "isoC-90",
! 79: "isoC-amd1", "isoC-tcor1", "isoC-tcor2",
! 80: "isoC-99", "ansiC", "ansiC-89",
! 81: "ansiC-99", "ieee754", "iso8802-3",
! 82: "xpg3", "xpg4", "xpg4.2",
! 83: "xpg4.3", "xbd5", "xcu5",
! 84: "xsh5", "xns5", "xns5.2d2.0",
! 85: "xcurses4.2", "susv2", "susv3",
! 86: "svid4", "filled", "words",
! 87: };
! 88:
! 89: const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
! 90: { NULL, 0 }, /* \" */
! 91: { NULL, 0 }, /* Dd */
! 92: { NULL, 0 }, /* Dt */
! 93: { NULL, 0 }, /* Os */
! 94: { macro_scoped_implicit, 0 }, /* Sh */
! 95: { macro_scoped_implicit, 0 }, /* Ss */
! 96: { NULL, 0 }, /* Pp */
! 97: { NULL, 0 }, /* D1 */
! 98: { NULL, 0 }, /* Dl */
! 99: { NULL, 0 }, /* Bd */
! 100: { NULL, 0 }, /* Ed */
! 101: { NULL, 0 }, /* Bl */
! 102: { NULL, 0 }, /* El */
! 103: { NULL, 0 }, /* It */
! 104: { macro_text, MDOC_CALLABLE }, /* Ad */
! 105: { NULL, 0 }, /* An */
! 106: { macro_text, MDOC_CALLABLE }, /* Ar */
! 107: { NULL, 0 }, /* Cd */
! 108: { macro_text, MDOC_CALLABLE }, /* Cm */
! 109: { macro_text, MDOC_CALLABLE }, /* Dv */
! 110: { macro_text, MDOC_CALLABLE }, /* Er */
! 111: { macro_text, MDOC_CALLABLE }, /* Ev */
! 112: { NULL, 0 }, /* Ex */
! 113: { macro_text, MDOC_CALLABLE }, /* Fa */
! 114: { NULL, 0 }, /* Fd */
! 115: { macro_text, MDOC_CALLABLE }, /* Fl */
! 116: { NULL, 0 }, /* Fn */
! 117: { macro_text, 0 }, /* Ft */
! 118: { macro_text, MDOC_CALLABLE }, /* Ic */
! 119: { NULL, 0 }, /* In */
! 120: { macro_text, MDOC_CALLABLE }, /* Li */
! 121: { NULL, 0 }, /* Nd */
! 122: { NULL, 0 }, /* Nm */
! 123: { NULL, 0 }, /* Op */
! 124: { NULL, 0 }, /* Ot */
! 125: { macro_text, MDOC_CALLABLE }, /* Pa */
! 126: { NULL, 0 }, /* Rv */
! 127: { NULL, 0 }, /* St */
! 128: { macro_text, MDOC_CALLABLE }, /* Va */
! 129: { macro_text, MDOC_CALLABLE }, /* Vt */
! 130: { NULL, 0 }, /* Xr */
! 131: { NULL, 0 }, /* %A */
! 132: { NULL, 0 }, /* %B */
! 133: { NULL, 0 }, /* %D */
! 134: { NULL, 0 }, /* %I */
! 135: { NULL, 0 }, /* %J */
! 136: { NULL, 0 }, /* %N */
! 137: { NULL, 0 }, /* %O */
! 138: { NULL, 0 }, /* %P */
! 139: { NULL, 0 }, /* %R */
! 140: { NULL, 0 }, /* %T */
! 141: { NULL, 0 }, /* %V */
! 142: { NULL, 0 }, /* Ac */
! 143: { NULL, 0 }, /* Ao */
! 144: { NULL, 0 }, /* Aq */
! 145: { NULL, 0 }, /* At */
! 146: { NULL, 0 }, /* Bc */
! 147: { NULL, 0 }, /* Bf */
! 148: { NULL, 0 }, /* Bo */
! 149: { NULL, 0 }, /* Bq */
! 150: { NULL, 0 }, /* Bsx */
! 151: { NULL, 0 }, /* Bx */
! 152: { NULL, 0 }, /* Db */
! 153: { NULL, 0 }, /* Dc */
! 154: { NULL, 0 }, /* Do */
! 155: { NULL, 0 }, /* Dq */
! 156: { NULL, 0 }, /* Ec */
! 157: { NULL, 0 }, /* Ef */
! 158: { macro_text, MDOC_CALLABLE }, /* Em */
! 159: { NULL, 0 }, /* Eo */
! 160: { NULL, 0 }, /* Fx */
! 161: { macro_text, 0 }, /* Ms */
! 162: { NULL, 0 }, /* No */
! 163: { NULL, 0 }, /* Ns */
! 164: { NULL, 0 }, /* Nx */
! 165: { NULL, 0 }, /* Ox */
! 166: { NULL, 0 }, /* Pc */
! 167: { NULL, 0 }, /* Pf */
! 168: { NULL, 0 }, /* Po */
! 169: { NULL, 0 }, /* Pq */
! 170: { NULL, 0 }, /* Qc */
! 171: { NULL, 0 }, /* Ql */
! 172: { NULL, 0 }, /* Qo */
! 173: { NULL, 0 }, /* Qq */
! 174: { NULL, 0 }, /* Re */
! 175: { NULL, 0 }, /* Rs */
! 176: { NULL, 0 }, /* Sc */
! 177: { NULL, 0 }, /* So */
! 178: { NULL, 0 }, /* Sq */
! 179: { NULL, 0 }, /* Sm */
! 180: { NULL, 0 }, /* Sx */
! 181: { NULL, 0 }, /* Sy */
! 182: { macro_text, MDOC_CALLABLE }, /* Tn */
! 183: { NULL, 0 }, /* Ux */
! 184: { NULL, 0 }, /* Xc */
! 185: { NULL, 0 }, /* Xo */
! 186: { NULL, 0 }, /* Fo */
! 187: { NULL, 0 }, /* Fc */
! 188: { NULL, 0 }, /* Oo */
! 189: { NULL, 0 }, /* Oc */
! 190: { NULL, 0 }, /* Bk */
! 191: { NULL, 0 }, /* Ek */
! 192: { NULL, 0 }, /* Bt */
! 193: { NULL, 0 }, /* Hf */
! 194: { NULL, 0 }, /* Fr */
! 195: { NULL, 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 void *xcalloc(size_t, size_t);
! 204: static char *xstrdup(const char *);
! 205:
! 206: static struct mdoc_arg *argdup(size_t, const struct mdoc_arg *);
! 207: static void argfree(size_t, struct mdoc_arg *);
! 208: static void argcpy(struct mdoc_arg *,
! 209: const struct mdoc_arg *);
! 210: static char **paramdup(size_t, const char **);
! 211: static void paramfree(size_t, char **);
! 212:
! 213: static void mdoc_node_freelist(struct mdoc_node *);
! 214: static void mdoc_node_append(struct mdoc *, int,
! 215: struct mdoc_node *);
! 216: static void mdoc_elem_free(struct mdoc_elem *);
! 217: static void mdoc_text_free(struct mdoc_text *);
! 218:
! 219:
! 220: const struct mdoc_node *
! 221: mdoc_result(struct mdoc *mdoc)
! 222: {
! 223:
! 224: return(mdoc->first);
! 225: }
! 226:
! 227:
! 228: void
! 229: mdoc_free(struct mdoc *mdoc)
! 230: {
! 231:
! 232: if (mdoc->first)
! 233: mdoc_node_freelist(mdoc->first);
! 234: if (mdoc->htab)
! 235: mdoc_hash_free(mdoc->htab);
! 236:
! 237: free(mdoc);
! 238: }
! 239:
! 240:
! 241: struct mdoc *
! 242: mdoc_alloc(void *data, const struct mdoc_cb *cb)
! 243: {
! 244: struct mdoc *p;
! 245:
! 246: p = xcalloc(1, sizeof(struct mdoc));
! 247:
! 248: p->data = data;
! 249: (void)memcpy(&p->cb, cb, sizeof(struct mdoc_cb));
! 250:
! 251: p->htab = mdoc_hash_alloc();
! 252: return(p);
! 253: }
! 254:
! 255:
! 256: static void *
! 257: xcalloc(size_t num, size_t sz)
! 258: {
! 259: void *p;
! 260:
! 261: if (NULL == (p = calloc(num, sz)))
! 262: err(EXIT_FAILURE, "calloc");
! 263: return(p);
! 264: }
! 265:
! 266:
! 267: static char *
! 268: xstrdup(const char *p)
! 269: {
! 270: char *pp;
! 271:
! 272: if (NULL == (pp = strdup(p)))
! 273: err(EXIT_FAILURE, "strdup");
! 274: return(pp);
! 275: }
! 276:
! 277:
! 278: int
! 279: mdoc_parseln(struct mdoc *mdoc, char *buf)
! 280: {
! 281: int c, i;
! 282: char tmp[5];
! 283:
! 284: if ('.' != *buf) {
! 285: /* TODO. */
! 286: return(1);
! 287: }
! 288:
! 289: if (buf[1] && '\\' == buf[1])
! 290: if (buf[2] && '\"' == buf[2])
! 291: return(1);
! 292:
! 293: i = 1;
! 294: while (buf[i] && ! isspace(buf[i]) && i < (int)sizeof(tmp))
! 295: i++;
! 296:
! 297: if (i == (int)sizeof(tmp))
! 298: return(mdoc_err(mdoc, -1, 1, ERR_MACRO_NOTSUP));
! 299: else if (i <= 2)
! 300: return(mdoc_err(mdoc, -1, 1, ERR_MACRO_NOTSUP));
! 301:
! 302: i--;
! 303:
! 304: (void)memcpy(tmp, buf + 1, i);
! 305: tmp[i++] = 0;
! 306:
! 307: if (MDOC_MAX == (c = mdoc_find(mdoc, tmp)))
! 308: return(mdoc_err(mdoc, c, 1, ERR_MACRO_NOTSUP));
! 309:
! 310: while (buf[i] && isspace(buf[i]))
! 311: i++;
! 312:
! 313: if (NULL == (mdoc_macros[c].fp)) {
! 314: (void)mdoc_err(mdoc, c, 1, ERR_MACRO_NOTSUP);
! 315: return(0);
! 316: }
! 317:
! 318: return((*mdoc_macros[c].fp)(mdoc, c, 1, &i, buf));
! 319: }
! 320:
! 321:
! 322: void
! 323: mdoc_msg(struct mdoc *mdoc, int pos, const char *fmt, ...)
! 324: {
! 325: va_list ap;
! 326: char buf[256];
! 327:
! 328: if (NULL == mdoc->cb.mdoc_msg)
! 329: return;
! 330:
! 331: va_start(ap, fmt);
! 332: (void)vsnprintf(buf, sizeof(buf), fmt, ap);
! 333: va_end(ap);
! 334:
! 335: (*mdoc->cb.mdoc_msg)(mdoc->data, pos, buf);
! 336: }
! 337:
! 338:
! 339: int
! 340: mdoc_err(struct mdoc *mdoc, int tok, int pos, enum mdoc_err type)
! 341: {
! 342:
! 343: if (NULL == mdoc->cb.mdoc_err)
! 344: return(0);
! 345: return((*mdoc->cb.mdoc_err)(mdoc->data, tok, pos, type));
! 346: }
! 347:
! 348:
! 349: int
! 350: mdoc_warn(struct mdoc *mdoc, int tok, int pos, enum mdoc_warn type)
! 351: {
! 352:
! 353: if (NULL == mdoc->cb.mdoc_warn)
! 354: return(0);
! 355: return((*mdoc->cb.mdoc_warn)(mdoc->data, tok, pos, type));
! 356: }
! 357:
! 358:
! 359: int
! 360: mdoc_macro(struct mdoc *mdoc, int tok, int ppos, int *pos, char *buf)
! 361: {
! 362:
! 363: if (NULL == (mdoc_macros[tok].fp)) {
! 364: (void)mdoc_err(mdoc, tok, ppos, ERR_MACRO_NOTSUP);
! 365: return(0);
! 366: } else if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
! 367: (void)mdoc_err(mdoc, tok, ppos, ERR_MACRO_NOTCALL);
! 368: return(0);
! 369: }
! 370:
! 371: return((*mdoc_macros[tok].fp)(mdoc, tok, ppos, pos, buf));
! 372: }
! 373:
! 374:
! 375: static void
! 376: mdoc_node_append(struct mdoc *mdoc, int pos, struct mdoc_node *p)
! 377: {
! 378: const char *nn, *on, *nt, *ot, *act;
! 379:
! 380: switch (p->type) {
! 381: case (MDOC_TEXT):
! 382: nn = "<text>";
! 383: nt = "text";
! 384: break;
! 385: case (MDOC_BODY):
! 386: nn = mdoc_macronames[p->data.body.tok];
! 387: nt = "body";
! 388: break;
! 389: case (MDOC_ELEM):
! 390: nn = mdoc_macronames[p->data.elem.tok];
! 391: nt = "elem";
! 392: break;
! 393: case (MDOC_HEAD):
! 394: nn = mdoc_macronames[p->data.head.tok];
! 395: nt = "head";
! 396: break;
! 397: case (MDOC_BLOCK):
! 398: nn = mdoc_macronames[p->data.block.tok];
! 399: nt = "block";
! 400: break;
! 401: }
! 402:
! 403: if (NULL == mdoc->first) {
! 404: assert(NULL == mdoc->last);
! 405: mdoc->first = p;
! 406: mdoc->last = p;
! 407: mdoc_msg(mdoc, pos, "parse: root %s `%s'", nt, nn);
! 408: return;
! 409: }
! 410:
! 411: switch (mdoc->last->type) {
! 412: case (MDOC_TEXT):
! 413: on = "<text>";
! 414: ot = "text";
! 415: break;
! 416: case (MDOC_BODY):
! 417: on = mdoc_macronames[mdoc->last->data.body.tok];
! 418: ot = "body";
! 419: break;
! 420: case (MDOC_ELEM):
! 421: on = mdoc_macronames[mdoc->last->data.elem.tok];
! 422: ot = "elem";
! 423: break;
! 424: case (MDOC_HEAD):
! 425: on = mdoc_macronames[mdoc->last->data.head.tok];
! 426: ot = "head";
! 427: break;
! 428: case (MDOC_BLOCK):
! 429: on = mdoc_macronames[mdoc->last->data.block.tok];
! 430: ot = "block";
! 431: break;
! 432: }
! 433:
! 434: switch (p->type) {
! 435: case (MDOC_BODY):
! 436: switch (mdoc->last->type) {
! 437: case (MDOC_BLOCK):
! 438: p->parent = mdoc->last;
! 439: mdoc->last->child = p;
! 440: act = "child";
! 441: break;
! 442: case (MDOC_HEAD):
! 443: p->parent = mdoc->last->parent;
! 444: mdoc->last->next = p;
! 445: act = "sibling";
! 446: break;
! 447: default:
! 448: abort();
! 449: /* NOTREACHED */
! 450: }
! 451: break;
! 452: case (MDOC_HEAD):
! 453: assert(mdoc->last->type == MDOC_BLOCK);
! 454: p->parent = mdoc->last;
! 455: mdoc->last->child = p;
! 456: act = "child";
! 457: break;
! 458: default:
! 459: switch (mdoc->last->type) {
! 460: case (MDOC_BODY):
! 461: /* FALLTHROUGH */
! 462: case (MDOC_HEAD):
! 463: p->parent = mdoc->last->parent;
! 464: mdoc->last->child = p;
! 465: act = "child";
! 466: break;
! 467: default:
! 468: p->parent = mdoc->last->parent;
! 469: mdoc->last->next = p;
! 470: act = "sibling";
! 471: break;
! 472: }
! 473: break;
! 474: }
! 475:
! 476: mdoc_msg(mdoc, pos, "parse: %s `%s' %s %s `%s'",
! 477: nt, nn, act, ot, on);
! 478: mdoc->last = p;
! 479: }
! 480:
! 481:
! 482: void
! 483: mdoc_head_alloc(struct mdoc *mdoc, int pos, int tok,
! 484: size_t paramsz, const char **params)
! 485: {
! 486: struct mdoc_node *p;
! 487:
! 488: assert(mdoc->first);
! 489: assert(mdoc->last);
! 490: assert(mdoc->last->type == MDOC_BLOCK);
! 491: assert(mdoc->last->data.block.tok == tok);
! 492:
! 493: p = xcalloc(1, sizeof(struct mdoc_node));
! 494: p->type = MDOC_HEAD;
! 495: p->data.head.tok = tok;
! 496: p->data.head.sz = paramsz;
! 497: p->data.head.args = paramdup(paramsz, params);
! 498:
! 499: mdoc_node_append(mdoc, pos, p);
! 500: }
! 501:
! 502:
! 503: void
! 504: mdoc_body_alloc(struct mdoc *mdoc, int pos, int tok)
! 505: {
! 506: struct mdoc_node *p;
! 507:
! 508: assert(mdoc->first);
! 509: assert(mdoc->last);
! 510: assert((mdoc->last->type == MDOC_BLOCK) ||
! 511: (mdoc->last->type == MDOC_HEAD));
! 512: if (mdoc->last->type == MDOC_BLOCK)
! 513: assert(mdoc->last->data.block.tok == tok);
! 514: else
! 515: assert(mdoc->last->data.head.tok == tok);
! 516:
! 517: p = xcalloc(1, sizeof(struct mdoc_node));
! 518:
! 519: p->type = MDOC_BODY;
! 520: p->data.body.tok = tok;
! 521:
! 522: mdoc_node_append(mdoc, pos, p);
! 523: }
! 524:
! 525:
! 526: void
! 527: mdoc_block_alloc(struct mdoc *mdoc, int pos, int tok,
! 528: size_t argsz, const struct mdoc_arg *args)
! 529: {
! 530: struct mdoc_node *p;
! 531:
! 532: p = xcalloc(1, sizeof(struct mdoc_node));
! 533:
! 534: p->type = MDOC_BLOCK;
! 535: p->data.block.tok = tok;
! 536: p->data.block.argc = argsz;
! 537: p->data.block.argv = argdup(argsz, args);
! 538:
! 539: mdoc_node_append(mdoc, pos, p);
! 540: }
! 541:
! 542:
! 543: void
! 544: mdoc_elem_alloc(struct mdoc *mdoc, int pos, int tok,
! 545: size_t argsz, const struct mdoc_arg *args,
! 546: size_t paramsz, const char **params)
! 547: {
! 548: struct mdoc_node *p;
! 549:
! 550: p = xcalloc(1, sizeof(struct mdoc_node));
! 551: p->type = MDOC_ELEM;
! 552: p->data.elem.tok = tok;
! 553: p->data.elem.sz = paramsz;
! 554: p->data.elem.args = paramdup(paramsz, params);
! 555: p->data.elem.argc = argsz;
! 556: p->data.elem.argv = argdup(argsz, args);
! 557:
! 558: mdoc_node_append(mdoc, pos, p);
! 559: }
! 560:
! 561:
! 562: void
! 563: mdoc_word_alloc(struct mdoc *mdoc, int pos, const char *word)
! 564: {
! 565: struct mdoc_node *p;
! 566:
! 567: p = xcalloc(1, sizeof(struct mdoc_node));
! 568: p->type = MDOC_TEXT;
! 569: p->data.text.string = xstrdup(word);
! 570:
! 571: mdoc_node_append(mdoc, pos, p);
! 572: }
! 573:
! 574:
! 575: static void
! 576: argfree(size_t sz, struct mdoc_arg *p)
! 577: {
! 578: size_t i, j;
! 579:
! 580: if (0 == sz)
! 581: return;
! 582:
! 583: assert(p);
! 584: for (i = 0; i < sz; i++)
! 585: if (p[i].sz > 0) {
! 586: assert(p[i].value);
! 587: for (j = 0; j < p[i].sz; j++)
! 588: free(p[i].value[j]);
! 589: }
! 590: free(p);
! 591: }
! 592:
! 593:
! 594: static void
! 595: mdoc_elem_free(struct mdoc_elem *p)
! 596: {
! 597:
! 598: paramfree(p->sz, p->args);
! 599: argfree(p->argc, p->argv);
! 600: }
! 601:
! 602:
! 603: static void
! 604: mdoc_block_free(struct mdoc_block *p)
! 605: {
! 606:
! 607: argfree(p->argc, p->argv);
! 608: }
! 609:
! 610:
! 611: static void
! 612: mdoc_text_free(struct mdoc_text *p)
! 613: {
! 614:
! 615: if (p->string)
! 616: free(p->string);
! 617: }
! 618:
! 619:
! 620: static void
! 621: mdoc_head_free(struct mdoc_head *p)
! 622: {
! 623:
! 624: paramfree(p->sz, p->args);
! 625: }
! 626:
! 627:
! 628: void
! 629: mdoc_node_free(struct mdoc_node *p)
! 630: {
! 631:
! 632: switch (p->type) {
! 633: case (MDOC_TEXT):
! 634: mdoc_text_free(&p->data.text);
! 635: break;
! 636: case (MDOC_ELEM):
! 637: mdoc_elem_free(&p->data.elem);
! 638: break;
! 639: case (MDOC_BLOCK):
! 640: mdoc_block_free(&p->data.block);
! 641: break;
! 642: case (MDOC_HEAD):
! 643: mdoc_head_free(&p->data.head);
! 644: break;
! 645: default:
! 646: break;
! 647: }
! 648:
! 649: free(p);
! 650: }
! 651:
! 652:
! 653: static void
! 654: mdoc_node_freelist(struct mdoc_node *p)
! 655: {
! 656:
! 657: if (p->child)
! 658: mdoc_node_freelist(p->child);
! 659: if (p->next)
! 660: mdoc_node_freelist(p->next);
! 661:
! 662: mdoc_node_free(p);
! 663: }
! 664:
! 665:
! 666: int
! 667: mdoc_find(const struct mdoc *mdoc, const char *key)
! 668: {
! 669:
! 670: return(mdoc_hash_find(mdoc->htab, key));
! 671: }
! 672:
! 673:
! 674: static void
! 675: argcpy(struct mdoc_arg *dst, const struct mdoc_arg *src)
! 676: {
! 677: size_t i;
! 678:
! 679: dst->arg = src->arg;
! 680: if (0 == (dst->sz = src->sz))
! 681: return;
! 682: dst->value = xcalloc(dst->sz, sizeof(char *));
! 683: for (i = 0; i < dst->sz; i++)
! 684: dst->value[i] = xstrdup(src->value[i]);
! 685: }
! 686:
! 687:
! 688: static struct mdoc_arg *
! 689: argdup(size_t argsz, const struct mdoc_arg *args)
! 690: {
! 691: struct mdoc_arg *pp;
! 692: size_t i;
! 693:
! 694: if (0 == argsz)
! 695: return(NULL);
! 696:
! 697: pp = xcalloc((size_t)argsz, sizeof(struct mdoc_arg));
! 698: for (i = 0; i < argsz; i++)
! 699: argcpy(&pp[i], &args[i]);
! 700:
! 701: return(pp);
! 702: }
! 703:
! 704:
! 705: static void
! 706: paramfree(size_t sz, char **p)
! 707: {
! 708: size_t i;
! 709:
! 710: if (0 == sz)
! 711: return;
! 712:
! 713: assert(p);
! 714: for (i = 0; i < sz; i++)
! 715: free(p[i]);
! 716: free(p);
! 717: }
! 718:
! 719:
! 720: static char **
! 721: paramdup(size_t sz, const char **p)
! 722: {
! 723: char **pp;
! 724: size_t i;
! 725:
! 726: if (0 == sz)
! 727: return(NULL);
! 728:
! 729: pp = xcalloc(sz, sizeof(char *));
! 730: for (i = 0; i < sz; i++)
! 731: pp[i] = xstrdup(p[i]);
! 732:
! 733: return(pp);
! 734: }
CVSweb