Rev 43807 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/*Copyright (C) by Jarkko Hietaniemi, 1998,1999,2000,2001,2002,2003,2006.All Rights Reserved.This program is free software; you can redistribute it and/or modifyit under the terms of either:a) the GNU Library General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) anylater version, orb) the "Artistic License" which comes with Perl source code.Other free software licensing schemes are negotiable.Furthermore:(1) This software is provided as-is, without warranties orobligations of any kind.(2) You shall include this copyright notice intact in all copiesand derived materials.*//*Based on version 0.16 of apse.c, with unused code removed.Modified by R-core to work with wchar_t and an alphabet of size 65536.*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#ifdef HAVE_VISIBILITY_ATTRIBUTE# define attribute_hidden __attribute__ ((visibility ("hidden")))#else# define attribute_hidden#endif#ifdef SUPPORT_MBCS# include <wctype.h># include <wchar.h>#endif#include "apse.h"#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>#define APSE_BITS_IN_BITVEC (8*sizeof(apse_vec_t))#define APSE_BIT(i) ((apse_vec_t)1 << ((i)%APSE_BITS_IN_BITVEC))#define APSE_IDX(p, q, i) ((p)*(q)+((i)/APSE_BITS_IN_BITVEC))#define APSE_BIT_SET(bv, p, q, i) ((bv[APSE_IDX(p, q, i)] |= APSE_BIT(i)))#define APSE_BIT_CLR(bv, p, q, i) ((bv[APSE_IDX(p, q, i)] &= ~APSE_BIT(i)))#define APSE_BIT_TST(bv, p, q, i) ((bv[APSE_IDX(p, q, i)] & APSE_BIT(i)))#define APSE_MATCH_STATE_BOT 0#define APSE_MATCH_STATE_SEARCH 1#define APSE_MATCH_STATE_BEGIN 2#define APSE_MATCH_STATE_FAIL 3#define APSE_MATCH_STATE_GREEDY 4#define APSE_MATCH_STATE_END 5#define APSE_MATCH_STATE_EOT 6#define APSE_TEST_HIGH_BIT(i) \(((i) & ((apse_vec_t)1 << (APSE_BITS_IN_BITVEC - 1))) ? 1 : 0)/* In case you are reading the TR 91-11 of University of Arizona, page 6:* j+1 state* j prev_state* d i* d-1 prev_i*/#define APSE_NEXT_EXACT(state, prev_state, text, i, carry) \(state[i] = ((prev_state[i] << 1 | carry) & text))#define APSE_NEXT_APPROX(state, prev_state, text, i, prev_i, carry) \(state[i] = (((prev_state[i] << 1) & text) | \prev_state[prev_i] | \((state[prev_i] | prev_state[prev_i]) << 1) | \carry))#define APSE_NEXT_COMMON(state, prev_state, text, i) \(state[i] = (prev_state[i] << 1) & text)#define APSE_NEXT_INSERT(state, prev_state, i, prev_i) \(state[i] |= prev_state[prev_i])#define APSE_NEXT_DELETE(state, i, prev_i) \(state[i] |= (state[prev_i] << 1))#define APSE_NEXT_SUBSTI(state, prev_state, i, prev_i) \(state[i] |= (prev_state[prev_i] << 1))#define APSE_NEXT_CARRY(state, i, carry) \(state[i] |= carry)#define APSE_EXACT_MATCH_BEGIN(ap) (ap->state[0] & 1)#define APSE_APPROX_MATCH_BEGIN(ap) \(ap->state[ap->largest_distance + ap->match_begin_bitvector] > \ap->match_begin_prefix && \ap->state[ap->largest_distance + ap->match_begin_bitvector] & \ap->match_begin_prefix)#define APSE_PREFIX_DELETE_MASK(ap) \do { if (ap->edit_deletions < ap->edit_distance && \ap->text_position < ap->edit_distance) \ap->state[h] &= ap->match_begin_bitmask; } while (0)/* The code begins. */staticapse_bool_t apse_set_pattern(apse_t* ap,unsigned char* pattern,apse_size_t pattern_size) {apse_size_t i;if (ap->case_mask)free(ap->case_mask);if (ap->fold_mask)free(ap->fold_mask);ap->pattern_mask = 0;ap->fold_mask = 0;ap->case_mask = 0;ap->is_greedy = 0;ap->prev_equal = 0;ap->prev_active = 0;ap->pattern_size = pattern_size;ap->bitvectors_in_state = (pattern_size - 1)/APSE_BITS_IN_BITVEC + 1;if (ap->edit_distance)ap->largest_distance = ap->edit_distance * ap->bitvectors_in_state;elseap->largest_distance = 0;ap->bytes_in_state = ap->bitvectors_in_state * sizeof(apse_vec_t);ap->case_mask = calloc(ap->n_alphabet, ap->bytes_in_state);if (ap->case_mask == 0)goto out;for (i = 0; i < pattern_size; i++) {#ifdef SUPPORT_MBCSunsigned o = ap->n_alphabet > 256 ?((wchar_t *)pattern)[i] % ap->n_alphabet :pattern[i];#elseunsigned o = pattern[i];#endifAPSE_BIT_SET(ap->case_mask, o, ap->bitvectors_in_state, i);}ap->pattern_mask = ap->case_mask;ap->match_end_bitmask =(apse_vec_t)1 << ((pattern_size - 1) % APSE_BITS_IN_BITVEC);out:if (ap && ap->case_mask)return 1;else {if (ap->case_mask)free(ap->case_mask);if (ap)free(ap);return 0;}}static int _apse_wrap_slice(apse_t* ap,apse_ssize_t begin_in,apse_ssize_t size_in,apse_ssize_t* begin_out,apse_ssize_t* size_out) {if (begin_in < 0) {if ((apse_size_t)-begin_in > ap->pattern_size)return 0;begin_in = ap->pattern_size + begin_in;}if (size_in < 0) {if (-size_in > begin_in)return 0;size_in = -size_in;begin_in -= size_in;}if ((apse_size_t)begin_in >= ap->pattern_size)return 0;if ((apse_size_t)begin_in + size_in > ap->pattern_size)size_in = ap->pattern_size - begin_in;if (begin_out)*begin_out = begin_in;if (size_out)*size_out = size_in;return 1;}static void _apse_reset_state(apse_t* ap) {apse_size_t i, j;(void)memset(ap->state, 0, ap->bytes_in_all_states);(void)memset(ap->prev_state, 0, ap->bytes_in_all_states);ap->prev_equal = 0;ap->prev_active = 0;for (i = 1; i <= ap->edit_distance; i++) {for (j = 0; j < i; j++)APSE_BIT_SET(ap->prev_state, i, ap->bitvectors_in_state, j);}}staticvoid apse_reset(apse_t *ap) {_apse_reset_state(ap);ap->text_position = ap->text_initial_position;#if 0ap->text_position_range = APSE_MATCH_BAD; /* Do not reset this. */#endifap->match_state = APSE_MATCH_STATE_BOT;ap->match_begin = APSE_MATCH_BAD;ap->match_end = APSE_MATCH_BAD;}staticapse_bool_t apse_set_edit_distance(apse_t *ap, apse_size_t edit_distance) {/* TODO: waste not--reuse if possible */if (ap->state)free(ap->state);if (ap->prev_state)free(ap->prev_state);if (edit_distance >= ap->pattern_size)edit_distance = ap->pattern_size;ap->edit_distance = edit_distance;ap->bytes_in_all_states = (edit_distance + 1) * ap->bytes_in_state;ap->state = ap->prev_state = 0;ap->state = calloc(edit_distance + 1, ap->bytes_in_state);if (ap->state == 0)goto out;ap->prev_state = calloc(edit_distance + 1, ap->bytes_in_state);if (ap->prev_state == 0)goto out;apse_reset(ap);if (!ap->has_different_distances) {ap->edit_insertions = edit_distance;ap->edit_deletions = edit_distance;ap->edit_substitutions = edit_distance;}if (ap->edit_distance && ap->bitvectors_in_state)ap->largest_distance = ap->edit_distance * ap->bitvectors_in_state;elseap->largest_distance = 0;ap->match_begin_bitvector =(edit_distance + 1) / APSE_BITS_IN_BITVEC;ap->match_begin_prefix = ((apse_vec_t)1 << edit_distance) - 1;ap->match_begin_bitmask =((apse_vec_t)1 << edit_distance) - 1;ap->match_end_bitvector =(ap->pattern_size - 1) / APSE_BITS_IN_BITVEC;out:return ap->state && ap->prev_state;}attribute_hiddenapse_bool_t apse_set_caseignore_slice(apse_t* ap,apse_ssize_t caseignore_begin,apse_ssize_t caseignore_size,apse_bool_t caseignore) {apse_size_t i, j;int k;apse_ssize_t true_begin, true_size;apse_bool_t okay = 0;#ifdef SUPPORT_MBCSwctrans_t trl = 0, tru = 0; /* -Wall */#endifif (!ap->fold_mask) {ap->fold_mask = calloc(ap->n_alphabet, ap->bytes_in_state);if (ap->fold_mask == 0)goto out;memcpy(ap->fold_mask,ap->case_mask,ap->n_alphabet * ap->bytes_in_state);ap->pattern_mask = ap->fold_mask;}if (!_apse_wrap_slice(ap, caseignore_begin, caseignore_size,&true_begin, &true_size))goto out;#ifdef SUPPORT_MBCSif(ap->n_alphabet > 256) {trl = wctrans("tolower");tru = wctrans("toupper");}#endifif (caseignore) {for (i = true_begin, j = true_begin + true_size;i < j && i < ap->pattern_size; i++) {for (k = 0; k < ap->n_alphabet; k++) {if (APSE_BIT_TST(ap->case_mask,k, ap->bitvectors_in_state, i)) {#ifdef SUPPORT_MBCSif(ap->n_alphabet > 256) {if (iswupper(k))APSE_BIT_SET(ap->fold_mask,towctrans(k, trl),ap->bitvectors_in_state, i);else if (iswlower(k))APSE_BIT_SET(ap->fold_mask,towctrans(k, tru),ap->bitvectors_in_state, i);} else#endif{if (isupper(k))APSE_BIT_SET(ap->fold_mask,tolower(k),ap->bitvectors_in_state, i);else if (islower(k))APSE_BIT_SET(ap->fold_mask,toupper(k),ap->bitvectors_in_state, i);}}}}} else {for (i = true_begin, j = true_begin + true_size;i < j && i < ap->pattern_size; i++) {for (k = 0; k < ap->n_alphabet; k++) {if (APSE_BIT_TST(ap->case_mask,k, ap->bitvectors_in_state, i)) {#ifdef SUPPORT_MBCSif(ap->n_alphabet > 256) {if (iswupper(k))APSE_BIT_CLR(ap->fold_mask,towctrans(k, trl),ap->bitvectors_in_state, i);else if (iswlower(k))APSE_BIT_CLR(ap->fold_mask,towctrans(k, tru),ap->bitvectors_in_state, i);} else#endif{if (isupper(k))APSE_BIT_CLR(ap->fold_mask,tolower(k),ap->bitvectors_in_state, i);else if (islower(k))APSE_BIT_CLR(ap->fold_mask,toupper(k),ap->bitvectors_in_state, i);}}}}}okay = 1;out:return okay;}attribute_hiddenvoid apse_destroy(apse_t *ap) {if (ap->case_mask) free(ap->case_mask);if (ap->fold_mask) free(ap->fold_mask);if (ap->state) free(ap->state);if (ap->prev_state) free(ap->prev_state);if (ap->exact_mask) free(ap->exact_mask);free(ap);}attribute_hiddenapse_t *apse_create(unsigned char* pattern,apse_size_t pattern_size,apse_size_t edit_distance,int n_alphabet) {apse_t *ap;apse_bool_t okay = 0;ap = calloc((size_t)1, sizeof(*ap));if (ap == 0)return 0;ap->pattern_size = 0;ap->pattern_mask = 0;ap->edit_distance = 0;ap->has_different_distances = 0;ap->edit_insertions = 0;ap->edit_deletions = 0;ap->edit_substitutions = 0;ap->use_minimal_distance = 0;ap->bitvectors_in_state = 0;ap->bytes_in_state = 0;ap->bytes_in_all_states = 0;ap->largest_distance = 0;ap->text = 0;ap->text_size = 0;ap->text_position = 0;ap->text_initial_position = 0;ap->text_final_position = APSE_MATCH_BAD;ap->text_position_range = APSE_MATCH_BAD;ap->state = 0;ap->prev_state = 0;ap->match_begin_bitmask = 0;ap->match_begin_prefix = 0;ap->match_end_bitvector = 0;ap->match_end_bitmask = 0;ap->match_state = APSE_MATCH_STATE_BOT;ap->match_begin = APSE_MATCH_BAD;ap->match_end = APSE_MATCH_BAD;ap->match_bot_callback = 0;ap->match_begin_callback = 0;ap->match_fail_callback = 0;ap->match_end_callback = 0;ap->match_eot_callback = 0;ap->exact_positions = 0;ap->exact_mask = 0;ap->is_greedy = 0;ap->custom_data = 0;ap->custom_data_size = 0;ap->n_alphabet = n_alphabet;if (!apse_set_pattern(ap, pattern, pattern_size))goto out;if (!apse_set_edit_distance(ap, edit_distance))goto out;ap->edit_insertions = ap->edit_deletions =ap->edit_substitutions = ap->edit_distance;ap->largest_distance = edit_distance * ap->bitvectors_in_state;okay = 1;out:if (!okay) {apse_destroy(ap);ap = 0;}return ap;}attribute_hiddenapse_bool_t apse_set_insertions(apse_t *ap, apse_size_t insertions) {apse_bool_t okay = 0;if (insertions > ap->edit_distance)insertions = ap->edit_distance;ap->edit_insertions = insertions;ap->has_different_distances = 1;okay = 1;return okay;}attribute_hiddenapse_bool_t apse_set_deletions(apse_t *ap, apse_size_t deletions) {apse_bool_t okay = 0;if (deletions > ap->edit_distance)deletions = ap->edit_distance;ap->edit_deletions = deletions;ap->has_different_distances = 1;okay = 1;return okay;}attribute_hiddenapse_bool_t apse_set_substitutions(apse_t *ap, apse_size_t substitutions) {apse_bool_t okay = 0;if (substitutions > ap->edit_distance)substitutions = ap->edit_distance;ap->edit_substitutions = substitutions;ap->has_different_distances = 1;return okay;}static void _apse_match_bot(apse_t *ap) {apse_reset(ap);if (ap->match_bot_callback)ap->match_bot_callback(ap);}static void _apse_match_begin(apse_t *ap) {ap->match_state = APSE_MATCH_STATE_BEGIN;ap->match_begin = ap->text_position;if (ap->match_begin_callback)ap->match_begin_callback(ap);}static void _apse_match_fail(apse_t *ap) {ap->match_state = APSE_MATCH_STATE_FAIL;ap->match_begin = APSE_MATCH_BAD;if (ap->match_fail_callback)ap->match_fail_callback(ap);ap->match_state = APSE_MATCH_STATE_SEARCH;}static void _apse_match_end(apse_t *ap) {ap->match_state = APSE_MATCH_STATE_END;if (ap->match_end_callback)ap->match_end_callback(ap);ap->match_state = APSE_MATCH_STATE_SEARCH;}static void _apse_match_eot(apse_t *ap) {ap->match_state = APSE_MATCH_STATE_EOT;ap->text_position = ap->text_size;if (ap->match_eot_callback)ap->match_eot_callback(ap);}static apse_bool_t _apse_match_next_state(apse_t *ap) {apse_size_t h, i, j, k;apse_vec_t match;k = ap->edit_distance * ap->bitvectors_in_state;switch (ap->match_state) {case APSE_MATCH_STATE_SEARCH:if (APSE_EXACT_MATCH_BEGIN(ap) || APSE_APPROX_MATCH_BEGIN(ap))_apse_match_begin(ap);break;case APSE_MATCH_STATE_BEGIN:{apse_size_t equal = 0;apse_size_t active = 0;for (h = 0;h <= k;h += ap->bitvectors_in_state) {for (i = h, j = h + ap->bitvectors_in_state - 1; i < j; j--)if (ap->state[j] != ap->prev_state[j])break;if (ap->prev_state[j] == ap->state[j])equal++;if (ap->state[j])active++;}if ((equal == ap->edit_distance + 1 &&ap->is_greedy == 0)||(equal < ap->prev_equal &&ap->prev_active &&active > ap->prev_active &&ap->text_position - ap->match_begin < 8 * ap->bytes_in_state &&!APSE_BIT_TST(ap->state,ap->edit_distance,ap->bitvectors_in_state,ap->text_position - ap->match_begin))) {ap->match_begin = ap->text_position;}else if (active == 0)_apse_match_fail(ap);ap->prev_equal = equal;ap->prev_active = active;}break;default:break;}for (match = 0, h = 0;h <= k;h += ap->bitvectors_in_state)match |= ap->state[h + ap->match_end_bitvector];if (match & ap->match_end_bitmask) {if (ap->match_state == APSE_MATCH_STATE_BEGIN) {if (ap->is_greedy) {ap->match_state = APSE_MATCH_STATE_GREEDY;} else {ap->match_state = APSE_MATCH_STATE_END;ap->match_end = ap->text_position;}}} else if (ap->match_state == APSE_MATCH_STATE_GREEDY) {ap->match_state = APSE_MATCH_STATE_END;ap->match_end = ap->text_position - 1;}return ap->match_state;}static void _apse_exact_multiple(apse_t* ap) {apse_size_t h;apse_size_t g = ap->edit_distance * ap->bitvectors_in_state;for (h = 0; h < ap->bitvectors_in_state; h++)ap->state[g + h] &= ~ap->exact_mask[h];}static apse_bool_t _apse_match_single_simple(apse_t *ap) {/* single apse_vec_t, edit_distance */for ( ; ap->text_position < ap->text_size; ap->text_position++) {unsigned o = (ap->n_alphabet > 256) ?((wchar_t *)ap->text)[ap->text_position] % ap->n_alphabet :ap->text[ap->text_position];apse_vec_t t = ap->pattern_mask[o * ap->bitvectors_in_state];apse_size_t h, g;APSE_NEXT_EXACT(ap->state, ap->prev_state, t, (apse_size_t)0, 1);for (g = 0, h = 1; h <= ap->edit_distance; g = h, h++) {APSE_NEXT_APPROX(ap->state, ap->prev_state, t, h, g, 1);}if (ap->exact_positions)ap->state[ap->edit_distance] &= ~ap->exact_mask[0];if (_apse_match_next_state(ap) == APSE_MATCH_STATE_END)return 1;(void)memcpy(ap->prev_state, ap->state, ap->bytes_in_all_states);}return 0;}static apse_bool_t _apse_match_multiple_simple(apse_t *ap) {/* multiple apse_vec_t:s, has_different_distances */apse_size_t h, i;for ( ; ap->text_position < ap->text_size; ap->text_position++) {unsigned o = (ap->n_alphabet > 256) ?((wchar_t *)ap->text)[ap->text_position] % ap->n_alphabet :ap->text[ap->text_position];apse_vec_t *t = ap->pattern_mask + o * ap->bitvectors_in_state;apse_vec_t c, d;for (c = 1, i = 0; i < ap->bitvectors_in_state; i++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[i]);APSE_NEXT_EXACT(ap->state, ap->prev_state, t[i], i, c);}for (h = 1; h <= ap->edit_distance; h++) {apse_size_t kj = h * ap->bitvectors_in_state,jj = kj - ap->bitvectors_in_state;for (c = 1, i = 0;i < ap->bitvectors_in_state;i++, kj++, jj++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[kj]);APSE_NEXT_APPROX(ap->state, ap->prev_state,t[i], kj, jj, c);}}if (ap->exact_positions)_apse_exact_multiple(ap);if (_apse_match_next_state(ap) == APSE_MATCH_STATE_END)return 1;(void)memcpy(ap->prev_state, ap->state,ap->bytes_in_all_states);}return 0;}static apse_bool_t _apse_match_single_complex(apse_t *ap) {/* single apse_vec_t, has_different_distances */for ( ; ap->text_position < ap->text_size; ap->text_position++) {unsigned o = (ap->n_alphabet > 256) ?((wchar_t *)ap->text)[ap->text_position] % ap->n_alphabet :ap->text[ap->text_position];apse_vec_t t = ap->pattern_mask[o * ap->bitvectors_in_state];apse_size_t h, g;APSE_NEXT_EXACT(ap->state, ap->prev_state, t, (apse_size_t)0, 1);for (g = 0, h = 1; h <= ap->edit_distance; g = h, h++) {apse_bool_t has_insertions = h <= ap->edit_insertions;apse_bool_t has_deletions = h <= ap->edit_deletions;apse_bool_t has_substitutions = h <= ap->edit_substitutions;APSE_NEXT_COMMON(ap->state, ap->prev_state, t, h);if (has_insertions)APSE_NEXT_INSERT(ap->state, ap->prev_state, h, g);if (has_deletions)APSE_NEXT_DELETE(ap->state, h, g);if (has_substitutions)APSE_NEXT_SUBSTI(ap->state, ap->prev_state, h, g);APSE_NEXT_CARRY(ap->state, h,has_deletions || has_substitutions ? 1 : 0);APSE_PREFIX_DELETE_MASK(ap);}if (ap->exact_positions)ap->state[ap->edit_distance] &= ~ap->exact_mask[0];if (_apse_match_next_state(ap) == APSE_MATCH_STATE_END)return 1;(void)memcpy(ap->prev_state, ap->state,ap->bytes_in_all_states);}return 0;}static apse_bool_t _apse_match_multiple_complex(apse_t *ap) {/* multiple apse_vec_t:s, has_different_distances */apse_size_t h, i;for ( ; ap->text_position < ap->text_size; ap->text_position++) {unsigned o = (ap->n_alphabet > 256) ?((wchar_t *)ap->text)[ap->text_position] % ap->n_alphabet :ap->text[ap->text_position];apse_vec_t *t = ap->pattern_mask + o * ap->bitvectors_in_state;apse_vec_t c, d;for (c = 1, i = 0; i < ap->bitvectors_in_state; i++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[i]);APSE_NEXT_EXACT(ap->state, ap->prev_state, t[i], i, c);}for (h = 1; h <= ap->edit_distance; h++) {apse_size_tkj = h * ap->bitvectors_in_state,jj = kj - ap->bitvectors_in_state;apse_bool_t has_insertions = h <= ap->edit_insertions;apse_bool_t has_deletions = h <= ap->edit_deletions;apse_bool_t has_substitutions = h <= ap->edit_substitutions;/* Is there such a thing as too much manual optimization? */if (has_insertions) {if (has_deletions && has_substitutions) {for (c = 1, i = 0;i < ap->bitvectors_in_state;i++, kj++, jj++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[kj]);APSE_NEXT_COMMON(ap->state, ap->prev_state, t[i], kj);APSE_NEXT_INSERT(ap->state, ap->prev_state, kj, jj);APSE_NEXT_DELETE(ap->state, kj, jj);APSE_NEXT_SUBSTI(ap->state, ap->prev_state, kj, jj);APSE_NEXT_CARRY(ap->state, kj, c);APSE_PREFIX_DELETE_MASK(ap);}} else if (has_deletions) {for (c = 1, i = 0;i < ap->bitvectors_in_state;i++, kj++, jj++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[kj]);APSE_NEXT_COMMON(ap->state, ap->prev_state, t[i], kj);APSE_NEXT_INSERT(ap->state, ap->prev_state, kj, jj);APSE_NEXT_DELETE(ap->state, kj, jj);APSE_NEXT_CARRY(ap->state, kj, c);APSE_PREFIX_DELETE_MASK(ap);}} else if (has_substitutions) {for (c = 1, i = 0;i < ap->bitvectors_in_state;i++, kj++, jj++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[kj]);APSE_NEXT_COMMON(ap->state, ap->prev_state, t[i], kj);APSE_NEXT_INSERT(ap->state, ap->prev_state, kj, jj);APSE_NEXT_SUBSTI(ap->state, ap->prev_state, kj, jj);APSE_NEXT_CARRY(ap->state, kj, c);APSE_PREFIX_DELETE_MASK(ap);}} else {for (c = 1, i = 0;i < ap->bitvectors_in_state;i++, kj++, jj++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[kj]);APSE_NEXT_COMMON(ap->state, ap->prev_state, t[i], kj);APSE_NEXT_INSERT(ap->state, ap->prev_state, kj, jj);APSE_NEXT_CARRY(ap->state, kj, c);APSE_PREFIX_DELETE_MASK(ap);}}} else {if (has_deletions && has_substitutions) {for (c = 1, i = 0;i < ap->bitvectors_in_state;i++, kj++, jj++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[kj]);APSE_NEXT_COMMON(ap->state, ap->prev_state, t[i], kj);APSE_NEXT_DELETE(ap->state, kj, jj);APSE_NEXT_SUBSTI(ap->state, ap->prev_state, kj, jj);APSE_NEXT_CARRY(ap->state, kj, c);APSE_PREFIX_DELETE_MASK(ap);}} else if (has_deletions) {for (c = 1, i = 0;i < ap->bitvectors_in_state;i++, kj++, jj++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[kj]);APSE_NEXT_COMMON(ap->state, ap->prev_state, t[i], kj);APSE_NEXT_DELETE(ap->state, kj, jj);APSE_NEXT_CARRY(ap->state, kj, c);APSE_PREFIX_DELETE_MASK(ap);}} else if (has_substitutions) {for (c = 1, i = 0;i < ap->bitvectors_in_state;i++, kj++, jj++, c = d) {d = APSE_TEST_HIGH_BIT(ap->state[kj]);APSE_NEXT_COMMON(ap->state, ap->prev_state, t[i], kj);APSE_NEXT_SUBSTI(ap->state, ap->prev_state, kj, jj);APSE_NEXT_CARRY(ap->state, kj, c);APSE_PREFIX_DELETE_MASK(ap);}}}if (ap->exact_positions)_apse_exact_multiple(ap);if (_apse_match_next_state(ap) == APSE_MATCH_STATE_END)return 1;(void)memcpy(ap->prev_state, ap->state,ap->bytes_in_all_states);}}return 0;}static apse_bool_t __apse_match(apse_t *ap,unsigned char *text,apse_size_t text_size) {apse_bool_t did_match = 0;if (ap->match_state == APSE_MATCH_STATE_BOT) {ap->text = text;if (ap->text_final_position == APSE_MATCH_BAD)ap->text_size = text_size;elseap->text_size =ap->text_final_position > text_size ?text_size : ap->text_final_position + 1;_apse_match_bot(ap);} else if (ap->match_state == APSE_MATCH_STATE_EOT)goto leave;if (ap->edit_deletions >= ap->pattern_size ||ap->edit_substitutions >= ap->pattern_size) {ap->match_state = APSE_MATCH_STATE_END;ap->match_begin = ap->text_initial_position;ap->match_end = ap->text_size - 1;ap->text_position = ap->text_size;goto out;}if (ap->pattern_size - ap->edit_deletions >ap->text_size - ap->text_initial_position) {ap->match_state = APSE_MATCH_STATE_EOT;ap->text_position = ap->text_size;goto out;}if (text_size + ap->edit_distance < ap->pattern_size + ap->text_position) {ap->text_position = ap->text_size;goto eot;}if (ap->match_state == APSE_MATCH_STATE_SEARCH) {ap->text_position++;_apse_reset_state(ap);}if (ap->text_position_range != APSE_MATCH_BAD &&ap->text_position - ap->text_initial_position >ap->text_position_range) {ap->match_state = APSE_MATCH_STATE_END;goto eot;}ap->match_state = APSE_MATCH_STATE_SEARCH;if (ap->has_different_distances) {if (ap->bitvectors_in_state == 1) {if (_apse_match_single_complex(ap))goto out;} else {if (_apse_match_multiple_complex(ap))goto out;}} else {if (ap->bitvectors_in_state == 1) {if (_apse_match_single_simple(ap))goto out;} else {if (_apse_match_multiple_simple(ap))goto out;}}out:if (ap->match_state == APSE_MATCH_STATE_GREEDY) {ap->match_state = APSE_MATCH_STATE_END;ap->match_end = ap->text_position - 1;}if (ap->match_state == APSE_MATCH_STATE_END) {_apse_match_end(ap);did_match = 1;}eot:if (ap->text_position == ap->text_size)_apse_match_eot(ap);leave:return did_match;}static apse_bool_t _apse_match(apse_t *ap,unsigned char *text,apse_size_t text_size) {if (ap->use_minimal_distance) {apse_set_edit_distance(ap, 0);if (__apse_match(ap, text, text_size))return 1;else {apse_size_t minimal_edit_distance;apse_size_t previous_edit_distance = 0;apse_size_t next_edit_distance;for (next_edit_distance = 1;next_edit_distance <= ap->pattern_size;next_edit_distance *= 2) {apse_set_edit_distance(ap, next_edit_distance);if (__apse_match(ap, text, text_size))break;previous_edit_distance = next_edit_distance;}minimal_edit_distance = next_edit_distance;if (next_edit_distance > 1) {do {minimal_edit_distance =(previous_edit_distance + next_edit_distance) / 2;if (minimal_edit_distance == previous_edit_distance)break;apse_set_edit_distance(ap, minimal_edit_distance);if (__apse_match(ap, text, text_size))next_edit_distance = minimal_edit_distance;elseprevious_edit_distance = minimal_edit_distance;} while (previous_edit_distance <= next_edit_distance);if (!__apse_match(ap, text, text_size))minimal_edit_distance++;}apse_set_edit_distance(ap, minimal_edit_distance);__apse_match(ap, text, text_size);return 1;}} elsereturn __apse_match(ap, text, text_size);}attribute_hiddenapse_bool_t apse_match(apse_t *ap,unsigned char *text, apse_size_t text_size) {apse_bool_t did_match = _apse_match(ap, text, text_size);_apse_match_eot(ap);apse_reset(ap);return did_match;}