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

Diff for /mandoc/Attic/mdocml.c between version 1.15 and 1.21

version 1.15, 2008/12/02 00:10:37 version 1.21, 2008/12/15 01:54:58
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   /* See begin_bufs. */  #define MD_LINE_SZ      (256)
 #define BUFFER_OUT_DEF  BUFSIZ   /* See begin_bufs. */  
   
   struct  md_parse {
           int              warn;
   #define MD_WARN_ALL     (1 << 0)
   #define MD_WARN_ERR     (1 << 1)
           int              dbg;
           struct mdoc     *mdoc;
           char            *buf;
           u_long           bufsz;
           char            *name;
           int              fd;
           int              lnn;
           char            *line;
   };
   
 static  void             usage(void);  static  void             usage(void);
   
 static  int              begin_io(const struct md_args *,  static  int              parse_begin(struct md_parse *);
                                 char *, char *);  static  int              parse_leave(struct md_parse *, int);
 static  int              leave_io(const struct md_buf *,  static  int              io_begin(struct md_parse *);
                                 const struct md_buf *, int);  static  int              io_leave(struct md_parse *, int);
 static  int              begin_bufs(const struct md_args *,  static  int              buf_begin(struct md_parse *);
                                 struct md_buf *, struct md_buf *);  static  int              buf_leave(struct md_parse *, int);
 static int               leave_bufs(const struct md_buf *,  
                                 const struct md_buf *, int);  
   
   static  int              msg_err(void *, int, int, enum mdoc_err);
   static  int              msg_warn(void *, int, int, enum mdoc_warn);
   static  void             msg_msg(void *, int, const char *);
   
   #ifdef __linux__
   extern  int              getsubopt(char **, char *const *, char **);
   #endif
   
 int  int
 main(int argc, char *argv[])  main(int argc, char *argv[])
 {  {
         int              c;          int              c;
         char            *out, *in;          struct md_parse  parser;
         struct md_args   args;          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 = in = NULL;          (void)memset(&parser, 0, sizeof(struct md_parse));
   
         (void)memset(&args, 0, sizeof(struct md_args));          while (-1 != (c = getopt(argc, argv, "vW:")))
   
         while (-1 != (c = getopt(argc, argv, "o:vW")))  
                 switch (c) {                  switch (c) {
                 case ('o'):  
                         out = optarg;  
                         break;  
                 case ('v'):                  case ('v'):
                         args.verbosity++;                          parser.dbg++;
                         break;                          break;
                 case ('W'):                  case ('W'):
                         args.warnings |= MD_WARN_ALL;                          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;                          break;
                 default:                  default:
                         usage();                          usage();
Line 77  main(int argc, char *argv[])
Line 106  main(int argc, char *argv[])
         argv += optind;          argv += optind;
         argc -= optind;          argc -= optind;
   
           parser.name = "-";
         if (1 == argc)          if (1 == argc)
                 in = *argv++;                  parser.name = *argv++;
   
         return(begin_io(&args, out ? out : "-", in ? in : "-"));          if ( ! io_begin(&parser))
                   return(EXIT_FAILURE);
   
           return(EXIT_SUCCESS);
 }  }
   
   
 /*  
  * Close out file descriptors opened in begin_io.  If the descriptor  
  * refers to stdin/stdout, then do nothing.  
  */  
 static int  static int
 leave_io(const struct md_buf *out,  io_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 (-1 == p->fd || STDIN_FILENO == p->fd)
                 assert(in->name);                  return(code);
                 warn("%s", in->name);  
                 c = 1;          if (-1 == close(p->fd)) {
                   warn("%s", p->name);
                   code = 0;
         }          }
         if (-1 != out->fd && STDOUT_FILENO != out->fd &&          return(code);
                         -1 == close(out->fd)) {  }
                 assert(out->name);  
                 warn("%s", out->name);  
                 c = 1;  static int
   io_begin(struct md_parse *p)
   {
   
           p->fd = STDIN_FILENO;
           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));
                   }
   
           return(io_leave(p, buf_begin(p)));
   }
   
   
   static int
   buf_leave(struct md_parse *p, int code)
   {
   
           if (p->buf)
                   free(p->buf);
           return(code);
   }
   
   
   static int
   buf_begin(struct md_parse *p)
   {
           struct stat      st;
   
           if (-1 == fstat(p->fd, &st)) {
                   warn("%s", p->name);
                   return(1);
           }
   
           p->bufsz = MAX(st.st_blksize, BUFSIZ);
   
           if (NULL == (p->buf = malloc(p->bufsz))) {
                   warn("malloc");
                   return(buf_leave(p, 0));
         }          }
         if (1 == c && STDOUT_FILENO != out->fd)  
                 if (-1 == unlink(out->name))  
                         warn("%s", out->name);  
   
         return(c);          return(buf_leave(p, parse_begin(p)));
 }  }
   
   
 /*  static void
  * Open file descriptors or assign stdin/stdout, if dictated by the "-"  print_node(const struct mdoc_node *n, int indent)
  * token instead of a filename.  {
  */          const char      *p, *t;
           int              i;
   
           switch (n->type) {
           case (MDOC_TEXT):
                   assert(NULL == n->child);
                   p = "<text>";
                   t = "text";
                   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_ELEM):
                   assert(NULL == n->child);
                   p = mdoc_macronames[n->data.elem.tok];
                   t = "element";
                   break;
           case (MDOC_BLOCK):
                   p = mdoc_macronames[n->data.block.tok];
                   t = "block";
                   break;
           }
   
           for (i = 0; i < indent; i++)
                   (void)printf("    ");
           (void)printf("%s (%s)\n", p, t);
   
           if (n->child)
                   print_node(n->child, indent + 1);
           if (n->next)
                   print_node(n->next, indent);
   }
   
   
 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;          const struct mdoc_node *n;
         struct md_buf    fo;  
   
 #define FI_FL   O_RDONLY          if (p->mdoc) {
 #define FO_FL   O_WRONLY|O_CREAT|O_TRUNC                  if ((n = mdoc_result(p->mdoc)))
                           print_node(n, 0);
                   mdoc_free(p->mdoc);
           }
           return(code);
   }
   
         assert(args);  
         assert(out);  
         assert(in);  
   
         bzero(&fi, sizeof(struct md_buf));  static int
         bzero(&fo, sizeof(struct md_buf));  parse_begin(struct md_parse *p)
   {
           ssize_t          sz, i;
           size_t           pos;
           char             line[256], sv[256];
           struct mdoc_cb   cb;
   
         fi.fd = STDIN_FILENO;          cb.mdoc_err = msg_err;
         fo.fd = STDOUT_FILENO;          cb.mdoc_warn = msg_warn;
           cb.mdoc_msg = msg_msg;
   
         fi.name = in;          if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
         fo.name = out;                  return(parse_leave(p, 0));
   
         if (0 != strncmp(fi.name, "-", 1))          p->lnn = 1;
                 if (-1 == (fi.fd = open(fi.name, FI_FL, 0))) {          p->line = sv;
                         warn("%s", fi.name);  
                         return(leave_io(&fo, &fi, 1));  
                 }  
   
         if (0 != strncmp(fo.name, "-", 1))          for (pos = 0; ; ) {
                 if (-1 == (fo.fd = open(fo.name, FO_FL, 0644))) {                  if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
                         warn("%s", fo.name);                          warn("%s", p->name);
                         return(leave_io(&fo, &fi, 1));                          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)) {
                                           /* LINTED */
                                           sv[pos] = p->buf[i];
                                           line[pos++] = p->buf[i];
                                           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, line))
                                   return(parse_leave(p, 0));
   
                           p->lnn++;
                           pos = 0;
                 }                  }
           }
   
         return(leave_io(&fo, &fi, begin_bufs(args, &fo, &fi)));          return(parse_leave(p, 1));
 }  }
   
   
 /*  
  * Free buffers allocated in begin_bufs.  
  */  
 static int  static int
 leave_bufs(const struct md_buf *out,  msg_err(void *arg, int tok, int col, enum mdoc_err type)
                 const struct md_buf *in, int c)  
 {  {
         assert(out);          char             *fmt, *lit;
         assert(in);          struct md_parse  *p;
         if (out->buf)          int               i;
                 free(out->buf);  
         if (in->buf)          p = (struct md_parse *)arg;
                 free(in->buf);  
         return(c);          fmt = lit = NULL;
   
           switch (type) {
           case (ERR_SYNTAX_QUOTE):
                   lit = "syntax: unterminated quotation";
                   break;
           case (ERR_SYNTAX_WS):
                   lit = "syntax: whitespace in argument";
                   break;
           case (ERR_SCOPE_BREAK):
                   /* Which scope is broken? */
                   fmt = "macro `%s' breaks prior explicit scope";
                   break;
           case (ERR_MACRO_NOTSUP):
                   fmt = "macro `%s' not supported";
                   break;
           case (ERR_MACRO_NOTCALL):
                   fmt = "macro `%s' not callable";
                   break;
           case (ERR_ARGS_GE1):
                   fmt = "macro `%s' expects one or more arguments";
                   break;
           default:
                   abort();
                   /* NOTREACHED */
           }
   
           if (fmt) {
                   (void)fprintf(stderr, "%s:%d: error: ",
                                   p->name, p->lnn);
                   (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
           } else
                   (void)fprintf(stderr, "%s:%d: error: %s",
                                   p->name, p->lnn, lit);
   
           if (p->dbg < 1) {
                   (void)fprintf(stderr, " (column %d)\n", col);
                   return(0);
           }
   
           (void)fprintf(stderr, "\nFrom: %s\n      ", p->line);
           for (i = 0; i < col; i++)
                   (void)fprintf(stderr, " ");
           (void)fprintf(stderr, "^\n");
   
           return(0);
 }  }
   
   
 /*  static void
  * Allocate buffers to the maximum of either the input file's blocksize  msg_msg(void *arg, int col, const char *msg)
  * or BUFFER_IN_DEF/BUFFER_OUT_DEF, which should be around BUFSIZE.  {
  */          struct md_parse  *p;
           int               i;
   
           p = (struct md_parse *)arg;
   
           if (p->dbg < 2)
                   return;
   
           (void)printf("%s:%d: %s", p->name, p->lnn, msg);
   
           if (p->dbg < 3) {
                   (void)printf(" (column %d)\n", col);
                   return;
           }
   
           (void)printf("\nFrom: %s\n      ", p->line);
           for (i = 0; i < col; i++)
                   (void)printf(" ");
           (void)printf("^\n");
   }
   
   
 static int  static int
 begin_bufs(const struct md_args *args,  msg_warn(void *arg, int tok, int col, enum mdoc_warn type)
                 struct md_buf *out, struct md_buf *in)  
 {  {
         struct stat      stin, stout;          char             *fmt, *lit;
         int              c;          struct md_parse  *p;
           int               i;
           extern char      *__progname;
   
         assert(args);          p = (struct md_parse *)arg;
         assert(in);  
         assert(out);  
   
         if (-1 == fstat(in->fd, &stin)) {          if ( ! (p->warn & MD_WARN_ALL))
                 warn("%s", in->name);  
                 return(1);                  return(1);
         } else if (STDIN_FILENO != in->fd && 0 == stin.st_size) {  
                 warnx("%s: empty file", in->name);          fmt = lit = NULL;
                 return(1);  
         } else if (-1 == fstat(out->fd, &stout)) {          switch (type) {
                 warn("%s", out->name);          case (WARN_SYNTAX_WS_EOLN):
                 return(1);                  lit = "syntax: whitespace at end-of-line";
                   break;
           case (WARN_SYNTAX_MACLIKE):
                   lit = "syntax: macro-like argument";
                   break;
           case (WARN_ARGS_GE1):
                   fmt = "macro `%s' suggests one or more arguments";
                   break;
           default:
                   abort();
                   /* NOTREACHED */
         }          }
   
         in->bufsz = MAX(stin.st_blksize, BUFFER_IN_DEF);          if (fmt) {
         out->bufsz = MAX(stout.st_blksize, BUFFER_OUT_DEF);                  (void)fprintf(stderr, "%s:%d: warning: ",
                                   p->name, p->lnn);
                   (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
           } else
                   (void)fprintf(stderr, "%s:%d: warning: %s",
                                   p->name, p->lnn, lit);
   
         if (NULL == (in->buf = malloc(in->bufsz))) {          if (p->dbg >= 1) {
                 warn("malloc");                  (void)fprintf(stderr, "\nFrom: %s\n      ", p->line);
                 return(leave_bufs(out, in, 1));                  for (i = 0; i < col; i++)
         } else if (NULL == (out->buf = malloc(out->bufsz))) {                          (void)fprintf(stderr, " ");
                 warn("malloc");                  (void)fprintf(stderr, "^\n");
                 return(leave_bufs(out, in, 1));          } 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);
         }          }
   
         c = md_run(args, out, in);          return(1);
         return(leave_bufs(out, in, -1 == c ? 1 : 0));  
 }  }
   
   
Line 220  usage(void)
Line 429  usage(void)
 {  {
         extern char     *__progname;          extern char     *__progname;
   
         (void)printf("usage: %s [-vW] [-o outfile] [infile]\n", __progname);          (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
                           __progname);
 }  }
   

Legend:
Removed from v.1.15  
changed lines
  Added in v.1.21

CVSweb