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

Diff for /mandoc/mdoc_validate.c between version 1.162 and 1.185

version 1.162, 2011/03/17 11:30:23 version 1.185, 2012/07/10 14:38:51
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>   * Copyright (c) 2010, 2011, 2012 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 33 
Line 33 
 #include <string.h>  #include <string.h>
 #include <time.h>  #include <time.h>
   
   #include "mdoc.h"
 #include "mandoc.h"  #include "mandoc.h"
 #include "libmdoc.h"  #include "libmdoc.h"
 #include "libmandoc.h"  #include "libmandoc.h"
Line 71  static void  check_text(struct mdoc *, int, int, char 
Line 72  static void  check_text(struct mdoc *, int, int, char 
 static  void     check_argv(struct mdoc *,  static  void     check_argv(struct mdoc *,
                         struct mdoc_node *, struct mdoc_argv *);                          struct mdoc_node *, struct mdoc_argv *);
 static  void     check_args(struct mdoc *, struct mdoc_node *);  static  void     check_args(struct mdoc *, struct mdoc_node *);
   static  int      concat(char *, const struct mdoc_node *, size_t);
 static  int      concat(struct mdoc *, char *,  
                         const struct mdoc_node *, size_t);  
 static  enum mdoc_sec   a2sec(const char *);  static  enum mdoc_sec   a2sec(const char *);
 static  size_t          macro2len(enum mdoct);  static  size_t          macro2len(enum mdoct);
   
Line 154  static v_post  posts_notext[] = { ewarn_eq0, NULL };
Line 153  static v_post  posts_notext[] = { ewarn_eq0, NULL };
 static  v_post   posts_ns[] = { post_ns, NULL };  static  v_post   posts_ns[] = { post_ns, NULL };
 static  v_post   posts_os[] = { post_os, post_prol, NULL };  static  v_post   posts_os[] = { post_os, post_prol, NULL };
 static  v_post   posts_rs[] = { post_rs, NULL };  static  v_post   posts_rs[] = { post_rs, NULL };
 static  v_post   posts_sh[] = { post_ignpar, hwarn_ge1, bwarn_ge1, post_sh, NULL };  static  v_post   posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL };
 static  v_post   posts_sp[] = { ewarn_le1, NULL };  static  v_post   posts_sp[] = { ewarn_le1, NULL };
 static  v_post   posts_ss[] = { post_ignpar, hwarn_ge1, bwarn_ge1, NULL };  static  v_post   posts_ss[] = { post_ignpar, hwarn_ge1, NULL };
 static  v_post   posts_st[] = { post_st, NULL };  static  v_post   posts_st[] = { post_st, NULL };
 static  v_post   posts_std[] = { post_std, NULL };  static  v_post   posts_std[] = { post_std, NULL };
 static  v_post   posts_text[] = { ewarn_ge1, NULL };  static  v_post   posts_text[] = { ewarn_ge1, NULL };
Line 179  static v_pre  pres_sh[] = { pre_sh, NULL };
Line 178  static v_pre  pres_sh[] = { pre_sh, NULL };
 static  v_pre    pres_ss[] = { pre_ss, NULL };  static  v_pre    pres_ss[] = { pre_ss, NULL };
 static  v_pre    pres_std[] = { pre_std, NULL };  static  v_pre    pres_std[] = { pre_std, NULL };
   
 const   struct valids mdoc_valids[MDOC_MAX] = {  static  const struct valids mdoc_valids[MDOC_MAX] = {
         { NULL, NULL },                         /* Ap */          { NULL, NULL },                         /* Ap */
         { pres_dd, posts_dd },                  /* Dd */          { pres_dd, posts_dd },                  /* Dd */
         { pres_dt, posts_dt },                  /* Dt */          { pres_dt, posts_dt },                  /* Dt */
Line 446  check_count(struct mdoc *m, enum mdoc_type type, 
Line 445  check_count(struct mdoc *m, enum mdoc_type type, 
         }          }
   
         t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;          t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
         mdoc_vmsg(m, t, m->last->line, m->last->pos,          mandoc_vmsg(t, m->parse, m->last->line, m->last->pos,
                         "want %s%d children (have %d)",                          "want %s%d children (have %d)",
                         p, val, m->last->nchild);                          p, val, m->last->nchild);
         return(1);          return(1);
Line 544  check_argv(struct mdoc *m, struct mdoc_node *n, struct
Line 543  check_argv(struct mdoc *m, struct mdoc_node *n, struct
 static void  static void
 check_text(struct mdoc *m, int ln, int pos, char *p)  check_text(struct mdoc *m, int ln, int pos, char *p)
 {  {
         int              c;          char            *cp;
         size_t           sz;  
   
         for ( ; *p; p++, pos++) {          if (MDOC_LITERAL & m->flags)
                 sz = strcspn(p, "\t\\");                  return;
                 p += (int)sz;  
   
                 if ('\0' == *p)          for (cp = p; NULL != (p = strchr(p, '\t')); p++)
                         break;                  mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
   
                 pos += (int)sz;  
   
                 if ('\t' == *p) {  
                         if ( ! (MDOC_LITERAL & m->flags))  
                                 mdoc_pmsg(m, ln, pos, MANDOCERR_BADTAB);  
                         continue;  
                 }  
   
                 if (0 == (c = mandoc_special(p))) {  
                         mdoc_pmsg(m, ln, pos, MANDOCERR_BADESCAPE);  
                         continue;  
                 }  
   
                 p += c - 1;  
                 pos += c - 1;  
         }  
 }  }
   
 static int  static int
Line 581  check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type 
Line 561  check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type 
                         (t == n->parent->type))                          (t == n->parent->type))
                 return(1);                  return(1);
   
         mdoc_vmsg(mdoc, MANDOCERR_SYNTCHILD,          mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
                                 n->line, n->pos, "want parent %s",                          n->pos, "want parent %s", MDOC_ROOT == t ?
                                 MDOC_ROOT == t ? "<root>" :                          "<root>" : mdoc_macronames[tok]);
                                         mdoc_macronames[tok]);  
         return(0);          return(0);
 }  }
   
Line 682  pre_bl(PRE_ARGS)
Line 661  pre_bl(PRE_ARGS)
                         comp = 1;                          comp = 1;
                         break;                          break;
                 case (MDOC_Width):                  case (MDOC_Width):
                         dup = (NULL != n->norm->Bl.width);                          /* NB: this can be empty! */
                         width = n->args->argv[i].value[0];                          if (n->args->argv[i].sz) {
                                   width = n->args->argv[i].value[0];
                                   dup = (NULL != n->norm->Bl.width);
                                   break;
                           }
                           mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
                         break;                          break;
                 case (MDOC_Offset):                  case (MDOC_Offset):
                         /* NB: this can be empty! */                          /* NB: this can be empty! */
Line 723  pre_bl(PRE_ARGS)
Line 707  pre_bl(PRE_ARGS)
                         if (LIST_column == lt) {                          if (LIST_column == lt) {
                                 n->norm->Bl.ncols =                                  n->norm->Bl.ncols =
                                         n->args->argv[i].sz;                                          n->args->argv[i].sz;
                                 n->norm->Bl.cols = (const char **)                                  n->norm->Bl.cols = (void *)
                                         n->args->argv[i].value;                                          n->args->argv[i].value;
                         }                          }
                 }                  }
Line 749  pre_bl(PRE_ARGS)
Line 733  pre_bl(PRE_ARGS)
         /*          /*
          * Validate the width field.  Some list types don't need width           * Validate the width field.  Some list types don't need width
          * types and should be warned about them.  Others should have it           * types and should be warned about them.  Others should have it
          * and must also be warned.           * and must also be warned.  Yet others have a default and need
            * no warning.
          */           */
   
         switch (n->norm->Bl.type) {          switch (n->norm->Bl.type) {
         case (LIST_tag):          case (LIST_tag):
                 if (n->norm->Bl.width)                  if (NULL == n->norm->Bl.width)
                         break;                          mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
                 mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);  
                 break;                  break;
         case (LIST_column):          case (LIST_column):
                 /* FALLTHROUGH */                  /* FALLTHROUGH */
Line 770  pre_bl(PRE_ARGS)
Line 754  pre_bl(PRE_ARGS)
                 if (n->norm->Bl.width)                  if (n->norm->Bl.width)
                         mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);                          mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
                 break;                  break;
           case (LIST_bullet):
                   /* FALLTHROUGH */
           case (LIST_dash):
                   /* FALLTHROUGH */
           case (LIST_hyphen):
                   if (NULL == n->norm->Bl.width)
                           n->norm->Bl.width = "2n";
                   break;
           case (LIST_enum):
                   if (NULL == n->norm->Bl.width)
                           n->norm->Bl.width = "3n";
                   break;
         default:          default:
                 break;                  break;
         }          }
Line 891  pre_sh(PRE_ARGS)
Line 887  pre_sh(PRE_ARGS)
         if (MDOC_BLOCK != n->type)          if (MDOC_BLOCK != n->type)
                 return(1);                  return(1);
   
         mdoc->regs->regs[(int)REG_nS].set = 0;          roff_regunset(mdoc->roff, REG_nS);
         return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));          return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
 }  }
   
Line 1125  static int
Line 1121  static int
 post_nm(POST_ARGS)  post_nm(POST_ARGS)
 {  {
         char             buf[BUFSIZ];          char             buf[BUFSIZ];
           int              c;
   
         /* If no child specified, make sure we have the meta name. */          /* If no child specified, make sure we have the meta name. */
   
Line 1136  post_nm(POST_ARGS)
Line 1133  post_nm(POST_ARGS)
   
         /* If no meta name, set it from the child. */          /* If no meta name, set it from the child. */
   
         if ( ! concat(mdoc, buf, mdoc->last->child, BUFSIZ))          buf[0] = '\0';
           if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
                   mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
                 return(0);                  return(0);
           }
   
           assert(c);
         mdoc->meta.name = mandoc_strdup(buf);          mdoc->meta.name = mandoc_strdup(buf);
   
         return(1);          return(1);
 }  }
   
Line 1332  post_it(POST_ARGS)
Line 1332  post_it(POST_ARGS)
                 else                  else
                         er = MANDOCERR_SYNTARGCOUNT;                          er = MANDOCERR_SYNTARGCOUNT;
   
                 mdoc_vmsg(mdoc, er, mdoc->last->line, mdoc->last->pos,                  mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
                                   mdoc->last->pos,
                                 "columns == %d (have %d)", cols, i);                                  "columns == %d (have %d)", cols, i);
                 return(MANDOCERR_ARGCOUNT == er);                  return(MANDOCERR_ARGCOUNT == er);
         default:          default:
Line 1410  post_bl_block_width(POST_ARGS)
Line 1411  post_bl_block_width(POST_ARGS)
   
         assert(i < (int)n->args->argc);          assert(i < (int)n->args->argc);
   
         snprintf(buf, NUMSIZ, "%zun", width);          snprintf(buf, NUMSIZ, "%un", (unsigned int)width);
         free(n->args->argv[i].value[0]);          free(n->args->argv[i].value[0]);
         n->args->argv[i].value[0] = mandoc_strdup(buf);          n->args->argv[i].value[0] = mandoc_strdup(buf);
   
Line 1460  post_bl_block_tag(POST_ARGS)
Line 1461  post_bl_block_tag(POST_ARGS)
   
         /* Defaults to ten ens. */          /* Defaults to ten ens. */
   
         snprintf(buf, NUMSIZ, "%zun", sz);          snprintf(buf, NUMSIZ, "%un", (unsigned int)sz);
   
         /*          /*
          * We have to dynamically add this to the macro's argument list.           * We have to dynamically add this to the macro's argument list.
Line 1526  post_bl_head(POST_ARGS) 
Line 1527  post_bl_head(POST_ARGS) 
         assert(0 == np->args->argv[j].sz);          assert(0 == np->args->argv[j].sz);
   
         /*          /*
          * Accomodate for new-style groff column syntax.  Shuffle the           * Accommodate for new-style groff column syntax.  Shuffle the
          * child nodes, all of which must be TEXT, as arguments for the           * child nodes, all of which must be TEXT, as arguments for the
          * column field.  Then, delete the head children.           * column field.  Then, delete the head children.
          */           */
Line 1536  post_bl_head(POST_ARGS) 
Line 1537  post_bl_head(POST_ARGS) 
                 ((size_t)mdoc->last->nchild * sizeof(char *));                  ((size_t)mdoc->last->nchild * sizeof(char *));
   
         mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;          mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
         mdoc->last->norm->Bl.cols = (const char **)np->args->argv[j].value;          mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
   
         for (i = 0, nn = mdoc->last->child; nn; i++) {          for (i = 0, nn = mdoc->last->child; nn; i++) {
                 np->args->argv[j].value[i] = nn->string;                  np->args->argv[j].value[i] = nn->string;
Line 1710  post_rs(POST_ARGS)
Line 1711  post_rs(POST_ARGS)
         }          }
   
         /*          /*
            * Nothing to sort if only invalid nodes were found
            * inside the `Rs' body.
            */
   
           if (NULL == mdoc->last->child)
                   return(1);
   
           /*
          * The full `Rs' block needs special handling to order the           * The full `Rs' block needs special handling to order the
          * sub-elements according to `rsord'.  Pick through each element           * sub-elements according to `rsord'.  Pick through each element
          * and correctly order it.  This is a insertion sort.           * and correctly order it.  This is a insertion sort.
Line 1834  static int
Line 1843  static int
 post_sh_head(POST_ARGS)  post_sh_head(POST_ARGS)
 {  {
         char             buf[BUFSIZ];          char             buf[BUFSIZ];
           struct mdoc_node *n;
         enum mdoc_sec    sec;          enum mdoc_sec    sec;
           int              c;
   
         /*          /*
          * Process a new section.  Sections are either "named" or           * Process a new section.  Sections are either "named" or
Line 1843  post_sh_head(POST_ARGS)
Line 1854  post_sh_head(POST_ARGS)
          * manual sections.           * manual sections.
          */           */
   
         if ( ! concat(mdoc, buf, mdoc->last->child, BUFSIZ))          sec = SEC_CUSTOM;
           buf[0] = '\0';
           if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
                   mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
                 return(0);                  return(0);
           } else if (1 == c)
                   sec = a2sec(buf);
   
         sec = a2sec(buf);  
   
         /* The NAME should be first. */          /* The NAME should be first. */
   
         if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)          if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
Line 1864  post_sh_head(POST_ARGS)
Line 1878  post_sh_head(POST_ARGS)
   
         mdoc->lastsec = sec;          mdoc->lastsec = sec;
   
           /*
            * Set the section attribute for the current HEAD, for its
            * parent BLOCK, and for the HEAD children; the latter can
            * only be TEXT nodes, so no recursion is needed.
            * For other blocks and elements, including .Sh BODY, this is
            * done when allocating the node data structures, but for .Sh
            * BLOCK and HEAD, the section is still unknown at that time.
            */
   
           mdoc->last->parent->sec = sec;
           mdoc->last->sec = sec;
           for (n = mdoc->last->child; n; n = n->next)
                   n->sec = sec;
   
         /* We don't care about custom sections after this. */          /* We don't care about custom sections after this. */
   
         if (SEC_CUSTOM == sec)          if (SEC_CUSTOM == sec)
Line 1995  post_dd(POST_ARGS)
Line 2023  post_dd(POST_ARGS)
 {  {
         char              buf[DATESIZE];          char              buf[DATESIZE];
         struct mdoc_node *n;          struct mdoc_node *n;
           int               c;
   
         if (mdoc->meta.date)          if (mdoc->meta.date)
                 free(mdoc->meta.date);                  free(mdoc->meta.date);
   
         n = mdoc->last;          n = mdoc->last;
         if (NULL == n->child || '\0' == n->child->string[0]) {          if (NULL == n->child || '\0' == n->child->string[0]) {
                 mdoc->meta.date = mandoc_normdate(NULL,                  mdoc->meta.date = mandoc_normdate
                     mdoc->msg, mdoc->data, n->line, n->pos);                          (mdoc->parse, NULL, n->line, n->pos);
                 return(1);                  return(1);
         }          }
   
         if ( ! concat(mdoc, buf, n->child, DATESIZE))          buf[0] = '\0';
           if (-1 == (c = concat(buf, n->child, DATESIZE))) {
                   mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
                 return(0);                  return(0);
           }
   
         mdoc->meta.date = mandoc_normdate(buf,          assert(c);
             mdoc->msg, mdoc->data, n->line, n->pos);          mdoc->meta.date = mandoc_normdate
                   (mdoc->parse, buf, n->line, n->pos);
   
         return(1);          return(1);
 }  }
Line 2037  post_dt(POST_ARGS)
Line 2070  post_dt(POST_ARGS)
   
         if (NULL != (nn = n->child))          if (NULL != (nn = n->child))
                 for (p = nn->string; *p; p++) {                  for (p = nn->string; *p; p++) {
                         if (toupper((u_char)*p) == *p)                          if (toupper((unsigned char)*p) == *p)
                                 continue;                                  continue;
   
                         /*                          /*
Line 2083  post_dt(POST_ARGS)
Line 2116  post_dt(POST_ARGS)
          *       arch = NULL           *       arch = NULL
          */           */
   
         cp = mdoc_a2msec(nn->string);          cp = mandoc_a2msec(nn->string);
         if (cp) {          if (cp) {
                 mdoc->meta.vol = mandoc_strdup(cp);                  mdoc->meta.vol = mandoc_strdup(cp);
                 mdoc->meta.msec = mandoc_strdup(nn->string);                  mdoc->meta.msec = mandoc_strdup(nn->string);
Line 2163  post_os(POST_ARGS)
Line 2196  post_os(POST_ARGS)
 {  {
         struct mdoc_node *n;          struct mdoc_node *n;
         char              buf[BUFSIZ];          char              buf[BUFSIZ];
           int               c;
 #ifndef OSNAME  #ifndef OSNAME
         struct utsname    utsname;          struct utsname    utsname;
 #endif  #endif
Line 2170  post_os(POST_ARGS)
Line 2204  post_os(POST_ARGS)
         n = mdoc->last;          n = mdoc->last;
   
         /*          /*
          * Set the operating system by way of the `Os' macro.  Note that           * Set the operating system by way of the `Os' macro.
          * if an argument isn't provided and -DOSNAME="\"foo\"" is           * The order of precedence is:
          * provided during compilation, this value will be used instead           * 1. the argument of the `Os' macro, unless empty
          * of filling in "sysname release" from uname().           * 2. the -Ios=foo command line argument, if provided
            * 3. -DOSNAME="\"foo\"", if provided during compilation
            * 4. "sysname release" from uname(3)
          */           */
   
         if (mdoc->meta.os)          free(mdoc->meta.os);
                 free(mdoc->meta.os);  
   
         if ( ! concat(mdoc, buf, n->child, BUFSIZ))          buf[0] = '\0';
           if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
                   mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
                 return(0);                  return(0);
           }
   
         /* XXX: yes, these can all be dynamically-adjusted buffers, but          assert(c);
          * it's really not worth the extra hackery.  
          */  
   
         if ('\0' == buf[0]) {          if ('\0' == buf[0]) {
                   if (mdoc->defos) {
                           mdoc->meta.os = mandoc_strdup(mdoc->defos);
                           return(1);
                   }
 #ifdef OSNAME  #ifdef OSNAME
                 if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {                  if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
                         mdoc_nmsg(mdoc, n, MANDOCERR_MEM);                          mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
                         return(0);                          return(0);
                 }                  }
 #else /*!OSNAME */  #else /*!OSNAME */
                 if (uname(&utsname)) {                  if (-1 == uname(&utsname)) {
                         mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);                          mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
                         mdoc->meta.os = mandoc_strdup("UNKNOWN");                          mdoc->meta.os = mandoc_strdup("UNKNOWN");
                         return(post_prol(mdoc));                          return(post_prol(mdoc));
Line 2247  post_std(POST_ARGS)
Line 2287  post_std(POST_ARGS)
         return(1);          return(1);
 }  }
   
   /*
    * Concatenate a node, stopping at the first non-text.
    * Concatenation is separated by a single whitespace.
    * Returns -1 on fatal (string overrun) error, 0 if child nodes were
    * encountered, 1 otherwise.
    */
 static int  static int
 concat(struct mdoc *m, char *p, const struct mdoc_node *n, size_t sz)  concat(char *p, const struct mdoc_node *n, size_t sz)
 {  {
   
         p[0] = '\0';          for ( ; NULL != n; n = n->next) {
                   if (MDOC_TEXT != n->type)
         /*  
          * Concatenate sibling nodes together.  All siblings must be of  
          * type MDOC_TEXT or an assertion is raised.  Concatenation is  
          * separated by a single whitespace.  Returns 0 on fatal (string  
          * overrun) error.  
          */  
   
         for ( ; n; n = n->next) {  
                 assert(MDOC_TEXT == n->type);  
   
                 if (strlcat(p, n->string, sz) >= sz) {  
                         mdoc_nmsg(m, n, MANDOCERR_MEM);  
                         return(0);                          return(0);
                 }                  if ('\0' != p[0] && strlcat(p, " ", sz) >= sz)
                           return(-1);
                 if (NULL == n->next)                  if (strlcat(p, n->string, sz) >= sz)
                         continue;                          return(-1);
                   concat(p, n->child, sz);
                 if (strlcat(p, " ", sz) >= sz) {  
                         mdoc_nmsg(m, n, MANDOCERR_MEM);  
                         return(0);  
                 }  
         }          }
   
         return(1);          return(1);

Legend:
Removed from v.1.162  
changed lines
  Added in v.1.185

CVSweb