Annotation of src/usr.bin/mandoc/man.c, Revision 1.98
1.98 ! schwarze 1: /* $OpenBSD: man.c,v 1.97 2015/01/30 21:28:21 schwarze Exp $ */
1.1 kristaps 2: /*
1.52 schwarze 3: * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.97 schwarze 4: * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
1.74 schwarze 5: * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
1.1 kristaps 6: *
7: * Permission to use, copy, modify, and distribute this software for any
1.2 schwarze 8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 10: *
1.98 ! schwarze 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1.2 schwarze 12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1.98 ! schwarze 13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1.2 schwarze 14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 18: */
1.14 schwarze 19: #include <sys/types.h>
20:
1.1 kristaps 21: #include <assert.h>
1.76 schwarze 22: #include <ctype.h>
1.1 kristaps 23: #include <stdarg.h>
24: #include <stdlib.h>
25: #include <stdio.h>
26: #include <string.h>
27:
1.98 ! schwarze 28: #include "mandoc_aux.h"
! 29: #include "mandoc.h"
! 30: #include "roff.h"
1.59 schwarze 31: #include "man.h"
1.98 ! schwarze 32: #include "libmandoc.h"
1.1 kristaps 33: #include "libman.h"
34:
1.79 schwarze 35: const char *const __man_macronames[MAN_MAX] = {
1.3 schwarze 36: "br", "TH", "SH", "SS",
1.79 schwarze 37: "TP", "LP", "PP", "P",
1.1 kristaps 38: "IP", "HP", "SM", "SB",
39: "BI", "IB", "BR", "RB",
40: "R", "B", "I", "IR",
1.96 schwarze 41: "RI", "sp", "nf",
1.50 schwarze 42: "fi", "RE", "RS", "DT",
43: "UC", "PD", "AT", "in",
1.70 schwarze 44: "ft", "OP", "EX", "EE",
1.78 schwarze 45: "UR", "UE", "ll"
1.1 kristaps 46: };
47:
48: const char * const *man_macronames = __man_macronames;
49:
1.97 schwarze 50: static void man_alloc1(struct man *);
51: static void man_breakscope(struct man *, enum mant);
52: static void man_descope(struct man *, int, int);
53: static void man_free1(struct man *);
1.79 schwarze 54: static struct man_node *man_node_alloc(struct man *, int, int,
1.98 ! schwarze 55: enum roff_type, enum mant);
1.92 schwarze 56: static void man_node_append(struct man *, struct man_node *);
1.22 schwarze 57: static void man_node_free(struct man_node *);
1.79 schwarze 58: static void man_node_unlink(struct man *,
1.22 schwarze 59: struct man_node *);
1.31 schwarze 60: static int man_ptext(struct man *, int, char *, int);
61: static int man_pmacro(struct man *, int, char *, int);
1.1 kristaps 62:
63:
64: const struct man_node *
1.69 schwarze 65: man_node(const struct man *man)
1.1 kristaps 66: {
67:
1.69 schwarze 68: return(man->first);
1.1 kristaps 69: }
70:
71: const struct man_meta *
1.69 schwarze 72: man_meta(const struct man *man)
1.1 kristaps 73: {
74:
1.69 schwarze 75: return(&man->meta);
1.1 kristaps 76: }
77:
1.16 schwarze 78: void
1.1 kristaps 79: man_reset(struct man *man)
80: {
81:
82: man_free1(man);
1.16 schwarze 83: man_alloc1(man);
1.1 kristaps 84: }
85:
86: void
87: man_free(struct man *man)
88: {
89:
90: man_free1(man);
91: free(man);
92: }
93:
94: struct man *
1.94 schwarze 95: man_alloc(struct roff *roff, struct mparse *parse,
96: const char *defos, int quick)
1.1 kristaps 97: {
98: struct man *p;
99:
1.16 schwarze 100: p = mandoc_calloc(1, sizeof(struct man));
1.1 kristaps 101:
1.13 schwarze 102: man_hash_init();
1.59 schwarze 103: p->parse = parse;
1.94 schwarze 104: p->defos = defos;
1.73 schwarze 105: p->quick = quick;
1.60 schwarze 106: p->roff = roff;
1.16 schwarze 107:
108: man_alloc1(p);
1.1 kristaps 109: return(p);
110: }
111:
1.95 schwarze 112: void
1.69 schwarze 113: man_endparse(struct man *man)
1.1 kristaps 114: {
115:
1.92 schwarze 116: man_macroend(man);
1.1 kristaps 117: }
118:
119: int
1.69 schwarze 120: man_parseln(struct man *man, int ln, char *buf, int offs)
1.1 kristaps 121: {
1.25 schwarze 122:
1.98 ! schwarze 123: if (man->last->type != ROFFT_EQN || ln > man->last->line)
1.89 schwarze 124: man->flags |= MAN_NEWLINE;
1.54 schwarze 125:
1.69 schwarze 126: return (roff_getcontrol(man->roff, buf, &offs) ?
1.79 schwarze 127: man_pmacro(man, ln, buf, offs) :
128: man_ptext(man, ln, buf, offs));
1.1 kristaps 129: }
130:
131: static void
132: man_free1(struct man *man)
133: {
134:
135: if (man->first)
1.22 schwarze 136: man_node_delete(man, man->first);
1.92 schwarze 137: free(man->meta.title);
138: free(man->meta.source);
139: free(man->meta.date);
140: free(man->meta.vol);
141: free(man->meta.msec);
1.1 kristaps 142: }
143:
1.16 schwarze 144: static void
1.69 schwarze 145: man_alloc1(struct man *man)
1.1 kristaps 146: {
147:
1.69 schwarze 148: memset(&man->meta, 0, sizeof(struct man_meta));
149: man->flags = 0;
150: man->last = mandoc_calloc(1, sizeof(struct man_node));
151: man->first = man->last;
1.98 ! schwarze 152: man->last->type = ROFFT_ROOT;
1.69 schwarze 153: man->last->tok = MAN_MAX;
154: man->next = MAN_NEXT_CHILD;
1.1 kristaps 155: }
156:
157:
1.92 schwarze 158: static void
1.1 kristaps 159: man_node_append(struct man *man, struct man_node *p)
160: {
161:
162: assert(man->last);
163: assert(man->first);
1.98 ! schwarze 164: assert(p->type != ROFFT_ROOT);
1.1 kristaps 165:
166: switch (man->next) {
1.79 schwarze 167: case MAN_NEXT_SIBLING:
1.1 kristaps 168: man->last->next = p;
169: p->prev = man->last;
170: p->parent = man->last->parent;
171: break;
1.79 schwarze 172: case MAN_NEXT_CHILD:
1.1 kristaps 173: man->last->child = p;
174: p->parent = man->last;
175: break;
176: default:
177: abort();
178: /* NOTREACHED */
179: }
1.79 schwarze 180:
1.22 schwarze 181: assert(p->parent);
1.5 schwarze 182: p->parent->nchild++;
1.1 kristaps 183:
1.9 schwarze 184: switch (p->type) {
1.98 ! schwarze 185: case ROFFT_BLOCK:
1.86 schwarze 186: if (p->tok == MAN_SH || p->tok == MAN_SS)
187: man->flags &= ~MAN_LITERAL;
188: break;
1.98 ! schwarze 189: case ROFFT_HEAD:
! 190: assert(p->parent->type == ROFFT_BLOCK);
1.9 schwarze 191: p->parent->head = p;
192: break;
1.98 ! schwarze 193: case ROFFT_BODY:
! 194: assert(p->parent->type == ROFFT_BLOCK);
1.9 schwarze 195: p->parent->body = p;
196: break;
197: default:
198: break;
199: }
200:
1.1 kristaps 201: man->last = p;
202:
203: switch (p->type) {
1.98 ! schwarze 204: case ROFFT_TBL:
1.52 schwarze 205: /* FALLTHROUGH */
1.98 ! schwarze 206: case ROFFT_TEXT:
1.92 schwarze 207: man_valid_post(man);
1.1 kristaps 208: break;
209: default:
210: break;
211: }
212: }
213:
214: static struct man_node *
1.79 schwarze 215: man_node_alloc(struct man *man, int line, int pos,
1.98 ! schwarze 216: enum roff_type type, enum mant tok)
1.1 kristaps 217: {
218: struct man_node *p;
219:
1.16 schwarze 220: p = mandoc_calloc(1, sizeof(struct man_node));
1.1 kristaps 221: p->line = line;
222: p->pos = pos;
223: p->type = type;
224: p->tok = tok;
1.54 schwarze 225:
1.92 schwarze 226: if (man->flags & MAN_NEWLINE)
1.54 schwarze 227: p->flags |= MAN_LINE;
1.69 schwarze 228: man->flags &= ~MAN_NEWLINE;
1.1 kristaps 229: return(p);
230: }
231:
1.92 schwarze 232: void
1.69 schwarze 233: man_elem_alloc(struct man *man, int line, int pos, enum mant tok)
1.1 kristaps 234: {
235: struct man_node *p;
236:
1.98 ! schwarze 237: p = man_node_alloc(man, line, pos, ROFFT_ELEM, tok);
1.92 schwarze 238: man_node_append(man, p);
1.69 schwarze 239: man->next = MAN_NEXT_CHILD;
1.1 kristaps 240: }
241:
1.92 schwarze 242: void
1.69 schwarze 243: man_head_alloc(struct man *man, int line, int pos, enum mant tok)
1.9 schwarze 244: {
245: struct man_node *p;
246:
1.98 ! schwarze 247: p = man_node_alloc(man, line, pos, ROFFT_HEAD, tok);
1.92 schwarze 248: man_node_append(man, p);
1.69 schwarze 249: man->next = MAN_NEXT_CHILD;
1.9 schwarze 250: }
251:
1.92 schwarze 252: void
1.69 schwarze 253: man_body_alloc(struct man *man, int line, int pos, enum mant tok)
1.9 schwarze 254: {
255: struct man_node *p;
256:
1.98 ! schwarze 257: p = man_node_alloc(man, line, pos, ROFFT_BODY, tok);
1.92 schwarze 258: man_node_append(man, p);
1.69 schwarze 259: man->next = MAN_NEXT_CHILD;
1.9 schwarze 260: }
261:
1.92 schwarze 262: void
1.69 schwarze 263: man_block_alloc(struct man *man, int line, int pos, enum mant tok)
1.9 schwarze 264: {
265: struct man_node *p;
266:
1.98 ! schwarze 267: p = man_node_alloc(man, line, pos, ROFFT_BLOCK, tok);
1.92 schwarze 268: man_node_append(man, p);
1.69 schwarze 269: man->next = MAN_NEXT_CHILD;
1.9 schwarze 270: }
271:
1.92 schwarze 272: void
1.69 schwarze 273: man_word_alloc(struct man *man, int line, int pos, const char *word)
1.1 kristaps 274: {
1.10 schwarze 275: struct man_node *n;
1.1 kristaps 276:
1.98 ! schwarze 277: n = man_node_alloc(man, line, pos, ROFFT_TEXT, MAN_MAX);
1.69 schwarze 278: n->string = roff_strdup(man->roff, word);
1.92 schwarze 279: man_node_append(man, n);
1.69 schwarze 280: man->next = MAN_NEXT_SIBLING;
1.90 schwarze 281: }
282:
283: void
284: man_word_append(struct man *man, const char *word)
285: {
286: struct man_node *n;
287: char *addstr, *newstr;
288:
289: n = man->last;
290: addstr = roff_strdup(man->roff, word);
291: mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
292: free(addstr);
293: free(n->string);
294: n->string = newstr;
295: man->next = MAN_NEXT_SIBLING;
1.10 schwarze 296: }
297:
1.22 schwarze 298: /*
299: * Free all of the resources held by a node. This does NOT unlink a
300: * node from its context; for that, see man_node_unlink().
301: */
302: static void
1.1 kristaps 303: man_node_free(struct man_node *p)
304: {
305:
1.92 schwarze 306: free(p->string);
1.1 kristaps 307: free(p);
308: }
309:
310: void
1.69 schwarze 311: man_node_delete(struct man *man, struct man_node *p)
1.1 kristaps 312: {
313:
1.22 schwarze 314: while (p->child)
1.69 schwarze 315: man_node_delete(man, p->child);
1.22 schwarze 316:
1.69 schwarze 317: man_node_unlink(man, p);
1.1 kristaps 318: man_node_free(p);
319: }
320:
1.93 schwarze 321: void
1.69 schwarze 322: man_addeqn(struct man *man, const struct eqn *ep)
1.57 schwarze 323: {
324: struct man_node *n;
325:
1.98 ! schwarze 326: n = man_node_alloc(man, ep->ln, ep->pos, ROFFT_EQN, MAN_MAX);
1.57 schwarze 327: n->eqn = ep;
1.88 schwarze 328: if (ep->ln > man->last->line)
329: n->flags |= MAN_LINE;
1.92 schwarze 330: man_node_append(man, n);
1.69 schwarze 331: man->next = MAN_NEXT_SIBLING;
1.92 schwarze 332: man_descope(man, ep->ln, ep->pos);
1.57 schwarze 333: }
1.1 kristaps 334:
1.93 schwarze 335: void
1.69 schwarze 336: man_addspan(struct man *man, const struct tbl_span *sp)
1.52 schwarze 337: {
1.55 schwarze 338: struct man_node *n;
1.52 schwarze 339:
1.97 schwarze 340: man_breakscope(man, MAN_MAX);
1.98 ! schwarze 341: n = man_node_alloc(man, sp->line, 0, ROFFT_TBL, MAN_MAX);
1.55 schwarze 342: n->span = sp;
1.92 schwarze 343: man_node_append(man, n);
1.69 schwarze 344: man->next = MAN_NEXT_SIBLING;
1.92 schwarze 345: man_descope(man, sp->line, 0);
1.52 schwarze 346: }
347:
1.92 schwarze 348: static void
1.69 schwarze 349: man_descope(struct man *man, int line, int offs)
1.52 schwarze 350: {
351: /*
352: * Co-ordinate what happens with having a next-line scope open:
353: * first close out the element scope (if applicable), then close
354: * out the block scope (also if applicable).
355: */
356:
1.92 schwarze 357: if (man->flags & MAN_ELINE) {
1.69 schwarze 358: man->flags &= ~MAN_ELINE;
1.92 schwarze 359: man_unscope(man, man->last->parent);
1.52 schwarze 360: }
1.92 schwarze 361: if ( ! (man->flags & MAN_BLINE))
362: return;
1.69 schwarze 363: man->flags &= ~MAN_BLINE;
1.92 schwarze 364: man_unscope(man, man->last->parent);
365: man_body_alloc(man, line, offs, man->last->tok);
1.52 schwarze 366: }
367:
1.1 kristaps 368: static int
1.69 schwarze 369: man_ptext(struct man *man, int line, char *buf, int offs)
1.1 kristaps 370: {
1.27 schwarze 371: int i;
1.26 schwarze 372:
1.10 schwarze 373: /* Literal free-form text whitespace is preserved. */
374:
1.92 schwarze 375: if (man->flags & MAN_LITERAL) {
376: man_word_alloc(man, line, offs, buf + offs);
377: man_descope(man, line, offs);
378: return(1);
1.10 schwarze 379: }
380:
1.92 schwarze 381: for (i = offs; buf[i] == ' '; i++)
1.10 schwarze 382: /* Skip leading whitespace. */ ;
1.18 schwarze 383:
1.71 schwarze 384: /*
385: * Blank lines are ignored right after headings
386: * but add a single vertical space elsewhere.
387: */
388:
1.92 schwarze 389: if (buf[i] == '\0') {
1.27 schwarze 390: /* Allocate a blank entry. */
1.92 schwarze 391: if (man->last->tok != MAN_SH &&
392: man->last->tok != MAN_SS) {
393: man_elem_alloc(man, line, offs, MAN_sp);
1.71 schwarze 394: man->next = MAN_NEXT_SIBLING;
395: }
1.68 schwarze 396: return(1);
1.10 schwarze 397: }
1.1 kristaps 398:
1.79 schwarze 399: /*
1.27 schwarze 400: * Warn if the last un-escaped character is whitespace. Then
1.79 schwarze 401: * strip away the remaining spaces (tabs stay!).
1.27 schwarze 402: */
1.18 schwarze 403:
1.27 schwarze 404: i = (int)strlen(buf);
405: assert(i);
1.18 schwarze 406:
1.27 schwarze 407: if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
408: if (i > 1 && '\\' != buf[i - 2])
1.81 schwarze 409: mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
410: line, i - 1, NULL);
1.18 schwarze 411:
1.27 schwarze 412: for (--i; i && ' ' == buf[i]; i--)
413: /* Spin back to non-space. */ ;
1.10 schwarze 414:
1.27 schwarze 415: /* Jump ahead of escaped whitespace. */
416: i += '\\' == buf[i] ? 2 : 1;
1.18 schwarze 417:
1.27 schwarze 418: buf[i] = '\0';
1.10 schwarze 419: }
1.92 schwarze 420: man_word_alloc(man, line, offs, buf + offs);
1.28 schwarze 421:
422: /*
423: * End-of-sentence check. If the last character is an unescaped
424: * EOS character, then flag the node as being the end of a
425: * sentence. The front-end will know how to interpret this.
426: */
427:
428: assert(i);
1.72 schwarze 429: if (mandoc_eos(buf, (size_t)i))
1.69 schwarze 430: man->last->flags |= MAN_EOS;
1.10 schwarze 431:
1.92 schwarze 432: man_descope(man, line, offs);
433: return(1);
1.1 kristaps 434: }
435:
1.53 schwarze 436: static int
1.69 schwarze 437: man_pmacro(struct man *man, int ln, char *buf, int offs)
1.1 kristaps 438: {
1.10 schwarze 439: struct man_node *n;
1.91 schwarze 440: const char *cp;
1.84 schwarze 441: enum mant tok;
442: int i, ppos;
443: int bline;
1.91 schwarze 444: char mac[5];
1.1 kristaps 445:
1.59 schwarze 446: ppos = offs;
1.1 kristaps 447:
1.23 schwarze 448: /*
1.59 schwarze 449: * Copy the first word into a nil-terminated buffer.
1.91 schwarze 450: * Stop when a space, tab, escape, or eoln is encountered.
1.23 schwarze 451: */
1.27 schwarze 452:
1.59 schwarze 453: i = 0;
1.91 schwarze 454: while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
1.59 schwarze 455: mac[i++] = buf[offs++];
1.1 kristaps 456:
1.59 schwarze 457: mac[i] = '\0';
1.1 kristaps 458:
1.59 schwarze 459: tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
1.1 kristaps 460:
1.91 schwarze 461: if (tok == MAN_MAX) {
1.85 schwarze 462: mandoc_msg(MANDOCERR_MACRO, man->parse,
463: ln, ppos, buf + ppos - 1);
1.1 kristaps 464: return(1);
465: }
466:
1.91 schwarze 467: /* Skip a leading escape sequence or tab. */
468:
469: switch (buf[offs]) {
470: case '\\':
471: cp = buf + offs + 1;
472: mandoc_escape(&cp, NULL, NULL);
473: offs = cp - buf;
474: break;
475: case '\t':
476: offs++;
477: break;
478: default:
479: break;
480: }
481:
482: /* Jump to the next non-whitespace word. */
1.1 kristaps 483:
1.92 schwarze 484: while (buf[offs] && buf[offs] == ' ')
1.59 schwarze 485: offs++;
1.18 schwarze 486:
1.79 schwarze 487: /*
1.27 schwarze 488: * Trailing whitespace. Note that tabs are allowed to be passed
489: * into the parser as "text", so we only warn about spaces here.
490: */
1.18 schwarze 491:
1.92 schwarze 492: if (buf[offs] == '\0' && buf[offs - 1] == ' ')
1.81 schwarze 493: mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
494: ln, offs - 1, NULL);
1.1 kristaps 495:
1.79 schwarze 496: /*
1.97 schwarze 497: * Some macros break next-line scopes; otherwise, remember
498: * whether we are in next-line scope for a block head.
1.21 schwarze 499: */
500:
1.97 schwarze 501: man_breakscope(man, tok);
1.84 schwarze 502: bline = man->flags & MAN_BLINE;
1.24 schwarze 503:
504: /* Call to handler... */
1.1 kristaps 505:
1.22 schwarze 506: assert(man_macros[tok].fp);
1.92 schwarze 507: (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
1.73 schwarze 508:
509: /* In quick mode (for mandocdb), abort after the NAME section. */
510:
1.92 schwarze 511: if (man->quick && tok == MAN_SH) {
1.80 schwarze 512: n = man->last;
1.98 ! schwarze 513: if (n->type == ROFFT_BODY &&
1.80 schwarze 514: strcmp(n->prev->child->string, "NAME"))
515: return(2);
516: }
1.1 kristaps 517:
1.79 schwarze 518: /*
1.84 schwarze 519: * If we are in a next-line scope for a block head,
520: * close it out now and switch to the body,
521: * unless the next-line scope is allowed to continue.
1.21 schwarze 522: */
523:
1.84 schwarze 524: if ( ! bline || man->flags & MAN_ELINE ||
525: man_macros[tok].flags & MAN_NSCOPED)
1.21 schwarze 526: return(1);
1.1 kristaps 527:
1.92 schwarze 528: assert(man->flags & MAN_BLINE);
1.69 schwarze 529: man->flags &= ~MAN_BLINE;
1.1 kristaps 530:
1.92 schwarze 531: man_unscope(man, man->last->parent);
532: man_body_alloc(man, ln, ppos, man->last->tok);
533: return(1);
1.97 schwarze 534: }
535:
536: void
537: man_breakscope(struct man *man, enum mant tok)
538: {
539: struct man_node *n;
540:
541: /*
542: * An element next line scope is open,
543: * and the new macro is not allowed inside elements.
544: * Delete the element that is being broken.
545: */
546:
547: if (man->flags & MAN_ELINE && (tok == MAN_MAX ||
548: ! (man_macros[tok].flags & MAN_NSCOPED))) {
549: n = man->last;
1.98 ! schwarze 550: assert(n->type != ROFFT_TEXT);
1.97 schwarze 551: if (man_macros[n->tok].flags & MAN_NSCOPED)
552: n = n->parent;
553:
554: mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
555: n->line, n->pos, "%s breaks %s",
556: tok == MAN_MAX ? "TS" : man_macronames[tok],
557: man_macronames[n->tok]);
558:
559: man_node_delete(man, n);
560: man->flags &= ~MAN_ELINE;
561: }
562:
563: /*
564: * A block header next line scope is open,
565: * and the new macro is not allowed inside block headers.
566: * Delete the block that is being broken.
567: */
568:
569: if (man->flags & MAN_BLINE && (tok == MAN_MAX ||
570: man_macros[tok].flags & MAN_BSCOPE)) {
571: n = man->last;
1.98 ! schwarze 572: if (n->type == ROFFT_TEXT)
1.97 schwarze 573: n = n->parent;
574: if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
575: n = n->parent;
576:
1.98 ! schwarze 577: assert(n->type == ROFFT_HEAD);
1.97 schwarze 578: n = n->parent;
1.98 ! schwarze 579: assert(n->type == ROFFT_BLOCK);
1.97 schwarze 580: assert(man_macros[n->tok].flags & MAN_SCOPED);
581:
582: mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
583: n->line, n->pos, "%s breaks %s",
584: tok == MAN_MAX ? "TS" : man_macronames[tok],
585: man_macronames[n->tok]);
586:
587: man_node_delete(man, n);
588: man->flags &= ~MAN_BLINE;
589: }
1.1 kristaps 590: }
1.21 schwarze 591:
1.22 schwarze 592: /*
1.69 schwarze 593: * Unlink a node from its context. If "man" is provided, the last parse
1.22 schwarze 594: * point will also be adjusted accordingly.
595: */
596: static void
1.69 schwarze 597: man_node_unlink(struct man *man, struct man_node *n)
1.21 schwarze 598: {
599:
1.22 schwarze 600: /* Adjust siblings. */
601:
602: if (n->prev)
1.21 schwarze 603: n->prev->next = n->next;
1.22 schwarze 604: if (n->next)
605: n->next->prev = n->prev;
606:
607: /* Adjust parent. */
608:
609: if (n->parent) {
610: n->parent->nchild--;
611: if (n->parent->child == n)
612: n->parent->child = n->prev ? n->prev : n->next;
613: }
614:
615: /* Adjust parse point, if applicable. */
616:
1.69 schwarze 617: if (man && man->last == n) {
1.22 schwarze 618: /*XXX: this can occur when bailing from validation. */
619: /*assert(NULL == n->next);*/
620: if (n->prev) {
1.69 schwarze 621: man->last = n->prev;
622: man->next = MAN_NEXT_SIBLING;
1.22 schwarze 623: } else {
1.69 schwarze 624: man->last = n->parent;
625: man->next = MAN_NEXT_CHILD;
1.21 schwarze 626: }
627: }
628:
1.69 schwarze 629: if (man && man->first == n)
630: man->first = NULL;
1.62 schwarze 631: }
632:
633: const struct mparse *
1.69 schwarze 634: man_mparse(const struct man *man)
1.62 schwarze 635: {
636:
1.69 schwarze 637: assert(man && man->parse);
638: return(man->parse);
1.76 schwarze 639: }
640:
641: void
642: man_deroff(char **dest, const struct man_node *n)
643: {
644: char *cp;
645: size_t sz;
646:
1.98 ! schwarze 647: if (n->type != ROFFT_TEXT) {
1.76 schwarze 648: for (n = n->child; n; n = n->next)
649: man_deroff(dest, n);
650: return;
651: }
652:
1.77 schwarze 653: /* Skip leading whitespace and escape sequences. */
1.76 schwarze 654:
1.77 schwarze 655: cp = n->string;
656: while ('\0' != *cp) {
657: if ('\\' == *cp) {
658: cp++;
659: mandoc_escape((const char **)&cp, NULL, NULL);
660: } else if (isspace((unsigned char)*cp))
661: cp++;
662: else
1.76 schwarze 663: break;
1.77 schwarze 664: }
1.76 schwarze 665:
666: /* Skip trailing whitespace. */
667:
668: for (sz = strlen(cp); sz; sz--)
669: if (0 == isspace((unsigned char)cp[sz-1]))
670: break;
671:
672: /* Skip empty strings. */
673:
674: if (0 == sz)
675: return;
676:
677: if (NULL == *dest) {
678: *dest = mandoc_strndup(cp, sz);
679: return;
680: }
681:
682: mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
683: free(*dest);
684: *dest = cp;
1.4 schwarze 685: }