Annotation of mandoc/mdoc.c, Revision 1.174
1.174 ! kristaps 1: /* $Id: mdoc.c,v 1.173 2010/12/25 13:50:37 kristaps Exp $ */
1.1 kristaps 2: /*
1.157 schwarze 3: * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
4: * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 5: *
6: * Permission to use, copy, modify, and distribute this software for any
1.75 kristaps 7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 9: *
1.75 kristaps 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 17: */
1.114 kristaps 18: #ifdef HAVE_CONFIG_H
19: #include "config.h"
20: #endif
21:
1.106 kristaps 22: #include <sys/types.h>
23:
1.1 kristaps 24: #include <assert.h>
25: #include <stdarg.h>
1.73 kristaps 26: #include <stdio.h>
1.1 kristaps 27: #include <stdlib.h>
28: #include <string.h>
1.120 kristaps 29: #include <time.h>
1.1 kristaps 30:
1.136 kristaps 31: #include "mandoc.h"
1.70 kristaps 32: #include "libmdoc.h"
1.113 kristaps 33: #include "libmandoc.h"
1.1 kristaps 34:
35: const char *const __mdoc_macronames[MDOC_MAX] = {
1.82 kristaps 36: "Ap", "Dd", "Dt", "Os",
1.1 kristaps 37: "Sh", "Ss", "Pp", "D1",
38: "Dl", "Bd", "Ed", "Bl",
39: "El", "It", "Ad", "An",
40: "Ar", "Cd", "Cm", "Dv",
41: "Er", "Ev", "Ex", "Fa",
42: "Fd", "Fl", "Fn", "Ft",
43: "Ic", "In", "Li", "Nd",
44: "Nm", "Op", "Ot", "Pa",
45: "Rv", "St", "Va", "Vt",
46: /* LINTED */
1.114 kristaps 47: "Xr", "%A", "%B", "%D",
1.1 kristaps 48: /* LINTED */
1.114 kristaps 49: "%I", "%J", "%N", "%O",
1.1 kristaps 50: /* LINTED */
1.114 kristaps 51: "%P", "%R", "%T", "%V",
1.1 kristaps 52: "Ac", "Ao", "Aq", "At",
53: "Bc", "Bf", "Bo", "Bq",
54: "Bsx", "Bx", "Db", "Dc",
55: "Do", "Dq", "Ec", "Ef",
56: "Em", "Eo", "Fx", "Ms",
57: "No", "Ns", "Nx", "Ox",
58: "Pc", "Pf", "Po", "Pq",
59: "Qc", "Ql", "Qo", "Qq",
60: "Re", "Rs", "Sc", "So",
61: "Sq", "Sm", "Sx", "Sy",
62: "Tn", "Ux", "Xc", "Xo",
63: "Fo", "Fc", "Oo", "Oc",
64: "Bk", "Ek", "Bt", "Hf",
1.82 kristaps 65: "Fr", "Ud", "Lb", "Lp",
66: "Lk", "Mt", "Brq", "Bro",
1.64 kristaps 67: /* LINTED */
1.114 kristaps 68: "Brc", "%C", "Es", "En",
1.69 kristaps 69: /* LINTED */
1.114 kristaps 70: "Dx", "%Q", "br", "sp",
1.110 kristaps 71: /* LINTED */
1.141 kristaps 72: "%U", "Ta"
1.1 kristaps 73: };
74:
75: const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
76: "split", "nosplit", "ragged",
77: "unfilled", "literal", "file",
78: "offset", "bullet", "dash",
79: "hyphen", "item", "enum",
80: "tag", "diag", "hang",
81: "ohang", "inset", "column",
82: "width", "compact", "std",
1.52 kristaps 83: "filled", "words", "emphasis",
1.108 kristaps 84: "symbolic", "nested", "centered"
1.1 kristaps 85: };
86:
87: const char * const *mdoc_macronames = __mdoc_macronames;
88: const char * const *mdoc_argnames = __mdoc_argnames;
89:
1.121 kristaps 90: static void mdoc_node_free(struct mdoc_node *);
91: static void mdoc_node_unlink(struct mdoc *,
92: struct mdoc_node *);
1.73 kristaps 93: static void mdoc_free1(struct mdoc *);
1.113 kristaps 94: static void mdoc_alloc1(struct mdoc *);
1.73 kristaps 95: static struct mdoc_node *node_alloc(struct mdoc *, int, int,
1.117 kristaps 96: enum mdoct, enum mdoc_type);
1.73 kristaps 97: static int node_append(struct mdoc *,
1.71 kristaps 98: struct mdoc_node *);
1.149 kristaps 99: static int mdoc_ptext(struct mdoc *, int, char *, int);
100: static int mdoc_pmacro(struct mdoc *, int, char *, int);
1.124 kristaps 101:
1.88 kristaps 102:
1.1 kristaps 103: const struct mdoc_node *
1.71 kristaps 104: mdoc_node(const struct mdoc *m)
1.1 kristaps 105: {
106:
1.71 kristaps 107: return(MDOC_HALT & m->flags ? NULL : m->first);
1.1 kristaps 108: }
109:
110:
1.37 kristaps 111: const struct mdoc_meta *
1.71 kristaps 112: mdoc_meta(const struct mdoc *m)
1.37 kristaps 113: {
114:
1.71 kristaps 115: return(MDOC_HALT & m->flags ? NULL : &m->meta);
1.37 kristaps 116: }
117:
118:
1.85 kristaps 119: /*
120: * Frees volatile resources (parse tree, meta-data, fields).
121: */
1.73 kristaps 122: static void
123: mdoc_free1(struct mdoc *mdoc)
1.67 kristaps 124: {
125:
126: if (mdoc->first)
1.121 kristaps 127: mdoc_node_delete(mdoc, mdoc->first);
1.67 kristaps 128: if (mdoc->meta.title)
129: free(mdoc->meta.title);
130: if (mdoc->meta.os)
131: free(mdoc->meta.os);
132: if (mdoc->meta.name)
133: free(mdoc->meta.name);
134: if (mdoc->meta.arch)
135: free(mdoc->meta.arch);
136: if (mdoc->meta.vol)
137: free(mdoc->meta.vol);
1.133 kristaps 138: if (mdoc->meta.msec)
139: free(mdoc->meta.msec);
1.73 kristaps 140: }
141:
142:
1.85 kristaps 143: /*
144: * Allocate all volatile resources (parse tree, meta-data, fields).
145: */
1.113 kristaps 146: static void
1.73 kristaps 147: mdoc_alloc1(struct mdoc *mdoc)
148: {
1.67 kristaps 149:
1.112 kristaps 150: memset(&mdoc->meta, 0, sizeof(struct mdoc_meta));
1.67 kristaps 151: mdoc->flags = 0;
1.85 kristaps 152: mdoc->lastnamed = mdoc->lastsec = SEC_NONE;
1.113 kristaps 153: mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node));
1.70 kristaps 154: mdoc->first = mdoc->last;
1.67 kristaps 155: mdoc->last->type = MDOC_ROOT;
156: mdoc->next = MDOC_NEXT_CHILD;
1.73 kristaps 157: }
158:
159:
160: /*
1.85 kristaps 161: * Free up volatile resources (see mdoc_free1()) then re-initialises the
162: * data with mdoc_alloc1(). After invocation, parse data has been reset
163: * and the parser is ready for re-invocation on a new tree; however,
164: * cross-parse non-volatile data is kept intact.
1.73 kristaps 165: */
1.113 kristaps 166: void
1.73 kristaps 167: mdoc_reset(struct mdoc *mdoc)
168: {
169:
170: mdoc_free1(mdoc);
1.113 kristaps 171: mdoc_alloc1(mdoc);
1.67 kristaps 172: }
173:
174:
1.68 kristaps 175: /*
1.85 kristaps 176: * Completely free up all volatile and non-volatile parse resources.
177: * After invocation, the pointer is no longer usable.
1.68 kristaps 178: */
1.67 kristaps 179: void
1.38 kristaps 180: mdoc_free(struct mdoc *mdoc)
1.34 kristaps 181: {
182:
1.73 kristaps 183: mdoc_free1(mdoc);
1.1 kristaps 184: free(mdoc);
185: }
186:
187:
1.85 kristaps 188: /*
189: * Allocate volatile and non-volatile parse resources.
190: */
1.1 kristaps 191: struct mdoc *
1.163 schwarze 192: mdoc_alloc(struct regset *regs, void *data, mandocmsg msg)
1.1 kristaps 193: {
194: struct mdoc *p;
195:
1.113 kristaps 196: p = mandoc_calloc(1, sizeof(struct mdoc));
197:
1.136 kristaps 198: p->msg = msg;
1.1 kristaps 199: p->data = data;
1.149 kristaps 200: p->regs = regs;
1.73 kristaps 201:
1.113 kristaps 202: mdoc_hash_init();
203: mdoc_alloc1(p);
204: return(p);
1.1 kristaps 205: }
206:
207:
1.68 kristaps 208: /*
209: * Climb back up the parse tree, validating open scopes. Mostly calls
1.85 kristaps 210: * through to macro_end() in macro.c.
1.68 kristaps 211: */
1.1 kristaps 212: int
1.72 kristaps 213: mdoc_endparse(struct mdoc *m)
1.20 kristaps 214: {
215:
1.72 kristaps 216: if (MDOC_HALT & m->flags)
1.20 kristaps 217: return(0);
1.72 kristaps 218: else if (mdoc_macroend(m))
1.20 kristaps 219: return(1);
1.72 kristaps 220: m->flags |= MDOC_HALT;
221: return(0);
1.20 kristaps 222: }
223:
224:
1.50 kristaps 225: /*
1.53 kristaps 226: * Main parse routine. Parses a single line -- really just hands off to
1.123 kristaps 227: * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
1.50 kristaps 228: */
1.20 kristaps 229: int
1.149 kristaps 230: mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs)
1.1 kristaps 231: {
232:
1.53 kristaps 233: if (MDOC_HALT & m->flags)
1.20 kristaps 234: return(0);
1.50 kristaps 235:
1.130 kristaps 236: m->flags |= MDOC_NEWLINE;
1.153 schwarze 237:
238: /*
239: * Let the roff nS register switch SYNOPSIS mode early,
240: * such that the parser knows at all times
241: * whether this mode is on or off.
242: * Note that this mode is also switched by the Sh macro.
243: */
244: if (m->regs->regs[(int)REG_nS].set) {
245: if (m->regs->regs[(int)REG_nS].v.u)
246: m->flags |= MDOC_SYNOPSIS;
247: else
248: m->flags &= ~MDOC_SYNOPSIS;
249: }
250:
1.135 kristaps 251: return(('.' == buf[offs] || '\'' == buf[offs]) ?
1.149 kristaps 252: mdoc_pmacro(m, ln, buf, offs) :
253: mdoc_ptext(m, ln, buf, offs));
1.1 kristaps 254: }
255:
256:
257: int
1.136 kristaps 258: mdoc_vmsg(struct mdoc *mdoc, enum mandocerr t,
259: int ln, int pos, const char *fmt, ...)
1.1 kristaps 260: {
1.31 kristaps 261: char buf[256];
262: va_list ap;
1.1 kristaps 263:
1.31 kristaps 264: va_start(ap, fmt);
1.136 kristaps 265: vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
1.31 kristaps 266: va_end(ap);
1.88 kristaps 267:
1.136 kristaps 268: return((*mdoc->msg)(t, mdoc->data, ln, pos, buf));
1.88 kristaps 269: }
270:
271:
272: int
1.148 kristaps 273: mdoc_macro(MACRO_PROT_ARGS)
1.88 kristaps 274: {
1.122 kristaps 275: assert(tok < MDOC_MAX);
276:
277: /* If we're in the body, deny prologue calls. */
1.117 kristaps 278:
1.88 kristaps 279: if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
1.174 ! kristaps 280: MDOC_PBODY & m->flags) {
! 281: mdoc_pmsg(m, line, ppos, MANDOCERR_BADBODY);
! 282: return(1);
! 283: }
1.122 kristaps 284:
285: /* If we're in the prologue, deny "body" macros. */
286:
287: if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
288: ! (MDOC_PBODY & m->flags)) {
1.174 ! kristaps 289: mdoc_pmsg(m, line, ppos, MANDOCERR_BADPROLOG);
1.167 kristaps 290: if (NULL == m->meta.msec)
291: m->meta.msec = mandoc_strdup("1");
1.120 kristaps 292: if (NULL == m->meta.title)
1.140 kristaps 293: m->meta.title = mandoc_strdup("UNKNOWN");
1.120 kristaps 294: if (NULL == m->meta.vol)
1.140 kristaps 295: m->meta.vol = mandoc_strdup("LOCAL");
1.120 kristaps 296: if (NULL == m->meta.os)
1.140 kristaps 297: m->meta.os = mandoc_strdup("LOCAL");
1.120 kristaps 298: if (0 == m->meta.date)
299: m->meta.date = time(NULL);
300: m->flags |= MDOC_PBODY;
301: }
1.88 kristaps 302:
1.149 kristaps 303: return((*mdoc_macros[tok].fp)(m, tok, line, ppos, pos, buf));
1.73 kristaps 304: }
305:
306:
307: static int
308: node_append(struct mdoc *mdoc, struct mdoc_node *p)
1.1 kristaps 309: {
310:
1.25 kristaps 311: assert(mdoc->last);
312: assert(mdoc->first);
313: assert(MDOC_ROOT != p->type);
1.1 kristaps 314:
1.13 kristaps 315: switch (mdoc->next) {
316: case (MDOC_NEXT_SIBLING):
1.6 kristaps 317: mdoc->last->next = p;
318: p->prev = mdoc->last;
1.13 kristaps 319: p->parent = mdoc->last->parent;
1.1 kristaps 320: break;
1.13 kristaps 321: case (MDOC_NEXT_CHILD):
322: mdoc->last->child = p;
1.1 kristaps 323: p->parent = mdoc->last;
324: break;
325: default:
1.13 kristaps 326: abort();
327: /* NOTREACHED */
1.1 kristaps 328: }
329:
1.86 kristaps 330: p->parent->nchild++;
331:
1.172 kristaps 332: /*
333: * Copy over the normalised-data pointer of our parent. Not
334: * everybody has one, but copying a null pointer is fine.
335: */
336:
337: switch (p->type) {
338: case (MDOC_BODY):
339: /* FALLTHROUGH */
340: case (MDOC_TAIL):
341: /* FALLTHROUGH */
342: case (MDOC_HEAD):
343: p->norm = p->parent->norm;
344: break;
345: default:
346: break;
347: }
348:
1.23 kristaps 349: if ( ! mdoc_valid_pre(mdoc, p))
350: return(0);
1.27 kristaps 351:
352: switch (p->type) {
353: case (MDOC_HEAD):
354: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 355: p->parent->head = p;
1.27 kristaps 356: break;
357: case (MDOC_TAIL):
358: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 359: p->parent->tail = p;
1.27 kristaps 360: break;
361: case (MDOC_BODY):
1.152 schwarze 362: if (p->end)
363: break;
1.27 kristaps 364: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 365: p->parent->body = p;
1.27 kristaps 366: break;
367: default:
368: break;
369: }
370:
1.1 kristaps 371: mdoc->last = p;
1.71 kristaps 372:
373: switch (p->type) {
374: case (MDOC_TEXT):
375: if ( ! mdoc_valid_post(mdoc))
376: return(0);
377: break;
378: default:
379: break;
380: }
381:
1.23 kristaps 382: return(1);
1.1 kristaps 383: }
384:
385:
1.45 kristaps 386: static struct mdoc_node *
1.117 kristaps 387: node_alloc(struct mdoc *m, int line, int pos,
388: enum mdoct tok, enum mdoc_type type)
1.45 kristaps 389: {
1.46 kristaps 390: struct mdoc_node *p;
391:
1.113 kristaps 392: p = mandoc_calloc(1, sizeof(struct mdoc_node));
1.91 kristaps 393: p->sec = m->lastsec;
1.73 kristaps 394: p->line = line;
395: p->pos = pos;
396: p->tok = tok;
1.118 kristaps 397: p->type = type;
1.150 kristaps 398:
399: /* Flag analysis. */
400:
1.153 schwarze 401: if (MDOC_SYNOPSIS & m->flags)
402: p->flags |= MDOC_SYNPRETTY;
403: else
404: p->flags &= ~MDOC_SYNPRETTY;
1.130 kristaps 405: if (MDOC_NEWLINE & m->flags)
406: p->flags |= MDOC_LINE;
407: m->flags &= ~MDOC_NEWLINE;
1.150 kristaps 408:
1.46 kristaps 409: return(p);
1.45 kristaps 410: }
411:
412:
1.23 kristaps 413: int
1.117 kristaps 414: mdoc_tail_alloc(struct mdoc *m, int line, int pos, enum mdoct tok)
1.17 kristaps 415: {
416: struct mdoc_node *p;
417:
1.91 kristaps 418: p = node_alloc(m, line, pos, tok, MDOC_TAIL);
1.102 kristaps 419: if ( ! node_append(m, p))
420: return(0);
421: m->next = MDOC_NEXT_CHILD;
422: return(1);
1.17 kristaps 423: }
424:
425:
1.23 kristaps 426: int
1.117 kristaps 427: mdoc_head_alloc(struct mdoc *m, int line, int pos, enum mdoct tok)
1.1 kristaps 428: {
429: struct mdoc_node *p;
430:
1.91 kristaps 431: assert(m->first);
432: assert(m->last);
1.1 kristaps 433:
1.91 kristaps 434: p = node_alloc(m, line, pos, tok, MDOC_HEAD);
1.102 kristaps 435: if ( ! node_append(m, p))
436: return(0);
437: m->next = MDOC_NEXT_CHILD;
438: return(1);
1.1 kristaps 439: }
440:
441:
1.23 kristaps 442: int
1.117 kristaps 443: mdoc_body_alloc(struct mdoc *m, int line, int pos, enum mdoct tok)
1.1 kristaps 444: {
445: struct mdoc_node *p;
446:
1.91 kristaps 447: p = node_alloc(m, line, pos, tok, MDOC_BODY);
1.102 kristaps 448: if ( ! node_append(m, p))
449: return(0);
450: m->next = MDOC_NEXT_CHILD;
1.152 schwarze 451: return(1);
452: }
453:
454:
455: int
456: mdoc_endbody_alloc(struct mdoc *m, int line, int pos, enum mdoct tok,
457: struct mdoc_node *body, enum mdoc_endbody end)
458: {
459: struct mdoc_node *p;
460:
461: p = node_alloc(m, line, pos, tok, MDOC_BODY);
462: p->pending = body;
463: p->end = end;
464: if ( ! node_append(m, p))
465: return(0);
466: m->next = MDOC_NEXT_SIBLING;
1.102 kristaps 467: return(1);
1.1 kristaps 468: }
469:
470:
1.23 kristaps 471: int
1.91 kristaps 472: mdoc_block_alloc(struct mdoc *m, int line, int pos,
1.117 kristaps 473: enum mdoct tok, struct mdoc_arg *args)
1.1 kristaps 474: {
475: struct mdoc_node *p;
476:
1.91 kristaps 477: p = node_alloc(m, line, pos, tok, MDOC_BLOCK);
1.77 kristaps 478: p->args = args;
479: if (p->args)
1.53 kristaps 480: (args->refcnt)++;
1.172 kristaps 481:
482: switch (tok) {
483: case (MDOC_Bd):
484: /* FALLTHROUGH */
485: case (MDOC_Bf):
486: /* FALLTHROUGH */
487: case (MDOC_Bl):
1.173 kristaps 488: /* FALLTHROUGH */
489: case (MDOC_Rs):
1.172 kristaps 490: p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
491: break;
492: default:
493: break;
494: }
495:
1.102 kristaps 496: if ( ! node_append(m, p))
497: return(0);
498: m->next = MDOC_NEXT_CHILD;
499: return(1);
1.1 kristaps 500: }
501:
502:
1.23 kristaps 503: int
1.91 kristaps 504: mdoc_elem_alloc(struct mdoc *m, int line, int pos,
1.117 kristaps 505: enum mdoct tok, struct mdoc_arg *args)
1.1 kristaps 506: {
507: struct mdoc_node *p;
508:
1.91 kristaps 509: p = node_alloc(m, line, pos, tok, MDOC_ELEM);
1.77 kristaps 510: p->args = args;
511: if (p->args)
1.53 kristaps 512: (args->refcnt)++;
1.172 kristaps 513:
514: switch (tok) {
515: case (MDOC_An):
516: p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
517: break;
518: default:
519: break;
520: }
521:
1.102 kristaps 522: if ( ! node_append(m, p))
523: return(0);
524: m->next = MDOC_NEXT_CHILD;
525: return(1);
1.1 kristaps 526: }
527:
528:
1.124 kristaps 529: int
530: mdoc_word_alloc(struct mdoc *m, int line, int pos, const char *p)
1.1 kristaps 531: {
1.91 kristaps 532: struct mdoc_node *n;
1.124 kristaps 533: size_t sv, len;
534:
535: len = strlen(p);
1.1 kristaps 536:
1.125 kristaps 537: n = node_alloc(m, line, pos, MDOC_MAX, MDOC_TEXT);
1.113 kristaps 538: n->string = mandoc_malloc(len + 1);
1.91 kristaps 539: sv = strlcpy(n->string, p, len + 1);
540:
541: /* Prohibit truncation. */
542: assert(sv < len + 1);
543:
1.101 kristaps 544: if ( ! node_append(m, n))
545: return(0);
1.124 kristaps 546:
1.101 kristaps 547: m->next = MDOC_NEXT_SIBLING;
548: return(1);
1.91 kristaps 549: }
550:
551:
1.155 kristaps 552: static void
1.53 kristaps 553: mdoc_node_free(struct mdoc_node *p)
1.1 kristaps 554: {
555:
1.172 kristaps 556: if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type)
1.171 kristaps 557: free(p->norm);
1.53 kristaps 558: if (p->string)
559: free(p->string);
560: if (p->args)
561: mdoc_argv_free(p->args);
1.1 kristaps 562: free(p);
563: }
564:
565:
1.121 kristaps 566: static void
567: mdoc_node_unlink(struct mdoc *m, struct mdoc_node *n)
568: {
569:
570: /* Adjust siblings. */
571:
572: if (n->prev)
573: n->prev->next = n->next;
574: if (n->next)
575: n->next->prev = n->prev;
576:
577: /* Adjust parent. */
578:
579: if (n->parent) {
580: n->parent->nchild--;
581: if (n->parent->child == n)
582: n->parent->child = n->prev ? n->prev : n->next;
1.169 kristaps 583: if (n->parent->last == n)
584: n->parent->last = n->prev ? n->prev : NULL;
1.121 kristaps 585: }
586:
587: /* Adjust parse point, if applicable. */
588:
589: if (m && m->last == n) {
590: if (n->prev) {
591: m->last = n->prev;
592: m->next = MDOC_NEXT_SIBLING;
593: } else {
594: m->last = n->parent;
595: m->next = MDOC_NEXT_CHILD;
596: }
597: }
598:
599: if (m && m->first == n)
600: m->first = NULL;
601: }
602:
603:
1.53 kristaps 604: void
1.121 kristaps 605: mdoc_node_delete(struct mdoc *m, struct mdoc_node *p)
1.1 kristaps 606: {
607:
1.121 kristaps 608: while (p->child) {
609: assert(p->nchild);
610: mdoc_node_delete(m, p->child);
611: }
612: assert(0 == p->nchild);
1.1 kristaps 613:
1.121 kristaps 614: mdoc_node_unlink(m, p);
1.53 kristaps 615: mdoc_node_free(p);
1.1 kristaps 616: }
617:
618:
1.53 kristaps 619: /*
620: * Parse free-form text, that is, a line that does not begin with the
621: * control character.
622: */
623: static int
1.149 kristaps 624: mdoc_ptext(struct mdoc *m, int line, char *buf, int offs)
1.1 kristaps 625: {
1.142 kristaps 626: char *c, *ws, *end;
627: struct mdoc_node *n;
1.1 kristaps 628:
1.123 kristaps 629: /* Ignore bogus comments. */
630:
1.135 kristaps 631: if ('\\' == buf[offs] &&
632: '.' == buf[offs + 1] &&
1.174 ! kristaps 633: '"' == buf[offs + 2]) {
! 634: mdoc_pmsg(m, line, offs, MANDOCERR_BADCOMMENT);
! 635: return(1);
! 636: }
1.123 kristaps 637:
1.124 kristaps 638: /* No text before an initial macro. */
639:
1.174 ! kristaps 640: if (SEC_NONE == m->lastnamed) {
! 641: mdoc_pmsg(m, line, offs, MANDOCERR_NOTEXT);
! 642: return(1);
! 643: }
1.142 kristaps 644:
645: assert(m->last);
646: n = m->last;
647:
648: /*
1.144 kristaps 649: * Divert directly to list processing if we're encountering a
1.142 kristaps 650: * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry
1.144 kristaps 651: * (a MDOC_BODY means it's already open, in which case we should
652: * process within its context in the normal way).
1.142 kristaps 653: */
654:
1.143 kristaps 655: if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
1.172 kristaps 656: LIST_column == n->norm->Bl.type) {
1.144 kristaps 657: /* `Bl' is open without any children. */
1.142 kristaps 658: m->flags |= MDOC_FREECOL;
1.149 kristaps 659: return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf));
1.142 kristaps 660: }
661:
662: if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
663: NULL != n->parent &&
664: MDOC_Bl == n->parent->tok &&
1.172 kristaps 665: LIST_column == n->parent->norm->Bl.type) {
1.144 kristaps 666: /* `Bl' has block-level `It' children. */
1.142 kristaps 667: m->flags |= MDOC_FREECOL;
1.149 kristaps 668: return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf));
1.142 kristaps 669: }
1.124 kristaps 670:
1.137 schwarze 671: /*
672: * Search for the beginning of unescaped trailing whitespace (ws)
673: * and for the first character not to be output (end).
674: */
1.139 kristaps 675:
676: /* FIXME: replace with strcspn(). */
1.137 schwarze 677: ws = NULL;
678: for (c = end = buf + offs; *c; c++) {
679: switch (*c) {
1.138 kristaps 680: case '-':
681: if (mandoc_hyph(buf + offs, c))
682: *c = ASCII_HYPH;
1.145 kristaps 683: ws = NULL;
1.138 kristaps 684: break;
1.137 schwarze 685: case ' ':
686: if (NULL == ws)
687: ws = c;
688: continue;
689: case '\t':
690: /*
691: * Always warn about trailing tabs,
692: * even outside literal context,
693: * where they should be put on the next line.
694: */
695: if (NULL == ws)
696: ws = c;
697: /*
698: * Strip trailing tabs in literal context only;
699: * outside, they affect the next line.
700: */
701: if (MDOC_LITERAL & m->flags)
702: continue;
703: break;
704: case '\\':
705: /* Skip the escaped character, too, if any. */
706: if (c[1])
707: c++;
708: /* FALLTHROUGH */
709: default:
710: ws = NULL;
711: break;
712: }
713: end = c + 1;
714: }
715: *end = '\0';
1.91 kristaps 716:
1.137 schwarze 717: if (ws)
1.174 ! kristaps 718: mdoc_pmsg(m, line, (int)(ws-buf), MANDOCERR_EOLNSPACE);
1.115 kristaps 719:
1.137 schwarze 720: if ('\0' == buf[offs] && ! (MDOC_LITERAL & m->flags)) {
1.174 ! kristaps 721: mdoc_pmsg(m, line, (int)(c-buf), MANDOCERR_NOBLANKLN);
1.124 kristaps 722:
1.119 kristaps 723: /*
1.165 schwarze 724: * Insert a `sp' in the case of a blank line. Technically,
1.124 kristaps 725: * blank lines aren't allowed, but enough manuals assume this
726: * behaviour that we want to work around it.
1.119 kristaps 727: */
1.165 schwarze 728: if ( ! mdoc_elem_alloc(m, line, offs, MDOC_sp, NULL))
1.119 kristaps 729: return(0);
1.124 kristaps 730:
731: m->next = MDOC_NEXT_SIBLING;
732: return(1);
1.119 kristaps 733: }
1.68 kristaps 734:
1.137 schwarze 735: if ( ! mdoc_word_alloc(m, line, offs, buf+offs))
736: return(0);
1.91 kristaps 737:
1.137 schwarze 738: if (MDOC_LITERAL & m->flags)
739: return(1);
1.128 kristaps 740:
741: /*
742: * End-of-sentence check. If the last character is an unescaped
743: * EOS character, then flag the node as being the end of a
744: * sentence. The front-end will know how to interpret this.
745: */
1.132 kristaps 746:
1.137 schwarze 747: assert(buf < end);
748:
1.159 schwarze 749: if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0))
1.128 kristaps 750: m->last->flags |= MDOC_EOS;
751:
752: return(1);
1.1 kristaps 753: }
754:
755:
1.53 kristaps 756: /*
757: * Parse a macro line, that is, a line beginning with the control
758: * character.
759: */
1.155 kristaps 760: static int
1.149 kristaps 761: mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs)
1.1 kristaps 762: {
1.144 kristaps 763: enum mdoct tok;
764: int i, j, sv;
765: char mac[5];
766: struct mdoc_node *n;
1.1 kristaps 767:
1.81 kristaps 768: /* Empty lines are ignored. */
1.63 kristaps 769:
1.135 kristaps 770: offs++;
771:
772: if ('\0' == buf[offs])
1.63 kristaps 773: return(1);
774:
1.135 kristaps 775: i = offs;
1.100 kristaps 776:
1.160 kristaps 777: /* Accept tabs/whitespace after the initial control char. */
1.100 kristaps 778:
1.160 kristaps 779: if (' ' == buf[i] || '\t' == buf[i]) {
1.100 kristaps 780: i++;
1.160 kristaps 781: while (buf[i] && (' ' == buf[i] || '\t' == buf[i]))
1.63 kristaps 782: i++;
1.115 kristaps 783: if ('\0' == buf[i])
1.63 kristaps 784: return(1);
785: }
1.1 kristaps 786:
1.130 kristaps 787: sv = i;
788:
1.160 kristaps 789: /*
1.162 schwarze 790: * Copy the first word into a nil-terminated buffer.
1.165 schwarze 791: * Stop copying when a tab, space, or eoln is encountered.
1.160 kristaps 792: */
1.1 kristaps 793:
1.162 schwarze 794: j = 0;
1.165 schwarze 795: while (j < 4 && '\0' != buf[i] && ' ' != buf[i] && '\t' != buf[i])
1.162 schwarze 796: mac[j++] = buf[i++];
1.135 kristaps 797: mac[j] = '\0';
1.1 kristaps 798:
1.163 schwarze 799: tok = (j > 1 || j < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
800: if (MDOC_MAX == tok) {
1.168 kristaps 801: mdoc_vmsg(m, MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1);
1.58 kristaps 802: return(1);
1.53 kristaps 803: }
1.1 kristaps 804:
1.160 kristaps 805: /* Disregard the first trailing tab, if applicable. */
806:
807: if ('\t' == buf[i])
808: i++;
809:
810: /* Jump to the next non-whitespace word. */
1.1 kristaps 811:
1.65 kristaps 812: while (buf[i] && ' ' == buf[i])
1.53 kristaps 813: i++;
1.1 kristaps 814:
1.125 kristaps 815: /*
816: * Trailing whitespace. Note that tabs are allowed to be passed
817: * into the parser as "text", so we only warn about spaces here.
818: */
1.115 kristaps 819:
820: if ('\0' == buf[i] && ' ' == buf[i - 1])
1.174 ! kristaps 821: mdoc_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE);
1.115 kristaps 822:
1.144 kristaps 823: /*
824: * If an initial macro or a list invocation, divert directly
825: * into macro processing.
826: */
827:
828: if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) {
1.149 kristaps 829: if ( ! mdoc_macro(m, tok, ln, sv, &i, buf))
1.144 kristaps 830: goto err;
831: return(1);
832: }
833:
834: n = m->last;
835: assert(m->last);
836:
837: /*
838: * If the first macro of a `Bl -column', open an `It' block
839: * context around the parsed macro.
840: */
841:
842: if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
1.172 kristaps 843: LIST_column == n->norm->Bl.type) {
1.144 kristaps 844: m->flags |= MDOC_FREECOL;
1.149 kristaps 845: if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
1.144 kristaps 846: goto err;
847: return(1);
848: }
849:
850: /*
851: * If we're following a block-level `It' within a `Bl -column'
852: * context (perhaps opened in the above block or in ptext()),
853: * then open an `It' block context around the parsed macro.
1.98 kristaps 854: */
1.144 kristaps 855:
856: if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
857: NULL != n->parent &&
858: MDOC_Bl == n->parent->tok &&
1.172 kristaps 859: LIST_column == n->parent->norm->Bl.type) {
1.144 kristaps 860: m->flags |= MDOC_FREECOL;
1.149 kristaps 861: if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
1.144 kristaps 862: goto err;
863: return(1);
864: }
865:
866: /* Normal processing of a macro. */
867:
1.149 kristaps 868: if ( ! mdoc_macro(m, tok, ln, sv, &i, buf))
1.53 kristaps 869: goto err;
1.1 kristaps 870:
1.53 kristaps 871: return(1);
1.1 kristaps 872:
1.53 kristaps 873: err: /* Error out. */
1.1 kristaps 874:
1.53 kristaps 875: m->flags |= MDOC_HALT;
876: return(0);
1.1 kristaps 877: }
1.100 kristaps 878:
879:
CVSweb