/** * List free function for goto list items. This will be called once per * ac_goto in the list. The data should be an ac_goto_list_free_data as * explained above. The states in the list are added to the list in data * except where the state matches the state in data. * * Returns AC_SUCCESS if successful or AC_FAILURE if a failure is encountered * when adding a state to the list. */ ac_error_code ac_goto_list_free_item(void* item, void* data) { ac_goto* goto_item = (ac_goto*) item; ac_goto_list_free_data* free_data = (ac_goto_list_free_data*) data; /* Add the state from the goto item to the list unless it is excluded. */ if (goto_item->state != free_data->state && ac_list_add(free_data->states, goto_item->state) != AC_SUCCESS) { return AC_FAILURE; } FREE(item); return AC_SUCCESS; }
/** * Associates the given symbol with the given state in a goto list. Returns * AC_SUCCESS if successful or AC_FAILURE if an error was encountered. */ ac_error_code ac_goto_list_add(ac_list* self, ac_symbol symbol, ac_state* state) { ac_goto* new_item; if ( ! (new_item = MALLOC(sizeof(ac_goto)))) { return AC_FAILURE; } new_item->symbol = symbol; new_item->state = state; if (ac_list_add(self, new_item) != AC_SUCCESS) { FREE(new_item); return AC_FAILURE; } return AC_SUCCESS; }
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; }
/** * Add an offset and an associated object to the output list. Returns * AC_SUCCESS if successful, or AC_FAILURE if the there was an error was * encountered. */ ac_error_code ac_output_list_add(ac_list* self, ac_offset offset, void* object) { ac_output* new_item; if ( ! (new_item = MALLOC(sizeof(ac_output)))) { return AC_FAILURE; } new_item->offset = offset; new_item->object = object; if (ac_list_add(self, new_item) != AC_SUCCESS) { FREE(new_item); return AC_FAILURE; } return AC_SUCCESS; }
/** * 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; }