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

/* -*- 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;
}