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

Diff for /mandoc/Attic/mdocml.c between version 1.6 and 1.53

version 1.6, 2008/11/23 11:05:25 version 1.53, 2009/02/20 23:35:36
Line 1 
Line 1 
 /* $Id$ */          /* $Id$ */
 /*  /*
  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>   * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
  *   *
Line 16 
Line 16 
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR   * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  * PERFORMANCE OF THIS SOFTWARE.   * PERFORMANCE OF THIS SOFTWARE.
  */   */
 #include <sys/param.h>  
 #include <sys/stat.h>  #include <sys/stat.h>
   #include <sys/param.h>
   
 #include <assert.h>  #include <assert.h>
 #include <err.h>  
 #include <fcntl.h>  #include <fcntl.h>
   #include <err.h>
 #include <getopt.h>  #include <getopt.h>
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
   
 #include "libmdocml.h"  #include "mdoc.h"
   
 #define BUFFER_IN_DEF   BUFSIZ  #define MD_LINE_SZ      (256)           /* Max input line size. */
 #define BUFFER_OUT_DEF  BUFSIZ  
   
 static void              usage(void);  struct  md_parse {
 static int               begin_io(const struct md_args *,          int               warn;         /* Warning flags. */
                                 char *, char *);  #define MD_WARN_SYNTAX   (1 << 0)       /* Show syntax warnings. */
 static int               leave_io(const struct md_buf *,  #define MD_WARN_COMPAT   (1 << 1)       /* Show compat warnings. */
                                 const struct md_buf *, int);  #define MD_WARN_ALL      (0x03)         /* Show all warnings. */
 static int               begin_bufs(const struct md_args *,  #define MD_WARN_ERR      (1 << 2)       /* Make warnings->errors. */
                                 struct md_buf *, struct md_buf *);          int               dbg;          /* Debug level. */
 static int               leave_bufs(const struct md_buf *,          struct mdoc      *mdoc;         /* Active parser. */
                                 const struct md_buf *, int);          char             *buf;          /* Input buffer. */
           u_long            bufsz;        /* Input buffer size. */
           char             *in;           /* Input file name. */
           int               fdin;         /* Input file desc. */
   };
   
   extern  char             *__progname;
   
   static  void              usage(void);
   
   static  int               parse_opts(struct md_parse *, int, char *[]);
   static  int               parse_subopts(struct md_parse *, char *);
   
   static  int               parse_begin(struct md_parse *);
   static  int               parse_leave(struct md_parse *, int);
   static  int               io_begin(struct md_parse *);
   static  int               io_leave(struct md_parse *, int);
   static  int               buf_begin(struct md_parse *);
   static  int               buf_leave(struct md_parse *, int);
   
   static  void              msg_msg(void *, int, int, const char *);
   static  int               msg_err(void *, int, int, const char *);
   static  int               msg_warn(void *, int, int,
                                   enum mdoc_warn, const char *);
   
   #ifdef __linux__
   extern  int               getsubopt(char **, char *const *, char **);
   #endif
   
 int  int
 main(int argc, char *argv[])  main(int argc, char *argv[])
 {  {
           struct md_parse  parser;
   
           (void)memset(&parser, 0, sizeof(struct md_parse));
   
           if ( ! parse_opts(&parser, argc, argv))
                   return(EXIT_FAILURE);
           if ( ! io_begin(&parser))
                   return(EXIT_FAILURE);
   
           return(EXIT_SUCCESS);
   }
   
   
   static int
   io_leave(struct md_parse *p, int code)
   {
   
           if (-1 == p->fdin || STDIN_FILENO == p->fdin)
                   return(code);
   
           if (-1 == close(p->fdin)) {
                   warn("%s", p->in);
                   code = 0;
           }
           return(code);
   }
   
   
   static int
   parse_subopts(struct md_parse *p, char *arg)
   {
           char            *v;
           char            *toks[] = { "all", "compat",
                                   "syntax", "error", NULL };
   
           /*
            * Future -Wxxx levels and so on should be here.  For now we
            * only recognise syntax and compat warnings as categories,
            * beyond the usually "all" and "error" (make warn error out).
            */
   
           while (*arg)
                   switch (getsubopt(&arg, toks, &v)) {
                   case (0):
                           p->warn |= MD_WARN_ALL;
                           break;
                   case (1):
                           p->warn |= MD_WARN_COMPAT;
                           break;
                   case (2):
                           p->warn |= MD_WARN_SYNTAX;
                           break;
                   case (3):
                           p->warn |= MD_WARN_ERR;
                           break;
                   default:
                           usage();
                           return(0);
                   }
   
           return(1);
   }
   
   
   static int
   parse_opts(struct md_parse *p, int argc, char *argv[])
   {
         int              c;          int              c;
         char            *out, *in;  
         struct md_args   args;  
   
         extern char     *optarg;          extern char     *optarg;
         extern int       optind;          extern int       optind;
   
         out = in = NULL;          p->in = "-";
   
         while (-1 != (c = getopt(argc, argv, "o:")))          while (-1 != (c = getopt(argc, argv, "vW:")))
                 switch (c) {                  switch (c) {
                 case ('o'):                  case ('v'):
                         out = optarg;                          p->dbg++;
                         break;                          break;
                   case ('W'):
                           if ( ! parse_subopts(p, optarg))
                                   return(0);
                           break;
                 default:                  default:
                         usage();                          usage();
                         return(1);                          return(0);
                 }                  }
   
         argv += optind;          argv += optind;
         argc -= optind;          if (0 == (argc -= optind))
                   return(1);
   
         if (1 == argc)          p->in = *argv++;
                 in = *argv++;          return(1);
   }
   
         args.type = MD_HTML4_STRICT;  
   
         return(begin_io(&args, out ? out : "-", in ? in : "-"));  static int
   io_begin(struct md_parse *p)
   {
   
           p->fdin = STDIN_FILENO;
           if (0 != strncmp(p->in, "-", 1))
                   if (-1 == (p->fdin = open(p->in, O_RDONLY, 0))) {
                           warn("%s", p->in);
                           return(io_leave(p, 0));
                   }
   
           return(io_leave(p, buf_begin(p)));
 }  }
   
   
 static int  static int
 leave_io(const struct md_buf *out,  buf_leave(struct md_parse *p, int code)
                 const struct md_buf *in, int c)  
 {  {
         assert(out);  
         assert(in);  
   
         if (-1 != in->fd && -1 == close(in->fd)) {          if (p->buf)
                 assert(in->name);                  free(p->buf);
                 warn("%s", in->name);          return(code);
                 c = 1;  }
   
   
   static int
   buf_begin(struct md_parse *p)
   {
           struct stat      st;
   
           if (-1 == fstat(p->fdin, &st)) {
                   warn("%s", p->in);
                   return(0);
           }
   
           /*
            * Try to intuit the fastest way of sucking down buffered data
            * by using either the block buffer size or the hard-coded one.
            * This is inspired by bin/cat.c.
            */
   
           p->bufsz = MAX(st.st_blksize, BUFSIZ);
   
           if (NULL == (p->buf = malloc(p->bufsz))) {
                   warn("malloc");
                   return(buf_leave(p, 0));
         }          }
         if (-1 != out->fd && STDOUT_FILENO != out->fd &&  
                         -1 == close(out->fd)) {  
                 assert(out->name);  
                 warn("%s", out->name);  
                 c = 1;  
         }  
   
         return(c);          return(buf_leave(p, parse_begin(p)));
 }  }
   
   
 static int  static int
 begin_io(const struct md_args *args, char *out, char *in)  parse_leave(struct md_parse *p, int code)
 {  {
         struct md_buf    fi;          extern int termprint(const struct mdoc_node *,
         struct md_buf    fo;                          const struct mdoc_meta *);
           /*extern int treeprint(const struct mdoc_node *,
                           const struct mdoc_meta *);*/
   
 #define FI_FL   O_RDONLY          if (NULL == p->mdoc)
 #define FO_FL   O_WRONLY|O_CREAT|O_TRUNC                  return(code);
   
         assert(args);          if ( ! mdoc_endparse(p->mdoc))
         assert(out);                  code = 0;
         assert(in);  
   
         bzero(&fi, sizeof(struct md_buf));          /* TODO */
         bzero(&fo, sizeof(struct md_buf));          if (code && ! termprint(mdoc_node(p->mdoc), mdoc_meta(p->mdoc)))
                   code = 0;
           /*if (code && ! treeprint(mdoc_node(p->mdoc), mdoc_meta(p->mdoc)))
                   code = 0;*/
   
         fi.fd = STDIN_FILENO;          mdoc_free(p->mdoc);
         fo.fd = STDOUT_FILENO;          return(code);
   }
   
         fi.name = in;  
         fo.name = out;  
   
         if (0 != strncmp(fi.name, "-", 1))  static int
                 if (-1 == (fi.fd = open(fi.name, FI_FL, 0))) {  parse_begin(struct md_parse *p)
                         warn("%s", fi.name);  {
                         return(leave_io(&fo, &fi, 1));          ssize_t          sz, i;
                 }          size_t           pos;
           char             line[MD_LINE_SZ];
           struct mdoc_cb   cb;
           int              lnn;
   
         if (0 != strncmp(fo.name, "-", 1))          cb.mdoc_err = msg_err;
                 if (-1 == (fo.fd = open(fo.name, FO_FL, 0644))) {          cb.mdoc_warn = msg_warn;
                         warn("%s", fo.name);          cb.mdoc_msg = msg_msg;
                         return(leave_io(&fo, &fi, 1));  
           if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
                   return(parse_leave(p, 0));
   
           /*
            * This is a little more complicated than fgets.  TODO: have
            * some benchmarks that show it's faster (note that I want to
            * check many, many manuals simultaneously, so speed is
            * important).  Fill a buffer (sized to the block size) with a
            * single read, then parse \n-terminated lines into a line
            * buffer, which is passed to the parser.  Hard-code the line
            * buffer to a particular size -- a reasonable assumption.
            */
   
           for (lnn = 1, pos = 0; ; ) {
                   if (-1 == (sz = read(p->fdin, p->buf, p->bufsz))) {
                           warn("%s", p->in);
                           return(parse_leave(p, 0));
                   } else if (0 == sz)
                           break;
   
                   for (i = 0; i < sz; i++) {
                           if ('\n' != p->buf[i]) {
                                   if (pos < sizeof(line)) {
                                           line[(int)pos++] = p->buf[(int)i];
                                           continue;
                                   }
                                   warnx("%s: line %d too long", p->in, lnn);
                                   return(parse_leave(p, 0));
                           }
   
                           line[(int)pos] = 0;
                           if ( ! mdoc_parseln(p->mdoc, lnn, line))
                                   return(parse_leave(p, 0));
   
                           lnn++;
                           pos = 0;
                 }                  }
           }
   
         return(leave_io(&fo, &fi, begin_bufs(args, &fo, &fi)));          return(parse_leave(p, 1));
 }  }
   
   
 static int  static int
 leave_bufs(const struct md_buf *out,  msg_err(void *arg, int line, int col, const char *msg)
                 const struct md_buf *in, int c)  
 {  {
         assert(out);          struct md_parse  *p;
         assert(in);  
         if (out->buf)          p = (struct md_parse *)arg;
                 free(out->buf);  
         if (in->buf)          warnx("%s:%d: error: %s (column %d)",
                 free(in->buf);                          p->in, line, msg, col);
         return(c);          return(0);
 }  }
   
   
   static void
   msg_msg(void *arg, int line, int col, const char *msg)
   {
           struct md_parse  *p;
   
           p = (struct md_parse *)arg;
   
           if (0 == p->dbg)
                   return;
   
           warnx("%s:%d: debug: %s (column %d)",
                           p->in, line, msg, col);
   }
   
   
 static int  static int
 begin_bufs(const struct md_args *args,  msg_warn(void *arg, int line, int col,
                 struct md_buf *out, struct md_buf *in)                  enum mdoc_warn type, const char *msg)
 {  {
         struct stat      stin, stout;          struct md_parse  *p;
         int              c;  
   
         assert(args);          p = (struct md_parse *)arg;
         assert(in);  
         assert(out);  
   
         if (-1 == fstat(in->fd, &stin)) {          switch (type) {
                 warn("%s", in->name);          case (WARN_COMPAT):
                   if (p->warn & MD_WARN_COMPAT)
                           break;
                 return(1);                  return(1);
         } else if (-1 == fstat(out->fd, &stout)) {          case (WARN_SYNTAX):
                 warn("%s", out->name);                  if (p->warn & MD_WARN_SYNTAX)
                           break;
                 return(1);                  return(1);
         }          }
   
         in->bufsz = MAX(stin.st_blksize, BUFFER_IN_DEF);          warnx("%s:%d: warning: %s (column %d)",
         out->bufsz = MAX(stout.st_blksize, BUFFER_OUT_DEF);                          p->in, line, msg, col);
   
         if (NULL == (in->buf = malloc(in->bufsz))) {          if ( ! (p->warn & MD_WARN_ERR))
                 warn("malloc");                  return(1);
                 return(leave_bufs(out, in, 1));  
         } else if (NULL == (out->buf = malloc(out->bufsz))) {  
                 warn("malloc");  
                 return(leave_bufs(out, in, 1));  
         }  
   
         c = md_run(args, out, in);          warnx("%s: considering warnings as errors", __progname);
         return(leave_bufs(out, in, -1 == c ? 1 : 0));          return(0);
 }  }
   
   
 static void  static void
 usage(void)  usage(void)
 {  {
         extern char     *__progname;  
   
         (void)printf("usage: %s [-o outfile] [infile]\n", __progname);          warnx("usage: %s [-v] [-Wwarn...] [infile]", __progname);
 }  }
   

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.53

CVSweb