Annotation of mandoc/mdoc.c, Revision 1.222
1.222 ! schwarze 1: /* $Id: mdoc.c,v 1.221 2014/07/30 21:18:24 schwarze Exp $ */
1.1 kristaps 2: /*
1.182 schwarze 3: * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.208 schwarze 4: * Copyright (c) 2010, 2012, 2013, 2014 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>
1.211 schwarze 25: #include <ctype.h>
1.1 kristaps 26: #include <stdarg.h>
1.73 kristaps 27: #include <stdio.h>
1.1 kristaps 28: #include <stdlib.h>
29: #include <string.h>
1.120 kristaps 30: #include <time.h>
1.1 kristaps 31:
1.187 kristaps 32: #include "mdoc.h"
1.136 kristaps 33: #include "mandoc.h"
1.209 schwarze 34: #include "mandoc_aux.h"
1.70 kristaps 35: #include "libmdoc.h"
1.113 kristaps 36: #include "libmandoc.h"
1.1 kristaps 37:
1.216 schwarze 38: const char *const __mdoc_macronames[MDOC_MAX + 1] = {
1.82 kristaps 39: "Ap", "Dd", "Dt", "Os",
1.1 kristaps 40: "Sh", "Ss", "Pp", "D1",
41: "Dl", "Bd", "Ed", "Bl",
42: "El", "It", "Ad", "An",
43: "Ar", "Cd", "Cm", "Dv",
44: "Er", "Ev", "Ex", "Fa",
45: "Fd", "Fl", "Fn", "Ft",
46: "Ic", "In", "Li", "Nd",
47: "Nm", "Op", "Ot", "Pa",
48: "Rv", "St", "Va", "Vt",
1.114 kristaps 49: "Xr", "%A", "%B", "%D",
50: "%I", "%J", "%N", "%O",
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.114 kristaps 67: "Brc", "%C", "Es", "En",
68: "Dx", "%Q", "br", "sp",
1.216 schwarze 69: "%U", "Ta", "ll", "text",
1.1 kristaps 70: };
71:
1.213 schwarze 72: const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
1.1 kristaps 73: "split", "nosplit", "ragged",
1.213 schwarze 74: "unfilled", "literal", "file",
75: "offset", "bullet", "dash",
76: "hyphen", "item", "enum",
77: "tag", "diag", "hang",
78: "ohang", "inset", "column",
79: "width", "compact", "std",
1.52 kristaps 80: "filled", "words", "emphasis",
1.108 kristaps 81: "symbolic", "nested", "centered"
1.1 kristaps 82: };
83:
84: const char * const *mdoc_macronames = __mdoc_macronames;
85: const char * const *mdoc_argnames = __mdoc_argnames;
86:
1.121 kristaps 87: static void mdoc_node_free(struct mdoc_node *);
1.213 schwarze 88: static void mdoc_node_unlink(struct mdoc *,
1.121 kristaps 89: struct mdoc_node *);
1.73 kristaps 90: static void mdoc_free1(struct mdoc *);
1.113 kristaps 91: static void mdoc_alloc1(struct mdoc *);
1.213 schwarze 92: static struct mdoc_node *node_alloc(struct mdoc *, int, int,
1.117 kristaps 93: enum mdoct, enum mdoc_type);
1.213 schwarze 94: static int node_append(struct mdoc *,
1.71 kristaps 95: struct mdoc_node *);
1.193 kristaps 96: #if 0
1.191 kristaps 97: static int mdoc_preptext(struct mdoc *, int, char *, int);
1.193 kristaps 98: #endif
1.149 kristaps 99: static int mdoc_ptext(struct mdoc *, int, char *, int);
100: static int mdoc_pmacro(struct mdoc *, int, char *, int);
1.88 kristaps 101:
1.213 schwarze 102:
1.1 kristaps 103: const struct mdoc_node *
1.203 schwarze 104: mdoc_node(const struct mdoc *mdoc)
1.1 kristaps 105: {
106:
1.203 schwarze 107: return(mdoc->first);
1.1 kristaps 108: }
109:
1.37 kristaps 110: const struct mdoc_meta *
1.203 schwarze 111: mdoc_meta(const struct mdoc *mdoc)
1.37 kristaps 112: {
113:
1.203 schwarze 114: return(&mdoc->meta);
1.37 kristaps 115: }
116:
1.85 kristaps 117: /*
118: * Frees volatile resources (parse tree, meta-data, fields).
119: */
1.73 kristaps 120: static void
121: mdoc_free1(struct mdoc *mdoc)
1.67 kristaps 122: {
123:
124: if (mdoc->first)
1.121 kristaps 125: mdoc_node_delete(mdoc, mdoc->first);
1.67 kristaps 126: if (mdoc->meta.title)
127: free(mdoc->meta.title);
128: if (mdoc->meta.os)
129: free(mdoc->meta.os);
130: if (mdoc->meta.name)
131: free(mdoc->meta.name);
132: if (mdoc->meta.arch)
133: free(mdoc->meta.arch);
134: if (mdoc->meta.vol)
135: free(mdoc->meta.vol);
1.133 kristaps 136: if (mdoc->meta.msec)
137: free(mdoc->meta.msec);
1.183 kristaps 138: if (mdoc->meta.date)
139: free(mdoc->meta.date);
1.73 kristaps 140: }
141:
1.85 kristaps 142: /*
143: * Allocate all volatile resources (parse tree, meta-data, fields).
144: */
1.113 kristaps 145: static void
1.73 kristaps 146: mdoc_alloc1(struct mdoc *mdoc)
147: {
1.67 kristaps 148:
1.112 kristaps 149: memset(&mdoc->meta, 0, sizeof(struct mdoc_meta));
1.67 kristaps 150: mdoc->flags = 0;
1.85 kristaps 151: mdoc->lastnamed = mdoc->lastsec = SEC_NONE;
1.113 kristaps 152: mdoc->last = mandoc_calloc(1, sizeof(struct mdoc_node));
1.70 kristaps 153: mdoc->first = mdoc->last;
1.67 kristaps 154: mdoc->last->type = MDOC_ROOT;
1.196 schwarze 155: mdoc->last->tok = MDOC_MAX;
1.67 kristaps 156: mdoc->next = MDOC_NEXT_CHILD;
1.73 kristaps 157: }
158:
159: /*
1.85 kristaps 160: * Free up volatile resources (see mdoc_free1()) then re-initialises the
161: * data with mdoc_alloc1(). After invocation, parse data has been reset
162: * and the parser is ready for re-invocation on a new tree; however,
163: * cross-parse non-volatile data is kept intact.
1.73 kristaps 164: */
1.113 kristaps 165: void
1.73 kristaps 166: mdoc_reset(struct mdoc *mdoc)
167: {
168:
169: mdoc_free1(mdoc);
1.113 kristaps 170: mdoc_alloc1(mdoc);
1.67 kristaps 171: }
172:
1.68 kristaps 173: /*
1.85 kristaps 174: * Completely free up all volatile and non-volatile parse resources.
175: * After invocation, the pointer is no longer usable.
1.68 kristaps 176: */
1.67 kristaps 177: void
1.38 kristaps 178: mdoc_free(struct mdoc *mdoc)
1.34 kristaps 179: {
180:
1.73 kristaps 181: mdoc_free1(mdoc);
1.1 kristaps 182: free(mdoc);
183: }
184:
1.85 kristaps 185: /*
1.213 schwarze 186: * Allocate volatile and non-volatile parse resources.
1.85 kristaps 187: */
1.1 kristaps 188: struct mdoc *
1.208 schwarze 189: mdoc_alloc(struct roff *roff, struct mparse *parse,
1.220 schwarze 190: const char *defos, int quick)
1.1 kristaps 191: {
192: struct mdoc *p;
193:
1.113 kristaps 194: p = mandoc_calloc(1, sizeof(struct mdoc));
195:
1.185 kristaps 196: p->parse = parse;
1.197 schwarze 197: p->defos = defos;
1.208 schwarze 198: p->quick = quick;
1.189 kristaps 199: p->roff = roff;
1.73 kristaps 200:
1.113 kristaps 201: mdoc_hash_init();
202: mdoc_alloc1(p);
203: return(p);
1.1 kristaps 204: }
205:
206: int
1.203 schwarze 207: mdoc_endparse(struct mdoc *mdoc)
1.20 kristaps 208: {
209:
1.221 schwarze 210: return(mdoc_macroend(mdoc));
1.181 kristaps 211: }
212:
213: int
1.203 schwarze 214: mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep)
1.181 kristaps 215: {
216: struct mdoc_node *n;
217:
1.203 schwarze 218: n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN);
1.181 kristaps 219: n->eqn = ep;
220:
1.203 schwarze 221: if ( ! node_append(mdoc, n))
1.181 kristaps 222: return(0);
223:
1.203 schwarze 224: mdoc->next = MDOC_NEXT_SIBLING;
1.181 kristaps 225: return(1);
1.20 kristaps 226: }
227:
1.175 kristaps 228: int
1.203 schwarze 229: mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp)
1.175 kristaps 230: {
1.180 kristaps 231: struct mdoc_node *n;
1.175 kristaps 232:
1.203 schwarze 233: n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL);
1.180 kristaps 234: n->span = sp;
235:
1.203 schwarze 236: if ( ! node_append(mdoc, n))
1.180 kristaps 237: return(0);
238:
1.203 schwarze 239: mdoc->next = MDOC_NEXT_SIBLING;
1.180 kristaps 240: return(1);
1.175 kristaps 241: }
242:
1.50 kristaps 243: /*
1.53 kristaps 244: * Main parse routine. Parses a single line -- really just hands off to
1.123 kristaps 245: * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
1.50 kristaps 246: */
1.20 kristaps 247: int
1.203 schwarze 248: mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
1.1 kristaps 249: {
250:
1.203 schwarze 251: mdoc->flags |= MDOC_NEWLINE;
1.153 schwarze 252:
253: /*
254: * Let the roff nS register switch SYNOPSIS mode early,
255: * such that the parser knows at all times
256: * whether this mode is on or off.
257: * Note that this mode is also switched by the Sh macro.
258: */
1.204 schwarze 259: if (roff_getreg(mdoc->roff, "nS"))
260: mdoc->flags |= MDOC_SYNOPSIS;
261: else
262: mdoc->flags &= ~MDOC_SYNOPSIS;
1.153 schwarze 263:
1.203 schwarze 264: return(roff_getcontrol(mdoc->roff, buf, &offs) ?
1.213 schwarze 265: mdoc_pmacro(mdoc, ln, buf, offs) :
266: mdoc_ptext(mdoc, ln, buf, offs));
1.1 kristaps 267: }
268:
1.88 kristaps 269: int
1.148 kristaps 270: mdoc_macro(MACRO_PROT_ARGS)
1.88 kristaps 271: {
1.122 kristaps 272: assert(tok < MDOC_MAX);
273:
274: /* If we're in the body, deny prologue calls. */
1.117 kristaps 275:
1.213 schwarze 276: if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
277: MDOC_PBODY & mdoc->flags) {
1.215 schwarze 278: mandoc_vmsg(MANDOCERR_PROLOG_ONLY, mdoc->parse,
279: line, ppos, "%s", mdoc_macronames[tok]);
1.174 kristaps 280: return(1);
281: }
1.122 kristaps 282:
283: /* If we're in the prologue, deny "body" macros. */
284:
1.213 schwarze 285: if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
286: ! (MDOC_PBODY & mdoc->flags)) {
1.215 schwarze 287: mandoc_vmsg(MANDOCERR_PROLOG_BAD, mdoc->parse,
288: line, ppos, "%s", mdoc_macronames[tok]);
1.203 schwarze 289: if (NULL == mdoc->meta.msec)
290: mdoc->meta.msec = mandoc_strdup("1");
291: if (NULL == mdoc->meta.title)
292: mdoc->meta.title = mandoc_strdup("UNKNOWN");
293: if (NULL == mdoc->meta.vol)
294: mdoc->meta.vol = mandoc_strdup("LOCAL");
295: if (NULL == mdoc->meta.os)
296: mdoc->meta.os = mandoc_strdup("LOCAL");
297: if (NULL == mdoc->meta.date)
298: mdoc->meta.date = mandoc_normdate
299: (mdoc->parse, NULL, line, ppos);
300: mdoc->flags |= MDOC_PBODY;
1.120 kristaps 301: }
1.88 kristaps 302:
1.203 schwarze 303: return((*mdoc_macros[tok].fp)(mdoc, 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) {
1.213 schwarze 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.213 schwarze 321: case MDOC_NEXT_CHILD:
1.13 kristaps 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) {
1.213 schwarze 338: case MDOC_BODY:
1.202 schwarze 339: if (ENDBODY_NOT != p->end)
340: break;
1.172 kristaps 341: /* FALLTHROUGH */
1.213 schwarze 342: case MDOC_TAIL:
1.172 kristaps 343: /* FALLTHROUGH */
1.213 schwarze 344: case MDOC_HEAD:
1.172 kristaps 345: p->norm = p->parent->norm;
346: break;
347: default:
348: break;
349: }
350:
1.23 kristaps 351: if ( ! mdoc_valid_pre(mdoc, p))
352: return(0);
1.27 kristaps 353:
354: switch (p->type) {
1.213 schwarze 355: case MDOC_HEAD:
1.27 kristaps 356: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 357: p->parent->head = p;
1.27 kristaps 358: break;
1.213 schwarze 359: case MDOC_TAIL:
1.27 kristaps 360: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 361: p->parent->tail = p;
1.27 kristaps 362: break;
1.213 schwarze 363: case MDOC_BODY:
1.152 schwarze 364: if (p->end)
365: break;
1.27 kristaps 366: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 367: p->parent->body = p;
1.27 kristaps 368: break;
369: default:
370: break;
371: }
372:
1.1 kristaps 373: mdoc->last = p;
1.71 kristaps 374:
375: switch (p->type) {
1.213 schwarze 376: case MDOC_TBL:
1.176 kristaps 377: /* FALLTHROUGH */
1.213 schwarze 378: case MDOC_TEXT:
1.71 kristaps 379: if ( ! mdoc_valid_post(mdoc))
380: return(0);
381: break;
382: default:
383: break;
384: }
385:
1.23 kristaps 386: return(1);
1.1 kristaps 387: }
388:
1.45 kristaps 389: static struct mdoc_node *
1.213 schwarze 390: node_alloc(struct mdoc *mdoc, int line, int pos,
1.117 kristaps 391: enum mdoct tok, enum mdoc_type type)
1.45 kristaps 392: {
1.46 kristaps 393: struct mdoc_node *p;
394:
1.113 kristaps 395: p = mandoc_calloc(1, sizeof(struct mdoc_node));
1.203 schwarze 396: p->sec = mdoc->lastsec;
1.73 kristaps 397: p->line = line;
398: p->pos = pos;
1.206 schwarze 399: p->lastline = line;
1.73 kristaps 400: p->tok = tok;
1.118 kristaps 401: p->type = type;
1.150 kristaps 402:
403: /* Flag analysis. */
404:
1.203 schwarze 405: if (MDOC_SYNOPSIS & mdoc->flags)
1.153 schwarze 406: p->flags |= MDOC_SYNPRETTY;
407: else
408: p->flags &= ~MDOC_SYNPRETTY;
1.203 schwarze 409: if (MDOC_NEWLINE & mdoc->flags)
1.130 kristaps 410: p->flags |= MDOC_LINE;
1.203 schwarze 411: mdoc->flags &= ~MDOC_NEWLINE;
1.150 kristaps 412:
1.46 kristaps 413: return(p);
1.45 kristaps 414: }
415:
1.23 kristaps 416: int
1.203 schwarze 417: mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
1.17 kristaps 418: {
419: struct mdoc_node *p;
420:
1.203 schwarze 421: p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL);
422: if ( ! node_append(mdoc, p))
1.102 kristaps 423: return(0);
1.203 schwarze 424: mdoc->next = MDOC_NEXT_CHILD;
1.102 kristaps 425: return(1);
1.17 kristaps 426: }
427:
1.23 kristaps 428: int
1.203 schwarze 429: mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
1.1 kristaps 430: {
431: struct mdoc_node *p;
432:
1.203 schwarze 433: assert(mdoc->first);
434: assert(mdoc->last);
1.1 kristaps 435:
1.203 schwarze 436: p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD);
437: if ( ! node_append(mdoc, p))
1.102 kristaps 438: return(0);
1.203 schwarze 439: mdoc->next = MDOC_NEXT_CHILD;
1.102 kristaps 440: return(1);
1.1 kristaps 441: }
442:
1.23 kristaps 443: int
1.203 schwarze 444: mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
1.1 kristaps 445: {
446: struct mdoc_node *p;
447:
1.203 schwarze 448: p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
449: if ( ! node_append(mdoc, p))
1.102 kristaps 450: return(0);
1.203 schwarze 451: mdoc->next = MDOC_NEXT_CHILD;
1.152 schwarze 452: return(1);
453: }
454:
455: int
1.203 schwarze 456: mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
1.152 schwarze 457: struct mdoc_node *body, enum mdoc_endbody end)
458: {
459: struct mdoc_node *p;
460:
1.203 schwarze 461: p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
1.152 schwarze 462: p->pending = body;
1.202 schwarze 463: p->norm = body->norm;
1.152 schwarze 464: p->end = end;
1.203 schwarze 465: if ( ! node_append(mdoc, p))
1.152 schwarze 466: return(0);
1.203 schwarze 467: mdoc->next = MDOC_NEXT_SIBLING;
1.102 kristaps 468: return(1);
1.1 kristaps 469: }
470:
1.23 kristaps 471: int
1.213 schwarze 472: mdoc_block_alloc(struct mdoc *mdoc, 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.203 schwarze 477: p = node_alloc(mdoc, 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) {
1.213 schwarze 483: case MDOC_Bd:
1.172 kristaps 484: /* FALLTHROUGH */
1.213 schwarze 485: case MDOC_Bf:
1.172 kristaps 486: /* FALLTHROUGH */
1.213 schwarze 487: case MDOC_Bl:
1.217 schwarze 488: /* FALLTHROUGH */
489: case MDOC_En:
1.173 kristaps 490: /* FALLTHROUGH */
1.213 schwarze 491: case MDOC_Rs:
1.172 kristaps 492: p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
493: break;
494: default:
495: break;
496: }
497:
1.203 schwarze 498: if ( ! node_append(mdoc, p))
1.102 kristaps 499: return(0);
1.203 schwarze 500: mdoc->next = MDOC_NEXT_CHILD;
1.102 kristaps 501: return(1);
1.1 kristaps 502: }
503:
1.23 kristaps 504: int
1.213 schwarze 505: mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
1.117 kristaps 506: enum mdoct tok, struct mdoc_arg *args)
1.1 kristaps 507: {
508: struct mdoc_node *p;
509:
1.203 schwarze 510: p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM);
1.77 kristaps 511: p->args = args;
512: if (p->args)
1.53 kristaps 513: (args->refcnt)++;
1.172 kristaps 514:
515: switch (tok) {
1.213 schwarze 516: case MDOC_An:
1.172 kristaps 517: p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
518: break;
519: default:
520: break;
521: }
522:
1.203 schwarze 523: if ( ! node_append(mdoc, p))
1.102 kristaps 524: return(0);
1.203 schwarze 525: mdoc->next = MDOC_NEXT_CHILD;
1.175 kristaps 526: return(1);
527: }
1.1 kristaps 528:
1.124 kristaps 529: int
1.203 schwarze 530: mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p)
1.1 kristaps 531: {
1.91 kristaps 532: struct mdoc_node *n;
1.1 kristaps 533:
1.203 schwarze 534: n = node_alloc(mdoc, line, pos, MDOC_MAX, MDOC_TEXT);
535: n->string = roff_strdup(mdoc->roff, p);
1.91 kristaps 536:
1.203 schwarze 537: if ( ! node_append(mdoc, n))
1.101 kristaps 538: return(0);
1.124 kristaps 539:
1.203 schwarze 540: mdoc->next = MDOC_NEXT_SIBLING;
1.101 kristaps 541: return(1);
1.91 kristaps 542: }
543:
1.205 schwarze 544: void
545: mdoc_word_append(struct mdoc *mdoc, const char *p)
546: {
547: struct mdoc_node *n;
548: char *addstr, *newstr;
549:
550: n = mdoc->last;
551: addstr = roff_strdup(mdoc->roff, p);
1.210 schwarze 552: mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
1.205 schwarze 553: free(addstr);
554: free(n->string);
555: n->string = newstr;
556: mdoc->next = MDOC_NEXT_SIBLING;
557: }
1.91 kristaps 558:
1.155 kristaps 559: static void
1.53 kristaps 560: mdoc_node_free(struct mdoc_node *p)
1.1 kristaps 561: {
562:
1.172 kristaps 563: if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type)
1.171 kristaps 564: free(p->norm);
1.53 kristaps 565: if (p->string)
566: free(p->string);
567: if (p->args)
568: mdoc_argv_free(p->args);
1.1 kristaps 569: free(p);
570: }
571:
1.121 kristaps 572: static void
1.203 schwarze 573: mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n)
1.121 kristaps 574: {
575:
576: /* Adjust siblings. */
577:
578: if (n->prev)
579: n->prev->next = n->next;
580: if (n->next)
581: n->next->prev = n->prev;
582:
583: /* Adjust parent. */
584:
585: if (n->parent) {
586: n->parent->nchild--;
587: if (n->parent->child == n)
588: n->parent->child = n->prev ? n->prev : n->next;
1.169 kristaps 589: if (n->parent->last == n)
590: n->parent->last = n->prev ? n->prev : NULL;
1.121 kristaps 591: }
592:
593: /* Adjust parse point, if applicable. */
594:
1.203 schwarze 595: if (mdoc && mdoc->last == n) {
1.121 kristaps 596: if (n->prev) {
1.203 schwarze 597: mdoc->last = n->prev;
598: mdoc->next = MDOC_NEXT_SIBLING;
1.121 kristaps 599: } else {
1.203 schwarze 600: mdoc->last = n->parent;
601: mdoc->next = MDOC_NEXT_CHILD;
1.121 kristaps 602: }
603: }
604:
1.203 schwarze 605: if (mdoc && mdoc->first == n)
606: mdoc->first = NULL;
1.121 kristaps 607: }
608:
1.53 kristaps 609: void
1.203 schwarze 610: mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p)
1.1 kristaps 611: {
612:
1.121 kristaps 613: while (p->child) {
614: assert(p->nchild);
1.203 schwarze 615: mdoc_node_delete(mdoc, p->child);
1.121 kristaps 616: }
617: assert(0 == p->nchild);
1.1 kristaps 618:
1.203 schwarze 619: mdoc_node_unlink(mdoc, p);
1.53 kristaps 620: mdoc_node_free(p);
1.201 schwarze 621: }
622:
623: int
1.203 schwarze 624: mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p)
1.201 schwarze 625: {
626:
1.203 schwarze 627: mdoc_node_unlink(mdoc, p);
628: return(node_append(mdoc, p));
1.1 kristaps 629: }
630:
1.193 kristaps 631: #if 0
1.191 kristaps 632: /*
633: * Pre-treat a text line.
634: * Text lines can consist of equations, which must be handled apart from
635: * the regular text.
636: * Thus, use this function to step through a line checking if it has any
637: * equations embedded in it.
638: * This must handle multiple equations AND equations that do not end at
639: * the end-of-line, i.e., will re-enter in the next roff parse.
640: */
641: static int
1.203 schwarze 642: mdoc_preptext(struct mdoc *mdoc, int line, char *buf, int offs)
1.191 kristaps 643: {
644: char *start, *end;
645: char delim;
646:
647: while ('\0' != buf[offs]) {
648: /* Mark starting position if eqn is set. */
649: start = NULL;
1.203 schwarze 650: if ('\0' != (delim = roff_eqndelim(mdoc->roff)))
1.191 kristaps 651: if (NULL != (start = strchr(buf + offs, delim)))
652: *start++ = '\0';
653:
654: /* Parse text as normal. */
1.203 schwarze 655: if ( ! mdoc_ptext(mdoc, line, buf, offs))
1.191 kristaps 656: return(0);
657:
658: /* Continue only if an equation exists. */
659: if (NULL == start)
660: break;
661:
662: /* Read past the end of the equation. */
663: offs += start - (buf + offs);
664: assert(start == &buf[offs]);
665: if (NULL != (end = strchr(buf + offs, delim))) {
666: *end++ = '\0';
667: while (' ' == *end)
668: end++;
669: }
670:
671: /* Parse the equation itself. */
1.203 schwarze 672: roff_openeqn(mdoc->roff, NULL, line, offs, buf);
1.191 kristaps 673:
674: /* Process a finished equation? */
1.203 schwarze 675: if (roff_closeeqn(mdoc->roff))
676: if ( ! mdoc_addeqn(mdoc, roff_eqn(mdoc->roff)))
1.191 kristaps 677: return(0);
678: offs += (end - (buf + offs));
1.213 schwarze 679: }
1.191 kristaps 680:
681: return(1);
682: }
1.193 kristaps 683: #endif
1.1 kristaps 684:
1.53 kristaps 685: /*
686: * Parse free-form text, that is, a line that does not begin with the
687: * control character.
688: */
689: static int
1.203 schwarze 690: mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
1.1 kristaps 691: {
1.142 kristaps 692: char *c, *ws, *end;
693: struct mdoc_node *n;
694:
1.203 schwarze 695: assert(mdoc->last);
696: n = mdoc->last;
1.142 kristaps 697:
698: /*
1.144 kristaps 699: * Divert directly to list processing if we're encountering a
1.142 kristaps 700: * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry
1.144 kristaps 701: * (a MDOC_BODY means it's already open, in which case we should
702: * process within its context in the normal way).
1.142 kristaps 703: */
704:
1.143 kristaps 705: if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
1.213 schwarze 706: LIST_column == n->norm->Bl.type) {
1.144 kristaps 707: /* `Bl' is open without any children. */
1.203 schwarze 708: mdoc->flags |= MDOC_FREECOL;
709: return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf));
1.142 kristaps 710: }
711:
712: if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
1.213 schwarze 713: NULL != n->parent &&
714: MDOC_Bl == n->parent->tok &&
715: LIST_column == n->parent->norm->Bl.type) {
1.144 kristaps 716: /* `Bl' has block-level `It' children. */
1.203 schwarze 717: mdoc->flags |= MDOC_FREECOL;
718: return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf));
1.142 kristaps 719: }
1.124 kristaps 720:
1.137 schwarze 721: /*
722: * Search for the beginning of unescaped trailing whitespace (ws)
723: * and for the first character not to be output (end).
724: */
1.139 kristaps 725:
726: /* FIXME: replace with strcspn(). */
1.137 schwarze 727: ws = NULL;
728: for (c = end = buf + offs; *c; c++) {
729: switch (*c) {
730: case ' ':
731: if (NULL == ws)
732: ws = c;
733: continue;
734: case '\t':
735: /*
736: * Always warn about trailing tabs,
737: * even outside literal context,
738: * where they should be put on the next line.
739: */
740: if (NULL == ws)
741: ws = c;
742: /*
743: * Strip trailing tabs in literal context only;
744: * outside, they affect the next line.
745: */
1.203 schwarze 746: if (MDOC_LITERAL & mdoc->flags)
1.137 schwarze 747: continue;
748: break;
749: case '\\':
750: /* Skip the escaped character, too, if any. */
751: if (c[1])
752: c++;
753: /* FALLTHROUGH */
754: default:
755: ws = NULL;
756: break;
757: }
758: end = c + 1;
759: }
760: *end = '\0';
1.91 kristaps 761:
1.137 schwarze 762: if (ws)
1.218 schwarze 763: mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
764: line, (int)(ws-buf), NULL);
1.115 kristaps 765:
1.203 schwarze 766: if ('\0' == buf[offs] && ! (MDOC_LITERAL & mdoc->flags)) {
1.218 schwarze 767: mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
768: line, (int)(c - buf), NULL);
1.124 kristaps 769:
1.119 kristaps 770: /*
1.165 schwarze 771: * Insert a `sp' in the case of a blank line. Technically,
1.124 kristaps 772: * blank lines aren't allowed, but enough manuals assume this
773: * behaviour that we want to work around it.
1.119 kristaps 774: */
1.203 schwarze 775: if ( ! mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL))
1.119 kristaps 776: return(0);
1.124 kristaps 777:
1.203 schwarze 778: mdoc->next = MDOC_NEXT_SIBLING;
1.199 schwarze 779:
1.203 schwarze 780: return(mdoc_valid_post(mdoc));
1.119 kristaps 781: }
1.68 kristaps 782:
1.203 schwarze 783: if ( ! mdoc_word_alloc(mdoc, line, offs, buf+offs))
1.137 schwarze 784: return(0);
1.91 kristaps 785:
1.203 schwarze 786: if (MDOC_LITERAL & mdoc->flags)
1.137 schwarze 787: return(1);
1.128 kristaps 788:
789: /*
790: * End-of-sentence check. If the last character is an unescaped
791: * EOS character, then flag the node as being the end of a
792: * sentence. The front-end will know how to interpret this.
793: */
1.132 kristaps 794:
1.137 schwarze 795: assert(buf < end);
796:
1.207 schwarze 797: if (mandoc_eos(buf+offs, (size_t)(end-buf-offs)))
1.203 schwarze 798: mdoc->last->flags |= MDOC_EOS;
1.128 kristaps 799:
800: return(1);
1.1 kristaps 801: }
802:
1.53 kristaps 803: /*
804: * Parse a macro line, that is, a line beginning with the control
805: * character.
806: */
1.155 kristaps 807: static int
1.203 schwarze 808: mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
1.1 kristaps 809: {
1.144 kristaps 810: enum mdoct tok;
1.188 kristaps 811: int i, sv;
1.144 kristaps 812: char mac[5];
813: struct mdoc_node *n;
1.1 kristaps 814:
1.188 kristaps 815: /* Empty post-control lines are ignored. */
1.63 kristaps 816:
1.188 kristaps 817: if ('"' == buf[offs]) {
1.218 schwarze 818: mandoc_msg(MANDOCERR_COMMENT_BAD, mdoc->parse,
819: ln, offs, NULL);
1.188 kristaps 820: return(1);
821: } else if ('\0' == buf[offs])
1.63 kristaps 822: return(1);
823:
1.188 kristaps 824: sv = offs;
1.130 kristaps 825:
1.213 schwarze 826: /*
1.162 schwarze 827: * Copy the first word into a nil-terminated buffer.
1.165 schwarze 828: * Stop copying when a tab, space, or eoln is encountered.
1.160 kristaps 829: */
1.1 kristaps 830:
1.188 kristaps 831: i = 0;
1.213 schwarze 832: while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] &&
833: '\t' != buf[offs])
1.188 kristaps 834: mac[i++] = buf[offs++];
835:
836: mac[i] = '\0';
837:
1.214 schwarze 838: tok = (i > 1 && i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
1.1 kristaps 839:
1.163 schwarze 840: if (MDOC_MAX == tok) {
1.222 ! schwarze 841: mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
! 842: ln, sv, buf + sv - 1);
1.58 kristaps 843: return(1);
1.53 kristaps 844: }
1.1 kristaps 845:
1.160 kristaps 846: /* Disregard the first trailing tab, if applicable. */
847:
1.188 kristaps 848: if ('\t' == buf[offs])
849: offs++;
1.160 kristaps 850:
851: /* Jump to the next non-whitespace word. */
1.1 kristaps 852:
1.188 kristaps 853: while (buf[offs] && ' ' == buf[offs])
854: offs++;
1.1 kristaps 855:
1.213 schwarze 856: /*
1.125 kristaps 857: * Trailing whitespace. Note that tabs are allowed to be passed
858: * into the parser as "text", so we only warn about spaces here.
859: */
1.115 kristaps 860:
1.188 kristaps 861: if ('\0' == buf[offs] && ' ' == buf[offs - 1])
1.218 schwarze 862: mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
863: ln, offs - 1, NULL);
1.115 kristaps 864:
1.144 kristaps 865: /*
866: * If an initial macro or a list invocation, divert directly
867: * into macro processing.
868: */
869:
1.221 schwarze 870: if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok)
871: return(mdoc_macro(mdoc, tok, ln, sv, &offs, buf));
1.144 kristaps 872:
1.203 schwarze 873: n = mdoc->last;
874: assert(mdoc->last);
1.144 kristaps 875:
876: /*
877: * If the first macro of a `Bl -column', open an `It' block
878: * context around the parsed macro.
879: */
880:
881: if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
1.213 schwarze 882: LIST_column == n->norm->Bl.type) {
1.203 schwarze 883: mdoc->flags |= MDOC_FREECOL;
1.221 schwarze 884: return(mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf));
1.144 kristaps 885: }
886:
887: /*
888: * If we're following a block-level `It' within a `Bl -column'
889: * context (perhaps opened in the above block or in ptext()),
890: * then open an `It' block context around the parsed macro.
1.98 kristaps 891: */
1.144 kristaps 892:
893: if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
1.213 schwarze 894: NULL != n->parent &&
895: MDOC_Bl == n->parent->tok &&
896: LIST_column == n->parent->norm->Bl.type) {
1.203 schwarze 897: mdoc->flags |= MDOC_FREECOL;
1.221 schwarze 898: return(mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf));
1.144 kristaps 899: }
900:
901: /* Normal processing of a macro. */
902:
1.213 schwarze 903: if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf))
1.221 schwarze 904: return(0);
1.208 schwarze 905:
906: /* In quick mode (for mandocdb), abort after the NAME section. */
907:
908: if (mdoc->quick && MDOC_Sh == tok &&
909: SEC_NAME != mdoc->last->sec)
910: return(2);
1.1 kristaps 911:
1.53 kristaps 912: return(1);
1.1 kristaps 913: }
1.100 kristaps 914:
1.186 kristaps 915: enum mdelim
916: mdoc_isdelim(const char *p)
917: {
918:
919: if ('\0' == p[0])
920: return(DELIM_NONE);
921:
922: if ('\0' == p[1])
923: switch (p[0]) {
1.213 schwarze 924: case '(':
1.186 kristaps 925: /* FALLTHROUGH */
1.213 schwarze 926: case '[':
1.186 kristaps 927: return(DELIM_OPEN);
1.213 schwarze 928: case '|':
1.186 kristaps 929: return(DELIM_MIDDLE);
1.213 schwarze 930: case '.':
1.186 kristaps 931: /* FALLTHROUGH */
1.213 schwarze 932: case ',':
1.186 kristaps 933: /* FALLTHROUGH */
1.213 schwarze 934: case ';':
1.186 kristaps 935: /* FALLTHROUGH */
1.213 schwarze 936: case ':':
1.186 kristaps 937: /* FALLTHROUGH */
1.213 schwarze 938: case '?':
1.186 kristaps 939: /* FALLTHROUGH */
1.213 schwarze 940: case '!':
1.186 kristaps 941: /* FALLTHROUGH */
1.213 schwarze 942: case ')':
1.186 kristaps 943: /* FALLTHROUGH */
1.213 schwarze 944: case ']':
1.186 kristaps 945: return(DELIM_CLOSE);
946: default:
947: return(DELIM_NONE);
948: }
949:
950: if ('\\' != p[0])
951: return(DELIM_NONE);
1.100 kristaps 952:
1.186 kristaps 953: if (0 == strcmp(p + 1, "."))
954: return(DELIM_CLOSE);
1.200 schwarze 955: if (0 == strcmp(p + 1, "fR|\\fP"))
1.186 kristaps 956: return(DELIM_MIDDLE);
957:
958: return(DELIM_NONE);
1.211 schwarze 959: }
960:
961: void
962: mdoc_deroff(char **dest, const struct mdoc_node *n)
963: {
964: char *cp;
965: size_t sz;
966:
967: if (MDOC_TEXT != n->type) {
968: for (n = n->child; n; n = n->next)
969: mdoc_deroff(dest, n);
970: return;
971: }
972:
973: /* Skip leading whitespace. */
974:
975: for (cp = n->string; '\0' != *cp; cp++)
976: if (0 == isspace((unsigned char)*cp))
977: break;
978:
979: /* Skip trailing whitespace. */
980:
981: for (sz = strlen(cp); sz; sz--)
982: if (0 == isspace((unsigned char)cp[sz-1]))
983: break;
984:
985: /* Skip empty strings. */
986:
987: if (0 == sz)
988: return;
989:
990: if (NULL == *dest) {
991: *dest = mandoc_strndup(cp, sz);
992: return;
993: }
994:
995: mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
996: free(*dest);
997: *dest = cp;
1.186 kristaps 998: }
CVSweb