[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.16 and 1.17

version 1.16, 2015/01/14 22:44:55 version 1.17, 2015/01/26 00:57:22
Line 1 
Line 1 
 /*      $Id$ */  /*      $Id$ */
 /*  /*
  * Copyright (c) 2009, 2010, 2011 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 53  struct tbl_phrase {
Line 54  struct tbl_phrase {
 /* Handle Commonwealth/American spellings. */  /* Handle Commonwealth/American spellings. */
 #define KEY_MAXKEYS      14  #define KEY_MAXKEYS      14
   
 /* Maximum length of key name string. */  
 #define KEY_MAXNAME      13  
   
 /* Maximum length of key number size. */  
 #define KEY_MAXNUMSZ     10  
   
 static  const struct tbl_phrase keys[KEY_MAXKEYS] = {  static  const struct tbl_phrase keys[KEY_MAXKEYS] = {
         { "center",      TBL_OPT_CENTRE,        KEY_CENTRE},          { "center",      TBL_OPT_CENTRE,        KEY_CENTRE},
         { "centre",      TBL_OPT_CENTRE,        KEY_CENTRE},          { "centre",      TBL_OPT_CENTRE,        KEY_CENTRE},
Line 76  static const struct tbl_phrase keys[KEY_MAXKEYS] = {
Line 71  static const struct tbl_phrase keys[KEY_MAXKEYS] = {
         { "nospaces",    TBL_OPT_NOSPACE,       KEY_NOSPACE},          { "nospaces",    TBL_OPT_NOSPACE,       KEY_NOSPACE},
 };  };
   
 static  int              arg(struct tbl_node *, int,  static  void             arg(struct tbl_node *, int,
                                 const char *, int *, enum tbl_ident);                                  const char *, int *, enum tbl_ident);
 static  void             opt(struct tbl_node *, int,  
                                 const char *, int *);  
   
   
 static int  static void
 arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)  arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
 {  {
         int              i;          const char      *optname;
         char             buf[KEY_MAXNUMSZ];          int              len, want;
   
         while (isspace((unsigned char)p[*pos]))          while (isspace((unsigned char)p[*pos]))
                 (*pos)++;                  (*pos)++;
   
         /* Arguments always begin with a parenthesis. */          /* Arguments are enclosed in parentheses. */
   
         if ('(' != p[*pos]) {          len = 0;
                 mandoc_msg(MANDOCERR_TBL, tbl->parse,          if (p[*pos] == '(') {
                     ln, *pos, NULL);                  (*pos)++;
                 return(0);                  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' == p[(*pos)++]) {                  optname = "delim";
                         mandoc_msg(MANDOCERR_TBL, tbl->parse,                  want = 2;
                             ln, *pos - 1, NULL);  
                         return(0);  
                 }  
   
                 if ('\0' == p[(*pos)++]) {  
                         mandoc_msg(MANDOCERR_TBL, tbl->parse,  
                             ln, *pos - 1, NULL);  
                         return(0);  
                 }  
                 break;                  break;
         case KEY_TAB:          case KEY_TAB:
                 if ('\0' != (tbl->opts.tab = p[(*pos)++]))                  optname = "tab";
                         break;                  want = 1;
                   if (len == want)
                 mandoc_msg(MANDOCERR_TBL, tbl->parse,                          tbl->opts.tab = p[*pos];
                     ln, *pos - 1, NULL);                  break;
                 return(0);  
         case KEY_LINESIZE:          case KEY_LINESIZE:
                 for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) {                  optname = "linesize";
                         buf[i] = p[*pos];                  want = 0;
                         if ( ! isdigit((unsigned char)buf[i]))                  break;
                                 break;  
                 }  
   
                 if (i < KEY_MAXNUMSZ) {  
                         buf[i] = '\0';  
                         tbl->opts.linesize = atoi(buf);  
                         break;  
                 }  
   
                 mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);  
                 return(0);  
         case KEY_DPOINT:          case KEY_DPOINT:
                 if ('\0' != (tbl->opts.decimal = p[(*pos)++]))                  optname = "decimalpoint";
                         break;                  want = 1;
                   if (len == want)
                 mandoc_msg(MANDOCERR_TBL, tbl->parse,                          tbl->opts.decimal = p[*pos];
                     ln, *pos - 1, NULL);                  break;
                 return(0);  
         default:          default:
                 abort();                  abort();
                 /* NOTREACHED */                  /* NOTREACHED */
         }          }
   
         /* End with a close parenthesis. */          if (len == 0)
                   mandoc_msg(MANDOCERR_TBLOPT_NOARG,
                       tbl->parse, ln, *pos, optname);
           else if (want && len != want)
                   mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ,
                       tbl->parse, ln, *pos,
                       "%s want %d have %d", optname, want, len);
   
         if (')' == p[(*pos)++])          *pos += len;
                 return(1);          if (p[*pos] == ')')
                   (*pos)++;
         mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos - 1, NULL);  
         return(0);  
 }  }
   
 static void  /*
 opt(struct tbl_node *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              i, sv;          int              i, pos, len;
         char             buf[KEY_MAXNAME];  
   
         /*          pos = 0;
          * Parse individual options from the stream as surrounded by          for (;;) {
          * this goto.  Each pass through the routine parses out a single                  while (isspace((unsigned char)p[pos]) || p[pos] == ',')
          * option and registers it.  Option arguments are processed in                          pos++;
          * the arg() function.  
          */  
   
 again:  /*                  if (p[pos] == ';')
          * EBNF describing this section:                          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] = (char)tolower((unsigned char)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);
                 mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);                          pos += len;
                 return;  
         }  
   
         buf[i] = '\0';  
   
         while (isspace((unsigned char)p[*pos]) || 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.  
                  */  
   
                   pos += len;
                 if (keys[i].key)                  if (keys[i].key)
                         tbl->opts.opts |= keys[i].key;                          tbl->opts.opts |= keys[i].key;
                 else if ( ! arg(tbl, ln, p, pos, keys[i].ident))                  else
                         return;                          arg(tbl, ln, p, &pos, keys[i].ident);
   
                 break;  
         }          }
   
         /*  
          * Allow us to recover from bad options by continuing to another  
          * parse sequence.  
          */  
   
         if (KEY_MAXKEYS == i)  
                 mandoc_msg(MANDOCERR_TBLOPT, tbl->parse, ln, sv, NULL);  
   
         goto again;  
         /* NOTREACHED */  
 }  
   
 void  
 tbl_option(struct tbl_node *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);  
 }  }

Legend:
Removed from v.1.16  
changed lines
  Added in v.1.17

CVSweb