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

Diff for /mandoc/tbl_opts.c between version 1.4 and 1.22

version 1.4, 2010/12/29 14:38:14 version 1.22, 2018/12/12 21:54:35
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
    * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above   * purpose with or without fee is hereby granted, provided that the above
Line 14 
Line 15 
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */   */
   #include "config.h"
   
   #include <sys/types.h>
   
 #include <ctype.h>  #include <ctype.h>
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
   
 #include "mandoc.h"  #include "mandoc.h"
   #include "tbl.h"
   #include "libmandoc.h"
 #include "libroff.h"  #include "libroff.h"
   
 enum    tbl_ident {  #define KEY_DPOINT      0
         KEY_CENTRE = 0,  #define KEY_DELIM       1
         KEY_DELIM,  #define KEY_LINESIZE    2
         KEY_EXPAND,  #define KEY_TAB         3
         KEY_BOX,  
         KEY_DBOX,  
         KEY_ALLBOX,  
         KEY_TAB,  
         KEY_LINESIZE,  
         KEY_NOKEEP,  
         KEY_DPOINT,  
         KEY_NOSPACE,  
         KEY_FRAME,  
         KEY_DFRAME,  
         KEY_MAX  
 };  
   
 struct  tbl_phrase {  struct  tbl_phrase {
         const char      *name;          const char      *name;
         int              key;          int              key;
         enum tbl_ident   ident;  
 };  };
   
 /* Handle Commonwealth/American spellings. */  static  const struct tbl_phrase keys[] = {
 #define KEY_MAXKEYS      14          {"decimalpoint", 0},
           {"delim",        0},
           {"linesize",     0},
           {"tab",          0},
           {"allbox",       TBL_OPT_ALLBOX | TBL_OPT_BOX},
           {"box",          TBL_OPT_BOX},
           {"frame",        TBL_OPT_BOX},
           {"center",       TBL_OPT_CENTRE},
           {"centre",       TBL_OPT_CENTRE},
           {"doublebox",    TBL_OPT_DBOX},
           {"doubleframe",  TBL_OPT_DBOX},
           {"expand",       TBL_OPT_EXPAND},
           {"nokeep",       TBL_OPT_NOKEEP},
           {"nospaces",     TBL_OPT_NOSPACE},
           {"nowarn",       TBL_OPT_NOWARN},
   };
   
 /* Maximum length of key name string. */  #define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0])))
 #define KEY_MAXNAME      13  
   
 /* Maximum length of key number size. */  static  void     arg(struct tbl_node *, int, const char *, int *, int);
 #define KEY_MAXNUMSZ     10  
   
 static  const struct tbl_phrase keys[KEY_MAXKEYS] = {  
         { "center",      TBL_OPT_CENTRE,        KEY_CENTRE},  
         { "centre",      TBL_OPT_CENTRE,        KEY_CENTRE},  
         { "delim",       0,                     KEY_DELIM},  
         { "expand",      TBL_OPT_EXPAND,        KEY_EXPAND},  
         { "box",         TBL_OPT_BOX,           KEY_BOX},  
         { "doublebox",   TBL_OPT_DBOX,          KEY_DBOX},  
         { "allbox",      TBL_OPT_ALLBOX,        KEY_ALLBOX},  
         { "frame",       TBL_OPT_BOX,           KEY_FRAME},  
         { "doubleframe", TBL_OPT_DBOX,          KEY_DFRAME},  
         { "tab",         0,                     KEY_TAB},  
         { "linesize",    0,                     KEY_LINESIZE},  
         { "nokeep",      TBL_OPT_NOKEEP,        KEY_NOKEEP},  
         { "decimalpoint", 0,                    KEY_DPOINT},  
         { "nospaces",    TBL_OPT_NOSPACE,       KEY_NOSPACE},  
 };  
   
 static  int              arg(struct tbl *, int, const char *, int *, int);  static void
 static  void             opt(struct tbl *, int, const char *, int *);  arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
   
 static int  
 arg(struct tbl *tbl, int ln, const char *p, int *pos, int key)  
 {  {
         int              i;          int              len, want;
         char             buf[KEY_MAXNUMSZ];  
   
         while (isspace((unsigned char)p[*pos]))          while (p[*pos] == ' ' || p[*pos] == '\t')
                 (*pos)++;                  (*pos)++;
   
         /* Arguments always begin with a parenthesis. */          /* Arguments are enclosed in parentheses. */
   
         if ('(' != p[*pos]) {          len = 0;
                 TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos);          if (p[*pos] == '(') {
                 return(0);                  (*pos)++;
                   while (p[*pos + len] != ')')
                           len++;
         }          }
   
         (*pos)++;  
   
         /*  
          * The arguments can be ANY value, so we can't just stop at the  
          * next close parenthesis (the argument can be a closed  
          * parenthesis itself).  
          */  
   
         switch (key) {          switch (key) {
         case (KEY_DELIM):          case KEY_DELIM:
                 if ('\0' == (tbl->delims[0] = p[(*pos)++])) {                  mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse,
                         TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1);                      ln, *pos, "%.*s", len, p + *pos);
                         return(0);                  want = 2;
                 }  
   
                 if ('\0' == (tbl->delims[1] = p[(*pos)++])) {  
                         TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1);  
                         return(0);  
                 }  
                 break;                  break;
         case (KEY_TAB):          case KEY_TAB:
                 if ('\0' != (tbl->tab = p[(*pos)++]))                  want = 1;
                         break;                  if (len == want)
                           tbl->opts.tab = p[*pos];
                 TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1);                  break;
                 return(0);          case KEY_LINESIZE:
         case (KEY_LINESIZE):                  want = 0;
                 for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) {                  break;
                         buf[i] = p[*pos];          case KEY_DPOINT:
                         if ( ! isdigit((unsigned char)buf[i]))                  want = 1;
                                 break;                  if (len == want)
                 }                          tbl->opts.decimal = p[*pos];
                   break;
                 if (i < KEY_MAXNUMSZ) {  
                         buf[i] = '\0';  
                         tbl->linesize = atoi(buf);  
                         break;  
                 }  
   
                 (*tbl->msg)(MANDOCERR_TBL, tbl->data, ln, *pos, NULL);  
                 return(0);  
         case (KEY_DPOINT):  
                 if ('\0' != (tbl->decimal = p[(*pos)++]))  
                         break;  
   
                 TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1);  
                 return(0);  
         default:          default:
                 abort();                  abort();
                 /* NOTREACHED */  
         }          }
   
         /* End with a close parenthesis. */          if (len == 0)
                   mandoc_msg(MANDOCERR_TBLOPT_NOARG,
                       tbl->parse, ln, *pos, keys[key].name);
           else if (want && len != want)
                   mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ,
                       tbl->parse, ln, *pos, "%s want %d have %d",
                       keys[key].name, want, len);
   
         if (')' == p[(*pos)++])          *pos += len;
                 return(1);          if (p[*pos] == ')')
                   (*pos)++;
         TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1);  
         return(0);  
 }  }
   
 static void  /*
 opt(struct tbl *tbl, int ln, const char *p, int *pos)   * Parse one line of options up to the semicolon.
    * Each option can be preceded by blanks and/or commas,
    * and some options are followed by arguments.
    */
   void
   tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
 {  {
         int              i, sv;          int              i, pos, len;
         char             buf[KEY_MAXNAME];  
   
         /*          pos = *offs;
          * Parse individual options from the stream as surrounded by          for (;;) {
          * this goto.  Each pass through the routine parses out a single                  while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',')
          * option and registers it.  Option arguments are processed in                          pos++;
          * the arg() function.  
          */  
   
 again:  /*                  if (p[pos] == ';') {
          * EBNF describing this section:                          *offs = pos + 1;
          *                          return;
          * options      ::= option_list [:space:]* [;][\n]                  }
          * option_list  ::= option option_tail  
          * option_tail  ::= [:space:]+ option_list |  
          *              ::= epsilon  
          * option       ::= [:alpha:]+ args  
          * args         ::= [:space:]* [(] [:alpha:]+ [)]  
          */  
   
         while (isspace((unsigned char)p[*pos]))                  /* Parse one option name. */
                 (*pos)++;  
   
         /* Safe exit point. */                  len = 0;
                   while (isalpha((unsigned char)p[pos + len]))
                           len++;
   
         if (';' == p[*pos])                  if (len == 0) {
                 return;                          mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA,
                               tbl->parse, ln, pos, "%c", p[pos]);
                           pos++;
                           continue;
                   }
   
         /* Copy up to first non-alpha character. */                  /* Look up the option name. */
   
         for (sv = *pos, i = 0; i < KEY_MAXNAME; i++, (*pos)++) {                  i = 0;
                 buf[i] = tolower(p[*pos]);                  while (i < KEY_MAXKEYS &&
                 if ( ! isalpha((unsigned char)buf[i]))                      (strncasecmp(p + pos, keys[i].name, len) ||
                         break;                       keys[i].name[len] != '\0'))
         }                          i++;
   
         /* Exit if buffer is empty (or overrun). */                  if (i == KEY_MAXKEYS) {
                           mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse,
         if (KEY_MAXNAME == i || 0 == i) {                              ln, pos, "%.*s", len, p + pos);
                 TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos);                          pos += len;
                 return;  
         }  
   
         buf[i] = '\0';  
   
         while (isspace((unsigned char)p[*pos]))  
                 (*pos)++;  
   
         /*  
          * Look through all of the available keys to find one that  
          * matches the input.  FIXME: hashtable this.  
          */  
   
         for (i = 0; i < KEY_MAXKEYS; i++) {  
                 if (strcmp(buf, keys[i].name))  
                         continue;                          continue;
                   }
   
                 /*                  /* Handle the option. */
                  * Note: this is more difficult to recover from, as we  
                  * can be anywhere in the option sequence and it's  
                  * harder to jump to the next.  Meanwhile, just bail out  
                  * of the sequence altogether.  
                  */  
   
                 if (keys[i].key)                  pos += len;
                         tbl->opts |= keys[i].key;                  if (keys[i].key)
                 else if ( ! arg(tbl, ln, p, pos, keys[i].ident))                          tbl->opts.opts |= keys[i].key;
                         return;                  else
                           arg(tbl, ln, p, &pos, i);
                 break;  
         }          }
   
         /*  
          * Allow us to recover from bad options by continuing to another  
          * parse sequence.  
          */  
   
         if (KEY_MAXKEYS == i)  
                 TBL_MSG(tbl, MANDOCERR_TBLOPT, ln, sv);  
   
         goto again;  
         /* NOTREACHED */  
 }  
   
 int  
 tbl_option(struct tbl *tbl, int ln, const char *p)  
 {  
         int              pos;  
   
         /*  
          * Table options are always on just one line, so automatically  
          * switch into the next input mode here.  
          */  
         tbl->part = TBL_PART_LAYOUT;  
   
         pos = 0;  
         opt(tbl, ln, p, &pos);  
   
         /* Always succeed. */  
         return(1);  
 }  }

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.22

CVSweb