[BACK]Return to main.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Diff for /mandoc/main.c between version 1.76 and 1.157

version 1.76, 2010/05/16 10:59:36 version 1.157, 2011/03/21 12:04:26
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>   * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above   * purpose with or without fee is hereby granted, provided that the above
Line 18 
Line 19 
 #include "config.h"  #include "config.h"
 #endif  #endif
   
 #include <sys/mman.h>  
 #include <sys/stat.h>  
   
 #include <assert.h>  #include <assert.h>
 #include <fcntl.h>  
 #include <stdio.h>  #include <stdio.h>
 #include <stdint.h>  #include <stdint.h>
 #include <stdlib.h>  #include <stdlib.h>
Line 30 
Line 27 
 #include <unistd.h>  #include <unistd.h>
   
 #include "mandoc.h"  #include "mandoc.h"
   #include "main.h"
 #include "mdoc.h"  #include "mdoc.h"
 #include "man.h"  #include "man.h"
 #include "roff.h"  
 #include "main.h"  
   
 #define UNCONST(a)      ((void *)(uintptr_t)(const void *)(a))  
   
 /* FIXME: Intel's compiler?  LLVM?  pcc?  */  
   
 #if !defined(__GNUC__) || (__GNUC__ < 2)  #if !defined(__GNUC__) || (__GNUC__ < 2)
 # if !defined(lint)  # if !defined(lint)
 #  define __attribute__(x)  #  define __attribute__(x)
Line 49  typedef void  (*out_mdoc)(void *, const struct mdoc *)
Line 41  typedef void  (*out_mdoc)(void *, const struct mdoc *)
 typedef void            (*out_man)(void *, const struct man *);  typedef void            (*out_man)(void *, const struct man *);
 typedef void            (*out_free)(void *);  typedef void            (*out_free)(void *);
   
 struct  buf {  enum    outt {
         char             *buf;          OUTT_ASCII = 0, /* -Tascii */
         size_t            sz;          OUTT_TREE,      /* -Ttree */
           OUTT_HTML,      /* -Thtml */
           OUTT_XHTML,     /* -Txhtml */
           OUTT_LINT,      /* -Tlint */
           OUTT_PS,        /* -Tps */
           OUTT_PDF        /* -Tpdf */
 };  };
   
 enum    intt {  struct  curparse {
         INTT_AUTO,          struct mparse    *mp;
         INTT_MDOC,          enum mandoclevel  wlevel;       /* ignore messages below this */
         INTT_MAN          int               wstop;        /* stop after a file with a warning */
           enum outt         outtype;      /* which output to use */
           out_mdoc          outmdoc;      /* mdoc output ptr */
           out_man           outman;       /* man output ptr */
           out_free          outfree;      /* free output ptr */
           void             *outdata;      /* data for output */
           char              outopts[BUFSIZ]; /* buf of output opts */
 };  };
   
 enum    outt {  static  const char * const      mandoclevels[MANDOCLEVEL_MAX] = {
         OUTT_ASCII = 0,          "SUCCESS",
         OUTT_TREE,          "RESERVED",
         OUTT_HTML,          "WARNING",
         OUTT_XHTML,          "ERROR",
         OUTT_LINT          "FATAL",
           "BADARG",
           "SYSERR"
 };  };
   
 struct  curparse {  static  const char * const      mandocerrs[MANDOCERR_MAX] = {
         const char       *file;         /* Current parse. */          "ok",
         int               fd;           /* Current parse. */  
         int               wflags;          "generic warning",
         /* FIXME: set by max error */  
 #define WARN_WALL        (1 << 0)       /* All-warnings mask. */          /* related to the prologue */
 #define WARN_WERR        (1 << 2)       /* Warnings->errors. */          "no title in document",
         int               fflags;          "document title should be all caps",
 #define FL_IGN_SCOPE     (1 << 0)       /* Ignore scope errors. */          "unknown manual section",
 #define FL_NIGN_ESCAPE   (1 << 1)       /* Don't ignore bad escapes. */          "date missing, using today's date",
 #define FL_NIGN_MACRO    (1 << 2)       /* Don't ignore bad macros. */          "cannot parse date, using it verbatim",
 #define FL_IGN_ERRORS    (1 << 4)       /* Ignore failed parse. */          "prologue macros out of order",
 #define FL_STRICT         FL_NIGN_ESCAPE | \          "duplicate prologue macro",
                           FL_NIGN_MACRO          "macro not allowed in prologue",
         enum intt         inttype;      /* Input parsers... */          "macro not allowed in body",
         struct man       *man;  
         struct mdoc      *mdoc;          /* related to document structure */
         struct roff      *roff;          ".so is fragile, better use ln(1)",
         enum outt         outtype;      /* Output devices... */          "NAME section must come first",
         out_mdoc          outmdoc;          "bad NAME section contents",
         out_man           outman;          "manual name not yet set",
         out_free          outfree;          "sections out of conventional order",
         void             *outdata;          "duplicate section name",
         char              outopts[BUFSIZ];          "section not in conventional manual section",
   
           /* related to macros and nesting */
           "skipping obsolete macro",
           "skipping paragraph macro",
           "skipping no-space macro",
           "blocks badly nested",
           "child violates parent syntax",
           "nested displays are not portable",
           "already in literal mode",
   
           /* related to missing macro arguments */
           "skipping empty macro",
           "argument count wrong",
           "missing display type",
           "list type must come first",
           "tag lists require a width argument",
           "missing font type",
           "skipping end of block that is not open",
   
           /* related to bad macro arguments */
           "skipping argument",
           "duplicate argument",
           "duplicate display type",
           "duplicate list type",
           "unknown AT&T UNIX version",
           "bad Boolean value",
           "unknown font",
           "unknown standard specifier",
           "bad width argument",
   
           /* related to plain text */
           "blank line in non-literal context",
           "tab in non-literal context",
           "end of line whitespace",
           "bad comment style",
           "unknown escape sequence",
           "unterminated quoted string",
   
           "generic error",
   
           /* related to tables */
           "bad table syntax",
           "bad table option",
           "bad table layout",
           "no table layout cells specified",
           "no table data cells specified",
           "ignore data in cell",
           "data block still open",
           "ignoring extra data cells",
   
           "input stack limit exceeded, infinite loop?",
           "skipping bad character",
           "escaped character not allowed in a name",
           "skipping text before the first section header",
           "skipping unknown macro",
           "NOT IMPLEMENTED, please use groff: skipping request",
           "line scope broken",
           "argument count wrong",
           "skipping end of block that is not open",
           "missing end of block",
           "scope open on exit",
           "uname(3) system call failed",
           "macro requires line argument(s)",
           "macro requires body argument(s)",
           "macro requires argument(s)",
           "missing list type",
           "line argument(s) will be lost",
           "body argument(s) will be lost",
   
           "generic fatal error",
   
           "column syntax is inconsistent",
           "NOT IMPLEMENTED: .Bd -file",
           "line scope broken, syntax violated",
           "argument count wrong, violates syntax",
           "child violates parent syntax",
           "argument count wrong, violates syntax",
           "NOT IMPLEMENTED: .so with absolute path or \"..\"",
           "no document body",
           "no document prologue",
           "static buffer exhausted",
 };  };
   
 static  void              fdesc(struct curparse *);  static  int               moptions(enum mparset *, char *);
 static  void              ffile(const char *, struct curparse *);  static  void              mmsg(enum mandocerr, enum mandoclevel,
 static  int               foptions(int *, char *);                                  const char *, int, int, const char *);
 static  struct man       *man_init(struct curparse *);  static  void              parse(struct curparse *, int,
 static  struct mdoc      *mdoc_init(struct curparse *);                                  const char *, enum mandoclevel *);
 static  struct roff      *roff_init(struct curparse *);  
 static  int               merr(void *, int, int, const char *); /* DEPRECATED */  
 static  int               moptions(enum intt *, char *);  
 static  int               mwarn(void *, int, int, const char *); /* DEPRECATED */  
 static  int               mmsg(enum mandocerr, void *,  
                                 int, int, const char *);  
 static  int               pset(const char *, int, struct curparse *,  
                                 struct man **, struct mdoc **);  
 static  int               toptions(struct curparse *, char *);  static  int               toptions(struct curparse *, char *);
 static  void              usage(void) __attribute__((noreturn));  static  void              usage(void) __attribute__((noreturn));
 static  void              version(void) __attribute__((noreturn));  static  void              version(void) __attribute__((noreturn));
 static  int               woptions(int *, char *);  static  int               woptions(struct curparse *, char *);
   
 static  const char       *progname;  static  const char       *progname;
 static  int               with_error;  
 static  int               with_warning;  
   
 int  int
 main(int argc, char *argv[])  main(int argc, char *argv[])
 {  {
         int              c;          int              c;
         struct curparse  curp;          struct curparse  curp;
           enum mparset     type;
           enum mandoclevel rc;
   
         progname = strrchr(argv[0], '/');          progname = strrchr(argv[0], '/');
         if (progname == NULL)          if (progname == NULL)
Line 130  main(int argc, char *argv[])
Line 208  main(int argc, char *argv[])
   
         memset(&curp, 0, sizeof(struct curparse));          memset(&curp, 0, sizeof(struct curparse));
   
         curp.inttype = INTT_AUTO;          type = MPARSE_AUTO;
         curp.outtype = OUTT_ASCII;          curp.outtype = OUTT_ASCII;
           curp.wlevel  = MANDOCLEVEL_FATAL;
   
         /* LINTED */          /* LINTED */
         while (-1 != (c = getopt(argc, argv, "f:m:O:T:VW:")))          while (-1 != (c = getopt(argc, argv, "m:O:T:VW:")))
                 switch (c) {                  switch (c) {
                 case ('f'):  
                         if ( ! foptions(&curp.fflags, optarg))  
                                 return(EXIT_FAILURE);  
                         break;  
                 case ('m'):                  case ('m'):
                         if ( ! moptions(&curp.inttype, optarg))                          if ( ! moptions(&type, optarg))
                                 return(EXIT_FAILURE);                                  return((int)MANDOCLEVEL_BADARG);
                         break;                          break;
                 case ('O'):                  case ('O'):
                         (void)strlcat(curp.outopts, optarg, BUFSIZ);                          (void)strlcat(curp.outopts, optarg, BUFSIZ);
Line 150  main(int argc, char *argv[])
Line 225  main(int argc, char *argv[])
                         break;                          break;
                 case ('T'):                  case ('T'):
                         if ( ! toptions(&curp, optarg))                          if ( ! toptions(&curp, optarg))
                                 return(EXIT_FAILURE);                                  return((int)MANDOCLEVEL_BADARG);
                         break;                          break;
                 case ('W'):                  case ('W'):
                         if ( ! woptions(&curp.wflags, optarg))                          if ( ! woptions(&curp, optarg))
                                 return(EXIT_FAILURE);                                  return((int)MANDOCLEVEL_BADARG);
                         break;                          break;
                 case ('V'):                  case ('V'):
                         version();                          version();
Line 164  main(int argc, char *argv[])
Line 239  main(int argc, char *argv[])
                         /* NOTREACHED */                          /* NOTREACHED */
                 }                  }
   
           curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp);
   
         argc -= optind;          argc -= optind;
         argv += optind;          argv += optind;
   
         if (NULL == *argv) {          rc = MANDOCLEVEL_OK;
                 curp.file = "<stdin>";  
                 curp.fd = STDIN_FILENO;  
   
                 fdesc(&curp);          if (NULL == *argv)
         }                  parse(&curp, STDIN_FILENO, "<stdin>", &rc);
   
         while (*argv) {          while (*argv) {
                 ffile(*argv, &curp);                  parse(&curp, -1, *argv, &rc);
                   if (MANDOCLEVEL_OK != rc && curp.wstop)
                 if (with_error && !(curp.fflags & FL_IGN_ERRORS))  
                         break;                          break;
                 ++argv;                  ++argv;
         }          }
   
         if (curp.outfree)          if (curp.outfree)
                 (*curp.outfree)(curp.outdata);                  (*curp.outfree)(curp.outdata);
         if (curp.mdoc)          if (curp.mp)
                 mdoc_free(curp.mdoc);                  mparse_free(curp.mp);
         if (curp.man)  
                 man_free(curp.man);  
         if (curp.roff)  
                 roff_free(curp.roff);  
   
         return((with_warning || with_error) ?          return((int)rc);
                         EXIT_FAILURE :  EXIT_SUCCESS);  
 }  }
   
   
 static void  static void
 version(void)  version(void)
 {  {
   
         (void)printf("%s %s\n", progname, VERSION);          printf("%s %s\n", progname, VERSION);
         exit(EXIT_SUCCESS);          exit((int)MANDOCLEVEL_OK);
 }  }
   
   
 static void  static void
 usage(void)  usage(void)
 {  {
   
         (void)fprintf(stderr, "usage: %s [-V] [-foption] "          fprintf(stderr, "usage: %s "
                         "[-mformat] [-Ooption] [-Toutput] "                          "[-V] "
                         "[-Werr] [file...]\n", progname);                          "[-foption] "
         exit(EXIT_FAILURE);                          "[-mformat] "
 }                          "[-Ooption] "
                           "[-Toutput] "
                           "[-Werr] "
                           "[file...]\n",
                           progname);
   
           exit((int)MANDOCLEVEL_BADARG);
 static struct man *  
 man_init(struct curparse *curp)  
 {  
         int              pflags;  
         struct man_cb    mancb;  
   
         mancb.man_err = merr;  
         mancb.man_warn = mwarn;  
   
         /* Defaults from mandoc.1. */  
   
         pflags = MAN_IGN_MACRO | MAN_IGN_ESCAPE;  
   
         if (curp->fflags & FL_NIGN_MACRO)  
                 pflags &= ~MAN_IGN_MACRO;  
         if (curp->fflags & FL_NIGN_ESCAPE)  
                 pflags &= ~MAN_IGN_ESCAPE;  
   
         return(man_alloc(curp, pflags, &mancb));  
 }  }
   
   
 static struct roff *  
 roff_init(struct curparse *curp)  
 {  
   
         return(roff_alloc(mmsg, curp));  
 }  
   
   
 static struct mdoc *  
 mdoc_init(struct curparse *curp)  
 {  
         int              pflags;  
         struct mdoc_cb   mdoccb;  
   
         mdoccb.mdoc_err = merr;  
         mdoccb.mdoc_warn = mwarn;  
   
         /* Defaults from mandoc.1. */  
   
         pflags = MDOC_IGN_MACRO | MDOC_IGN_ESCAPE;  
   
         if (curp->fflags & FL_IGN_SCOPE)  
                 pflags |= MDOC_IGN_SCOPE;  
         if (curp->fflags & FL_NIGN_ESCAPE)  
                 pflags &= ~MDOC_IGN_ESCAPE;  
         if (curp->fflags & FL_NIGN_MACRO)  
                 pflags &= ~MDOC_IGN_MACRO;  
   
         return(mdoc_alloc(curp, pflags, &mdoccb));  
 }  
   
   
 static void  static void
 ffile(const char *file, struct curparse *curp)  parse(struct curparse *curp, int fd,
                   const char *file, enum mandoclevel *level)
 {  {
           enum mandoclevel  rc;
           struct mdoc      *mdoc;
           struct man       *man;
   
         curp->file = file;          /* Begin by parsing the file itself. */
         if (-1 == (curp->fd = open(curp->file, O_RDONLY, 0))) {  
                 perror(curp->file);  
                 with_error = 1;  
                 return;  
         }  
   
         fdesc(curp);          assert(file);
           assert(fd >= -1);
   
         if (-1 == close(curp->fd))          rc = mparse_readfd(curp->mp, fd, file);
                 perror(curp->file);  
 }  
   
           /* Stop immediately if the parse has failed. */
   
 static int          if (MANDOCLEVEL_FATAL <= rc)
 resize_buf(struct buf *buf, size_t initial)                  goto cleanup;
 {  
         void *tmp;  
         size_t sz;  
   
         if (buf->sz == 0)  
                 sz = initial;  
         else  
                 sz = 2 * buf->sz;  
         tmp = realloc(buf->buf, sz);  
         if (NULL == tmp) {  
                 perror(NULL);  
                 return(0);  
         }  
         buf->buf = tmp;  
         buf->sz = sz;  
         return(1);  
 }  
   
   
 static int  
 read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap)  
 {  
         struct stat      st;  
         size_t           off;  
         ssize_t          ssz;  
   
         if (-1 == fstat(curp->fd, &st)) {  
                 perror(curp->file);  
                 with_error = 1;  
                 return(0);  
         }  
   
         /*          /*
          * If we're a regular file, try just reading in the whole entry           * With -Wstop and warnings or errors of at least the requested
          * via mmap().  This is faster than reading it into blocks, and           * level, do not produce output.
          * since each file is only a few bytes to begin with, I'm not  
          * concerned that this is going to tank any machines.  
          */           */
   
         if (S_ISREG(st.st_mode)) {          if (MANDOCLEVEL_OK != rc && curp->wstop)
                 if (st.st_size >= (1U << 31)) {                  goto cleanup;
                         fprintf(stderr, "%s: input too large\n",  
                                         curp->file);  
                         with_error = 1;  
                         return(0);  
                 }  
                 *with_mmap = 1;  
                 fb->sz = (size_t)st.st_size;  
                 fb->buf = mmap(NULL, fb->sz, PROT_READ,  
                                 MAP_FILE, curp->fd, 0);  
                 if (fb->buf != MAP_FAILED)  
                         return(1);  
         }  
   
         /*  
          * If this isn't a regular file (like, say, stdin), then we must  
          * go the old way and just read things in bit by bit.  
          */  
   
         *with_mmap = 0;  
         off = 0;  
         fb->sz = 0;  
         fb->buf = NULL;  
         for (;;) {  
                 if (off == fb->sz) {  
                         if (fb->sz == (1U << 31)) {  
                                 fprintf(stderr, "%s: input too large\n",  
                                                 curp->file);  
                                 break;  
                         }  
                         if (! resize_buf(fb, 65536))  
                                 break;  
                 }  
                 ssz = read(curp->fd, fb->buf + (int)off, fb->sz - off);  
                 if (ssz == 0) {  
                         fb->sz = off;  
                         return(1);  
                 }  
                 if (ssz == -1) {  
                         perror(curp->file);  
                         break;  
                 }  
                 off += (size_t)ssz;  
         }  
   
         free(fb->buf);  
         fb->buf = NULL;  
         with_error = 1;  
         return(0);  
 }  
   
   
 static void  
 fdesc(struct curparse *curp)  
 {  
         struct buf       ln, blk;  
         int              i, pos, lnn, lnn_start, with_mmap, of;  
         enum rofferr     re;  
         struct man      *man;  
         struct mdoc     *mdoc;  
         struct roff     *roff;  
   
         man = NULL;  
         mdoc = NULL;  
         roff = NULL;  
         memset(&ln, 0, sizeof(struct buf));  
   
         /*  
          * Two buffers: ln and buf.  buf is the input file and may be  
          * memory mapped.  ln is a line buffer and grows on-demand.  
          */  
   
         if ( ! read_whole_file(curp, &blk, &with_mmap))  
                 return;  
   
         if (NULL == curp->roff)  
                 curp->roff = roff_init(curp);  
         if (NULL == (roff = curp->roff))  
                 goto bailout;  
   
         for (i = 0, lnn = 1; i < (int)blk.sz;) {  
                 pos = 0;  
                 lnn_start = lnn;  
                 while (i < (int)blk.sz) {  
                         if ('\n' == blk.buf[i]) {  
                                 ++i;  
                                 ++lnn;  
                                 break;  
                         }  
                         /* Trailing backslash is like a plain character. */  
                         if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {  
                                 if (pos >= (int)ln.sz)  
                                         if (! resize_buf(&ln, 256))  
                                                 goto bailout;  
                                 ln.buf[pos++] = blk.buf[i++];  
                                 continue;  
                         }  
                         /* Found an escape and at least one other character. */  
                         if ('\n' == blk.buf[i + 1]) {  
                                 /* Escaped newlines are skipped over */  
                                 i += 2;  
                                 ++lnn;  
                                 continue;  
                         }  
                         if ('"' == blk.buf[i + 1]) {  
                                 i += 2;  
                                 /* Comment, skip to end of line */  
                                 for (; i < (int)blk.sz; ++i) {  
                                         if ('\n' == blk.buf[i]) {  
                                                 ++i;  
                                                 ++lnn;  
                                                 break;  
                                         }  
                                 }  
                                 /* Backout trailing whitespaces */  
                                 for (; pos > 0; --pos) {  
                                         if (ln.buf[pos - 1] != ' ')  
                                                 break;  
                                         if (pos > 2 && ln.buf[pos - 2] == '\\')  
                                                 break;  
                                 }  
                                 break;  
                         }  
                         /* Some other escape sequence, copy and continue. */  
                         if (pos + 1 >= (int)ln.sz)  
                                 if (! resize_buf(&ln, 256))  
                                         goto bailout;  
   
                         ln.buf[pos++] = blk.buf[i++];  
                         ln.buf[pos++] = blk.buf[i++];  
                 }  
   
                 if (pos >= (int)ln.sz)  
                         if (! resize_buf(&ln, 256))  
                                 goto bailout;  
                 ln.buf[pos] = '\0';  
   
                 /*  
                  * A significant amount of complexity is contained by  
                  * the roff preprocessor.  It's line-oriented but can be  
                  * expressed on one line, so we need at times to  
                  * readjust our starting point and re-run it.  The roff  
                  * preprocessor can also readjust the buffers with new  
                  * data, so we pass them in wholesale.  
                  */  
   
                 of = 0;  
                 do {  
                         re = roff_parseln(roff, lnn_start,  
                                         &ln.buf, &ln.sz, of, &of);  
                 } while (ROFF_RERUN == re);  
   
                 if (ROFF_IGN == re)  
                         continue;  
                 else if (ROFF_ERR == re)  
                         goto bailout;  
   
                 /*  
                  * If input parsers have not been allocated, do so now.  
                  * We keep these instanced betwen parsers, but set them  
                  * locally per parse routine since we can use different  
                  * parsers with each one.  
                  */  
   
                 if ( ! (man || mdoc))  
                         if ( ! pset(ln.buf + of, pos - of, curp, &man, &mdoc))  
                                 goto bailout;  
   
                 /* Lastly, push down into the parsers themselves. */  
   
                 if (man && ! man_parseln(man, lnn_start, ln.buf, of))  
                         goto bailout;  
                 if (mdoc && ! mdoc_parseln(mdoc, lnn_start, ln.buf, of))  
                         goto bailout;  
         }  
   
         /* NOTE a parser may not have been assigned, yet. */  
   
         if ( ! (man || mdoc)) {  
                 fprintf(stderr, "%s: Not a manual\n", curp->file);  
                 goto bailout;  
         }  
   
         /* Clean up the parse routine ASTs. */  
   
         if (mdoc && ! mdoc_endparse(mdoc))  
                 goto bailout;  
         if (man && ! man_endparse(man))  
                 goto bailout;  
         if (roff && ! roff_endparse(roff))  
                 goto bailout;  
   
         /* If unset, allocate output dev now (if applicable). */          /* If unset, allocate output dev now (if applicable). */
   
         if ( ! (curp->outman && curp->outmdoc)) {          if ( ! (curp->outman && curp->outmdoc)) {
                 switch (curp->outtype) {                  switch (curp->outtype) {
                 case (OUTT_XHTML):                  case (OUTT_XHTML):
                         curp->outdata = xhtml_alloc(curp->outopts);                          curp->outdata = xhtml_alloc(curp->outopts);
                         curp->outman = html_man;  
                         curp->outmdoc = html_mdoc;  
                         curp->outfree = html_free;  
                         break;                          break;
                 case (OUTT_HTML):                  case (OUTT_HTML):
                         curp->outdata = html_alloc(curp->outopts);                          curp->outdata = html_alloc(curp->outopts);
                           break;
                   case (OUTT_ASCII):
                           curp->outdata = ascii_alloc(curp->outopts);
                           curp->outfree = ascii_free;
                           break;
                   case (OUTT_PDF):
                           curp->outdata = pdf_alloc(curp->outopts);
                           curp->outfree = pspdf_free;
                           break;
                   case (OUTT_PS):
                           curp->outdata = ps_alloc(curp->outopts);
                           curp->outfree = pspdf_free;
                           break;
                   default:
                           break;
                   }
   
                   switch (curp->outtype) {
                   case (OUTT_HTML):
                           /* FALLTHROUGH */
                   case (OUTT_XHTML):
                         curp->outman = html_man;                          curp->outman = html_man;
                         curp->outmdoc = html_mdoc;                          curp->outmdoc = html_mdoc;
                         curp->outfree = html_free;                          curp->outfree = html_free;
Line 542  fdesc(struct curparse *curp)
Line 355  fdesc(struct curparse *curp)
                         curp->outman = tree_man;                          curp->outman = tree_man;
                         curp->outmdoc = tree_mdoc;                          curp->outmdoc = tree_mdoc;
                         break;                          break;
                 case (OUTT_LINT):                  case (OUTT_PDF):
                         break;                          /* FALLTHROUGH */
                 default:                  case (OUTT_ASCII):
                         curp->outdata = ascii_alloc(80);                          /* FALLTHROUGH */
                   case (OUTT_PS):
                         curp->outman = terminal_man;                          curp->outman = terminal_man;
                         curp->outmdoc = terminal_mdoc;                          curp->outmdoc = terminal_mdoc;
                         curp->outfree = terminal_free;  
                         break;                          break;
                   default:
                           break;
                 }                  }
         }          }
   
           mparse_result(curp->mp, &mdoc, &man);
   
         /* Execute the out device, if it exists. */          /* Execute the out device, if it exists. */
   
         if (man && curp->outman)          if (man && curp->outman)
Line 561  fdesc(struct curparse *curp)
Line 378  fdesc(struct curparse *curp)
                 (*curp->outmdoc)(curp->outdata, mdoc);                  (*curp->outmdoc)(curp->outdata, mdoc);
   
  cleanup:   cleanup:
         if (mdoc)  
                 mdoc_reset(mdoc);  
         if (man)  
                 man_reset(man);  
         if (roff)  
                 roff_reset(roff);  
         if (ln.buf)  
                 free(ln.buf);  
         if (with_mmap)  
                 munmap(blk.buf, blk.sz);  
         else  
                 free(blk.buf);  
   
         return;          mparse_reset(curp->mp);
   
  bailout:          if (*level < rc)
         with_error = 1;                  *level = rc;
         goto cleanup;  
 }  }
   
   
 static int  static int
 pset(const char *buf, int pos, struct curparse *curp,  moptions(enum mparset *tflags, char *arg)
                 struct man **man, struct mdoc **mdoc)  
 {  {
         int              i;  
   
         /*  
          * Try to intuit which kind of manual parser should be used.  If  
          * passed in by command-line (-man, -mdoc), then use that  
          * explicitly.  If passed as -mandoc, then try to guess from the  
          * line: either skip dot-lines, use -mdoc when finding `.Dt', or  
          * default to -man, which is more lenient.  
          */  
   
         if ('.' == buf[0] || '\'' == buf[0]) {  
                 for (i = 1; buf[i]; i++)  
                         if (' ' != buf[i] && '\t' != buf[i])  
                                 break;  
                 if (0 == buf[i])  
                         return(1);  
         }  
   
         switch (curp->inttype) {  
         case (INTT_MDOC):  
                 if (NULL == curp->mdoc)  
                         curp->mdoc = mdoc_init(curp);  
                 if (NULL == (*mdoc = curp->mdoc))  
                         return(0);  
                 return(1);  
         case (INTT_MAN):  
                 if (NULL == curp->man)  
                         curp->man = man_init(curp);  
                 if (NULL == (*man = curp->man))  
                         return(0);  
                 return(1);  
         default:  
                 break;  
         }  
   
         if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3))  {  
                 if (NULL == curp->mdoc)  
                         curp->mdoc = mdoc_init(curp);  
                 if (NULL == (*mdoc = curp->mdoc))  
                         return(0);  
                 return(1);  
         }  
   
         if (NULL == curp->man)  
                 curp->man = man_init(curp);  
         if (NULL == (*man = curp->man))  
                 return(0);  
         return(1);  
 }  
   
   
 static int  
 moptions(enum intt *tflags, char *arg)  
 {  
   
         if (0 == strcmp(arg, "doc"))          if (0 == strcmp(arg, "doc"))
                 *tflags = INTT_MDOC;                  *tflags = MPARSE_MDOC;
         else if (0 == strcmp(arg, "andoc"))          else if (0 == strcmp(arg, "andoc"))
                 *tflags = INTT_AUTO;                  *tflags = MPARSE_AUTO;
         else if (0 == strcmp(arg, "an"))          else if (0 == strcmp(arg, "an"))
                 *tflags = INTT_MAN;                  *tflags = MPARSE_MAN;
         else {          else {
                 fprintf(stderr, "%s: Bad argument\n", arg);                  fprintf(stderr, "%s: Bad argument\n", arg);
                 return(0);                  return(0);
Line 655  moptions(enum intt *tflags, char *arg)
Line 403  moptions(enum intt *tflags, char *arg)
         return(1);          return(1);
 }  }
   
   
 static int  static int
 toptions(struct curparse *curp, char *arg)  toptions(struct curparse *curp, char *arg)
 {  {
Line 664  toptions(struct curparse *curp, char *arg)
Line 411  toptions(struct curparse *curp, char *arg)
                 curp->outtype = OUTT_ASCII;                  curp->outtype = OUTT_ASCII;
         else if (0 == strcmp(arg, "lint")) {          else if (0 == strcmp(arg, "lint")) {
                 curp->outtype = OUTT_LINT;                  curp->outtype = OUTT_LINT;
                 curp->wflags |= WARN_WALL;                  curp->wlevel  = MANDOCLEVEL_WARNING;
                 curp->fflags |= FL_STRICT;          } else if (0 == strcmp(arg, "tree"))
         }  
         else if (0 == strcmp(arg, "tree"))  
                 curp->outtype = OUTT_TREE;                  curp->outtype = OUTT_TREE;
         else if (0 == strcmp(arg, "html"))          else if (0 == strcmp(arg, "html"))
                 curp->outtype = OUTT_HTML;                  curp->outtype = OUTT_HTML;
         else if (0 == strcmp(arg, "xhtml"))          else if (0 == strcmp(arg, "xhtml"))
                 curp->outtype = OUTT_XHTML;                  curp->outtype = OUTT_XHTML;
           else if (0 == strcmp(arg, "ps"))
                   curp->outtype = OUTT_PS;
           else if (0 == strcmp(arg, "pdf"))
                   curp->outtype = OUTT_PDF;
         else {          else {
                 fprintf(stderr, "%s: Bad argument\n", arg);                  fprintf(stderr, "%s: Bad argument\n", arg);
                 return(0);                  return(0);
Line 681  toptions(struct curparse *curp, char *arg)
Line 430  toptions(struct curparse *curp, char *arg)
         return(1);          return(1);
 }  }
   
   
 static int  static int
 foptions(int *fflags, char *arg)  woptions(struct curparse *curp, char *arg)
 {  {
         char            *v, *o;          char            *v, *o;
         const char      *toks[8];          const char      *toks[6];
   
         toks[0] = "ign-scope";          toks[0] = "stop";
         toks[1] = "no-ign-escape";          toks[1] = "all";
         toks[2] = "no-ign-macro";          toks[2] = "warning";
         toks[3] = "ign-errors";          toks[3] = "error";
         toks[4] = "strict";          toks[4] = "fatal";
         toks[5] = "ign-escape";          toks[5] = NULL;
         toks[6] = NULL;  
   
         while (*arg) {          while (*arg) {
                 o = arg;                  o = arg;
                 switch (getsubopt(&arg, UNCONST(toks), &v)) {                  switch (getsubopt(&arg, UNCONST(toks), &v)) {
                 case (0):                  case (0):
                         *fflags |= FL_IGN_SCOPE;                          curp->wstop = 1;
                         break;                          break;
                 case (1):                  case (1):
                         *fflags |= FL_NIGN_ESCAPE;                          /* FALLTHROUGH */
                         break;  
                 case (2):                  case (2):
                         *fflags |= FL_NIGN_MACRO;                          curp->wlevel = MANDOCLEVEL_WARNING;
                         break;                          break;
                 case (3):                  case (3):
                         *fflags |= FL_IGN_ERRORS;                          curp->wlevel = MANDOCLEVEL_ERROR;
                         break;                          break;
                 case (4):                  case (4):
                         *fflags |= FL_STRICT;                          curp->wlevel = MANDOCLEVEL_FATAL;
                         break;                          break;
                 case (5):  
                         *fflags &= ~FL_NIGN_ESCAPE;  
                         break;  
                 default:                  default:
                         fprintf(stderr, "%s: Bad argument\n", o);                          fprintf(stderr, "-W%s: Bad argument\n", o);
                         return(0);                          return(0);
                 }                  }
         }          }
Line 726  foptions(int *fflags, char *arg)
Line 469  foptions(int *fflags, char *arg)
         return(1);          return(1);
 }  }
   
   static void
 static int  mmsg(enum mandocerr t, enum mandoclevel lvl,
 woptions(int *wflags, char *arg)                  const char *file, int line, int col, const char *msg)
 {  {
         char            *v, *o;  
         const char      *toks[3];  
   
         toks[0] = "all";          fprintf(stderr, "%s:%d:%d: %s: %s",
         toks[1] = "error";                          file, line, col + 1,
         toks[2] = NULL;                          mandoclevels[lvl], mandocerrs[t]);
   
         while (*arg) {  
                 o = arg;  
                 switch (getsubopt(&arg, UNCONST(toks), &v)) {  
                 case (0):  
                         *wflags |= WARN_WALL;  
                         break;  
                 case (1):  
                         *wflags |= WARN_WERR;  
                         break;  
                 default:  
                         fprintf(stderr, "%s: Bad argument\n", o);  
                         return(0);  
                 }  
         }  
   
         return(1);  
 }  
   
   
 /* ARGSUSED */  
 static int  
 merr(void *arg, int line, int col, const char *msg)  
 {  
         struct curparse *curp;  
   
         curp = (struct curparse *)arg;  
   
         (void)fprintf(stderr, "%s:%d:%d: error: %s\n",  
                         curp->file, line, col + 1, msg);  
   
         with_error = 1;  
   
         return(0);  
 }  
   
   
 static int  
 mwarn(void *arg, int line, int col, const char *msg)  
 {  
         struct curparse *curp;  
   
         curp = (struct curparse *)arg;  
   
         if ( ! (curp->wflags & WARN_WALL))  
                 return(1);  
   
         (void)fprintf(stderr, "%s:%d:%d: warning: %s\n",  
                         curp->file, line, col + 1, msg);  
   
         with_warning = 1;  
         if (curp->wflags & WARN_WERR) {  
                 with_error = 1;  
                 return(0);  
         }  
   
         return(1);  
 }  
   
 static  const char * const      mandocerrs[MANDOCERR_MAX] = {  
         "ok",  
         "multi-line scope open on exit",  
         "request for scope closure when no matching scope is open",  
         "line arguments will be lost",  
         "memory exhausted"  
 };  
   
 /*  
  * XXX: this is experimental code that will eventually become the  
  * generic means of covering all warnings and errors!  
  */  
 /* ARGSUSED */  
 static int  
 mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg)  
 {  
 #if 0  
         struct curparse *cp;  
   
         cp = (struct curparse *)arg;  
   
         fprintf(stderr, "%s:%d:%d: %s", cp->file,  
                         ln, col + 1, mandocerrs[t]);  
   
         if (msg)          if (msg)
                 fprintf(stderr, ": %s", msg);                  fprintf(stderr, ": %s", msg);
   
         fputc('\n', stderr);          fputc('\n', stderr);
 #endif  
         return(1);  
 }  }

Legend:
Removed from v.1.76  
changed lines
  Added in v.1.157

CVSweb