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

Diff for /mandoc/main.c between version 1.127 and 1.152

version 1.127, 2010/12/29 14:38:14 version 1.152, 2011/03/17 08:49:34
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>   * 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 42 
Line 42 
 #endif  #endif
   
 #define REPARSE_LIMIT   1000  #define REPARSE_LIMIT   1000
 #define UNCONST(a)      ((void *)(uintptr_t)(const void *)(a))  
   
 /* FIXME: Intel's compiler?  LLVM?  pcc?  */  /* FIXME: Intel's compiler?  LLVM?  pcc?  */
   
Line 78  enum outt {
Line 77  enum outt {
 };  };
   
 struct  curparse {  struct  curparse {
         const char       *file;         /* Current parse. */          enum mandoclevel  exit_status;  /* status of all file parses */
         int               fd;           /* Current parse. */          const char       *file;         /* current file-name */
         int               line;         /* Line number in the file. */          enum mandoclevel  file_status;  /* error status of current parse */
         enum mandoclevel  wlevel;       /* Ignore messages below this. */          int               fd;           /* current file-descriptor */
         int               wstop;        /* Stop after a file with a warning. */          int               line;         /* line number in the file */
           enum mandoclevel  wlevel;       /* ignore messages below this */
           int               wstop;        /* stop after a file with a warning */
         enum intt         inttype;      /* which parser to use */          enum intt         inttype;      /* which parser to use */
         struct man       *pman;         /* persistent man parser */          struct man       *pman;         /* persistent man parser */
         struct mdoc      *pmdoc;        /* persistent mdoc parser */          struct mdoc      *pmdoc;        /* persistent mdoc parser */
Line 128  static const char * const mandocerrs[MANDOCERR_MAX] = 
Line 129  static const char * const mandocerrs[MANDOCERR_MAX] = 
         "no title in document",          "no title in document",
         "document title should be all caps",          "document title should be all caps",
         "unknown manual section",          "unknown manual section",
         "cannot parse date argument",          "date missing, using today's date",
           "cannot parse date, using it verbatim",
         "prologue macros out of order",          "prologue macros out of order",
         "duplicate prologue macro",          "duplicate prologue macro",
         "macro not allowed in prologue",          "macro not allowed in prologue",
Line 146  static const char * const mandocerrs[MANDOCERR_MAX] = 
Line 148  static const char * const mandocerrs[MANDOCERR_MAX] = 
         /* related to macros and nesting */          /* related to macros and nesting */
         "skipping obsolete macro",          "skipping obsolete macro",
         "skipping paragraph macro",          "skipping paragraph macro",
           "skipping no-space macro",
         "blocks badly nested",          "blocks badly nested",
         "child violates parent syntax",          "child violates parent syntax",
         "nested displays are not portable",          "nested displays are not portable",
Line 153  static const char * const mandocerrs[MANDOCERR_MAX] = 
Line 156  static const char * const mandocerrs[MANDOCERR_MAX] = 
   
         /* related to missing macro arguments */          /* related to missing macro arguments */
         "skipping empty macro",          "skipping empty macro",
           "argument count wrong",
         "missing display type",          "missing display type",
         "list type must come first",          "list type must come first",
         "tag lists require a width argument",          "tag lists require a width argument",
         "missing font type",          "missing font type",
           "skipping end of block that is not open",
   
         /* related to bad macro arguments */          /* related to bad macro arguments */
         "skipping argument",          "skipping argument",
Line 176  static const char * const mandocerrs[MANDOCERR_MAX] = 
Line 181  static const char * const mandocerrs[MANDOCERR_MAX] = 
         "bad comment style",          "bad comment style",
         "unknown escape sequence",          "unknown escape sequence",
         "unterminated quoted string",          "unterminated quoted string",
   
         "generic error",          "generic error",
   
           /* related to tables */
         "bad table syntax",          "bad table syntax",
         "bad table option",          "bad table option",
         "bad table layout",          "bad table layout",
         "no table layout cells specified",          "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?",          "input stack limit exceeded, infinite loop?",
         "skipping bad character",          "skipping bad character",
           "escaped character not allowed in a name",
         "skipping text before the first section header",          "skipping text before the first section header",
         "skipping unknown macro",          "skipping unknown macro",
         "NOT IMPLEMENTED: skipping request",          "NOT IMPLEMENTED, please use groff: skipping request",
         "line scope broken",          "line scope broken",
         "argument count wrong",          "argument count wrong",
         "skipping end of block that is not open",          "skipping end of block that is not open",
Line 230  static void    version(void) __attribute__((noreturn))
Line 242  static void    version(void) __attribute__((noreturn))
 static  int               woptions(struct curparse *, char *);  static  int               woptions(struct curparse *, char *);
   
 static  const char       *progname;  static  const char       *progname;
 static  enum mandoclevel  file_status = MANDOCLEVEL_OK;  
 static  enum mandoclevel  exit_status = MANDOCLEVEL_OK;  
   
 int  int
 main(int argc, char *argv[])  main(int argc, char *argv[])
Line 250  main(int argc, char *argv[])
Line 260  main(int argc, char *argv[])
         curp.inttype = INTT_AUTO;          curp.inttype = INTT_AUTO;
         curp.outtype = OUTT_ASCII;          curp.outtype = OUTT_ASCII;
         curp.wlevel  = MANDOCLEVEL_FATAL;          curp.wlevel  = MANDOCLEVEL_FATAL;
           curp.exit_status = MANDOCLEVEL_OK;
   
         /* LINTED */          /* LINTED */
         while (-1 != (c = getopt(argc, argv, "m:O:T:VW:")))          while (-1 != (c = getopt(argc, argv, "m:O:T:VW:")))
Line 290  main(int argc, char *argv[])
Line 301  main(int argc, char *argv[])
   
         while (*argv) {          while (*argv) {
                 ffile(*argv, &curp);                  ffile(*argv, &curp);
                 if (MANDOCLEVEL_OK != exit_status && curp.wstop)                  if (MANDOCLEVEL_OK != curp.exit_status && curp.wstop)
                         break;                          break;
                 ++argv;                  ++argv;
         }          }
Line 304  main(int argc, char *argv[])
Line 315  main(int argc, char *argv[])
         if (curp.roff)          if (curp.roff)
                 roff_free(curp.roff);                  roff_free(curp.roff);
   
         return((int)exit_status);          return((int)curp.exit_status);
 }  }
   
   
Line 349  ffile(const char *file, struct curparse *curp)
Line 360  ffile(const char *file, struct curparse *curp)
   
         if (-1 == (curp->fd = open(curp->file, O_RDONLY, 0))) {          if (-1 == (curp->fd = open(curp->file, O_RDONLY, 0))) {
                 perror(curp->file);                  perror(curp->file);
                 exit_status = MANDOCLEVEL_SYSERR;                  curp->exit_status = MANDOCLEVEL_SYSERR;
                 return;                  return;
         }          }
   
Line 367  pfile(const char *file, struct curparse *curp)
Line 378  pfile(const char *file, struct curparse *curp)
   
         if (-1 == (fd = open(file, O_RDONLY, 0))) {          if (-1 == (fd = open(file, O_RDONLY, 0))) {
                 perror(file);                  perror(file);
                 file_status = MANDOCLEVEL_SYSERR;                  curp->file_status = MANDOCLEVEL_SYSERR;
                 return(0);                  return(0);
         }          }
   
Line 385  pfile(const char *file, struct curparse *curp)
Line 396  pfile(const char *file, struct curparse *curp)
         if (-1 == close(fd))          if (-1 == close(fd))
                 perror(file);                  perror(file);
   
         return(MANDOCLEVEL_FATAL > file_status ? 1 : 0);          return(MANDOCLEVEL_FATAL > curp->file_status ? 1 : 0);
 }  }
   
   
Line 394  resize_buf(struct buf *buf, size_t initial)
Line 405  resize_buf(struct buf *buf, size_t initial)
 {  {
   
         buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;          buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial;
         buf->buf = realloc(buf->buf, buf->sz);          buf->buf = mandoc_realloc(buf->buf, buf->sz);
         if (NULL == buf->buf) {  
                 perror(NULL);  
                 exit((int)MANDOCLEVEL_SYSERR);  
         }  
 }  }
   
   
Line 489  fdesc(struct curparse *curp)
Line 496  fdesc(struct curparse *curp)
   
         curp->mdoc = NULL;          curp->mdoc = NULL;
         curp->man = NULL;          curp->man = NULL;
         file_status = MANDOCLEVEL_OK;          curp->file_status = MANDOCLEVEL_OK;
   
         /* Make sure the mandotory roff parser is initialised. */          /* Make sure the mandotory roff parser is initialised. */
   
Line 502  fdesc(struct curparse *curp)
Line 509  fdesc(struct curparse *curp)
   
         pdesc(curp);          pdesc(curp);
   
         if (MANDOCLEVEL_FATAL <= file_status)          if (MANDOCLEVEL_FATAL <= curp->file_status)
                 goto cleanup;                  goto cleanup;
   
         /* NOTE a parser may not have been assigned, yet. */          /* NOTE a parser may not have been assigned, yet. */
   
         if ( ! (curp->man || curp->mdoc)) {          if ( ! (curp->man || curp->mdoc)) {
                 fprintf(stderr, "%s: Not a manual\n", curp->file);                  fprintf(stderr, "%s: Not a manual\n", curp->file);
                 file_status = MANDOCLEVEL_FATAL;                  curp->file_status = MANDOCLEVEL_FATAL;
                 goto cleanup;                  goto cleanup;
         }          }
   
         /* Clean up the parse routine ASTs. */          /* Clean up the parse routine ASTs. */
   
         if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {          if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
                 assert(MANDOCLEVEL_FATAL <= file_status);                  assert(MANDOCLEVEL_FATAL <= curp->file_status);
                 goto cleanup;                  goto cleanup;
         }          }
   
         if (curp->man && ! man_endparse(curp->man)) {          if (curp->man && ! man_endparse(curp->man)) {
                 assert(MANDOCLEVEL_FATAL <= file_status);                  assert(MANDOCLEVEL_FATAL <= curp->file_status);
                 goto cleanup;                  goto cleanup;
         }          }
   
         assert(curp->roff);          assert(curp->roff);
         if ( ! roff_endparse(curp->roff)) {          roff_endparse(curp->roff);
                 assert(MANDOCLEVEL_FATAL <= file_status);  
                 goto cleanup;  
         }  
   
         /*          /*
          * With -Wstop and warnings or errors of at least           * With -Wstop and warnings or errors of at least
          * the requested level, do not produce output.           * the requested level, do not produce output.
          */           */
   
         if (MANDOCLEVEL_OK != file_status && curp->wstop)          if (MANDOCLEVEL_OK != curp->file_status && curp->wstop)
                 goto cleanup;                  goto cleanup;
   
         /* If unset, allocate output dev now (if applicable). */          /* If unset, allocate output dev now (if applicable). */
Line 611  fdesc(struct curparse *curp)
Line 615  fdesc(struct curparse *curp)
         assert(curp->roff);          assert(curp->roff);
         roff_reset(curp->roff);          roff_reset(curp->roff);
   
         if (exit_status < file_status)          if (curp->exit_status < curp->file_status)
                 exit_status = file_status;                  curp->exit_status = curp->file_status;
   
         return;          return;
 }  }
Line 631  pdesc(struct curparse *curp)
Line 635  pdesc(struct curparse *curp)
          */           */
   
         if ( ! read_whole_file(curp, &blk, &with_mmap)) {          if ( ! read_whole_file(curp, &blk, &with_mmap)) {
                 file_status = MANDOCLEVEL_SYSERR;                  curp->file_status = MANDOCLEVEL_SYSERR;
                 return;                  return;
         }          }
   
Line 647  pdesc(struct curparse *curp)
Line 651  pdesc(struct curparse *curp)
                 free(blk.buf);                  free(blk.buf);
 }  }
   
   /*
    * Main parse routine for an opened file.  This is called for each
    * opened file and simply loops around the full input file, possibly
    * nesting (i.e., with `so').
    */
 static void  static void
 parsebuf(struct curparse *curp, struct buf blk, int start)  parsebuf(struct curparse *curp, struct buf blk, int start)
 {  {
           const struct tbl_span   *span;
         struct buf       ln;          struct buf       ln;
         enum rofferr     rr;          enum rofferr     rr;
         int              i, of, rc;          int              i, of, rc;
Line 657  parsebuf(struct curparse *curp, struct buf blk, int st
Line 667  parsebuf(struct curparse *curp, struct buf blk, int st
         int              lnn; /* line number in the real file */          int              lnn; /* line number in the real file */
         unsigned char    c;          unsigned char    c;
   
         /*  
          * Main parse routine for an opened file.  This is called for  
          * each opened file and simply loops around the full input file,  
          * possibly nesting (i.e., with `so').  
          */  
   
         memset(&ln, 0, sizeof(struct buf));          memset(&ln, 0, sizeof(struct buf));
   
         lnn = curp->line;          lnn = curp->line;
Line 678  parsebuf(struct curparse *curp, struct buf blk, int st
Line 682  parsebuf(struct curparse *curp, struct buf blk, int st
                 }                  }
   
                 while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {                  while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
   
                           /*
                            * When finding an unescaped newline character,
                            * leave the character loop to process the line.
                            * Skip a preceding carriage return, if any.
                            */
   
                           if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz &&
                               '\n' == blk.buf[i + 1])
                                   ++i;
                         if ('\n' == blk.buf[i]) {                          if ('\n' == blk.buf[i]) {
                                 ++i;                                  ++i;
                                 ++lnn;                                  ++lnn;
Line 712  parsebuf(struct curparse *curp, struct buf blk, int st
Line 726  parsebuf(struct curparse *curp, struct buf blk, int st
                                 continue;                                  continue;
                         }                          }
   
                         /* Found escape & at least one other char. */                          /*
                            * Found escape and at least one other character.
                            * When it's a newline character, skip it.
                            * When there is a carriage return in between,
                            * skip that one as well.
                            */
   
                           if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz &&
                               '\n' == blk.buf[i + 2])
                                   ++i;
                         if ('\n' == blk.buf[i + 1]) {                          if ('\n' == blk.buf[i + 1]) {
                                 i += 2;                                  i += 2;
                                 /* Escaped newlines are skipped over */  
                                 ++lnn;                                  ++lnn;
                                 continue;                                  continue;
                         }                          }
Line 782  rerun:
Line 803  rerun:
                         pos = 0;                          pos = 0;
                         continue;                          continue;
                 case (ROFF_APPEND):                  case (ROFF_APPEND):
                         pos = strlen(ln.buf);                          pos = (int)strlen(ln.buf);
                         continue;                          continue;
                 case (ROFF_RERUN):                  case (ROFF_RERUN):
                         goto rerun;                          goto rerun;
Line 790  rerun:
Line 811  rerun:
                         pos = 0;                          pos = 0;
                         continue;                          continue;
                 case (ROFF_ERR):                  case (ROFF_ERR):
                         assert(MANDOCLEVEL_FATAL <= file_status);                          assert(MANDOCLEVEL_FATAL <= curp->file_status);
                         break;                          break;
                 case (ROFF_SO):                  case (ROFF_SO):
                         if (pfile(ln.buf + of, curp)) {                          if (pfile(ln.buf + of, curp)) {
Line 798  rerun:
Line 819  rerun:
                                 continue;                                  continue;
                         } else                          } else
                                 break;                                  break;
                 case (ROFF_CONT):                  default:
                         break;                          break;
                 }                  }
   
                 /*                  /*
                    * If we encounter errors in the recursive parsebuf()
                    * call, make sure we don't continue parsing.
                    */
   
                   if (MANDOCLEVEL_FATAL <= curp->file_status)
                           break;
   
                   /*
                  * If input parsers have not been allocated, do so now.                   * If input parsers have not been allocated, do so now.
                  * We keep these instanced betwen parsers, but set them                   * We keep these instanced betwen parsers, but set them
                  * locally per parse routine since we can use different                   * locally per parse routine since we can use different
Line 816  rerun:
Line 845  rerun:
                  * Lastly, push down into the parsers themselves.  One                   * Lastly, push down into the parsers themselves.  One
                  * of these will have already been set in the pset()                   * of these will have already been set in the pset()
                  * routine.                   * routine.
                    * If libroff returns ROFF_TBL, then add it to the
                    * currently open parse.  Since we only get here if
                    * there does exist data (see tbl_data.c), we're
                    * guaranteed that something's been allocated.
                    * Do the same for ROFF_EQN.
                  */                   */
   
                 if (curp->man || curp->mdoc) {                  rc = -1;
   
                   if (ROFF_TBL == rr)
                           while (NULL != (span = roff_span(curp->roff))) {
                                   rc = curp->man ?
                                           man_addspan(curp->man, span) :
                                           mdoc_addspan(curp->mdoc, span);
                                   if (0 == rc)
                                           break;
                           }
                   else if (ROFF_EQN == rr)
                           rc = curp->mdoc ?
                                   mdoc_addeqn(curp->mdoc,
                                           roff_eqn(curp->roff)) :
                                   man_addeqn(curp->man,
                                           roff_eqn(curp->roff));
                   else if (curp->man || curp->mdoc)
                         rc = curp->man ?                          rc = curp->man ?
                                 man_parseln(curp->man,                                  man_parseln(curp->man,
                                         curp->line, ln.buf, of) :                                          curp->line, ln.buf, of) :
                                 mdoc_parseln(curp->mdoc,                                  mdoc_parseln(curp->mdoc,
                                         curp->line, ln.buf, of);                                          curp->line, ln.buf, of);
   
                         if ( ! rc) {                  if (0 == rc) {
                                 assert(MANDOCLEVEL_FATAL <= file_status);                          assert(MANDOCLEVEL_FATAL <= curp->file_status);
                                 break;                          break;
                         }  
                 }                  }
   
                 /* Temporary buffers typically are not full. */                  /* Temporary buffers typically are not full. */
Line 1008  mmsg(enum mandocerr t, void *arg, int ln, int col, con
Line 1057  mmsg(enum mandocerr t, void *arg, int ln, int col, con
                 fprintf(stderr, ": %s", msg);                  fprintf(stderr, ": %s", msg);
         fputc('\n', stderr);          fputc('\n', stderr);
   
         if (file_status < level)          if (cp->file_status < level)
                 file_status = level;                  cp->file_status = level;
   
         return(level < MANDOCLEVEL_FATAL);          return(level < MANDOCLEVEL_FATAL);
 }  }

Legend:
Removed from v.1.127  
changed lines
  Added in v.1.152

CVSweb