2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 13:37:55 +00:00

[#2272] Added split function to expression syntax

doc/sphinx/arm/classify.rst
    Documented new split() function

src/lib/eval/eval_messages.cc b/src/lib/eval/eval_messages.*
    New debug log messges

src/lib/eval/lexer.ll
src/lib/eval/parser.yy
    added split parsing

src/lib/eval/tests/token_unittest.cc
    Added tests for split()

src/lib/eval/token.*
    Added TokenSplit class
This commit is contained in:
Thomas Markwalder 2022-04-14 07:21:12 -04:00 committed by Razvan Becheriu
parent 2404bd82a2
commit 29988a24e2
13 changed files with 2857 additions and 2766 deletions

View File

@ -474,6 +474,10 @@ Notes:
| | | a hexadecimal string, |
| | | e.g. 0a:1b:2c:3e |
+-----------------------+-------------------------+-----------------------+
| Split | split('foo.bar','.',2) | Return the second |
| | | field, splitting on |
| | | dots. |
+-----------------------+-------------------------+-----------------------+
.. table:: List of conversion-to-text expressions
@ -586,6 +590,25 @@ or:
'abcdefghijkl...'
Split
---------
The Split operator ``Split(value, delimiters, field-number)`` accepts a list
of characters to use as delimiters and a positive field number of the
desired field when the value is split into fields separated by the delimiters.
Adjacent delimit are not compressed out, rather they result in
an empty string for that field number. If value is an empty string, the result
will an empty string. If the delimiters list is empty, the result will be the
original value. If the is less than one or larger than the number of fields,
the result will be an empty string. Some examples follow:
::
split ('one.two..four', '.', 1) == 'one'
split ('one.two..four', '.', 2) == 'two'
split ('one.two..four', '.', 3) == ''
split ('one.two..four', '.', 4) == 'four'
split ('one.two..four', '.', 5) == ''
Ifelse
------

View File

@ -27,6 +27,10 @@ extern const isc::log::MessageID EVAL_DEBUG_PKT4 = "EVAL_DEBUG_PKT4";
extern const isc::log::MessageID EVAL_DEBUG_PKT6 = "EVAL_DEBUG_PKT6";
extern const isc::log::MessageID EVAL_DEBUG_RELAY6 = "EVAL_DEBUG_RELAY6";
extern const isc::log::MessageID EVAL_DEBUG_RELAY6_RANGE = "EVAL_DEBUG_RELAY6_RANGE";
extern const isc::log::MessageID EVAL_DEBUG_SPLIT = "EVAL_DEBUG_SPLIT";
extern const isc::log::MessageID EVAL_DEBUG_SPLIT_DELIM_EMPTY = "EVAL_DEBUG_SPLIT_DELIM_EMPTY";
extern const isc::log::MessageID EVAL_DEBUG_SPLIT_EMPTY = "EVAL_DEBUG_SPLIT_EMPTY";
extern const isc::log::MessageID EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE = "EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE";
extern const isc::log::MessageID EVAL_DEBUG_STRING = "EVAL_DEBUG_STRING";
extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING = "EVAL_DEBUG_SUBSTRING";
extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING_EMPTY = "EVAL_DEBUG_SUBSTRING_EMPTY";
@ -75,6 +79,10 @@ const char* values[] = {
"EVAL_DEBUG_PKT6", "Pushing PKT6 field %1 with value %2",
"EVAL_DEBUG_RELAY6", "Pushing PKT6 relay field %1 nest %2 with value %3",
"EVAL_DEBUG_RELAY6_RANGE", "Pushing PKT6 relay field %1 nest %2 with value %3",
"EVAL_DEBUG_SPLIT", "Popping field %1, delimiters %2, string %3, pushing result %4",
"EVAL_DEBUG_SPLIT_DELIM_EMPTY", "Popping field %1, delimiters %2, string %3, pushing result %4",
"EVAL_DEBUG_SPLIT_EMPTY", "Popping field %1, delimiters %2, string %3, pushing result %4",
"EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE", "Popping field %1, delimiters %2, string %3, pushing result %4",
"EVAL_DEBUG_STRING", "Pushing text string %1",
"EVAL_DEBUG_SUBSTRING", "Popping length %1, start %2, string %3 pushing result %4",
"EVAL_DEBUG_SUBSTRING_EMPTY", "Popping length %1, start %2, string %3 pushing result %4",

View File

@ -28,6 +28,10 @@ extern const isc::log::MessageID EVAL_DEBUG_PKT4;
extern const isc::log::MessageID EVAL_DEBUG_PKT6;
extern const isc::log::MessageID EVAL_DEBUG_RELAY6;
extern const isc::log::MessageID EVAL_DEBUG_RELAY6_RANGE;
extern const isc::log::MessageID EVAL_DEBUG_SPLIT;
extern const isc::log::MessageID EVAL_DEBUG_SPLIT_DELIM_EMPTY;
extern const isc::log::MessageID EVAL_DEBUG_SPLIT_EMPTY;
extern const isc::log::MessageID EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE;
extern const isc::log::MessageID EVAL_DEBUG_STRING;
extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING;
extern const isc::log::MessageID EVAL_DEBUG_SUBSTRING_EMPTY;

View File

@ -261,3 +261,26 @@ and vendor option was not found.
This debug message indicates that the expression has been evaluated
to said value. This message is mostly useful during debugging of the
client classification expressions.
% EVAL_DEBUG_SPLIT_EMPTY Popping field %1, delimiters %2, string %3, pushing result %4
This debug message indicates that the string popped from the stack was empty
and so the result will also be empty. The field, deli meter string, and string are
still popped from the stack and the result is still pushed.
% EVAL_DEBUG_SPLIT_DELIM_EMPTY Popping field %1, delimiters %2, string %3, pushing result %4
This debug message indicates that the deli meter string popped from the stack was empty
and so the result will also be empty. The field, deli meter string, and string are
still popped from the stack and the result is still pushed.
% EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE Popping field %1, delimiters %2, string %3, pushing result %4
This debug message indicates that the field is either less than one or larger
than the number of fields in the string popped from the stack. the result will
be empty. The field, deli meter string, and string are still popped from the
stack and the result is still pushed.
% EVAL_DEBUG_SPLIT Popping field %1, delimiters %2, string %3, pushing result %4
This debug message indicates that three values are being popped from
the value stack and a result is being pushed onto the value stack. The
values being popped are the field, delimiter_string and string and the
result is the extracted field. The resulting string is pushed onto
the stack. The strings are displayed in hex.

View File

@ -710,8 +710,8 @@ static void yynoreturn yy_fatal_error ( const char* msg );
/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
(yy_c_buf_p) = yy_cp;
/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
#define YY_NUM_RULES 62
#define YY_END_OF_BUFFER 63
#define YY_NUM_RULES 63
#define YY_END_OF_BUFFER 64
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
@ -719,38 +719,38 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
static const flex_int16_t yy_accept[275] =
static const flex_int16_t yy_accept[279] =
{ 0,
0, 0, 63, 61, 1, 2, 61, 54, 55, 59,
60, 58, 61, 53, 5, 5, 61, 61, 61, 61,
56, 57, 61, 61, 61, 61, 61, 61, 61, 61,
61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
0, 0, 64, 62, 1, 2, 62, 55, 56, 60,
61, 59, 62, 54, 5, 5, 62, 62, 62, 62,
57, 58, 62, 62, 62, 62, 62, 62, 62, 62,
62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1, 2, 0, 3, 5, 0, 5, 0, 0, 0,
0, 7, 8, 0, 0, 0, 0, 6, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 4, 7, 0, 38, 50, 0, 0,
52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 7, 0, 39, 51, 0,
0, 20, 0, 0, 0, 15, 0, 0, 0, 0,
0, 21, 0, 23, 0, 0, 49, 0, 0, 17,
0, 0, 19, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 35, 0, 0, 0, 0, 24, 0,
0, 0, 20, 0, 0, 0, 15, 0, 0, 0,
0, 0, 21, 0, 23, 0, 0, 50, 0, 0,
17, 0, 0, 0, 19, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 35, 0, 0, 0, 0,
24, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 22, 30, 0, 0, 0, 0, 14, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22, 30, 0, 0, 0, 14, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 25, 18,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26, 39, 0, 16, 27, 0, 40, 0, 0, 0,
0, 25, 18, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 38, 0, 0, 0, 0, 0,
0, 0, 0, 0, 26, 40, 0, 16, 27, 0,
0, 52, 0, 9, 0, 10, 11, 29, 0, 0,
0, 0, 0, 33, 28, 7, 0, 0, 0, 0,
0, 0, 0, 31, 0, 0, 32, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 13, 12, 0,
0, 0, 0, 0, 0, 0, 41, 0, 0, 0,
37, 0, 0, 0, 0, 42, 36, 0, 0, 43,
0, 0, 0, 0, 44, 45, 0, 0, 46, 0,
47, 48, 34, 0
41, 0, 0, 0, 0, 53, 0, 9, 0, 10,
11, 29, 0, 0, 0, 0, 0, 33, 28, 7,
0, 0, 0, 0, 0, 0, 0, 31, 0, 0,
32, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 13, 12, 0, 0, 0, 0, 0, 0, 0,
42, 0, 0, 0, 37, 0, 0, 0, 0, 43,
36, 0, 0, 44, 0, 0, 0, 0, 45, 46,
0, 0, 47, 0, 48, 49, 34, 0
} ;
static const YY_CHAR yy_ec[256] =
@ -794,128 +794,129 @@ static const YY_CHAR yy_meta[50] =
1, 1, 1, 1, 1, 1, 1, 1, 1
} ;
static const flex_int16_t yy_base[284] =
static const flex_int16_t yy_base[288] =
{ 0,
0, 0, 379, 380, 376, 374, 372, 380, 380, 380,
380, 380, 0, 380, 39, 36, 355, 353, 86, 124,
380, 380, 35, 38, 34, 37, 337, 48, 43, 58,
63, 331, 22, 60, 339, 115, 116, 334, 337, 332,
365, 363, 361, 380, 0, 0, 121, 344, 343, 0,
342, 0, 380, 147, 160, 0, 0, 380, 330, 322,
328, 330, 317, 311, 310, 309, 317, 324, 303, 318,
300, 132, 303, 307, 306, 315, 305, 309, 297, 296,
0, 308, 294, 300, 309, 306, 306, 286, 305, 292,
291, 302, 318, 0, 0, 285, 0, 0, 296, 296,
0, 0, 383, 384, 380, 378, 376, 384, 384, 384,
384, 384, 0, 384, 39, 36, 359, 357, 86, 124,
384, 384, 35, 38, 34, 37, 341, 48, 43, 58,
63, 335, 22, 60, 343, 122, 116, 338, 341, 336,
369, 367, 365, 384, 0, 0, 121, 348, 347, 0,
346, 0, 384, 147, 158, 0, 0, 384, 334, 326,
332, 334, 321, 315, 314, 313, 321, 328, 307, 322,
304, 119, 307, 311, 310, 319, 309, 313, 301, 300,
0, 312, 298, 304, 313, 302, 309, 309, 289, 308,
295, 294, 305, 321, 0, 0, 288, 0, 0, 299,
297, 0, 292, 279, 291, 277, 280, 277, 288, 279,
152, 0, 279, 0, 286, 269, 0, 277, 269, 150,
283, 279, 0, 265, 263, 267, 261, 274, 273, 0,
258, 271, 273, 0, 257, 254, 267, 252, 0, 264,
263, 250, 275, 278, 246, 262, 257, 239, 246, 258,
0, 0, 236, 253, 238, 0, 238, 157, 240, 249,
268, 237, 234, 231, 233, 230, 230, 229, 0, 0,
239, 225, 224, 227, 236, 223, 223, 224, 232, 159,
219, 218, 224, 241, 244, 212, 213, 212, 0, 209,
0, 0, 210, 0, 0, 216, 0, 210, 209, 204,
299, 300, 0, 295, 282, 294, 280, 283, 280, 291,
282, 157, 0, 282, 0, 289, 272, 0, 280, 272,
159, 286, 282, 276, 0, 267, 265, 269, 263, 276,
275, 0, 260, 273, 275, 0, 259, 256, 269, 254,
0, 266, 265, 252, 277, 280, 248, 264, 259, 241,
248, 260, 0, 0, 238, 255, 240, 239, 0, 239,
166, 241, 250, 269, 238, 235, 232, 234, 231, 231,
230, 0, 0, 240, 226, 225, 228, 237, 224, 224,
225, 233, 162, 220, 0, 219, 225, 242, 245, 213,
214, 213, 0, 210, 0, 0, 211, 0, 0, 217,
217, 0, 215, 0, 215, 0, 0, 0, 209, 213,
198, 197, 200, 230, 0, 0, 207, 202, 197, 191,
190, 202, 190, 0, 189, 191, 0, 189, 188, 183,
176, 179, 182, 186, 176, 173, 156, 0, 0, 169,
156, 155, 167, 160, 152, 164, 0, 147, 146, 148,
0, 160, 159, 142, 161, 0, 0, 143, 142, 0,
137, 136, 138, 138, 0, 0, 136, 135, 0, 130,
0, 0, 0, 380, 206, 143, 209, 107, 212, 215,
219, 78, 77
0, 211, 210, 205, 218, 0, 216, 0, 216, 0,
0, 0, 210, 214, 199, 198, 201, 231, 0, 0,
208, 203, 198, 192, 191, 203, 191, 0, 190, 192,
0, 190, 189, 184, 160, 180, 183, 192, 193, 192,
175, 0, 0, 188, 176, 175, 187, 180, 172, 184,
0, 167, 166, 168, 0, 180, 179, 162, 176, 0,
0, 147, 144, 0, 140, 139, 138, 138, 0, 0,
129, 126, 0, 123, 0, 0, 0, 384, 190, 162,
193, 107, 196, 199, 203, 78, 77
} ;
static const flex_int16_t yy_def[284] =
static const flex_int16_t yy_def[288] =
{ 0,
274, 1, 274, 274, 274, 274, 275, 274, 274, 274,
274, 274, 276, 274, 274, 15, 277, 274, 274, 19,
274, 274, 19, 19, 19, 19, 20, 20, 20, 20,
278, 1, 278, 278, 278, 278, 279, 278, 278, 278,
278, 278, 280, 278, 278, 15, 281, 278, 278, 19,
278, 278, 19, 19, 19, 19, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
274, 274, 275, 274, 276, 278, 15, 277, 279, 280,
277, 281, 274, 274, 20, 19, 20, 274, 19, 20,
278, 278, 279, 278, 280, 282, 15, 281, 283, 284,
281, 285, 278, 278, 20, 19, 20, 278, 19, 20,
20, 20, 20, 19, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 278, 280, 281, 19, 20, 20, 20, 20,
20, 20, 20, 282, 284, 285, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 282,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 286, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 286, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
282, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 283, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 287, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 283, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 287,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 0, 274, 274, 274, 274, 274, 274,
274, 274, 274
20, 20, 20, 20, 20, 20, 20, 0, 278, 278,
278, 278, 278, 278, 278, 278, 278
} ;
static const flex_int16_t yy_nxt[430] =
static const flex_int16_t yy_nxt[434] =
{ 0,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 16, 16, 16, 16, 16, 16, 17,
18, 19, 20, 20, 21, 22, 4, 23, 19, 24,
25, 26, 19, 27, 28, 29, 20, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 20, 40, 46,
47, 47, 47, 47, 47, 47, 47, 47, 48, 274,
47, 47, 47, 47, 47, 47, 47, 47, 48, 278,
49, 64, 50, 80, 81, 59, 49, 49, 49, 49,
49, 49, 60, 62, 61, 72, 66, 65, 63, 69,
216, 161, 73, 274, 67, 70, 50, 54, 54, 74,
220, 164, 73, 278, 67, 70, 50, 54, 54, 74,
76, 82, 71, 75, 77, 55, 83, 56, 56, 56,
56, 56, 56, 56, 56, 48, 78, 56, 57, 57,
93, 58, 55, 56, 56, 56, 56, 56, 56, 57,
94, 58, 55, 56, 56, 56, 56, 56, 56, 57,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
57, 57, 57, 274, 274, 57, 45, 88, 54, 54,
85, 57, 57, 57, 57, 57, 57, 86, 89, 109,
87, 274, 274, 110, 143, 151, 144, 152, 274, 184,
145, 185, 58, 273, 206, 186, 207, 274, 274, 272,
271, 270, 269, 268, 267, 274, 266, 265, 264, 263,
262, 261, 260, 259, 258, 257, 256, 255, 254, 253,
57, 57, 57, 278, 278, 57, 110, 89, 54, 54,
111, 57, 57, 57, 57, 57, 57, 85, 90, 278,
278, 278, 278, 86, 87, 45, 277, 88, 278, 145,
276, 146, 58, 275, 153, 147, 154, 210, 188, 211,
189, 274, 273, 278, 190, 278, 272, 271, 270, 248,
43, 269, 43, 43, 43, 43, 51, 51, 51, 49,
252, 274, 251, 250, 249, 244, 43, 248, 43, 43,
43, 43, 51, 51, 51, 49, 49, 49, 94, 247,
94, 95, 95, 95, 95, 246, 245, 243, 242, 241,
240, 239, 238, 237, 236, 235, 234, 233, 232, 231,
230, 229, 228, 227, 226, 225, 224, 223, 222, 221,
220, 219, 218, 217, 215, 214, 213, 212, 211, 210,
209, 208, 205, 204, 203, 202, 201, 200, 199, 198,
197, 196, 195, 194, 193, 192, 191, 190, 189, 188,
187, 183, 182, 181, 180, 179, 178, 177, 176, 175,
174, 173, 172, 171, 170, 169, 168, 167, 166, 165,
49, 49, 95, 268, 95, 96, 96, 96, 96, 267,
266, 265, 264, 263, 262, 261, 260, 259, 258, 257,
256, 255, 254, 253, 252, 251, 250, 249, 247, 246,
245, 244, 243, 242, 241, 240, 239, 238, 237, 236,
235, 234, 233, 232, 231, 230, 229, 228, 227, 226,
225, 224, 223, 222, 221, 219, 218, 217, 216, 215,
214, 213, 212, 209, 208, 207, 206, 205, 204, 203,
202, 201, 200, 199, 198, 197, 196, 195, 194, 193,
192, 191, 187, 186, 185, 184, 183, 182, 181, 180,
179, 178, 177, 176, 175, 174, 173, 172, 171, 170,
164, 163, 162, 160, 159, 158, 157, 156, 155, 154,
153, 150, 149, 148, 147, 146, 142, 141, 140, 139,
138, 137, 136, 135, 134, 133, 132, 131, 130, 129,
128, 127, 126, 125, 124, 123, 122, 121, 120, 119,
118, 117, 116, 115, 114, 113, 112, 111, 108, 107,
106, 105, 104, 103, 102, 101, 100, 99, 98, 97,
96, 52, 48, 52, 44, 42, 41, 92, 91, 90,
84, 79, 68, 53, 52, 44, 42, 41, 274, 3,
274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
169, 168, 167, 166, 165, 163, 162, 161, 160, 159,
158, 157, 156, 155, 152, 151, 150, 149, 148, 144,
143, 142, 141, 140, 139, 138, 137, 136, 135, 134,
133, 132, 131, 130, 129, 128, 127, 126, 125, 124,
123, 122, 121, 120, 119, 118, 117, 116, 115, 114,
113, 112, 109, 108, 107, 106, 105, 104, 103, 102,
101, 100, 99, 98, 97, 52, 48, 52, 44, 42,
41, 93, 92, 91, 84, 79, 68, 53, 52, 44,
42, 41, 278, 3, 278, 278, 278, 278, 278, 278,
278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274, 274
278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
278, 278, 278
} ;
static const flex_int16_t yy_chk[430] =
static const flex_int16_t yy_chk[434] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -925,54 +926,55 @@ static const flex_int16_t yy_chk[430] =
15, 15, 15, 15, 15, 15, 15, 15, 15, 16,
15, 25, 15, 33, 33, 23, 15, 15, 15, 15,
15, 15, 23, 24, 23, 29, 26, 25, 24, 28,
283, 282, 29, 16, 26, 28, 15, 19, 19, 30,
287, 286, 29, 16, 26, 28, 15, 19, 19, 30,
31, 34, 28, 30, 31, 19, 34, 19, 19, 19,
19, 19, 19, 19, 19, 19, 31, 19, 19, 19,
278, 19, 19, 19, 19, 19, 19, 19, 19, 19,
282, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 20, 20, 20, 20, 20,
20, 20, 20, 20, 47, 20, 276, 37, 54, 54,
36, 20, 20, 20, 20, 20, 20, 36, 37, 72,
36, 55, 55, 72, 111, 120, 111, 120, 47, 158,
111, 158, 54, 270, 180, 158, 180, 231, 231, 268,
267, 264, 263, 262, 261, 55, 259, 258, 255, 254,
253, 252, 250, 249, 248, 246, 245, 244, 243, 242,
20, 20, 20, 20, 47, 20, 72, 37, 54, 54,
72, 20, 20, 20, 20, 20, 20, 36, 37, 55,
55, 235, 235, 36, 36, 280, 274, 36, 47, 112,
272, 112, 54, 271, 121, 112, 121, 183, 161, 183,
161, 268, 267, 55, 161, 235, 266, 265, 263, 235,
279, 262, 279, 279, 279, 279, 281, 281, 281, 283,
241, 231, 240, 237, 236, 231, 275, 235, 275, 275,
275, 275, 277, 277, 277, 279, 279, 279, 280, 234,
280, 281, 281, 281, 281, 233, 232, 230, 229, 228,
226, 225, 223, 222, 221, 220, 219, 218, 217, 214,
213, 212, 211, 210, 209, 205, 203, 201, 200, 199,
198, 196, 193, 190, 188, 187, 186, 185, 184, 183,
182, 181, 179, 178, 177, 176, 175, 174, 173, 172,
171, 168, 167, 166, 165, 164, 163, 162, 161, 160,
159, 157, 155, 154, 153, 150, 149, 148, 147, 146,
145, 144, 143, 142, 141, 140, 138, 137, 136, 135,
283, 283, 284, 259, 284, 285, 285, 285, 285, 258,
257, 256, 254, 253, 252, 250, 249, 248, 247, 246,
245, 244, 241, 240, 239, 238, 237, 236, 234, 233,
232, 230, 229, 227, 226, 225, 224, 223, 222, 221,
218, 217, 216, 215, 214, 213, 209, 207, 205, 204,
203, 202, 200, 197, 194, 192, 191, 190, 189, 188,
187, 186, 184, 182, 181, 180, 179, 178, 177, 176,
175, 174, 171, 170, 169, 168, 167, 166, 165, 164,
163, 162, 160, 158, 157, 156, 155, 152, 151, 150,
149, 148, 147, 146, 145, 144, 143, 142, 140, 139,
133, 132, 131, 129, 128, 127, 126, 125, 124, 122,
121, 119, 118, 116, 115, 113, 110, 109, 108, 107,
106, 105, 104, 103, 101, 100, 99, 96, 93, 92,
91, 90, 89, 88, 87, 86, 85, 84, 83, 82,
80, 79, 78, 77, 76, 75, 74, 73, 71, 70,
69, 68, 67, 66, 65, 64, 63, 62, 61, 60,
59, 51, 49, 48, 43, 42, 41, 40, 39, 38,
35, 32, 27, 18, 17, 7, 6, 5, 3, 274,
274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
138, 137, 135, 134, 133, 131, 130, 129, 128, 127,
126, 124, 123, 122, 120, 119, 117, 116, 114, 111,
110, 109, 108, 107, 106, 105, 104, 102, 101, 100,
97, 94, 93, 92, 91, 90, 89, 88, 87, 86,
85, 84, 83, 82, 80, 79, 78, 77, 76, 75,
74, 73, 71, 70, 69, 68, 67, 66, 65, 64,
63, 62, 61, 60, 59, 51, 49, 48, 43, 42,
41, 40, 39, 38, 35, 32, 27, 18, 17, 7,
6, 5, 3, 278, 278, 278, 278, 278, 278, 278,
278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274, 274
278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
278, 278, 278
} ;
/* Table of booleans, true if rule could match eol. */
static const flex_int32_t yy_rule_can_match_eol[63] =
static const flex_int32_t yy_rule_can_match_eol[64] =
{ 0,
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, };
0, 0, 0, 0, };
static yy_state_type yy_last_accepting_state;
static char *yy_last_accepting_cpos;
@ -980,7 +982,7 @@ static char *yy_last_accepting_cpos;
extern int yy_flex_debug;
int yy_flex_debug = 1;
static const flex_int16_t yy_rule_linenum[62] =
static const flex_int16_t yy_rule_linenum[63] =
{ 0,
106, 111, 117, 127, 133, 151, 175, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
@ -988,7 +990,7 @@ static const flex_int16_t yy_rule_linenum[62] =
212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
242
242, 243
} ;
/* The intent behind this definition is that it'll catch
@ -1000,7 +1002,7 @@ static const flex_int16_t yy_rule_linenum[62] =
#define YY_RESTORE_YY_MORE_OFFSET
char *yytext;
#line 1 "lexer.ll"
/* Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
/* Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
@ -1039,7 +1041,7 @@ namespace {
/* To avoid the call to exit... oops! */
#define YY_FATAL_ERROR(msg) isc::eval::EvalContext::fatal(msg)
#line 1042 "lexer.cc"
#line 1044 "lexer.cc"
/* noyywrap disables automatic rewinding for the next file to parse. Since we
always parse only a single string, there's no need to do any wraps. And
using yywrap requires linking with -lfl, which provides the default yywrap
@ -1064,8 +1066,8 @@ namespace {
by moving it ahead by yyleng bytes. yyleng specifies the length of the
currently matched token. */
#define YY_USER_ACTION loc.columns(evalleng);
#line 1067 "lexer.cc"
#line 1068 "lexer.cc"
#line 1069 "lexer.cc"
#line 1070 "lexer.cc"
#define INITIAL 0
@ -1364,7 +1366,7 @@ YY_DECL
#line 1367 "lexer.cc"
#line 1369 "lexer.cc"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
@ -1393,13 +1395,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 275 )
if ( yy_current_state >= 279 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
++yy_cp;
}
while ( yy_current_state != 274 );
while ( yy_current_state != 278 );
yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state);
@ -1428,13 +1430,13 @@ do_action: /* This label is used only to access EOF actions. */
{
if ( yy_act == 0 )
fprintf( stderr, "--scanner backing up\n" );
else if ( yy_act < 62 )
else if ( yy_act < 63 )
fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
(long)yy_rule_linenum[yy_act], yytext );
else if ( yy_act == 62 )
else if ( yy_act == 63 )
fprintf( stderr, "--accepting default rule (\"%s\")\n",
yytext );
else if ( yy_act == 63 )
else if ( yy_act == 64 )
fprintf( stderr, "--(end of buffer or a NUL)\n" );
else
fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
@ -1713,133 +1715,138 @@ return isc::eval::EvalParser::make_SUBSTRING(loc);
case 38:
YY_RULE_SETUP
#line 219 "lexer.ll"
return isc::eval::EvalParser::make_ALL(loc);
return isc::eval::EvalParser::make_SPLIT(loc);
YY_BREAK
case 39:
YY_RULE_SETUP
#line 220 "lexer.ll"
return isc::eval::EvalParser::make_CONCAT(loc);
return isc::eval::EvalParser::make_ALL(loc);
YY_BREAK
case 40:
YY_RULE_SETUP
#line 221 "lexer.ll"
return isc::eval::EvalParser::make_IFELSE(loc);
return isc::eval::EvalParser::make_CONCAT(loc);
YY_BREAK
case 41:
YY_RULE_SETUP
#line 222 "lexer.ll"
return isc::eval::EvalParser::make_TOHEXSTRING(loc);
return isc::eval::EvalParser::make_IFELSE(loc);
YY_BREAK
case 42:
YY_RULE_SETUP
#line 223 "lexer.ll"
return isc::eval::EvalParser::make_ADDRTOTEXT(loc);
return isc::eval::EvalParser::make_TOHEXSTRING(loc);
YY_BREAK
case 43:
YY_RULE_SETUP
#line 224 "lexer.ll"
return isc::eval::EvalParser::make_INT8TOTEXT(loc);
return isc::eval::EvalParser::make_ADDRTOTEXT(loc);
YY_BREAK
case 44:
YY_RULE_SETUP
#line 225 "lexer.ll"
return isc::eval::EvalParser::make_INT16TOTEXT(loc);
return isc::eval::EvalParser::make_INT8TOTEXT(loc);
YY_BREAK
case 45:
YY_RULE_SETUP
#line 226 "lexer.ll"
return isc::eval::EvalParser::make_INT32TOTEXT(loc);
return isc::eval::EvalParser::make_INT16TOTEXT(loc);
YY_BREAK
case 46:
YY_RULE_SETUP
#line 227 "lexer.ll"
return isc::eval::EvalParser::make_UINT8TOTEXT(loc);
return isc::eval::EvalParser::make_INT32TOTEXT(loc);
YY_BREAK
case 47:
YY_RULE_SETUP
#line 228 "lexer.ll"
return isc::eval::EvalParser::make_UINT16TOTEXT(loc);
return isc::eval::EvalParser::make_UINT8TOTEXT(loc);
YY_BREAK
case 48:
YY_RULE_SETUP
#line 229 "lexer.ll"
return isc::eval::EvalParser::make_UINT32TOTEXT(loc);
return isc::eval::EvalParser::make_UINT16TOTEXT(loc);
YY_BREAK
case 49:
YY_RULE_SETUP
#line 230 "lexer.ll"
return isc::eval::EvalParser::make_NOT(loc);
return isc::eval::EvalParser::make_UINT32TOTEXT(loc);
YY_BREAK
case 50:
YY_RULE_SETUP
#line 231 "lexer.ll"
return isc::eval::EvalParser::make_AND(loc);
return isc::eval::EvalParser::make_NOT(loc);
YY_BREAK
case 51:
YY_RULE_SETUP
#line 232 "lexer.ll"
return isc::eval::EvalParser::make_OR(loc);
return isc::eval::EvalParser::make_AND(loc);
YY_BREAK
case 52:
YY_RULE_SETUP
#line 233 "lexer.ll"
return isc::eval::EvalParser::make_MEMBER(loc);
return isc::eval::EvalParser::make_OR(loc);
YY_BREAK
case 53:
YY_RULE_SETUP
#line 234 "lexer.ll"
return isc::eval::EvalParser::make_DOT(loc);
return isc::eval::EvalParser::make_MEMBER(loc);
YY_BREAK
case 54:
YY_RULE_SETUP
#line 235 "lexer.ll"
return isc::eval::EvalParser::make_LPAREN(loc);
return isc::eval::EvalParser::make_DOT(loc);
YY_BREAK
case 55:
YY_RULE_SETUP
#line 236 "lexer.ll"
return isc::eval::EvalParser::make_RPAREN(loc);
return isc::eval::EvalParser::make_LPAREN(loc);
YY_BREAK
case 56:
YY_RULE_SETUP
#line 237 "lexer.ll"
return isc::eval::EvalParser::make_LBRACKET(loc);
return isc::eval::EvalParser::make_RPAREN(loc);
YY_BREAK
case 57:
YY_RULE_SETUP
#line 238 "lexer.ll"
return isc::eval::EvalParser::make_RBRACKET(loc);
return isc::eval::EvalParser::make_LBRACKET(loc);
YY_BREAK
case 58:
YY_RULE_SETUP
#line 239 "lexer.ll"
return isc::eval::EvalParser::make_COMA(loc);
return isc::eval::EvalParser::make_RBRACKET(loc);
YY_BREAK
case 59:
YY_RULE_SETUP
#line 240 "lexer.ll"
return isc::eval::EvalParser::make_ANY(loc);
return isc::eval::EvalParser::make_COMA(loc);
YY_BREAK
case 60:
YY_RULE_SETUP
#line 241 "lexer.ll"
return isc::eval::EvalParser::make_PLUS(loc);
return isc::eval::EvalParser::make_ANY(loc);
YY_BREAK
case 61:
YY_RULE_SETUP
#line 242 "lexer.ll"
driver.error (loc, "Invalid character: " + std::string(evaltext));
YY_BREAK
case YY_STATE_EOF(INITIAL):
#line 243 "lexer.ll"
return isc::eval::EvalParser::make_END(loc);
return isc::eval::EvalParser::make_PLUS(loc);
YY_BREAK
case 62:
YY_RULE_SETUP
#line 243 "lexer.ll"
driver.error (loc, "Invalid character: " + std::string(evaltext));
YY_BREAK
case YY_STATE_EOF(INITIAL):
#line 244 "lexer.ll"
return isc::eval::EvalParser::make_END(loc);
YY_BREAK
case 63:
YY_RULE_SETUP
#line 245 "lexer.ll"
ECHO;
YY_BREAK
#line 1842 "lexer.cc"
#line 1849 "lexer.cc"
case YY_END_OF_BUFFER:
{
@ -2158,7 +2165,7 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 275 )
if ( yy_current_state >= 279 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
@ -2191,11 +2198,11 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 275 )
if ( yy_current_state >= 279 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
yy_is_jam = (yy_current_state == 274);
yy_is_jam = (yy_current_state == 278);
return yy_is_jam ? 0 : yy_current_state;
}
@ -2951,7 +2958,7 @@ void yyfree (void * ptr )
/* %ok-for-header */
#line 244 "lexer.ll"
#line 245 "lexer.ll"
using namespace isc::eval;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
/* Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
@ -215,6 +215,7 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]*
"data" return isc::eval::EvalParser::make_DATA(loc);
"enterprise" return isc::eval::EvalParser::make_ENTERPRISE(loc);
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
"split" return isc::eval::EvalParser::make_SPLIT(loc);
"all" return isc::eval::EvalParser::make_ALL(loc);
"concat" return isc::eval::EvalParser::make_CONCAT(loc);
"ifelse" return isc::eval::EvalParser::make_IFELSE(loc);

View File

@ -1,8 +1,8 @@
// A Bison parser, made by GNU Bison 3.8.2.
// A Bison parser, made by GNU Bison 3.3.1.
// Locations for Bison parsers in C++
// Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc.
// Copyright (C) 2002-2015, 2018-2019 Free Software Foundation, Inc.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -15,7 +15,7 @@
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// As a special exception, you may create a larger work that contains
// part or all of the Bison parser skeleton and distribute that work
@ -38,6 +38,7 @@
#ifndef YY_EVAL_LOCATION_HH_INCLUDED
# define YY_EVAL_LOCATION_HH_INCLUDED
# include <algorithm> // std::max
# include <iostream>
# include <string>
@ -53,23 +54,17 @@
# endif
# endif
#line 14 "parser.yy"
#line 14 "parser.yy" // location.cc:339
namespace isc { namespace eval {
#line 59 "location.hh"
#line 60 "location.hh" // location.cc:339
/// A point in a source file.
class position
{
public:
/// Type for file name.
typedef const std::string filename_type;
/// Type for line and column numbers.
typedef int counter_type;
/// Construct a position.
explicit position (filename_type* f = YY_NULLPTR,
counter_type l = 1,
counter_type c = 1)
explicit position (std::string* f = YY_NULLPTR,
unsigned l = 1u,
unsigned c = 1u)
: filename (f)
, line (l)
, column (c)
@ -77,9 +72,9 @@ namespace isc { namespace eval {
/// Initialization.
void initialize (filename_type* fn = YY_NULLPTR,
counter_type l = 1,
counter_type c = 1)
void initialize (std::string* fn = YY_NULLPTR,
unsigned l = 1u,
unsigned c = 1u)
{
filename = fn;
line = l;
@ -89,40 +84,41 @@ namespace isc { namespace eval {
/** \name Line and Column related manipulators
** \{ */
/// (line related) Advance to the COUNT next lines.
void lines (counter_type count = 1)
void lines (int count = 1)
{
if (count)
{
column = 1;
column = 1u;
line = add_ (line, count, 1);
}
}
/// (column related) Advance to the COUNT next columns.
void columns (counter_type count = 1)
void columns (int count = 1)
{
column = add_ (column, count, 1);
}
/** \} */
/// File name to which this position refers.
filename_type* filename;
std::string* filename;
/// Current line number.
counter_type line;
unsigned line;
/// Current column number.
counter_type column;
unsigned column;
private:
/// Compute max (min, lhs+rhs).
static counter_type add_ (counter_type lhs, counter_type rhs, counter_type min)
static unsigned add_ (unsigned lhs, int rhs, int min)
{
return lhs + rhs < min ? min : lhs + rhs;
return static_cast<unsigned> (std::max (min,
static_cast<int> (lhs) + rhs));
}
};
/// Add \a width columns, in place.
inline position&
operator+= (position& res, position::counter_type width)
operator+= (position& res, int width)
{
res.columns (width);
return res;
@ -130,25 +126,43 @@ namespace isc { namespace eval {
/// Add \a width columns.
inline position
operator+ (position res, position::counter_type width)
operator+ (position res, int width)
{
return res += width;
}
/// Subtract \a width columns, in place.
inline position&
operator-= (position& res, position::counter_type width)
operator-= (position& res, int width)
{
return res += -width;
}
/// Subtract \a width columns.
inline position
operator- (position res, position::counter_type width)
operator- (position res, int width)
{
return res -= width;
}
/// Compare two position objects.
inline bool
operator== (const position& pos1, const position& pos2)
{
return (pos1.line == pos2.line
&& pos1.column == pos2.column
&& (pos1.filename == pos2.filename
|| (pos1.filename && pos2.filename
&& *pos1.filename == *pos2.filename)));
}
/// Compare two position objects.
inline bool
operator!= (const position& pos1, const position& pos2)
{
return !(pos1 == pos2);
}
/** \brief Intercept output stream redirection.
** \param ostr the destination output stream
** \param pos a reference to the position to redirect
@ -166,10 +180,6 @@ namespace isc { namespace eval {
class location
{
public:
/// Type for file name.
typedef position::filename_type filename_type;
/// Type for line and column numbers.
typedef position::counter_type counter_type;
/// Construct a location from \a b to \a e.
location (const position& b, const position& e)
@ -184,18 +194,18 @@ namespace isc { namespace eval {
{}
/// Construct a 0-width location in \a f, \a l, \a c.
explicit location (filename_type* f,
counter_type l = 1,
counter_type c = 1)
explicit location (std::string* f,
unsigned l = 1u,
unsigned c = 1u)
: begin (f, l, c)
, end (f, l, c)
{}
/// Initialization.
void initialize (filename_type* f = YY_NULLPTR,
counter_type l = 1,
counter_type c = 1)
void initialize (std::string* f = YY_NULLPTR,
unsigned l = 1u,
unsigned c = 1u)
{
begin.initialize (f, l, c);
end = begin;
@ -211,13 +221,13 @@ namespace isc { namespace eval {
}
/// Extend the current location to the COUNT next columns.
void columns (counter_type count = 1)
void columns (int count = 1)
{
end += count;
}
/// Extend the current location to the COUNT next lines.
void lines (counter_type count = 1)
void lines (int count = 1)
{
end.lines (count);
}
@ -232,49 +242,57 @@ namespace isc { namespace eval {
};
/// Join two locations, in place.
inline location&
operator+= (location& res, const location& end)
inline location& operator+= (location& res, const location& end)
{
res.end = end.end;
return res;
}
/// Join two locations.
inline location
operator+ (location res, const location& end)
inline location operator+ (location res, const location& end)
{
return res += end;
}
/// Add \a width columns to the end position, in place.
inline location&
operator+= (location& res, location::counter_type width)
inline location& operator+= (location& res, int width)
{
res.columns (width);
return res;
}
/// Add \a width columns to the end position.
inline location
operator+ (location res, location::counter_type width)
inline location operator+ (location res, int width)
{
return res += width;
}
/// Subtract \a width columns to the end position, in place.
inline location&
operator-= (location& res, location::counter_type width)
inline location& operator-= (location& res, int width)
{
return res += -width;
}
/// Subtract \a width columns to the end position.
inline location
operator- (location res, location::counter_type width)
inline location operator- (location res, int width)
{
return res -= width;
}
/// Compare two location objects.
inline bool
operator== (const location& loc1, const location& loc2)
{
return loc1.begin == loc2.begin && loc1.end == loc2.end;
}
/// Compare two location objects.
inline bool
operator!= (const location& loc1, const location& loc2)
{
return !(loc1 == loc2);
}
/** \brief Intercept output stream redirection.
** \param ostr the destination output stream
** \param loc a reference to the location to redirect
@ -285,8 +303,7 @@ namespace isc { namespace eval {
std::basic_ostream<YYChar>&
operator<< (std::basic_ostream<YYChar>& ostr, const location& loc)
{
location::counter_type end_col
= 0 < loc.end.column ? loc.end.column - 1 : 0;
unsigned end_col = 0 < loc.end.column ? loc.end.column - 1 : 0;
ostr << loc.begin;
if (loc.end.filename
&& (!loc.begin.filename
@ -299,8 +316,7 @@ namespace isc { namespace eval {
return ostr;
}
#line 14 "parser.yy"
#line 14 "parser.yy" // location.cc:339
} } // isc::eval
#line 305 "location.hh"
#line 322 "location.hh" // location.cc:339
#endif // !YY_EVAL_LOCATION_HH_INCLUDED

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
/* Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
@ -70,6 +70,7 @@ using namespace isc::eval;
YIADDR "yiaddr"
SIADDR "siaddr"
SUBSTRING "substring"
SPLIT "split"
ALL "all"
COMA ","
CONCAT "concat"
@ -360,6 +361,11 @@ string_expr : STRING
TokenPtr sub(new TokenSubstring());
ctx.expression.push_back(sub);
}
| SPLIT "(" string_expr "," string_expr "," int_expr ")"
{
TokenPtr split(new TokenSplit());
ctx.expression.push_back(split);
}
| CONCAT "(" string_expr "," string_expr ")"
{
TokenPtr conc(new TokenConcat());
@ -622,6 +628,12 @@ length_expr : INTEGER
ctx.expression.push_back(str);
}
;
int_expr : INTEGER
{
TokenPtr str(new TokenString($1));
ctx.expression.push_back(str);
}
;
%%
void

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2019,2021 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@ -20,6 +20,9 @@
#include <log/logger_support.h>
#include <testutils/log_utils.h>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/constants.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
@ -255,6 +258,45 @@ public:
}
}
/// @brief Verify that the split eval works properly
///
/// This function takes the parameters and sets up the value
/// stack then executes the eval and checks the results.
///
/// @param test_string The string to operate on
/// @param test_delimiters The string of delimiter characters to split upon
/// @param test_field The field number of the desired field
/// @param result_string The expected result of the eval
/// @param should_throw The eval will throw
void verifySplitEval(const std::string& test_string,
const std::string& test_delimeters,
const std::string& test_field,
const std::string& result_string,
bool should_throw = false) {
// create the token
ASSERT_NO_THROW(t_.reset(new TokenSplit()));
// push values on stack
values_.push(test_string);
values_.push(test_delimeters);
values_.push(test_field);
// evaluate the token
if (should_throw) {
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError);
ASSERT_EQ(0, values_.size());
} else {
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
// verify results
ASSERT_EQ(1, values_.size());
EXPECT_EQ(result_string, values_.top());
// remove result
values_.pop();
}
}
/// @brief Creates vendor-option with specified value and adds it to packet
///
/// This method creates specified vendor option, removes any existing
@ -3324,4 +3366,114 @@ TEST_F(TokenTest, integer) {
testInteger(encode(4294967295), 4294967295);
}
// Verify TokenSplit::eval, single delimeter.
TEST_F(TokenTest, split) {
// Get the whole string
std::string input(".two.three..five.");
std::string delims(".");
// Empty input string should yield empty result.
verifySplitEval("", delims, "1", "");
// Empty delimiters string should original string result.
verifySplitEval(input, "", "1", input);
// Field number less than one yield empty result.
verifySplitEval(input, delims, "0", "");
// Now get each field in succession.
verifySplitEval(input, delims, "1", "");
verifySplitEval(input, delims, "2", "two");
verifySplitEval(input, delims, "3", "three");
verifySplitEval(input, delims, "4", "");
verifySplitEval(input, delims, "5", "five");
verifySplitEval(input, delims, "6", "");
// Too large of a field should yield empty result.
verifySplitEval(input, delims, "7", "");
// A string without delimiters returns as field 1.
verifySplitEval("just_one", delims, "1", "just_one");
// Check that the debug output was correct. Add the strings
// to the test vector in the class and then call checkFile
// for comparison
addString("EVAL_DEBUG_SPLIT_EMPTY Popping field 1, delimiters .,"
" string , pushing result 0x");
addString("EVAL_DEBUG_SPLIT_DELIM_EMPTY Popping field 1, delimiters ,"
" string .two.three..five., pushing result 0x2E74776F2E74687265652E2E666976652E");
addString("EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE Popping field 0, delimiters .,"
" string .two.three..five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT Popping field 1, delimiters .,"
" string .two.three..five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT Popping field 2, delimiters .,"
" string .two.three..five., pushing result 0x74776F");
addString("EVAL_DEBUG_SPLIT Popping field 3, delimiters .,"
" string .two.three..five., pushing result 0x7468726565");
addString("EVAL_DEBUG_SPLIT Popping field 4, delimiters .,"
" string .two.three..five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT Popping field 5, delimiters .,"
" string .two.three..five., pushing result 0x66697665");
addString("EVAL_DEBUG_SPLIT Popping field 6, delimiters .,"
" string .two.three..five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE Popping field 7, delimiters .,"
" string .two.three..five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT Popping field 1, delimiters .,"
" string just_one, pushing result 0x6A7573745F6F6E65");
EXPECT_TRUE(checkFile());
}
// Verify TokenSplit::eval with more than one delimeter.
TEST_F(TokenTest, splitMultipleDelims) {
// Get the whole string
std::string input(".two:three.:five.");
std::string delims(".:");
// Empty input string should yield empty result.
verifySplitEval("", delims, "1", "");
// Too small of a field should yield empty result.
verifySplitEval(input, delims, "0", "");
// Now get each field in succession.
verifySplitEval(input, delims, "1", "");
verifySplitEval(input, delims, "2", "two");
verifySplitEval(input, delims, "3", "three");
verifySplitEval(input, delims, "4", "");
verifySplitEval(input, delims, "5", "five");
verifySplitEval(input, delims, "6", "");
// Too large of a field should yield empty result.
verifySplitEval(input, delims, "7", "");
// A string without delimiters returns as field 1.
verifySplitEval("just_one", delims, "1", "just_one");
// Check that the debug output was correct. Add the strings
// to the test vector in the class and then call checkFile
// for comparison
addString("EVAL_DEBUG_SPLIT_EMPTY Popping field 1, delimiters .:,"
" string , pushing result 0x");
addString("EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE Popping field 0, delimiters .:,"
" string .two:three.:five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT Popping field 1, delimiters .:,"
" string .two:three.:five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT Popping field 2, delimiters .:,"
" string .two:three.:five., pushing result 0x74776F");
addString("EVAL_DEBUG_SPLIT Popping field 3, delimiters .:,"
" string .two:three.:five., pushing result 0x7468726565");
addString("EVAL_DEBUG_SPLIT Popping field 4, delimiters .:,"
" string .two:three.:five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT Popping field 5, delimiters .:,"
" string .two:three.:five., pushing result 0x66697665");
addString("EVAL_DEBUG_SPLIT Popping field 6, delimiters .:,"
" string .two:three.:five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE Popping field 7, delimiters .:,"
" string .two:three.:five., pushing result 0x");
addString("EVAL_DEBUG_SPLIT Popping field 1, delimiters .:,"
" string just_one, pushing result 0x6A7573745F6F6E65");
EXPECT_TRUE(checkFile());
}
};

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@ -19,6 +19,10 @@
#include <dhcp/dhcp6.h>
#include <dhcp/option_vendor.h>
#include <dhcp/option_vendor_class.h>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <cstring>
#include <string>
#include <iomanip>
@ -775,6 +779,90 @@ TokenSubstring::evaluate(Pkt& /*pkt*/, ValueStack& values) {
.arg(toHex(values.top()));
}
void
TokenSplit::evaluate(Pkt& /*pkt*/, ValueStack& values) {
if (values.size() < 3) {
isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
"3 values for split operator, got " << values.size());
}
// Pop the parameters.
string field_str = values.top();
values.pop();
string delim_str = values.top();
values.pop();
string string_str = values.top();
values.pop();
// If we have no string to start with we push an empty string and leave
if (string_str.empty()) {
values.push("");
// Log what we popped and pushed
LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SPLIT_EMPTY)
.arg(field_str)
.arg(delim_str)
.arg(string_str)
.arg("0x");
return;
}
// Convert the starting position and length from strings to numbers
// the length may also be "all" in which case simply make it the
// length of the string.
// If we have a problem push an empty string and leave
int field;
try {
field = boost::lexical_cast<int>(field_str);
} catch (const boost::bad_lexical_cast&) {
isc_throw(EvalTypeError, "the parameter '" << field_str
<< "' for the field field for split "
<< "couldn't be converted to an integer.");
}
// If we have no string to start with we push an empty string and leave
if (delim_str.empty()) {
values.push(string_str);
// Log what we popped and pushed
LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SPLIT_DELIM_EMPTY)
.arg(field_str)
.arg(delim_str)
.arg(string_str)
.arg(toHex(values.top()));
return;
}
// Split the string into fields.
std::vector<std::string> fields;
boost::split(fields, string_str, boost::is_any_of(delim_str),
boost::algorithm::token_compress_off);
// Range check the field.
if (field < 1 || field > fields.size()) {
// Push an empty string if field is out of range.
values.push("");
// Log what we popped and pushed
LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE)
.arg(field_str)
.arg(delim_str)
.arg(string_str)
.arg("0x");
return;
}
// Push the desired field.
values.push(fields[field - 1]);
// Log what we popped and pushed
LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SPLIT)
.arg(field_str)
.arg(delim_str)
.arg(string_str)
.arg(toHex(values.top()));
}
void
TokenConcat::evaluate(Pkt& /*pkt*/, ValueStack& values) {
if (values.size() < 2) {

View File

@ -453,7 +453,7 @@ protected:
/// encapsulation
///
/// This represents a reference to a given option similar to TokenOption
/// but from within the information from a relay. In the expresssion
/// but from within the information from a relay. In the expression
/// relay6[nest-level].option[option-code], nest-level indicates which
/// of the relays to examine and option-code which option to extract.
///
@ -795,6 +795,50 @@ public:
void evaluate(Pkt& pkt, ValueStack& values);
};
class TokenSplit : public Token {
public:
/// @brief Constructor (does nothing)
TokenSplit() {}
/// @brief Extract a field from a delimited string
///
/// Evaluation does not use packet information. It requires at least
/// three values to be present on the stack. It will consume the top
/// three values on the stack as parameters and push the resulting substring
/// onto the stack. From the top it expects the values on the stack as:
/// - field
/// - delims
/// - str
///
/// str is the string to split. If it is empty, an empty
/// string is pushed onto the value stack.
/// delims is string of character delimiters by which to split str. If it is
/// empty the entire value of str will be pushed on onto the value stack.
/// field is the field number (starting at 1) of the desired field. If it is
/// out of range an empty string is pushed on the the value stack.
///
/// The following examples all use the base string "one.two..four" and shows
/// the value returned for a given field:
/// ```
/// field => value
/// --------------
/// - 0 => ""
/// - 1 => "one"
/// - 2 => "two"
/// - 3 => ""
/// - 4 => "four"
/// - 5 => ""
/// ```
///
/// @throw EvalBadStack if there are less than 3 values on stack
/// @throw EvalTypeError if field is not a number
///
/// @param pkt (unused)
/// @param values - stack of values (3 arguments will be popped, 1 result
/// will be pushed)
void evaluate(Pkt& pkt, ValueStack& values);
};
/// @brief Token that represents concat operator (concatenates two other tokens)
///
/// For example in the sub-expression "concat('foo','bar')" the result