forked from osmocom/wireshark
dfilter: Add bitwise masking of bits
Add support for masking of bits. Before the bitwise operator could only test bits, it did not support clearing bits. This allows testing if any combination of bits are set/unset more naturally with a single test. Previously this was only possible by combining several bitwise predicates. Bitwise is implemented as a test node, even though it is not. Maybe the test node should be renamed to something else. Fixes #17246.pespin/osmux-wip
parent
3e3db6cd3e
commit
16729be2c1
|
@ -378,8 +378,8 @@ following bit field operation is supported:
|
|||
|
||||
bitwise_and, & Bitwise AND
|
||||
|
||||
The bitwise AND operation allows testing to see if one or more bits are set.
|
||||
Bitwise AND operates on integer protocol fields and slices.
|
||||
The bitwise AND operation allows masking bits and testing to see if one or
|
||||
more bits are set. Bitwise AND operates on integer protocol fields and slices.
|
||||
|
||||
When testing for TCP SYN packets, you can write:
|
||||
|
||||
|
|
|
@ -63,6 +63,8 @@ They previously shipped with Npcap 1.55.
|
|||
** Floats must be written with a leading and ending digit. For example the values ".7" and "7." are now invalid as floats.
|
||||
It must be written "7.0" and "0.7" respectively.
|
||||
** The operator "~=" is deprecated and will be removed in a future version. Use "!==" with the same meaning instead.
|
||||
** The "bitwise and" operator is now a first-class bit operator, not a boolean operator. In particular this means
|
||||
it is now possible to mask bits, e.g.: frame[0] & 0x0F == 3.
|
||||
|
||||
* text2pcap and "Import from Hex Dump":
|
||||
** text2pcap supports writing the output file in all the capture file formats
|
||||
|
|
|
@ -102,6 +102,7 @@ dfilter_vfail(dfwork_t *dfw, const char *format, va_list args);
|
|||
void
|
||||
dfilter_fail(dfwork_t *dfw, const char *format, ...) G_GNUC_PRINTF(2, 3);
|
||||
|
||||
WS_NORETURN
|
||||
void
|
||||
dfilter_fail_throw(dfwork_t *dfw, long code, const char *format, ...) G_GNUC_PRINTF(3, 4);
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ const char *tokenstr(int token)
|
|||
case TOKEN_TEST_GE: return "TEST_GE";
|
||||
case TOKEN_TEST_CONTAINS: return "TEST_CONTAINS";
|
||||
case TOKEN_TEST_MATCHES: return "TEST_MATCHES";
|
||||
case TOKEN_TEST_BITWISE_AND: return "TEST_BITWISE_AND";
|
||||
case TOKEN_BITWISE_AND: return "BITWISE_AND";
|
||||
case TOKEN_TEST_NOT: return "TEST_NOT";
|
||||
case TOKEN_STRING: return "STRING";
|
||||
case TOKEN_CHARCONST: return "CHARCONST";
|
||||
|
|
|
@ -272,9 +272,14 @@ dfvm_dump(FILE *f, dfilter_t *df)
|
|||
id, arg1_str, arg2_str);
|
||||
break;
|
||||
|
||||
case ANY_BITWISE_AND:
|
||||
fprintf(f, "%05d ANY_BITWISE_AND\t%s & %s\n",
|
||||
id, arg1_str, arg2_str);
|
||||
case MK_BITWISE_AND:
|
||||
fprintf(f, "%05d MK_BITWISE_AND\t%s & %s -> %s\n",
|
||||
id, arg1_str, arg2_str, arg3_str);
|
||||
break;
|
||||
|
||||
case ANY_NOTZERO:
|
||||
fprintf(f, "%05d ANY_NOTZERO\t%s\n",
|
||||
id, arg1_str);
|
||||
break;
|
||||
|
||||
case ANY_CONTAINS:
|
||||
|
@ -380,6 +385,7 @@ enum match_how {
|
|||
};
|
||||
|
||||
typedef gboolean (*DFVMCompareFunc)(const fvalue_t*, const fvalue_t*);
|
||||
typedef gboolean (*DFVMTestFunc)(const fvalue_t*);
|
||||
|
||||
static gboolean
|
||||
cmp_test(enum match_how how, DFVMCompareFunc match_func,
|
||||
|
@ -410,6 +416,39 @@ cmp_test(enum match_how how, DFVMCompareFunc match_func,
|
|||
return want_all;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cmp_test_unary(enum match_how how, DFVMTestFunc test_func, GSList *arg1)
|
||||
{
|
||||
GSList *list1;
|
||||
gboolean want_all = (how == MATCH_ALL);
|
||||
gboolean want_any = (how == MATCH_ANY);
|
||||
gboolean have_match;
|
||||
|
||||
list1 = arg1;
|
||||
|
||||
while (list1) {
|
||||
have_match = test_func(list1->data);
|
||||
if (want_all && !have_match) {
|
||||
return FALSE;
|
||||
}
|
||||
else if (want_any && have_match) {
|
||||
return TRUE;
|
||||
}
|
||||
list1 = g_slist_next(list1);
|
||||
}
|
||||
/* want_all || !want_any */
|
||||
return want_all;
|
||||
}
|
||||
|
||||
/* cmp(A) <=> cmp(a1) OR cmp(a2) OR cmp(a3) OR ... */
|
||||
static gboolean
|
||||
any_test_unary(dfilter_t *df, DFVMTestFunc func, dfvm_value_t *arg1)
|
||||
{
|
||||
ws_assert(arg1->type == REGISTER);
|
||||
GSList *list1 = df->registers[arg1->value.numeric];
|
||||
return cmp_test_unary(MATCH_ANY, func, list1);
|
||||
}
|
||||
|
||||
/* cmp(A) <=> cmp(a1) OR cmp(a2) OR cmp(a3) OR ... */
|
||||
static gboolean
|
||||
any_test(dfilter_t *df, DFVMCompareFunc cmp,
|
||||
|
@ -562,6 +601,77 @@ call_function(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2,
|
|||
return accum;
|
||||
}
|
||||
|
||||
static void debug_op_error(fvalue_t *v1, fvalue_t *v2, const char *op, const char *msg)
|
||||
{
|
||||
char *s1 = fvalue_to_debug_repr(NULL, v1);
|
||||
char *s2 = fvalue_to_debug_repr(NULL, v2);
|
||||
ws_noisy("Error: %s %s %s: %s", s1, op, s2, msg);
|
||||
g_free(s1);
|
||||
g_free(s2);
|
||||
}
|
||||
|
||||
|
||||
typedef fvalue_t* (*DFVMBitwiseFunc)(const fvalue_t*, const fvalue_t*, char **);
|
||||
|
||||
static void
|
||||
mk_bitwise_internal(DFVMBitwiseFunc func,
|
||||
GSList *arg1, GSList *arg2, GSList **retval)
|
||||
{
|
||||
GSList *list1, *list2;
|
||||
GSList *to_list = NULL;
|
||||
fvalue_t *val1, *val2;
|
||||
fvalue_t *result;
|
||||
char *err_msg = NULL;
|
||||
|
||||
list1 = arg1;
|
||||
while (list1) {
|
||||
list2 = arg2;
|
||||
while (list2) {
|
||||
val1 = list1->data;
|
||||
val2 = list2->data;
|
||||
result = func(val1, val2, &err_msg);
|
||||
if (result == NULL) {
|
||||
debug_op_error(val1, val2, "&", err_msg);
|
||||
g_free(err_msg);
|
||||
err_msg = NULL;
|
||||
}
|
||||
else {
|
||||
to_list = g_slist_prepend(to_list, result);
|
||||
}
|
||||
list2 = g_slist_next(list2);
|
||||
}
|
||||
list1 = g_slist_next(list1);
|
||||
}
|
||||
*retval = to_list;
|
||||
}
|
||||
|
||||
static void
|
||||
mk_bitwise(dfilter_t *df, DFVMBitwiseFunc func,
|
||||
dfvm_value_t *arg1, dfvm_value_t *arg2, dfvm_value_t *to_arg)
|
||||
{
|
||||
ws_assert(arg1->type == REGISTER);
|
||||
GSList *list1 = df->registers[arg1->value.numeric];
|
||||
GSList *result = NULL;
|
||||
|
||||
if (arg2->type == REGISTER) {
|
||||
GSList *list2 = df->registers[arg2->value.numeric];
|
||||
|
||||
mk_bitwise_internal(func, list1, list2, &result);
|
||||
}
|
||||
else if (arg2->type == FVALUE) {
|
||||
GSList list2;
|
||||
|
||||
list2.data = arg2->value.fvalue;
|
||||
list2.next = NULL;
|
||||
mk_bitwise_internal(func, list1, &list2, &result);
|
||||
}
|
||||
else {
|
||||
ws_assert_not_reached();
|
||||
}
|
||||
df->registers[to_arg->value.numeric] = result;
|
||||
df->free_registers[to_arg->value.numeric] = (GDestroyNotify)fvalue_free;
|
||||
}
|
||||
|
||||
gboolean
|
||||
dfvm_apply(dfilter_t *df, proto_tree *tree)
|
||||
{
|
||||
|
@ -646,8 +756,12 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
|
|||
accum = any_test(df, fvalue_le, arg1, arg2);
|
||||
break;
|
||||
|
||||
case ANY_BITWISE_AND:
|
||||
accum = any_test(df, fvalue_bitwise_and, arg1, arg2);
|
||||
case MK_BITWISE_AND:
|
||||
mk_bitwise(df, fvalue_bitwise_and, arg1, arg2, arg3);
|
||||
break;
|
||||
|
||||
case ANY_NOTZERO:
|
||||
accum = any_test_unary(df, fvalue_is_true, arg1);
|
||||
break;
|
||||
|
||||
case ANY_CONTAINS:
|
||||
|
|
|
@ -61,10 +61,11 @@ typedef enum {
|
|||
ANY_GE,
|
||||
ANY_LT,
|
||||
ANY_LE,
|
||||
ANY_BITWISE_AND,
|
||||
ANY_CONTAINS,
|
||||
ANY_MATCHES,
|
||||
ANY_NOTZERO,
|
||||
MK_RANGE,
|
||||
MK_BITWISE_AND,
|
||||
CALL_FUNCTION,
|
||||
ANY_IN_RANGE
|
||||
|
||||
|
|
|
@ -279,6 +279,32 @@ gen_relation_in(dfwork_t *dfw, stnode_t *st_arg1, stnode_t *st_arg2)
|
|||
set_nodelist_free(nodelist_head);
|
||||
}
|
||||
|
||||
static dfvm_value_t *
|
||||
gen_bitwise(dfwork_t *dfw, stnode_t *st_arg, GSList **jumps_ptr)
|
||||
{
|
||||
stnode_t *left, *right;
|
||||
test_op_t st_op;
|
||||
dfvm_value_t *reg_val, *val1, *val2;
|
||||
dfvm_opcode_t op;
|
||||
|
||||
sttype_test_get(st_arg, &st_op, &left, &right);
|
||||
|
||||
switch (st_op) {
|
||||
case OP_BITWISE_AND:
|
||||
op = MK_BITWISE_AND;
|
||||
break;
|
||||
default:
|
||||
ws_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
|
||||
val1 = gen_entity(dfw, left, jumps_ptr);
|
||||
val2 = gen_entity(dfw, right, jumps_ptr);
|
||||
reg_val = dfvm_value_new_register(dfw->next_register++);
|
||||
gen_relation_insn(dfw, op, val1, val2, reg_val, NULL);
|
||||
return reg_val;
|
||||
}
|
||||
|
||||
/* Parse an entity, returning the reg that it gets put into.
|
||||
* p_jmp will be set if it has to be set by the calling code; it should
|
||||
* be set to the place to jump to, to return to the calling code,
|
||||
|
@ -314,6 +340,9 @@ gen_entity(dfwork_t *dfw, stnode_t *st_arg, GSList **jumps_ptr)
|
|||
else if (e_type == STTYPE_PCRE) {
|
||||
val = dfvm_value_new_pcre(stnode_steal_data(st_arg));
|
||||
}
|
||||
else if (e_type == STTYPE_BITWISE) {
|
||||
val = gen_bitwise(dfw, st_arg, jumps_ptr);
|
||||
}
|
||||
else {
|
||||
/* printf("sttype_id is %u\n", (unsigned)e_type); */
|
||||
ws_assert_not_reached();
|
||||
|
@ -328,7 +357,9 @@ gen_test(dfwork_t *dfw, stnode_t *st_node)
|
|||
test_op_t st_op;
|
||||
stnode_t *st_arg1, *st_arg2;
|
||||
dfvm_insn_t *insn;
|
||||
dfvm_value_t *jmp;
|
||||
dfvm_value_t *jmp, *val1;
|
||||
GSList *jumps = NULL;
|
||||
|
||||
header_field_info *hfinfo;
|
||||
|
||||
sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2);
|
||||
|
@ -359,6 +390,16 @@ gen_test(dfwork_t *dfw, stnode_t *st_node)
|
|||
|
||||
break;
|
||||
|
||||
case TEST_OP_NOTZERO:
|
||||
val1 = gen_entity(dfw, st_arg1, &jumps);
|
||||
insn = dfvm_insn_new(ANY_NOTZERO);
|
||||
insn->arg1 = dfvm_value_ref(val1);
|
||||
dfw_append_insn(dfw, insn);
|
||||
g_slist_foreach(jumps, fixup_jumps, dfw);
|
||||
g_slist_free(jumps);
|
||||
jumps = NULL;
|
||||
break;
|
||||
|
||||
case TEST_OP_NOT:
|
||||
gencode(dfw, st_arg1);
|
||||
insn = dfvm_insn_new(NOT);
|
||||
|
@ -421,8 +462,8 @@ gen_test(dfwork_t *dfw, stnode_t *st_node)
|
|||
gen_relation(dfw, ANY_LE, st_arg1, st_arg2);
|
||||
break;
|
||||
|
||||
case TEST_OP_BITWISE_AND:
|
||||
gen_relation(dfw, ANY_BITWISE_AND, st_arg1, st_arg2);
|
||||
case OP_BITWISE_AND:
|
||||
ws_assert_not_reached();
|
||||
break;
|
||||
|
||||
case TEST_OP_CONTAINS:
|
||||
|
|
|
@ -127,30 +127,35 @@ logical_test(T) ::= entity(E).
|
|||
sttype_test_set1_args(T, E);
|
||||
}
|
||||
|
||||
logical_test(T) ::= bitwise_term(E).
|
||||
{
|
||||
T = new_test(dfw, TEST_OP_NOTZERO, NULL);
|
||||
sttype_test_set1_args(T, E);
|
||||
}
|
||||
|
||||
|
||||
/* Entities, or things that can be compared/tested/checked */
|
||||
entity(E) ::= STRING(S).
|
||||
atom(E) ::= STRING(S).
|
||||
{
|
||||
E = stnode_new_string(df_lval_value(S), df_lval_value(S));
|
||||
df_lval_free(S, FALSE);
|
||||
}
|
||||
entity(E) ::= CHARCONST(C).
|
||||
atom(E) ::= CHARCONST(C).
|
||||
{
|
||||
E = stnode_new_charconst(df_lval_number(C), df_lval_value(C));
|
||||
df_lval_free(C, FALSE);
|
||||
}
|
||||
entity(E) ::= UNPARSED(U).
|
||||
atom(E) ::= UNPARSED(U).
|
||||
{
|
||||
E = stnode_new_unparsed(df_lval_value(U), df_lval_value(U));
|
||||
df_lval_free(U, FALSE);
|
||||
}
|
||||
entity(E) ::= LITERAL(S).
|
||||
atom(E) ::= LITERAL(S).
|
||||
{
|
||||
E = stnode_new_literal(df_lval_value(S), df_lval_value(S));
|
||||
df_lval_free(S, FALSE);
|
||||
}
|
||||
entity(E) ::= IDENTIFIER(F).
|
||||
atom(E) ::= IDENTIFIER(F).
|
||||
{
|
||||
char *name = df_lval_value(F);
|
||||
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, name);
|
||||
|
@ -160,9 +165,21 @@ entity(E) ::= IDENTIFIER(F).
|
|||
E = stnode_new(STTYPE_FIELD, hfinfo, name);
|
||||
df_lval_free(F, FALSE);
|
||||
}
|
||||
entity(E) ::= atom(A). { E = A; }
|
||||
entity(E) ::= range(R). { E = R; }
|
||||
entity(E) ::= function(F). { E = F; }
|
||||
|
||||
bitwise_term(T) ::= entity(F) BITWISE_AND(B) entity(M).
|
||||
{
|
||||
T = stnode_new(STTYPE_BITWISE, NULL, df_lval_value(B));
|
||||
sttype_test_set2(T, OP_BITWISE_AND, F, M);
|
||||
df_lval_free(B, FALSE);
|
||||
}
|
||||
|
||||
|
||||
term(T) ::= entity(E). { T = E; }
|
||||
term(T) ::= bitwise_term(E). { T = E; }
|
||||
|
||||
|
||||
/* Ranges */
|
||||
range(R) ::= entity(E) LBRACKET range_node_list(L) RBRACKET.
|
||||
|
@ -207,16 +224,15 @@ cmp_op(O) ::= TEST_GT(L). { O = new_test(dfw, TEST_OP_GT, L); }
|
|||
cmp_op(O) ::= TEST_GE(L). { O = new_test(dfw, TEST_OP_GE, L); }
|
||||
cmp_op(O) ::= TEST_LT(L). { O = new_test(dfw, TEST_OP_LT, L); }
|
||||
cmp_op(O) ::= TEST_LE(L). { O = new_test(dfw, TEST_OP_LE, L); }
|
||||
cmp_op(O) ::= TEST_BITWISE_AND(L). { O = new_test(dfw, TEST_OP_BITWISE_AND, L); }
|
||||
|
||||
comparison_test(T) ::= entity(E) cmp_op(O) entity(F).
|
||||
comparison_test(T) ::= term(E) cmp_op(O) term(F).
|
||||
{
|
||||
T = O;
|
||||
sttype_test_set2_args(O, E, F);
|
||||
}
|
||||
|
||||
/* 'a == b == c' or 'a < b <= c <= d < e' */
|
||||
comparison_test(T) ::= entity(E) cmp_op(O) comparison_test(R).
|
||||
comparison_test(T) ::= term(E) cmp_op(O) comparison_test(R).
|
||||
{
|
||||
stnode_t *L, *F;
|
||||
/* for now generate it like E O F TEST_OP_AND F P G, later it could be optimized
|
||||
|
|
|
@ -137,8 +137,6 @@ WORD_CHAR [][:alnum:]_:/+-]
|
|||
"lt" return simple(TOKEN_TEST_LT);
|
||||
"<=" return simple(TOKEN_TEST_LE);
|
||||
"le" return simple(TOKEN_TEST_LE);
|
||||
"bitwise_and" return simple(TOKEN_TEST_BITWISE_AND);
|
||||
"&" return simple(TOKEN_TEST_BITWISE_AND);
|
||||
"contains" return simple(TOKEN_TEST_CONTAINS);
|
||||
"~" return simple(TOKEN_TEST_MATCHES);
|
||||
"matches" return simple(TOKEN_TEST_MATCHES);
|
||||
|
@ -150,6 +148,9 @@ WORD_CHAR [][:alnum:]_:/+-]
|
|||
"or" return simple(TOKEN_TEST_OR);
|
||||
"in" return simple(TOKEN_TEST_IN);
|
||||
|
||||
"&" return simple(TOKEN_BITWISE_AND);
|
||||
"bitwise_and" return simple(TOKEN_BITWISE_AND);
|
||||
|
||||
"[" {
|
||||
BEGIN(RANGE);
|
||||
return simple(TOKEN_LBRACKET);
|
||||
|
|
|
@ -38,6 +38,12 @@ semcheck(dfwork_t *dfw, stnode_t *st_node);
|
|||
static void
|
||||
check_function(dfwork_t *dfw, stnode_t *st_node);
|
||||
|
||||
static ftenum_t
|
||||
check_bitwise_entity(dfwork_t *dfw, stnode_t *st_node, stnode_t *st_arg, ftenum_t ftype);
|
||||
|
||||
static ftenum_t
|
||||
check_bitwise_operation(dfwork_t *dfw, stnode_t *st_node);
|
||||
|
||||
static fvalue_t *
|
||||
mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, const char *s);
|
||||
|
||||
|
@ -903,6 +909,36 @@ again:
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_relation_LHS_BITWISE(dfwork_t *dfw, test_op_t st_op _U_,
|
||||
FtypeCanFunc can_func _U_, gboolean allow_partial_value,
|
||||
stnode_t *st_node _U_,
|
||||
stnode_t *st_arg1, stnode_t *st_arg2)
|
||||
{
|
||||
stnode_t *bitwise_entity;
|
||||
sttype_id_t bitwise_entity_type;
|
||||
|
||||
LOG_NODE(st_node);
|
||||
|
||||
/* (arg1: bitwise) <relop> (arg2: rhs) */
|
||||
check_bitwise_operation(dfw, st_arg1);
|
||||
|
||||
sttype_test_get(st_arg1, NULL, &bitwise_entity, NULL);
|
||||
bitwise_entity_type = stnode_type_id(bitwise_entity);
|
||||
|
||||
if (bitwise_entity_type == STTYPE_FIELD) {
|
||||
check_relation_LHS_FIELD(dfw, st_op, can_func, allow_partial_value, st_node, bitwise_entity, st_arg2);
|
||||
}
|
||||
else if (bitwise_entity_type == STTYPE_RANGE) {
|
||||
check_relation_LHS_RANGE(dfw, st_op, can_func, allow_partial_value, st_node, bitwise_entity, st_arg2);
|
||||
}
|
||||
else if (bitwise_entity_type == STTYPE_FUNCTION) {
|
||||
check_relation_LHS_FUNCTION(dfw, st_op, can_func, allow_partial_value, st_node, bitwise_entity, st_arg2);
|
||||
}
|
||||
else {
|
||||
ws_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the semantics of any relational test. */
|
||||
static void
|
||||
|
@ -927,6 +963,10 @@ check_relation(dfwork_t *dfw, test_op_t st_op,
|
|||
check_relation_LHS_FUNCTION(dfw, st_op, can_func,
|
||||
allow_partial_value, st_node, st_arg1, st_arg2);
|
||||
break;
|
||||
case STTYPE_BITWISE:
|
||||
check_relation_LHS_BITWISE(dfw, st_op, can_func,
|
||||
allow_partial_value, st_node, st_arg1, st_arg2);
|
||||
break;
|
||||
default:
|
||||
FAIL(dfw, "Left side of %s expression must be a field or function, not %s.",
|
||||
stnode_todisplay(st_node), stnode_todisplay(st_arg1));
|
||||
|
@ -1075,6 +1115,11 @@ check_test(dfwork_t *dfw, stnode_t *st_node)
|
|||
check_exists(dfw, st_arg1);
|
||||
break;
|
||||
|
||||
case TEST_OP_NOTZERO:
|
||||
ws_assert(stnode_type_id(st_arg1) == STTYPE_BITWISE);
|
||||
check_bitwise_operation(dfw, st_arg1);
|
||||
break;
|
||||
|
||||
case TEST_OP_NOT:
|
||||
semcheck(dfw, st_arg1);
|
||||
break;
|
||||
|
@ -1113,9 +1158,6 @@ check_test(dfwork_t *dfw, stnode_t *st_node)
|
|||
case TEST_OP_LE:
|
||||
check_relation(dfw, st_op, ftype_can_cmp, FALSE, st_node, st_arg1, st_arg2);
|
||||
break;
|
||||
case TEST_OP_BITWISE_AND:
|
||||
check_relation(dfw, st_op, ftype_can_bitwise_and, FALSE, st_node, st_arg1, st_arg2);
|
||||
break;
|
||||
case TEST_OP_CONTAINS:
|
||||
check_relation_contains(dfw, st_node, st_arg1, st_arg2);
|
||||
break;
|
||||
|
@ -1131,6 +1173,95 @@ check_test(dfwork_t *dfw, stnode_t *st_node)
|
|||
}
|
||||
}
|
||||
|
||||
static ftenum_t
|
||||
check_bitwise_entity(dfwork_t *dfw, stnode_t *st_node, stnode_t *st_arg, ftenum_t lhs_ftype)
|
||||
{
|
||||
header_field_info *hfinfo;
|
||||
ftenum_t ftype;
|
||||
fvalue_t *fvalue;
|
||||
sttype_id_t type;
|
||||
df_func_def_t *funcdef;
|
||||
|
||||
LOG_NODE(st_arg);
|
||||
|
||||
resolve_unparsed(dfw, st_arg);
|
||||
type = stnode_type_id(st_arg);
|
||||
|
||||
if (type == STTYPE_FIELD) {
|
||||
hfinfo = stnode_data(st_arg);
|
||||
ftype = hfinfo->type;
|
||||
|
||||
if (!ftype_can_bitwise_and(ftype)) {
|
||||
FAIL(dfw, "%s (type=%s) cannot participate in %s comparison.",
|
||||
hfinfo->abbrev, ftype_pretty_name(ftype),
|
||||
stnode_todisplay(st_node));
|
||||
}
|
||||
return ftype;
|
||||
}
|
||||
else if (type == STTYPE_FUNCTION) {
|
||||
check_function(dfw, st_arg);
|
||||
|
||||
funcdef = sttype_function_funcdef(st_arg);
|
||||
ftype = funcdef->retval_ftype;
|
||||
|
||||
if (!ftype_can_bitwise_and(ftype)) {
|
||||
FAIL(dfw, "Function %s (type=%s) cannot participate in %s comparison.",
|
||||
funcdef->name, ftype_pretty_name(ftype),
|
||||
stnode_todisplay(st_node));
|
||||
}
|
||||
return ftype;
|
||||
}
|
||||
else if (type == STTYPE_RANGE) {
|
||||
check_drange_sanity(dfw, st_arg);
|
||||
ftype = FT_BYTES;
|
||||
|
||||
if (!ftype_can_bitwise_and(ftype)) {
|
||||
FAIL(dfw, "Range %s (type=%s) cannot participate in %s comparison.",
|
||||
stnode_todisplay(st_arg), ftype_pretty_name(ftype),
|
||||
stnode_todisplay(st_node));
|
||||
}
|
||||
return ftype;
|
||||
}
|
||||
else if (lhs_ftype != FT_NONE) {
|
||||
/* numeric constant */
|
||||
ftype = lhs_ftype;
|
||||
fvalue = dfilter_fvalue_from_literal(dfw, ftype, st_arg, FALSE, NULL);
|
||||
stnode_replace(st_arg, STTYPE_FVALUE, fvalue);
|
||||
}
|
||||
else {
|
||||
FAIL(dfw, "Invalid bitwise operand %s in comparison %s.",
|
||||
stnode_todisplay(st_arg), stnode_todisplay(st_arg));
|
||||
}
|
||||
return ftype;
|
||||
}
|
||||
|
||||
static ftenum_t
|
||||
check_bitwise_operation(dfwork_t *dfw, stnode_t *st_node)
|
||||
{
|
||||
test_op_t st_op;
|
||||
stnode_t *st_arg1, *st_arg2;
|
||||
ftenum_t ftype1, ftype2;
|
||||
|
||||
LOG_NODE(st_node);
|
||||
|
||||
sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2);
|
||||
|
||||
ftype1 = check_bitwise_entity(dfw, st_node, st_arg1, FT_NONE);
|
||||
ftype2 = check_bitwise_entity(dfw, st_node, st_arg2, ftype1);
|
||||
|
||||
if (!ftype_can_is_true(ftype1)) {
|
||||
FAIL(dfw, "Cannot test if %s is true", stnode_todisplay(st_arg1));
|
||||
}
|
||||
|
||||
/* XXX This could be relaxed with type promotions. */
|
||||
if (ftype1 != ftype2) {
|
||||
FAIL(dfw, "%s %s %s: entities have different types",
|
||||
stnode_todisplay(st_arg1),
|
||||
stnode_todisplay(st_node),
|
||||
stnode_todisplay(st_arg2));
|
||||
}
|
||||
return ftype1;
|
||||
}
|
||||
|
||||
/* Check the entire syntax tree. */
|
||||
static void
|
||||
|
|
|
@ -71,7 +71,7 @@ test_todisplay(test_op_t op)
|
|||
|
||||
switch(op) {
|
||||
case TEST_OP_EXISTS:
|
||||
s = "exists";
|
||||
s = "<exists>";
|
||||
break;
|
||||
case TEST_OP_NOT:
|
||||
s = "!";
|
||||
|
@ -106,9 +106,12 @@ test_todisplay(test_op_t op)
|
|||
case TEST_OP_LE:
|
||||
s = "<=";
|
||||
break;
|
||||
case TEST_OP_BITWISE_AND:
|
||||
case OP_BITWISE_AND:
|
||||
s = "&";
|
||||
break;
|
||||
case TEST_OP_NOTZERO:
|
||||
s = "<notzero>";
|
||||
break;
|
||||
case TEST_OP_CONTAINS:
|
||||
s = "contains";
|
||||
break;
|
||||
|
@ -170,8 +173,11 @@ test_todebug(test_op_t op)
|
|||
case TEST_OP_LE:
|
||||
s = "TEST_LE";
|
||||
break;
|
||||
case TEST_OP_BITWISE_AND:
|
||||
s = "TEST_BITAND";
|
||||
case OP_BITWISE_AND:
|
||||
s = "BITWISE_AND";
|
||||
break;
|
||||
case TEST_OP_NOTZERO:
|
||||
s = "TEST_NOTZERO";
|
||||
break;
|
||||
case TEST_OP_CONTAINS:
|
||||
s = "TEST_CONTAINS";
|
||||
|
@ -214,6 +220,7 @@ num_operands(test_op_t op)
|
|||
break;
|
||||
case TEST_OP_EXISTS:
|
||||
case TEST_OP_NOT:
|
||||
case TEST_OP_NOTZERO:
|
||||
return 1;
|
||||
case TEST_OP_AND:
|
||||
case TEST_OP_OR:
|
||||
|
@ -225,7 +232,7 @@ num_operands(test_op_t op)
|
|||
case TEST_OP_GE:
|
||||
case TEST_OP_LT:
|
||||
case TEST_OP_LE:
|
||||
case TEST_OP_BITWISE_AND:
|
||||
case OP_BITWISE_AND:
|
||||
case TEST_OP_CONTAINS:
|
||||
case TEST_OP_MATCHES:
|
||||
case TEST_OP_IN:
|
||||
|
@ -325,8 +332,18 @@ sttype_register_test(void)
|
|||
test_dup,
|
||||
test_tostr
|
||||
};
|
||||
/* XXX Bitwise ops are not "tests". */
|
||||
static sttype_t bitwise_type = {
|
||||
STTYPE_BITWISE,
|
||||
"BITWISE",
|
||||
test_new,
|
||||
test_free,
|
||||
test_dup,
|
||||
test_tostr
|
||||
};
|
||||
|
||||
sttype_register(&test_type);
|
||||
sttype_register(&bitwise_type);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -412,7 +412,8 @@ visit_tree(wmem_strbuf_t *buf, stnode_t *node, int level)
|
|||
{
|
||||
stnode_t *left, *right;
|
||||
|
||||
if (stnode_type_id(node) == STTYPE_TEST) {
|
||||
if (stnode_type_id(node) == STTYPE_TEST ||
|
||||
stnode_type_id(node) == STTYPE_BITWISE) {
|
||||
wmem_strbuf_append_printf(buf, "%s(", stnode_todebug(node));
|
||||
sttype_test_get(node, NULL, &left, &right);
|
||||
if (left && right) {
|
||||
|
|
|
@ -32,6 +32,7 @@ typedef enum {
|
|||
STTYPE_FUNCTION,
|
||||
STTYPE_SET,
|
||||
STTYPE_PCRE,
|
||||
STTYPE_BITWISE,
|
||||
STTYPE_NUM_TYPES
|
||||
} sttype_id_t;
|
||||
|
||||
|
@ -49,7 +50,8 @@ typedef enum {
|
|||
TEST_OP_GE,
|
||||
TEST_OP_LT,
|
||||
TEST_OP_LE,
|
||||
TEST_OP_BITWISE_AND,
|
||||
OP_BITWISE_AND,
|
||||
TEST_OP_NOTZERO,
|
||||
TEST_OP_CONTAINS,
|
||||
TEST_OP_MATCHES,
|
||||
TEST_OP_IN
|
||||
|
|
|
@ -515,26 +515,29 @@ cmp_order(const fvalue_t *fv_a, const fvalue_t *fv_b)
|
|||
return memcmp(a->data, b->data, a->len);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cmp_bitwise_and(const fvalue_t *fv_a, const fvalue_t *fv_b)
|
||||
static enum ft_result
|
||||
bytes_bitwise_and(fvalue_t *fv_dst, const fvalue_t *fv_a, const fvalue_t *fv_b, char **err_ptr _U_)
|
||||
{
|
||||
GByteArray *a = fv_a->value.bytes;
|
||||
GByteArray *b = fv_b->value.bytes;
|
||||
guint i = 0;
|
||||
GByteArray *dst;
|
||||
unsigned char *p_a, *p_b;
|
||||
|
||||
if (b->len != a->len) {
|
||||
return FALSE;
|
||||
guint len = MIN(a->len, b->len);
|
||||
if (len == 0) {
|
||||
fv_dst->value.bytes = g_byte_array_new();
|
||||
return FT_OK;
|
||||
}
|
||||
dst = g_byte_array_sized_new(len);
|
||||
|
||||
p_a = a->data;
|
||||
p_b = b->data;
|
||||
while (i < b->len) {
|
||||
if (p_a[i] & p_b[i])
|
||||
return TRUE;
|
||||
else
|
||||
i++;
|
||||
for (guint i = 0; i < len; i++) {
|
||||
guint8 byte = p_a[i] & p_b[i];
|
||||
g_byte_array_append(dst, &byte, 1);
|
||||
}
|
||||
return FALSE;
|
||||
fv_dst->value.bytes = dst;
|
||||
return FT_OK;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -559,6 +562,22 @@ cmp_matches(const fvalue_t *fv, const ws_regex_t *regex)
|
|||
return ws_regex_matches_length(regex, a->data, a->len);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
bytes_is_true(const fvalue_t *fv_a)
|
||||
{
|
||||
GByteArray *a = fv_a->value.bytes;
|
||||
|
||||
if (a->len == 0)
|
||||
return FALSE;
|
||||
|
||||
for (guint i = 0; i < a->len; i++) {
|
||||
if (a->data[i] != 0) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
ftype_register_bytes(void)
|
||||
{
|
||||
|
@ -579,12 +598,13 @@ ftype_register_bytes(void)
|
|||
{ .get_value_ptr = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_bitwise_and,
|
||||
cmp_contains,
|
||||
cmp_matches,
|
||||
|
||||
bytes_is_true, /* is_true */
|
||||
len,
|
||||
slice,
|
||||
bytes_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
|
||||
static ftype_t uint_bytes_type = {
|
||||
|
@ -603,12 +623,13 @@ ftype_register_bytes(void)
|
|||
{ .get_value_ptr = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_bitwise_and,
|
||||
cmp_contains,
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
bytes_is_true, /* is_true */
|
||||
len,
|
||||
slice,
|
||||
bytes_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
|
||||
static ftype_t ax25_type = {
|
||||
|
@ -627,12 +648,13 @@ ftype_register_bytes(void)
|
|||
{ .get_value_ptr = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_bitwise_and,
|
||||
cmp_contains,
|
||||
cmp_matches,
|
||||
|
||||
bytes_is_true, /* is_true */
|
||||
len,
|
||||
slice,
|
||||
bytes_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
|
||||
static ftype_t vines_type = {
|
||||
|
@ -651,12 +673,13 @@ ftype_register_bytes(void)
|
|||
{ .get_value_ptr = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_bitwise_and,
|
||||
cmp_contains,
|
||||
cmp_matches,
|
||||
|
||||
bytes_is_true, /* is_true */
|
||||
len,
|
||||
slice,
|
||||
bytes_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
|
||||
static ftype_t ether_type = {
|
||||
|
@ -675,12 +698,13 @@ ftype_register_bytes(void)
|
|||
{ .get_value_ptr = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_bitwise_and,
|
||||
cmp_contains,
|
||||
cmp_matches,
|
||||
|
||||
bytes_is_true, /* is_true */
|
||||
len,
|
||||
slice,
|
||||
bytes_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
|
||||
static ftype_t oid_type = {
|
||||
|
@ -699,12 +723,13 @@ ftype_register_bytes(void)
|
|||
{ .get_value_ptr = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_bitwise_and,
|
||||
cmp_contains,
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
bytes_is_true, /* is_true */
|
||||
len,
|
||||
slice,
|
||||
bytes_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
|
||||
static ftype_t rel_oid_type = {
|
||||
|
@ -723,12 +748,13 @@ ftype_register_bytes(void)
|
|||
{ .get_value_ptr = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_bitwise_and,
|
||||
cmp_contains,
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
bytes_is_true, /* is_true */
|
||||
len,
|
||||
slice,
|
||||
bytes_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
|
||||
static ftype_t system_id_type = {
|
||||
|
@ -747,12 +773,13 @@ ftype_register_bytes(void)
|
|||
{ .get_value_ptr = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_bitwise_and,
|
||||
cmp_contains,
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
bytes_is_true, /* is_true */
|
||||
len,
|
||||
slice,
|
||||
bytes_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
|
||||
static ftype_t fcwwn_type = {
|
||||
|
@ -771,12 +798,13 @@ ftype_register_bytes(void)
|
|||
{ .get_value_ptr = value_get }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
cmp_bitwise_and,
|
||||
cmp_contains,
|
||||
cmp_matches,
|
||||
|
||||
bytes_is_true, /* is_true */
|
||||
len,
|
||||
slice,
|
||||
bytes_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
|
||||
ftype_register(FT_BYTES, &bytes_type);
|
||||
|
|
|
@ -85,6 +85,12 @@ double_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _
|
|||
return buf;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
double_is_true(const fvalue_t *fv)
|
||||
{
|
||||
return fv->value.floating != 0.0;
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_order(const fvalue_t *a, const fvalue_t *b)
|
||||
{
|
||||
|
@ -115,12 +121,13 @@ ftype_register_double(void)
|
|||
{ .get_value_floating = value_get_floating }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
NULL, /* cmp_bitwise_and */
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
double_is_true, /* is_true */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, /* bitwise_and */
|
||||
};
|
||||
|
||||
static ftype_t double_type = {
|
||||
|
@ -139,12 +146,13 @@ ftype_register_double(void)
|
|||
{ .get_value_floating = value_get_floating }, /* union get_value */
|
||||
|
||||
cmp_order,
|
||||
NULL, /* cmp_bitwise_and */
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
double_is_true, /* is_true */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, /* bitwise_and */
|
||||
};
|
||||
|
||||
ftype_register(FT_FLOAT, &float_type);
|
||||
|
|
|
@ -114,11 +114,12 @@ ftype_register_guid(void)
|
|||
|
||||
cmp_order,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
ftype_register(FT_GUID, &guid_type);
|
||||
|
|
|
@ -453,9 +453,9 @@ sfloat_ieee_11073_cmp_order(const fvalue_t *a, const fvalue_t *b)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
sfloat_ieee_11073_cmp_bitwise_and(const fvalue_t *a, const fvalue_t *b)
|
||||
sfloat_ieee_11073_is_true(const fvalue_t *a)
|
||||
{
|
||||
return ((a->value.uinteger & b->value.uinteger) != 0);
|
||||
return a->value.sfloat_ieee_11073 != 0;
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
|
@ -862,9 +862,9 @@ float_ieee_11073_cmp_order(const fvalue_t *a, const fvalue_t *b)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
float_ieee_11073_cmp_bitwise_and(const fvalue_t *a, const fvalue_t *b)
|
||||
float_ieee_11073_is_true(const fvalue_t *a)
|
||||
{
|
||||
return ((a->value.uinteger & b->value.uinteger) != 0);
|
||||
return a->value.float_ieee_11073 != 0;
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
|
@ -914,12 +914,13 @@ Example: 114 is 0x0072
|
|||
{ .get_value_uinteger = sfloat_ieee_11073_value_get }, /* union get_value */
|
||||
|
||||
sfloat_ieee_11073_cmp_order,
|
||||
sfloat_ieee_11073_cmp_bitwise_and, /* cmp_bitwise_and */
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
sfloat_ieee_11073_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
NULL, /* bitwise_and */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -965,12 +966,13 @@ Example: 36.4 is 0xFF00016C
|
|||
{ .get_value_uinteger = float_ieee_11073_value_get }, /* union get_value */
|
||||
|
||||
float_ieee_11073_cmp_order,
|
||||
float_ieee_11073_cmp_bitwise_and, /* cmp_bitwise_and */
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
float_ieee_11073_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
NULL, /* bitwise_and */
|
||||
};
|
||||
|
||||
ftype_register(FT_IEEE_11073_SFLOAT, &sfloat_type);
|
||||
|
|
|
@ -458,12 +458,6 @@ sinteger64_cmp_order(const fvalue_t *a, const fvalue_t *b)
|
|||
return a->value.sinteger64 < b->value.sinteger64 ? -1 : 1;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cmp_bitwise_and(const fvalue_t *a, const fvalue_t *b)
|
||||
{
|
||||
return ((a->value.uinteger & b->value.uinteger) != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
int64_fvalue_new(fvalue_t *fv)
|
||||
{
|
||||
|
@ -746,10 +740,56 @@ uinteger64_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _
|
|||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
cmp_bitwise_and64(const fvalue_t *a, const fvalue_t *b)
|
||||
enum ft_result
|
||||
uint_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
|
||||
{
|
||||
return ((a->value.uinteger64 & b->value.uinteger64) != 0);
|
||||
dst->value.uinteger = a->value.uinteger & b->value.uinteger;
|
||||
return FT_OK;
|
||||
}
|
||||
|
||||
gboolean
|
||||
uint_is_true(const fvalue_t *fv)
|
||||
{
|
||||
return fv->value.uinteger != 0;
|
||||
}
|
||||
|
||||
enum ft_result
|
||||
uint64_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
|
||||
{
|
||||
dst->value.uinteger64 = a->value.uinteger64 & b->value.uinteger64;
|
||||
return FT_OK;
|
||||
}
|
||||
|
||||
gboolean
|
||||
uint64_is_true(const fvalue_t *fv)
|
||||
{
|
||||
return fv->value.uinteger64 != 0;
|
||||
}
|
||||
|
||||
enum ft_result
|
||||
sint_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
|
||||
{
|
||||
dst->value.sinteger = a->value.sinteger & b->value.sinteger;
|
||||
return FT_OK;
|
||||
}
|
||||
|
||||
gboolean
|
||||
sint_is_true(const fvalue_t *fv)
|
||||
{
|
||||
return fv->value.sinteger != 0;
|
||||
}
|
||||
|
||||
enum ft_result
|
||||
sint64_bitwise_and(fvalue_t *dst, const fvalue_t *a, const fvalue_t *b, char **err_ptr _U_)
|
||||
{
|
||||
dst->value.sinteger64 = a->value.sinteger64 & b->value.sinteger64;
|
||||
return FT_OK;
|
||||
}
|
||||
|
||||
gboolean
|
||||
sint64_is_true(const fvalue_t *fv)
|
||||
{
|
||||
return fv->value.sinteger64 != 0;
|
||||
}
|
||||
|
||||
/* BOOLEAN-specific */
|
||||
|
@ -869,12 +909,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger = get_uinteger }, /* union get_value */
|
||||
|
||||
uinteger_cmp_order,
|
||||
cmp_bitwise_and,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
uint_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
uint_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t uint8_type = {
|
||||
FT_UINT8, /* ftype */
|
||||
|
@ -892,12 +933,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger = get_uinteger }, /* union get_value */
|
||||
|
||||
uinteger_cmp_order,
|
||||
cmp_bitwise_and,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
uint_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
uint_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t uint16_type = {
|
||||
FT_UINT16, /* ftype */
|
||||
|
@ -915,12 +957,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger = get_uinteger }, /* union get_value */
|
||||
|
||||
uinteger_cmp_order,
|
||||
cmp_bitwise_and,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
uint_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
uint_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t uint24_type = {
|
||||
FT_UINT24, /* ftype */
|
||||
|
@ -938,12 +981,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger = get_uinteger }, /* union get_value */
|
||||
|
||||
uinteger_cmp_order,
|
||||
cmp_bitwise_and,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
uint_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
uint_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t uint32_type = {
|
||||
FT_UINT32, /* ftype */
|
||||
|
@ -961,12 +1005,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger = get_uinteger }, /* union get_value */
|
||||
|
||||
uinteger_cmp_order,
|
||||
cmp_bitwise_and,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
uint_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
uint_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t uint40_type = {
|
||||
FT_UINT40, /* ftype */
|
||||
|
@ -984,12 +1029,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
|
||||
|
||||
uinteger64_cmp_order,
|
||||
cmp_bitwise_and64,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
uint64_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
uint64_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t uint48_type = {
|
||||
FT_UINT48, /* ftype */
|
||||
|
@ -1007,12 +1053,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
|
||||
|
||||
uinteger64_cmp_order,
|
||||
cmp_bitwise_and64,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
uint64_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
uint64_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t uint56_type = {
|
||||
FT_UINT56, /* ftype */
|
||||
|
@ -1030,12 +1077,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
|
||||
|
||||
uinteger64_cmp_order,
|
||||
cmp_bitwise_and64,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
uint64_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
uint64_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t uint64_type = {
|
||||
FT_UINT64, /* ftype */
|
||||
|
@ -1053,12 +1101,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
|
||||
|
||||
uinteger64_cmp_order,
|
||||
cmp_bitwise_and64,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
uint64_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
uint64_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t int8_type = {
|
||||
FT_INT8, /* ftype */
|
||||
|
@ -1076,12 +1125,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_sinteger = get_sinteger }, /* union get_value */
|
||||
|
||||
sinteger_cmp_order,
|
||||
cmp_bitwise_and,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
sint_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
sint_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t int16_type = {
|
||||
FT_INT16, /* ftype */
|
||||
|
@ -1099,12 +1149,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_sinteger = get_sinteger }, /* union get_value */
|
||||
|
||||
sinteger_cmp_order,
|
||||
cmp_bitwise_and,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
sint_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
sint_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t int24_type = {
|
||||
FT_INT24, /* ftype */
|
||||
|
@ -1122,12 +1173,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_sinteger = get_sinteger }, /* union get_value */
|
||||
|
||||
sinteger_cmp_order,
|
||||
cmp_bitwise_and,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
sint_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
sint_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t int32_type = {
|
||||
FT_INT32, /* ftype */
|
||||
|
@ -1145,12 +1197,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_sinteger = get_sinteger }, /* union get_value */
|
||||
|
||||
sinteger_cmp_order,
|
||||
cmp_bitwise_and,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
sint_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
sint_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t int40_type = {
|
||||
FT_INT40, /* ftype */
|
||||
|
@ -1168,12 +1221,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_sinteger64 = get_sinteger64 }, /* union get_value */
|
||||
|
||||
sinteger64_cmp_order,
|
||||
cmp_bitwise_and64,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
sint64_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
sint64_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t int48_type = {
|
||||
FT_INT48, /* ftype */
|
||||
|
@ -1191,12 +1245,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_sinteger64 = get_sinteger64 }, /* union get_value */
|
||||
|
||||
sinteger64_cmp_order,
|
||||
cmp_bitwise_and64,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
sint64_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
sint64_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t int56_type = {
|
||||
FT_INT56, /* ftype */
|
||||
|
@ -1214,12 +1269,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_sinteger64 = get_sinteger64 }, /* union get_value */
|
||||
|
||||
sinteger64_cmp_order,
|
||||
cmp_bitwise_and64,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
sint64_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
sint64_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t int64_type = {
|
||||
FT_INT64, /* ftype */
|
||||
|
@ -1237,12 +1293,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_sinteger64 = get_sinteger64 }, /* union get_value */
|
||||
|
||||
sinteger64_cmp_order,
|
||||
cmp_bitwise_and64,
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
sint64_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||
NULL, /* slice */
|
||||
sint64_bitwise_and, /* bitwise_and */
|
||||
};
|
||||
static ftype_t boolean_type = {
|
||||
FT_BOOLEAN, /* ftype */
|
||||
|
@ -1260,12 +1317,13 @@ ftype_register_integers(void)
|
|||
{ .get_value_uinteger64 = get_uinteger64 }, /* union get_value */
|
||||
|
||||
boolean_cmp_order, /* cmp_eq */
|
||||
NULL, /* cmp_bitwise_and */
|
||||
NULL, /* cmp_contains */
|
||||
NULL, /* cmp_matches */
|
||||
|
||||
uint64_is_true, /* is_true */
|
||||
NULL, /* len */
|
||||