Browse Source

[4204fd] Applied my proposed changes

Francis Dupont 9 years ago
parent
commit
c4cd450f03

+ 5 - 5
doc/guide/classify.xml

@@ -161,7 +161,7 @@
 <row><entry>Hex String</entry><entry>0XABCD</entry><entry>A hexadecimal string</entry></row>
 <row><entry>Hex String</entry><entry>0XABCD</entry><entry>A hexadecimal string</entry></row>
 <row><entry>Integer</entry><entry>123</entry><entry>An integer value</entry></row>
 <row><entry>Integer</entry><entry>123</entry><entry>An integer value</entry></row>
 <row><entry>Option Text</entry><entry>option[code].text</entry><entry>The value of the option with code "code" from the packet as text</entry></row>
 <row><entry>Option Text</entry><entry>option[code].text</entry><entry>The value of the option with code "code" from the packet as text</entry></row>
-<row><entry>Option Hex</entry><entry>option[code].hex</entry><entry>The value of the option with code "code" from the packet as hex</entry></row>
+<row><entry>Option Bin</entry><entry>option[code].bin</entry><entry>The value of the option with code "code" from the packet as binary</entry></row>
           </tbody>
           </tbody>
           </tgroup>
           </tgroup>
         </table>
         </table>
@@ -178,8 +178,8 @@
       <para>
       <para>
       "option[code]" extracts the value of the option with the given code
       "option[code]" extracts the value of the option with the given code
       from the incoming packet. If the packet doesn't contain the option, it
       from the incoming packet. If the packet doesn't contain the option, it
-      returns the empty string.  The string can be presented as text or hex
-      with the ".text" or ".hex" modifiers.  In both cases only the payload
+      returns the empty string.  The string can be presented as text or binary
+      with the ".text" or ".bin" modifiers.  In both cases only the payload
       is presented; the type code and length fields are not included.
       is presented; the type code and length fields are not included.
       </para>
       </para>
 
 
@@ -297,7 +297,7 @@
     "client-classes": [<userinput>
     "client-classes": [<userinput>
         {
         {
             "name": "Client_enterprise",
             "name": "Client_enterprise",
-            "test": "substring(option[2].hex,0,6) == 0x0002AABBCCDD'",
+            "test": "substring(option[2].bin,0,6) == 0x0002AABBCCDD'",
             "option-data": [
             "option-data": [
                 {
                 {
                     "name": "dns-servers",
                     "name": "dns-servers",
@@ -370,7 +370,7 @@
     "client-classes": [
     "client-classes": [
         {
         {
             "name": "Client_enterprise",
             "name": "Client_enterprise",
-            "test": "substring(option[2].hex,0,6) == 0x0002AABBCCDD'",
+            "test": "substring(option[2].bin,0,6) == 0x0002AABBCCDD'",
             "option-data": [
             "option-data": [
                 {
                 {
                     "name": "dns-servers",
                     "name": "dns-servers",

+ 1 - 1
doc/guide/dhcp6-srv.xml

@@ -1615,7 +1615,7 @@ should include options from the isc option space:
     "client-classes": [
     "client-classes": [
         {<userinput>
         {<userinput>
             "name": "Client_enterprise",
             "name": "Client_enterprise",
-            "test": "substring(option[2].hex,0,6) == 0x0002AABBCCDD'",
+            "test": "substring(option[2].bin,0,6) == 0x0002AABBCCDD'",
             "option-data": [
             "option-data": [
                 {
                 {
                     "name": "dns-servers",
                     "name": "dns-servers",

+ 95 - 0
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc

@@ -1766,6 +1766,101 @@ TEST_F(Dhcpv4SrvTest, matchClassification) {
     EXPECT_FALSE(opt3);
     EXPECT_FALSE(opt3);
 }
 }
 
 
+// Checks if client packets are classified properly using match expressions
+// using option names
+TEST_F(Dhcpv4SrvTest, matchClassificationOptionName) {
+    NakedDhcpv4Srv srv(0);
+
+    // The router class matches incoming packets with foo in a host-name
+    string config = "{ \"interfaces-config\": {"
+        "    \"interfaces\": [ \"*\" ] }, "
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"valid-lifetime\": 4000, "
+        "\"subnet4\": [ "
+        "{   \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ], "
+        "    \"subnet\": \"192.0.2.0/24\" } ], "
+        "\"client-classes\": [ "
+        "{   \"name\": \"router\", "
+        "    \"test\": \"option[host-name].text == 'foo'\" } ] }";
+
+    ElementPtr json = Element::fromJSON(config);
+    ConstElementPtr status;
+
+    // Configure the server and make sure the config is accepted
+    EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
+    ASSERT_TRUE(status);
+    comment_ = config::parseAnswer(rcode_, status);
+    ASSERT_EQ(0, rcode_);
+
+    CfgMgr::instance().commit();
+
+    // Create a packet with enough to select the subnet
+    Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 1234));
+    query->setRemoteAddr(IOAddress("192.0.2.1"));
+
+    // Create and add a host-name option to the query
+    OptionStringPtr hostname(new OptionString(Option::V4, 12, "foo"));
+    ASSERT_TRUE(hostname);
+    query->addOption(hostname);
+
+    // Classify packets
+    srv.classifyPacket(query);
+
+    // The queey should be in the router class
+    EXPECT_TRUE(query->inClass("router"));
+}
+
+// Checks if client packets are classified properly using match expressions
+// using option names and definitions
+TEST_F(Dhcpv4SrvTest, matchClassificationOptionDef) {
+    NakedDhcpv4Srv srv(0);
+
+    // The router class matches incoming packets with foo in a defined
+    // option
+    string config = "{ \"interfaces-config\": {"
+        "    \"interfaces\": [ \"*\" ] }, "
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"valid-lifetime\": 4000, "
+        "\"subnet4\": [ "
+        "{   \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ], "
+        "    \"subnet\": \"192.0.2.0/24\" } ], "
+        "\"client-classes\": [ "
+        "{   \"name\": \"router\", "
+        "    \"test\": \"option[my-host-name].text == 'foo'\" } ], "
+        "\"option-def\": [ {"
+        "    \"name\": \"my-host-name\", "
+        "    \"code\": 250, "
+        "    \"type\": \"string\" } ] }";
+
+    ElementPtr json = Element::fromJSON(config);
+    ConstElementPtr status;
+
+    // Configure the server and make sure the config is accepted
+    EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
+    ASSERT_TRUE(status);
+    comment_ = config::parseAnswer(rcode_, status);
+    ASSERT_EQ(0, rcode_);
+
+    CfgMgr::instance().commit();
+
+    // Create a packet with enough to select the subnet
+    Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 1234));
+    query->setRemoteAddr(IOAddress("192.0.2.1"));
+
+    // Create and add a my-host-name option to the query
+    OptionStringPtr hostname(new OptionString(Option::V4, 250, "foo"));
+    ASSERT_TRUE(hostname);
+    query->addOption(hostname);
+
+    // Classify packets
+    srv.classifyPacket(query);
+
+    // The queey should be in the router class
+    EXPECT_TRUE(query->inClass("router"));
+}
+
 // Checks subnet options have the priority over class options
 // Checks subnet options have the priority over class options
 TEST_F(Dhcpv4SrvTest, subnetClassPriority) {
 TEST_F(Dhcpv4SrvTest, subnetClassPriority) {
     IfaceMgrTestConfig test_config(true);
     IfaceMgrTestConfig test_config(true);

+ 2 - 1
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -1837,6 +1837,7 @@ TEST_F(Dhcpv6SrvTest, docsisClientClassification) {
 }
 }
 
 
 // Checks if client packets are classified properly using match expressions.
 // Checks if client packets are classified properly using match expressions.
+// Note option names and definitions are used.
 TEST_F(Dhcpv6SrvTest, matchClassification) {
 TEST_F(Dhcpv6SrvTest, matchClassification) {
     IfaceMgrTestConfig test_config(true);
     IfaceMgrTestConfig test_config(true);
 
 
@@ -1866,7 +1867,7 @@ TEST_F(Dhcpv6SrvTest, matchClassification) {
         "    \"option-data\": ["
         "    \"option-data\": ["
         "        {    \"name\": \"ipv6-forwarding\", "
         "        {    \"name\": \"ipv6-forwarding\", "
         "             \"data\": \"true\" } ], "
         "             \"data\": \"true\" } ], "
-        "    \"test\": \"option[1234].text == 'foo'\" } ] }";
+        "    \"test\": \"option[host-name].text == 'foo'\" } ] }";
     ASSERT_NO_THROW(configure(config));
     ASSERT_NO_THROW(configure(config));
 
 
     // Create packets with enough to select the subnet
     // Create packets with enough to select the subnet

+ 1 - 1
src/lib/dhcp/option.cc

@@ -229,7 +229,7 @@ Option::toBinary(const bool include_header) {
         pack(buf);
         pack(buf);
 
 
     } catch (const std::exception &ex) {
     } catch (const std::exception &ex) {
-        isc_throw(OutOfRange, "unable to obtain hexadecimal representation"
+        isc_throw(OutOfRange, "unable to obtain binary representation"
                   " of option " << getType() << ": " << ex.what());
                   " of option " << getType() << ": " << ex.what());
     }
     }
     const uint8_t* option_data = static_cast<const uint8_t*>(buf.getData());
     const uint8_t* option_data = static_cast<const uint8_t*>(buf.getData());

+ 12 - 12
src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc

@@ -182,19 +182,19 @@ TEST_F(ExpressionParserTest, validExpressionWithOptionName4) {
                               "hundred4");
                               "hundred4");
 }
 }
 
 
-// Verifies that given a valid expression using .hex operator for option, the
+// Verifies that given a valid expression using .bin operator for option, the
 // ExpressionParser produces an Expression which can be evaluated against
 // ExpressionParser produces an Expression which can be evaluated against
 // a v4 packet.
 // a v4 packet.
-TEST_F(ExpressionParserTest, validExpressionWithHex4) {
-    testValidExpression<Pkt4>(Option::V4, "\"option[12].hex == 0x68756E6472656434\"",
+TEST_F(ExpressionParserTest, validExpressionWithBin4) {
+    testValidExpression<Pkt4>(Option::V4, "\"option[12].bin == 0x68756E6472656434\"",
                               "hundred4");
                               "hundred4");
 }
 }
 
 
-// Verifies that the option name can be used together with .hex operator in
+// Verifies that the option name can be used together with .bin operator in
 // the evaluated expression.
 // the evaluated expression.
-TEST_F(ExpressionParserTest, validExpressionWithOptionNameAndHex4) {
+TEST_F(ExpressionParserTest, validExpressionWithOptionNameAndBin4) {
     testValidExpression<Pkt6>(Option::V4,
     testValidExpression<Pkt6>(Option::V4,
-                              "\"option[host-name].text == 0x68756E6472656434\"",
+                              "\"option[host-name].bin == 0x68756E6472656434\"",
                               "hundred4");
                               "hundred4");
 }
 }
 
 
@@ -212,19 +212,19 @@ TEST_F(ExpressionParserTest, validExpressionWithOptionName6) {
                               "hundred6");
                               "hundred6");
 }
 }
 
 
-// Verifies that given a valid expression using .hex operator for option, the
+// Verifies that given a valid expression using .bin operator for option, the
 // ExpressionParser produces an Expression which can be evaluated against
 // ExpressionParser produces an Expression which can be evaluated against
 // a v6 packet.
 // a v6 packet.
-TEST_F(ExpressionParserTest, validExpressionWithHex6) {
-    testValidExpression<Pkt6>(Option::V6, "\"option[59].hex == 0x68756E6472656436\"",
+TEST_F(ExpressionParserTest, validExpressionWithBin6) {
+    testValidExpression<Pkt6>(Option::V6, "\"option[59].bin == 0x68756E6472656436\"",
                               "hundred6");
                               "hundred6");
 }
 }
 
 
-// Verifies that the option name can be used together with .hex operator in
+// Verifies that the option name can be used together with .bin operator in
 // the evaluated expression.
 // the evaluated expression.
-TEST_F(ExpressionParserTest, validExpressionWithOptionNameAndHex6) {
+TEST_F(ExpressionParserTest, validExpressionWithOptionNameAndBin6) {
     testValidExpression<Pkt6>(Option::V6,
     testValidExpression<Pkt6>(Option::V6,
-                              "\"option[bootfile-url].text == 0x68756E6472656436\"",
+                              "\"option[bootfile-url].bin == 0x68756E6472656436\"",
                               "hundred6");
                               "hundred6");
 }
 }
 
 

+ 3 - 3
src/lib/eval/eval.dox

@@ -85,9 +85,9 @@
 19.                 TokenPtr opt(new TokenOption($3, TokenOption::TEXTUAL));
 19.                 TokenPtr opt(new TokenOption($3, TokenOption::TEXTUAL));
 20.                 ctx.expression.push_back(opt);
 20.                 ctx.expression.push_back(opt);
 21.             }
 21.             }
-22.       | OPTION '[' INTEGER ']' DOT HEX
+22.       | OPTION '[' INTEGER ']' DOT BIN
 23.             {
 23.             {
-24.                 TokenPtr opt(new TokenOption($3, TokenOption::HEXADECIMAL));
+24.                 TokenPtr opt(new TokenOption($3, TokenOption::BINARY));
 25.                 ctx.expression.push_back(opt);
 25.                 ctx.expression.push_back(opt);
 26.              }
 26.              }
 27.       ;
 27.       ;
@@ -99,7 +99,7 @@ single token or an expression "token == token" (EQUAL has been defined as
 "==" elsewhere). Token is further
 "==" elsewhere). Token is further
 defined in lines 7-22: it may either be a string (lines 7-11),
 defined in lines 7-22: it may either be a string (lines 7-11),
 a hex string (lines 12-16), option in the textual format (lines 17-21)
 a hex string (lines 12-16), option in the textual format (lines 17-21)
-or option in a hexadecimal format (lines 22-26).
+or option in the binary format (lines 22-26).
 When the actual case is determined, the respective C++ action
 When the actual case is determined, the respective C++ action
 is executed. For example, if the token is a string, the TokenString class is
 is executed. For example, if the token is a string, the TokenString class is
 instantiated with the appropriate value and put onto the expression vector.
 instantiated with the appropriate value and put onto the expression vector.

+ 142 - 144
src/lib/eval/lexer.cc

@@ -18,7 +18,7 @@
 #define FLEX_SCANNER
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
+#define YY_FLEX_SUBMINOR_VERSION 39
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #define FLEX_BETA
 #endif
 #endif
@@ -72,7 +72,6 @@ typedef int16_t flex_int16_t;
 typedef uint16_t flex_uint16_t;
 typedef uint16_t flex_uint16_t;
 typedef int32_t flex_int32_t;
 typedef int32_t flex_int32_t;
 typedef uint32_t flex_uint32_t;
 typedef uint32_t flex_uint32_t;
-typedef uint64_t flex_uint64_t;
 #else
 #else
 typedef signed char flex_int8_t;
 typedef signed char flex_int8_t;
 typedef short int flex_int16_t;
 typedef short int flex_int16_t;
@@ -80,7 +79,6 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 
 /* Limits of integral types. */
 /* Limits of integral types. */
 #ifndef INT8_MIN
 #ifndef INT8_MIN
@@ -111,6 +109,8 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #define UINT32_MAX             (4294967295U)
 #endif
 #endif
 
 
+#endif /* ! C99 */
+
 #endif /* ! FLEXINT_H */
 #endif /* ! FLEXINT_H */
 
 
 /* %endif */
 /* %endif */
@@ -225,11 +225,18 @@ extern FILE *yyin, *yyout;
      */
      */
     #define  YY_LESS_LINENO(n) \
     #define  YY_LESS_LINENO(n) \
             do { \
             do { \
-                yy_size_t yyl;\
+                int yyl;\
                 for ( yyl = n; yyl < yyleng; ++yyl )\
                 for ( yyl = n; yyl < yyleng; ++yyl )\
                     if ( yytext[yyl] == '\n' )\
                     if ( yytext[yyl] == '\n' )\
                         --yylineno;\
                         --yylineno;\
             }while(0)
             }while(0)
+    #define YY_LINENO_REWIND_TO(dst) \
+            do {\
+                const char *p;\
+                for ( p = yy_cp-1; p >= (dst); --p)\
+                    if ( *p == '\n' )\
+                        --yylineno;\
+            }while(0)
     
     
 /* Return all but the first "n" matched characters back to the input stream. */
 /* Return all but the first "n" matched characters back to the input stream. */
 #define yyless(n) \
 #define yyless(n) \
@@ -420,7 +427,7 @@ void yyfree (void *  );
 /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */
 /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */
 /* Begin user sect3 */
 /* Begin user sect3 */
 
 
-#define yywrap(n) 1
+#define yywrap() 1
 #define YY_SKIP_YYWRAP
 #define YY_SKIP_YYWRAP
 
 
 #define FLEX_DEBUG
 #define FLEX_DEBUG
@@ -438,6 +445,8 @@ int yylineno = 1;
 extern char *yytext;
 extern char *yytext;
 #define yytext_ptr yytext
 #define yytext_ptr yytext
 
 
+/* %% [1.5] DFA */
+
 /* %if-c-only Standard (non-C++) definition */
 /* %if-c-only Standard (non-C++) definition */
 
 
 static yy_state_type yy_get_previous_state (void );
 static yy_state_type yy_get_previous_state (void );
@@ -453,7 +462,7 @@ static void yy_fatal_error (yyconst char msg[]  );
 #define YY_DO_BEFORE_ACTION \
 #define YY_DO_BEFORE_ACTION \
 	(yytext_ptr) = yy_bp; \
 	(yytext_ptr) = yy_bp; \
 /* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\
 /* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\
-	yyleng = (yy_size_t) (yy_cp - yy_bp); \
+	yyleng = (size_t) (yy_cp - yy_bp); \
 	(yy_hold_char) = *yy_cp; \
 	(yy_hold_char) = *yy_cp; \
 	*yy_cp = '\0'; \
 	*yy_cp = '\0'; \
 /* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
 /* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
@@ -469,27 +478,27 @@ struct yy_trans_info
 	flex_int32_t yy_verify;
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	flex_int32_t yy_nxt;
 	};
 	};
-static yyconst flex_int16_t yy_acclist[84] =
+static yyconst flex_int16_t yy_acclist[90] =
     {   0,
     {   0,
        21,   19,   20,    1,   19,   20,    2,   20,   19,   20,
        21,   19,   20,    1,   19,   20,    2,   20,   19,   20,
-       13,   19,   20,   14,   19,   20,   17,   19,   20,   19,
-       20,   12,   19,   20,    5,   19,   20,    5,   19,   20,
-       19,   20,   19,   20,   15,   19,   20,   16,   19,   20,
-       19,   20,   19,   20,   19,   20,   19,   20,   19,   20,
-        1,    2,    3,    5,    6,16402,16402,16402,16402,16402,
-    16402,    4, 8210,   11,16402,    9,16402,16402,16402,16402,
-    16402,16402,    8,16402,16402,16402,    7,16402,16402,16402,
-    16402,   10,16402
+       14,   19,   20,   15,   19,   20,   18,   19,   20,   19,
+       20,   13,   19,   20,    5,   19,   20,    5,   19,   20,
+       19,   20,   19,   20,16390,   16,   19,   20,   17,   19,
+       20,   19,   20,16390,   19,   20,16390,   19,   20,16390,
+       19,   20,16390,   19,   20,16390,    1,    2,    3,    5,
+        7,16390, 8198,16390,16390,16390,16390,16390,    4,   12,
+    16390,   10,16390,16390,16390,16390,16390,16390,    9,16390,
+    16390,16390,    8,16390,16390,16390,16390,   11,16390
     } ;
     } ;
 
 
-static yyconst flex_int16_t yy_accept[57] =
+static yyconst flex_int16_t yy_accept[58] =
     {   0,
     {   0,
         1,    1,    1,    2,    4,    7,    9,   11,   14,   17,
         1,    1,    1,    2,    4,    7,    9,   11,   14,   17,
-       20,   22,   25,   28,   31,   33,   35,   38,   41,   43,
-       45,   47,   49,   51,   52,   53,   53,   54,   55,   55,
-       56,   57,   58,   59,   60,   61,   62,   63,   63,   64,
-       66,   68,   69,   70,   71,   72,   73,   75,   76,   77,
-       79,   80,   81,   82,   84,   84
+       20,   22,   25,   28,   31,   33,   36,   39,   42,   45,
+       48,   51,   54,   57,   58,   59,   59,   60,   61,   61,
+       62,   62,   62,   63,   64,   65,   66,   67,   68,   69,
+       70,   72,   74,   75,   76,   77,   78,   79,   81,   82,
+       83,   85,   86,   87,   88,   90,   90
     } ;
     } ;
 
 
 static yyconst flex_int32_t yy_ec[256] =
 static yyconst flex_int32_t yy_ec[256] =
@@ -505,8 +514,8 @@ static yyconst flex_int32_t yy_ec[256] =
        14,   14,   14,   14,   14,   14,   14,   15,   14,   14,
        14,   14,   14,   14,   14,   14,   14,   15,   14,   14,
        16,    1,   17,    1,   18,    1,   19,   20,   13,   13,
        16,    1,   17,    1,   18,    1,   19,   20,   13,   13,
 
 
-       21,   13,   22,   23,   24,   14,   14,   25,   14,   26,
-       27,   28,   14,   29,   30,   31,   32,   14,   14,   33,
+       21,   13,   22,   14,   23,   14,   14,   24,   14,   25,
+       26,   27,   14,   28,   29,   30,   31,   14,   14,   32,
        14,   14,    1,    1,    1,    1,    1,    1,    1,    1,
        14,   14,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -524,74 +533,72 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
         1,    1,    1,    1,    1
     } ;
     } ;
 
 
-static yyconst flex_int32_t yy_meta[34] =
+static yyconst flex_int32_t yy_meta[33] =
     {   0,
     {   0,
-        1,    1,    2,    1,    1,    1,    1,    3,    1,    4,
-        4,    1,    4,    3,    3,    1,    1,    3,    4,    4,
-        4,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    3
+        1,    2,    3,    1,    1,    1,    1,    2,    1,    4,
+        4,    1,    4,    2,    2,    1,    2,    2,    4,    4,
+        4,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+        2,    2
     } ;
     } ;
 
 
-static yyconst flex_int16_t yy_base[59] =
+static yyconst flex_int16_t yy_base[60] =
     {   0,
     {   0,
-        0,    0,  121,  122,  118,  116,  110,  122,  122,  122,
-       24,  122,   26,   28,   98,    0,  122,  122,   77,   79,
-       67,   61,   63,   68,   50,   47,  122,   32,    0,  122,
-       38,   43,   44,   45,   46,   47,    0,   48,  122,   50,
-       52,   54,   55,   56,   72,   73,   77,   79,   80,   81,
-       84,   86,   89,   90,  122,  112,  114,   40
+        0,    0,  113,  114,  110,  108,  106,  114,  114,  114,
+       23,  114,   25,   27,   97,   37,  114,  114,   56,   18,
+       19,   20,   26,  106,  104,  102,  114,   38,    0,  114,
+       50,   51,   81,  114,   80,   35,   32,   41,   39,    0,
+       79,   78,   46,   48,   52,   55,   54,   76,   61,   59,
+       73,   65,   66,   70,   69,  114,   94,   97,   62
     } ;
     } ;
 
 
-static yyconst flex_int16_t yy_def[59] =
+static yyconst flex_int16_t yy_def[60] =
     {   0,
     {   0,
-       55,    1,   55,   55,   55,   55,   56,   55,   55,   55,
-       55,   55,   55,   55,   55,   57,   55,   55,   57,   57,
-       57,   57,   57,   55,   55,   56,   55,   55,   58,   55,
-       57,   57,   57,   57,   57,   57,   58,   55,   55,   57,
-       57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
-       57,   57,   57,   57,    0,   55,   55,   55
+       56,    1,   56,   56,   56,   56,   57,   56,   56,   56,
+       56,   56,   56,   56,   56,   58,   56,   56,   58,   19,
+       19,   19,   19,   56,   56,   57,   56,   56,   59,   56,
+       56,   19,   19,   56,   19,   19,   19,   19,   19,   59,
+       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,    0,   56,   56,   56
     } ;
     } ;
 
 
-static yyconst flex_int16_t yy_nxt[156] =
+static yyconst flex_int16_t yy_nxt[147] =
     {   0,
     {   0,
         4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
         4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
-       14,   15,   16,   16,   16,   17,   18,    4,   19,   16,
-       16,   16,   20,   16,   16,   16,   21,   16,   16,   22,
-       23,   16,   16,   28,   28,   28,   28,   28,   28,   38,
-       29,   28,   28,   37,   38,   38,   38,   38,   38,   38,
-       27,   38,   25,   38,   39,   38,   38,   38,   29,   39,
-       39,   39,   39,   39,   39,   43,   39,   40,   39,   24,
-       39,   39,   39,   38,   38,   42,   41,   45,   38,   44,
-       38,   38,   38,   36,   46,   38,   47,   38,   39,   39,
-       38,   38,   35,   39,   34,   39,   39,   39,   48,   33,
-
-       39,   32,   39,   49,   50,   39,   39,   52,   51,   30,
-       54,   53,   26,   27,   26,   26,   31,   31,   25,   24,
-       55,    3,   55,   55,   55,   55,   55,   55,   55,   55,
-       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
-       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
-       55,   55,   55,   55,   55
+       14,   15,   16,   16,   16,   17,   18,    4,   19,   20,
+       16,   16,   16,   16,   16,   21,   16,   16,   22,   23,
+       16,   16,   28,   28,   28,   28,   28,   28,   31,   29,
+       36,   33,   33,   33,   32,   37,   39,   28,   28,   33,
+       38,   31,   56,   34,   32,   33,   29,   31,   33,   42,
+       44,   43,   33,   32,   33,   40,   34,   56,   46,   33,
+       45,   33,   34,   32,   33,   33,   47,   33,   33,   35,
+       49,   48,   33,   50,   33,   51,   52,   53,   33,   33,
+       54,   55,   33,   33,   26,   26,   33,   26,   33,   33,
+
+       33,   33,   33,   41,   33,   27,   25,   24,   30,   27,
+       25,   24,   56,    3,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56
     } ;
     } ;
 
 
-static yyconst flex_int16_t yy_chk[156] =
+static yyconst flex_int16_t yy_chk[147] =
     {   0,
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,   11,   11,   13,   13,   14,   14,   31,
-       13,   28,   28,   58,   32,   33,   34,   35,   36,   38,
-       26,   40,   25,   41,   31,   42,   43,   44,   13,   32,
-       33,   34,   35,   36,   38,   35,   40,   32,   41,   24,
-       42,   43,   44,   45,   46,   34,   33,   42,   47,   36,
-       48,   49,   50,   23,   43,   51,   44,   52,   45,   46,
-       53,   54,   22,   47,   21,   48,   49,   50,   45,   20,
-
-       51,   19,   52,   46,   48,   53,   54,   51,   49,   15,
-       53,   52,   56,    7,   56,   56,   57,   57,    6,    5,
-        3,   55,   55,   55,   55,   55,   55,   55,   55,   55,
-       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
-       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
-       55,   55,   55,   55,   55
+        1,    1,   11,   11,   13,   13,   14,   14,   16,   13,
+       20,   20,   21,   22,   16,   21,   23,   28,   28,   23,
+       22,   31,   32,   16,   16,   37,   13,   19,   36,   36,
+       38,   37,   39,   19,   38,   59,   31,   32,   43,   43,
+       39,   44,   19,   19,   32,   45,   44,   47,   46,   19,
+       46,   45,   50,   47,   49,   49,   50,   52,   52,   53,
+       53,   54,   55,   54,   57,   57,   51,   57,   58,   48,
+
+       58,   42,   41,   35,   33,   26,   25,   24,   15,    7,
+        6,    5,    3,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56
     } ;
     } ;
 
 
 /* Table of booleans, true if rule could match eol. */
 /* Table of booleans, true if rule could match eol. */
@@ -605,8 +612,8 @@ int yy_flex_debug = 1;
 
 
 static yyconst flex_int16_t yy_rule_linenum[20] =
 static yyconst flex_int16_t yy_rule_linenum[20] =
     {   0,
     {   0,
-       83,   87,   93,  103,  109,  123,  124,  125,  126,  127,
-      128,  129,  130,  131,  132,  133,  134,  136,  143
+       83,   87,   93,  103,  109,  123,  130,  131,  132,  133,
+      134,  135,  136,  137,  138,  139,  140,  141,  143
     } ;
     } ;
 
 
 static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
 static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
@@ -688,7 +695,7 @@ static isc::eval::location loc;
 // by moving it ahead by yyleng bytes. yyleng specifies the length of the
 // by moving it ahead by yyleng bytes. yyleng specifies the length of the
 // currently matched token.
 // currently matched token.
 #define YY_USER_ACTION  loc.columns(yyleng);
 #define YY_USER_ACTION  loc.columns(yyleng);
-#line 692 "lexer.cc"
+#line 699 "lexer.cc"
 
 
 #define INITIAL 0
 #define INITIAL 0
 
 
@@ -806,7 +813,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  * we now use fwrite().
  */
  */
-#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
 /* %endif */
 /* %endif */
 /* %if-c++-only C++ definition */
 /* %if-c++-only C++ definition */
 /* %endif */
 /* %endif */
@@ -821,7 +828,7 @@ static int input (void );
 	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
 	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
 		{ \
 		{ \
 		int c = '*'; \
 		int c = '*'; \
-		yy_size_t n; \
+		size_t n; \
 		for ( n = 0; n < max_size && \
 		for ( n = 0; n < max_size && \
 			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
 			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
 			buf[n] = (char) c; \
@@ -927,17 +934,6 @@ YY_DECL
 	register char *yy_cp, *yy_bp;
 	register char *yy_cp, *yy_bp;
 	register int yy_act;
 	register int yy_act;
     
     
-/* %% [7.0] user's declarations go here */
-#line 76 "lexer.ll"
-
-
-
-    // Code run each time yylex is called.
-    loc.step();
-
-
-#line 940 "lexer.cc"
-
 	if ( !(yy_init) )
 	if ( !(yy_init) )
 		{
 		{
 		(yy_init) = 1;
 		(yy_init) = 1;
@@ -978,6 +974,18 @@ YY_DECL
 		yy_load_buffer_state( );
 		yy_load_buffer_state( );
 		}
 		}
 
 
+	{
+/* %% [7.0] user's declarations go here */
+#line 76 "lexer.ll"
+
+
+
+    // Code run each time yylex is called.
+    loc.step();
+
+
+#line 988 "lexer.cc"
+
 	while ( 1 )		/* loops until end-of-file is reached */
 	while ( 1 )		/* loops until end-of-file is reached */
 		{
 		{
 /* %% [8.0] yymore()-related code goes here */
 /* %% [8.0] yymore()-related code goes here */
@@ -1000,24 +1008,23 @@ YY_DECL
 yy_match:
 yy_match:
 		do
 		do
 			{
 			{
-			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 56 )
+				if ( yy_current_state >= 57 )
 					yy_c = yy_meta[(unsigned int) yy_c];
 					yy_c = yy_meta[(unsigned int) yy_c];
 				}
 				}
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 			*(yy_state_ptr)++ = yy_current_state;
 			*(yy_state_ptr)++ = yy_current_state;
 			++yy_cp;
 			++yy_cp;
 			}
 			}
-		while ( yy_current_state != 55 );
+		while ( yy_current_state != 56 );
 
 
 yy_find_action:
 yy_find_action:
 /* %% [10.0] code to find the action number goes here */
 /* %% [10.0] code to find the action number goes here */
 		yy_current_state = *--(yy_state_ptr);
 		yy_current_state = *--(yy_state_ptr);
 		(yy_lp) = yy_accept[yy_current_state];
 		(yy_lp) = yy_accept[yy_current_state];
-goto find_rule; /* Shut up GCC warning -Wall */
 find_rule: /* we branch to this label when backing up */
 find_rule: /* we branch to this label when backing up */
 		for ( ; ; ) /* until we find what rule we matched */
 		for ( ; ; ) /* until we find what rule we matched */
 			{
 			{
@@ -1150,72 +1157,72 @@ YY_RULE_SETUP
 case 6:
 case 6:
 YY_RULE_SETUP
 YY_RULE_SETUP
 #line 123 "lexer.ll"
 #line 123 "lexer.ll"
-return isc::eval::EvalParser::make_EQUAL(loc);
+{
+    // This string specifies option name starting with a letter
+    // and further containing letters, digits, hyphens and
+    // underscores and finishing by letters or digits.
+    return isc::eval::EvalParser::make_OPTION_NAME(yytext, loc);
+}
 	YY_BREAK
 	YY_BREAK
 case 7:
 case 7:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 124 "lexer.ll"
-return isc::eval::EvalParser::make_OPTION(loc);
+#line 130 "lexer.ll"
+return isc::eval::EvalParser::make_EQUAL(loc);
 	YY_BREAK
 	YY_BREAK
 case 8:
 case 8:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 125 "lexer.ll"
-return isc::eval::EvalParser::make_TEXT(loc);
+#line 131 "lexer.ll"
+return isc::eval::EvalParser::make_OPTION(loc);
 	YY_BREAK
 	YY_BREAK
 case 9:
 case 9:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 126 "lexer.ll"
-return isc::eval::EvalParser::make_HEX(loc);
+#line 132 "lexer.ll"
+return isc::eval::EvalParser::make_TEXT(loc);
 	YY_BREAK
 	YY_BREAK
 case 10:
 case 10:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 127 "lexer.ll"
-return isc::eval::EvalParser::make_SUBSTRING(loc);
+#line 133 "lexer.ll"
+return isc::eval::EvalParser::make_BIN(loc);
 	YY_BREAK
 	YY_BREAK
 case 11:
 case 11:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 128 "lexer.ll"
-return isc::eval::EvalParser::make_ALL(loc);
+#line 134 "lexer.ll"
+return isc::eval::EvalParser::make_SUBSTRING(loc);
 	YY_BREAK
 	YY_BREAK
 case 12:
 case 12:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 129 "lexer.ll"
-return isc::eval::EvalParser::make_DOT(loc);
+#line 135 "lexer.ll"
+return isc::eval::EvalParser::make_ALL(loc);
 	YY_BREAK
 	YY_BREAK
 case 13:
 case 13:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 130 "lexer.ll"
-return isc::eval::EvalParser::make_LPAREN(loc);
+#line 136 "lexer.ll"
+return isc::eval::EvalParser::make_DOT(loc);
 	YY_BREAK
 	YY_BREAK
 case 14:
 case 14:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 131 "lexer.ll"
-return isc::eval::EvalParser::make_RPAREN(loc);
+#line 137 "lexer.ll"
+return isc::eval::EvalParser::make_LPAREN(loc);
 	YY_BREAK
 	YY_BREAK
 case 15:
 case 15:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 132 "lexer.ll"
-return isc::eval::EvalParser::make_LBRACKET(loc);
+#line 138 "lexer.ll"
+return isc::eval::EvalParser::make_RPAREN(loc);
 	YY_BREAK
 	YY_BREAK
 case 16:
 case 16:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 133 "lexer.ll"
-return isc::eval::EvalParser::make_RBRACKET(loc);
+#line 139 "lexer.ll"
+return isc::eval::EvalParser::make_LBRACKET(loc);
 	YY_BREAK
 	YY_BREAK
 case 17:
 case 17:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 134 "lexer.ll"
-return isc::eval::EvalParser::make_COMA(loc);
+#line 140 "lexer.ll"
+return isc::eval::EvalParser::make_RBRACKET(loc);
 	YY_BREAK
 	YY_BREAK
 case 18:
 case 18:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 136 "lexer.ll"
-{
-    // This string specifies option name starting with a letter
-    // and further containing letters, digits, hyphens and
-    // underscores.
-    return isc::eval::EvalParser::make_OPTION_NAME(yytext, loc);
-}
+#line 141 "lexer.ll"
+return isc::eval::EvalParser::make_COMA(loc);
 	YY_BREAK
 	YY_BREAK
 case 19:
 case 19:
 YY_RULE_SETUP
 YY_RULE_SETUP
@@ -1231,7 +1238,7 @@ YY_RULE_SETUP
 #line 145 "lexer.ll"
 #line 145 "lexer.ll"
 ECHO;
 ECHO;
 	YY_BREAK
 	YY_BREAK
-#line 1235 "lexer.cc"
+#line 1242 "lexer.cc"
 
 
 	case YY_END_OF_BUFFER:
 	case YY_END_OF_BUFFER:
 		{
 		{
@@ -1361,6 +1368,7 @@ ECHO;
 			"fatal flex scanner internal error--no action found" );
 			"fatal flex scanner internal error--no action found" );
 	} /* end of action switch */
 	} /* end of action switch */
 		} /* end of scanning one token */
 		} /* end of scanning one token */
+	} /* end of user's declarations */
 } /* end of yylex */
 } /* end of yylex */
 /* %ok-for-header */
 /* %ok-for-header */
 
 
@@ -1511,7 +1519,7 @@ static int yy_get_next_buffer (void)
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 56 )
+			if ( yy_current_state >= 57 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1539,15 +1547,15 @@ static int yy_get_next_buffer (void)
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 56 )
+		if ( yy_current_state >= 57 )
 			yy_c = yy_meta[(unsigned int) yy_c];
 			yy_c = yy_meta[(unsigned int) yy_c];
 		}
 		}
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 55);
+	yy_is_jam = (yy_current_state == 56);
 	if ( ! yy_is_jam )
 	if ( ! yy_is_jam )
 		*(yy_state_ptr)++ = yy_current_state;
 		*(yy_state_ptr)++ = yy_current_state;
 
 
-	return yy_is_jam ? 0 : yy_current_state;
+		return yy_is_jam ? 0 : yy_current_state;
 }
 }
 
 
 /* %if-c-only */
 /* %if-c-only */
@@ -1606,7 +1614,7 @@ static int yy_get_next_buffer (void)
 				case EOB_ACT_END_OF_FILE:
 				case EOB_ACT_END_OF_FILE:
 					{
 					{
 					if ( yywrap( ) )
 					if ( yywrap( ) )
-						return 0;
+						return EOF;
 
 
 					if ( ! (yy_did_buffer_switch_on_eof) )
 					if ( ! (yy_did_buffer_switch_on_eof) )
 						YY_NEW_FILE;
 						YY_NEW_FILE;
@@ -1770,17 +1778,6 @@ static void yy_load_buffer_state  (void)
 	yyfree((void *) b  );
 	yyfree((void *) b  );
 }
 }
 
 
-/* %if-c-only */
-
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-    
-/* %endif */
-
-/* %if-c++-only */
-/* %endif */
-
 /* Initializes or reinitializes a buffer.
 /* Initializes or reinitializes a buffer.
  * This function is sometimes called more than once on the same buffer,
  * This function is sometimes called more than once on the same buffer,
  * such as during a yyrestart() or at EOF.
  * such as during a yyrestart() or at EOF.
@@ -2021,8 +2018,8 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
 /* %if-c-only */
 /* %if-c-only */
 /** Setup the input buffer state to scan the given bytes. The next call to yylex() will
 /** Setup the input buffer state to scan the given bytes. The next call to yylex() will
  * scan from a @e copy of @a bytes.
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
  * 
  * 
  * @return the newly allocated buffer state object.
  * @return the newly allocated buffer state object.
  */
  */
@@ -2030,7 +2027,8 @@ YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len
 {
 {
 	YY_BUFFER_STATE b;
 	YY_BUFFER_STATE b;
 	char *buf;
 	char *buf;
-	yy_size_t n, i;
+	yy_size_t n;
+	yy_size_t i;
     
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
 	/* Get memory for full buffer, including space for trailing EOB's. */
 	n = _yybytes_len + 2;
 	n = _yybytes_len + 2;

+ 8 - 8
src/lib/eval/lexer.ll

@@ -120,10 +120,17 @@ blank [ \t]
     return isc::eval::EvalParser::make_INTEGER(tmp, loc);
     return isc::eval::EvalParser::make_INTEGER(tmp, loc);
 }
 }
 
 
+[A-Za-z]([-_A-Za-z0-9]*[A-Za-z0-9])?/{blank}*] {
+    // This string specifies option name starting with a letter
+    // and further containing letters, digits, hyphens and
+    // underscores and finishing by letters or digits.
+    return isc::eval::EvalParser::make_OPTION_NAME(yytext, loc);
+}
+
 "=="        return isc::eval::EvalParser::make_EQUAL(loc);
 "=="        return isc::eval::EvalParser::make_EQUAL(loc);
 "option"    return isc::eval::EvalParser::make_OPTION(loc);
 "option"    return isc::eval::EvalParser::make_OPTION(loc);
 "text"      return isc::eval::EvalParser::make_TEXT(loc);
 "text"      return isc::eval::EvalParser::make_TEXT(loc);
-"hex"       return isc::eval::EvalParser::make_HEX(loc);
+"bin"       return isc::eval::EvalParser::make_BIN(loc);
 "substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
 "substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
 "all"       return isc::eval::EvalParser::make_ALL(loc);
 "all"       return isc::eval::EvalParser::make_ALL(loc);
 "."         return isc::eval::EvalParser::make_DOT(loc);
 "."         return isc::eval::EvalParser::make_DOT(loc);
@@ -133,13 +140,6 @@ blank [ \t]
 "]"         return isc::eval::EvalParser::make_RBRACKET(loc);
 "]"         return isc::eval::EvalParser::make_RBRACKET(loc);
 ","         return isc::eval::EvalParser::make_COMA(loc);
 ","         return isc::eval::EvalParser::make_COMA(loc);
 
 
-[A-Za-z][A-Za-z0-9_\-]+/{blank}*] {
-    // This string specifies option name starting with a letter
-    // and further containing letters, digits, hyphens and
-    // underscores.
-    return isc::eval::EvalParser::make_OPTION_NAME(yytext, loc);
-}
-
 .          driver.error (loc, "Invalid character: " + std::string(yytext));
 .          driver.error (loc, "Invalid character: " + std::string(yytext));
 <<EOF>>    return isc::eval::EvalParser::make_END(loc);
 <<EOF>>    return isc::eval::EvalParser::make_END(loc);
 %%
 %%

+ 5 - 5
src/lib/eval/parser.cc

@@ -643,7 +643,7 @@ namespace isc { namespace eval {
 #line 134 "parser.yy" // lalr1.cc:859
 #line 134 "parser.yy" // lalr1.cc:859
     {
     {
                       uint16_t numeric_code = convert_option_code(yystack_[3].value.as< std::string > (), yystack_[3].location, ctx);
                       uint16_t numeric_code = convert_option_code(yystack_[3].value.as< std::string > (), yystack_[3].location, ctx);
-                      TokenPtr opt(new TokenOption(numeric_code, TokenOption::HEXADECIMAL));
+                      TokenPtr opt(new TokenOption(numeric_code, TokenOption::BINARY));
                       ctx.expression.push_back(opt);
                       ctx.expression.push_back(opt);
                   }
                   }
 #line 650 "parser.cc" // lalr1.cc:859
 #line 650 "parser.cc" // lalr1.cc:859
@@ -659,7 +659,7 @@ namespace isc { namespace eval {
                                                        TokenOption::TEXTUAL));
                                                        TokenOption::TEXTUAL));
                           ctx.expression.push_back(opt);
                           ctx.expression.push_back(opt);
 
 
-                      } catch (const std::exception& ex) {
+                      } catch (const isc::BadValue& ex) {
                           ctx.error(yystack_[3].location, ex.what());
                           ctx.error(yystack_[3].location, ex.what());
                       }
                       }
                   }
                   }
@@ -673,10 +673,10 @@ namespace isc { namespace eval {
                           // This may result in exception if the specified
                           // This may result in exception if the specified
                           // name is unknown.
                           // name is unknown.
                           TokenPtr opt(new TokenOption(yystack_[3].value.as< std::string > (), option_universe,
                           TokenPtr opt(new TokenOption(yystack_[3].value.as< std::string > (), option_universe,
-                                                       TokenOption::HEXADECIMAL));
+                                                       TokenOption::BINARY));
                           ctx.expression.push_back(opt);
                           ctx.expression.push_back(opt);
 
 
-                      } catch (const std::exception& ex) {
+                      } catch (const isc::BadValue& ex) {
                           ctx.error(yystack_[3].location, ex.what());
                           ctx.error(yystack_[3].location, ex.what());
                       }
                       }
                   }
                   }
@@ -1058,7 +1058,7 @@ namespace isc { namespace eval {
   const EvalParser::yytname_[] =
   const EvalParser::yytname_[] =
   {
   {
   "\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"",
   "\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"",
-  "\"substring\"", "\"text\"", "\"hex\"", "\"all\"", "\".\"", "\",\"",
+  "\"substring\"", "\"text\"", "\"bin\"", "\"all\"", "\".\"", "\",\"",
   "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"", "\"integer\"",
   "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"", "\"integer\"",
   "\"constant hexstring\"", "\"option name\"", "TOKEN", "$accept",
   "\"constant hexstring\"", "\"option name\"", "TOKEN", "$accept",
   "expression", "bool_expr", "string_expr", "start_expr", "length_expr", YY_NULLPTR
   "expression", "bool_expr", "string_expr", "start_expr", "length_expr", YY_NULLPTR

+ 4 - 4
src/lib/eval/parser.h

@@ -328,7 +328,7 @@ namespace isc { namespace eval {
         TOKEN_OPTION = 259,
         TOKEN_OPTION = 259,
         TOKEN_SUBSTRING = 260,
         TOKEN_SUBSTRING = 260,
         TOKEN_TEXT = 261,
         TOKEN_TEXT = 261,
-        TOKEN_HEX = 262,
+        TOKEN_BIN = 262,
         TOKEN_ALL = 263,
         TOKEN_ALL = 263,
         TOKEN_DOT = 264,
         TOKEN_DOT = 264,
         TOKEN_COMA = 265,
         TOKEN_COMA = 265,
@@ -469,7 +469,7 @@ namespace isc { namespace eval {
 
 
     static inline
     static inline
     symbol_type
     symbol_type
-    make_HEX (const location_type& l);
+    make_BIN (const location_type& l);
 
 
     static inline
     static inline
     symbol_type
     symbol_type
@@ -1021,9 +1021,9 @@ namespace isc { namespace eval {
   }
   }
 
 
   EvalParser::symbol_type
   EvalParser::symbol_type
-  EvalParser::make_HEX (const location_type& l)
+  EvalParser::make_BIN (const location_type& l)
   {
   {
-    return symbol_type (token::TOKEN_HEX, l);
+    return symbol_type (token::TOKEN_BIN, l);
   }
   }
 
 
   EvalParser::symbol_type
   EvalParser::symbol_type

+ 7 - 7
src/lib/eval/parser.yy

@@ -51,7 +51,7 @@ using namespace isc::eval;
   OPTION "option"
   OPTION "option"
   SUBSTRING "substring"
   SUBSTRING "substring"
   TEXT "text"
   TEXT "text"
-  HEX "hex"
+  BIN "bin"
   ALL "all"
   ALL "all"
   DOT "."
   DOT "."
   COMA ","
   COMA ","
@@ -130,10 +130,10 @@ string_expr : STRING
                       TokenPtr opt(new TokenOption(numeric_code, TokenOption::TEXTUAL));
                       TokenPtr opt(new TokenOption(numeric_code, TokenOption::TEXTUAL));
                       ctx.expression.push_back(opt);
                       ctx.expression.push_back(opt);
                   }
                   }
-            | OPTION "[" INTEGER "]" DOT HEX
+            | OPTION "[" INTEGER "]" DOT BIN
                   {
                   {
                       uint16_t numeric_code = convert_option_code($3, @3, ctx);
                       uint16_t numeric_code = convert_option_code($3, @3, ctx);
-                      TokenPtr opt(new TokenOption(numeric_code, TokenOption::HEXADECIMAL));
+                      TokenPtr opt(new TokenOption(numeric_code, TokenOption::BINARY));
                       ctx.expression.push_back(opt);
                       ctx.expression.push_back(opt);
                   }
                   }
             | OPTION "[" OPTION_NAME "]" DOT TEXT
             | OPTION "[" OPTION_NAME "]" DOT TEXT
@@ -145,20 +145,20 @@ string_expr : STRING
                                                        TokenOption::TEXTUAL));
                                                        TokenOption::TEXTUAL));
                           ctx.expression.push_back(opt);
                           ctx.expression.push_back(opt);
 
 
-                      } catch (const std::exception& ex) {
+                      } catch (const isc::BadValue& ex) {
                           ctx.error(@3, ex.what());
                           ctx.error(@3, ex.what());
                       }
                       }
                   }
                   }
-            | OPTION "[" OPTION_NAME "]" DOT HEX
+            | OPTION "[" OPTION_NAME "]" DOT BIN
                   {
                   {
                       try {
                       try {
                           // This may result in exception if the specified
                           // This may result in exception if the specified
                           // name is unknown.
                           // name is unknown.
                           TokenPtr opt(new TokenOption($3, option_universe,
                           TokenPtr opt(new TokenOption($3, option_universe,
-                                                       TokenOption::HEXADECIMAL));
+                                                       TokenOption::BINARY));
                           ctx.expression.push_back(opt);
                           ctx.expression.push_back(opt);
 
 
-                      } catch (const std::exception& ex) {
+                      } catch (const isc::BadValue& ex) {
                           ctx.error(@3, ex.what());
                           ctx.error(@3, ex.what());
                       }
                       }
                   }
                   }

+ 12 - 3
src/lib/eval/tests/context_unittest.cc

@@ -227,11 +227,11 @@ TEST_F(EvalContextTest, optionWithNameAndWhitespace) {
     checkTokenOption(eval.expression.at(0), 12);
     checkTokenOption(eval.expression.at(0), 12);
 }
 }
 
 
-// Test parsing of an option represented as hexadecimal string.
-TEST_F(EvalContextTest, optionHex) {
+// Test parsing of an option represented as binary string.
+TEST_F(EvalContextTest, optionBin) {
     EvalContext eval(Option::V4);
     EvalContext eval(Option::V4);
 
 
-    EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].hex == 0x666F6F"));
+    EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].bin == 0x666F6F"));
     EXPECT_TRUE(parsed_);
     EXPECT_TRUE(parsed_);
     ASSERT_EQ(3, eval.expression.size());
     ASSERT_EQ(3, eval.expression.size());
     checkTokenOption(eval.expression.at(0), 123);
     checkTokenOption(eval.expression.at(0), 123);
@@ -292,6 +292,11 @@ TEST_F(EvalContextTest, scanParseErrors) {
                " expecting .");
                " expecting .");
     checkError("option[123].text < 'foo'", "<string>:1.18: Invalid"
     checkError("option[123].text < 'foo'", "<string>:1.18: Invalid"
                " character: <");
                " character: <");
+    checkError("option[-ab].text", "<string>:1.8: Invalid character: -");
+    checkError("option[0ab].text",
+               "<string>:1.9-10: syntax error, unexpected option name, "
+               "expecting ]");
+    checkError("option[ab_].bin", "<string>:1.8: Invalid character: a");
     checkError("substring('foo',12345678901234567890,1)",
     checkError("substring('foo',12345678901234567890,1)",
                "<string>:1.17-36: Failed to convert 12345678901234567890 "
                "<string>:1.17-36: Failed to convert 12345678901234567890 "
                "to an integer.");
                "to an integer.");
@@ -311,6 +316,10 @@ TEST_F(EvalContextTest, parseErrors) {
     checkError("option(10) == 'ab'",
     checkError("option(10) == 'ab'",
                "<string>:1.7: syntax error, "
                "<string>:1.7: syntax error, "
                "unexpected (, expecting [");
                "unexpected (, expecting [");
+    checkError("option['ab'].text == 'foo'",
+               "<string>:1.8-11: syntax error, "
+               "unexpected constant string, "
+               "expecting integer or option name");
     checkError("option[ab].text == 'foo'",
     checkError("option[ab].text == 'foo'",
                "<string>:1.8-9: option 'ab' is not defined");
                "<string>:1.8-9: option 'ab' is not defined");
     checkError("option[0xa].text == 'ab'",
     checkError("option[0xa].text == 'ab'",

+ 2 - 2
src/lib/eval/tests/evaluate_unittest.cc

@@ -209,13 +209,13 @@ TEST_F(EvaluateTest, packet) {
     EXPECT_FALSE(result_);
     EXPECT_FALSE(result_);
 }
 }
 
 
-// A test which compares option value represented in hexadecimal format.
+// A test which compares option value represented in binary format.
 TEST_F(EvaluateTest, optionHex) {
 TEST_F(EvaluateTest, optionHex) {
     TokenPtr toption;
     TokenPtr toption;
     TokenPtr tstring;
     TokenPtr tstring;
     TokenPtr tequal;
     TokenPtr tequal;
 
 
-    ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
+    ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::BINARY)));
     e_.push_back(toption);
     e_.push_back(toption);
     ASSERT_NO_THROW(tstring.reset(new TokenString("hundred4")));
     ASSERT_NO_THROW(tstring.reset(new TokenString("hundred4")));
     e_.push_back(tstring);
     e_.push_back(tstring);

+ 14 - 14
src/lib/eval/tests/token_unittest.cc

@@ -325,14 +325,14 @@ TEST_F(TokenTest, optionWithNameString4) {
 
 
 // This test checks if a token representing option value is able to extract
 // This test checks if a token representing option value is able to extract
 // the option from an IPv4 packet and properly store its value in a
 // the option from an IPv4 packet and properly store its value in a
-// hexadecimal format.
-TEST_F(TokenTest, optionHexString4) {
+// binary format.
+TEST_F(TokenTest, optionBinString4) {
     TokenPtr found;
     TokenPtr found;
     TokenPtr not_found;
     TokenPtr not_found;
 
 
     // The packets we use have option 100 with a string in them.
     // The packets we use have option 100 with a string in them.
-    ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
-    ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::HEXADECIMAL)));
+    ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::BINARY)));
+    ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::BINARY)));
 
 
     // This should evaluate to the content of the option 100 (i.e. "hundred4")
     // This should evaluate to the content of the option 100 (i.e. "hundred4")
     ASSERT_NO_THROW(found->evaluate(*pkt4_, values_));
     ASSERT_NO_THROW(found->evaluate(*pkt4_, values_));
@@ -354,8 +354,8 @@ TEST_F(TokenTest, optionHexString4) {
 
 
 // This test checks if a token representing an option identified by name is
 // This test checks if a token representing an option identified by name is
 // able to extract this option from an IPv4 packet and properly store its
 // able to extract this option from an IPv4 packet and properly store its
-// value in the hexadecimal format.
-TEST_F(TokenTest, optionWithNameHexString4) {
+// value in the binary format.
+TEST_F(TokenTest, optionWithNameBinString4) {
     // Create definition of option 100 to provide a mapping between option
     // Create definition of option 100 to provide a mapping between option
     // code and option name.
     // code and option name.
     ASSERT_NO_THROW(createOptionDefinitions4());
     ASSERT_NO_THROW(createOptionDefinitions4());
@@ -364,7 +364,7 @@ TEST_F(TokenTest, optionWithNameHexString4) {
     // map the option name to its code.
     // map the option name to its code.
     TokenPtr token;
     TokenPtr token;
     ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred4", Option::V4,
     ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred4", Option::V4,
-                                                TokenOption::HEXADECIMAL)));
+                                                TokenOption::BINARY)));
 
 
     // Evaluate option in the packet.
     // Evaluate option in the packet.
     ASSERT_NO_THROW(token->evaluate(*pkt4_, values_));
     ASSERT_NO_THROW(token->evaluate(*pkt4_, values_));
@@ -426,15 +426,15 @@ TEST_F(TokenTest, optionWithNameString6) {
 
 
 
 
 // This test checks if a token representing an option value is able to extract
 // This test checks if a token representing an option value is able to extract
-// the option from an IPv6 packet and properly store its value in hexadecimal
+// the option from an IPv6 packet and properly store its value in binary
 // format.
 // format.
-TEST_F(TokenTest, optionHexString6) {
+TEST_F(TokenTest, optionBinString6) {
     TokenPtr found;
     TokenPtr found;
     TokenPtr not_found;
     TokenPtr not_found;
 
 
     // The packets we use have option 100 with a string in them.
     // The packets we use have option 100 with a string in them.
-    ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
-    ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::HEXADECIMAL)));
+    ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::BINARY)));
+    ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::BINARY)));
 
 
     // This should evaluate to the content of the option 100 (i.e. "hundred6")
     // This should evaluate to the content of the option 100 (i.e. "hundred6")
     ASSERT_NO_THROW(found->evaluate(*pkt6_, values_));
     ASSERT_NO_THROW(found->evaluate(*pkt6_, values_));
@@ -456,8 +456,8 @@ TEST_F(TokenTest, optionHexString6) {
 
 
 // This test checks if a token representing an option identified by name is
 // This test checks if a token representing an option identified by name is
 // able to extract this option from an IPv6 packet and properly store its
 // able to extract this option from an IPv6 packet and properly store its
-// value in the hexadecimal format.
-TEST_F(TokenTest, optionWithNameHexString6) {
+// value in the binary format.
+TEST_F(TokenTest, optionWithNameBinString6) {
     // Create definition of option 100 to provide a mapping between option
     // Create definition of option 100 to provide a mapping between option
     // code and option name.
     // code and option name.
     ASSERT_NO_THROW(createOptionDefinitions6());
     ASSERT_NO_THROW(createOptionDefinitions6());
@@ -466,7 +466,7 @@ TEST_F(TokenTest, optionWithNameHexString6) {
     // map the option name to its code.
     // map the option name to its code.
     TokenPtr token;
     TokenPtr token;
     ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred6", Option::V6,
     ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred6", Option::V6,
-                                                TokenOption::HEXADECIMAL)));
+                                                TokenOption::BINARY)));
 
 
     // Evaluate option in the packet.
     // Evaluate option in the packet.
     ASSERT_NO_THROW(token->evaluate(*pkt6_, values_));
     ASSERT_NO_THROW(token->evaluate(*pkt6_, values_));

+ 4 - 1
src/lib/eval/token.cc

@@ -93,7 +93,10 @@ TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
             opt_str = opt->toString();
             opt_str = opt->toString();
         } else {
         } else {
             std::vector<uint8_t> binary = opt->toBinary();
             std::vector<uint8_t> binary = opt->toBinary();
-            opt_str.assign(binary.begin(), binary.end());
+            opt_str.resize(binary.size());
+            if (!binary.empty()) {
+                memmove(&opt_str[0], &binary[0], binary.size());
+            }
         }
         }
     }
     }
 
 

+ 3 - 2
src/lib/eval/token.h

@@ -153,13 +153,13 @@ public:
     /// @brief Token representation type.
     /// @brief Token representation type.
     ///
     ///
     /// There are many possible ways in which option can be presented.
     /// There are many possible ways in which option can be presented.
-    /// Currently the textual and hexadecimal representations are
+    /// Currently the textual and binary representations are
     /// supported. The type of representation is specified in the
     /// supported. The type of representation is specified in the
     /// constructor and it affects the value generated by the
     /// constructor and it affects the value generated by the
     /// @c TokenOption::evaluate function.
     /// @c TokenOption::evaluate function.
     enum RepresentationType {
     enum RepresentationType {
         TEXTUAL,
         TEXTUAL,
-        HEXADECIMAL
+        BINARY
     };
     };
 
 
     /// @brief Constructor that takes an option code as a parameter
     /// @brief Constructor that takes an option code as a parameter
@@ -177,6 +177,7 @@ public:
     /// @param option_name Name of the option to be represented.
     /// @param option_name Name of the option to be represented.
     /// @param option_universe Option universe: DHCPv4 or DHCPv6.
     /// @param option_universe Option universe: DHCPv4 or DHCPv6.
     /// @param rep_type Token representation type.
     /// @param rep_type Token representation type.
+    /// @throw BadValue when the option_name cannot be resolved
     TokenOption(const std::string& option_name,
     TokenOption(const std::string& option_name,
                 const Option::Universe& option_universe,
                 const Option::Universe& option_universe,
                 const RepresentationType& rep_type);
                 const RepresentationType& rep_type);