Merge branch 'vendor/FILE'
[dragonfly.git] / contrib / mdocml / read.c
1 /*      $Id: read.c,v 1.10 2011/04/03 10:11:25 kristaps Exp $ */
2 /*
3  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
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.
17  */
18 #include <sys/stat.h>
19 #include <sys/mman.h>
20
21 #include <assert.h>
22 #include <ctype.h>
23 #include <fcntl.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "mandoc.h"
31 #include "libmandoc.h"
32 #include "mdoc.h"
33 #include "man.h"
34
35 #ifndef MAP_FILE
36 #define MAP_FILE        0
37 #endif
38
39 #define REPARSE_LIMIT   1000
40
41 struct  buf {
42         char             *buf; /* binary input buffer */
43         size_t            sz; /* size of binary buffer */
44 };
45
46 struct  mparse {
47         enum mandoclevel  file_status; /* status of current parse */
48         enum mandoclevel  wlevel; /* ignore messages below this */
49         int               line; /* line number in the file */
50         enum mparset      inttype; /* which parser to use */
51         struct man       *pman; /* persistent man parser */
52         struct mdoc      *pmdoc; /* persistent mdoc parser */
53         struct man       *man; /* man parser */
54         struct mdoc      *mdoc; /* mdoc parser */
55         struct roff      *roff; /* roff parser (!NULL) */
56         struct regset     regs; /* roff registers */
57         int               reparse_count; /* finite interp. stack */
58         mandocmsg         mmsg; /* warning/error message handler */
59         void             *arg; /* argument to mmsg */
60         const char       *file; 
61 };
62
63 static  void      resize_buf(struct buf *, size_t);
64 static  void      mparse_buf_r(struct mparse *, struct buf, int);
65 static  void      mparse_readfd_r(struct mparse *, int, const char *, int);
66 static  void      pset(const char *, int, struct mparse *);
67 static  void      pdesc(struct mparse *, const char *, int);
68 static  int       read_whole_file(const char *, int, struct buf *, int *);
69 static  void      mparse_end(struct mparse *);
70
71 static  const enum mandocerr    mandoclimits[MANDOCLEVEL_MAX] = {
72         MANDOCERR_OK,
73         MANDOCERR_WARNING,
74         MANDOCERR_WARNING,
75         MANDOCERR_ERROR,
76         MANDOCERR_FATAL,
77         MANDOCERR_MAX,
78         MANDOCERR_MAX
79 };
80
81 static  const char * const      mandocerrs[MANDOCERR_MAX] = {
82         "ok",
83
84         "generic warning",
85
86         /* related to the prologue */
87         "no title in document",
88         "document title should be all caps",
89         "unknown manual section",
90         "date missing, using today's date",
91         "cannot parse date, using it verbatim",
92         "prologue macros out of order",
93         "duplicate prologue macro",
94         "macro not allowed in prologue",
95         "macro not allowed in body",
96
97         /* related to document structure */
98         ".so is fragile, better use ln(1)",
99         "NAME section must come first",
100         "bad NAME section contents",
101         "manual name not yet set",
102         "sections out of conventional order",
103         "duplicate section name",
104         "section not in conventional manual section",
105
106         /* related to macros and nesting */
107         "skipping obsolete macro",
108         "skipping paragraph macro",
109         "skipping no-space macro",
110         "blocks badly nested",
111         "child violates parent syntax",
112         "nested displays are not portable",
113         "already in literal mode",
114         "line scope broken",
115
116         /* related to missing macro arguments */
117         "skipping empty macro",
118         "argument count wrong",
119         "missing display type",
120         "list type must come first",
121         "tag lists require a width argument",
122         "missing font type",
123         "skipping end of block that is not open",
124
125         /* related to bad macro arguments */
126         "skipping argument",
127         "duplicate argument",
128         "duplicate display type",
129         "duplicate list type",
130         "unknown AT&T UNIX version",
131         "bad Boolean value",
132         "unknown font",
133         "unknown standard specifier",
134         "bad width argument",
135
136         /* related to plain text */
137         "blank line in non-literal context",
138         "tab in non-literal context",
139         "end of line whitespace",
140         "bad comment style",
141         "unknown escape sequence",
142         "unterminated quoted string",
143         
144         "generic error",
145
146         /* related to tables */
147         "bad table syntax",
148         "bad table option",
149         "bad table layout",
150         "no table layout cells specified",
151         "no table data cells specified",
152         "ignore data in cell",
153         "data block still open",
154         "ignoring extra data cells",
155
156         "input stack limit exceeded, infinite loop?",
157         "skipping bad character",
158         "escaped character not allowed in a name",
159         "skipping text before the first section header",
160         "skipping unknown macro",
161         "NOT IMPLEMENTED, please use groff: skipping request",
162         "argument count wrong",
163         "skipping end of block that is not open",
164         "missing end of block",
165         "scope open on exit",
166         "uname(3) system call failed",
167         "macro requires line argument(s)",
168         "macro requires body argument(s)",
169         "macro requires argument(s)",
170         "missing list type",
171         "line argument(s) will be lost",
172         "body argument(s) will be lost",
173
174         "generic fatal error",
175
176         "not a manual",
177         "column syntax is inconsistent",
178         "NOT IMPLEMENTED: .Bd -file",
179         "line scope broken, syntax violated",
180         "argument count wrong, violates syntax",
181         "child violates parent syntax",
182         "argument count wrong, violates syntax",
183         "NOT IMPLEMENTED: .so with absolute path or \"..\"",
184         "no document body",
185         "no document prologue",
186         "static buffer exhausted",
187 };
188
189 static  const char * const      mandoclevels[MANDOCLEVEL_MAX] = {
190         "SUCCESS",
191         "RESERVED",
192         "WARNING",
193         "ERROR",
194         "FATAL",
195         "BADARG",
196         "SYSERR"
197 };
198
199 static void
200 resize_buf(struct buf *buf, size_t initial)
201 {
202
203         buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;
204         buf->buf = mandoc_realloc(buf->buf, buf->sz);
205 }
206
207 static void
208 pset(const char *buf, int pos, struct mparse *curp)
209 {
210         int              i;
211
212         /*
213          * Try to intuit which kind of manual parser should be used.  If
214          * passed in by command-line (-man, -mdoc), then use that
215          * explicitly.  If passed as -mandoc, then try to guess from the
216          * line: either skip dot-lines, use -mdoc when finding `.Dt', or
217          * default to -man, which is more lenient.
218          *
219          * Separate out pmdoc/pman from mdoc/man: the first persists
220          * through all parsers, while the latter is used per-parse.
221          */
222
223         if ('.' == buf[0] || '\'' == buf[0]) {
224                 for (i = 1; buf[i]; i++)
225                         if (' ' != buf[i] && '\t' != buf[i])
226                                 break;
227                 if ('\0' == buf[i])
228                         return;
229         }
230
231         switch (curp->inttype) {
232         case (MPARSE_MDOC):
233                 if (NULL == curp->pmdoc) 
234                         curp->pmdoc = mdoc_alloc(&curp->regs, curp);
235                 assert(curp->pmdoc);
236                 curp->mdoc = curp->pmdoc;
237                 return;
238         case (MPARSE_MAN):
239                 if (NULL == curp->pman) 
240                         curp->pman = man_alloc(&curp->regs, curp);
241                 assert(curp->pman);
242                 curp->man = curp->pman;
243                 return;
244         default:
245                 break;
246         }
247
248         if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3))  {
249                 if (NULL == curp->pmdoc) 
250                         curp->pmdoc = mdoc_alloc(&curp->regs, curp);
251                 assert(curp->pmdoc);
252                 curp->mdoc = curp->pmdoc;
253                 return;
254         } 
255
256         if (NULL == curp->pman) 
257                 curp->pman = man_alloc(&curp->regs, curp);
258         assert(curp->pman);
259         curp->man = curp->pman;
260 }
261
262 /*
263  * Main parse routine for an opened file.  This is called for each
264  * opened file and simply loops around the full input file, possibly
265  * nesting (i.e., with `so').
266  */
267 static void
268 mparse_buf_r(struct mparse *curp, struct buf blk, int start)
269 {
270         const struct tbl_span   *span;
271         struct buf       ln;
272         enum rofferr     rr;
273         int              i, of, rc;
274         int              pos; /* byte number in the ln buffer */
275         int              lnn; /* line number in the real file */
276         unsigned char    c;
277
278         memset(&ln, 0, sizeof(struct buf));
279
280         lnn = curp->line; 
281         pos = 0; 
282
283         for (i = 0; i < (int)blk.sz; ) {
284                 if (0 == pos && '\0' == blk.buf[i])
285                         break;
286
287                 if (start) {
288                         curp->line = lnn;
289                         curp->reparse_count = 0;
290                 }
291
292                 while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
293
294                         /*
295                          * When finding an unescaped newline character,
296                          * leave the character loop to process the line.
297                          * Skip a preceding carriage return, if any.
298                          */
299
300                         if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz &&
301                             '\n' == blk.buf[i + 1])
302                                 ++i;
303                         if ('\n' == blk.buf[i]) {
304                                 ++i;
305                                 ++lnn;
306                                 break;
307                         }
308
309                         /* 
310                          * Warn about bogus characters.  If you're using
311                          * non-ASCII encoding, you're screwing your
312                          * readers.  Since I'd rather this not happen,
313                          * I'll be helpful and drop these characters so
314                          * we don't display gibberish.  Note to manual
315                          * writers: use special characters.
316                          */
317
318                         c = (unsigned char) blk.buf[i];
319
320                         if ( ! (isascii(c) && 
321                                         (isgraph(c) || isblank(c)))) {
322                                 mandoc_msg(MANDOCERR_BADCHAR, curp,
323                                                 curp->line, pos, "ignoring byte");
324                                 i++;
325                                 continue;
326                         }
327
328                         /* Trailing backslash = a plain char. */
329
330                         if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
331                                 if (pos >= (int)ln.sz)
332                                         resize_buf(&ln, 256);
333                                 ln.buf[pos++] = blk.buf[i++];
334                                 continue;
335                         }
336
337                         /*
338                          * Found escape and at least one other character.
339                          * When it's a newline character, skip it.
340                          * When there is a carriage return in between,
341                          * skip that one as well.
342                          */
343
344                         if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz &&
345                             '\n' == blk.buf[i + 2])
346                                 ++i;
347                         if ('\n' == blk.buf[i + 1]) {
348                                 i += 2;
349                                 ++lnn;
350                                 continue;
351                         }
352
353                         if ('"' == blk.buf[i + 1]) {
354                                 i += 2;
355                                 /* Comment, skip to end of line */
356                                 for (; i < (int)blk.sz; ++i) {
357                                         if ('\n' == blk.buf[i]) {
358                                                 ++i;
359                                                 ++lnn;
360                                                 break;
361                                         }
362                                 }
363
364                                 /* Backout trailing whitespaces */
365                                 for (; pos > 0; --pos) {
366                                         if (ln.buf[pos - 1] != ' ')
367                                                 break;
368                                         if (pos > 2 && ln.buf[pos - 2] == '\\')
369                                                 break;
370                                 }
371                                 break;
372                         }
373
374                         /* Some other escape sequence, copy & cont. */
375
376                         if (pos + 1 >= (int)ln.sz)
377                                 resize_buf(&ln, 256);
378
379                         ln.buf[pos++] = blk.buf[i++];
380                         ln.buf[pos++] = blk.buf[i++];
381                 }
382
383                 if (pos >= (int)ln.sz)
384                         resize_buf(&ln, 256);
385
386                 ln.buf[pos] = '\0';
387
388                 /*
389                  * A significant amount of complexity is contained by
390                  * the roff preprocessor.  It's line-oriented but can be
391                  * expressed on one line, so we need at times to
392                  * readjust our starting point and re-run it.  The roff
393                  * preprocessor can also readjust the buffers with new
394                  * data, so we pass them in wholesale.
395                  */
396
397                 of = 0;
398
399 rerun:
400                 rr = roff_parseln
401                         (curp->roff, curp->line, 
402                          &ln.buf, &ln.sz, of, &of);
403
404                 switch (rr) {
405                 case (ROFF_REPARSE):
406                         if (REPARSE_LIMIT >= ++curp->reparse_count)
407                                 mparse_buf_r(curp, ln, 0);
408                         else
409                                 mandoc_msg(MANDOCERR_ROFFLOOP, curp,
410                                         curp->line, pos, NULL);
411                         pos = 0;
412                         continue;
413                 case (ROFF_APPEND):
414                         pos = (int)strlen(ln.buf);
415                         continue;
416                 case (ROFF_RERUN):
417                         goto rerun;
418                 case (ROFF_IGN):
419                         pos = 0;
420                         continue;
421                 case (ROFF_ERR):
422                         assert(MANDOCLEVEL_FATAL <= curp->file_status);
423                         break;
424                 case (ROFF_SO):
425                         mparse_readfd_r(curp, -1, ln.buf + of, 1);
426                         if (MANDOCLEVEL_FATAL <= curp->file_status)
427                                 break;
428                         pos = 0;
429                         continue;
430                 default:
431                         break;
432                 }
433
434                 /*
435                  * If we encounter errors in the recursive parse, make
436                  * sure we don't continue parsing.
437                  */
438
439                 if (MANDOCLEVEL_FATAL <= curp->file_status)
440                         break;
441
442                 /*
443                  * If input parsers have not been allocated, do so now.
444                  * We keep these instanced betwen parsers, but set them
445                  * locally per parse routine since we can use different
446                  * parsers with each one.
447                  */
448
449                 if ( ! (curp->man || curp->mdoc))
450                         pset(ln.buf + of, pos - of, curp);
451
452                 /* 
453                  * Lastly, push down into the parsers themselves.  One
454                  * of these will have already been set in the pset()
455                  * routine.
456                  * If libroff returns ROFF_TBL, then add it to the
457                  * currently open parse.  Since we only get here if
458                  * there does exist data (see tbl_data.c), we're
459                  * guaranteed that something's been allocated.
460                  * Do the same for ROFF_EQN.
461                  */
462
463                 rc = -1;
464
465                 if (ROFF_TBL == rr)
466                         while (NULL != (span = roff_span(curp->roff))) {
467                                 rc = curp->man ?
468                                         man_addspan(curp->man, span) :
469                                         mdoc_addspan(curp->mdoc, span);
470                                 if (0 == rc)
471                                         break;
472                         }
473                 else if (ROFF_EQN == rr)
474                         rc = curp->mdoc ? 
475                                 mdoc_addeqn(curp->mdoc, 
476                                         roff_eqn(curp->roff)) :
477                                 man_addeqn(curp->man,
478                                         roff_eqn(curp->roff));
479                 else if (curp->man || curp->mdoc)
480                         rc = curp->man ?
481                                 man_parseln(curp->man, 
482                                         curp->line, ln.buf, of) :
483                                 mdoc_parseln(curp->mdoc, 
484                                         curp->line, ln.buf, of);
485
486                 if (0 == rc) {
487                         assert(MANDOCLEVEL_FATAL <= curp->file_status);
488                         break;
489                 }
490
491                 /* Temporary buffers typically are not full. */
492
493                 if (0 == start && '\0' == blk.buf[i])
494                         break;
495
496                 /* Start the next input line. */
497
498                 pos = 0;
499         }
500
501         free(ln.buf);
502 }
503
504 static void
505 pdesc(struct mparse *curp, const char *file, int fd)
506 {
507         struct buf       blk;
508         int              with_mmap;
509
510         /*
511          * Run for each opened file; may be called more than once for
512          * each full parse sequence if the opened file is nested (i.e.,
513          * from `so').  Simply sucks in the whole file and moves into
514          * the parse phase for the file.
515          */
516
517         if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
518                 curp->file_status = MANDOCLEVEL_SYSERR;
519                 return;
520         }
521
522         /* Line number is per-file. */
523
524         curp->line = 1;
525
526         mparse_buf_r(curp, blk, 1);
527
528         if (with_mmap)
529                 munmap(blk.buf, blk.sz);
530         else
531                 free(blk.buf);
532 }
533
534 static int
535 read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
536 {
537         struct stat      st;
538         size_t           off;
539         ssize_t          ssz;
540
541         if (-1 == fstat(fd, &st)) {
542                 perror(file);
543                 return(0);
544         }
545
546         /*
547          * If we're a regular file, try just reading in the whole entry
548          * via mmap().  This is faster than reading it into blocks, and
549          * since each file is only a few bytes to begin with, I'm not
550          * concerned that this is going to tank any machines.
551          */
552
553         if (S_ISREG(st.st_mode)) {
554                 if (st.st_size >= (1U << 31)) {
555                         fprintf(stderr, "%s: input too large\n", file);
556                         return(0);
557                 }
558                 *with_mmap = 1;
559                 fb->sz = (size_t)st.st_size;
560                 fb->buf = mmap(NULL, fb->sz, PROT_READ, 
561                                 MAP_FILE|MAP_SHARED, fd, 0);
562                 if (fb->buf != MAP_FAILED)
563                         return(1);
564         }
565
566         /*
567          * If this isn't a regular file (like, say, stdin), then we must
568          * go the old way and just read things in bit by bit.
569          */
570
571         *with_mmap = 0;
572         off = 0;
573         fb->sz = 0;
574         fb->buf = NULL;
575         for (;;) {
576                 if (off == fb->sz) {
577                         if (fb->sz == (1U << 31)) {
578                                 fprintf(stderr, "%s: input too large\n", file);
579                                 break;
580                         }
581                         resize_buf(fb, 65536);
582                 }
583                 ssz = read(fd, fb->buf + (int)off, fb->sz - off);
584                 if (ssz == 0) {
585                         fb->sz = off;
586                         return(1);
587                 }
588                 if (ssz == -1) {
589                         perror(file);
590                         break;
591                 }
592                 off += (size_t)ssz;
593         }
594
595         free(fb->buf);
596         fb->buf = NULL;
597         return(0);
598 }
599
600 static void
601 mparse_end(struct mparse *curp)
602 {
603
604         if (MANDOCLEVEL_FATAL <= curp->file_status)
605                 return;
606
607         if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
608                 assert(MANDOCLEVEL_FATAL <= curp->file_status);
609                 return;
610         }
611
612         if (curp->man && ! man_endparse(curp->man)) {
613                 assert(MANDOCLEVEL_FATAL <= curp->file_status);
614                 return;
615         }
616
617         if ( ! (curp->man || curp->mdoc)) {
618                 mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL);
619                 curp->file_status = MANDOCLEVEL_FATAL;
620                 return;
621         }
622
623         roff_endparse(curp->roff);
624 }
625
626 static void
627 mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re)
628 {
629         const char      *svfile;
630
631         if (-1 == fd)
632                 if (-1 == (fd = open(file, O_RDONLY, 0))) {
633                         perror(file);
634                         curp->file_status = MANDOCLEVEL_SYSERR;
635                         return;
636                 }
637
638         svfile = curp->file;
639         curp->file = file;
640
641         pdesc(curp, file, fd);
642
643         if (0 == re && MANDOCLEVEL_FATAL > curp->file_status)
644                 mparse_end(curp);
645
646         if (STDIN_FILENO != fd && -1 == close(fd))
647                 perror(file);
648
649         curp->file = svfile;
650 }
651
652 enum mandoclevel
653 mparse_readfd(struct mparse *curp, int fd, const char *file)
654 {
655
656         mparse_readfd_r(curp, fd, file, 0);
657         return(curp->file_status);
658 }
659
660 struct mparse *
661 mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg)
662 {
663         struct mparse   *curp;
664
665         assert(wlevel <= MANDOCLEVEL_FATAL);
666
667         curp = mandoc_calloc(1, sizeof(struct mparse));
668
669         curp->wlevel = wlevel;
670         curp->mmsg = mmsg;
671         curp->arg = arg;
672         curp->inttype = inttype;
673
674         curp->roff = roff_alloc(&curp->regs, curp);
675         return(curp);
676 }
677
678 void
679 mparse_reset(struct mparse *curp)
680 {
681
682         memset(&curp->regs, 0, sizeof(struct regset));
683
684         roff_reset(curp->roff);
685
686         if (curp->mdoc)
687                 mdoc_reset(curp->mdoc);
688         if (curp->man)
689                 man_reset(curp->man);
690
691         curp->file_status = MANDOCLEVEL_OK;
692         curp->mdoc = NULL;
693         curp->man = NULL;
694 }
695
696 void
697 mparse_free(struct mparse *curp)
698 {
699
700         if (curp->pmdoc)
701                 mdoc_free(curp->pmdoc);
702         if (curp->pman)
703                 man_free(curp->pman);
704         if (curp->roff)
705                 roff_free(curp->roff);
706
707         free(curp);
708 }
709
710 void
711 mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man)
712 {
713
714         if (mdoc)
715                 *mdoc = curp->mdoc;
716         if (man)
717                 *man = curp->man;
718 }
719
720 void
721 mandoc_vmsg(enum mandocerr t, struct mparse *m,
722                 int ln, int pos, const char *fmt, ...)
723 {
724         char             buf[256];
725         va_list          ap;
726
727         va_start(ap, fmt);
728         vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
729         va_end(ap);
730
731         mandoc_msg(t, m, ln, pos, buf);
732 }
733
734 void
735 mandoc_msg(enum mandocerr er, struct mparse *m, 
736                 int ln, int col, const char *msg)
737 {
738         enum mandoclevel level;
739
740         level = MANDOCLEVEL_FATAL;
741         while (er < mandoclimits[level])
742                 level--;
743
744         if (level < m->wlevel)
745                 return;
746
747         if (m->mmsg)
748                 (*m->mmsg)(er, level, m->file, ln, col, msg);
749
750         if (m->file_status < level)
751                 m->file_status = level;
752 }
753
754 const char *
755 mparse_strerror(enum mandocerr er)
756 {
757
758         return(mandocerrs[er]);
759 }
760
761 const char *
762 mparse_strlevel(enum mandoclevel lvl)
763 {
764         return(mandoclevels[lvl]);
765 }