Annotation of mandoc/mdoc.c, Revision 1.88
1.88 ! kristaps 1: /* $Id: mdoc.c,v 1.87 2009/07/06 09:21:24 kristaps Exp $ */
1.1 kristaps 2: /*
1.76 kristaps 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.75 kristaps 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.75 kristaps 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.
1.1 kristaps 16: */
17: #include <assert.h>
18: #include <ctype.h>
19: #include <stdarg.h>
1.73 kristaps 20: #include <stdio.h>
1.1 kristaps 21: #include <stdlib.h>
22: #include <string.h>
23:
1.70 kristaps 24: #include "libmdoc.h"
1.1 kristaps 25:
26: const char *const __mdoc_macronames[MDOC_MAX] = {
1.82 kristaps 27: "Ap", "Dd", "Dt", "Os",
1.1 kristaps 28: "Sh", "Ss", "Pp", "D1",
29: "Dl", "Bd", "Ed", "Bl",
30: "El", "It", "Ad", "An",
31: "Ar", "Cd", "Cm", "Dv",
32: "Er", "Ev", "Ex", "Fa",
33: "Fd", "Fl", "Fn", "Ft",
34: "Ic", "In", "Li", "Nd",
35: "Nm", "Op", "Ot", "Pa",
36: "Rv", "St", "Va", "Vt",
37: /* LINTED */
38: "Xr", "\%A", "\%B", "\%D",
39: /* LINTED */
40: "\%I", "\%J", "\%N", "\%O",
41: /* LINTED */
42: "\%P", "\%R", "\%T", "\%V",
43: "Ac", "Ao", "Aq", "At",
44: "Bc", "Bf", "Bo", "Bq",
45: "Bsx", "Bx", "Db", "Dc",
46: "Do", "Dq", "Ec", "Ef",
47: "Em", "Eo", "Fx", "Ms",
48: "No", "Ns", "Nx", "Ox",
49: "Pc", "Pf", "Po", "Pq",
50: "Qc", "Ql", "Qo", "Qq",
51: "Re", "Rs", "Sc", "So",
52: "Sq", "Sm", "Sx", "Sy",
53: "Tn", "Ux", "Xc", "Xo",
54: "Fo", "Fc", "Oo", "Oc",
55: "Bk", "Ek", "Bt", "Hf",
1.82 kristaps 56: "Fr", "Ud", "Lb", "Lp",
57: "Lk", "Mt", "Brq", "Bro",
1.64 kristaps 58: /* LINTED */
1.82 kristaps 59: "Brc", "\%C", "Es", "En",
1.69 kristaps 60: /* LINTED */
1.82 kristaps 61: "Dx", "\%Q"
1.1 kristaps 62: };
63:
64: const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
65: "split", "nosplit", "ragged",
66: "unfilled", "literal", "file",
67: "offset", "bullet", "dash",
68: "hyphen", "item", "enum",
69: "tag", "diag", "hang",
70: "ohang", "inset", "column",
71: "width", "compact", "std",
1.52 kristaps 72: "filled", "words", "emphasis",
1.64 kristaps 73: "symbolic", "nested"
1.1 kristaps 74: };
75:
76: const char * const *mdoc_macronames = __mdoc_macronames;
77: const char * const *mdoc_argnames = __mdoc_argnames;
78:
1.73 kristaps 79: static void mdoc_free1(struct mdoc *);
80: static int mdoc_alloc1(struct mdoc *);
81: static struct mdoc_node *node_alloc(struct mdoc *, int, int,
82: int, enum mdoc_type);
83: static int node_append(struct mdoc *,
1.71 kristaps 84: struct mdoc_node *);
85: static int parsetext(struct mdoc *, int, char *);
86: static int parsemacro(struct mdoc *, int, char *);
87: static int macrowarn(struct mdoc *, int, const char *);
1.88 ! kristaps 88:
1.71 kristaps 89:
1.1 kristaps 90: const struct mdoc_node *
1.71 kristaps 91: mdoc_node(const struct mdoc *m)
1.1 kristaps 92: {
93:
1.71 kristaps 94: return(MDOC_HALT & m->flags ? NULL : m->first);
1.1 kristaps 95: }
96:
97:
1.37 kristaps 98: const struct mdoc_meta *
1.71 kristaps 99: mdoc_meta(const struct mdoc *m)
1.37 kristaps 100: {
101:
1.71 kristaps 102: return(MDOC_HALT & m->flags ? NULL : &m->meta);
1.37 kristaps 103: }
104:
105:
1.85 kristaps 106: /*
107: * Frees volatile resources (parse tree, meta-data, fields).
108: */
1.73 kristaps 109: static void
110: mdoc_free1(struct mdoc *mdoc)
1.67 kristaps 111: {
112:
113: if (mdoc->first)
114: mdoc_node_freelist(mdoc->first);
115: if (mdoc->meta.title)
116: free(mdoc->meta.title);
117: if (mdoc->meta.os)
118: free(mdoc->meta.os);
119: if (mdoc->meta.name)
120: free(mdoc->meta.name);
121: if (mdoc->meta.arch)
122: free(mdoc->meta.arch);
123: if (mdoc->meta.vol)
124: free(mdoc->meta.vol);
1.73 kristaps 125: }
126:
127:
1.85 kristaps 128: /*
129: * Allocate all volatile resources (parse tree, meta-data, fields).
130: */
1.73 kristaps 131: static int
132: mdoc_alloc1(struct mdoc *mdoc)
133: {
1.67 kristaps 134:
135: bzero(&mdoc->meta, sizeof(struct mdoc_meta));
136: mdoc->flags = 0;
1.85 kristaps 137: mdoc->lastnamed = mdoc->lastsec = SEC_NONE;
1.70 kristaps 138: mdoc->last = calloc(1, sizeof(struct mdoc_node));
139: if (NULL == mdoc->last)
1.73 kristaps 140: return(0);
141:
1.70 kristaps 142: mdoc->first = mdoc->last;
1.67 kristaps 143: mdoc->last->type = MDOC_ROOT;
144: mdoc->next = MDOC_NEXT_CHILD;
1.73 kristaps 145: return(1);
146: }
147:
148:
149: /*
1.85 kristaps 150: * Free up volatile resources (see mdoc_free1()) then re-initialises the
151: * data with mdoc_alloc1(). After invocation, parse data has been reset
152: * and the parser is ready for re-invocation on a new tree; however,
153: * cross-parse non-volatile data is kept intact.
1.73 kristaps 154: */
155: int
156: mdoc_reset(struct mdoc *mdoc)
157: {
158:
159: mdoc_free1(mdoc);
160: return(mdoc_alloc1(mdoc));
1.67 kristaps 161: }
162:
163:
1.68 kristaps 164: /*
1.85 kristaps 165: * Completely free up all volatile and non-volatile parse resources.
166: * After invocation, the pointer is no longer usable.
1.68 kristaps 167: */
1.67 kristaps 168: void
1.38 kristaps 169: mdoc_free(struct mdoc *mdoc)
1.34 kristaps 170: {
171:
1.73 kristaps 172: mdoc_free1(mdoc);
1.68 kristaps 173: if (mdoc->htab)
1.74 kristaps 174: mdoc_hash_free(mdoc->htab);
1.1 kristaps 175: free(mdoc);
176: }
177:
178:
1.85 kristaps 179: /*
180: * Allocate volatile and non-volatile parse resources.
181: */
1.1 kristaps 182: struct mdoc *
1.55 kristaps 183: mdoc_alloc(void *data, int pflags, const struct mdoc_cb *cb)
1.1 kristaps 184: {
185: struct mdoc *p;
186:
1.70 kristaps 187: if (NULL == (p = calloc(1, sizeof(struct mdoc))))
1.73 kristaps 188: return(NULL);
1.74 kristaps 189: if (cb)
190: (void)memcpy(&p->cb, cb, sizeof(struct mdoc_cb));
1.1 kristaps 191:
192: p->data = data;
1.73 kristaps 193: p->pflags = pflags;
194:
1.74 kristaps 195: if (NULL == (p->htab = mdoc_hash_alloc())) {
196: free(p);
197: return(NULL);
198: } else if (mdoc_alloc1(p))
199: return(p);
1.1 kristaps 200:
1.73 kristaps 201: free(p);
202: return(NULL);
1.1 kristaps 203: }
204:
205:
1.68 kristaps 206: /*
207: * Climb back up the parse tree, validating open scopes. Mostly calls
1.85 kristaps 208: * through to macro_end() in macro.c.
1.68 kristaps 209: */
1.1 kristaps 210: int
1.72 kristaps 211: mdoc_endparse(struct mdoc *m)
1.20 kristaps 212: {
213:
1.72 kristaps 214: if (MDOC_HALT & m->flags)
1.20 kristaps 215: return(0);
1.72 kristaps 216: else if (mdoc_macroend(m))
1.20 kristaps 217: return(1);
1.72 kristaps 218: m->flags |= MDOC_HALT;
219: return(0);
1.20 kristaps 220: }
221:
222:
1.50 kristaps 223: /*
1.53 kristaps 224: * Main parse routine. Parses a single line -- really just hands off to
1.85 kristaps 225: * the macro (parsemacro()) or text parser (parsetext()).
1.50 kristaps 226: */
1.20 kristaps 227: int
1.53 kristaps 228: mdoc_parseln(struct mdoc *m, int ln, char *buf)
1.1 kristaps 229: {
230:
1.53 kristaps 231: if (MDOC_HALT & m->flags)
1.20 kristaps 232: return(0);
1.50 kristaps 233:
1.53 kristaps 234: return('.' == *buf ? parsemacro(m, ln, buf) :
235: parsetext(m, ln, buf));
1.1 kristaps 236: }
237:
238:
239: int
1.31 kristaps 240: mdoc_verr(struct mdoc *mdoc, int ln, int pos,
241: const char *fmt, ...)
1.1 kristaps 242: {
1.31 kristaps 243: char buf[256];
244: va_list ap;
1.1 kristaps 245:
246: if (NULL == mdoc->cb.mdoc_err)
247: return(0);
1.31 kristaps 248:
249: va_start(ap, fmt);
250: (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
251: va_end(ap);
1.88 ! kristaps 252:
1.31 kristaps 253: return((*mdoc->cb.mdoc_err)(mdoc->data, ln, pos, buf));
1.1 kristaps 254: }
255:
256:
257: int
1.87 kristaps 258: mdoc_vwarn(struct mdoc *mdoc, int ln, int pos, const char *fmt, ...)
1.1 kristaps 259: {
1.31 kristaps 260: char buf[256];
261: va_list ap;
1.1 kristaps 262:
263: if (NULL == mdoc->cb.mdoc_warn)
264: return(0);
1.31 kristaps 265:
266: va_start(ap, fmt);
267: (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
268: va_end(ap);
1.88 ! kristaps 269:
1.87 kristaps 270: return((*mdoc->cb.mdoc_warn)(mdoc->data, ln, pos, buf));
1.1 kristaps 271: }
272:
273:
274: int
1.88 ! kristaps 275: mdoc_err(struct mdoc *m, int line, int pos, int iserr, enum merr type)
1.78 kristaps 276: {
1.88 ! kristaps 277: char *p;
! 278:
! 279: p = NULL;
1.73 kristaps 280:
281: switch (type) {
282: case (ENOCALL):
283: p = "not callable";
284: break;
285: case (EPROLBODY):
286: p = "macro disallowed in document body";
287: break;
288: case (EBODYPROL):
289: p = "macro disallowed in document prologue";
290: break;
291: case (EMALLOC):
292: p = "memory exhausted";
293: break;
294: case (ETEXTPROL):
295: p = "text disallowed in document prologue";
296: break;
297: case (ENOBLANK):
298: p = "blank lines disallowed in non-literal contexts";
299: break;
300: case (ESPACE):
301: p = "whitespace disallowed after delimiter";
302: break;
1.88 ! kristaps 303: case (ETOOLONG):
! 304: p = "text argument too long";
! 305: break;
! 306: case (EESCAPE):
! 307: p = "invalid escape sequence";
! 308: break;
! 309: case (EPRINT):
! 310: p = "invalid character";
! 311: break;
! 312: case (ENESTDISP):
! 313: p = "displays may not be nested";
! 314: break;
! 315: case (EBOOL):
! 316: p = "expected boolean value";
! 317: break;
! 318: case (EARGREP):
! 319: p = "argument repeated";
! 320: break;
! 321: case (EMULTIDISP):
! 322: p = "multiple display types specified";
! 323: break;
! 324: case (EMULTILIST):
! 325: p = "multiple list types specified";
! 326: break;
! 327: case (ELISTTYPE):
! 328: p = "missing list type";
! 329: break;
! 330: case (EDISPTYPE):
! 331: p = "missing display type";
! 332: break;
! 333: case (ESECNAME):
! 334: p = "the NAME section must come first";
! 335: break;
! 336: case (ELINE):
! 337: p = "expected line arguments";
! 338: break;
! 339: case (ENOPROLOGUE):
! 340: p = "document has no prologue";
! 341: break;
! 342: case (ENODAT):
! 343: p = "document has no data";
! 344: break;
! 345: case (ECOLMIS):
! 346: p = "column syntax style mismatch";
! 347: break;
! 348: case (EATT):
! 349: p = "expected valid AT&T symbol";
! 350: break;
! 351: case (ENAME):
! 352: p = "default name not yet set";
! 353: break;
! 354: case (ENOWIDTH):
! 355: p = "superfluous width argument";
! 356: break;
! 357: case (EMISSWIDTH):
! 358: p = "missing width argument";
! 359: break;
! 360: case (EWRONGMSEC):
! 361: p = "document section in wrong manual section";
! 362: break;
! 363: case (ESECOOO):
! 364: p = "document section out of conventional order";
! 365: break;
! 366: case (ESECREP):
! 367: p = "document section repeated";
! 368: break;
! 369: case (EBADSTAND):
! 370: p = "unknown standard";
! 371: break;
! 372: case (ENAMESECINC):
! 373: p = "NAME section contents incomplete/badly-ordered";
! 374: break;
! 375: case (ENOMULTILINE):
! 376: p = "suggested no multi-line arguments";
! 377: break;
! 378: case (EMULTILINE):
! 379: p = "suggested multi-line arguments";
! 380: break;
! 381: case (ENOLINE):
! 382: p = "suggested no line arguments";
! 383: break;
! 384: case (EPROLOOO):
! 385: p = "prologue macros out-of-order";
! 386: break;
! 387: case (EPROLREP):
! 388: p = "prologue macros repeated";
! 389: break;
! 390: case (EARGVAL):
! 391: p = "argument value suggested";
! 392: break;
! 393: case (EFONT):
! 394: p = "invalid font mode";
! 395: break;
! 396: case (EBADMSEC):
! 397: p = "inappropriate manual section";
! 398: break;
! 399: case (EBADSEC):
! 400: p = "inappropriate document section";
! 401: break;
! 402: case (EQUOTTERM):
! 403: p = "unterminated quoted parameter";
! 404: break;
! 405: case (EQUOTPARM):
! 406: p = "unexpected quoted parameter";
! 407: break;
! 408: case (EARGVPARM):
! 409: p = "argument-like parameter";
! 410: break;
! 411: case (ECOLEMPTY):
! 412: p = "last list column is empty";
! 413: break;
! 414: case (ETAILWS):
! 415: p = "trailing whitespace";
! 416: break;
! 417: case (ENUMFMT):
! 418: p = "bad number format";
! 419: break;
! 420: case (EUTSNAME):
! 421: p = "utsname";
! 422: break;
! 423: case (EBADDATE):
! 424: p = "malformed date syntax";
! 425: break;
! 426: case (EOPEN):
! 427: p = "explicit scope still open on exit";
! 428: break;
! 429: case (EQUOT):
! 430: p = "unterminated quotation";
! 431: break;
! 432: case (ENOCTX):
! 433: p = "closure has no prior context";
! 434: break;
! 435: case (ENOPARMS):
! 436: p = "unexpect line arguments";
! 437: break;
! 438: case (EIGNE):
! 439: p = "ignoring empty element";
! 440: break;
! 441: case (EIMPBRK):
! 442: p = "crufty end-of-line scope violation";
! 443: break;
! 444: case (EMACPARM):
! 445: p = "macro-like parameter";
! 446: break;
! 447: case (EOBS):
! 448: p = "macro marked obsolete";
! 449: break;
1.73 kristaps 450: }
1.88 ! kristaps 451:
1.73 kristaps 452: assert(p);
1.88 ! kristaps 453:
! 454: if (iserr)
! 455: return(mdoc_verr(m, line, pos, p));
! 456:
! 457: return(mdoc_vwarn(m, line, pos, p));
! 458: }
! 459:
! 460:
! 461: int
! 462: mdoc_macro(struct mdoc *m, int tok,
! 463: int ln, int pp, int *pos, char *buf)
! 464: {
! 465:
! 466: if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
! 467: MDOC_PBODY & m->flags)
! 468: return(mdoc_perr(m, ln, pp, EPROLBODY));
! 469: if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
! 470: ! (MDOC_PBODY & m->flags))
! 471: return(mdoc_perr(m, ln, pp, EBODYPROL));
! 472:
! 473: if (1 != pp && ! (MDOC_CALLABLE & mdoc_macros[tok].flags))
! 474: return(mdoc_perr(m, ln, pp, ENOCALL));
! 475:
! 476: return((*mdoc_macros[tok].fp)(m, tok, ln, pp, pos, buf));
1.73 kristaps 477: }
478:
479:
480: static int
481: node_append(struct mdoc *mdoc, struct mdoc_node *p)
1.1 kristaps 482: {
483:
1.25 kristaps 484: assert(mdoc->last);
485: assert(mdoc->first);
486: assert(MDOC_ROOT != p->type);
1.1 kristaps 487:
1.13 kristaps 488: switch (mdoc->next) {
489: case (MDOC_NEXT_SIBLING):
1.6 kristaps 490: mdoc->last->next = p;
491: p->prev = mdoc->last;
1.13 kristaps 492: p->parent = mdoc->last->parent;
1.1 kristaps 493: break;
1.13 kristaps 494: case (MDOC_NEXT_CHILD):
495: mdoc->last->child = p;
1.1 kristaps 496: p->parent = mdoc->last;
497: break;
498: default:
1.13 kristaps 499: abort();
500: /* NOTREACHED */
1.1 kristaps 501: }
502:
1.86 kristaps 503: p->parent->nchild++;
504:
1.23 kristaps 505: if ( ! mdoc_valid_pre(mdoc, p))
506: return(0);
1.68 kristaps 507: if ( ! mdoc_action_pre(mdoc, p))
508: return(0);
1.27 kristaps 509:
510: switch (p->type) {
511: case (MDOC_HEAD):
512: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 513: p->parent->head = p;
1.27 kristaps 514: break;
515: case (MDOC_TAIL):
516: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 517: p->parent->tail = p;
1.27 kristaps 518: break;
519: case (MDOC_BODY):
520: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 521: p->parent->body = p;
1.27 kristaps 522: break;
523: default:
524: break;
525: }
526:
1.1 kristaps 527: mdoc->last = p;
1.71 kristaps 528:
529: switch (p->type) {
530: case (MDOC_TEXT):
531: if ( ! mdoc_valid_post(mdoc))
532: return(0);
533: if ( ! mdoc_action_post(mdoc))
534: return(0);
535: break;
536: default:
537: break;
538: }
539:
1.23 kristaps 540: return(1);
1.1 kristaps 541: }
542:
543:
1.45 kristaps 544: static struct mdoc_node *
1.73 kristaps 545: node_alloc(struct mdoc *mdoc, int line,
546: int pos, int tok, enum mdoc_type type)
1.45 kristaps 547: {
1.46 kristaps 548: struct mdoc_node *p;
549:
1.73 kristaps 550: if (NULL == (p = calloc(1, sizeof(struct mdoc_node)))) {
1.88 ! kristaps 551: (void)mdoc_nerr(mdoc, mdoc->last, EMALLOC);
1.73 kristaps 552: return(NULL);
553: }
554:
1.46 kristaps 555: p->sec = mdoc->lastsec;
1.73 kristaps 556: p->line = line;
557: p->pos = pos;
558: p->tok = tok;
559: if (MDOC_TEXT != (p->type = type))
560: assert(p->tok >= 0);
1.45 kristaps 561:
1.46 kristaps 562: return(p);
1.45 kristaps 563: }
564:
565:
1.23 kristaps 566: int
1.22 kristaps 567: mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, int tok)
1.17 kristaps 568: {
569: struct mdoc_node *p;
570:
1.73 kristaps 571: p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL);
572: if (NULL == p)
573: return(0);
574: return(node_append(mdoc, p));
1.17 kristaps 575: }
576:
577:
1.23 kristaps 578: int
1.22 kristaps 579: mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, int tok)
1.1 kristaps 580: {
581: struct mdoc_node *p;
582:
583: assert(mdoc->first);
584: assert(mdoc->last);
585:
1.73 kristaps 586: p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD);
587: if (NULL == p)
588: return(0);
589: return(node_append(mdoc, p));
1.1 kristaps 590: }
591:
592:
1.23 kristaps 593: int
1.22 kristaps 594: mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, int tok)
1.1 kristaps 595: {
596: struct mdoc_node *p;
597:
1.73 kristaps 598: p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
599: if (NULL == p)
600: return(0);
601: return(node_append(mdoc, p));
1.1 kristaps 602: }
603:
604:
1.23 kristaps 605: int
1.22 kristaps 606: mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
1.53 kristaps 607: int tok, struct mdoc_arg *args)
1.1 kristaps 608: {
609: struct mdoc_node *p;
610:
1.73 kristaps 611: p = node_alloc(mdoc, line, pos, tok, MDOC_BLOCK);
612: if (NULL == p)
613: return(0);
1.77 kristaps 614: p->args = args;
615: if (p->args)
1.53 kristaps 616: (args->refcnt)++;
1.73 kristaps 617: return(node_append(mdoc, p));
1.1 kristaps 618: }
619:
620:
1.23 kristaps 621: int
1.22 kristaps 622: mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
1.53 kristaps 623: int tok, struct mdoc_arg *args)
1.1 kristaps 624: {
625: struct mdoc_node *p;
626:
1.73 kristaps 627: p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM);
628: if (NULL == p)
629: return(0);
1.77 kristaps 630: p->args = args;
631: if (p->args)
1.53 kristaps 632: (args->refcnt)++;
1.73 kristaps 633: return(node_append(mdoc, p));
1.1 kristaps 634: }
635:
636:
1.23 kristaps 637: int
1.22 kristaps 638: mdoc_word_alloc(struct mdoc *mdoc,
639: int line, int pos, const char *word)
1.1 kristaps 640: {
641: struct mdoc_node *p;
642:
1.73 kristaps 643: p = node_alloc(mdoc, line, pos, -1, MDOC_TEXT);
644: if (NULL == p)
645: return(0);
646: if (NULL == (p->string = strdup(word))) {
1.88 ! kristaps 647: (void)mdoc_nerr(mdoc, mdoc->last, EMALLOC);
1.73 kristaps 648: return(0);
649: }
1.88 ! kristaps 650:
1.73 kristaps 651: return(node_append(mdoc, p));
1.1 kristaps 652: }
653:
654:
1.53 kristaps 655: void
656: mdoc_node_free(struct mdoc_node *p)
1.1 kristaps 657: {
658:
1.86 kristaps 659: if (p->parent)
660: p->parent->nchild--;
1.53 kristaps 661: if (p->string)
662: free(p->string);
663: if (p->args)
664: mdoc_argv_free(p->args);
1.1 kristaps 665: free(p);
666: }
667:
668:
1.53 kristaps 669: void
670: mdoc_node_freelist(struct mdoc_node *p)
1.1 kristaps 671: {
672:
1.53 kristaps 673: if (p->child)
674: mdoc_node_freelist(p->child);
675: if (p->next)
676: mdoc_node_freelist(p->next);
1.1 kristaps 677:
1.86 kristaps 678: assert(0 == p->nchild);
1.53 kristaps 679: mdoc_node_free(p);
1.1 kristaps 680: }
681:
682:
1.53 kristaps 683: /*
684: * Parse free-form text, that is, a line that does not begin with the
685: * control character.
686: */
687: static int
1.68 kristaps 688: parsetext(struct mdoc *m, int line, char *buf)
1.1 kristaps 689: {
690:
1.85 kristaps 691: if (SEC_NONE == m->lastnamed)
1.88 ! kristaps 692: return(mdoc_perr(m, line, 0, ETEXTPROL));
1.1 kristaps 693:
1.68 kristaps 694: if (0 == buf[0] && ! (MDOC_LITERAL & m->flags))
1.88 ! kristaps 695: return(mdoc_perr(m, line, 0, ENOBLANK));
1.68 kristaps 696:
697: if ( ! mdoc_word_alloc(m, line, 0, buf))
1.53 kristaps 698: return(0);
1.1 kristaps 699:
1.68 kristaps 700: m->next = MDOC_NEXT_SIBLING;
1.53 kristaps 701: return(1);
1.1 kristaps 702: }
703:
704:
1.58 kristaps 705: static int
706: macrowarn(struct mdoc *m, int ln, const char *buf)
707: {
708: if ( ! (MDOC_IGN_MACRO & m->pflags))
1.88 ! kristaps 709: return(mdoc_verr(m, ln, 1,
1.73 kristaps 710: "unknown macro: %s%s",
1.59 kristaps 711: buf, strlen(buf) > 3 ? "..." : ""));
1.88 ! kristaps 712: return(mdoc_vwarn(m, ln, 1, "unknown macro: %s%s",
1.59 kristaps 713: buf, strlen(buf) > 3 ? "..." : ""));
1.58 kristaps 714: }
715:
716:
1.53 kristaps 717: /*
718: * Parse a macro line, that is, a line beginning with the control
719: * character.
720: */
721: int
722: parsemacro(struct mdoc *m, int ln, char *buf)
1.1 kristaps 723: {
1.53 kristaps 724: int i, c;
725: char mac[5];
1.1 kristaps 726:
1.81 kristaps 727: /* Empty lines are ignored. */
1.63 kristaps 728:
729: if (0 == buf[1])
730: return(1);
731:
1.65 kristaps 732: if (' ' == buf[1]) {
1.63 kristaps 733: i = 2;
1.65 kristaps 734: while (buf[i] && ' ' == buf[i])
1.63 kristaps 735: i++;
736: if (0 == buf[i])
737: return(1);
1.88 ! kristaps 738: return(mdoc_perr(m, ln, 1, ESPACE));
1.63 kristaps 739: }
1.1 kristaps 740:
1.53 kristaps 741: /* Copy the first word into a nil-terminated buffer. */
1.1 kristaps 742:
1.53 kristaps 743: for (i = 1; i < 5; i++) {
744: if (0 == (mac[i - 1] = buf[i]))
745: break;
1.65 kristaps 746: else if (' ' == buf[i])
1.53 kristaps 747: break;
748: }
1.1 kristaps 749:
1.53 kristaps 750: mac[i - 1] = 0;
1.1 kristaps 751:
1.53 kristaps 752: if (i == 5 || i <= 2) {
1.58 kristaps 753: if ( ! macrowarn(m, ln, mac))
754: goto err;
755: return(1);
1.53 kristaps 756: }
757:
1.74 kristaps 758: if (MDOC_MAX == (c = mdoc_hash_find(m->htab, mac))) {
1.58 kristaps 759: if ( ! macrowarn(m, ln, mac))
760: goto err;
761: return(1);
1.53 kristaps 762: }
1.1 kristaps 763:
1.53 kristaps 764: /* The macro is sane. Jump to the next word. */
1.1 kristaps 765:
1.65 kristaps 766: while (buf[i] && ' ' == buf[i])
1.53 kristaps 767: i++;
1.1 kristaps 768:
1.53 kristaps 769: /* Begin recursive parse sequence. */
1.1 kristaps 770:
1.53 kristaps 771: if ( ! mdoc_macro(m, c, ln, 1, &i, buf))
772: goto err;
1.1 kristaps 773:
1.53 kristaps 774: return(1);
1.1 kristaps 775:
1.53 kristaps 776: err: /* Error out. */
1.1 kristaps 777:
1.53 kristaps 778: m->flags |= MDOC_HALT;
779: return(0);
1.1 kristaps 780: }
CVSweb