You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.3 KiB
138 lines
4.3 KiB
/* -*- coding: utf-8 -*-
|
|
* ----------------------------------------------------------------------
|
|
* Copyright © 2010-2012, RedJack, LLC.
|
|
* All rights reserved.
|
|
*
|
|
* Please see the LICENSE.txt file in this distribution for license
|
|
* details.
|
|
* ----------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include <libcork/core.h>
|
|
|
|
#include "ipset/bdd/nodes.h"
|
|
#include "ipset/bits.h"
|
|
#include "ipset/logging.h"
|
|
|
|
|
|
static void
|
|
initialize(struct ipset_expanded_assignment *exp,
|
|
const struct ipset_assignment *assignment,
|
|
ipset_variable var_count)
|
|
{
|
|
/* First loop through all of the variables in the assignment vector,
|
|
* making sure not to go further than the caller requested. */
|
|
|
|
ipset_variable last_assignment = cork_array_size(&assignment->values);
|
|
if (var_count < last_assignment) {
|
|
last_assignment = var_count;
|
|
}
|
|
|
|
ipset_variable var;
|
|
for (var = 0; var < last_assignment; var++) {
|
|
enum ipset_tribool curr_value =
|
|
cork_array_at(&assignment->values, var);
|
|
|
|
if (curr_value == IPSET_EITHER) {
|
|
/* If this variable is EITHER, start it off as FALSE, and
|
|
* add it to the eithers list. */
|
|
DEBUG("Variable %u is EITHER", var);
|
|
|
|
IPSET_BIT_SET(exp->values.buf, var, false);
|
|
cork_array_append(&exp->eithers, var);
|
|
} else {
|
|
/* Otherwise set the variable to the same value in the
|
|
* expanded assignment as it is in the non-expanded one. */
|
|
|
|
DEBUG("Variable %u is %s", var, curr_value? "true": "false");
|
|
IPSET_BIT_SET(exp->values.buf, var, curr_value);
|
|
}
|
|
}
|
|
|
|
/* If the caller requested more variables than there are in the
|
|
* assignment vector, add them to the eithers list. */
|
|
for (var = last_assignment; var < var_count; var++) {
|
|
DEBUG("Variable %u is implicitly EITHER", var);
|
|
cork_array_append(&exp->eithers, var);
|
|
}
|
|
}
|
|
|
|
|
|
struct ipset_expanded_assignment *
|
|
ipset_assignment_expand(const struct ipset_assignment *assignment,
|
|
ipset_variable var_count)
|
|
{
|
|
/* First allocate the iterator itself, and all of its contained
|
|
* fields. */
|
|
|
|
struct ipset_expanded_assignment *exp;
|
|
unsigned int values_size = (var_count / 8) + ((var_count % 8) != 0);
|
|
|
|
exp = cork_new(struct ipset_expanded_assignment);
|
|
exp->finished = false;
|
|
cork_buffer_init(&exp->values);
|
|
cork_buffer_ensure_size(&exp->values, values_size);
|
|
memset(exp->values.buf, 0, values_size);
|
|
cork_array_init(&exp->eithers);
|
|
|
|
/* Then initialize the values and eithers fields. */
|
|
initialize(exp, assignment, var_count);
|
|
return exp;
|
|
}
|
|
|
|
|
|
void
|
|
ipset_expanded_assignment_free(struct ipset_expanded_assignment *exp)
|
|
{
|
|
if (exp == NULL) {
|
|
return;
|
|
}
|
|
|
|
cork_buffer_done(&exp->values);
|
|
cork_array_done(&exp->eithers);
|
|
free(exp);
|
|
}
|
|
|
|
|
|
void
|
|
ipset_expanded_assignment_advance(struct ipset_expanded_assignment *exp)
|
|
{
|
|
/* If we're already at the end of the iterator, don't do anything. */
|
|
if (CORK_UNLIKELY(exp->finished)) {
|
|
return;
|
|
}
|
|
|
|
DEBUG("Advancing iterator");
|
|
|
|
/* Look at the last EITHER bit in the assignment. If it's 0, then
|
|
* set it to 1 and return. Otherwise we set it to 0 and carry up to
|
|
* the previous indeterminate bit. */
|
|
|
|
size_t i;
|
|
for (i = cork_array_size(&exp->eithers); i > 0; i--) {
|
|
size_t idx = i - 1;
|
|
ipset_variable either_var = cork_array_at(&exp->eithers, idx);
|
|
DEBUG("Checking EITHER variable %u", either_var);
|
|
|
|
if (IPSET_BIT_GET(exp->values.buf, either_var)) {
|
|
/* This variable is currently true, so set it back to false
|
|
* and carry. */
|
|
DEBUG(" Variable %u is true, changing to false and carrying",
|
|
either_var);
|
|
IPSET_BIT_SET(exp->values.buf, either_var, false);
|
|
} else {
|
|
/* This variable is currently false, so set it to true and
|
|
* return. */
|
|
DEBUG(" Variable %u is false, changing to true",
|
|
either_var);
|
|
IPSET_BIT_SET(exp->values.buf, either_var, true);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* If we fall through then we've made it through all of the expanded
|
|
* assignments. */
|
|
exp->finished = true;
|
|
}
|