Annotation of mandoc/mdoc.c, Revision 1.55
1.55 ! kristaps 1: /* $Id: mdoc.c,v 1.54 2009/03/08 12:40:27 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the
7: * above copyright notice and this permission notice appear in all
8: * copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11: * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12: * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13: * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16: * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17: * PERFORMANCE OF THIS SOFTWARE.
18: */
19: #include <assert.h>
20: #include <ctype.h>
21: #include <err.h>
22: #include <stdarg.h>
23: #include <stdlib.h>
24: #include <stdio.h>
25: #include <string.h>
26:
27: #include "private.h"
28:
1.41 kristaps 29: /*
30: * Main caller in the libmdoc library. This begins the parsing routine,
31: * handles allocation of data, and so forth. Most of the "work" is done
1.48 kristaps 32: * in macro.c and validate.c.
1.41 kristaps 33: */
34:
1.48 kristaps 35: static struct mdoc_node *mdoc_node_alloc(const struct mdoc *);
36: static int mdoc_node_append(struct mdoc *,
37: struct mdoc_node *);
1.53 kristaps 38:
39: static int parsetext(struct mdoc *, int, char *);
40: static int parsemacro(struct mdoc *, int, char *);
1.48 kristaps 41:
42:
1.1 kristaps 43: const char *const __mdoc_macronames[MDOC_MAX] = {
44: "\\\"", "Dd", "Dt", "Os",
45: "Sh", "Ss", "Pp", "D1",
46: "Dl", "Bd", "Ed", "Bl",
47: "El", "It", "Ad", "An",
48: "Ar", "Cd", "Cm", "Dv",
49: "Er", "Ev", "Ex", "Fa",
50: "Fd", "Fl", "Fn", "Ft",
51: "Ic", "In", "Li", "Nd",
52: "Nm", "Op", "Ot", "Pa",
53: "Rv", "St", "Va", "Vt",
54: /* LINTED */
55: "Xr", "\%A", "\%B", "\%D",
56: /* LINTED */
57: "\%I", "\%J", "\%N", "\%O",
58: /* LINTED */
59: "\%P", "\%R", "\%T", "\%V",
60: "Ac", "Ao", "Aq", "At",
61: "Bc", "Bf", "Bo", "Bq",
62: "Bsx", "Bx", "Db", "Dc",
63: "Do", "Dq", "Ec", "Ef",
64: "Em", "Eo", "Fx", "Ms",
65: "No", "Ns", "Nx", "Ox",
66: "Pc", "Pf", "Po", "Pq",
67: "Qc", "Ql", "Qo", "Qq",
68: "Re", "Rs", "Sc", "So",
69: "Sq", "Sm", "Sx", "Sy",
70: "Tn", "Ux", "Xc", "Xo",
71: "Fo", "Fc", "Oo", "Oc",
72: "Bk", "Ek", "Bt", "Hf",
1.52 kristaps 73: "Fr", "Ud", "Lb",
1.1 kristaps 74: };
75:
76: const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
77: "split", "nosplit", "ragged",
78: "unfilled", "literal", "file",
79: "offset", "bullet", "dash",
80: "hyphen", "item", "enum",
81: "tag", "diag", "hang",
82: "ohang", "inset", "column",
83: "width", "compact", "std",
1.52 kristaps 84: "filled", "words", "emphasis",
85: "symbolic"
1.1 kristaps 86: };
87:
88: const char * const *mdoc_macronames = __mdoc_macronames;
89: const char * const *mdoc_argnames = __mdoc_argnames;
90:
1.45 kristaps 91:
1.1 kristaps 92: const struct mdoc_node *
1.47 kristaps 93: mdoc_node(const struct mdoc *mdoc)
1.1 kristaps 94: {
95:
96: return(mdoc->first);
97: }
98:
99:
1.37 kristaps 100: const struct mdoc_meta *
1.47 kristaps 101: mdoc_meta(const struct mdoc *mdoc)
1.37 kristaps 102: {
103:
104: return(&mdoc->meta);
105: }
106:
107:
1.1 kristaps 108: void
1.38 kristaps 109: mdoc_free(struct mdoc *mdoc)
1.34 kristaps 110: {
111:
1.38 kristaps 112: if (mdoc->first)
113: mdoc_node_freelist(mdoc->first);
114: if (mdoc->htab)
115: mdoc_tokhash_free(mdoc->htab);
1.34 kristaps 116: if (mdoc->meta.title)
117: free(mdoc->meta.title);
118: if (mdoc->meta.os)
119: free(mdoc->meta.os);
120: if (mdoc->meta.name)
121: free(mdoc->meta.name);
1.52 kristaps 122: if (mdoc->meta.arch)
123: free(mdoc->meta.arch);
124: if (mdoc->meta.vol)
125: free(mdoc->meta.vol);
1.34 kristaps 126:
1.1 kristaps 127: free(mdoc);
128: }
129:
130:
131: struct mdoc *
1.55 ! kristaps 132: mdoc_alloc(void *data, int pflags, const struct mdoc_cb *cb)
1.1 kristaps 133: {
134: struct mdoc *p;
135:
136: p = xcalloc(1, sizeof(struct mdoc));
137:
138: p->data = data;
1.33 kristaps 139: if (cb)
140: (void)memcpy(&p->cb, cb, sizeof(struct mdoc_cb));
1.1 kristaps 141:
1.25 kristaps 142: p->last = xcalloc(1, sizeof(struct mdoc_node));
143: p->last->type = MDOC_ROOT;
144: p->first = p->last;
1.55 ! kristaps 145: p->pflags = pflags;
1.25 kristaps 146: p->next = MDOC_NEXT_CHILD;
1.4 kristaps 147: p->htab = mdoc_tokhash_alloc();
1.25 kristaps 148:
1.1 kristaps 149: return(p);
150: }
151:
152:
153: int
1.20 kristaps 154: mdoc_endparse(struct mdoc *mdoc)
155: {
156:
157: if (MDOC_HALT & mdoc->flags)
158: return(0);
159: if (NULL == mdoc->first)
160: return(1);
161:
162: assert(mdoc->last);
163: if ( ! macro_end(mdoc)) {
164: mdoc->flags |= MDOC_HALT;
165: return(0);
166: }
167: return(1);
168: }
169:
170:
1.50 kristaps 171: /*
1.53 kristaps 172: * Main parse routine. Parses a single line -- really just hands off to
173: * the macro or text parser.
1.50 kristaps 174: */
1.20 kristaps 175: int
1.53 kristaps 176: mdoc_parseln(struct mdoc *m, int ln, char *buf)
1.1 kristaps 177: {
178:
1.53 kristaps 179: /* If in error-mode, then we parse no more. */
1.50 kristaps 180:
1.53 kristaps 181: if (MDOC_HALT & m->flags)
1.20 kristaps 182: return(0);
1.50 kristaps 183:
1.53 kristaps 184: return('.' == *buf ? parsemacro(m, ln, buf) :
185: parsetext(m, ln, buf));
1.1 kristaps 186: }
187:
188:
189: void
1.31 kristaps 190: mdoc_vmsg(struct mdoc *mdoc, int ln, int pos, const char *fmt, ...)
1.1 kristaps 191: {
1.31 kristaps 192: char buf[256];
1.23 kristaps 193: va_list ap;
1.1 kristaps 194:
195: if (NULL == mdoc->cb.mdoc_msg)
196: return;
197:
198: va_start(ap, fmt);
1.31 kristaps 199: (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
1.1 kristaps 200: va_end(ap);
1.31 kristaps 201: (*mdoc->cb.mdoc_msg)(mdoc->data, ln, pos, buf);
1.1 kristaps 202: }
203:
204:
205: int
1.31 kristaps 206: mdoc_verr(struct mdoc *mdoc, int ln, int pos,
207: const char *fmt, ...)
1.1 kristaps 208: {
1.31 kristaps 209: char buf[256];
210: va_list ap;
1.1 kristaps 211:
212: if (NULL == mdoc->cb.mdoc_err)
213: return(0);
1.31 kristaps 214:
215: va_start(ap, fmt);
216: (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
217: va_end(ap);
218: return((*mdoc->cb.mdoc_err)(mdoc->data, ln, pos, buf));
1.1 kristaps 219: }
220:
221:
222: int
1.31 kristaps 223: mdoc_vwarn(struct mdoc *mdoc, int ln, int pos,
224: enum mdoc_warn type, const char *fmt, ...)
1.1 kristaps 225: {
1.31 kristaps 226: char buf[256];
227: va_list ap;
1.1 kristaps 228:
229: if (NULL == mdoc->cb.mdoc_warn)
230: return(0);
1.31 kristaps 231:
232: va_start(ap, fmt);
233: (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
234: va_end(ap);
235: return((*mdoc->cb.mdoc_warn)(mdoc->data, ln, pos, type, buf));
1.1 kristaps 236: }
237:
238:
239: int
1.53 kristaps 240: mdoc_macro(struct mdoc *m, int tok,
241: int ln, int pp, int *pos, char *buf)
1.1 kristaps 242: {
243:
1.53 kristaps 244: /* FIXME - these should happen during validation. */
1.31 kristaps 245:
1.44 kristaps 246: if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
1.53 kristaps 247: SEC_PROLOGUE != m->lastnamed)
248: return(mdoc_perr(m, ln, pp,
249: "disallowed in document body"));
250:
1.44 kristaps 251: if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
1.53 kristaps 252: SEC_PROLOGUE == m->lastnamed)
253: return(mdoc_perr(m, ln, pp,
254: "disallowed in prologue"));
255:
256: if (1 != pp && ! (MDOC_CALLABLE & mdoc_macros[tok].flags))
257: return(mdoc_perr(m, ln, pp, "not callable"));
258:
259: return((*mdoc_macros[tok].fp)(m, tok, ln, pp, pos, buf));
1.1 kristaps 260: }
261:
262:
1.23 kristaps 263: static int
264: mdoc_node_append(struct mdoc *mdoc, struct mdoc_node *p)
1.1 kristaps 265: {
266:
1.25 kristaps 267: assert(mdoc->last);
268: assert(mdoc->first);
269: assert(MDOC_ROOT != p->type);
1.1 kristaps 270:
1.13 kristaps 271: switch (mdoc->next) {
272: case (MDOC_NEXT_SIBLING):
1.6 kristaps 273: mdoc->last->next = p;
274: p->prev = mdoc->last;
1.13 kristaps 275: p->parent = mdoc->last->parent;
1.1 kristaps 276: break;
1.13 kristaps 277: case (MDOC_NEXT_CHILD):
278: mdoc->last->child = p;
1.1 kristaps 279: p->parent = mdoc->last;
280: break;
281: default:
1.13 kristaps 282: abort();
283: /* NOTREACHED */
1.1 kristaps 284: }
285:
1.23 kristaps 286: if ( ! mdoc_valid_pre(mdoc, p))
287: return(0);
1.27 kristaps 288:
289: switch (p->type) {
290: case (MDOC_HEAD):
291: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 292: p->parent->head = p;
1.27 kristaps 293: break;
294: case (MDOC_TAIL):
295: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 296: p->parent->tail = p;
1.27 kristaps 297: break;
298: case (MDOC_BODY):
299: assert(MDOC_BLOCK == p->parent->type);
1.53 kristaps 300: p->parent->body = p;
1.27 kristaps 301: break;
302: default:
303: break;
304: }
305:
1.1 kristaps 306: mdoc->last = p;
1.23 kristaps 307: return(1);
1.1 kristaps 308: }
309:
310:
1.45 kristaps 311: static struct mdoc_node *
1.46 kristaps 312: mdoc_node_alloc(const struct mdoc *mdoc)
1.45 kristaps 313: {
1.46 kristaps 314: struct mdoc_node *p;
315:
316: p = xcalloc(1, sizeof(struct mdoc_node));
317: p->sec = mdoc->lastsec;
1.45 kristaps 318:
1.46 kristaps 319: return(p);
1.45 kristaps 320: }
321:
322:
1.23 kristaps 323: int
1.22 kristaps 324: mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, int tok)
1.17 kristaps 325: {
326: struct mdoc_node *p;
327:
328: assert(mdoc->first);
329: assert(mdoc->last);
330:
1.46 kristaps 331: p = mdoc_node_alloc(mdoc);
1.17 kristaps 332:
1.22 kristaps 333: p->line = line;
334: p->pos = pos;
1.17 kristaps 335: p->type = MDOC_TAIL;
1.27 kristaps 336: p->tok = tok;
1.17 kristaps 337:
1.23 kristaps 338: return(mdoc_node_append(mdoc, p));
1.17 kristaps 339: }
340:
341:
1.23 kristaps 342: int
1.22 kristaps 343: mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, int tok)
1.1 kristaps 344: {
345: struct mdoc_node *p;
346:
347: assert(mdoc->first);
348: assert(mdoc->last);
349:
1.46 kristaps 350: p = mdoc_node_alloc(mdoc);
1.13 kristaps 351:
1.22 kristaps 352: p->line = line;
353: p->pos = pos;
1.1 kristaps 354: p->type = MDOC_HEAD;
1.27 kristaps 355: p->tok = tok;
1.1 kristaps 356:
1.23 kristaps 357: return(mdoc_node_append(mdoc, p));
1.1 kristaps 358: }
359:
360:
1.23 kristaps 361: int
1.22 kristaps 362: mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, int tok)
1.1 kristaps 363: {
364: struct mdoc_node *p;
365:
366: assert(mdoc->first);
367: assert(mdoc->last);
368:
1.46 kristaps 369: p = mdoc_node_alloc(mdoc);
1.1 kristaps 370:
1.22 kristaps 371: p->line = line;
372: p->pos = pos;
1.1 kristaps 373: p->type = MDOC_BODY;
1.27 kristaps 374: p->tok = tok;
1.1 kristaps 375:
1.23 kristaps 376: return(mdoc_node_append(mdoc, p));
1.1 kristaps 377: }
378:
379:
1.23 kristaps 380: int
1.25 kristaps 381: mdoc_root_alloc(struct mdoc *mdoc)
382: {
383: struct mdoc_node *p;
384:
1.46 kristaps 385: p = mdoc_node_alloc(mdoc);
1.25 kristaps 386:
387: p->type = MDOC_ROOT;
388:
389: return(mdoc_node_append(mdoc, p));
390: }
391:
392:
393: int
1.22 kristaps 394: mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
1.53 kristaps 395: int tok, struct mdoc_arg *args)
1.1 kristaps 396: {
397: struct mdoc_node *p;
398:
1.46 kristaps 399: p = mdoc_node_alloc(mdoc);
1.1 kristaps 400:
1.22 kristaps 401: p->pos = pos;
402: p->line = line;
1.1 kristaps 403: p->type = MDOC_BLOCK;
1.27 kristaps 404: p->tok = tok;
1.53 kristaps 405: p->args = args;
406:
407: if (args)
408: (args->refcnt)++;
1.1 kristaps 409:
1.23 kristaps 410: return(mdoc_node_append(mdoc, p));
1.1 kristaps 411: }
412:
413:
1.23 kristaps 414: int
1.22 kristaps 415: mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
1.53 kristaps 416: int tok, struct mdoc_arg *args)
1.1 kristaps 417: {
418: struct mdoc_node *p;
419:
1.46 kristaps 420: p = mdoc_node_alloc(mdoc);
1.22 kristaps 421:
422: p->line = line;
423: p->pos = pos;
1.1 kristaps 424: p->type = MDOC_ELEM;
1.27 kristaps 425: p->tok = tok;
1.53 kristaps 426: p->args = args;
427:
428: if (args)
429: (args->refcnt)++;
1.1 kristaps 430:
1.23 kristaps 431: return(mdoc_node_append(mdoc, p));
1.1 kristaps 432: }
433:
434:
1.23 kristaps 435: int
1.22 kristaps 436: mdoc_word_alloc(struct mdoc *mdoc,
437: int line, int pos, const char *word)
1.1 kristaps 438: {
439: struct mdoc_node *p;
440:
1.46 kristaps 441: p = mdoc_node_alloc(mdoc);
1.45 kristaps 442:
1.22 kristaps 443: p->line = line;
444: p->pos = pos;
1.1 kristaps 445: p->type = MDOC_TEXT;
1.53 kristaps 446: p->string = xstrdup(word);
1.1 kristaps 447:
1.23 kristaps 448: return(mdoc_node_append(mdoc, p));
1.1 kristaps 449: }
450:
451:
1.53 kristaps 452: void
453: mdoc_node_free(struct mdoc_node *p)
1.1 kristaps 454: {
455:
1.53 kristaps 456: if (p->string)
457: free(p->string);
458: if (p->args)
459: mdoc_argv_free(p->args);
1.1 kristaps 460: free(p);
461: }
462:
463:
1.53 kristaps 464: void
465: mdoc_node_freelist(struct mdoc_node *p)
1.1 kristaps 466: {
467:
1.53 kristaps 468: if (p->child)
469: mdoc_node_freelist(p->child);
470: if (p->next)
471: mdoc_node_freelist(p->next);
1.1 kristaps 472:
1.53 kristaps 473: mdoc_node_free(p);
1.1 kristaps 474: }
475:
476:
1.53 kristaps 477: /*
478: * Parse free-form text, that is, a line that does not begin with the
479: * control character.
480: */
481: static int
482: parsetext(struct mdoc *mdoc, int line, char *buf)
1.1 kristaps 483: {
484:
1.53 kristaps 485: if (SEC_PROLOGUE == mdoc->lastnamed)
486: return(mdoc_perr(mdoc, line, 0,
487: "text disallowed in prologue"));
1.1 kristaps 488:
1.53 kristaps 489: if ( ! mdoc_word_alloc(mdoc, line, 0, buf))
490: return(0);
1.1 kristaps 491:
1.53 kristaps 492: mdoc->next = MDOC_NEXT_SIBLING;
493: return(1);
1.1 kristaps 494: }
495:
496:
1.53 kristaps 497: /*
498: * Parse a macro line, that is, a line beginning with the control
499: * character.
500: */
501: int
502: parsemacro(struct mdoc *m, int ln, char *buf)
1.1 kristaps 503: {
1.53 kristaps 504: int i, c;
505: char mac[5];
1.1 kristaps 506:
1.53 kristaps 507: /* Comments are quickly ignored. */
1.1 kristaps 508:
1.53 kristaps 509: if (buf[1] && '\\' == buf[1])
510: if (buf[2] && '\"' == buf[2])
511: return(1);
1.1 kristaps 512:
1.53 kristaps 513: /* Copy the first word into a nil-terminated buffer. */
1.1 kristaps 514:
1.53 kristaps 515: for (i = 1; i < 5; i++) {
516: if (0 == (mac[i - 1] = buf[i]))
517: break;
518: else if (isspace((unsigned char)buf[i]))
519: break;
520: }
1.1 kristaps 521:
1.54 kristaps 522: /* FIXME: be able to skip unknown macro lines! */
523:
1.53 kristaps 524: mac[i - 1] = 0;
1.1 kristaps 525:
1.53 kristaps 526: if (i == 5 || i <= 2) {
527: (void)mdoc_perr(m, ln, 1, "unknown macro: %s%s",
528: mac, i == 5 ? "..." : "");
529: goto err;
530: }
531:
532: if (MDOC_MAX == (c = mdoc_tokhash_find(m->htab, mac))) {
533: (void)mdoc_perr(m, ln, 1, "unknown macro: %s", mac);
534: goto err;
535: }
1.1 kristaps 536:
1.53 kristaps 537: /* The macro is sane. Jump to the next word. */
1.1 kristaps 538:
1.53 kristaps 539: while (buf[i] && isspace((unsigned char)buf[i]))
540: i++;
1.1 kristaps 541:
1.53 kristaps 542: /* Begin recursive parse sequence. */
1.1 kristaps 543:
1.53 kristaps 544: if ( ! mdoc_macro(m, c, ln, 1, &i, buf))
545: goto err;
1.1 kristaps 546:
1.53 kristaps 547: return(1);
1.1 kristaps 548:
1.53 kristaps 549: err: /* Error out. */
1.1 kristaps 550:
1.53 kristaps 551: m->flags |= MDOC_HALT;
552: return(0);
1.1 kristaps 553: }
CVSweb