ac_error_code ac_index_free(ac_index* self, ac_free_function object_free) { ac_list* queue = NULL; ac_state* state = NULL; ac_error_code result = AC_SUCCESS; if ( ! self) { return AC_FAILURE; } if ( ! (queue = ac_list_new())) { return AC_FAILURE; } // Free all the state nodes by following the goto function tree breadth // first, starting with state_0. state = self->state_0; while (state) { // Free the state and enqueue the states from the goto list. if (ac_state_free(state, queue, object_free) != AC_SUCCESS) { result = AC_FAILURE; } state = ac_state_queue_get(queue); } ac_state_queue_free(queue); // The queue should be empty. self->state_0 = NULL; FREE(self); return result; }
/** * Construct a new state object. The goto list and the both output lists are * initially empty, and the failure state is initially NULL. Returns a pointer * to the new state object if successful or NULL if an error was encountered * while trying to allocate heap space for the object or while constructing * one of its lists. */ ac_state* ac_state_new(void) { ac_state* self; if ( ! (self = MALLOC(sizeof(ac_state))) ) { return NULL; } if ( ! (self->gotos = ac_list_new())) { return NULL; } if ( ! (self->outputs = ac_list_new())) { return NULL; } if ( ! (self->extra_outputs = ac_list_new())) { return NULL; } self->failure = NULL; return self; }
static ac_list *user_build_ac_list(void) { if (!uidshm) return NULL; ac_list *acl = ac_list_new(); if (!acl) return NULL; int size = uidshm->number; for (int i = 0; i < size; ++i) { const char *user_name = uidshm->userid[i]; if (*user_name) ac_list_add(acl, user_name); } return acl; }
/** * Fix the index, making it ready to be queried. This is an implementation of * the last part of Algorithm 2 from the paper combined with an implementation * of 'Algorithm 3. Construction of the failure function.' from the paper. * Returns AC_SUCCESS if the index was successfully fixed or AC_FAILURE if an * error was encountered or if the index was not 'unfixed'. */ ac_error_code ac_index_fix(ac_index* self) { // This is an implementation of the last part of Algorithm 2 from the paper // combined with an implementation of 'Algorithm 3. Construction of the // failure function.' from the paper. int symbol; ac_state* state = NULL; ac_state* r = NULL; ac_list* queue = NULL; ac_list_item* list_item = NULL; ac_goto* item = NULL; // You can't fix an index that is already fixed. if (self->index_state != AC_INDEX_UNFIXED) { return AC_FAILURE; } // Mark the index as being fixed. self->index_state = AC_INDEX_FIXED; // Make a temporary queue of states. if ( ! (queue = ac_list_new())) { return AC_FAILURE; } // Look at all the symbols. If state_0 has a goto for a symbol, add the // state to the queue and point the failure state back to state_0 - the // first part of Algorithm 3. Otherwise make state_0 goto itself for that // symbol - the last part of Algorithm 2. // TODO: Improve efficiency of state_0 to state_0 gotos. for (symbol = AC_MIN_SYMBOL; symbol <= AC_MAX_SYMBOL; symbol++) { if ((state = ac_goto_list_get(self->state_0->gotos, symbol))) { if (ac_list_add(queue, state) != AC_SUCCESS) { return AC_FAILURE; } state->failure = self->state_0; } else { if (ac_goto_list_add(self->state_0->gotos, symbol, self->state_0) != AC_SUCCESS) { return AC_FAILURE; } } } // Do the second part of Algorithm 3. Burn through the queue, enqueing // states from goto list in order to traverse the goto tree breadth-first. // ... while ((r = ac_state_queue_get(queue))) { list_item = r->gotos->first; while (list_item) { item = (ac_goto*) list_item->item; symbol = item->symbol; if (ac_list_add(queue, item->state) != AC_SUCCESS) { return AC_FAILURE; } // ... For each goto state, find the failure function by following // the failure function back until there is a goto defined. We // will always find a defined goto because state_0 has a goto // defined for every symbol (by now). ... state = r->failure; while ( ! ac_goto_list_has(state->gotos, symbol)) { state = state->failure; } item->state->failure = ac_goto_list_get(state->gotos, symbol); // ... Add the outputs for the failure state to the outputs. We // use the extra_outputs list because the outputs are already // referenced. if (ac_output_list_add_list(item->state->extra_outputs, item->state->failure->outputs)) { return AC_FAILURE; }; if (ac_output_list_add_list(item->state->extra_outputs, item->state->failure->extra_outputs)) { return AC_FAILURE; }; list_item = list_item->next; } } // Free the temporary queue. ac_state_queue_free(queue); return AC_SUCCESS; }