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

Diff for /mandoc/roff.c between version 1.44 and 1.52

version 1.44, 2008/12/06 13:18:44 version 1.52, 2008/12/08 16:29:57
Line 35 
Line 35 
 /* FIXME: First letters of quoted-text interpreted in rofffindtok. */  /* FIXME: First letters of quoted-text interpreted in rofffindtok. */
 /* FIXME: `No' not implemented. */  /* FIXME: `No' not implemented. */
 /* TODO: warn if Pp occurs before/after Sh etc. (see mdoc.samples). */  /* TODO: warn if Pp occurs before/after Sh etc. (see mdoc.samples). */
 /* TODO: warn about "X section only" macros. */  
 /* TODO: warn about empty lists. */  /* TODO: warn about empty lists. */
 /* TODO: (warn) some sections need specific elements. */  /* TODO: (warn) some sections need specific elements. */
 /* TODO: (warn) NAME section has particular order. */  /* TODO: (warn) NAME section has particular order. */
Line 57  struct rofftree {
Line 56  struct rofftree {
         char              name[64];             /* `Nm' results. */          char              name[64];             /* `Nm' results. */
         char              os[64];               /* `Os' results. */          char              os[64];               /* `Os' results. */
         char              title[64];            /* `Dt' results. */          char              title[64];            /* `Dt' results. */
         char              section[64];          /* `Dt' results. */          enum roffmsec     section;
         char              volume[64];           /* `Dt' results. */          char              volume[64];           /* `Dt' results. */
         int               state;          int               state;
 #define ROFF_PRELUDE     (1 << 1)               /* In roff prelude. */  #define ROFF_PRELUDE     (1 << 1)               /* In roff prelude. */
Line 67  struct rofftree {
Line 66  struct rofftree {
 #define ROFF_BODY        (1 << 5)               /* In roff body. */  #define ROFF_BODY        (1 << 5)               /* In roff body. */
         struct roffcb     cb;                   /* Callbacks. */          struct roffcb     cb;                   /* Callbacks. */
         void             *arg;                  /* Callbacks' arg. */          void             *arg;                  /* Callbacks' arg. */
           int               csec;                 /* Current section. */
           int               asec;                 /* Thus-far sections. */
 };  };
   
 static  struct roffnode  *roffnode_new(int, struct rofftree *);  static  struct roffnode  *roffnode_new(int, struct rofftree *);
Line 80  static int    roffscan(int, const int *);
Line 81  static int    roffscan(int, const int *);
 static  int               rofffindtok(const char *);  static  int               rofffindtok(const char *);
 static  int               rofffindarg(const char *);  static  int               rofffindarg(const char *);
 static  int               rofffindcallable(const char *);  static  int               rofffindcallable(const char *);
   static  int               roffismsec(const char *);
   static  int               roffissec(const char **);
   static  int               roffispunct(const char *);
   static  int               roffchecksec(struct rofftree *,
                                   const char *, int);
 static  int               roffargs(const struct rofftree *,  static  int               roffargs(const struct rofftree *,
                                 int, char *, char **);                                  int, char *, char **);
 static  int               roffargok(int, int);  static  int               roffargok(int, int);
Line 88  static int    roffnextopt(const struct rofftree *,
Line 94  static int    roffnextopt(const struct rofftree *,
 static  int               roffparseopts(struct rofftree *, int,  static  int               roffparseopts(struct rofftree *, int,
                                 char ***, int *, char **);                                  char ***, int *, char **);
 static  int               roffcall(struct rofftree *, int, char **);  static  int               roffcall(struct rofftree *, int, char **);
   static  int               roffexit(struct rofftree *, int);
 static  int               roffparse(struct rofftree *, char *);  static  int               roffparse(struct rofftree *, char *);
 static  int               textparse(struct rofftree *, char *);  static  int               textparse(struct rofftree *, char *);
 static  int               roffdata(struct rofftree *, int, char *);  static  int               roffdata(struct rofftree *, int, char *);
 static  int               roffspecial(struct rofftree *, int,  static  int               roffspecial(struct rofftree *, int,
                                 const char *, size_t, char **);                                  const char *, const int *,
                                   const char **, size_t, char **);
 static  int               roffsetname(struct rofftree *, char **);  static  int               roffsetname(struct rofftree *, char **);
   
 #ifdef __linux__  #ifdef __linux__
Line 120  roff_free(struct rofftree *tree, int flush)
Line 128  roff_free(struct rofftree *tree, int flush)
         if (ROFF_PRELUDE & tree->state) {          if (ROFF_PRELUDE & tree->state) {
                 roff_err(tree, NULL, "prelude never finished");                  roff_err(tree, NULL, "prelude never finished");
                 goto end;                  goto end;
         }          } else if ( ! (ROFFSec_NAME & tree->asec)) {
                   roff_err(tree, NULL, "missing `NAME' section");
                   goto end;
           } else if ( ! (ROFFSec_NMASK & tree->asec))
                   roff_warn(tree, NULL, "missing suggested `NAME', "
                                   "`SYNOPSIS', `DESCRIPTION' sections");
   
         for (n = tree->last; n; n = n->parent) {          for (n = tree->last; n; n = n->parent) {
                 if (0 != tokens[n->tok].ctx)                  if (0 != tokens[n->tok].ctx)
Line 132  roff_free(struct rofftree *tree, int flush)
Line 145  roff_free(struct rofftree *tree, int flush)
   
         while (tree->last) {          while (tree->last) {
                 t = tree->last->tok;                  t = tree->last->tok;
                 if ( ! (*tokens[t].cb)(t, tree, NULL, ROFF_EXIT))                  if ( ! roffexit(tree, t))
                         goto end;                          goto end;
         }          }
   
Line 165  roff_alloc(const struct roffcb *cb, void *args)
Line 178  roff_alloc(const struct roffcb *cb, void *args)
   
         tree->state = ROFF_PRELUDE;          tree->state = ROFF_PRELUDE;
         tree->arg = args;          tree->arg = args;
           tree->section = ROFF_MSEC_MAX;
   
         (void)memcpy(&tree->cb, cb, sizeof(struct roffcb));          (void)memcpy(&tree->cb, cb, sizeof(struct roffcb));
   
Line 323  roffparse(struct rofftree *tree, char *buf)
Line 337  roffparse(struct rofftree *tree, char *buf)
                         return(1);                          return(1);
   
         if (ROFF_MAX == (tok = rofffindtok(buf + 1))) {          if (ROFF_MAX == (tok = rofffindtok(buf + 1))) {
                 roff_err(tree, buf + 1, "bogus line macro");                  roff_err(tree, buf, "bogus line macro");
                 return(0);                  return(0);
         } else if (NULL == tokens[tok].cb) {          } else if ( ! roffargs(tree, tok, buf, argv))
                 roff_err(tree, buf + 1, "unsupported macro `%s'",  
                                 toknames[tok]);  
                 return(0);                  return(0);
         }  
   
         assert(ROFF___ != tok);  
         if ( ! roffargs(tree, tok, buf, argv))  
                 return(0);  
   
         argvp = (char **)argv;          argvp = (char **)argv;
   
         /*          /*
Line 343  roffparse(struct rofftree *tree, char *buf)
Line 350  roffparse(struct rofftree *tree, char *buf)
   
         if (ROFF_PRELUDE & tree->state) {          if (ROFF_PRELUDE & tree->state) {
                 assert(NULL == tree->last);                  assert(NULL == tree->last);
                 return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));                  return(roffcall(tree, tok, argvp));
         }          }
   
         assert(ROFF_BODY & tree->state);          assert(ROFF_BODY & tree->state);
Line 374  roffparse(struct rofftree *tree, char *buf)
Line 381  roffparse(struct rofftree *tree, char *buf)
          */           */
   
         if (ROFF_LAYOUT != tokens[tok].type)          if (ROFF_LAYOUT != tokens[tok].type)
                 return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));                  return(roffcall(tree, tok, argvp));
         if (0 == tokens[tok].ctx)          if (0 == tokens[tok].ctx)
                 return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));                  return(roffcall(tree, tok, argvp));
   
         /*          /*
          * First consider implicit-end tags, like as follows:           * First consider implicit-end tags, like as follows:
Line 418  roffparse(struct rofftree *tree, char *buf)
Line 425  roffparse(struct rofftree *tree, char *buf)
                  */                   */
   
                 if (NULL == n)                  if (NULL == n)
                         return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));                          return(roffcall(tree, tok, argvp));
   
                 /*                  /*
                  * Close out all intermediary scoped blocks, then hang                   * Close out all intermediary scoped blocks, then hang
Line 427  roffparse(struct rofftree *tree, char *buf)
Line 434  roffparse(struct rofftree *tree, char *buf)
   
                 do {                  do {
                         t = tree->last->tok;                          t = tree->last->tok;
                         if ( ! (*tokens[t].cb)(t, tree, NULL, ROFF_EXIT))                          if ( ! roffexit(tree, t))
                                 return(0);                                  return(0);
                 } while (t != tok);                  } while (t != tok);
   
                 return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));                  return(roffcall(tree, tok, argvp));
         }          }
   
         /*          /*
Line 467  roffparse(struct rofftree *tree, char *buf)
Line 474  roffparse(struct rofftree *tree, char *buf)
         /* LINTED */          /* LINTED */
         do {          do {
                 t = tree->last->tok;                  t = tree->last->tok;
                 if ( ! (*tokens[t].cb)(t, tree, NULL, ROFF_EXIT))                  if ( ! roffexit(tree, t))
                         return(0);                          return(0);
         } while (t != tokens[tok].ctx);          } while (t != tokens[tok].ctx);
   
Line 519  rofffindtok(const char *buf)
Line 526  rofffindtok(const char *buf)
   
   
 static int  static int
   roffchecksec(struct rofftree *tree, const char *start, int sec)
   {
           int              prior;
   
           switch (sec) {
           case(ROFFSec_SYNOP):
                   if ((prior = ROFFSec_NAME) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_DESC):
                   if ((prior = ROFFSec_SYNOP) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_RETVAL):
                   if ((prior = ROFFSec_DESC) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_ENV):
                   if ((prior = ROFFSec_RETVAL) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_FILES):
                   if ((prior = ROFFSec_ENV) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_EX):
                   if ((prior = ROFFSec_FILES) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_DIAG):
                   if ((prior = ROFFSec_EX) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_ERRS):
                   if ((prior = ROFFSec_DIAG) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_SEEALSO):
                   if ((prior = ROFFSec_ERRS) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_STAND):
                   if ((prior = ROFFSec_SEEALSO) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_HIST):
                   if ((prior = ROFFSec_STAND) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_AUTH):
                   if ((prior = ROFFSec_HIST) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_CAVEATS):
                   if ((prior = ROFFSec_AUTH) & tree->asec)
                           return(1);
                   break;
           case(ROFFSec_BUGS):
                   if ((prior = ROFFSec_CAVEATS) & tree->asec)
                           return(1);
                   break;
           default:
                   return(1);
           }
   
           roff_warn(tree, start, "section violates conventional order");
           return(1);
   }
   
   
   static int
   roffissec(const char **p)
   {
   
           assert(*p);
           if (NULL != *(p + 1)) {
                   if (NULL != *(p + 2))
                           return(ROFFSec_OTHER);
                   if (0 == strcmp(*p, "RETURN") &&
                                   0 == strcmp(*(p + 1), "VALUES"))
                           return(ROFFSec_RETVAL);
                   if (0 == strcmp(*p, "SEE") &&
                                   0 == strcmp(*(p + 1), "ALSO"))
                           return(ROFFSec_SEEALSO);
                   return(ROFFSec_OTHER);
           }
   
           if (0 == strcmp(*p, "NAME"))
                   return(ROFFSec_NAME);
           else if (0 == strcmp(*p, "SYNOPSIS"))
                   return(ROFFSec_SYNOP);
           else if (0 == strcmp(*p, "DESCRIPTION"))
                   return(ROFFSec_DESC);
           else if (0 == strcmp(*p, "ENVIRONMENT"))
                   return(ROFFSec_ENV);
           else if (0 == strcmp(*p, "FILES"))
                   return(ROFFSec_FILES);
           else if (0 == strcmp(*p, "EXAMPLES"))
                   return(ROFFSec_EX);
           else if (0 == strcmp(*p, "DIAGNOSTICS"))
                   return(ROFFSec_DIAG);
           else if (0 == strcmp(*p, "ERRORS"))
                   return(ROFFSec_ERRS);
           else if (0 == strcmp(*p, "STANDARDS"))
                   return(ROFFSec_STAND);
           else if (0 == strcmp(*p, "HISTORY"))
                   return(ROFFSec_HIST);
           else if (0 == strcmp(*p, "AUTHORS"))
                   return(ROFFSec_AUTH);
           else if (0 == strcmp(*p, "CAVEATS"))
                   return(ROFFSec_CAVEATS);
           else if (0 == strcmp(*p, "BUGS"))
                   return(ROFFSec_BUGS);
   
           return(ROFFSec_OTHER);
   }
   
   
   static int
   roffismsec(const char *p)
   {
   
           if (0 == strcmp(p, "1"))
                   return(ROFF_MSEC_1);
           else if (0 == strcmp(p, "2"))
                   return(ROFF_MSEC_2);
           else if (0 == strcmp(p, "3"))
                   return(ROFF_MSEC_3);
           else if (0 == strcmp(p, "3p"))
                   return(ROFF_MSEC_3p);
           else if (0 == strcmp(p, "4"))
                   return(ROFF_MSEC_4);
           else if (0 == strcmp(p, "5"))
                   return(ROFF_MSEC_5);
           else if (0 == strcmp(p, "6"))
                   return(ROFF_MSEC_6);
           else if (0 == strcmp(p, "7"))
                   return(ROFF_MSEC_7);
           else if (0 == strcmp(p, "8"))
                   return(ROFF_MSEC_8);
           else if (0 == strcmp(p, "9"))
                   return(ROFF_MSEC_9);
           else if (0 == strcmp(p, "unass"))
                   return(ROFF_MSEC_UNASS);
           else if (0 == strcmp(p, "draft"))
                   return(ROFF_MSEC_DRAFT);
           else if (0 == strcmp(p, "paper"))
                   return(ROFF_MSEC_PAPER);
   
           return(ROFF_MSEC_MAX);
   }
   
   
   static int
 roffispunct(const char *p)  roffispunct(const char *p)
 {  {
   
Line 618  roffnode_free(struct rofftree *tree)
Line 779  roffnode_free(struct rofftree *tree)
   
   
 static int  static int
 roffspecial(struct rofftree *tree, int tok,  roffspecial(struct rofftree *tree, int tok, const char *start,
                 const char *start, size_t sz, char **ordp)                  const int *argc, const char **argv,
                   size_t sz, char **ordp)
 {  {
   
         switch (tok) {          switch (tok) {
           case (ROFF_At):
                   if (0 == sz)
                           break;
                   if (0 == strcmp(*ordp, "v1"))
                           break;
                   else if (0 == strcmp(*ordp, "v2"))
                           break;
                   else if (0 == strcmp(*ordp, "v3"))
                           break;
                   else if (0 == strcmp(*ordp, "v6"))
                           break;
                   else if (0 == strcmp(*ordp, "v7"))
                           break;
                   else if (0 == strcmp(*ordp, "32v"))
                           break;
                   else if (0 == strcmp(*ordp, "V.1"))
                           break;
                   else if (0 == strcmp(*ordp, "V.4"))
                           break;
                   roff_err(tree, *ordp, "invalid `At' arg");
                   return(0);
   
           case (ROFF_Xr):
                   if (2 == sz) {
                           assert(ordp[1]);
                           if (ROFF_MSEC_MAX != roffismsec(ordp[1]))
                                   break;
                           roff_warn(tree, start, "invalid `%s' manual "
                                           "section", toknames[tok]);
                   }
                   /* FALLTHROUGH */
   
           case (ROFF_Sx):
                   /* FALLTHROUGH*/
           case (ROFF_Fn):
                   if (0 != sz)
                           break;
                   roff_err(tree, start, "`%s' expects at least "
                                   "one arg", toknames[tok]);
                   return(0);
   
         case (ROFF_Nm):          case (ROFF_Nm):
                 if (0 == sz) {                  if (0 == sz) {
                         if (0 == tree->name[0]) {                          if (0 == tree->name[0]) {
Line 635  roffspecial(struct rofftree *tree, int tok, 
Line 838  roffspecial(struct rofftree *tree, int tok, 
                         return(0);                          return(0);
                 break;                  break;
   
           case (ROFF_Rv):
                   /* FALLTHROUGH*/
         case (ROFF_Ex):          case (ROFF_Ex):
                 if (0 == sz) {                  if (1 == sz)
                         roff_err(tree, start, "`Ex' expects an arg");                          break;
                         return(0);                  roff_err(tree, start, "`%s' expects one arg",
                 } else if (1 != sz) {                                  toknames[tok]);
                         roff_err(tree, start, "`Ex' expects one arg");                  return(0);
                         return(0);  
                 }  
                 break;  
   
         case (ROFF_Sm):          case (ROFF_Sm):
                 if (0 == sz) {                  if (1 != sz) {
                         roff_err(tree, start, "`Sm' expects an arg");  
                         return(0);  
                 } else if (1 != sz) {  
                         roff_err(tree, start, "`Sm' expects one arg");                          roff_err(tree, start, "`Sm' expects one arg");
                         return(0);                          return(0);
                 }                  }
Line 660  roffspecial(struct rofftree *tree, int tok, 
Line 859  roffspecial(struct rofftree *tree, int tok, 
                         return(0);                          return(0);
                 }                  }
                 break;                  break;
   
           case (ROFF_Ud):
                   /* FALLTHROUGH */
           case (ROFF_Ux):
                   /* FALLTHROUGH */
           case (ROFF_Bt):
                   if (0 != sz) {
                           roff_err(tree, start, "`%s' expects no args",
                                           toknames[tok]);
                           return(0);
                   }
                   break;
         default:          default:
                 break;                  break;
         }          }
   
         return((*tree->cb.roffspecial)          return((*tree->cb.roffspecial)(tree->arg, tok, tree->cur,
                         (tree->arg, tok, tree->cur, ordp));                                  argc, argv, (const char **)ordp));
 }  }
   
   
 static int  static int
   roffexit(struct rofftree *tree, int tok)
   {
   
           assert(tokens[tok].cb);
           return((*tokens[tok].cb)(tok, tree, NULL, ROFF_EXIT));
   }
   
   
   static int
 roffcall(struct rofftree *tree, int tok, char **argv)  roffcall(struct rofftree *tree, int tok, char **argv)
 {  {
           int              i;
           enum roffmsec    c;
   
         if (NULL == tokens[tok].cb) {          if (NULL == tokens[tok].cb) {
                 roff_err(tree, *argv, "unsupported macro `%s'",                  roff_err(tree, *argv, "`%s' is unsupported",
                                 toknames[tok]);                                  toknames[tok]);
                 return(0);                  return(0);
         }          }
         if ( ! (*tokens[tok].cb)(tok, tree, argv, ROFF_ENTER))          if (tokens[tok].sections && ROFF_MSEC_MAX != tree->section) {
                 return(0);                  i = 0;
         return(1);                  while (ROFF_MSEC_MAX !=
                                   (c = tokens[tok].sections[i++]))
                           if (c == tree->section)
                                   break;
                   if (ROFF_MSEC_MAX == c) {
                           roff_warn(tree, *argv, "`%s' is not a valid "
                                           "macro in this manual section",
                                           toknames[tok]);
                   }
           }
   
           return((*tokens[tok].cb)(tok, tree, argv, ROFF_ENTER));
 }  }
   
   
Line 907  roff_Dt(ROFFCALL_ARGS)
Line 1140  roff_Dt(ROFFCALL_ARGS)
         if (NULL == *argv) {          if (NULL == *argv) {
                 roff_err(tree, *argv, "`Dt' needs section");                  roff_err(tree, *argv, "`Dt' needs section");
                 return(0);                  return(0);
         } else if (strlcpy(tree->section, *argv, sizeof(tree->section))          }
                         >= sizeof(tree->section)) {  
                 roff_err(tree, *argv, "`Dt' section too long");          if (ROFF_MSEC_MAX == (tree->section = roffismsec(*argv))) {
                   roff_err(tree, *argv, "bad `Dt' section");
                 return(0);                  return(0);
         }          }
   
Line 953  roffsetname(struct rofftree *tree, char **ordp)
Line 1187  roffsetname(struct rofftree *tree, char **ordp)
   
   
 /* ARGSUSED */  /* ARGSUSED */
 static int  
 roff_Sm(ROFFCALL_ARGS)  
 {  
         char            *ordp[1], *p;  
   
         p = *argv++;  
         *ordp = *argv;  
   
         return(roffspecial(tree, tok, p, *ordp ? 1 : 0, ordp));  
 }  
   
   
 /* ARGSUSED */  
 static  int  static  int
 roff_Ns(ROFFCALL_ARGS)  roff_Ns(ROFFCALL_ARGS)
 {  {
Line 975  roff_Ns(ROFFCALL_ARGS)
Line 1196  roff_Ns(ROFFCALL_ARGS)
         first = (*argv++ == tree->cur);          first = (*argv++ == tree->cur);
         morep[0] = NULL;          morep[0] = NULL;
   
         if ( ! roffspecial(tree, tok, *argv, 0, morep))          if ( ! roffspecial(tree, tok, *argv, NULL, NULL, 0, morep))
                 return(0);                  return(0);
   
         while (*argv) {          while (*argv) {
Line 1053  roff_Os(ROFFCALL_ARGS)
Line 1274  roff_Os(ROFFCALL_ARGS)
         tree->state &= ~ROFF_PRELUDE;          tree->state &= ~ROFF_PRELUDE;
         tree->state |= ROFF_BODY;          tree->state |= ROFF_BODY;
   
           assert(ROFF_MSEC_MAX != tree->section);
           assert(0 != tree->title[0]);
           assert(0 != tree->os[0]);
   
         assert(NULL == tree->last);          assert(NULL == tree->last);
   
         return((*tree->cb.roffhead)(tree->arg, &tree->tm,          return((*tree->cb.roffhead)(tree->arg, &tree->tm,
Line 1068  roff_layout(ROFFCALL_ARGS) 
Line 1293  roff_layout(ROFFCALL_ARGS) 
         int              i, c, argcp[ROFF_MAXLINEARG];          int              i, c, argcp[ROFF_MAXLINEARG];
         char            *argvp[ROFF_MAXLINEARG];          char            *argvp[ROFF_MAXLINEARG];
   
           /*
            * The roff_layout function is for multi-line macros.  A layout
            * has a start and end point, which is either declared
            * explicitly or implicitly.  An explicit start and end is
            * embodied by `.Bl' and `.El', with the former being the start
            * and the latter being an end.  The `.Sh' and `.Ss' tags, on
            * the other hand, are implicit.  The scope of a layout is the
            * space between start and end.  Explicit layouts may not close
            * out implicit ones and vice versa; implicit layouts may close
            * out other implicit layouts.
            */
   
           assert( ! (ROFF_CALLABLE & tokens[tok].flags));
   
         if (ROFF_PRELUDE & tree->state) {          if (ROFF_PRELUDE & tree->state) {
                 roff_err(tree, *argv, "bad `%s' in prelude",                  roff_err(tree, *argv, "bad `%s' in prelude",
                                 toknames[tok]);                                  toknames[tok]);
Line 1092  roff_layout(ROFFCALL_ARGS) 
Line 1331  roff_layout(ROFFCALL_ARGS) 
          * Layouts have two parts: the layout body and header.  The           * Layouts have two parts: the layout body and header.  The
          * layout header is the trailing text of the line macro, while           * layout header is the trailing text of the line macro, while
          * the layout body is everything following until termination.           * the layout body is everything following until termination.
            * Example:
            *
            * .It Fl f ) ;
            * Bar.
            *
            * ...Produces...
            *
            * <block>
            *      <head>
            *              <!Fl f!> ;
            *      </head>
            *
            *      <body>
            *              Bar.
            *      </body>
            * </block>
          */           */
   
         if ( ! (*tree->cb.roffblkin)(tree->arg, tok, argcp, argvp))          if ( ! (*tree->cb.roffblkin)(tree->arg, tok, argcp,
                                   (const char **)argvp))
                 return(0);                  return(0);
   
           /* +++ Begin run macro-specific hooks over argv. */
   
           switch (tok) {
           case (ROFF_Sh):
                   if (NULL == *argv) {
                           roff_err(tree, *(argv - 1),
                                           "`Sh' expects arguments");
                           return(0);
                   }
                   tree->csec = roffissec((const char **)argv);
                   if ( ! (ROFFSec_OTHER & tree->csec) &&
                                   tree->asec & tree->csec)
                           roff_warn(tree, *argv, "section repeated");
                   if (0 == tree->asec && ! (ROFFSec_NAME & tree->csec)) {
                           roff_err(tree, *argv, "`NAME' section "
                                           "must be first");
                           return(0);
                   } else if ( ! roffchecksec(tree, *argv, tree->csec))
                           return(0);
   
                   tree->asec |= tree->csec;
                   break;
           default:
                   break;
           }
   
           /* --- End run macro-specific hooks over argv. */
   
         if (NULL == *argv)          if (NULL == *argv)
                 return((*tree->cb.roffblkbodyin)                  return((*tree->cb.roffblkbodyin)
                                 (tree->arg, tok, argcp, argvp));                                  (tree->arg, tok, argcp,
                                    (const char **)argvp));
   
         if ( ! (*tree->cb.roffblkheadin)(tree->arg, tok, argcp, argvp))          if ( ! (*tree->cb.roffblkheadin)(tree->arg, tok, argcp,
                                   (const char **)argvp))
                 return(0);                  return(0);
   
         /*          /*
Line 1116  roff_layout(ROFFCALL_ARGS) 
Line 1403  roff_layout(ROFFCALL_ARGS) 
   
                 if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))                  if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
                         return(0);                          return(0);
                 return((*tree->cb.roffblkbodyin)                  return((*tree->cb.roffblkbodyin)(tree->arg, tok, argcp,
                                 (tree->arg, tok, argcp, argvp));                                   (const char **)argvp));
         }          }
   
         /*          /*
Line 1148  roff_layout(ROFFCALL_ARGS) 
Line 1435  roff_layout(ROFFCALL_ARGS) 
                 if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))                  if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
                         return(0);                          return(0);
                 return((*tree->cb.roffblkbodyin)                  return((*tree->cb.roffblkbodyin)
                                 (tree->arg, tok, argcp, argvp));                                  (tree->arg, tok, argcp,
                                    (const char **)argvp));
         }          }
   
         /*          /*
Line 1158  roff_layout(ROFFCALL_ARGS) 
Line 1446  roff_layout(ROFFCALL_ARGS) 
   
         if ( ! roffpurgepunct(tree, argv))          if ( ! roffpurgepunct(tree, argv))
                 return(0);                  return(0);
   
         if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))          if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
                 return(0);                  return(0);
         return((*tree->cb.roffblkbodyin)          return((*tree->cb.roffblkbodyin)(tree->arg,
                         (tree->arg, tok, argcp, argvp));                                  tok, argcp, (const char **)argvp));
 }  }
   
   
Line 1170  roff_layout(ROFFCALL_ARGS) 
Line 1457  roff_layout(ROFFCALL_ARGS) 
 static int  static int
 roff_ordered(ROFFCALL_ARGS)  roff_ordered(ROFFCALL_ARGS)
 {  {
         /* FIXME: the tail-switch statement is in two different places:  
          * consolidate. */  
         int              i, first, c, argcp[ROFF_MAXLINEARG];          int              i, first, c, argcp[ROFF_MAXLINEARG];
         char            *ordp[ROFF_MAXLINEARG], *p,          char            *ordp[ROFF_MAXLINEARG], *p,
                         *argvp[ROFF_MAXLINEARG];                          *argvp[ROFF_MAXLINEARG];
   
           /*
            * Ordered macros pass their arguments directly to handlers,
            * instead of considering it free-form text.  Thus, the
            * following macro looks as follows:
            *
            * .Xr foo 1 ) ,
            *
            * .Xr arg1 arg2 punctuation
            */
   
         if (ROFF_PRELUDE & tree->state) {          if (ROFF_PRELUDE & tree->state) {
                 roff_err(tree, *argv, "`%s' disallowed in prelude",                  roff_err(tree, *argv, "`%s' disallowed in prelude",
                                 toknames[tok]);                                  toknames[tok]);
Line 1184  roff_ordered(ROFFCALL_ARGS) 
Line 1479  roff_ordered(ROFFCALL_ARGS) 
   
         first = (*argv == tree->cur);          first = (*argv == tree->cur);
         p = *argv++;          p = *argv++;
           ordp[0] = NULL;
   
         if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))          if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
                 return(0);                  return(0);
   
         if (NULL == *argv)          if (NULL == *argv)
                 return(roffspecial(tree, tok, p, 0, ordp));                  return(roffspecial(tree, tok, p, argcp,
                                           (const char **)argvp, 0, ordp));
   
         i = 0;          i = 0;
         while (*argv && i < ROFF_MAXLINEARG) {          while (*argv && i < ROFF_MAXLINEARG) {
                 c = rofffindcallable(*argv);                  c = ROFF_PARSED & tokens[tok].flags ?
                           rofffindcallable(*argv) : ROFF_MAX;
   
                 if (ROFF_MAX == c && ! roffispunct(*argv)) {                  if (ROFF_MAX == c && ! roffispunct(*argv)) {
                         ordp[i++] = *argv++;                          ordp[i++] = *argv++;
Line 1204  roff_ordered(ROFFCALL_ARGS) 
Line 1502  roff_ordered(ROFFCALL_ARGS) 
                 if (ROFF_MAX == c)                  if (ROFF_MAX == c)
                         break;                          break;
   
                 if ( ! roffspecial(tree, tok, p, (size_t)i, ordp))                  if ( ! roffspecial(tree, tok, p, argcp,
                                           (const char **)argvp,
                                           (size_t)i, ordp))
                         return(0);                          return(0);
   
                 return(roffcall(tree, c, ordp));                  return(roffcall(tree, c, argv));
         }          }
   
         assert(i != ROFF_MAXLINEARG);          assert(i != ROFF_MAXLINEARG);
         ordp[i] = NULL;          ordp[i] = NULL;
   
         if ( ! roffspecial(tree, tok, p, (size_t)i, ordp))          if ( ! roffspecial(tree, tok, p, argcp,
                                   (const char**)argvp,
                                   (size_t)i, ordp))
                 return(0);                  return(0);
   
         /* FIXME: error if there's stuff after the punctuation. */          /* FIXME: error if there's stuff after the punctuation. */
Line 1232  roff_text(ROFFCALL_ARGS) 
Line 1534  roff_text(ROFFCALL_ARGS) 
         int              i, j, first, c, argcp[ROFF_MAXLINEARG];          int              i, j, first, c, argcp[ROFF_MAXLINEARG];
         char            *argvp[ROFF_MAXLINEARG];          char            *argvp[ROFF_MAXLINEARG];
   
           /*
            * Text macros are similar to special tokens, except that
            * arguments are instead flushed as pure data: we're only
            * concerned with the macro and its arguments.  Example:
            *
            * .Fl v W f ;
            *
            * ...Produces...
            *
            * <fl> v W f </fl> ;
            */
   
         if (ROFF_PRELUDE & tree->state) {          if (ROFF_PRELUDE & tree->state) {
                 roff_err(tree, *argv, "`%s' disallowed in prelude",                  roff_err(tree, *argv, "`%s' disallowed in prelude",
                                 toknames[tok]);                                  toknames[tok]);
Line 1243  roff_text(ROFFCALL_ARGS) 
Line 1557  roff_text(ROFFCALL_ARGS) 
   
         if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))          if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
                 return(0);                  return(0);
         if ( ! (*tree->cb.roffin)(tree->arg, tok, argcp, argvp))          if ( ! (*tree->cb.roffin)(tree->arg, tok, argcp,
                                   (const char **)argvp))
                 return(0);                  return(0);
         if (NULL == *argv)          if (NULL == *argv)
                 return((*tree->cb.roffout)(tree->arg, tok));                  return((*tree->cb.roffout)(tree->arg, tok));
Line 1262  roff_text(ROFFCALL_ARGS) 
Line 1577  roff_text(ROFFCALL_ARGS) 
          * terminating punctuation.  If we encounter it and all           * terminating punctuation.  If we encounter it and all
          * subsequent tokens are punctuation, then stop processing (the           * subsequent tokens are punctuation, then stop processing (the
          * line-dominant macro will print these tokens after closure).           * line-dominant macro will print these tokens after closure).
            * If the punctuation is followed by non-punctuation, then close
            * and re-open our scope, then continue.
          */           */
   
         i = 0;          i = 0;
Line 1293  roff_text(ROFFCALL_ARGS) 
Line 1610  roff_text(ROFFCALL_ARGS) 
                                 break;                                  break;
   
                 if (argv[j]) {                  if (argv[j]) {
                           if (ROFF_LSCOPE & tokens[tok].flags) {
                                   if ( ! roffdata(tree, 0, *argv++))
                                           return(0);
                                   continue;
                           }
                           if ( ! (*tree->cb.roffout)(tree->arg, tok))
                                   return(0);
                         if ( ! roffdata(tree, 0, *argv++))                          if ( ! roffdata(tree, 0, *argv++))
                                 return(0);                                  return(0);
                           if ( ! (*tree->cb.roffin)(tree->arg, tok,
                                                   argcp,
                                                   (const char **)argvp))
                                   return(0);
   
                           i = 0;
                         continue;                          continue;
                 }                  }
   

Legend:
Removed from v.1.44  
changed lines
  Added in v.1.52

CVSweb