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

Diff for /mandoc/Attic/mdocml.c between version 1.2 and 1.38

version 1.2, 2008/11/22 16:55:02 version 1.38, 2009/01/09 14:45:44
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"
   
 struct md_file {  #define MD_LINE_SZ      (256)
         int              fd;  
         const char      *name;  
 };  
   
 struct md_buf {  struct  md_parse {
         struct md_file  *file;          int              warn;
   #define MD_WARN_ALL     (1 << 0)
   #define MD_WARN_ERR     (1 << 1)
           int              dbg;
           struct mdoc     *mdoc;
         char            *buf;          char            *buf;
         size_t           bufsz;          u_long           bufsz;
         size_t           line;          char            *name;
           int              fd;
           int              lnn;
           char            *line;
 };  };
   
 struct md_mbuf {  static  void             usage(void);
         struct md_buf   *buf;  
         size_t           pos;  
 };  
   
 static void              usage(void);  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 int               md_begin(const char *, const char *);  static  int              msg_err(void *, int, int, enum mdoc_err);
 static int               md_begin_io(const char *, const char *);  static  int              msg_warn(void *, int, int, enum mdoc_warn);
 static int               md_begin_bufs(struct md_file *, struct md_file *);  static  void             msg_msg(void *, int, int, const char *);
 static int               md_run(struct md_buf *, struct md_buf *);  
 static int               md_line(struct md_mbuf *, const struct md_buf *,  
                                 const char *, size_t);  
   
 static ssize_t           md_buf_fill(struct md_buf *);  #ifdef __linux__
 static int               md_buf_flush(struct md_mbuf *);  extern  int              getsubopt(char **, char *const *, char **);
   #endif
   
 static int               md_buf_putchar(struct md_mbuf *, char);  
 static int               md_buf_puts(struct md_mbuf *,  
                                 const char *, size_t);  
   
   
 int  int
 main(int argc, char *argv[])  main(int argc, char *argv[])
 {  {
         int              c;          int              c;
         char            *out, *in;          struct md_parse  parser;
           char            *opts, *v;
   #define ALL              0
   #define ERROR            1
           char            *toks[] = { "all", "error", NULL };
   
         extern char     *optarg;          extern char     *optarg;
         extern int       optind;          extern int       optind;
   
         out = NULL;          (void)memset(&parser, 0, sizeof(struct md_parse));
   
         while (-1 != (c = getopt(argc, argv, "o:")))          while (-1 != (c = getopt(argc, argv, "vW:")))
                 switch (c) {                  switch (c) {
                 case ('o'):                  case ('v'):
                         out = optarg;                          parser.dbg++;
                         break;                          break;
                   case ('W'):
                           opts = optarg;
                           while (*opts)
                                   switch (getsubopt(&opts, toks, &v)) {
                                   case (ALL):
                                           parser.warn |= MD_WARN_ALL;
                                           break;
                                   case (ERROR):
                                           parser.warn |= MD_WARN_ERR;
                                           break;
                                   default:
                                           usage();
                                           return(1);
                                   }
                           break;
                 default:                  default:
                         usage();                          usage();
                         return(1);                          return(1);
                 }                  }
   
         argv += optind;          argv += optind;
         if (1 != (argc -= optind)) {          argc -= optind;
                 usage();  
                 return(1);  
         }  
   
         argc--;          parser.name = "-";
         in = *argv++;          if (1 == argc)
                   parser.name = *argv++;
   
         return(md_begin(out, in));          if ( ! io_begin(&parser))
                   return(EXIT_FAILURE);
   
           return(EXIT_SUCCESS);
 }  }
   
   
 static int  static int
 md_begin(const char *out, const char *in)  io_leave(struct md_parse *p, int code)
 {  {
         char             buf[MAXPATHLEN];  
   
         assert(in);          if (-1 == p->fd || STDIN_FILENO == p->fd)
         if (out)                  return(code);
                 return(md_begin_io(out, in));  
   
         if (strlcpy(buf, in, MAXPATHLEN) >= MAXPATHLEN)          if (-1 == close(p->fd)) {
                 warnx("output filename too long");                  warn("%s", p->name);
         else if (strlcat(buf, ".html", MAXPATHLEN) >= MAXPATHLEN)                  code = 0;
                 warnx("output filename too long");          }
         else          return(code);
                 return(md_begin_io(buf, in));  
   
         return(1);  
 }  }
   
   
 static int  static int
 md_begin_io(const char *out, const char *in)  io_begin(struct md_parse *p)
 {  {
         int              c;  
         struct md_file   fin, fout;  
   
         assert(out);          p->fd = STDIN_FILENO;
         assert(in);          if (0 != strncmp(p->name, "-", 1))
                   if (-1 == (p->fd = open(p->name, O_RDONLY, 0))) {
                           warn("%s", p->name);
                           return(io_leave(p, 0));
                   }
   
         /* TODO: accept "-" as both input and output. */          return(io_leave(p, buf_begin(p)));
   }
   
         fin.name = in;  
   
         if (-1 == (fin.fd = open(fin.name, O_RDONLY, 0))) {  static int
                 warn("%s", fin.name);  buf_leave(struct md_parse *p, int code)
                 return(1);  {
         }  
   
         fout.name = out;          if (p->buf)
                   free(p->buf);
           return(code);
   }
   
         fout.fd = open(fout.name, O_WRONLY | O_CREAT | O_TRUNC, 0644);  
         if (-1 == fout.fd) {  static int
                 warn("%s", fout.name);  buf_begin(struct md_parse *p)
                 if (-1 == close(fin.fd))  {
                         warn("%s", fin.name);          struct stat      st;
   
           if (-1 == fstat(p->fd, &st)) {
                   warn("%s", p->name);
                 return(1);                  return(1);
         }          }
   
         c = md_begin_bufs(&fout, &fin);          p->bufsz = MAX(st.st_blksize, BUFSIZ);
   
         if (-1 == close(fin.fd)) {          if (NULL == (p->buf = malloc(p->bufsz))) {
                 warn("%s", in);                  warn("malloc");
                 c = 1;                  return(buf_leave(p, 0));
         }          }
         if (-1 == close(fout.fd)) {  
                 warn("%s", out);  
                 c = 1;  
         }  
   
         return(c);          return(buf_leave(p, parse_begin(p)));
 }  }
   
   
 static int  static void
 md_begin_bufs(struct md_file *out, struct md_file *in)  print_node(const struct mdoc_node *n, int indent)
 {  {
         struct stat      stin, stout;          const char       *p, *t;
         struct md_buf    inbuf, outbuf;          int               i, j;
         int              c;          size_t            argc, sz;
           char            **params;
           struct mdoc_arg  *argv;
   
         assert(in);          argv = NULL;
         assert(out);          argc = 0;
           params = NULL;
           sz = 0;
   
         if (-1 == fstat(in->fd, &stin)) {          switch (n->type) {
                 warn("fstat: %s", in->name);          case (MDOC_TEXT):
                 return(1);                  assert(NULL == n->child);
         } else if (-1 == fstat(out->fd, &stout)) {                  p = n->data.text.string;
                 warn("fstat: %s", out->name);                  t = "text";
                 return(1);                  break;
           case (MDOC_BODY):
                   p = mdoc_macronames[n->data.body.tok];
                   t = "block-body";
                   break;
           case (MDOC_HEAD):
                   p = mdoc_macronames[n->data.head.tok];
                   t = "block-head";
                   break;
           case (MDOC_TAIL):
                   p = mdoc_macronames[n->data.tail.tok];
                   t = "block-tail";
                   break;
           case (MDOC_ELEM):
                   p = mdoc_macronames[n->data.elem.tok];
                   t = "element";
                   argv = n->data.elem.argv;
                   argc = n->data.elem.argc;
                   break;
           case (MDOC_BLOCK):
                   p = mdoc_macronames[n->data.block.tok];
                   t = "block";
                   argv = n->data.block.argv;
                   argc = n->data.block.argc;
                   break;
           case (MDOC_ROOT):
                   p = "root";
                   t = "root";
                   break;
           default:
                   abort();
                   /* NOTREACHED */
         }          }
   
         inbuf.file = in;          for (i = 0; i < indent; i++)
         inbuf.line = 1;                  (void)printf("    ");
         /*inbuf.bufsz = MAX(stin.st_blksize, BUFSIZ);*/          (void)printf("%s (%s)", p, t);
         inbuf.bufsz = 256;  
   
         outbuf.file = out;          for (i = 0; i < (int)argc; i++) {
         outbuf.line = 1;                  (void)printf(" -%s", mdoc_argnames[argv[i].arg]);
         /*outbuf.bufsz = MAX(stout.st_blksize, BUFSIZ);*/                  for (j = 0; j < (int)argv[i].sz; j++)
         outbuf.bufsz = 256;                          (void)printf(" \"%s\"", argv[i].value[j]);
   
         if (NULL == (inbuf.buf = malloc(inbuf.bufsz))) {  
                 warn("malloc");  
                 return(1);  
         } else if (NULL == (outbuf.buf = malloc(outbuf.bufsz))) {  
                 warn("malloc");  
                 free(inbuf.buf);  
                 return(1);  
         }          }
   
         c = md_run(&outbuf, &inbuf);          for (i = 0; i < (int)sz; i++)
                   (void)printf(" \"%s\"", params[i]);
   
         free(inbuf.buf);          (void)printf("\n");
         free(outbuf.buf);  
   
         return(c);          if (n->child)
                   print_node(n->child, indent + 1);
           if (n->next)
                   print_node(n->next, indent);
 }  }
   
   
 static ssize_t  static int
 md_buf_fill(struct md_buf *in)  parse_leave(struct md_parse *p, int code)
 {  {
         ssize_t          ssz;          const struct mdoc_node *n;
   
         assert(in);          if (NULL == p->mdoc)
         assert(in->file);                  return(code);
         assert(in->buf);  
         assert(in->bufsz > 0);  
         assert(in->file->name);  
   
         if (-1 == (ssz = read(in->file->fd, in->buf, in->bufsz)))          if ( ! mdoc_endparse(p->mdoc))
                 warn("%s", in->file->name);                  code = 0;
         else          if ((n = mdoc_result(p->mdoc)))
                 (void)printf("%s: filled %zd bytes\n",                  print_node(n, 0);
                                 in->file->name, ssz);  
   
         return(ssz);          mdoc_free(p->mdoc);
   
           return(code);
 }  }
   
   
 static int  static int
 md_run(struct md_buf *out, struct md_buf *in)  parse_begin(struct md_parse *p)
 {  {
         struct md_mbuf   mbuf;  
         ssize_t          sz, i;          ssize_t          sz, i;
         char             line[BUFSIZ];  
         size_t           pos;          size_t           pos;
           char             line[256], sv[256];
           struct mdoc_cb   cb;
   
         assert(in);          cb.mdoc_err = msg_err;
         assert(out);          cb.mdoc_warn = msg_warn;
           cb.mdoc_msg = msg_msg;
   
         mbuf.buf = out;          if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
         mbuf.pos = 0;                  return(parse_leave(p, 0));
   
         /* LINTED */          p->lnn = 1;
           p->line = sv;
   
         for (pos = 0; ; ) {          for (pos = 0; ; ) {
                 if (-1 == (sz = md_buf_fill(in)))                  if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
                         return(1);                          warn("%s", p->name);
                 else if (0 == sz)                          return(parse_leave(p, 0));
                   } else if (0 == sz)
                         break;                          break;
   
                 for (i = 0; i < sz; i++) {                  for (i = 0; i < sz; i++) {
                         if ('\n' == in->buf[i]) {                          if ('\n' != p->buf[i]) {
                                 if (md_line(&mbuf, in, line, pos))                                  if (pos < sizeof(line)) {
                                         return(1);                                          sv[(int)pos] = p->buf[(int)i];
                                 in->line++;                                          line[(int)pos++] =
                                 pos = 0;                                                  p->buf[(int)i];
                                 continue;                                          continue;
                                   }
                                   warnx("%s: line %d too long",
                                                   p->name, p->lnn);
                                   return(parse_leave(p, 0));
                         }                          }
   
                           line[(int)pos] = sv[(int)pos] = 0;
                           if ( ! mdoc_parseln(p->mdoc, p->lnn, line))
                                   return(parse_leave(p, 0));
   
                         if (pos < BUFSIZ) {                          p->lnn++;
                                 /* LINTED */                          pos = 0;
                                 line[pos++] = in->buf[i];  
                                 continue;  
                         }  
   
                         warnx("%s: line %zu too long",  
                                         in->file->name, in->line);  
                         return(1);  
                 }                  }
         }          }
   
         if (0 != pos && md_line(&mbuf, in, line, pos))          return(parse_leave(p, 1));
                 return(1);  
   
         return(md_buf_flush(&mbuf) ? 0 : 1);  
 }  }
   
   
 static int  static int
 md_buf_flush(struct md_mbuf *buf)  msg_err(void *arg, int line, int col, enum mdoc_err type)
 {  {
         ssize_t          sz;          char             *lit;
           struct md_parse  *p;
           int               i;
   
         assert(buf);          p = (struct md_parse *)arg;
         assert(buf->buf);  
         assert(buf->buf->file);  
         assert(buf->buf->buf);  
         assert(buf->buf->file->name);  
   
         (void)printf("%s: flushing %zu bytes\n",          lit = NULL;
                         buf->buf->file->name, buf->pos);  
   
         if (0 == buf->pos)          switch (type) {
                 return(1);          case (ERR_SYNTAX_NOTEXT):
                   lit = "syntax: context-free text disallowed";
                   break;
           case (ERR_SYNTAX_QUOTE):
                   lit = "syntax: disallowed argument quotation";
                   break;
           case (ERR_SYNTAX_UNQUOTE):
                   lit = "syntax: unterminated quotation";
                   break;
           case (ERR_SYNTAX_WS):
                   lit = "syntax: whitespace in argument";
                   break;
           case (ERR_SYNTAX_ARGFORM):
                   lit = "syntax: macro arguments malformed";
                   break;
           case (ERR_SYNTAX_NOPUNCT):
                   lit = "syntax: macro doesn't understand punctuation";
                   break;
           case (ERR_SYNTAX_ARG):
                   lit = "syntax: unknown argument for macro";
                   break;
           case (ERR_SCOPE_BREAK):
                   /* Which scope is broken? */
                   lit = "scope: macro breaks prior explicit scope";
                   break;
           case (ERR_SCOPE_NOCTX):
                   lit = "scope: closure macro has no context";
                   break;
           case (ERR_SCOPE_NONEST):
                   lit = "scope: macro may not be nested in the current context";
                   break;
           case (ERR_MACRO_NOTSUP):
                   lit = "macro not supported";
                   break;
           case (ERR_MACRO_NOTCALL):
                   lit = "macro not callable";
                   break;
           case (ERR_SEC_PROLOGUE):
                   lit = "macro cannot be called in the prologue";
                   break;
           case (ERR_SEC_NPROLOGUE):
                   lit = "macro called outside of prologue";
                   break;
           case (ERR_ARGS_EQ0):
                   lit = "macro expects zero arguments";
                   break;
           case (ERR_ARGS_EQ1):
                   lit = "macro expects one argument";
                   break;
           case (ERR_ARGS_GE1):
                   lit = "macro expects one or more arguments";
                   break;
           case (ERR_ARGS_LE2):
                   lit = "macro expects two or fewer arguments";
                   break;
           case (ERR_ARGS_LE8):
                   lit = "macro expects eight or fewer arguments";
                   break;
           case (ERR_ARGS_MANY):
                   lit = "macro has too many arguments";
                   break;
           case (ERR_SEC_PROLOGUE_OO):
                   lit = "prologue macro is out-of-order";
                   break;
           case (ERR_SEC_PROLOGUE_REP):
                   lit = "prologue macro repeated";
                   break;
           case (ERR_SEC_NAME):
                   lit = "`NAME' section must be first";
                   break;
           case (ERR_SYNTAX_ARGVAL):
                   lit = "syntax: expected value for macro argument";
                   break;
           case (ERR_SYNTAX_ARGBAD):
                   lit = "syntax: invalid value for macro argument";
                   break;
           case (ERR_SYNTAX_ARGMANY):
                   lit = "syntax: too many values for macro argument";
                   break;
           case (ERR_SYNTAX_CHILDHEAD):
                   lit = "syntax: expected only block-header section";
                   break;
           case (ERR_SYNTAX_CHILDBODY):
                   lit = "syntax: expected only a block-body section";
                   break;
           case (ERR_SYNTAX_EMPTYHEAD):
                   lit = "syntax: block-header section may not be empty";
                   break;
           case (ERR_SYNTAX_EMPTYBODY):
                   lit = "syntax: block-body section may not be empty";
                   break;
           default:
                   abort();
                   /* NOTREACHED */
           }
   
         sz = write(buf->buf->file->fd, buf->buf->buf, buf->pos);          (void)fprintf(stderr, "%s:%d: error: %s", p->name, p->lnn, lit);
   
         if (-1 == sz) {          if (p->dbg < 1) {
                 warn("%s", buf->buf->file->name);                  (void)fprintf(stderr, " (column %d)\n", col);
                 return(0);                  return(0);
         } else if ((size_t)sz != buf->pos) {          }
                 warnx("%s: short write", buf->buf->file->name);  
                 return(0);  
         }  
   
         buf->pos = 0;          (void)fprintf(stderr, "\nFrom: %s\n      ", p->line);
         return(1);          for (i = 0; i < col; i++)
 }                  (void)fprintf(stderr, " ");
           (void)fprintf(stderr, "^\n");
   
           return(0);
 static int  
 md_buf_putchar(struct md_mbuf *buf, char c)  
 {  
         return(md_buf_puts(buf, &c, 1));  
 }  }
   
   
 static int  static void
 md_buf_puts(struct md_mbuf *buf, const char *p, size_t sz)  msg_msg(void *arg, int line, int col, const char *msg)
 {  {
         size_t           ssz;          struct md_parse  *p;
           int               i;
   
         assert(p);          p = (struct md_parse *)arg;
         assert(buf);  
         assert(buf->buf);  
   
         while (buf->pos + sz > buf->buf->bufsz) {          if (p->dbg < 2)
                 ssz = buf->buf->bufsz - buf->pos;                  return;
                 (void)memcpy(buf->buf->buf + buf->pos, p, ssz);  
                 p += ssz;  
                 sz -= ssz;  
                 buf->pos += ssz;  
   
                 if ( ! md_buf_flush(buf))          (void)printf("%s:%d: %s", p->name, line, msg);
                         return(0);  
           if (p->dbg < 3) {
                   (void)printf(" (column %d)\n", col);
                   return;
         }          }
   
         (void)memcpy(buf->buf->buf + buf->pos, p, sz);          (void)printf("\nFrom: %s\n      ", p->line);
         buf->pos += sz;          for (i = 0; i < col; i++)
         return(1);                  (void)printf(" ");
           (void)printf("^\n");
 }  }
   
   
 static int  static int
 md_line(struct md_mbuf *out, const struct md_buf *in,  msg_warn(void *arg, int line, int col, enum mdoc_warn type)
                 const char *buf, size_t sz)  
 {  {
           char             *lit;
           struct md_parse  *p;
           int               i;
           extern char      *__progname;
   
         assert(buf);          p = (struct md_parse *)arg;
         assert(out);  
         assert(in);  
   
         if ( ! md_buf_puts(out, buf, sz))          if ( ! (p->warn & MD_WARN_ALL))
                 return(1);                  return(1);
         if ( ! md_buf_putchar(out, '\n'))  
                 return(1);  
   
         return(0);          lit = NULL;
   
           switch (type) {
           case (WARN_SYNTAX_WS_EOLN):
                   lit = "syntax: whitespace at end-of-line";
                   break;
           case (WARN_SYNTAX_QUOTED):
                   lit = "syntax: quotation mark starting string";
                   break;
           case (WARN_SYNTAX_MACLIKE):
                   lit = "syntax: macro-like argument";
                   break;
           case (WARN_SYNTAX_ARGLIKE):
                   lit = "syntax: argument-like value";
                   break;
           case (WARN_SYNTAX_EMPTYBODY):
                   lit = "syntax: empty block-body section";
                   break;
           case (WARN_SEC_OO):
                   lit = "section is out of conventional order";
                   break;
           case (WARN_SEC_REP):
                   lit = "section repeated";
                   break;
           case (WARN_ARGS_GE1):
                   lit = "macro suggests one or more arguments";
                   break;
           case (WARN_ARGS_EQ0):
                   lit = "macro suggests zero arguments";
                   break;
           case (WARN_IGN_AFTER_BLK):
                   lit = "ignore: macro ignored after block macro";
                   break;
           case (WARN_IGN_OBSOLETE):
                   lit = "ignore: macro is obsolete";
                   break;
           case (WARN_IGN_BEFORE_BLK):
                   lit = "ignore: macro before block macro ignored";
                   break;
           case (WARN_COMPAT_TROFF):
                   lit = "compat: macro behaves differently in troff and nroff";
                   break;
           default:
                   abort();
                   /* NOTREACHED */
           }
   
   
           (void)fprintf(stderr, "%s:%d: warning: %s", p->name, line, lit);
   
           if (p->dbg >= 1) {
                   (void)fprintf(stderr, "\nFrom: %s\n      ", p->line);
                   for (i = 0; i < col; i++)
                           (void)fprintf(stderr, " ");
                   (void)fprintf(stderr, "^\n");
           } else
                   (void)fprintf(stderr, " (column %d)\n", col);
   
           if (p->warn & MD_WARN_ERR) {
                   (void)fprintf(stderr, "%s: considering warnings as "
                                   "errors\n", __progname);
                   return(0);
           }
   
           return(1);
 }  }
   
   
Line 365  usage(void)
Line 558  usage(void)
 {  {
         extern char     *__progname;          extern char     *__progname;
   
         (void)printf("usage: %s [-o outfile] infile\n", __progname);          (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
                           __progname);
 }  }
   

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.38

CVSweb