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