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

Diff for /mandoc/Attic/terminal.c between version 1.2 and 1.12

version 1.2, 2009/03/19 16:40:49 version 1.12, 2009/03/26 16:47:13
Line 23 
Line 23 
 #include <string.h>  #include <string.h>
   
 #include "term.h"  #include "term.h"
   #include "man.h"
   #include "mdoc.h"
   
 #ifdef __linux__  extern  int               man_run(struct termp *,
 extern  size_t            strlcpy(char *, const char *, size_t);                                  const struct man *);
 extern  size_t            strlcat(char *, const char *, size_t);  extern  int               mdoc_run(struct termp *,
 #endif                                  const struct mdoc *);
   
 static  struct termp     *termp_alloc(enum termenc);  static  struct termp     *term_alloc(enum termenc);
 static  void              termp_free(struct termp *);  static  void              term_free(struct termp *);
 static  void              termp_body(struct termp *, struct termpair *,  static  void              term_pword(struct termp *, const char *, int);
                                 const struct mdoc_meta *,  static  void              term_pescape(struct termp *,
                                 const struct mdoc_node *);  
 static  void              termp_head(struct termp *,  
                                 const struct mdoc_meta *);  
 static  void              termp_foot(struct termp *,  
                                 const struct mdoc_meta *);  
 static  void              termp_pword(struct termp *, const char *, int);  
 static  void              termp_pescape(struct termp *,  
                                 const char *, int *, int);                                  const char *, int *, int);
 static  void              termp_nescape(struct termp *,  static  void              term_nescape(struct termp *,
                                 const char *, size_t);                                  const char *, size_t);
 static  void              termp_chara(struct termp *, char);  static  void              term_chara(struct termp *, char);
 static  void              termp_stringa(struct termp *,  static  void              term_stringa(struct termp *,
                                 const char *, size_t);                                  const char *, size_t);
 static  void              sanity(const struct mdoc_node *); /* XXX */  static  int               term_isopendelim(const char *, int);
   static  int               term_isclosedelim(const char *, int);
   
   
 void *  void *
 latin1_alloc(void)  
 {  
   
         return(termp_alloc(TERMENC_LATIN1));  
 }  
   
   
 void *  
 utf8_alloc(void)  
 {  
   
         return(termp_alloc(TERMENC_UTF8));  
 }  
   
   
 void *  
 ascii_alloc(void)  ascii_alloc(void)
 {  {
   
         return(termp_alloc(TERMENC_ASCII));          return(term_alloc(TERMENC_ASCII));
 }  }
   
   
 int  int
 terminal_run(void *arg, const struct mdoc *mdoc)  terminal_run(void *arg, const struct man *man,
                   const struct mdoc *mdoc)
 {  {
         struct termp    *p;          struct termp    *p;
   
         p = (struct termp *)arg;          p = (struct termp *)arg;
   
         if (NULL == p->symtab)          if (NULL == p->symtab)
                 p->symtab = ascii2htab();                  p->symtab = term_ascii2htab();
   
         termp_head(p, mdoc_meta(mdoc));          if (man)
         termp_body(p, NULL, mdoc_meta(mdoc), mdoc_node(mdoc));                  return(man_run(p, man));
         termp_foot(p, mdoc_meta(mdoc));          if (mdoc)
                   return(mdoc_run(p, mdoc));
   
         return(1);          return(1);
 }  }
Line 95  void
Line 77  void
 terminal_free(void *arg)  terminal_free(void *arg)
 {  {
   
         termp_free((struct termp *)arg);          term_free((struct termp *)arg);
 }  }
   
   
 static void  static void
 termp_free(struct termp *p)  term_free(struct termp *p)
 {  {
   
         if (p->buf)          if (p->buf)
                 free(p->buf);                  free(p->buf);
         if (TERMENC_ASCII == p->enc && p->symtab)          if (TERMENC_ASCII == p->enc && p->symtab)
                 asciifree(p->symtab);                  term_asciifree(p->symtab);
   
         free(p);          free(p);
 }  }
   
   
 static struct termp *  static struct termp *
 termp_alloc(enum termenc enc)  term_alloc(enum termenc enc)
 {  {
         struct termp *p;          struct termp *p;
   
Line 126  termp_alloc(enum termenc enc)
Line 108  termp_alloc(enum termenc enc)
 }  }
   
   
   static int
   term_isclosedelim(const char *p, int len)
   {
   
           if (1 != len)
                   return(0);
   
           switch (*p) {
           case('.'):
                   /* FALLTHROUGH */
           case(','):
                   /* FALLTHROUGH */
           case(';'):
                   /* FALLTHROUGH */
           case(':'):
                   /* FALLTHROUGH */
           case('?'):
                   /* FALLTHROUGH */
           case('!'):
                   /* FALLTHROUGH */
           case(')'):
                   /* FALLTHROUGH */
           case(']'):
                   /* FALLTHROUGH */
           case('}'):
                   return(1);
           default:
                   break;
           }
   
           return(0);
   }
   
   
   static int
   term_isopendelim(const char *p, int len)
   {
   
           if (1 != len)
                   return(0);
   
           switch (*p) {
           case('('):
                   /* FALLTHROUGH */
           case('['):
                   /* FALLTHROUGH */
           case('{'):
                   return(1);
           default:
                   break;
           }
   
           return(0);
   }
   
   
 /*  /*
  * Flush a line of text.  A "line" is loosely defined as being something   * Flush a line of text.  A "line" is loosely defined as being something
  * that should be followed by a newline, regardless of whether it's   * that should be followed by a newline, regardless of whether it's
Line 161  termp_alloc(enum termenc enc)
Line 199  termp_alloc(enum termenc enc)
  *  possible).   *  possible).
  */   */
 void  void
 flushln(struct termp *p)  term_flushln(struct termp *p)
 {  {
         int              i, j;          int              i, j;
         size_t           vsz, vis, maxvis, mmax, bp;          size_t           vsz, vis, maxvis, mmax, bp;
Line 222  flushln(struct termp *p)
Line 260  flushln(struct termp *p)
                                 for (j = 0; j < (int)p->offset; j++)                                  for (j = 0; j < (int)p->offset; j++)
                                         putchar(' ');                                          putchar(' ');
                                 vis = 0;                                  vis = 0;
                         } else if (vis + vsz > bp)                          }
                                 warnx("word breaks right margin");                  } else if (vis && vis + vsz > bp) {
                           putchar('\n');
                         /* TODO: hyphenate. */                          for (j = 0; j < (int)p->rmargin; j++)
                                   putchar(' ');
                 } else {                          vis = p->rmargin - p->offset;
                         if (vis && vis + vsz > bp) {  
                                 putchar('\n');  
                                 for (j = 0; j < (int)p->rmargin; j++)  
                                         putchar(' ');  
                                 vis = p->rmargin - p->offset;  
                         } else if (vis + vsz > bp)  
                                 warnx("word breaks right margin");  
   
                         /* TODO: hyphenate. */  
                 }                  }
   
                 /*                  /*
Line 294  flushln(struct termp *p)
Line 323  flushln(struct termp *p)
  * assertion.   * assertion.
  */   */
 void  void
 newln(struct termp *p)  term_newln(struct termp *p)
 {  {
   
         p->flags |= TERMP_NOSPACE;          p->flags |= TERMP_NOSPACE;
Line 302  newln(struct termp *p)
Line 331  newln(struct termp *p)
                 p->flags &= ~TERMP_NOLPAD;                  p->flags &= ~TERMP_NOLPAD;
                 return;                  return;
         }          }
         flushln(p);          term_flushln(p);
         p->flags &= ~TERMP_NOLPAD;          p->flags &= ~TERMP_NOLPAD;
 }  }
   
Line 314  newln(struct termp *p)
Line 343  newln(struct termp *p)
  * assertion.   * assertion.
  */   */
 void  void
 vspace(struct termp *p)  term_vspace(struct termp *p)
 {  {
   
         newln(p);          term_newln(p);
         putchar('\n');          putchar('\n');
 }  }
   
Line 329  vspace(struct termp *p)
Line 358  vspace(struct termp *p)
  * the word and put it verbatim into the output buffer.   * the word and put it verbatim into the output buffer.
  */   */
 void  void
 word(struct termp *p, const char *word)  term_word(struct termp *p, const char *word)
 {  {
         int              i, j, len;          int              i, j, len;
   
           len = (int)strlen(word);
   
         if (p->flags & TERMP_LITERAL) {          if (p->flags & TERMP_LITERAL) {
                 termp_pword(p, word, (int)strlen(word));                  term_pword(p, word, len);
                 return;                  return;
         }          }
   
         if (0 == (len = (int)strlen(word)))  
                 errx(1, "blank line not in literal context");  
   
         if (mdoc_isdelim(word)) {  
                 if ( ! (p->flags & TERMP_IGNDELIM))  
                         p->flags |= TERMP_NOSPACE;  
                 p->flags &= ~TERMP_IGNDELIM;  
         }  
   
         /* LINTED */          /* LINTED */
         for (j = i = 0; i < len; i++) {          for (j = i = 0; i < len; i++) {
                 if (' ' != word[i]) {                  if (' ' != word[i]) {
Line 363  word(struct termp *p, const char *word)
Line 385  word(struct termp *p, const char *word)
                 if (0 == j)                  if (0 == j)
                         continue;                          continue;
                 assert(i >= j);                  assert(i >= j);
                 termp_pword(p, &word[i - j], j);                  term_pword(p, &word[i - j], j);
                 j = 0;                  j = 0;
         }          }
         if (j > 0) {          if (j > 0) {
                 assert(i >= j);                  assert(i >= j);
                 termp_pword(p, &word[i - j], j);                  term_pword(p, &word[i - j], j);
         }          }
 }  }
   
   
 /*  /*
  * This is the main function for printing out nodes.  It's constituted  
  * of PRE and POST functions, which correspond to prefix and infix  
  * processing.  The termpair structure allows data to persist between  
  * prefix and postfix invocations.  
  */  
 static void  
 termp_body(struct termp *p, struct termpair *ppair,  
                 const struct mdoc_meta *meta,  
                 const struct mdoc_node *node)  
 {  
         int              dochild;  
         struct termpair  pair;  
   
         /* Some quick sanity-checking. */  
   
         sanity(node);  
   
         /* Pre-processing. */  
   
         dochild = 1;  
         pair.ppair = ppair;  
         pair.type = 0;  
         pair.offset = pair.rmargin = 0;  
         pair.flag = 0;  
         pair.count = 0;  
   
         if (MDOC_TEXT != node->type) {  
                 if (termacts[node->tok].pre)  
                         if ( ! (*termacts[node->tok].pre)(p, &pair, meta, node))  
                                 dochild = 0;  
         } else /* MDOC_TEXT == node->type */  
                 word(p, node->string);  
   
         /* Children. */  
   
         if (TERMPAIR_FLAG & pair.type)  
                 p->flags |= pair.flag;  
   
         if (dochild && node->child)  
                 termp_body(p, &pair, meta, node->child);  
   
         if (TERMPAIR_FLAG & pair.type)  
                 p->flags &= ~pair.flag;  
   
         /* Post-processing. */  
   
         if (MDOC_TEXT != node->type)  
                 if (termacts[node->tok].post)  
                         (*termacts[node->tok].post)(p, &pair, meta, node);  
   
         /* Siblings. */  
   
         if (node->next)  
                 termp_body(p, ppair, meta, node->next);  
 }  
   
   
 static void  
 termp_foot(struct termp *p, const struct mdoc_meta *meta)  
 {  
         struct tm       *tm;  
         char            *buf, *os;  
   
         if (NULL == (buf = malloc(p->rmargin)))  
                 err(1, "malloc");  
         if (NULL == (os = malloc(p->rmargin)))  
                 err(1, "malloc");  
   
         tm = localtime(&meta->date);  
   
 #ifdef __OpenBSD__  
         if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm))  
 #else  
         if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm))  
 #endif  
                 err(1, "strftime");  
   
         (void)strlcpy(os, meta->os, p->rmargin);  
   
         /*  
          * This is /slightly/ different from regular groff output  
          * because we don't have page numbers.  Print the following:  
          *  
          * OS                                            MDOCDATE  
          */  
   
         vspace(p);  
   
         p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;  
         p->rmargin = p->maxrmargin - strlen(buf);  
         p->offset = 0;  
   
         word(p, os);  
         flushln(p);  
   
         p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;  
         p->offset = p->rmargin;  
         p->rmargin = p->maxrmargin;  
         p->flags &= ~TERMP_NOBREAK;  
   
         word(p, buf);  
         flushln(p);  
   
         free(buf);  
         free(os);  
 }  
   
   
 static void  
 termp_head(struct termp *p, const struct mdoc_meta *meta)  
 {  
         char            *buf, *title;  
   
         p->rmargin = p->maxrmargin;  
         p->offset = 0;  
   
         if (NULL == (buf = malloc(p->rmargin)))  
                 err(1, "malloc");  
         if (NULL == (title = malloc(p->rmargin)))  
                 err(1, "malloc");  
   
         /*  
          * The header is strange.  It has three components, which are  
          * really two with the first duplicated.  It goes like this:  
          *  
          * IDENTIFIER              TITLE                   IDENTIFIER  
          *  
          * The IDENTIFIER is NAME(SECTION), which is the command-name  
          * (if given, or "unknown" if not) followed by the manual page  
          * section.  These are given in `Dt'.  The TITLE is a free-form  
          * string depending on the manual volume.  If not specified, it  
          * switches on the manual section.  
          */  
   
         assert(meta->vol);  
         (void)strlcpy(buf, meta->vol, p->rmargin);  
   
         if (meta->arch) {  
                 (void)strlcat(buf, " (", p->rmargin);  
                 (void)strlcat(buf, meta->arch, p->rmargin);  
                 (void)strlcat(buf, ")", p->rmargin);  
         }  
   
         (void)snprintf(title, p->rmargin, "%s(%d)",  
                         meta->title, meta->msec);  
   
         p->offset = 0;  
         p->rmargin = (p->maxrmargin - strlen(buf)) / 2;  
         p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;  
   
         word(p, title);  
         flushln(p);  
   
         p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;  
         p->offset = p->rmargin;  
         p->rmargin = p->maxrmargin - strlen(title);  
   
         word(p, buf);  
         flushln(p);  
   
         p->offset = p->rmargin;  
         p->rmargin = p->maxrmargin;  
         p->flags &= ~TERMP_NOBREAK;  
         p->flags |= TERMP_NOLPAD | TERMP_NOSPACE;  
   
         word(p, title);  
         flushln(p);  
   
         p->rmargin = p->maxrmargin;  
         p->offset = 0;  
         p->flags &= ~TERMP_NOSPACE;  
   
         free(title);  
         free(buf);  
 }  
   
   
 /*  
  * Determine the symbol indicated by an escape sequences, that is, one   * Determine the symbol indicated by an escape sequences, that is, one
  * starting with a backslash.  Once done, we pass this value into the   * starting with a backslash.  Once done, we pass this value into the
  * output buffer by way of the symbol table.   * output buffer by way of the symbol table.
  */   */
 static void  static void
 termp_nescape(struct termp *p, const char *word, size_t len)  term_nescape(struct termp *p, const char *word, size_t len)
 {  {
         const char      *rhs;          const char      *rhs;
         size_t           sz;          size_t           sz;
   
         if (NULL == (rhs = a2ascii(p->symtab, word, len, &sz)))          if (NULL == (rhs = term_a2ascii(p->symtab, word, len, &sz)))
                 return;                  return;
         termp_stringa(p, rhs, sz);          term_stringa(p, rhs, sz);
 }  }
   
   
Line 574  termp_nescape(struct termp *p, const char *word, size_
Line 418  termp_nescape(struct termp *p, const char *word, size_
  * the escape sequence (we assert upon badly-formed escape sequences).   * the escape sequence (we assert upon badly-formed escape sequences).
  */   */
 static void  static void
 termp_pescape(struct termp *p, const char *word, int *i, int len)  term_pescape(struct termp *p, const char *word, int *i, int len)
 {  {
         int              j;          int              j;
   
Line 586  termp_pescape(struct termp *p, const char *word, int *
Line 430  termp_pescape(struct termp *p, const char *word, int *
                 if (*i + 1 >= len)                  if (*i + 1 >= len)
                         return;                          return;
   
                 termp_nescape(p, &word[*i], 2);                  term_nescape(p, &word[*i], 2);
                 (*i)++;                  (*i)++;
                 return;                  return;
   
Line 601  termp_pescape(struct termp *p, const char *word, int *
Line 445  termp_pescape(struct termp *p, const char *word, int *
                         if (*i + 1 >= len)                          if (*i + 1 >= len)
                                 return;                                  return;
   
                         termp_nescape(p, &word[*i], 2);                          term_nescape(p, &word[*i], 2);
                         (*i)++;                          (*i)++;
                         return;                          return;
                 case ('['):                  case ('['):
                         break;                          break;
                 default:                  default:
                         termp_nescape(p, &word[*i], 1);                          term_nescape(p, &word[*i], 1);
                         return;                          return;
                 }                  }
   
           } else if ('f' == word[*i]) {
                   (*i)++;
                   if (*i >= len)
                           return;
                   switch (word[*i]) {
                   case ('B'):
                           p->flags |= TERMP_BOLD;
                           break;
                   case ('I'):
                           p->flags |= TERMP_UNDER;
                           break;
                   case ('P'):
                           /* FALLTHROUGH */
                   case ('R'):
                           p->flags &= ~TERMP_STYLE;
                           break;
                   default:
                           break;
                   }
                   return;
   
         } else if ('[' != word[*i]) {          } else if ('[' != word[*i]) {
                 termp_nescape(p, &word[*i], 1);                  term_nescape(p, &word[*i], 1);
                 return;                  return;
         }          }
   
Line 623  termp_pescape(struct termp *p, const char *word, int *
Line 488  termp_pescape(struct termp *p, const char *word, int *
         if (0 == word[*i])          if (0 == word[*i])
                 return;                  return;
   
         termp_nescape(p, &word[*i - j], (size_t)j);          term_nescape(p, &word[*i - j], (size_t)j);
 }  }
   
   
Line 633  termp_pescape(struct termp *p, const char *word, int *
Line 498  termp_pescape(struct termp *p, const char *word, int *
  * handles word styling.   * handles word styling.
  */   */
 static void  static void
 termp_pword(struct termp *p, const char *word, int len)  term_pword(struct termp *p, const char *word, int len)
 {  {
         int              i;          int              i;
   
         if ( ! (TERMP_NOSPACE & p->flags) &&          if (term_isclosedelim(word, len))
                         ! (TERMP_LITERAL & p->flags))                  if ( ! (TERMP_IGNDELIM & p->flags))
                 termp_chara(p, ' ');                          p->flags |= TERMP_NOSPACE;
   
           if ( ! (TERMP_NOSPACE & p->flags))
                   term_chara(p, ' ');
   
         if ( ! (p->flags & TERMP_NONOSPACE))          if ( ! (p->flags & TERMP_NONOSPACE))
                 p->flags &= ~TERMP_NOSPACE;                  p->flags &= ~TERMP_NOSPACE;
   
Line 651  termp_pword(struct termp *p, const char *word, int len
Line 519  termp_pword(struct termp *p, const char *word, int len
   
         for (i = 0; i < len; i++) {          for (i = 0; i < len; i++) {
                 if ('\\' == word[i]) {                  if ('\\' == word[i]) {
                         termp_pescape(p, word, &i, len);                          term_pescape(p, word, &i, len);
                         continue;                          continue;
                 }                  }
   
                 if (TERMP_STYLE & p->flags) {                  if (TERMP_STYLE & p->flags) {
                         if (TERMP_BOLD & p->flags) {                          if (TERMP_BOLD & p->flags) {
                                 termp_chara(p, word[i]);                                  term_chara(p, word[i]);
                                 termp_chara(p, 8);                                  term_chara(p, 8);
                         }                          }
                         if (TERMP_UNDER & p->flags) {                          if (TERMP_UNDER & p->flags) {
                                 termp_chara(p, '_');                                  term_chara(p, '_');
                                 termp_chara(p, 8);                                  term_chara(p, 8);
                         }                          }
                 }                  }
   
                 termp_chara(p, word[i]);                  term_chara(p, word[i]);
         }          }
   
           if (term_isopendelim(word, len))
                   p->flags |= TERMP_NOSPACE;
 }  }
   
   
 /*  /*
  * Like termp_chara() but for arbitrary-length buffers.  Resize the   * Like term_chara() but for arbitrary-length buffers.  Resize the
  * buffer by a factor of two (if the buffer is less than that) or the   * buffer by a factor of two (if the buffer is less than that) or the
  * buffer's size.   * buffer's size.
  */   */
 static void  static void
 termp_stringa(struct termp *p, const char *c, size_t sz)  term_stringa(struct termp *p, const char *c, size_t sz)
 {  {
         size_t           s;          size_t           s;
   
Line 706  termp_stringa(struct termp *p, const char *c, size_t s
Line 577  termp_stringa(struct termp *p, const char *c, size_t s
  * size.   * size.
  */   */
 static void  static void
 termp_chara(struct termp *p, char c)  term_chara(struct termp *p, char c)
 {  {
         size_t           s;          size_t           s;
   
Line 722  termp_chara(struct termp *p, char c)
Line 593  termp_chara(struct termp *p, char c)
         p->buf[(int)(p->col)++] = c;          p->buf[(int)(p->col)++] = c;
 }  }
   
   
 static void  
 sanity(const struct mdoc_node *n)  
 {  
   
         switch (n->type) {  
         case (MDOC_TEXT):  
                 if (n->child)  
                         errx(1, "regular form violated (1)");  
                 if (NULL == n->parent)  
                         errx(1, "regular form violated (2)");  
                 if (NULL == n->string)  
                         errx(1, "regular form violated (3)");  
                 switch (n->parent->type) {  
                 case (MDOC_TEXT):  
                         /* FALLTHROUGH */  
                 case (MDOC_ROOT):  
                         errx(1, "regular form violated (4)");  
                         /* NOTREACHED */  
                 default:  
                         break;  
                 }  
                 break;  
         case (MDOC_ELEM):  
                 if (NULL == n->parent)  
                         errx(1, "regular form violated (5)");  
                 switch (n->parent->type) {  
                 case (MDOC_TAIL):  
                         /* FALLTHROUGH */  
                 case (MDOC_BODY):  
                         /* FALLTHROUGH */  
                 case (MDOC_HEAD):  
                         break;  
                 default:  
                         errx(1, "regular form violated (6)");  
                         /* NOTREACHED */  
                 }  
                 if (n->child) switch (n->child->type) {  
                 case (MDOC_TEXT):  
                         break;  
                 default:  
                         errx(1, "regular form violated (7(");  
                         /* NOTREACHED */  
                 }  
                 break;  
         case (MDOC_HEAD):  
                 /* FALLTHROUGH */  
         case (MDOC_BODY):  
                 /* FALLTHROUGH */  
         case (MDOC_TAIL):  
                 if (NULL == n->parent)  
                         errx(1, "regular form violated (8)");  
                 if (MDOC_BLOCK != n->parent->type)  
                         errx(1, "regular form violated (9)");  
                 if (n->child) switch (n->child->type) {  
                 case (MDOC_BLOCK):  
                         /* FALLTHROUGH */  
                 case (MDOC_ELEM):  
                         /* FALLTHROUGH */  
                 case (MDOC_TEXT):  
                         break;  
                 default:  
                         errx(1, "regular form violated (a)");  
                         /* NOTREACHED */  
                 }  
                 break;  
         case (MDOC_BLOCK):  
                 if (NULL == n->parent)  
                         errx(1, "regular form violated (b)");  
                 if (NULL == n->child)  
                         errx(1, "regular form violated (c)");  
                 switch (n->parent->type) {  
                 case (MDOC_ROOT):  
                         /* FALLTHROUGH */  
                 case (MDOC_HEAD):  
                         /* FALLTHROUGH */  
                 case (MDOC_BODY):  
                         /* FALLTHROUGH */  
                 case (MDOC_TAIL):  
                         break;  
                 default:  
                         errx(1, "regular form violated (d)");  
                         /* NOTREACHED */  
                 }  
                 switch (n->child->type) {  
                 case (MDOC_ROOT):  
                         /* FALLTHROUGH */  
                 case (MDOC_ELEM):  
                         errx(1, "regular form violated (e)");  
                         /* NOTREACHED */  
                 default:  
                         break;  
                 }  
                 break;  
         case (MDOC_ROOT):  
                 if (n->parent)  
                         errx(1, "regular form violated (f)");  
                 if (NULL == n->child)  
                         errx(1, "regular form violated (10)");  
                 switch (n->child->type) {  
                 case (MDOC_BLOCK):  
                         break;  
                 default:  
                         errx(1, "regular form violated (11)");  
                         /* NOTREACHED */  
                 }  
                 break;  
         }  
 }  

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.12

CVSweb