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

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

version 1.40, 2008/12/04 23:10:51 version 1.52, 2008/12/08 16:29:57
Line 30 
Line 30 
   
 #include "libmdocml.h"  #include "libmdocml.h"
 #include "private.h"  #include "private.h"
   #include "roff.h"
   
 /* 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. */
 /* TODO: unify empty-content tags a la <br />. */  /* TODO: unify empty-content tags a la <br />. */
 /* TODO: macros with a set number of arguments? */  /* TODO: macros with a set number of arguments? */
 /* TODO: validate Dt macro arguments. */  /* TODO: validate Dt macro arguments. */
   /* FIXME: Bl -diag supposed to ignore callable children. */
   /* FIXME: Nm has newline when used in NAME section. */
   
 enum    roffd {  
         ROFF_ENTER = 0,  
         ROFF_EXIT  
 };  
   
 enum    rofftype {  
         ROFF_COMMENT,  
         ROFF_TEXT,  
         ROFF_LAYOUT,  
         ROFF_SPECIAL  
 };  
   
 #define ROFFCALL_ARGS \  
         int tok, struct rofftree *tree, \  
         char *argv[], enum roffd type  
   
 struct  rofftree;  
   
 struct  rofftok {  
         int             (*cb)(ROFFCALL_ARGS);   /* Callback. */  
         const int        *args;                 /* Args (or NULL). */  
         const int        *parents;              /* Limit to parents. */  
         const int        *children;             /* Limit to kids. */  
         int               ctx;                  /* Blk-close node. */  
         enum rofftype     type;                 /* Type of macro. */  
         int               flags;  
 #define ROFF_PARSED      (1 << 0)               /* "Parsed". */  
 #define ROFF_CALLABLE    (1 << 1)               /* "Callable". */  
 #define ROFF_SHALLOW     (1 << 2)               /* Nesting block. */  
 #define ROFF_LSCOPE      (1 << 3)               /* Line scope. */  
 };  
   
 struct  roffnode {  struct  roffnode {
         int               tok;                  /* Token id. */          int               tok;                  /* Token id. */
         struct roffnode  *parent;               /* Parent (or NULL). */          struct roffnode  *parent;               /* Parent (or NULL). */
Line 83  struct rofftree {
Line 53  struct rofftree {
         struct roffnode  *last;                 /* Last parsed node. */          struct roffnode  *last;                 /* Last parsed node. */
         char             *cur;                  /* Line start. */          char             *cur;                  /* Line start. */
         struct tm         tm;                   /* `Dd' results. */          struct tm         tm;                   /* `Dd' 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 95  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  int               roff_Dd(ROFFCALL_ARGS);  
 static  int               roff_Dt(ROFFCALL_ARGS);  
 static  int               roff_Os(ROFFCALL_ARGS);  
 static  int               roff_Ns(ROFFCALL_ARGS);  
 static  int               roff_Sm(ROFFCALL_ARGS);  
 static  int               roff_layout(ROFFCALL_ARGS);  
 static  int               roff_text(ROFFCALL_ARGS);  
 static  int               roff_noop(ROFFCALL_ARGS);  
 static  int               roff_depr(ROFFCALL_ARGS);  
 static  int               roff_ordered(ROFFCALL_ARGS);  
 static  struct roffnode  *roffnode_new(int, struct rofftree *);  static  struct roffnode  *roffnode_new(int, struct rofftree *);
 static  void              roffnode_free(struct rofftree *);  static  void              roffnode_free(struct rofftree *);
 static  void              roff_warn(const struct rofftree *,  static  void              roff_warn(const struct rofftree *,
Line 118  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 126  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, char **);  static  int               roffspecial(struct rofftree *, int,
                                   const char *, const int *,
                                   const char **, size_t, char **);
   static  int               roffsetname(struct rofftree *, char **);
   
 #ifdef __linux__  #ifdef __linux__
 extern  size_t            strlcat(char *, const char *, size_t);  extern  size_t            strlcat(char *, const char *, size_t);
Line 140  extern char   *strptime(const char *, const char *,
Line 112  extern char   *strptime(const char *, const char *,
                                 struct tm *);                                  struct tm *);
 #endif  #endif
   
   
 static  const int roffarg_An[] = { ROFF_Split, ROFF_Nosplit, ROFF_ARGMAX };  
 static  const int roffarg_Bd[] = { ROFF_Ragged, ROFF_Unfilled, ROFF_Literal,  
         ROFF_File, ROFF_Offset, ROFF_Filled, ROFF_Compact, ROFF_ARGMAX };  
 static  const int roffarg_Bk[] = { ROFF_Words, ROFF_ARGMAX };  
 static  const int roffarg_Ex[] = { ROFF_Std, ROFF_ARGMAX };  
 static  const int roffarg_Rv[] = { ROFF_Std, ROFF_ARGMAX };  
 static  const int roffarg_Bl[] = { ROFF_Bullet, ROFF_Dash, ROFF_Hyphen,  
         ROFF_Item, ROFF_Enum, ROFF_Tag, ROFF_Diag, ROFF_Hang, ROFF_Ohang,  
         ROFF_Inset, ROFF_Column, ROFF_Offset, ROFF_Width, ROFF_Compact,  
         ROFF_ARGMAX };  
 static  const int roffarg_St[] = { ROFF_p1003_1_88, ROFF_p1003_1_90,  
         ROFF_p1003_1_96, ROFF_p1003_1_2001, ROFF_p1003_1_2004, ROFF_p1003_1,  
         ROFF_p1003_1b, ROFF_p1003_1b_93, ROFF_p1003_1c_95, ROFF_p1003_1g_2000,  
         ROFF_p1003_2_92, ROFF_p1387_2_95, ROFF_p1003_2, ROFF_p1387_2,  
         ROFF_isoC_90, ROFF_isoC_amd1, ROFF_isoC_tcor1, ROFF_isoC_tcor2,  
         ROFF_isoC_99, ROFF_ansiC, ROFF_ansiC_89, ROFF_ansiC_99, ROFF_ieee754,  
         ROFF_iso8802_3, ROFF_xpg3, ROFF_xpg4, ROFF_xpg4_2, ROFF_xpg4_3,  
         ROFF_xbd5, ROFF_xcu5, ROFF_xsh5, ROFF_xns5, ROFF_xns5_2d2_0,  
         ROFF_xcurses4_2, ROFF_susv2, ROFF_susv3, ROFF_svid4, ROFF_ARGMAX };  
   
 static  const int roffchild_Bl[] = { ROFF_It, ROFF_El, ROFF_MAX };  
 static  const int roffchild_Fo[] = { ROFF_Fa, ROFF_Fc, ROFF_MAX };  
 static  const int roffchild_Rs[] = { ROFF_Re, ROFF__A, ROFF__B, ROFF__D,  
         ROFF__I, ROFF__J, ROFF__N, ROFF__O, ROFF__P, ROFF__R, ROFF__T, ROFF__V,  
         ROFF_MAX };  
   
 static  const int roffparent_El[] = { ROFF_Bl, ROFF_It, ROFF_MAX };  
 static  const int roffparent_Fc[] = { ROFF_Fo, ROFF_Fa, ROFF_MAX };  
 static  const int roffparent_Oc[] = { ROFF_Oo, ROFF_MAX };  
 static  const int roffparent_It[] = { ROFF_Bl, ROFF_It, ROFF_MAX };  
 static  const int roffparent_Re[] = { ROFF_Rs, ROFF_MAX };  
   
 static  const struct rofftok tokens[ROFF_MAX] = {  
         {   roff_noop, NULL, NULL, NULL, 0, ROFF_COMMENT, 0 }, /* \" */  
         {     roff_Dd, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Dd */  
         {     roff_Dt, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Dt */  
         {     roff_Os, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Os */  
         { roff_layout, NULL, NULL, NULL, ROFF_Sh, ROFF_LAYOUT, 0 }, /* Sh */  
         { roff_layout, NULL, NULL, NULL, ROFF_Ss, ROFF_LAYOUT, 0 }, /* Ss */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Pp */ /* XXX 0 args */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_LSCOPE }, /* D1 */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_LSCOPE }, /* Dl */  
         { roff_layout, roffarg_Bd, NULL, NULL, 0, ROFF_LAYOUT, 0 },     /* Bd */  
         {   roff_noop, NULL, NULL, NULL, ROFF_Bd, ROFF_LAYOUT, 0 }, /* Ed */  
         { roff_layout, roffarg_Bl, NULL, roffchild_Bl, 0, ROFF_LAYOUT, 0 }, /* Bl */  
         {   roff_noop, NULL, roffparent_El, NULL, ROFF_Bl, ROFF_LAYOUT, 0 }, /* El */  
         { roff_layout, NULL, roffparent_It, NULL, ROFF_It, ROFF_LAYOUT, ROFF_PARSED | ROFF_SHALLOW }, /* It */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ad */ /* FIXME */  
         {   roff_text, roffarg_An, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* An */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ar */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Cd */ /* XXX man.4 only */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Cm */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Dv */ /* XXX needs arg */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Er */ /* XXX needs arg */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ev */ /* XXX needs arg */  
         {   roff_text, roffarg_Ex, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Ex */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Fa */ /* XXX needs arg */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Fd */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Fl */  
         {roff_ordered, NULL, NULL, NULL, 0, ROFF_TEXT, /*XXX*/ -1 }, /* Fn */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ft */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ic */ /* XXX needs arg */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* In */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Li */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Nd */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Nm */ /* FIXME */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE | ROFF_LSCOPE }, /* Op */  
         {   roff_depr, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Ot */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Pa */  
         {   roff_text, roffarg_Rv, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Rv */  
         {   roff_text, roffarg_St, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* St */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Va */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Vt */ /* XXX needs arg */  
         {roff_ordered, NULL, NULL, NULL, 0, ROFF_TEXT, /*XXX*/ -1 }, /* Xr */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* %A */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE}, /* %B */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %D */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE}, /* %I */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE}, /* %J */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %N */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %O */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %P */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %R */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* %T */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* %V */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ac */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ao */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE | ROFF_LSCOPE }, /* Aq */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* At */ /* XXX at most 2 args */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Bc */  
         { roff_layout, NULL, NULL, NULL, 0, ROFF_LAYOUT, 0 }, /* Bf */ /* FIXME */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Bo */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE | ROFF_LSCOPE }, /* Bq */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Bsx */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Bx */  
         {        NULL, NULL, NULL, NULL, 0, ROFF_SPECIAL, 0 },  /* Db */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Dc */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Do */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE | ROFF_LSCOPE }, /* Dq */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ec */  
         {   roff_noop, NULL, NULL, NULL, ROFF_Bf, ROFF_LAYOUT, 0 }, /* Ef */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Em */ /* XXX needs arg */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Eo */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Fx */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ms */  
         {        NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* No */  
         {     roff_Ns, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ns */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Nx */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ox */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Pc */  
         {        NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Pf */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Po */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE | ROFF_LSCOPE }, /* Pq */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Qc */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ql */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Qo */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE | ROFF_LSCOPE }, /* Qq */  
         {   roff_noop, NULL, roffparent_Re, NULL, ROFF_Rs, ROFF_LAYOUT, 0 }, /* Re */  
         { roff_layout, NULL, NULL, roffchild_Rs, 0, ROFF_LAYOUT, 0 },   /* Rs */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Sc */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* So */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE | ROFF_LSCOPE }, /* Sq */  
         {     roff_Sm, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Sm */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Sx */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Sy */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Tn */  
         {   roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ux */  
         {        NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Xc */  
         {        NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Xo */  
         { roff_layout, NULL, NULL, roffchild_Fo, 0, ROFF_LAYOUT, 0 }, /* Fo */  
         {   roff_noop, NULL, roffparent_Fc, NULL, ROFF_Fo, ROFF_LAYOUT, 0 }, /* Fc */  
         { roff_layout, NULL, NULL, NULL, 0, ROFF_LAYOUT, 0 }, /* Oo */  
         {   roff_noop, NULL, roffparent_Oc, NULL, ROFF_Oo, ROFF_LAYOUT, 0 }, /* Oc */  
         { roff_layout, roffarg_Bk, NULL, NULL, 0, ROFF_LAYOUT, 0 }, /* Bk */  
         {   roff_noop, NULL, NULL, NULL, ROFF_Bk, ROFF_LAYOUT, 0 }, /* Ek */  
         {        NULL, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Bt */  
         {        NULL, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Hf */  
         {   roff_depr, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Fr */  
         {        NULL, NULL, NULL, NULL, 0, ROFF_TEXT, 0 }, /* Ud */  
         };  
   
 #define ROFF_VALUE      (1 << 0)  
   
 static  const int tokenargs[ROFF_ARGMAX] = {  
         0,              0,              0,              0,  
         0,              ROFF_VALUE,     ROFF_VALUE,     0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         0,              0,              ROFF_VALUE,     0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         0,              0,              0,              0,  
         };  
   
 const   char *const toknamesp[ROFF_MAX] = {  
         "\\\"",         "Dd",           "Dt",           "Os",  
         "Sh",           "Ss",           "Pp",           "D1",  
         "Dl",           "Bd",           "Ed",           "Bl",  
         "El",           "It",           "Ad",           "An",  
         "Ar",           "Cd",           "Cm",           "Dv",  
         "Er",           "Ev",           "Ex",           "Fa",  
         "Fd",           "Fl",           "Fn",           "Ft",  
         "Ic",           "In",           "Li",           "Nd",  
         "Nm",           "Op",           "Ot",           "Pa",  
         "Rv",           "St",           "Va",           "Vt",  
         /* LINTED */  
         "Xr",           "\%A",          "\%B",          "\%D",  
         /* LINTED */  
         "\%I",          "\%J",          "\%N",          "\%O",  
         /* LINTED */  
         "\%P",          "\%R",          "\%T",          "\%V",  
         "Ac",           "Ao",           "Aq",           "At",  
         "Bc",           "Bf",           "Bo",           "Bq",  
         "Bsx",          "Bx",           "Db",           "Dc",  
         "Do",           "Dq",           "Ec",           "Ef",  
         "Em",           "Eo",           "Fx",           "Ms",  
         "No",           "Ns",           "Nx",           "Ox",  
         "Pc",           "Pf",           "Po",           "Pq",  
         "Qc",           "Ql",           "Qo",           "Qq",  
         "Re",           "Rs",           "Sc",           "So",  
         "Sq",           "Sm",           "Sx",           "Sy",  
         "Tn",           "Ux",           "Xc",           "Xo",  
         "Fo",           "Fc",           "Oo",           "Oc",  
         "Bk",           "Ek",           "Bt",           "Hf",  
         "Fr",           "Ud",  
         };  
   
 const   char *const tokargnamesp[ROFF_ARGMAX] = {  
         "split",                "nosplit",              "ragged",  
         "unfilled",             "literal",              "file",  
         "offset",               "bullet",               "dash",  
         "hyphen",               "item",                 "enum",  
         "tag",                  "diag",                 "hang",  
         "ohang",                "inset",                "column",  
         "width",                "compact",              "std",  
         "p1003.1-88",           "p1003.1-90",           "p1003.1-96",  
         "p1003.1-2001",         "p1003.1-2004",         "p1003.1",  
         "p1003.1b",             "p1003.1b-93",          "p1003.1c-95",  
         "p1003.1g-2000",        "p1003.2-92",           "p1387.2-95",  
         "p1003.2",              "p1387.2",              "isoC-90",  
         "isoC-amd1",            "isoC-tcor1",           "isoC-tcor2",  
         "isoC-99",              "ansiC",                "ansiC-89",  
         "ansiC-99",             "ieee754",              "iso8802-3",  
         "xpg3",                 "xpg4",                 "xpg4.2",  
         "xpg4.3",               "xbd5",                 "xcu5",  
         "xsh5",                 "xns5",                 "xns5.2d2.0",  
         "xcurses4.2",           "susv2",                "susv3",  
         "svid4",                "filled",               "words",  
         };  
   
 const   char *const *toknames = toknamesp;  
 const   char *const *tokargnames = tokargnamesp;  
   
   
 int  int
 roff_free(struct rofftree *tree, int flush)  roff_free(struct rofftree *tree, int flush)
 {  {
Line 378  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 390  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 423  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 581  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 601  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 632  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 676  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 685  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 725  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 777  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 876  roffnode_free(struct rofftree *tree)
Line 779  roffnode_free(struct rofftree *tree)
   
   
 static int  static int
 roffspecial(struct rofftree *tree, int tok, char **ordp)  roffspecial(struct rofftree *tree, int tok, const char *start,
                   const int *argc, const char **argv,
                   size_t sz, char **ordp)
 {  {
   
         return((*tree->cb.roffspecial)(tree->arg, tok,          switch (tok) {
                                 tree->cur, ordp));          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):
                   if (0 == sz) {
                           if (0 == tree->name[0]) {
                                   roff_err(tree, start, "`Nm' not set");
                                   return(0);
                           }
                           ordp[0] = tree->name;
                           ordp[1] = NULL;
                   } else if ( ! roffsetname(tree, ordp))
                           return(0);
                   break;
   
           case (ROFF_Rv):
                   /* FALLTHROUGH*/
           case (ROFF_Ex):
                   if (1 == sz)
                           break;
                   roff_err(tree, start, "`%s' expects one arg",
                                   toknames[tok]);
                   return(0);
   
           case (ROFF_Sm):
                   if (1 != sz) {
                           roff_err(tree, start, "`Sm' expects one arg");
                           return(0);
                   }
   
                   if (0 != strcmp(ordp[0], "on") &&
                                   0 != strcmp(ordp[0], "off")) {
                           roff_err(tree, start, "`Sm' has invalid argument");
                           return(0);
                   }
                   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:
                   break;
           }
   
           return((*tree->cb.roffspecial)(tree->arg, tok, tree->cur,
                                   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 1122  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 1144  roff_Dt(ROFFCALL_ARGS)
Line 1163  roff_Dt(ROFFCALL_ARGS)
 }  }
   
   
 /* ARGSUSED */  static int
 static  int  roffsetname(struct rofftree *tree, char **ordp)
 roff_Sm(ROFFCALL_ARGS)  
 {  {
         char            *morep[1], *p;  
           assert(*ordp);
   
         p = *argv++;          /* FIXME: not all sections can set this. */
   
         if (NULL == (morep[0] = *argv++)) {          if (NULL != *(ordp + 1)) {
                 roff_err(tree, p, "`Sm' expects an argument");                  roff_err(tree, *ordp, "too many `Nm' args");
                 return(0);                  return(0);
         } else if (0 != strcmp(morep[0], "on") &&          }
                         0 != strcmp(morep[0], "off")) {  
                 roff_err(tree, p, "`Sm' has invalid argument");          if (strlcpy(tree->name, *ordp, sizeof(tree->name))
                           >= sizeof(tree->name)) {
                   roff_err(tree, *ordp, "`Nm' arg too long");
                 return(0);                  return(0);
         }          }
   
         if (*argv)  
                 roff_warn(tree, *argv, "`Sm' shouldn't have arguments");  
   
         if ( ! roffspecial(tree, tok, morep))  
                 return(0);  
   
         while (*argv)  
                 if ( ! roffdata(tree, 1, *argv++))  
                         return(0);  
   
         return(1);          return(1);
 }  }
   
Line 1185  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, morep))          if ( ! roffspecial(tree, tok, *argv, NULL, NULL, 0, morep))
                 return(0);                  return(0);
   
         while (*argv) {          while (*argv) {
Line 1263  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 1278  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 1302  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 1326  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 1358  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 1368  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 1380  roff_layout(ROFFCALL_ARGS) 
Line 1457  roff_layout(ROFFCALL_ARGS) 
 static int  static int
 roff_ordered(ROFFCALL_ARGS)  roff_ordered(ROFFCALL_ARGS)
 {  {
         int              i, first, c;          int              i, first, c, argcp[ROFF_MAXLINEARG];
         char            *ordp[ROFF_MAXLINEARG];          char            *ordp[ROFF_MAXLINEARG], *p,
                           *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 1390  roff_ordered(ROFFCALL_ARGS) 
Line 1478  roff_ordered(ROFFCALL_ARGS) 
         }          }
   
         first = (*argv == tree->cur);          first = (*argv == tree->cur);
         argv++;          p = *argv++;
           ordp[0] = NULL;
   
         if (NULL == *argv) {          if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
                   return(0);
   
                 /* FIXME: satisfies number of args? */          if (NULL == *argv)
                   return(roffspecial(tree, tok, p, argcp,
                                           (const char **)argvp, 0, ordp));
   
                 ordp[0] = NULL;  
                 return(roffspecial(tree, tok, ordp));  
         }  
   
         i = 0;          i = 0;
         while (*argv && i < ROFF_MAXLINEARG) {          while (*argv && i < ROFF_MAXLINEARG) {
                 if (ROFF_MAX != (c = rofffindcallable(*argv)))                  c = ROFF_PARSED & tokens[tok].flags ?
                         return(roffcall(tree, c, argv));                          rofffindcallable(*argv) : ROFF_MAX;
                 if (roffispunct(*argv))  
                   if (ROFF_MAX == c && ! roffispunct(*argv)) {
                           ordp[i++] = *argv++;
                           continue;
                   }
                   ordp[i] = NULL;
   
                   if (ROFF_MAX == c)
                         break;                          break;
   
                 ordp[i++] = *argv++;                  if ( ! roffspecial(tree, tok, p, argcp,
                                           (const char **)argvp,
                                           (size_t)i, ordp))
                           return(0);
   
                   return(roffcall(tree, c, argv));
         }          }
   
           assert(i != ROFF_MAXLINEARG);
         ordp[i] = NULL;          ordp[i] = NULL;
   
         /* FIXME: too many or too few args? */          if ( ! roffspecial(tree, tok, p, argcp,
                                   (const char**)argvp,
         if (i == ROFF_MAXLINEARG && *argv) {                                  (size_t)i, ordp))
                 roff_err(tree, *argv, "too many args", toknames[tok]);  
                 return(0);                  return(0);
         }  
   
         /* FIXME: error if there's stuff after the punctuation. */          /* FIXME: error if there's stuff after the punctuation. */
   
         if ( ! roffspecial(tree, tok, ordp))  
                 return(0);  
   
         if ( ! first || NULL == *argv)          if ( ! first || NULL == *argv)
                 return(1);                  return(1);
   
Line 1438  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 1449  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 1468  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 1499  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.40  
changed lines
  Added in v.1.52

CVSweb