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

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

version 1.51, 2008/12/08 12:46:28 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 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 81  static int    rofffindtok(const char *);
Line 82  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               roffismsec(const char *);
   static  int               roffissec(const char **);
 static  int               roffispunct(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 124  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 328  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 ( ! roffargs(tree, tok, buf, argv))          } else if ( ! roffargs(tree, tok, buf, argv))
                 return(0);                  return(0);
Line 517  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)  roffismsec(const char *p)
 {  {
   
Line 660  roffspecial(struct rofftree *tree, int tok, const char
Line 788  roffspecial(struct rofftree *tree, int tok, const char
         case (ROFF_At):          case (ROFF_At):
                 if (0 == sz)                  if (0 == sz)
                         break;                          break;
                 if (0 == strcmp(*ordp, "v6"))                  if (0 == strcmp(*ordp, "v1"))
                         break;                          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"))                  else if (0 == strcmp(*ordp, "v7"))
                         break;                          break;
                 else if (0 == strcmp(*ordp, "32v"))                  else if (0 == strcmp(*ordp, "32v"))
Line 670  roffspecial(struct rofftree *tree, int tok, const char
Line 804  roffspecial(struct rofftree *tree, int tok, const char
                         break;                          break;
                 else if (0 == strcmp(*ordp, "V.4"))                  else if (0 == strcmp(*ordp, "V.4"))
                         break;                          break;
                 roff_err(tree, start, "invalid `At' arg");                  roff_err(tree, *ordp, "invalid `At' arg");
                 return(0);                  return(0);
   
         case (ROFF_Xr):          case (ROFF_Xr):
Line 683  roffspecial(struct rofftree *tree, int tok, const char
Line 817  roffspecial(struct rofftree *tree, int tok, const char
                 }                  }
                 /* FALLTHROUGH */                  /* FALLTHROUGH */
   
           case (ROFF_Sx):
                   /* FALLTHROUGH*/
         case (ROFF_Fn):          case (ROFF_Fn):
                 if (0 != sz)                  if (0 != sz)
                         break;                          break;
Line 704  roffspecial(struct rofftree *tree, int tok, const char
Line 840  roffspecial(struct rofftree *tree, int tok, const char
   
         case (ROFF_Rv):          case (ROFF_Rv):
                 /* FALLTHROUGH*/                  /* FALLTHROUGH*/
         case (ROFF_Sx):  
                 /* FALLTHROUGH*/  
         case (ROFF_Ex):          case (ROFF_Ex):
                 if (1 == sz)                  if (1 == sz)
                         break;                          break;
Line 1159  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 1183  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,          if ( ! (*tree->cb.roffblkin)(tree->arg, tok, argcp,
                                 (const char **)argvp))                                  (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,                                  (tree->arg, tok, argcp,
Line 1210  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,  
                                  (const char **)argvp));                                   (const char **)argvp));
         }          }
   
Line 1254  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,                                  tok, argcp, (const char **)argvp));
                          (const char **)argvp));  
 }  }
   
   
Line 1271  roff_ordered(ROFFCALL_ARGS) 
Line 1461  roff_ordered(ROFFCALL_ARGS) 
         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 1279  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)
                 ordp[0] = NULL;  
                 return(roffspecial(tree, tok, p, argcp,                  return(roffspecial(tree, tok, p, argcp,
                                         (const char **)argvp, 0, ordp));                                          (const char **)argvp, 0, ordp));
         }  
   
         i = 0;          i = 0;
         while (*argv && i < ROFF_MAXLINEARG) {          while (*argv && i < ROFF_MAXLINEARG) {
Line 1334  roff_text(ROFFCALL_ARGS) 
Line 1533  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",

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

CVSweb